Is it possible to connect a local Python app to Azure OIDC? - python

My setup is as follows:
I make API calls from python scripts activated in excel, using the wonderful xlwings.
This enables complex data extraction and transformation workflows to be coded in nice python instead of annoying VBA. It also makes these workflows available to non-coding users at the click of an embedded button.
My problem:
My API calls used hardcoded API keys in the past. This is a big security no-no. Now my API calls need to go through OIDC (OAuth2) authentication in Azure AD.
My questions:
Is it possible to trigger OIDC authentication (in Azure AD) from a local Python script?
Where could I securely store my client secret in such a setup?

Yes you can do this. You don't say which APIs you are calling but any of them act the same.
There are two types of authentication: interactive and non-interactive. You'll need to describe the one you want, but since you're concerned about hard-coded keys, let's assume that you want interactive.
This means that when a user wants to access the data, the user is prompted for credentials in a browser. An access token is returned to the application which is then used to call the APIs. No hardcoded keys are used and the token expires after a period of time.
You can get started by referring to this documenation: https://learn.microsoft.com/en-us/azure/developer/python/azure-sdk-authenticate

Related

How to sign in with Firebase Auth using python

I'm trying to make an app and I can't figure out how to sign in to a user with the python library firebase_admin. I don't have any code as of this moment. Let me know if you can help me out.
The Firebase Admin SDK is designed to be used in a trusted environment, such as your development machine, a server you control, or Cloud Functions/Cloud Run. It gets its authorization from its context or from a credentials file that you provide to it, and which gives it full, administrative access to the project. Therefor it doesn't need, and doesn't have a way, to sign in as a specific user.
If your use-case requires that you sign a user in to Firebase from your Python code, you can consider calling the REST API to authenticate. But the use-case for this would typically be to then pass the ID token you receive back to a user (similar to the use-case in creating custom tokens).

Daemon application authentication for OneDrive files

I have a OneDrive for Business user account within a large organization. I'd like to have a daemon service running (Python) that automatically uploads files to this user's OneDrive.
This service will be running in a headless VM, so browser-based authentication (especially if it needs to be done more than once) is very difficult.
What are my options for authenticating this app to allow it to write to the user's OneDrive? I've registered an app and created a client secret for it. I was experimenting with the authorization flow described here, but that SDK is deprecated and no longer supported, so I'd prefer to use Graph if possible.
What are my options for authentication with Python in this scenario, and is any sample code / example available?
Both delegated and application permissions are supported on MS Graph API: https://learn.microsoft.com/en-us/graph/api/drive-list?view=graph-rest-1.0&tabs=http. Application permissions might not be acceptable for your use case since they would allow access to all users' OneDrives?
Application permissions would definitely be the easiest choice.
But you can also implement this scenario using delegated permissions
You would need the user to initialize the process by authenticating interactively once.
When they do that, store the refresh token in a secret store accessible by the server application.
Then it can use the refresh token to get a new refresh token + access token when needed.
This approach has some more complexity but does allow you to only give access to this one user's OneDrive for the app.
Also, keep in mind that refresh tokens can expire.
The user would need to re-authenticate if that happens.
If this process is critical, application permissions can be a really good idea despite the downsides.

Can you change the authority in a MSAL ConfidentialClientApplication after instantiating it?

I am working on a multi-tenant Azure AD application using the Client Credentials flow, and relying MSAL for Python to obtain the tokens needed to call the MS Graph API. The application itself is a mixture of a deamon and web app, meaning that no users can be directly signed in, but either when invoked or periodically it needs to make the MS Graph API calls on their behalf. I have registered the application properly, and the admins have granted the application permissions for all the tenants.
Upon requesting the tokens as described here and here, for the home tenant with the corresponding authority, I managed to successfully call the Graph API for a user within that tenant. However, when I tried to invoke MS Graph API for a user within the other tenant, (presumably as expected) it results in an erroneous response.
I am sure that the permissions have been granted because if I re-instantiate msal with a different authority or manually invoke the /token endpoint as described here, I successfully retrieve the Graph API data for the corresponding user.
I have not posted any code as the questions are more related to the design and MSAL for Python itself. Also, to do the sanity check, I have tried directly setting the authority field within the instantiated msal app but that doesn't make a change. After a bit more digging in the MSAL source, I realised that it doesn't change because the initialisation of the app creates the authority in the constructor, and the use of neither ConfidentialClientApplication(...).aquire_token_for_client(...), nor Client(...).aquireTokenForClient(...) on which the former relies, fiddles with the authority itself. Finally, I couldn't find any issues on the repository, anything in the docs, nor any questions on SO which were able to answer my question.
Therefore, as the tenants I need to interact with might change, and as I feel that instantiating the MSAL app every time I need to request an access token within my own endpoint creates a bit of an overhead, my questions are:
Am I missing something obvious?
Is it possible to change the authority after creating the msal instance?
If it is not possible, what would be the optimal way to handle the acquiring of access tokens for each tenant within this use case?
Thenk you in advance!
EDIT:
I have managed to find something which might be useful. It is a sample flask app provided by Azure, in which msal app is created every time by invoking the _build_msal_app() method. Nonetheless, my question if this is the optimal way still remains, even though the answer is probably in line with Azure's implementation.

