Windows Service connect to Azure AD as User (MFA) - c#

I have a service which needs to run under user context, because some endpoints of Microsoft need an user context to execute. My problem now is 01.09.2019 MFA is mandatory. So, at least at the beginning, the service needs a person who logs in, but this is not possible because it is an non interactive Windows Service. So my question is, it is possible to login as a user by code or not? If it is, how? And will the refresh token be stored in the aad cache?
UserIdentifier user = new UserIdentifier(Cred.UserName,UserIdentifierType.OptionalDisplayableId);
return Task.Run(() => authContext.AcquireTokenAsync(
"https://api.partnercenter.microsoft.com",
Cred.ApplicationId,
new Uri("http://localhost"),
new PlatformParameters(PromptBehavior.Auto),
user)).Result;

You'll need to have some kind of app that authenticates the user and stores their refresh token in a secure place like an Azure Key Vault.
Your background service can then use the refresh token to get a new access token and new refresh token.
You can use the access token to call the API and store the new refresh token over the old one.
Then if the refresh token does not work, you'll need to repeat the authentication process.
Refresh tokens can go invalid for some reasons, so your app needs to be ready for that.

it is possible to login as a user by code or not?
yes it is possible
In Authentication time the app receives both sign in info (the id_token) and artifacts (ex: an authorization code) that the app can use for obtaining an access token. That token can be used to access other resources -
This sample shows how to use MSAL to redeem the authorization code into an access token, which is saved in a cache along with any other useful artifact (such as associated refresh_tokens) so that it can be used later on in the application.

Related

Azure AD Acquire Token silent From web job

I'm trying to authenticate with Azure AD from windows service, so i tried to get access token using MSAL.NET library with acquiretokenbyIntegratedWindowsauth and it's working good on prem.
The intention is to migrate this windows service to azure web jobs, I challenging to get token that contains onPremisesSamAccountName claim silently from Azure AD without providing username and password.
Any help or workaround to get the token in this way.
Azure WebJobs won't allow usage of integrated Windows authentication.
There are two ways to get a token with user info from a background service:
Refresh token authentication (requires bootstrapping)
ROPC flow (username-password)
The first option's advantage is that no username or password needs to be stored.
But it requires that you have a bootstrapping process where the user signs in, a refresh token is acquired and stored somewhere where the background worker can get it.
The WebJob could then use that to get a token whenever it needs one.
The disadvantage of the first option is that it's more complex and the refresh token can expire, requiring bootstrapping it again.
The second option you might be aware of already as you mentioned not wanting to use username and password.
The advantage is that this approach is simpler, but it comes with that downside of storing a password.
Also the user account cannot have MFA turned on.

Storing Non-AWS API Access Tokens in Cognito User Attributes

Currently, I have configured a desktop UWP C# application which users sign into and register using AWS Cognito Users and User Pools. The application also needs to communicate with another 3erd party API which uses a 1 time registration to return an OAuth2.0 access token and a refresh token. The access token expires ~20mins and then refresh token last the life of the request, typically forever until revoked by the user. I would like to store the refresh token so that it can be retrieved when the user signs in and is validated by Cognito. Is it okay to store this access token in the Cognito user attributes when they register or do I need to store it somewhere else? If I do need to store it elsewhere are there any AWS services which are typically used for this?
There is indeed an AWS service for this specific purpose. Its called AWS Secrets Manager.
Benefits;
Default encryption in storage and transit
You can use IAM to manage access control. So you could lock access down to one or two senior developers
You can use IAM for fine grain access control. This means you can lock the Secret down to a specific user and its secured at the storage level
Very simple to integrate with using the SDKs

Not able to get new refresh token from azure AD with grant type refresh_token called with old refresh token

I am using Azure Service management API and OAuth API for generating Access token. But while making the call for grant type "refresh_token", to refresh access token it returns new access token but that response does not has new refresh token. So I have to use old refresh token for refreshing access token. And the problem is after 5-6 hours, refreshing token returns error invalid_client(Error validating credentials. Invalid client secret is provided).
In other cases like Office 365 app authentication via Azure AD it returns everything.
Is there is any specific parameter or header that I have to pass with the API call ?
Below is the screenshot of my code
Please help.
Thanks in advance
If you use the v2 endpoint scopes are requested dynamically and a refresh token must be requested using "offline_access" scope. This is much different than in the v1 model, where scopes are pre-registered with the app registration and a refresh token is always returned w/o explicit scope. If you're using v1 & you don't get refresh token, it might be due to restricted security policy about refresh tokens by your ADFS provider, which is not sending back a refresh token to the API calling the OAuth authentication and authorization.
This is security enhancement/block to disable your application not to hold a lifetime refresh token that can be lived forever (if refreshed).
So if you can use v2 endpoint - use offline_access scope. Otherwise check security policies with you ADFS provider.
I run into the same problem as you & gathered most of the information that helped to answer this question from here:
https://stackoverflow.com/a/44813531/4446128.

