Get an Azure Active Directory token as a user - python

I want to be able getting access token while I act as a user (meaning I only have username and password).
In all the relevant topics I only see that they try getting the token as administrator of the application (for example, in order to know the clientId), but can I do the same while acting as the user of the application?

As suggested by #Thomas, you can make use of ROPC flow.
In order to get access token as a user, you still need to know values of client_id and tenant_id along with your UPN and password.
Client_Id - Your Application ID
Tenant_Id - Your Directory ID
You can get these values from the person who registered the application by:
Go to Azure Portal -> Azure Active Directory -> Your Application -> Overview
After getting those values, make use of Postman to generate the access token.
For that, POST an HTTP request like below that need tenant_id and parameters like below:
https://login.microsoftonline.com/your_tenant_id/oauth2/v2.0/token
In Postman, Go to Authorization tab and select type as Oauth2.0
Visit Headers tab and include Content-Type key with value as application/x-www-form-urlencoded
In Body tab, include parameters like client_id, grant_type, username, password and scope as below:
Make sure to grant admin consent to required API permissions defined in scope before sending the request.
Now, send the request and you can get the access token successfully like below:
To know more in detail, please refer below links:
Sign in with resource owner password credentials grant - Microsoft identity platform | Microsoft Docs
Azure registered app error: The user or administrator has not consented to use the application with ID - Stack Overflow

Related

O365 Authorization Code Grant Flow URL not loading

I'm trying to use the O365 pypl python library to receive a new auth token after changing my microsoft password. The authentication flow looks like this:
from O365 import Account
credentials = ('my_client_id', 'my_client_secret')
# the default protocol will be Microsoft Graph
# the default authentication method will be "on behalf of a user"
account = Account(credentials)
if account.authenticate(scopes=['basic', 'message_all']):
print('Authenticated!')
I receive a message saying to visit the following URL to give consent. However, when I paste the URL, I am asked to login to microsoft and then nothing happens i.e. no permissions or consent page appears. My organization recently switched to Single Sign On so I'm wondering if this could potentially be causing the issue or if anyone else has experienced this? I'm new to this and very lost so any help is greatly appreciated! Thanks so much!!
To receive auth token, please check the following:
Register your application at Microsoft Application Registration Portal.
Login to the portal to get the access token.
To consent the application in order to access the resources first get the authorization URL like below:
url = account.connection.get_authorization_url()
Visit the above URL and grant consent for the application.
To perform authentication, create Account instance and authenticate using the authenticate method.
from pyo365 import Account
account = Account(credentials=('client_id', 'client_secret'))
result = account.authenticate(scopes=['basic', 'message_all'])
After requesting a token, app consent screen will appear where you have to give consent.
The user have to provide the result url after consent.
Token will be stored in the default location if all goes as expected.
For more information in detail, please refer below links:
https://github.com/janscas/pyo365#authentication
Question about get_authorization_url · Issue #13 · janscas/pyo365 · GitHub

How to do google Sign In with the help of idToken in Django

