Changing expired password(s) using Azure Graph API - azure

I have the following Python code to authenticate against the Graph API
import requests
def login(tenant_name, client_id, client_secret, username, password):
url = 'https://login.windows.net/' + tenant_name + '/oauth2/token'
payload = {
'grant_type': 'password',
'username': username + '#' + tenant_name,
'password': password,
'client_id': client_id,
'client_secret': client_secret,
'resource': 'https://graph.windows.net'
}
r = requests.post(url, data=payload)
return r.json()
If I have user, whose password has expired, I get a response(as expected):
{
'timestamp': '2015-09-15 02:59:26Z',
'trace_id': '8abff845-6941-4867-9729-15626c23330f',
'submit_url': None,
'correlation_id': '81184c06-2627-4bca-82e3-76aab7713a5f',
'error_description': 'AADSTS70002: Error validating credentials. AADSTS50055: Password is expired.
Trace ID: 8abff845-6941-4867-9729-15626c23330f
Correlation ID: 81184c06-2627-4bca-82e3-76aab7713a5f
Timestamp: 2015-09-15 02:59:26Z',
'context': None,
'error': 'user_password_expired',
'error_codes': [70002, 50055]
}
Graph API provides use an endpoint to reset a password, but to do so, I need a valid token (to make a PATCH request to the endpoint mentioned in the documentation) and since I couldn't login, I don't have one.
What is the right way to change a user password on expiry using the Azure Graph API?

You can't.
At least not with the Resource Owner Password Credentials Grant (grant_type=password) flow, where you only have the end-user's credentials (though really, there are very few cases where this flow is a good choice--see this answer and this answer for more).
The user needs to be directed to Azure AD's web interface (in a browser/web view) to authenticate and change their password.

Related

401 Error - Google API with service account

Hello fellow User.
I'm trying to write to a Google sheets document via a Google service account. The account has writing permission the the document, so that's not the issue.
The reason I'm using a service account is to avoid having to constantly refresh access tokens. I think there lies the issue. Because this is the response from the API:
{
"error": {
"code": 401,
"message": "Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential.
See https://developers.google.com/identity/sign-in/web/devconsole-project.",
"status": "UNAUTHENTICATED"
}
}
This occurs when I try sending a put request to the spreadsheet to edit data. I previously connected the service account to the sheets API, aquired the credentials from there and used them in the request.
If anyone knows, where the error might be, I'd be very thankful.
Here is the Python code that triggered the error:
iat = time.time()
exp = iat + 3600
payload = {'iss': <SERVICE ACCOUNT EMAIL>,
'sub': <SERVICE ACCOUNT EMAIL>,
'aud': f'https://sheets.googleapis.com/v4/spreadsheets/<SHEETID>/values/Sheet1!A2:B5',
'iat': iat,
'exp': exp}
additional_headers = {'kid': <PRIVATE KEY ID>}
signed_jwt = jwt.encode(payload, key=<PRIVATE KEY>,
headers=additional_headers, algorithm='RS256')
headers = {'authorization': f'Bearer {signed_jwt}'}
params = {'range': f'Sheet1!A2B5',
'majorDimension':'ROWS',
'values':[
<LISTS OF ENTRIES>
]}
spreadsheetId = <SHEETID>
resp = requests.put(url=f'https://sheets.googleapis.com/v4/spreadsheets/{spreadsheetId}/
values/Sheet1!A2:B5?valueInputOption=USER_ENTERED',
data = params, headers = headers)
For anyone interested, I was following these guides:
How to use service account for authentication: https://developers.google.com/identity/protocols/oauth2/service-account#python_1
How to issue correct put request: https://developers.google.com/sheets/api/samples/writing
How to get correct endpoint for jwt-encoded credentials: https://developers.google.com/sheets/api/reference/rest
Expected OAuth 2 access token, login cookie or other valid authentication credential.
The coded used for accessing APIs with a service account is not the same as the code used for Oauth2. The code you are using appears to be trying to authenticate using Oauth2.
You should be using something like this.
credentials = ServiceAccountCredentials.from_json_keyfile_name(
KEY_FILE_LOCATION, SCOPES)
service = build('calendar', 'v3', credentials=credentials)
Reference:
oauth2client.service_account module

How to use Cognito for AppSync mutation call (Python)

