Azure AD OpenId Connect Token Authentication - azure

I am stuck with Azure Active Directory OpenId.
I Have a ReactJs Web Client that does Authentication to Azure AD, When signed in a token_id is return representing a JWT token. This will be passed back to a ASP.Net Core Web Api and then Authenticated with the JwtSecurityTokenHandler in System.IdentityModel.Tokens.Jwt.
This is wired up with the Middelware when the application starts. When you access the OpenIdConnectOption Events on TokenValidated call, the token is validated already in the back end. A TokenValidatedContext get passed in to the Event Method which contains the JwtSecurityToken and I have access to the whole JWT Token.
I created a separate validation service that takes in the token string.
public ClaimsPrincipal ValidateToken(string token)
{
SecurityToken validatedToken;
var sectoken = TokenHandler.ReadJwtToken(token);
var tokenValidationParams = new TokenValidationParameters()
{
ValidAudiences = sectoken.Audiences,
ValidIssuer = sectoken.Issuer,
};
return TokenHandler.ValidateToken(token, tokenValidationParams, out validatedToken);
}
Is that the SigningKey object is null and the ValidateToken fails. If I do the same validation in the Event call then the SigningKey is valid and the cert is set to Microsoft Cert that seems to be issues by the Azure AD Service.
The main objective is to have a separate Token Validation Service.
Thanks in advance.

Related

Get a Power BI access token after logged into Azure AD

I have code that logs me into Azure AD, but I cant' figure out how to get the access token to call the REST API's or PowerBI
There is the sample code to get access token for Power BI REST API.
//The client id that Azure AD created when you registered your client app.
string clientID = "{Client_ID}";
//RedirectUri you used when you register your app.
//For a client app, a redirect uri gives Azure AD more details on the application that it will authenticate.
// You can use this redirect uri for your client app
string redirectUri = "https://login.live.com/oauth20_desktop.srf";
//Resource Uri for Power BI API
string resourceUri = "https://analysis.windows.net/powerbi/api";
//OAuth2 authority Uri
string authorityUri = "https://login.microsoftonline.com/common/";
// AcquireToken will acquire an Azure access token
// Call AcquireToken to get an Azure token from Azure Active Directory token issuance endpoint
AuthenticationContext authContext = new AuthenticationContext(authorityUri);
var token = authContext.AcquireTokenAsync(resourceUri, clientID, new Uri(redirectUri)).Result.AccessToken;
Console.WriteLine(token);
For more details, see here.

Service to service authentication in Azure without ADAL

I configured azure application proxy for our on-premise hosted web service and turned on Azure AD authentication. I am able to authenticate using ADAL but must find a way to get the token and call web service without ADAL now (we are going to use this from Dynamics 365 online and in sandbox mode I can't use ADAL). I followed some examples regarding service to service scenario and I successfully retrieve the token using client credentials grant flow. But when I try to call the app proxy with Authorization header and access token, I receive an error "This corporate app can't be accessed right now. Please try again later". Status code is 500 Internal server error.
Please note the following:
I don't see any error in app proxy connectors event log.
I added tracing on our on-premise server and it seems like the call never comes there.
If I generate token with ADAL for a NATIVE app (can't have client_secret so I can't use client credentials grant flow), I can call the service.
I created an appRole in manifest for service being called and added application permission to the client app.
This is the way I get the token:
public async static System.Threading.Tasks.Task<AzureAccessToken> CreateOAuthAuthorizationToken(string clientId, string clientSecret, string resourceId, string tenantId)
{
AzureAccessToken token = null;
string oauthUrl = string.Format("https://login.microsoftonline.com/{0}/oauth2/token", tenantId);
string reqBody = string.Format("grant_type=client_credentials&client_id={0}&client_secret={1}&resource={2}", Uri.EscapeDataString(clientId), Uri.EscapeDataString(clientSecret), Uri.EscapeDataString(resourceId));
HttpClient client = new HttpClient();
HttpContent content = new StringContent(reqBody);
content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/x-www-form-urlencoded");
using (HttpResponseMessage response = await client.PostAsync(oauthUrl, content))
{
if (response.IsSuccessStatusCode)
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(AzureAccessToken));
Stream json = await response.Content.ReadAsStreamAsync();
token = (AzureAccessToken)serializer.ReadObject(json);
}
}
return token;
}
AzureAccessToken is my simple class marked for serialization.
I assume it must be something I haven't configured properly. Am I missing some permissions that are required for this scenario?
Any help is appriciated.

Azure B2C - JWT Signature validation failed