This is the code I use to retrieve idToken in my flutter app
Future<void> _handleSignIn() async {
try {
final result = await _googleSignIn.signIn();
final ggAuth = await result!.authentication;
print(ggAuth.idToken); // this is the one that I use as token value
print(ggAuth.accessToken);
} catch (error) {
print(error);
}
}
And this is the code I use to access user info in my backend.
from google.oauth2 import id_token
from google.auth.transport import requests
try:
idinfo = id_token.verify_oauth2_token(token, requests.Request(), CLIENT_ID)
userid = idinfo['sub']
print(userid)
except ValueError:
print('Invalid token)
But after replacing the token variable with the token received from flutter app and replacing the CLIENT_ID with the id generated for my app (available in the console) , it still throws the error of invalid token. What am I doing wrong?
EDIT- When I use https://jwt.io/ to decode the token it works as expected and I get all the details.
Authentication Think of the id token as your birth certificate. It just identifies you as a person.
Authorization Think of the access token as your drivers license its what contains the permissions that you have to drive a car.
An Id token does not out write give you permission to access any data on google servers. With an access token you have been authorized to access some data in this case some profile information.
The issue you are having is that you are using sign-in in. Sign in is Open id connect think of it as a birth certificate (Id token). There is a user their who is signing in to your app. They are in fount of their computer. By default with Google signin gives you get basic profile information. What you are doing with Jwt.io is checking the claims that are returned in the Id token. Id tokens are just the token that allows your application to identify that the user is logged in. There should also be a sub claim there you should use this id to map the user to your integral user system. There may be a user name and email address in the claims but you can not guarantee that they will be there every time google has stated they do not always return these claims.
To get user profile information after the user has logged in you should be using the people api the people.get method when passed the access token will return to you the profile information of the currently authenticated user.
beyond that you should IMO not be passing tokens to your backend if you want the token in the backend you should log the user in using your backend language.
Okay so the idToken that I had was correct but flutter terminal was not able to print its full length and because of which I was copying only half the token and was getting a signature error when checking manually.

How to avoid the popup for choosing email when use try to use oauth2 in python?

I am trying to build an flask app on AWS lambda, which needs to access https://www.googleapis.com/auth/admin.directory.device.chromeos.readonly to get the Mac Address of chrome devices by domain name and chrome device id.
Basically the working flow is blew:
A Chrome Extension deployed by G-Suit sends an request with domain name and device id to AWS(as we are using AWS), then the AWS sends an request with domain name and device id to Google Cloud to get Mac Address.
I started with using an access the directory API as a service account like service_account.Credentials.from_service_account_file(SERVICE_ACCOUNT_FILE, scopes=SCOPES, subject="username#domainName.com"), and it works. However, I realised it was wrong implementation as the domainName would be changed and subject will be different for each domain as the Chrome Extension can be deployed via different domains.
Then I started to use the sample code from Google(https://developers.google.com/api-client-library/python/auth/web-app), and I was able to access the domain and get the Mac Address of each device.
However, the problem is it requires to choose the email when you call the google api for the first time. But as I mentioned above, this app is going to run on AWS, so clearly users cannot choose the email.
So is that possible that we just use the domainName instead of choosing email to do the authentication and access the different directories? If so, is there any examples or documentations I need to read?
I suspect I need to modify this part from the sample, but I am still getting confused how it works.
#app.route('/adminlogin')
def authorize():
# Create flow instance to manage the OAuth 2.0 Authorization Grant Flow steps.
flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
CLIENT_SECRETS_FILE, scopes=SCOPES)
flow.redirect_uri = flask.url_for('oauth2callback', _external=True)
authorization_url, state = flow.authorization_url(
# Enable offline access so that you can refresh an access token without
# re-prompting the user for permission. Recommended for web server apps.
access_type='offline',
approval_prompt="force",
# Enable incremental authorization. Recommended as a best practice.
#include_granted_scopes='true'
)
# Store the state so the callback can verify the auth server response.
flask.session['state'] = state
return flask.redirect(authorization_url)
Any hint will be helpful.

DialogFlow detectIntentText

I am using DF with Python API and here is the code and I can't use the detect intent text.
If I use the second line I get the next error:
google.api_core.exceptions.PermissionDenied: 403 IAM permission 'dialogflow.sessions.detectIntent' on 'projects/newagent/agent' denied.
If I use the first one:
google.api_core.exceptions.InvalidArgument: 400 Resource name 'projects/newagent/agent/environments/draft/users//agent/sessions/5276b6d4-a0b6-4e91-84d3-16512d1f3299' does not match 'projects//agent/environments//users//sessions/'.
I have enabled billing on Google Cloud and the user has Owner privileges. What is going wrong?
def detect_intent_texts(project_id, session_id, texts, language_code):
session_client = dialogflow_v2.SessionsClient()
#----------------------------------------------------------Lines that I talk about in the question---------------------------------------------------------------------------------------------------
#session = session_client.session_path(project_id, session_id)
session = "projects/newagent/agent/environments/draft/users/<user id>/sessions/6344a857-9de5-406c-ba0f-c71b7b3ffdba"
#----------------------------------------------------------Lines that I talk about in the question---------------------------------------------------------------------------------------------------
for text in texts:
text_input = dialogflow_v2.types.TextInput(text=text, language_code=language_code)
query_input = dialogflow_v2.types.QueryInput(text=text_input)
response = session_client.detect_intent(session=session, query_input=query_input)
detect_intent_texts("newagent/agent/environments/draft/users/<User Number>",str(uuid.uuid4()),"Que tal?","es-ES")
The Session ID should have the format projects/<Project ID>/agent/sessions/<Session ID> (being <Project ID> the ID of the GCP project where your agent is located and <Session ID> the ID you use for your ongoing session), as can be seen in this documentation page.
In your code I see that you are calling the detect_intent_texts() function like:
project_id = "newagent/agent/environments/draft/users/<User Number>"
session_id = str(uuid.uuid4())
texts = "Que tal?"
language_code = "es-ES"
I see two main errors here:
The Project ID has the wrong format, it should be the ID of your GCP project, which usually has a format like my-first-project or similar, and slashes / are not supported, so you are using a wrong Project ID.
The text should be a Python list of strings, like ["hello"] and not just "hello".
Just as an example, the following minimal code provides the result below:
import dialogflow
def detect_intent_texts(project_id, session_id, texts, language_code):
session_client = dialogflow.SessionsClient()
session = session_client.session_path(project_id, session_id)
print('Session path: {}\n'.format(session))
for text in texts:
text_input = dialogflow.types.TextInput(text=text, language_code=language_code)
query_input = dialogflow.types.QueryInput(text=text_input)
response = session_client.detect_intent(session=session, query_input=query_input)
print('Fulfillment text: {}\n'.format(response.query_result.fulfillment_text))
detect_intent_texts("my-project","abcd",["hello"],"en-US")
Result:
user#my-project:~/dialogflow$ python detect_intent_minimal.py
Session path: projects/my-project/agent/sessions/abcd
Fulfillment text: Hi!
Therefore I suspect that changing the project_id to its correct value and the texts to a list should solve your issues.
EDIT:
I have been able to reproduce the issue that you are seeing with a 403 PermissionDenied message by using a Service Account without the required permissions.
In order to run intents in Dialogflow, you need to use a Service Account with one of the following roles:
Dialogflow API Admin and Dialogflow API Client can query for intents, and therefore, one of those is required in order to make the type of requests you are trying to do with your script.
I see you said that your user has owner privileges over the project. However, the issue may be that you are using a wrong service account. In order to set up authentication correctly, follow the steps detailed in the docs. In summary, you will have to create a Service Account with the right permissions, download its JSON key, and use it as an environment variable by running the command export GOOGLE_APPLICATION_CREDENTIALS="/path/to/your/key.json" wherever you are running the script.
When an identity calls a Google Cloud Platform API, Google Cloud Identity and Access Management(IAM) requires that the identity has the appropriate permissions to use the resource for which you have to create custom roles and then assign to service account. Then you will use that service account to call Google Cloud Platform API. Here you can search Dialogflow and see that DF is supported with custom roles only. That is why you have google.api_core.exceptions.PermissionDenied: 403 IAM permission 'dialogflow.sessions.detectIntent'. Do following steps:
Go to you project in Google Cloud Platform and then select roles as shown here:
Then click on Create Role, insert role name and related fields. Then click on Add Permissions and in the filter, search 'Service: Dialogflow'. Select the permissions you want and then click on create.
Then select this:
Click on Create Service Account and on Select Role option, type and search for the role you created on step 2 and save the account.
Do this: . A list of service account will show. Click on 'Create credentials' button.
Select the service account created in above steps and choose JSON. Then select Create. A JSON file be downloaded.
Add that file in your code as: os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = 'yourfilename.json'
Create an agent in Dialogflow console with google project for which you did all of the above steps. Enjoy :D

administrator has not consented to use the application -- Azure AD

I am trying to obtain a token from Azure AD from Python client application. I want users to seamlessly authenticate with just a username and password (client_id / secret will be embedded in the app). I registered my app and given it all permissions and hit the "grant permissions" button in the new portal according to this post:
The user or administrator has not consented to use the application - Send an interactive authorization request for this user and resource
I am sending an http post to:
https://login.microsoftonline.com/{tenant_id}/oauth2/token
with the following data:
headers = {
"Content-Type": "application/x-www-form-urlencoded"
}
body = "resource={0}&grant_type=password&username={1}&password={2}&client_id={3}&client_secret={4}&scope=openid".format(app_id_uri,user,password,client_id,client_secret)
I cannot seem to get past this error no matter what I try:
b'{"error":"invalid_grant","error_description":"AADSTS65001: The user or administrator has not consented to use the application with ID \'078c1175-e384-4ac7-9116-efbebda7ccc2\'. Send an interactive authorization request for this user and resource.
Again, my goal:
User enters user / pass and nothing else. App sends user / pass / client_id / client_secret, obtains token.
According to your comment:
The message I'm receiving says to do an interactive request but that is exactly what I'm trying to avoid because this is a python app with no web browser and I'm trying to avoid complexity.
I think you want to build a daemon app or an app only application integrating with Azure AD. You can refer to https://graph.microsoft.io/en-us/docs/authorization/app_only for the general introduction.
Furthermore, you can leverage the ADAL for Python to implement this functionality with a ease. Also, you can refer to client_credentials_sample.py for a quick start.
You should try logging in as an admin to be able to give consent to use the application on your tenant at all.

Categories

Resources