How to link Firebase's Authentication with its Realtime Database in python - python

I am using the firebase library and I've already tried the pyrebase library too but the database request doesn't seem to be authenticated.
Heres a snippet of my code
import firebase
# I have changed the firebase config details for security purposes, but I still can connect to firebase with my valid credentials
firebase_config = {
'apiKey': "asdfghjkl",
'authDomain': "fir-test-6bb4c.firebaseapp.com",
'projectId': "fir-test-6bb4c",
'storageBucket': "fir-test-6bb4c.appspot.com",
'messagingSenderId': "410996397069",
'appId': "1:410996397069:web:856f4181a8d9debf15b144",
'measurementId': "G-Y0Z6PDGKC2",
'databaseURL': 'https://fir-test-6bb4c-default-rtdb.firebaseio.com/'
}
cloud = firebase.Firebase(firebase_config)
auth = cloud.auth()
db = cloud.database()
storage = cloud.storage()
# Sign In
# for security purposes again, I have changed the email, but it is to confirm that I can authenticate successfully with the right email and password
email = "test1234567#gmail.com"
password = "123456789"
auth.sign_in_with_email_and_password(email, password)
# Connect to Real Time Data Base
uid = auth.current_user["localId"]
path = db.child("users/" + uid)
And here's the database rules
{
"rules": {
".read": false,
".write": false,
"users": {
"$folder": {
".read": "auth != null && auth.uid === $folder",
".write": "auth != null && auth.uid === $folder"
}
},
"secrets": {
".read": false,
".write": false
}
}
}
These are a few things I found out while playing with the rules and in the rules playground:
The firebase/pyrebase database requests are not authenticated even though the authentication at auth.sign_in_with_email_and_password(email, password) was successful
In the rules playground I was able to send authenticated request which allowed me to read and write when the uid and folder name matched
I was also looking for method by which rules could print or log somethings for debug purposes, or if the rules could read and write to the database.
I found out that firestore had the debug() function but I would like to stick to the realtime database since I've been using it for a while.

Related

Microsoft Graph API update user authentication method - Access Denied

I'm creating an application in Azure AD as a daemon to get user phone
authentication methods using the python msal library and calling the following following endpoint GET https://graph.microsoft.com/beta/users/{id | UPN}/authentication/phoneMethods but i get the following error
{
"error": {
"code": "accessDenied",
"message": "Request Authorization failed",
"innerError": {
"message": "Request Authorization failed",
"date": "2020-11-19T19:26:28",
"request-id": "11975e07-ee6b-4bd2-9a74-7c175c5da560",
"client-request-id": "11975e07-ee6b-4bd2-9a74-7c175c5da560"
}
}
}
My app has the required application permissions to get the info i'm looking for, which are UserAuthenticationMethod.Read.All and UserAuthenticationMethod.ReadWrite.All and it already works with different end points such as GET https://graph.microsoft.com/beta/users/{id | UPN}, this is the code i'm using in order to get the access token required and call the graph api
import json
import logging
import requests
import msal
config = {
"authority": "https://login.microsoftonline.com/TENANT_NAME",
"client_id": "APP_ID",
"scope": ["https://graph.microsoft.com/.default"],
"secret": "APP_SECRET",
"endpoint": "https://graph.microsoft.com/beta/users/{USER_ID}/authentication/phoneMethods"
}
app = msal.ConfidentialClientApplication(
config["client_id"], authority=config["authority"],
client_credential=config["secret"],
)
result = None
result = app.acquire_token_silent(config["scope"], account=None)
if not result:
logging.info("No suitable token exists in cache. Let's get a new one from AAD.")
result = app.acquire_token_for_client(scopes=config["scope"])
if "access_token" in result:
graph_data = requests.get(
config["endpoint"],
headers={'Authorization': 'Bearer ' + result['access_token']}, ).json()
print("Graph API call result: ")
print(json.dumps(graph_data, indent=2))
else:
print(result.get("error"))
print(result.get("error_description"))
print(result.get("correlation_id"))
i tried to do the same thing using curl or postman and i get the exact same error, so i'm guessing it's an access token issue maybe ?
Thanks in advance
The api call does not support application permissions. You need to grant delegated permissions to the application, and then use the auth code flow to obtain the token.