I have setup MSAL to fetch tokens from Azure AD B2C, setup dotnet core WebAPI to accept JWT tokens. Pointed WebApi at the Authority Endpoint:
services.AddAuthentication(options =>
{
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(jwtOptions =>
{
string tenant = Configuration["AzureAdB2C:Tenant"], policy = Configuration["AzureAdB2C:Policy"], clientId = Configuration["AzureAdB2C:ClientId"];
jwtOptions.Authority = $"https://login.microsoftonline.com/tfp/{tenant}/{policy}/v2.0/";
jwtOptions.Audience = clientId;
jwtOptions.Events = new JwtBearerEvents
{
OnAuthenticationFailed = AuthenticationFailed
};
});
as per the samples. MSAL is configured to use the same policy and same client Id and receives token.
MSAL Authority - https://login.microsoftonline.com/tfp/{tenant}.onmicrosoft.com/{policy}/v2.0.
However, that AuthFailed event handler just returns
IDX10501: Signature validation failed. Unable to match keys.
and bounces the auth as a 401.
I went looking for signing keys and the kid of the token is not the same as the kid listed at the discovery endpoint.
https://login.microsoftonline.com/tfp/{tenant}/{policy}/discovery/v2.0/keys
Any ideas?
Seems that I had not selected the correct Issuer claim setting. MSAL was grabbing its token using the https://login.microsoftonline.com/{guid}/v2.0 endpoint whereas WebAPI was using the https://login.microsoftonline.com/tfp/{guid}/{policy}/v2.0/ issuer.
As per the docs this isn't an openid compatible endpoint, but works fine for B2C. Pays to check over the two different claim sets!

Using Oauth to protect WebAPI with Azure active directory

I have browsed all the tutorials regarding using Oauth to protect WebAPI in Azure active directory online. But unfortunately, none of them can work.
I am using VS 2017 and my project is .net core.
So far what I have tried is:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
ervices.AddAuthentication(); // -----------> newly added
}
In "Configure", I added:
app.UseJwtBearerAuthentication(new JwtBearerOptions
{
AutomaticAuthenticate = true,
AutomaticChallenge = true,
Authority = String.Format(Configuration["AzureAd:AadInstance"], Configuration["AzureAD:Tenant"]),
Audience = Configuration["AzureAd:Audience"],
});
Here is my config:
"AzureAd": {
"AadInstance": "https://login.microsoftonline.com/{0}",
"Tenant": "tenantname.onmicrosoft.com",
"Audience": "https://tenantname.onmicrosoft.com/webapiservice"
}
I have registered this "webapiservice" (link is: http://webapiservice.azurewebsites.net) on my AAD.
Also, to access this web api service, I created a webapi client "webapiclient" which is also a web api and also registered it on my AAD and requested permission to access "webapiservice". The webapi client link is: http://webapiclient.azurewebsites.net
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://webapiservice.azurewebsites.net/");
//is this uri correct? should it be the link of webapi service or the one of webapi client?
HttpResponseMessage response = client.GetAsync("api/values").Result;
if (response.IsSuccessStatusCode)
{
var result = response.Content.ReadAsAsync<IEnumerable<string>>().Result;
return result;
}
else
{
return new string[] { "Something wrong" };
}
So theoretically, I should receive the correct results from webapiservice. but I always received "Something wrong".
Am I missing anything here?
You need an access token from Azure AD.
There are plenty of good example apps on GitHub, here is one for a Daemon App: https://github.com/Azure-Samples/active-directory-dotnet-daemon/blob/master/TodoListDaemon/Program.cs#L96
AuthenticationResult authResult = await authContext.AcquireTokenAsync(todoListResourceId, clientCredential);
This app fetches an access token with its client id and client secret for an API. You can follow a similar approach in your case. You can just replace todoListResourceId with "https://graph.windows.net/" for Azure AD Graph API, or "https://graph.microsoft.com/" for Microsoft Graph API, for example. That is the identifier for the API that you want a token for.
This is the way it works in AAD. You want access to an API, you ask for that access from AAD. In a successful response you will get back an access token, that you must attach to the HTTP call as a header:
Authorization: Bearer accesstokengoeshere......
Now if you are building a web application, you may instead want to do it a bit differently, as you are now accessing the API as the client app, not the user. If you want to make a delegated call, then you will need to use e.g. the Authorization Code flow, where you show the user a browser, redirect them to the right address, and they get sent back to your app for login.
To call web api protected by azure ad , you should pass this obtained access token in the authorization header using a bearer scheme :
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authResult.AccessToken);

Azure samples - WebApp-WSFederation-DotNet

The sample app can be found here --> https://github.com/Azure-Samples/active-directory-dotnet-webapp-wsfederation.
The application is using Microsoft.Owin and this is what I am expecting:
Users navigate to your application.
Your application redirects anonymous users to authenticate at Azure AD, sending a WS-Federation protocol request that indicates the application URI for the realm parameter. The URI should match the App ID URI shown in the single sign-on settings.
The request is sent to your tenant WS-Federation endpoint, for example: https://login.windows.net/solexpaad.onmicrosoft.com/wsfed
The user is presented with a login page, unless he or she already has a valid cookie for the Azure AD tenant.
When authenticated, a SAML token is returned in the HTTP POST to the application URL with a WS-Federation response. The URL to use is specified in the single sign-on settings as the Reply URL.
The application processes this response, verifies the token is signed by a trusted issuer (Azure AD), and confirms that the token is still valid.
My Question:
After the authentication a SAML token is returned via the HTTP POST. How can I view the SAML response? Currently when I view the HttpContext after POST there is nothing in it.
Thanks for any help.
In the App_Start/Startup.Auth.cs, you should be able to get access to the token.
I've added the SecurityTokenReceived Func:
app.UseWsFederationAuthentication(
new WsFederationAuthenticationOptions
{
Wtrealm = realm,
MetadataAddress = metadata,
Notifications = new WsFederationAuthenticationNotifications
{
AuthenticationFailed = context =>
{
context.HandleResponse();
context.Response.Redirect("Home/Error?message=" + context.Exception.Message);
return Task.FromResult(0);
},
SecurityTokenReceived = context =>
{
// Get the token
var token = context.ProtocolMessage.GetToken();
return Task.FromResult(0);
}
}
});

Resources