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.
Related
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
I am working on a .net MVC and web API project and using active directory to authenticate users to API, on authentication, a code is being returned from AD and I have to exchange the code to obtain a token and use that token to call the API, the question is why is the code returned and why do I have to exchange it for the token? can I directly obtain a token?
This is all because of security reasons.
OAuth 2.0 wanted to meet these two criteria:
All developers will not have an SSL enabled server and you should allow them to use non-HTTPS redirect URI
You don't want hackers to be able to steal access/refresh tokens by intercepting requests.
Since the Authorization Code grant has the extra step of exchanging the authorization code for the access token, it provides an additional layer of security not present in the Implicit grant type.
According to Nate Barbettini we want the extra step of exchanging the authentication code for the access token, because the authentication code can be used in the front channel (less secure), and the access token can be used in the back channel (more secure).
Thus, the security benefit is that the access token isn't exposed to the browser, and thus cannot be intercepted/grabbed from a browser. We trust the web server more, which communicates via back channels. The access token, which is secret, can then remain on the web server, and not be exposed to the browser (i.e. front channels).
For more information, watch this fantastic video:
OAuth 2.0 and OpenID Connect (in plain English) https://youtu.be/996OiexHze0?t=26m30s (Start 26 mins)
Your question isn't really specific to Azure AD, and is more about the OAuth flow and why it is used.
The flow seems a bit complex, and well, it is, but there are reasons for all the things it does.
I encourage you to use authorization code flow instead of other approaches.
It has many advantages:
Your app will never see the user's password
The user cannot see your app's client secret
The user cannot see your app's access tokens (and neither can a man-in-the-middle attacker)
You get a refresh token that you can use to get new tokens whenever needed (you do need to specify the offline_access scope for this though)
The user can go through multi-factor authentication, federated authentication with ADFS etc., and your app doesn't need to care about that
Alternative flows and their downsides:
Implicit flow
Gives you a token directly without the code exchange
There is no refresh token
Mainly used in Single Page Apps, where refresh is done using a hidden iframe, but that depends on the user's session remaining active
If you use this outside a SPA, you can't really refresh the token, requiring the user to login again every hour
User can see and take your app's access tokens
Client credentials flow
Instead of accessing the API as a user, you access it as the app itself
Some APIs do not support this approach and require you to make calls on behalf of a user
This doesn't allow you to authenticate a user
Application permissions are needed to use this flow, which usually give very broad access to the entire organization
The upside of this flow is that it is very simple
Resource Owner Password Credentials flow
Do not use this flow
HTTP request to token endpoint with app + user credentials
Exposes user password to your app (!)
Does not work if user has MFA, expired password etc.
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.
I've tried acquiring token using ROPC with the username and password provided by client. But the error message was "parsing_wstrust_response_failed". Same as the error message (last error) described here
From this error message I understood my user is a federated user and cannot use this method. Is there any other way to acquire token for a federated user using username and password?
try
{
result = await app.AcquireTokenByUsernamePassword(scopes,
"joe#contoso.com",
securePassword)
.ExecuteAsync();
}
catch (MsalClientException ex) when (ex.ErrorCode=="parsing_wstrust_response_failed"){
}
No. There is no way.
You need to handle the authentication with another flow.
I mentioned this downside in my recent article: https://joonasw.net/view/ropc-grant-flow-in-azure-ad
First, a warning: You really should not use username/password in your app. In general, it's less secure and increases the risk you're exposing the associated environment to. It is also a brittle approach, as you will likely find Azure AD will require an interactive sign-in at some time in the future--probably at a very inconvenient time for you.
Second, a clarification: AcquireTokenByUsernamePassword will not always use the Resource Owner Password Credentials (ROPC) OAuth 2.0 flow. When MSAL discovers that the user is part of a federated domain name, the library will attempt a non-interactive username/password authentication if the federated identity provider publishes an metadata exchange document which includes an endpoint supporting this method. If this request succeeds, MSAL will then attempt to exchange the response (issued by the federated identity provider) for the normal token set from Azure AD (issued by Azure AD).
So, to answer your question: It depends. It is possible to use AcquireTokenByUsernamePassword with a federated user. However, it requires that the federated identity service support this. AD FS, which is the most common IdP to be federated with Azure AD, supports this is the "usernamemixed" endpoint.
Depending on what you are trying to build you could use the AcquireTokenByIntegratedWindowsAuth() instead. Our scenario was we needed a headless console app to be able to send emails and notifications to a Teams channel. We are also Federated, so username\password auth wouldn't work. But since we are running on on Windows we can use integrated auth.
I followed this guide to get the Access Token: https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/wiki/Integrated-Windows-Authentication
Our scenario did require a one time user consent, so the user the console app runs as had the proper permissions. https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/authorize?client_id={clientId}&response_type=code&scope={scopes}
I have an API that uses another API (example google calendar API) which is authenticated with OAuth 2.
httpRequest => MyApi under test => uses external Oauth2 enabled API
If the "Oauth2 enabled API" were using HTTP basic authentication, I could just hardcode the username and password somewhere to test the application —using the username and password of a test user created in the external APP that exposes the API that I am using.
As with Oauth2 we require the user to consent (the user is usually redirected to a web page) to ask them for consent to the app to access their data through the API.
I just want to create simple Integration Test: For example, my API creates an event in the google calendar, then deletes it for cleanup, but without human intervention.
Is this possible and how?
If you're developing an API, then your tests should be against that API only. You are not responsible for the work done in the external Oauth2 API, the author of that API is. Only test your own code.
Which means, you should find a way to mock out the calls to the external API if possible.
I've been wondering about the best way to do this myself.
So far I've found a few of options:
Use the password grant type, to authenticate as a user. This is apparently no longer recommended as per best practices, but that's for end-users. Not for testing.
Use the client_credentials grant type, to authenticate as the app itself. The problem with this is that if your test depends on being able to retrieve user data, the app won't have any associated to itself, unless you manipulate it beforehand.
Request a refresh_token, to re-authenticate as a previously authenticated user. This is done by requesting the offline_access scope. A user will have to do the first authentication, get a refresh token and provision the test script with it. The script then must be able to keep updating itself with a fresh refresh token each time it runs. And if the refresh token should expire before the next run, human intervention will be required again.
Use the device_code grant type to poll for end-user consent elsewhere. This is like what YouTube uses to pair your SmartTV, whereby you start the login on your SmartTV and consent to it with a pairing code on your mobile device. Here, human intervention is required as well for the consent, at least the first time, and then again should the consent expire.