How to create an API with a "remember me" function in Flask?

I'm going to build an API in Flask for a (to be created) app which will be built using PhoneGap. In the API many calls will need authentication.
To get into the topic I was reading this tutorial on creating authentication for a Flask-built API. In this tutorial they first show how a user can use basic password authentication for every call, after which token based authentication is introduced.
As far as I understand, the client who calls the API should simply get a token and authenticate every subsequent call with that. In the meantime, the client should keep track of time and either get a new token every 9 minutes (before the old token expires) or simply keep on calling with the token until the client gets an Unauhorized Access message. Am I understanding this correctly?
Moving on, I wonder how it works with Apps on which you login on your phone and then are always logged in whenever you open the app (like for example the Facebook app). This is obviously more convenient to the user than always needing to provide the username/password and I would like to implement something like that as well. I wonder though; how is a permanent logged in feature like this implemented on the server side? Is it done by providing the password and username for every call, or using a never expiring token, or yet a different way?
All tips are welcome!
I've done what you want to do with:
Flask-security https://pythonhosted.org/Flask-Security/:
To manage users and permissions.
Flask-oauth-lib https://flask-oauthlib.readthedocs.org/en/latest/:
Provide oauth functionnality.
So, you have to take a look at Oauth flow, implements a user backend (like Flask-security) and implements an oauth server (with flask oauth lib for example) and bind it to your user backend.
After that, it's oauth standard flow. You just have to give the right token on each api calls and TADA !
With this way you can also, if you want, give access to your api to third-party app thanks to oAuth :)

GAE: Can't Use Google Server Side API's (Whitelisting Issue)

To use Google API's, after activating them from the Google Developers Console, one needs to generate credentials. In my case, I have a backend that is supposed to consume the API server side. For this purpose, there is an option to generate what the Google page calls "Key for server applications". So far so good.
The problem is that in order to generate the key, one has to mention IP addresses of servers that would be whitelisted. But GAE has no static IP address that I could use there.
There is an option to manually get the IP's by executing:
dig -t TXT _netblocks.google.com #ns1.google.com
However there is no guarantee that the list is static (further more, it is known to change from time to time), and there is no programatic way I could automate the use of adding IP's that I get from dig into the Google Developers Console.
This leaves me with two choices:
Forget about GAE for this project, ironically, GAE cannot be used as a backend for Google API's (better use Amazon or some other solution for that). or
Program something like a watchdog over the output of the dig command that would notify me if there's a change, and then I would manually update the whitelist (no way I am going to do this - too dangerous), or allow all IP's to use the Google API granted it has my API key. Not the most secure solution but it works.
Is there any other workaround? Can it be that GAE does not support consuming Google API's server side?
You can use App Identity to access Google's API from AppEngine. See: https://developers.google.com/appengine/docs/python/appidentity/. If you setup your app using the cloud console, it should have already added your app's identity with permission to your project, but you can always check that out. From the "Permissions" Tab in cloud console for your project, make sure your service account is added under "Service Accounts" (in the form of your_app_id#appspot.gserviceaccount.com)
Furthermore, if you use something like the JSON API Libs available for python, you can use the bundled oauth2 library to do all of this for you using AppAssertionCredentials to authorize the API you wish to use. See: https://developers.google.com/api-client-library/python/guide/google_app_engine#ServiceAccounts
Yes, you should use App Identity. Forget about getting an IP or giving up on GAE :-) Here is an example of how to use Big Query, for example, inside a GAE application:
static {
// initializes Big Query
JsonFactory jsonFactory = new JacksonFactory();
HttpTransport httpTransport = new UrlFetchTransport();
AppIdentityCredential credential = new AppIdentityCredential(Arrays.asList(Constants.BIGQUERY_SCOPE));
bigquery = new Bigquery.Builder(httpTransport, jsonFactory, credential)
.setApplicationName(Constants.APPLICATION_NAME).setHttpRequestInitializer(credential)
.setBigqueryRequestInitializer(new BigqueryRequestInitializer(Constants.API_KEY)).build();
}

Categories

Resources