I'd like to call mutations from AppSync using my Python function but use a Cognito user for the authorization as "API-KEY", "IAM" and other methods are not suitable for my application.
My mutation looks like this (test purposes):
mutation XYZ {
updateTask(input: {id: "a1b2c3", name: "newTaskName"}) {
id
name
}
}
I am assuming that the user is already created and enabled by some means. If your AppSync API is secured only using Cognito, you are always going to need a username and a password to begin with. For example, you can use below code to login and get the AccessToken from the response:
import boto3
def get_user_auth(event, context):
client = boto3.client('cognito-idp')
response = client.initiate_auth(
UserPoolId='xxxxxxxxx',
ClientId='xxxxxxxxxxxxxx',
AuthFlow='USER_PASSWORD_AUTH',
AuthParameters={
'USERNAME': 'xxxxxx',
'PASSWORD': 'xxxxxx'
}
)
return response
Note: Make sure that you have "Enable username password based authentication (ALLOW_USER_PASSWORD_AUTH)" enabled.
Once you have the access token, you can use this in HTTP headers within your request as follows:
{
"authorization": "<YOUR-VERY-VERY-LONG-ACCESS-TOKEN>"
}
For example:
import requests
from requests_aws4auth import AWS4Auth
import boto3
session = requests.Session()
APPSYNC_API_ENDPOINT_URL = '<YOUR-API-URL>'
mutation = """mutation XYZ {updateTask(input: {id: "a1b2c3", name: "newTaskName"}) {id, name}}"""
response = session.request(
url=APPSYNC_API_ENDPOINT_URL,
method='POST',
headers={'authorization': '<YOUR-VERY-VERY-LONG-ACCESS-TOKEN>'},
json={'mutation': mutation}
)
print(response.json()['data'])
Since this access token has some expiration, you might also need to refresh this token by using the RefreshToken from the above response. Like so:
def refresh_token(self, username, refresh_token):
try:
return client.initiate_auth(
ClientId=self.client_id,
AuthFlow='REFRESH_TOKEN_AUTH',
AuthParameters={
'REFRESH_TOKEN': refresh_token,
# 'SECRET_HASH': self.get_secret_hash(username)
# If the User Pool has been defined with App Client secret,
# you will have to generate secret hash as well.
}
)
except botocore.exceptions.ClientError as e:
return e.response
Example of how you can generate secret hash.

Obtaining JWT token from Azure AD using Python

I am working on an application that needs to obtain a bearer token form Azure AD. Right now I have everything set in Azure and I can generate/obtain the token using Postman (see picture)
However, and this is my struggle, I am having problems obtaining the token programmatically using Python. The code below is what I have tried, with some variations of what to iinclude as fields in the request_payload, without any luck
import json
import requests
#TOKEN_URL = "https://login.microsoftonline.com/organizations/oauth2/v2.0/token"
TOKEN_URL = "https://login.microsoftonline.com/41ff26dc-250f/oauth2/token?resource=https://graph.windows.net"
RESOURCE_URL = "https://login.microsoftonline.com/41ff26dc-739be8610c21/oauth2/authorize?resource=https://graph.windows.net"
def authenticate():
request_payload = {
"callback_url" : "https://localhost",
"auth_url" : "https://login.microsoftonline.com/41ff26dc-250fc21/oauth2/authorize?resource=https://graph.windows.net",
"access_token_url" : "https://login.microsoftonline.com/41ff26dc-739be8610c21/oauth2/token?resource=https://graph.windows.net",
"username": MY USER NAME,
"password": MY PASSWORD,
"resource": RESOURCE_URL,
"grant_type": "Authorization_Code",
"client_id": 'e0d00a8e-b799-4285-be3f-eb5822aaa86e',
"client_secret": '-n24Y2is~p5Jk7~6kYcp4~q2lrmnRCXoW_'}
response = requests.post(url=TOKEN_URL, data=request_payload).json()
print(response)
bearer_token = response["access_token"]
print(bearer_token)
return bearer_token
print(authenticate())
This is the error I get when I fill in my credentials (MY USER NAME and MY PASSWORD) appropriately
{'error': 'invalid_request', 'error_description': "AADSTS900144: The request body must contain the following parameter: 'code'.\r\nTrace ID: d84b06a7-1c45-4657-bb3f-085248de5d01\r\nCorrelation ID: e431a09a-07dc-4c12-bf19-3b8ff7e7c358\r\nTimestamp: 2020-06-25 21:55:25Z", 'error_codes': [900144], 'timestamp': '2020-06-25 21:55:25Z', 'trace_id': 'd84b06a7-1c45-4657-bb3f-085248de5d01', 'correlation_id': 'e431a09a-07dc-4c12-bf19-3b8ff7e7c358', 'error_uri': 'https://login.microsoftonline.com/error?code=900144'}
Any thoughts, suggestions or leads are very much appreciated. Like I said before, I am not sure what fields should I put in the payload, I am not even sure what are all possible fields to try there either.
Please follow this document for auth code flow
you need to send below
https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize?
client_id=6731de76-14a6-49ae-97bc-6eba6914391e
&response_type=code
&redirect_uri=http%3A%2F%2Flocalhost%2Fmyapp%2F
&response_mode=query
&scope=openid%20offline_access%20https%3A%2F%2Fgraph.microsoft.com%2Fmail.read
&state=12345
please refer to this python sample

how to make the token active when the user is accessing the API