How to authenticate against an AWS Cognito User Pool in Python?

I have a static serverless website that allows authentication with Javascript using an AWS Cognito User Pool.
Now I'm trying to enable some programmatic access so I need to do this same authentication via a Python script. Is this possible? The docs don't provide any code examples for Python.
I'm just trying to find some way for Python to issue a GET or POST request against an AWS URL, passing it a username and login, and getting back the signed cookies verifying authentication.
The closest example I've found is this code, which references the cognito-idp API. I've modified to:
import boto3
client_id = '<my_app_client_id>'
region_name = 'us-east-1'
auth_data = { 'USERNAME':'myusername' , 'PASSWORD':'mypassword' }
provider_client = boto3.client('cognito-idp', region_name=region_name)
resp = provider_client.initiate_auth(AuthFlow='USER_PASSWORD_AUTH', AuthParameters=auth_data, ClientId=client_id)
print('resp:', resp)
However, even though I use the same credentials as through the Javascript API, this fails to authenticate and simply returns the error:
botocore.exceptions.NoCredentialsError: Unable to locate credentials
This this the correct Python equivalent as the Javascript Cognito API?
The following snippet shows a complete authentication workflow with Cognito using boto3.
def get_secret_hash(username):
msg = username + CLIENT_ID
dig = hmac.new(
str(CLIENT_SECRET).encode('utf-8'),
msg=str(msg).encode('utf-8'),
digestmod=hashlib.sha256
).digest()
d2 = base64.b64encode(dig).decode()
return d2
def initiate_auth(client, username, password):
secret_hash = get_secret_hash(username)
try:
resp = client.admin_initiate_auth(
UserPoolId=USER_POOL_ID,
ClientId=CLIENT_ID,
AuthFlow='ADMIN_NO_SRP_AUTH',
AuthParameters={
'USERNAME': username,
'SECRET_HASH': secret_hash,
'PASSWORD': password,
},
ClientMetadata={
'username': username,
'password': password, })
except client.exceptions.NotAuthorizedException:
return None, "The username or password is incorrect"
except client.exceptions.UserNotConfirmedException:
return None, "User is not confirmed"
except Exception as e:
return None, e.__str__()
return resp, None
#app.route('/auth/login', methods=['POST'])
def login():
event = auth.current_request.json_body
client = boto3.client('cognito-idp')
username = event['username']
password = event['password']
for field in ["username", "password"]:
if event.get(field) is None:
return {"error": True,
"success": False,
"message": f"{field} is required",
"data": None}
resp, msg = initiate_auth(client, username, password)
if msg != None:
return {'message': msg,
"error": True, "success": False, "data": None}
if resp.get("AuthenticationResult"):
return {'message': "success",
"error": False,
"success": True,
"data": {
"id_token": resp["AuthenticationResult"]["IdToken"],
"refresh_token": resp["AuthenticationResult"]["RefreshToken"],
"access_token": resp["AuthenticationResult"]["AccessToken"],
"expires_in": resp["AuthenticationResult"]["ExpiresIn"],
"token_type": resp["AuthenticationResult"]["TokenType"]
}}
else: # this code block is relevant only when MFA is enabled
return {"error": True,
"success": False,
"data": None, "message": None}
Here's the important part parsed from the functions.
resp = client.admin_initiate_auth(
UserPoolId=USER_POOL_ID,
ClientId=CLIENT_ID,
AuthFlow='ADMIN_NO_SRP_AUTH',
AuthParameters={
'USERNAME': username,
'SECRET_HASH': secret_hash,
'PASSWORD': password,
},
ClientMetadata={
'username': username,
'password': password, })
The examples were taken from a four part tutorial that unfortunately didn't help me integrate this with the Chalice CognitoUserPoolAuthorizer but otherwise seems to work well. Here are the tutorials if you can't find better code examples.
part 1
part 2
part 3
part 4
Pass the access and secret key to boto3 like this.
provider_client = boto3.client('cognito-idp', region_name=region_name, aws_access_key_id=AWS_ACCESS_KEY_ID,
aws_secret_access_key=AWS_SECRET_ACCESS_KEY)

firebase_admin prints None but I have data in db and permission is allow all [duplicate]

