Python Firebase authentication - python

So I am trying to obtain some data from Firebase, which ofcourse has some rules/security constraints defined. I can authenticate my user from the Login & Auth tab, and I'd like to get data from firebase, however my user is still not authenticated.
user = ref.authenticate(email, password) , which returns the following for user
{
u'token':{some long token here}',
u'user':{
u'uid':u'ef44b781-8842-4f28-abf0-2ac9aa0b2bea',
u'provider':u'password',
u'email':u'user#email.com',
u'isTemporaryPassword':False,
u'sessionKey':u'{session key here}}',
u'md5_hash':u'{md5_hash here}}',
u'id':u'ef44b781-8842-4f28-abf0-2ac9aa0b2bea'
}
}
Now that I know the user is authenticated (otherwise it returns something along the lines of an error, I would like to do a simple GET conversations = firebase.get(FIREBASE_NAME + '/conversations/' + me), where 'me' is the user['user']['uid']
I have the following structure for conversations:
conversations/my-uid/other-uid/{data}
I would think my user is authenticated, still it returns a PermissionDenied
EDIT
Solved this by using a different library you can find here. The initial library I used did not support authentication, while this one does. The way it was solved, was by implementing some functions from the other one and sending my token as follow:
FIREBASE.child('/messages/').get(token=token)

You should not send passwords in the URL, you can do this way:
__FIREBASE_USER_VERIFY_SERVICE = "https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyPassword"
__FIREBASE_API_KEY = __your_api_key_here__
def user_login(email, passwd):
url = "%s?key=%s" % (__FIREBASE_USER_VERIFY_SERVICE, __FIREBASE_API_KEY)
data = {"email": email,
"password": passwd,
"returnSecureToken": True}
result = requests.post(url, json=data)
is_login_successful = result.ok
json_result = result.json()
return json_result # authToken=> json_result['idToken']
If successful, it will result like:
{
"displayName": "",
"email": "your_users_email#example.com",
"expiresIn": "3600",
"idToken": "abc123...",
"kind": "identitytoolkit#VerifyPasswordResponse",
"localId": "UWQ...x2",
"refreshToken": "def098...",
"registered": true
}
If fails (wrong password etc) :
{
"error": {
"code": 400,
"errors": [
{
"domain": "global",
"message": "INVALID_PASSWORD",
"reason": "invalid"
}
],
"message": "INVALID_PASSWORD"
}
}
or may be
{
"error": {
"code": 400,
"errors": [
{
"domain": "global",
"message": "MISSING_PASSWORD",
"reason": "invalid"
}
],
"message": "MISSING_PASSWORD"
}
}

Solved this by using a different library you can find here. The initial library I used did not support authentication, while this one does. The way it was solved, was by implementing some functions from the other one and authenticate as follows:
def auth_with_password(self, email, password):
request_ref = 'https://auth.firebase.com/auth/firebase?firebase={0}&email={1}&password={2}'.\
format(self.fire_base_name, email, password)
request_object = self.requests.get(request_ref)
return request_object.json()
Then to make an authorized call, do this
user = auth_with_password(email, password)
token = user['user']['token']
FIREBASE.child('/messages/').get(token=token)
Make sure your token is correct. The library supports this, but otherwise I would suggest that you use Firebase token generator for Python

Related

Elastic search Api

Hey Stackoverflow fam,
I am working on an API which pulls requests from elastic search tool and displays it.
I am trying to pull data using get request
import requests
import json
payload = {
"query": {
"match": {
"metric": "metric_name"
}
}
}
url = "https://url_name:9200/siren-kinesis*/_search"
payload = json.dumps(payload)
print(type(payload))
headers = {
'Content-Type': 'application/json',
}
result = requests.get(url=url,data=payload,headers=headers,auth=("test#example.com","*"))
print(result.json())
and getting the following error
{
"error": {
"root_cause": [
{
"type": "security_exception",
"reason": "unable to authenticate user [test#example.com] for REST request [/_search]",
"header": {
"WWW-Authenticate": "Basic realm=\"security\" charset=\"UTF-8\""
}
}
],
"type": "security_exception",
"reason": "unable to authenticate user [test#example.com] for REST request [/_search]",
"header": {
"WWW-Authenticate": "Basic realm=\"security\" charset=\"UTF-8\""
}
},
"status": 401
}
I am Basic Auth .i.e. passing username and password for authorization.
Can somebody help me ?
In the case of Basic Auth in any request, if you're requesting via postman you can provide the credentials in the Authentication tab. But In the case of Code/Console/Browser, the certificates must be given in the request URL.
e.g.
https://username:password#URL
https://admin:admin#www.the-internet.herokuapp.com/basic_auth

Open the url with Access Token which comes in API response

I have a set of api calls which can be accessible by Access Token and I'm able to get responses from the apis but one of the responses contain URL but when I try to access it, url asks for Log in which i'm already Logged in because thats how I got Access Token.
API response:
{
"root": "some value",
"blocks": {
"some value": {
"display_name": "some display name",
"block_id": "abc123",
"view_url": "https://www.abc.come",
"web_url": "https://www.abv.com",
"type": "some type",
"id": "some id"
}
}
}
So from this response I want to access "web_url" so when i do a Get request, it asks for Log in.
So how can I access web_url without Log in ?
You can access the url from the response using the access token
access_token = "your_access_token"
web_url_response = requests.get(response['blocks']['some value']['web_url'], headers={"Authorization": "Bearer " + access_token})

Permission problems with Google Apps Marketplace

We created an application for Google Apps Marketplace, and we want to add a new feature - get all the domain's user defined schemas. But I didn't find out how to grant our application permission to do it. Do we have to get permission again from all our customers? Or maybe create a new Google Apps Marketplace application and ask permission for it only from the customers who need it? (not all our customers need this feature).
Here is my code, it fails in two ways:
class EmailSettingsClient:
headers = None
domain = None
def __init__(self, admin_email):
self.initCredentials(admin_email)
logging.debug("headers={}".format(self.headers))
def initCredentials(self, admin_email):
http = httplib2.Http()
credentials = SignedJwtAssertionCredentials(
SERVICE_EMAIL,
PRIVATE_KEY,
scope='https://apps-apis.google.com/a/feeds/emailsettings/2.0/ https://www.googleapis.com/auth/admin.directory.user.readonly https://www.googleapis.com/auth/admin.directory.userschema.readonly',
sub=str(admin_email) # it doesn't work with this line.
)
http = credentials.authorize(http)
service = build(serviceName='admin', version='directory_v1', http=http)
creds = credentials.to_json()
access_token = credentials.token_response['access_token']
self.headers = {
'Content-type': 'application/atom+xml',
'Authorization': 'Bearer '+access_token
}
def get_all_domain_custom_schemas(self, feed_uri):
customer_id = "..." # domain customerId
logging.debug("EmailSettingsClient::get_all_domain_custom_schemas, feed_uri = {}, customerId = {} .".format(feed_uri, customer_id))
request_url = 'https://www.googleapis.com/admin/directory/v1/customer/{}/schemas'.format(customer_id)
reply = requests.get(request_url, headers=self.headers)
# data = json.loads(reply.content)
logging.info(reply.content)
customer_id = "my_customer"
logging.debug("EmailSettingsClient::get_all_domain_custom_schemas, feed_uri = {}, customerId = {} .".format(feed_uri, customer_id))
request_url = 'https://www.googleapis.com/admin/directory/v1/customer/{}/schemas'.format(customer_id)
reply = requests.get(request_url, headers=self.headers)
# data = json.loads(reply.content)
logging.info(reply.content)
class GetAllDomainCustomSchemasHandler(RequestHandler):
def post(self):
return self.get()
def get(self):
domain_str = self.request.get('domain')
domain = Domain.get_by_key_name(domain_str)
feed_uri = self.request.get('feed_uri', "")
email_settings_client = EmailSettingsClient(domain.admin)
email_settings_client.get_all_domain_custom_schemas(feed_uri)
return
One, it throws an exception if we use the "sub" parameter from another user with the domain admin's email address. And Two, if I don't include the "sub" parameter and run the application from the domain admin's account, it returns an error message: When I tried with the domain customerId, I got this error message:
{
"error": {
"errors": [
{
"domain": "global",
"reason": "forbidden",
"message": "Not Authorized to access this resource/api"
}
],
"code": 403,
"message": "Not Authorized to access this resource/api"
}
}
And when I tried with "my_customer", I got this error message:
{
"error": {
"errors": [
{
"domain": "global",
"reason": "backendError",
"message": "Service unavailable. Please try again"
}
],
"code": 503,
"message": "Service unavailable. Please try again"
}
}
I'm sure I missed something, but I didn't find out how to make it work. Any suggestions?
Eventually I found out that we can add this permission in the Google Developers Console, under APIs / Google Apps Marketplace SDK / Configuration. I added https://www.googleapis.com/auth/admin.directory.userschema.readonly, and each domain admin has to approve the new permissions. If you have more information you can edit this answer or post a new answer.

Custom exception message from google endpoints exception

Currently, I've a Python endpoints service to change the name of a user. If there is no problem, I return a MessageField with a lot of informations.
But sometimes, the request is correct and I want to say to client that there is an error that he can handle : "Hey, sorry but there is already a user with this name", or also, "Hey, sorry but you have already change your name today !".
The problem is, when I raise an endpoint exception like a UnauthorizedException or anything else, I can just put a custom message :
raise endpoints.UnauthorizedException('Invalid user_id or auth_token !')
result in :
{
"error": {
"errors": [
{
"domain": "global",
"reason": "required",
"message": "Invalid user_id or auth_token !",
"locationType": "header",
"location": "Authorization"
}
],
"code": 401,
"message": "Invalid user_id or auth_token !"
}
}
Is there a way to really customize this message ? Or to return a completely different MessageField in this case ?
For example, I would like to return a JSON like this (maybe with HTTP Code 400) :
{
"error": {
"username_already_exist": 1
}
}
Thanks !
If you don't want to return the JSON that is build with an exception, you'll have to do a straight up return in your code instead of raising an exception. You can build the JSON you mention and then return that whenever you hit the "exception point".
Or what you can do is use the message to send the error to the client, then have the client catch that exception, parse appropriately, and display whatever you want.

Trying to delete a post using Blogger API returns "not found" error

Sending a DELETE request to Blogger REST API (v3.0), I'm trying to delete a post using delete method. For this I use the following code:
api_uri = 'https://www.googleapis.com/blogger/v3/blogs/%s/posts/%s' % (blogId, postId)
result = urlfetch.fetch(url=api_uri,
method=urlfetch.DELETE,
headers={'Authorization' : oauth_token})
self.response.out.write(result.content)
But the server returns:
{
"error": {
"errors": [
{
"domain": "global",
"reason": "notFound",
"message": "Not Found"
}
],
"code": 404,
"message": "Not Found"
}
}
However, I can retrieve information about this post, using the following code:
api_uri = 'https://www.googleapis.com/blogger/v3/blogs/%s/posts/%s' % (blogId, postId)
result = urlfetch.fetch(url=api_uri,
headers={'Authorization' : oauth_token})
self.response.out.write(result.content)
At this moment, I can't understand what am I doing wrong — the request is authorized, the blogId and postId are correct — but anyway, the server returns "not found" error.
If you know how to solve this problem or you can give useful advice — help me please. Thank you for your time and consideration of this matter.
UPD 1: If I send requests to the following URLs:
# https://www.googleapis.com/blogger/v3/users/{userID}
# https://www.googleapis.com/blogger/v3/users/self
The server also returns:
{
"error": {
"errors": [
{
"domain": "global",
"reason": "notFound",
"message": "Not Found"
}
],
"code": 404,
"message": "Not Found"
}
}
UPD 2: I forgot to say that I'm using OAuth 2.0 for Server to Server Applications. Thus, to get authorization token, I send request to https://accounts.google.com/o/oauth2/token using the following JWT Claim Set:
jwt_claim_set = {
'iss' : '{id}#developer.gserviceaccount.com',
'scope' : 'https://www.googleapis.com/auth/blogger',
'aud' : 'https://accounts.google.com/o/oauth2/token',
'exp' : expire,
'iat' : timestamp
}
The server returns:
{
"access_token" : "1/8xbJqaOZXSUZbHLl5EOtu1pxz3fmmetKx9W8CV4t79M",
"token_type" : "Bearer",
"expires_in" : 3600
}
And define variable oauth_token, using:
data = simplejson.loads(result.content)
oauth_token = data['token_type'] + ' ' + data['access_token']
Are you sure that you're using OAuth2 properly? It seems to me that you're not properly logged in, and that's why you're getting those errors.
Try those same queries using Google OAuh2 Playground (https://code.google.com/oauthplayground/) and see what happens.

Categories