Obtaining a token on behalf of a user in a multi-tenanted, azure AD based application - No permission to access user information is configured?

I am currently prototyping an authentication model for a series of cloud based micro services and have run into a wall when trying to obtaining a token from Azure AD on behalf of the authenticated user. I feel I am missing something obvious so I am hoping someone can point me in the right direction.
Overview
My prototype consists of two applications:
An Asp.MVC base UI
A WebAPI based data service.
Both applications are hosted in azure and use Azure's active directory for access management. In azure, I have set up two AD instances:
Service Directory: This is the master directory where all applications are registered.
Tenant Directory: The AD instance for the tenant. Going forward, there would be one of these per tenant.
Both the UI and data service are registered in the service directory and set to multi-tenant. The UI authentication is based on Vibronet's multi-tenant sample and correctly pushes the users through the consent grant flow when they first log in, and then registers the UI application with the users AD instance. During the consent grant, the UI requests the following permissions:
Access your organization's directory
Enable sign-on and read users' profiles
Read and write directory data
Read directory data
The user is then redirected back to the UI application and I can successfully view the users claim information at this point. So, up until this point I believe everything is configured and working correctly.
The Problem
Once the user is authenticated, the UI application should then obtain a token on behalf of the current user to access the back-end data service and this is where the problem lies.
The authentication for the data service is based on WebApi-On-Behalf-of sample however whenever I attempt to obtain the token, I get the following error:
No permission to access user information is configured for [AppGuid] application, or it is expired or revoked
Given the permissions granted during the consent flow, however, I believe it should have permissions to access the tenant AD instance and have tried giving the UI application all application and delegated permissions available in AD and re-running the consent flow but still get the same result.
My code for obtaining the on-behalf-of token is as follows:
ClientCredential uICredentials = new ClientCredential(StartUp.UiClientId, StartUp.UiSecret);
BootstrapContext bootStrapContext = GetBootstrapContext();
UserAssertion userAssertion = new UserAssertion(bootStrapContext.Token);
AuthenticationContext authContext = new AuthenticationContext(StartUp.adAuthority);
var authResult = authContext.AcquireToken(routerServiceResourceId, uICredentials, userAssertion);
with the exception being raised on the final line. The parameters here are:
StartUp.UiClientId: The application id for the UI in the service directory.
StartUp.UiSecret: The secret key for the UI app in the service directory.
StartUp.adAuthority: I have tried this with the common AD endpoint for multi-tenant applications (https://login.microsoftonline.com/common/) and with the specific endpoint for this tenant (https://login.microsoftonline.com/tenantid). Both give the same result.
routerServiceResourceId: The App Id URI for the data service.
In addition, I have set 'SaveSigninToken' to true in the TokenValidationParameters for the UI application so I can obtain the BootstrapContext.Token.
As far as I can see, this is everything it should need to work but, as I say, I continually get the error above =/
Can anyone suggest a way forward / obvious solution / further reading for this. I seem to be banging my head against this and not getting very far. I am also not 100% what information is pertinent here regarding the problem so if I have missed any important points, please let me know and I can update the question.
The OnBehalf of flow isn't really appropriate in this case. The OnBehalf of flow is appropriate when a WebAPI receives an access token and needs to get an access token for a downstream WebAPI. The flow that is most appropriate in your case is the OpenID Connect code+id_token flow. In this flow the WebApp receives an id_token that authenticates the user and an authorization code that allows the WebApp to get an access token for a back end server. The WebApp then redeems the authorization code for the access token.
The best example of this flow is here:
https://github.com/AzureADSamples/WebApp-WebAPI-OpenIDConnect-DotNet
Pay attention to Startup.Auth.cs where the AuthorizationCodeRecieved notification is set up. This shows how to retrieve the code and redeem it.

Facebook Graph API: Have app access token, need user access token without interaction

We have an audio blogging website which can be configured to publish links to the user's Facebook timeline whenever they make a new blog entry.
To do this, we have the user authorise our app when they set up the link to their Facebook account. We obtain the publish_stream, offline_access and manage_pages permissions (more on that later).
All the code is in C# but the principles apply to any language as it's the workings of the Facebook API we are concerned with. We're using OAuth 2 and the Graph API to achieve all of this.
So, we obtain an app access token using our app ID and secret and use that token to publish to the user's timeline, this works fine (because they have already authorised our app to do this). We can also query the Graph API and get their likes, friends and various other data.
NOW HERE IS THE PROBLEM:
Some of our users want to publish updates to their own timelime and also to the timelines of pages that they manage. In theory this is simple: you query the API for the pages that the user manages using this url: https://graph.facebook.com/{userid}/accounts?access_token={token}
The JSON returned from this call is said to contain the page IDs and the page access tokens for those pages. You then use the page access token to publish to the pages' timelines.
However, when we try to call this URL with the app access token we are getting an OAuthException 102 "A user access token is required to request this resource".
Note this is different to OAuthException 104 "An access token is required to request this resource" (which is what you'd get if you neglected to pass an access token), and also OAuthException 190 "Invalid OAuth access token signature" (which you would get if the access token was not a valid one).
So our access token is valid, but just not valid for this particular url. It seems therefore that we need a user access token and not an app access token for this particular feed (I am long past caring why this is the case, it just seems to be the way it is).
All the Facebook documentation on this subject (and I must have read all of it by now) leads to one place: http://developers.facebook.com/docs/authentication/server-side/, aka the "Server-Side Authentication Flow" page. This page describes how to get the elusive user access token by redirecting the user to the auth dialog and asking for the relevant permissions but we need to achieve this without interaction from the user and the user has already given our app all the permissions we need. All of this automated publishing happens server side in the post-processing of the audio so we cannot interact with the user at this stage anyway.
I don't get it. Why is it we can use the app access token to get almost any data we want from the user (well, whatever they have given us permission to get) but the /accounts data we need a different (user) access token for?
Can anyone shed any light on how we can get a user access token which will allow us to get the /accounts data for our users without any further interaction from the user?
So our access token is valid, but just not valid for this particular url. It seems therefore that we need a user access token and not an app access token for this particular feed
Due to the permissions per type of access token, you do need a valid user access token in this particular case. Read all about access tokens and types. That's just the way it is.
This page describes how to get the elusive user access token by redirecting the user to the auth dialog and asking for the relevant permissions but we need to achieve this without interaction from the user and the user has already given our app all the permissions we need.
If your user already has given his/her permissions, why are you struggling then? I suggest you persist the user access token. From this endpoint:
https://www.facebook.com/dialog/oauth?client_id=..&redirect_uri=..&state=..&scope=..&response_type=..&display=.."
you retrieve a code, like this:
YOUR_REDIRECT_URI?code=OAUTH_CODE_GENERATED_BY_FACEBOOK&state=YOUR_STATE_VALUE
Use this code to generate your user access token, as explained here:
https://graph.facebook.com/oauth/access_token?client_id=..&redirect_uri=..&client_secret=..&code=..
This will result in a response like:
access_token=USER_ACCESS_TOKEN&expires=NUMBER_OF_SECONDS_UNTIL_TOKEN_EXPIRES
There it is, your user access token. Persist it. As you can see it expires after the value indicated in the response. If you are using the new API, it should indicate 60 days (that brings me back to this: offline_access is deprecated and results in short-lived - valid for 2 hours - tokens), link. Whenever your user logs in to your app and uses the Facebook integration, the tokens gets refreshed to again, 60 days. This means, that IF your user should not login to your app and use it for 60 days, it will expire.
You can check whether the user access token is expired with:
https://graph.facebook.com/debug_token?input_token=INPUT_TOKEN&access_token=ACCESS_TOKEN
If that does: renew the user access token by using your app access token, it is well documented right over here. But I'm quoting this part:
Server-side Login
To obtain a fresh [user] access token in this case you must pass the user through the full server-side Login flow again. However, assuming the user has not de-authorized your app, when you redirect the user to the OAuth Dialog, they will not be prompted to reauthorize your app, and will be immediately redirected to the redirect_uri. This means that the re-authentication process can appear reasonably transparent to the user.
Bottom-line: there are no user access tokens that are valid for ever, the app access token however is. Persist your user access token and check whether it is still valid before performing API calls with it. A normal user should use your app within 60 days and should not just de-authorize your app for fun. Hence the use case in which the user should re-authorize is fairly rare, however, you need to expect it.

Categories