I have created a JWT Token based login system, I am able to generate the token and I have added the expiry time to that token.
Requiremenent:
When the user is accessing the UI the token should not expire.
When the User is not Accessing the UI for 10 minutes the token should expire.
I am using Angular for UI and python flask for backend, I don't no from where(either UI or Backend) I have to handle this. I am thinking we have to handle it from python flask so I have used python and flask tags, If I am wrong let me know.
my backend code:
def loginM(email, password):
try:
time_count = get_time_count_details()
user = Credentials.query.filter_by(email=email).first()
user_reg = Registration.query.filter_by(email=email).first()
if bcrypt.check_password_hash(user.password, password):
payload = {"email": user.email, 'user_id': user.user_id,
'first_name': user_reg.first_name,
'company': user_reg.company, 'mobile_num': user_reg.mobile_number,
'exp': time.time() + time_count}
secret_key = open(SECRET_KEY).read()
token = jwt.encode(payload, secret_key, algorithm='RS256').decode('utf-8')
return dict(token=token)
else:
return dict(Unsucessful="Invalid Email Address and password")
except Exception:
return False
you can use redis key expire instead of exp in jwt payload
jwt payload dont save exp value, jwt will not expired. payload like this:
payload = {"email": user.email, 'eco_user_id': user.eco_user_id,
'first_name': user_reg.first_name,
'company': user_reg.company, 'mobile_num': user_reg.mobile_number,}
redis save token,and set expiration as 10min
redis.set(token, user.id)
redis.expire(token, 60 * 10)
When the user is accessing the api, sever will find token in redis.if find token in redis,we will refresh redis expiration time,otherwise return 403 and tell user to login

How to get saved tracks for a specific user, or change the current user?

The Spotify API has an endpoint "Get a Users's Saved Tracks" GET https://api.spotify.com/v1/me/tracks but as you can see from me in the url, and in the documentation, this is only for the current user. How can I access information about a non current user, or change the current user?
For example, userA logs in, I get an access and refresh token for userA. userB logs in, replacing userA as the current user, I get userB's tokens. How can I now make make requests for information about userA?
You need to store the tokens you get from authenticating users.
Say you're using user sessions:
User A logs in.
You get the access and refresh tokens for user A.
You save these tokens to User A's session.
User B logs in.
You get the access and refresh tokens for user B.
You save these tokens to User B's session.
You'd do this the same way that you have already implemented user sessions.
And so when a user lands on your redirect URI, you save the tokens you received to their session.
And then when you need to use the Spotify API you use the tokens saved in the users session.
If you however want to do this for one end-user, then with a web server things get a little harder.
But with a CLI app things can be a little easier.
What you want to do is log user A and B into your application, manually saving both tokens independently.
This is as easy as making an authentication function that you call twice and save the results to two variables.
After this you can then call the API with the saved tokens.
And use user A's token when you want to get user A's saved tracks.
Here's a low-level example implementation in Python 3 using Requests, of getting the users tracks and user information, using different scopes. Where the comments are the part the code's at in the authorization code flow:
import time
import urllib.parse as parse
import webbrowser
import requests
from requests.auth import HTTPBasicAuth
OAUTH_AUTHORIZE_URL = 'https://accounts.spotify.com/authorize'
OAUTH_TOKEN_URL = 'https://accounts.spotify.com/api/token'
# Change to your application settings
class Settings:
client_id = ''
client_secret = ''
redirect_uri = ''
def authenticate(scope=None):
'''Implement OAuth 2 Spotify authentication'''
# Application: Request authorization to access data
payload = {'client_id': Settings.client_id,
'response_type': 'code',
'redirect_uri': Settings.redirect_uri,
'show_dialog': 'true'} # allow second account to login
if scope:
payload['scope'] = scope
auth_url = '{}?{}'.format(OAUTH_AUTHORIZE_URL, parse.urlencode(payload))
# Spotify: Displays scopes & prompts user to login (if required)
# User: Logs in, authorizes access
webbrowser.open(auth_url)
response = input('Enter the URL you were redirected to: ')
code = parse.parse_qs(parse.urlparse(response).query)['code'][0]
payload = {'redirect_uri': Settings.redirect_uri,
'code': code,
'grant_type': 'authorization_code'}
if scope:
payload['scope'] = scope
# Application: Request access and refresh tokens
# Spotify: Returns access and refresh tokens
auth = HTTPBasicAuth(Settings.client_id, Settings.client_secret)
response = requests.post(OAUTH_TOKEN_URL, data=payload, auth=auth)
if response.status_code != 200:
response.raise_for_status()
token_info = response.json()
token_info['expires_at'] = int(time.time()) + token_info['expires_in']
token_info['scope'] = scope
return token_info
if __name__ == '__main__':
user_a = authenticate(scope='user-library-read')
user_b = authenticate(scope='user-read-email user-read-private user-read-birthdate')
print('user_a', user_a)
print('user_b', user_b)
for url in ['https://api.spotify.com/v1/me/tracks',
'https://api.spotify.com/v1/me']:
for user in [user_a, user_b]:
token = 'Bearer ' + user['access_token']
# Application: Uses access token in requests to Web API
# Spotify: Returns request data
r = requests.get(url, headers={'authorization': token})
if r.status_code != 200:
print(r.text)
else:
print([
'{}: {}'.format(key, str(value)[:20])
for key, value in r.json().items()
])

Resources