I have a chat app using Firebase that keeps on having a
setValue at x failed: DatabaseError: permission denied
error every time I type a message.
I set my Database to be public already:
service cloud.firestore {
match /databases/{database}/documents {
match /{allPaths=**} {
allow read, write: if request.auth.uid != null;
}
}
}
Is it something from within my chat reference?
private void displayChat() {
ListView listOfMessage = findViewById(R.id.list_of_message);
Query query = FirebaseDatabase.getInstance().getReference();
FirebaseListOptions<Chat> options = new FirebaseListOptions.Builder<Chat>()
.setLayout(R.layout.list_item)
.setQuery(query, Chat.class)
.build();
adapter = new FirebaseListAdapter<Chat>(options) {
#Override
protected void populateView(View v, Chat model, int position) {
//Get reference to the views of list_item.xml
TextView messageText, messageUser, messageTime;
messageText = v.findViewById(R.id.message_text);
messageUser = v.findViewById(R.id.message_user);
messageTime = v.findViewById(R.id.message_time);
messageText.setText(model.getMessageText());
messageUser.setText(model.getMessageUser());
messageTime.setText(DateFormat.format("dd-MM-yyyy (HH:mm:ss)", model.getMessageTime()));
}
};
listOfMessage.setAdapter(adapter);
}
Your code is using the Firebase Realtime Database, but you're changing the security rules for Cloud Firestore. While both databases are part of Firebase, they are completely different and the server-side security rules for one, don't apply to the other.
When you go the database panel in the Firebase console, you most likely end up in the Cloud Firestore rules:
If you are on the Cloud Firestore rules in the Firebase console, you can change to the Realtime Database rules by clicking Cloud Firestore BETA at the top, and then selecting Realtime Database from the list.
You can also directly go to the security rules for the Realtime Database, by clicking this link.
The security rules for the realtime database that match what you have are:
{
"rules": {
".read": "auth.uid !== null",
".write": "auth.uid !== null"
}
}
This will grant any authenticated user full read and write access to the entire database. Read my answer to this question on more on the security/risk trade-off for such rules: Firebase email saying my realtime database has insecure rules.
change this
request.auth.uid != null
to
request.auth.uid == null
or defined a proper auth mechanism before starting the conversation where user defined by userID

How to authenticate a WAMP connection via a ticket in python

I'm trying to connect to a WAMP bus from a different application that has certain roles configured. The roles are authenticated with a static ticket, so I believe that I need to declare what role I want to connect as and what the associated ticket is. I'm writing this in Python and have most of the component set up, but I can't find any documentation about how to do this sort of authentication.
from autobahn.twisted.component import Component, run
COMP = Component(
realm=u"the-realm-to-connect",
transports=u"wss://this.is.my.url/topic",
authentication={
# This is where I need help
# u"ticket"?
# u"authid"?
}
)
Without the authentication, I'm able to connect to and publish to the WAMP bus when it is running locally on my computer, but that one is configured to allow anonymous users to publish. My production WAMP bus does not allow anonymous users to publish, so I need to authenticate what role this is connecting as. The Autobahn|Python documentation implies that it can be done in Python, but I've only been able to find examples of how to do it in JavaScript/JSON in Crossbar.io's documentation.
the documentation is not very up to date.
With the Component it is necessary to do like that for tickets:
from autobahn.twisted.component import Component, run
component = Component(
realm=u"the-realm-to-connect",
transports=u"wss://this.is.my.url/topic",
authentication={
"ticket": {
"authid": "username",
"ticket": "secrettoken"
}
},
)
Here is some example that can be helpful for you:
https://github.com/crossbario/crossbar-examples/tree/master/authentication
I think you need to use WAMP-Ticket Dynamic Authentication method.
WAMP-Ticket dynamic authentication is a simple cleartext challenge
scheme. A client connects to a realm under some authid and requests
authmethod = ticket. Crossbar.io will "challenge" the client, asking
for a ticket. The client sends the ticket, and Crossbar.io will in
turn call a user implemented WAMP procedure for the actual
verification of the ticket.
So you need to create an additional component to Authenticate users:
from autobahn.twisted.wamp import ApplicationSession
from autobahn.wamp.exception import ApplicationError
class AuthenticatorSession(ApplicationSession):
#inlineCallbacks
def onJoin(self, details):
def authenticate(realm, authid, details):
ticket = details['ticket']
print("WAMP-Ticket dynamic authenticator invoked: realm='{}', authid='{}', ticket='{}'".format(realm, authid, ticket))
pprint(details)
if authid in PRINCIPALS_DB:
if ticket == PRINCIPALS_DB[authid]['ticket']:
return PRINCIPALS_DB[authid]['role']
else:
raise ApplicationError("com.example.invalid_ticket", "could not authenticate session - invalid ticket '{}' for principal {}".format(ticket, authid))
else:
raise ApplicationError("com.example.no_such_user", "could not authenticate session - no such principal {}".format(authid))
try:
yield self.register(authenticate, 'com.example.authenticate')
print("WAMP-Ticket dynamic authenticator registered!")
except Exception as e:
print("Failed to register dynamic authenticator: {0}".format(e))
and add Authentication method in the configuration:
"transports": [
{
"type": "web",
"endpoint": {
"type": "tcp",
"port": 8080
},
"paths": {
"ws": {
"type": "websocket",
"serializers": [
"json"
],
"auth": {
"ticket": {
"type": "dynamic",
"authenticator": "com.example.authenticate"
}
}
}
}
}
]

