mongodb python get users of database - python

I want to create an admin application to monitor data collection. For this the user registration process is based on the database access i.e, when we create a new database user through MongoDB atlas, they will immediately be able to log into the admin application with their database username and password. How do I get a mongo document/response containing the list of database users and their hashed passwords using python?

I made a function that accepts the Mongo database user's username and password and uses that to connect to a Mongo client. I then attempt to perform a basic read operation (read operation requires the least user privilege) If the read op is successful then it means the username and password provides are authentic and I return true, else check if the operation failed because of a failed authentication and return false.
from pymongo import MongoClient
from pymongo.errors import OperationFailure
def check_dbuser(username, password):
""" Attempts to connect to mongo atlas using the username and password. It then attempts a basic operation which is
to list the database names of the cluster. If the operation works, the username and password are authentic and
return True.
Else if there is an OperationFailure we check that the error is due to failed authentication and return False
"""
auth = False
failed_message = 'bad auth Authentication failed.' # this is the err message returned on a failed authentication
uri = f'mongodb+srv://{username}:{password}#cluster-connection-string'
client = MongoClient(uri)
try:
client.list_database_names()
except OperationFailure as e:
assert(e.details['errmsg'] == failed_message) # assert that the error message is that of an authentication failure
else:
auth = True
return auth

Related

Migrate Users from keycloak to Firebase with Python

