We have an Azure hosted ‘on-premise’ instance of Dynamics 2016 running as an IFD utilising ADFS authentication. We now have a requirement for an Azure hosted API to communicate with the Dynamics instance using the CRM Web API. To achieve this we need to authenticate using OAuth authentication using ADAL as outlined here https://msdn.microsoft.com/en-gb/library/gg327838.aspx , utilising the Microsoft.IdentityModel.Clients.ActiveDirectory library. We have the following code to retrieve a token from ADFS
var resource = "https://reosurce.com/";
var clientId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
var authProvider = "https://adfs.server.com/adfs/oauth2/token";
var redirectUri = "https://crm2Environment.com/";
var authContext = new AuthenticationContext(authProvider, false);
var authToken = authContext.AcquireTokenAsync(resource, clientId, new
Uri(redirectUri), new PlatformParameters(PromptBehavior.Always)).
Result.AccessToken;
The code example runs successfully, however is for use in an interactive flow situation and as soon as the AcquireTokenAsync method is called login dialog appears (makes sense as how else does ADFS know whether its ok to Authenticate), however this is obviously not going to work on the API which is domain agnostic and there is no way of passing credentials to ADFS (not that We would want to anyway). None of the alternative overloads to the AcquireTokenAsync method appear to be applicable to ADFS in the situation outlined (but open to suggestions). Are we missing something? Is there another way to retrieve the token with a non-interactive flow / without using Domain Account authentication? Bear in mind that the examples available for Azure AD do not appear to work in the ADFS scenario also we do not own or have access to the current ADSF server as this is managed by our infrastructure team (although if there is a requirement for them to make changes on the ADFS this is possible)
What version of ADFS are you using?
If ADFS 4.0 and the flow is server to server (sounds like it is) use client credentials which uses the knowledge of a secret key - no login / password.
Good link here.
Take a look at MSI (Managed Service Identity). This is a new communication protocol for Azure-to-Azure services.
Managed Service Identity (MSI) for Azure resources
As you research this, try not to fall into confusion with the old pattern (which is still valid for Service-to-AzureService communication) This is where you generate a ClientId/ClientSecret/Url on Azure that gives permissions, then share these values with the application that requires access. Here is an example of that Use Azure Key Vault from a Web Application The example demonstrates connecting to Azure Key Vault, but it could be any Azure service that uses Azure Active Directory Authentication.
Related
I have created a Single Page Application with Angular and authentication/authorisation is managed by Azure AD. I have used MSAL.js to initiate the implicit flow.
Everything is working fine, but now my client wants to use her own identity provider (IDP) so that users have a single point of entry for all apps (including mine). This IDP is not mainstream, it is built in-house by the client;
I want to keep using Azure AD to manage authorisations (groups, roles...). I also want my application and its dedicated backend API to be registered in Azure AD, not in the third-party IDP.
Azure AD should remain responsible for providing the Access Token to the SPA in order to call the API.
Somehow, I should redirect the user to the third-party IDP login form and upon successful login it will redirect to my SPA, which should then associate the tokenID with an AzureAD account and retrieve the Access Token (I suppose I will have to create an account in Azure AD for users identified in the third-party provider)
However I'm having a hard time figuring out how to achieve this and if it is at all possible ?
What would be the recommended approach for this scenario ? Can I still use MSAL.js or do I have to rely on something else ?
ARCHITECTURE
Your goals are completely correct and you should not need to change a single line of code to integrate a new IDP - so you can continue to use MSAL.js.
PREREQUISITES
In order to integrate their own IDP into your system you need to insist on certain prerequisites:
The client needs to provide a Standards Compliant Identity Provider
Typically the IDP needs to communicate with your Authorization Server (Azure AD) via either Open Id Connect messages or SAML2P messages
A home grown IDP may not meet these prerequisites in which case you need to explain to the client that they need to get standards compliant.
HOW FEDERATION WORKS
Your UI will redirect to your AS
The AS will redirect to the IDP, when given a trigger
The user will authenticate in the IDP
The IDP will post a token to your AS to identify the user
The AS will issue another token to your UI
Note that there is no coding involved here - there is only standards based integration between vendor systems.
WHAT THE CLIENT WILL GIVE YOU
Client details are often supplied by giving you their metadata document, and these details are then configured in Azure AD as a trust entry:
The entity id of the IDP
The token signing public key for IDP tokens, so that your AS can validate them
A URL to redirect to
WHAT YOU WILL GIVE THE CLIENT
A similar trust entry will need to be configured in the client IDP so that it trusts requests and issues tokens - though no certificate is usually needed here:
The entity id of the AS
A URL to post tokens to
TRIGGERING THE REDIRECT FROM THE AS TO THE IDP
One option is to forward the entity id to the authorization server in Open Id Connect redirects. Often an 'idp' query parameter is used, something like this:
Client accesses your app with a bookmarked URL:
https://app.mycompany.com?idp=urn:client.com
You add an extra parameter to the Open Id connect redirect to tell it where authentication should happen:
https://login.mycompany.com/authorize?client_id=XX&idp=urn:client.com
AZURE AD SPECIFICS
Once you understand the high level process there is some technical stuff to configure the connection and you'll need to consult vendor documentation, such as this Microsoft Azure B2B article.
PRACTICE
If you haven't done this before then you need to invest some time to get a connection working and then document the process.
You can use Windows Server and ADFS to simulate a client connection, then integrate it as a SAML2P connection. There is a learning curve though, and you'll need infrastructure such as ADFS certificates.
We're in a scenario where a single page application that we develop ourselves (AngularJS front end with https server APIs in the back) opens another
web application developed by a partner of ours in a new browser tab, and where this second web application needs access to a https server API that is also developed by us.
After looking around for possible solutions, we have now created a proof of concept using IdentityServer4, where the second web application is configured as a client with "authorization_code" grant type. When all applications are running on the same domain, the third party application is able to access our https server API without being prompted for user id and password.
The implementation of the second web application in this proof of concept is very much like the solution presented by bayardw for the post
Identity Server 4 Authorization Code Flow example
My question now is:
When - in production - the second web application no longer shares domain with our application and our https server API, will a call from the second web application be prompted for username and password when accessing our http server API?
Seems, you are missing some major things. First of all any API should never ask for username and password. Instead your app(s) should put a token into each request and API should validate that token. Where the user credentials should be asked is when a user accesses your (or 3-rd party) web application. Then Identity Provider creates an Identity token (usually to be persisted in a cookie and used within the app) and access token (to be provided to APIs). Each token is issued for specific Client (app) pre-registered in IdP. Probably when been hosted at the same domain your two apps shared the identity cookie and Client Id what is not correct. In production scenario you have to register the apps separately. All the rest should work fine (if you follow the routine i briefly described at the beginning).
Chosing to post an answer myself from feedback through other channels:
This boils down to the session tracking of the IdP. If cookies are being used to track IdP session, the behavior is impacted by whether a session cookie or a persistent cookie is used.
In general, I have found that Robert Broeckelmann has great articles on medium.com.
Not sure if that is possible: I would like to switch from server flow to native client flow in order to provide a better authentication experience for my users.
The problem is that Azure AppService requires a "web application" OAUTH setup (contains client ID and a secret), while the native login works with just a client ID and not secret. This means that after the login on the phone, I do have a Google token, but AppService wouldn't know what to do with it and returns me an HTTP Unauthorized.
The mobile client SDK gives me an API, but that doesn't work with such a token.
var jObject = new JObject(
new JProperty("access_token", auth.AccessToken),
new JProperty("id_token", auth.IdToken));
await ServiceClient.LoginAsync(MobileServiceAuthenticationProvider.Google, jObject);
Any idea on the proper way to integrate this without having to write my own server-side token validation?
You would still need to configure the web application in Google since you are attempting to access a non-Google API. The native login on its own is not enough.
That means you will still need to provide the backend with an ID and secret. The client is responsible for obtaining an id token and authorization code which get sent to the server, and the server does the actual retrieval of the access token, per the Google documentation.
So that means your call will actually look something like the following:
var jObject = new JObject(
new JProperty("authorization_code", auth.ServerAuthCode), // not sure what property your auth binding exposes this as
new JProperty("id_token", auth.IdToken));
await ServiceClient.LoginAsync(MobileServiceAuthenticationProvider.Google, jObject);
There isn't documentation for the end-to-end using Xamarin.Android, but you might find it useful to glance over the App Service iOS documentation for this scenario just to see the moving parts. The general pattern you will follow is:
Configure everything for the server flow (as you've done before)
Set up the Google Sign-in SDK (seems like you've done that already, too).
Make the call as described above
The main issue you might run into is making sure that you have the API console registration correct. You'll want to make sure you have an Android client there connected to the web application client ID you are using. I'd recommend giving the Google Sign-in for Android setup instructions a quick look. Also note that authorization codes are one-time use, and there are some throttles that Google puts in place for a user requesting too many of them within some span of time. You might run into that during dev.
AS far as I know, the native client flow also use the google code flow to get access token.
According to this article, the Android, iOS, or Chrome applications doesn't need the secret to get the access token.
The client secret obtained from the API Console. This value is not needed for clients registered as Android, iOS, or Chrome applications.
But the web app backend will not authorized this access token if you don't set in your backend to enable Azure App Service authentication/authorization. Because the backend will have its own logic(the mobile server library write the logic according to the access token) to return the auth token according to the access token.
Now, the most easily way to enable the client flow in your mobile app is set in your backend to enable Azure App Service google authentication/authorization with the same clientid and secret(based on my test: if you don't set the right secret, the backend will still return the auth token).
Here is the test image:
If you still don't want to enable the app google easy auth, I suggest you could create custom authentication which contains your own logic to check the accesstoekn and get the user information from the google.
If the checked result is success and get the enough value, you could generate the auth token and return to the client side.
More details about how to create custom authentication in the mobile app backend , you could refer to this article.
Currently I have 2 relying parties setup in the same ADFS server; one for my web api and one setup for MVC application. When I get the token for authenticating in MVC app I capture this token to send it to my web api for authentication as well. This token does not work for the web api.
If I specifically make a new call for that relying party(web api) it will work so i think that it is setup correctly in ADFS...
Is there a configuration issue in ADFS not not allow the same token to work for both?
Is this even possible?
Is this the wrong architecture in ADFS?
Should I use one relying party for both apps?
You can use Identity Delegation which helps in scenarios like this where an app calls a service instead of a user.
This similar question has some good resources:
Pass ADFS Token to a Service
I have an application that has been under developpment for quite a while now.
We used OWIN with individual accounts.
The application is asp.Net MVC with WebApi and AngularJs frontend.
The API grew quite a lot and we have cases where we need to give access to clients to the API directly.
Problem is that it is secured using CookieAuthentication.
I would like to use the OAuth that is packaged with OWIN and directly available (though a lot of the implementation is up to the developer as it looks like).
Is it possible to add implementation of the Authorization server (http://www.asp.net/aspnet/overview/owin-and-katana/owin-oauth-20-authorization-server) in the same application or should I deploy another server?
The whole thing is that nothing should change for the users of the web site that is currently deployed, this is just an extra feature to help API security.
Thanks
Yes it's possible to implement your Authorization Server to grant client access to your API.
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/OAuth/Token"),
AuthorizeEndpointPath = new PathString("/Api/Account/ExternalLogin"),
Provider = new MyOAuthAuthorizationServerProvider()
};
I leave the implementation of the OAuthAuthorizationServerProvider to you but you can find some inspiration with the Thinktecture Identity project.
Last step is to register your new middleware:
// Enable the application to use bearer tokens to authenticate users (Authorization Server and Resource Server)
app.UseOAuthBearerTokens(OAuthOptions);
You can then send requests to your API with the access token you received from your OAuth provider using the 'client_credentials' grant type.
Hope it helped.