AZURE AD ADAL "error":"invalid_grant","error_description":"AADSTS70000: Transmission data parser failure: Authorization Code is malformed or invalid - azure

I am trying to Authenticate using AZURE AD. I took the java client code from the git [https://github.com/Azure-Samples/active-directory-java-webapp-openidconnect][1].
I am able to make the authorize call and get the Authorization code. By passing the authorization code to get the access token using the acquireTokenByAuthorizationCode method from the oauth2 jar. Here I am getting the below error.
"error":"invalid_grant","error_description":"AADSTS70000: Transmission data parser failure: Authorization Code is malformed or invalid.
How to pass the grant_type=authorization_code to the acquireTokenByAuthorizationCode method?
How to check the post request which got fired? I am not able to see it in the network section of the chrome?
Below is the code:
String authCode = authorizationCode.getValue();
ClientCredential credential = new ClientCredential(clientId,
clientSecret);
AuthenticationContext context;
AuthenticationResult result = null;
ExecutorService service = null;
try {
ThreadFactory factory = ThreadManager.currentRequestThreadFactory();
service = Executors.newCachedThreadPool(factory);
context = new AuthenticationContext(authority + tenant + "/", true,
service);
Future<AuthenticationResult> future = context
.acquireTokenByAuthorizationCode(authCode, new URI(
currentUri), credential, null);
The post request should be:
String redirectUrl = authority
+ this.tenant
+ "/oauth2/v2.0/token?p=b2c_1_abcd&grant_type=authorization_code&resource=https%3a%2f%2fgraph.windows.net&redirect_uri="
+ URLEncoder.encode(REDIRECT_URL, "UTF-8");
Not sure how to provide the information which is in bold.

EDIT after more info
If you are using v2 endpoints, you can't use ADAL.
If you have registered your app in the v2 dev portal, you need to register your app via Azure Portal's Azure AD interface. And then make sure your Azure AD URLs do not include v2.0.
To get a token with authorization code, you use acquireTokenByAuthorizationCode (https://github.com/Azure-Samples/active-directory-java-webapp-openidconnect/blob/master/src/main/java/com/microsoft/aad/adal4jsample/BasicFilter.java#L268-L270):
Future<AuthenticationResult> future = context
.acquireTokenByAuthorizationCode(authCode, new URI(
currentUri), credential, null);
You will not see the request in Chrome because it goes from your web server to Azure AD. The browser is not a part of the chain. And that's a good thing since we are passing the client secret to Azure AD. You can use tools like Fiddler to monitor the traffic.

Related

How to find Audience field for Active Directory OAuth Authentication? (How to send a post request to DevOps from Azure Logic App?)

Please help me with this problem.
I'm trying to send a post request from Azure Logic App to the DevOps to create a release.
I created an http action in my Logic App, This is the uri for creating a release:
https://vsrm.dev.azure.com/{organization}/{project}/_apis/release/releases?api-version=5.0
I'm using Active Directory OAuth for authentication, which I need to provide tenant, client id, audience and secret.
I'm using tenant, client id and secret of my application in Azure Active Directory, but I'm not sure what to use for audience.
Can some one explain for me how to find this audience field?
Do I need to do other things to connect to my DevOps? or define permissions or any other parameters for header?
There will be two approaches for getting authenticated.
Use Azure AD Authentication.
The resource for DevOps is a static value: 499b84ac-1321-427f-aa17-267ca6975798. But, as the DevOps REST API can only set with delegated permission.
You need to use password grant flow to get token:
The token you get will be a bearer token.
The other option is to use personal access token. You can create one in DevOps portal.
And then use it as following:
try
{
var personalaccesstoken = "PAT_FROM_WEBSITE";
using (HttpClient client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Add(
new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic",
Convert.ToBase64String(
System.Text.ASCIIEncoding.ASCII.GetBytes(
string.Format("{0}:{1}", "", personalaccesstoken))));
using (HttpResponseMessage response = await client.GetAsync(
"https://dev.azure.com/{organization}/_apis/projects"))
{
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine(responseBody);
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
Token you get in this way is a basic token.

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.

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 B2C - Failed to acquire token silently

I'm building an application with ASP.NET MVC and WebAPI using this template : Azure AD B2C WebApp / WepAPI. I've configured my Azure B2C AD through the web.config files and when i click "Sign in" i see my identity providers. Login works so far (i see my username on the top right corner) and i'm able to execute the "To-Do List"-Action.
But a soon as i stop the debugger and restart the Application by pressing F5, i get an error when i click on "To-Do List"-Action again.
Failed to acquire token silently. Call method AcquireToken text --> Code
This happens, cause the user is still authenticated, but the NaiveSessionCache is empty after the applications restart. A possible solution would be, to store the token in the OnAuthorizationCodeReceived Handler, but i looks a little bit weird to me
private async Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedNotification notification)
{
string userObjectID = notification.AuthenticationTicket.Identity.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
string authority = String.Format(CultureInfo.InvariantCulture, aadInstance, tenant, string.Empty, string.Empty);
ClientCredential credential = new ClientCredential(clientId, clientSecret);
string mostRecentPolicy = notification.AuthenticationTicket.Identity.FindFirst(Startup.AcrClaimType).Value;
AuthenticationContext authContext = new AuthenticationContext(authority);
AuthenticationResult result = await authContext.AcquireTokenByAuthorizationCodeAsync(notification.Code, new Uri(redirectUri), credential, new string[] { clientId }, mostRecentPolicy);
// Store token in ClaimsIdentity
notification.AuthenticationTicket.Identity.AddClaim(new System.Security.Claims.Claim("Token", result.Token));
}
How do i correct retrieve the bearer token using AuthenticationContext-class for further use in my Angular-SPA client?
Is it a good idea to store the token as a claim within the OnAuthorizationCodeReceived Handler?
The solution uses the Microsoft.Experimental.IdentityModel.Clients.ActiveDirectory package. Is Microsoft.IdentityModel.Clients.ActiveDirectory still not supporting Azure B2C ?
Your cache is empty because it is not being persisted anywhere. Check out http://www.cloudidentity.com/blog/2014/07/09/the-new-token-cache-in-adal-v2/. Search for EFADALTokenCache and you will find the implementation that will help you persist the cache to some storage.
Azure B2C will only be supported via the new library called MSAL available at https://www.nuget.org/packages/Microsoft.Identity.Client. This library is still under preview.

Custom authorization with Azure AD Authentication in OWIN Web API

We are using Azure AD authentication for one of our client application. We want to implement claims based authorization along with it.
Our application set up is Angular Based client app connecting with Web API (both client server secured using Azure AD Bearer Authentication). Server application is hosted using OWIN.
We need to provide custom authorization on server side. There is a provision in Azure AD for adding users and roles. However, that is not enough for us. Our user management is through AD & Security Groups. To gain access to application, users need to part of a base group and further rights (access particular section of application, edit a specific entity etc.) are assigned based on additional groups or given directly to users in the application. Essentially, not all users will be registered in the application and we may have to query the AD using graph API to check which all application specific groups they belong.
OWIN authentication and authorization model is based on Authentication Server and Resource server. We can separate them on need basis. However, in our case, we need to split the authentication and authorization. When the client presents the bearer token, we need to verify if the token is valid and then add claims to user profile. We also need to cache the user claims so that we do not hit the database frequently. (Our client app make multiple Web API calls in one user action.)
What is the location in Identity 2.0 where
I can verify the token &
insert application specific claims
If my entire application revolves around the user authorization and all queries need to be filtered on what data the user can access, which is a more suitable design pattern for the Web API application?
I believe what you're looking for are the Authentication and Authorization filters in the ASP.NET Web API 2.0 stack.
You can implement per-web method authorization by implementing System.Web.Http.Filters.IAuthorizationFilter on an attribute class, then decorate the web action methods of your service controller with that attribute. Web API 2.0 will select a method based on URL routing, notice that there is an attribute on that method implementing IAuthorizationFilter, and will call the ExecuteAuthorizationFilterAsync method on that attribute instance before calling the web method. Placing the authorization step before the web method invocation allows invalid requests to be discarded quickly, before getting into the heavy lifting of parameter binding.
The incoming token is validated by an IAuthenticationFilter implementation which executes before the authorization step.
Documentation and examples are extremely hard to find. Here's one of the few search results that are actually relevant: http://thegrumpycoder.com/post/105427070626/secure-web-services-with-web-api-and-sitecore
you can check if this helps...
UserProfile profile = new UserProfile(); //To deserialize the response stream (JSON)
string tenantId = ClaimsPrincipal.Current.FindFirst(TenantIdClaimType).Value;
AuthenticationResult result = null;
try
{
// Get the access token from the cache
string userObjectID =
ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier")
.Value;
AuthenticationContext authContext = new AuthenticationContext(Startup.Authority, new NaiveSessionCache(userObjectID));
//use ClientID, ClientSecret
ClientCredential credential = new ClientCredential("b557ceed-xxxx-xxxx-xxxx-xxxxxxxbc240", "AXFxx//xxxxxxxxxxxxxjVFz4sqYm8NDAPEOLkU=");
result = authContext.AcquireTokenSilent("https://graph.windows.net", credential,
new UserIdentifier(userObjectID, UserIdentifierType.UniqueId));
// AcquireTokenSilent may throw exception if the cache is empty. In that case, logout the user and make him login.
string requestUrl = String.Format(
CultureInfo.InvariantCulture,
"https://graph.windows.net/cdmsdev.onmicrosoft.com/groups/b40xxxx-14a8-xxxx-9559-xxxxxxca90c8/members/?api-version=1.6");
//Above grap API url is for getting list of users who belong to a specific group (with GUID b40xxxx-1....)
HttpClient client = new HttpClient();
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, requestUrl);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
HttpResponseMessage response = client.SendAsync(request).Result;
if (response.IsSuccessStatusCode)
{
var upn = ClaimsPrincipal.Current.Identity.Name;
string responseString = response.Content.ReadAsStringAsync().Result;
profile = JsonConvert.DeserializeObject<UserProfile>(responseString);
if (profile.Users.Contains(upn)) //check if the current user is in the list of users of the Admin group
return true;
}
}
catch (Exception e)
{
//handle authorization exception here
}
The graph API URL can be replaced with a function to check for membership of a specific group which will directly return a bool value instead of getting all users of that group.

Resources