Login Required error using service account Google BigQuery API

I wrote a python script that called insert API of BigQuery to insert data to a table. I use service account for OAuth authentication. It functioned correctly for few days but now it gives Login Required error (401). Following is the code:
scopes = ['https://www.googleapis.com/auth/bigquery']
credentials =ServiceAccountCredentials.from_json_keyfile_name('/home/ubuntu/aha/udofy.json', scopes=scopes)
service = discovery.build('bigquery', 'v2', credentials=credentials)
job_body = { } #Body JSON
request = service.jobs().insert(projectId=projectId, body=job_body)
response = request.execute()
I see the following error when I check the job logs on the UI:
{
"error": {
"errors": [
{
"domain": "global",
"reason": "required",
"message": "Login Required",
"locationType": "header",
"location": "Authorization"
}
],
"code": 401,
"message": "Login Required"
}
}
API Response:
{u'configuration': {u'query': {u'createDisposition': u'CREATE_IF_NEEDED',
u'destinationTable': {u'datasetId': u'co_gradeup_android_ANDROID',
u'projectId': u'udofy-1021',
u'tableId': u'user_answer_attempts'},
u'query': u' SELECT user_dim.user_id as user_id, event_dim.params.value.string_value as post_id, DATE(USEC_TO_TIMESTAMP(event_dim.timestamp_micros)) as attempt_date, count(*) as attempt_count FROM [udofy-1021:co_gradeup_android_ANDROID.app_events_20161101] WHERE event_dim.name =\'Answer_Selected\' and event_dim.params.key = \'postId\' and user_dim.user_id is not null and user_dim.user_id != "" group by 1,2,3 ',
u'writeDisposition': u'WRITE_APPEND'}},
u'etag': u'', #User_etag
u'id': u'', #User_Id
u'jobReference': {u'jobId': u'job_C9kSTaEOQBw0VPBEF_Yj44C0-Us',
u'projectId': u'udofy-1021'},
u'kind': u'bigquery#job',
u'selfLink': u'https://www.googleapis.com/bigquery/v2/projects/udofy-1021/jobs/job_C9kSTaEOQBw0VPBEF_Yj44C0-Us',
u'statistics': {u'creationTime': u'1478082742163',
u'startTime': u'1478082742420'},
u'status': {u'state': u'RUNNING'},
u'user_email': u''} #service_account_email
The service account doesn't have permissions to access the big query project in question. Service accounts are not you, it needs to be preauthorized.
No idea if you can grant another user access to a project but if you can take the service account email address and add it as a user.
This is all contingent on your service account code working. My python skills are limited I will have to assume its right.
The issue was that the output schema/format of the query in the job body did not match the schema of the table in which the data was being inserted via the insert API. There was a minor change in the query which was executed in the job body.
The output format of the query should be exact same as the table schema in the the output data has to be inserted.

Categories

Resources