We have switched from Keycloak authentication to Firebase authentication and I need to migrate the users from Keycloak to Firebase using Python.
These users were stored by Keycloak in a Postgres DB. I used the Admin SDK to get the users out of the Postgres DB and have already successfully saved them to Firebase, using the instructions from Firebase: https://firebase.google.com/docs/auth/admin/import-users. The users are also successfully created and displayed in Firebase. The users who logged in with the identity provider like Google Auth. can log in without problems. Only those users who log in with email and password get an error message INVALID_PASSWORD, CODE:400.
My guess then was that the salt and/or hash are not passed correctly or that they are stored wrong (keycloak hashing alg.:pbkdf2_sha256 and iterations: 27500 (default value)).
When passing in Python to the firebase attributes: password_hash and password_salt a byte array is expected, which I convert with bytes(user.password_hash/.password_salt, encoding='utf-8') to a byte
array. In some posts (like https://github.com/firebase/firebase-admin-python/issues/182) I saw that I should decode the hash in base64 and after that it should already work.
users = []
for user in list_users:
record = auth.ImportUserRecord(
uid=user.uid,
email= user.email,
display_name= user.display_name,
email_verified= user.email_verified,
password_hash= None if user.password_hash is None else ab64_decode(bytes(user.password_hash, encoding='utf-8')),
password_salt= None if user.password_salt is None else bytes(user.password_salt, encoding='utf-8'),
provider_data= None if user.providers == [] else getProviderRecords(user.providers),
)
users.append(record)
But what I know is that keycloak already stores hash and salt in format base 64 into the DB. The salt was also tested by me with an online tool (https://8gwifi.org/pbkdf.jsp) and it could validate. When saving in Firebase I don't get an exception and I also reconstructed the saving of the hash (https://github.com/firebase/firebase-admin-python/blob/master/firebase_admin/_user_import.py).
However, there could be something wrong with auth.UserImportHash, but I also got this code from the Firebase instructions.
iteraions_round=27500
hash_alg = auth.UserImportHash.pbkdf2_sha256(rounds=iteraions_round)
try:
result = auth.import_users(users, hash_alg=hash_alg)
print('Successfully imported {0} users. Failed to import {1} users.'.format(
result.success_count, result.failure_count))
for err in result.errors:
print('Failed to import {0} due to {1}'.format(users[err.index].uid, err.reason))
except exceptions.FirebaseError:
# Some unrecoverable error occurred that prevented the operation from running.
pass
Also, I output the users again before saving, but password_hash and password_salt are also saved with b'hash/salt' as in the Firebas instructions.
"If the salt is stored as a base64 encoded string, you have to decode that before passing it to Firebase. The code above only seems to decode the password hash." hiranya911
following code worked as expected:
...
password_hash= None if user.password_hash is None else ab64_decode(bytes(user.password_hash, encoding='utf-8')),
password_salt= None if user.password_salt is None else ab64_decode(bytes(user.password_salt, encoding='utf-8')),
...

Flask + SQLAlchemy + Google Ads API : How to properly update refresh token?

# create/login local user on successful OAuth login
#oauth_authorized.connect_via(google)
def google_logged_in(blueprint, token):
#
# Token is accessible in this scope with token=xyz
#
# One Time Commit to unlock the database
# db.session.commit()
##########################################
if not token:
flash("Failed to log in.", category="error")
return False
resp = blueprint.session.get("/oauth2/v1/userinfo")
if not resp.ok:
msg = "Failed to fetch user info."
flash(msg, category="error")
return False
info = resp.json()
user_id = str(info["id"])
# Find this OAuth token in the database, or create it
query = OAuth.query.filter_by(provider=blueprint.name, provider_user_id=user_id)
try:
oauth = query.one()
db.session.commit()
except NoResultFound:
oauth = OAuth(provider=blueprint.name, provider_user_id=user_id, token=token)
if oauth.user:
# If this OAuth token already has an associated local account,
# log in that local user account.
# Note that if we just created this OAuth token, then it can't
# have an associated local account yet.
#
try:
update=OAuth.query.filter_by(provider=blueprint.name, provider_user_id=user_id)
update.token=token
db.session.commit()
except:
print('cannot update login token')
login_user(oauth.user)
flash("Successfully signed in.")
else:
# Create a new local user account for this user
user = User(email=info["email"],image_url=info["picture"])
# Associate the new local user account with the OAuth token
oauth.user = user
# Save and commit our database models
db.session.add_all([user, oauth])
db.session.commit()
# Log in the new local user account
login_user(user)
flash("Successfully signed in.")
# Disable Flask-Dance's default behavior for saving the OAuth token
return False
What I am trying to do is following:
Flowchart of my Process
I am database noob so i am not sure if I am doing what I want.
The problem is that my database locks after my token expires so something is not working with this part:
if oauth.user:
# If this OAuth token already has an associated local account,
# log in that local user account.
# Note that if we just created this OAuth token, then it can't
# have an associated local account yet.
#
try:
update=OAuth.query.filter_by(provider=blueprint.name, provider_user_id=user_id)
update.token=token
db.session.commit()
except:
print('cannot update login token')
login_user(oauth.user)
flash("Successfully signed in.")
But I couldnt find out where the problem is.
Docs didnt help and following SO posts didnt help either:
How do I unlock a SQLite database?
SQLAlchemy and SQLite: database is locked
https://www.reddit.com/r/flask/comments/36g2g7/af_sqlite_database_locking_problem/
Can someone get my ass out of existential chrisis and SQL dumbness?
Edit:
After the token has expired I now only get the message:
oauthlib.oauth2.rfc6749.errors.InvalidGrantError: (invalid_grant) Token has been expired or revoked.
I fixed a little bit when i replaced
query = OAuth.query.filter_by(provider=blueprint.name, provider_user_id=user_id)
with
query = db.session.query(OAuth).filter_by(provider=blueprint.name, provider_user_id=user_id)
but I seem not to write the new token to the database since I still get:
oauthlib.oauth2.rfc6749.errors.InvalidGrantError: (invalid_grant) Token has been expired or revoked.
So now my question how do I properly update refresh token?
I did not catch an error in:
update=db.session.query(OAuth).filter_by(provider=blueprint.name, provider_user_id=user_id) update.token=token
because of try statement(i know its noobish). I than updated my code like this:
if oauth.user:
# If this OAuth token already has an associated local account,
# log in that local user account.
# Note that if we just created this OAuth token, then it can't
# have an associated local account yet.
#
#try:
print('Trying to update the token')
update=db.session.query(OAuth).filter_by(provider=blueprint.name, provider_user_id=user_id)
update.token=token
db.session.commit()
print('User has been updated:', update.token==token)
#except:
# print('cannot update login token')
login_user(oauth.user)
flash("Successfully signed in.")
Found out that
AttributeError: 'BaseQuery' object has no attribute 'token'
googled it quickly and found out that i need to use the first() like that:
update=db.session.query(OAuth).filter_by(provider=blueprint.name, provider_user_id=user_id).first()
Thanks to myself for being such noob and still get an answer to my question.

Unable to validate The credentials using pysnow

I need to validate if servicenow login credentials are correct or not.
I am using pysnow
def validate_conn(self, data):
instance = data['url']
user = data['uname']
password = data['pwd']
try:
pysnow.client.Client(instance=instance, host=None, user=user, password='xfgdfgdf', raise_on_empty=None,
request_params=None, session=None)
print("valid")
except:
print("invalid")
return data['pwd']
In the above code I gave the invalid password so it have to come to the except block but i am getting valid as output. I need to validate if credentials are valid or not
The ServiceNow Web Services API does not provide a mechanism to validate credentials. One way to validate credentials from a Web Services client is to attempt to read a record that you know exists. One record that must exist is your own user record from sys_user.
The following code attempts to read your own user record from sys_user. If you are unable to read this record, then something must be wrong.
try:
client = pysnow.Client(instance=instance, user=user, password=password)
response = (client
.resource(api_path='/table/sys_user')
.get(query={'user_name': user})
.one())
print('credentials are valid')
except:
print('credentials are not valid')

Get two-factor authentication code from user without losing session (Flask server)

I have an API request to a third-party website that works great in the command line (from https://github.com/haochi/personalcapital):
pc = PersonalCapital()
try:
pc.login(email, password)
except RequireTwoFactorException:
pc.two_factor_challenge(TwoFactorVerificationModeEnum.SMS)
pc.two_factor_authenticate(TwoFactorVerificationModeEnum.SMS, input('code: '))
pc.authenticate_password(password)
accounts_response = pc.fetch('/newaccount/getAccounts')
accounts = accounts_response.json()['spData']
When I run the above in the command line, I get back a JSON just as intended.
However, I'd like to use it in a web app on a Flask server. So, I need to remove the command line input('code: ') for SMS confirmation. I'm thinking I'll use a form via 'POST' to get the user input.
However, if I redirect() or render_template() to send the user to the form, it interrupts my API session, and I get back a "session not authenticated" response from the API.
Server logic. Routes in question are /update (email and password first) and /authenticate (SMS confirmation form):
#app.route("/update", methods=["GET", "POST"])
#login_required
def update():
# Via post:
if request.method == "POST":
# Ensure userentered email
if not request.form.get("pc_email"):
return apology("Please enter username", 400)
# Ensure user entered password
elif not request.form.get("pc_password"):
return apology("Please enter password", 400)
# Save email & password
email = request.form.get("pc_email")
password = request.form.get("pc_password")
# Try to log in
try:
pc.login(email, password)
# If 2-factor is required, send sms & redirect
except RequireTwoFactorException:
pc.two_factor_challenge(TwoFactorVerificationModeEnum.SMS)
return redirect("/authenticate")
# Get data:
else:
# Get accounts data
accounts_response = pc.fetch('/newaccount/getAccounts')
accounts = accounts_response.json()['spData']
# TODO - update database w/ data from accounts & transactions
return redirect("/")
#app.route("/authenticate", methods=["GET","POST"])
#login_required
def authenticate():
# Via POST:
if request.method == "POST":
# SMS authentication
pc.two_factor_authenticate(TwoFactorVerificationModeEnum.SMS, \
request.form.get(sms))
pc.authenticate_password(password)
# Get accounts data
accounts_response = pc.fetch('/newaccount/getAccounts')
accounts = accounts_response.json()
# TODO - update database w/ data from accounts & transactions
# Redirect to "/"
return render_template("test.html", accounts=accounts)
# Via GET:
else:
return render_template("authenticate.html")
Source code for project is here: https://github.com/bennett39/budget/blob/stackoverflow/01/application.py
How do I block the code from executing while waiting for the user to respond with their SMS code? Or, should I be going about this problem a different way?
The error you are experiencing is actually due to the way you try to use global variables to persist state between requests. You initially define password as a module level variable and then set password = request.form.get("pc_password") within your update function. Due to pythons rules regarding global and local variables https://docs.python.org/3/faq/programming.html#id9 this creates a new local variable containing the password value and leaves the module level variable untouched. You then access the original global password variable within your authenticate function which fails as this password variable is still set to its original value of ''. The quick fix would be to add global password at the start of your update function but this ignores the other problems with this method of persisting state. All of your global variables are shared between everyone using your site, so that if multiple people are logged in then they will all be logged into the same personal capital account. It would be preferable to use the session object to persist this data as each user will then only be able to access their own session object and there will be no risk of people accessing each others accounts. Your use of the PersonalCapital object complicates things a little as this uses instance variables to persist state, which is appropriate for a command line application but less so for a web application. It is a very simple object however, with only 2 instance variables. It should therefore be fairly straightforward to extract these and store them in the session at the end of your update function and use these values to rebuild the object at the start of your authenticate function.

Using boto3, how to check if AWS IAM user has password?

Among the users in IAM, I want to programmatically get the list of all password enabled users. From AWS Console, I can easily spot them. But, how to get their list programmatically? I want to use python boto to get that.
I was reading up here http://boto3.readthedocs.io/en/latest/reference/services/iam.html#iam, but by most of the ways listed in this doc, I can only see option of using 'PasswordLastUsed' which would be null in three cases
The user does not have a password
The password exists but has never been used
there is no sign-in data associated with the user.
So just by checking if 'PasswordLastUsed' is null I can not claim that user does not have password and thereby, can not get all the users with password. Am I missing something here? Any other way or any other python resource I can use to do this?
import boto3
iam = boto3.resource('iam')
def isPasswordEnabled(user):
login_profile = iam.LoginProfile(user)
try:
login_profile.create_date
print True
except:
print False
>>> isPasswordEnabled('user1')
True
>>> isPasswordEnabled('user2')
False
I can see that there is a way, just where you would expect it to be...
http://boto3.readthedocs.io/en/latest/reference/services/iam.html#IAM.Client.get_credential_report
In the report, field password_enabled set to false indicates no password.
You could use the GetLoginProfile API request to determine if an IAM user has a login profile or not. If there is no login profile associated with the user this request will return a 404 response. Some code like this should work:
import boto3
iam = boto3.client('iam')
user_name = 'bob'
try:
response = iam.get_login_profile(UserName=user_name)
except Exception, e:
if e.response['ResponseMetadata']['HTTPStatusCode'] == 404:
print('User {} has no login profile'.format(user_name))

Categories

Resources