please kindly help me out with my attempt to implement client side authentication for a xamarin forms aplication i am developing. i have followed every single tutorial on how to integrate Azure active directory into xamarin when using azure mobile services. the error is always thrown at the point of calling loginAsync. on futher investigation using the azure log i found out that the error was coming from the easyauthmodule. please help like i said i have followed every single tutorial on this issue and i have been on it now everyday for the past one week
please find my code below
try
{
AuthenticationContext ac = new AuthenticationContext(authority);
ac.TokenCache.Clear();
AuthenticationResult ar = await ac.AcquireTokenAsync(resource, clientId, new Uri(returnUri), new PlatformParameters(this));
JObject payload = new JObject();
payload["access_token"] = ar.AccessToken;
// DataRepository.DefaultManager.CurrentClient.Logout();
user = await DataRepository.DefaultManager.CurrentClient.LoginAsync(MobileServiceAuthenticationProvider.WindowsAzureActiveDirectory,payload);
}
catch (Exception ex)
{
CreateAndShowDialog(ex.Message, "Authentication failed");
}
EasyAuth is incompatible with Azure Mobile Services. Are you sure you are using the right service moniker?
Make sure you are using the following NuGet for Azure Mobile Apps: https://www.nuget.org/packages/Microsoft.Azure.Mobile.Client/
EasyAuth is only available in Azure App Service. You need to configure the App Service Authentication / Authorization module. Assuming you have already integrated ADAL into your Xamarin app and have an access token from ADAL, your code is pretty close. However, I've found that configuration of AAD for mobile apps is complex. So I wrote a couple of blog posts about it.
Here is the server flow edition: https://shellmonger.com/2016/04/04/30-days-of-zumo-v2-azure-mobile-apps-day-3-azure-ad-authentication/
Here is the client flow edition: https://shellmonger.com/2016/04/06/30-days-of-zumo-v2-azure-mobile-apps-day-4-adal-integration/
Both are using Cordova as a mobile client, but the configuration of the service is identical. The client details (aside from the obvious language differences) are similar as well.
Related
I have a .net core 2.2 api setup and deployed to Azure. I have used OpenId Connect to handle the authentication using azure active directory single tenenat using the code below. And the Authorize decorator on my controller. Everything works and when I browse to my azure deployed api (myappname.azurewebsites.net) I get microsoft login prompt. I'm able to then login and view my route data.
services.AddAuthentication(auth =>
{
auth.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
auth.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
auth.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(opts =>
{
Configuration.GetSection("OpenIdConnect").Bind(opts);
opts.Events = new OpenIdConnectEvents
{
OnAuthorizationCodeReceived = ctx =>
{
return Task.CompletedTask;
}
};
opts.Scope.Add("openid");
opts.Scope.Add("profile");
opts.Scope.Add("access_as_user");
});
The problem is that when I have the Authorization turned on for my controller, I am not able to call it form my angular SPA client application. I have successfully configured MSAL and my api calls are passing a token. However, I get the following error:
https://login.microsoftonline.com/bit4f574-5968-4a40-049d-1c0dc2ca0513/oauth2/authorize?client_id=caor847f-dd19-4489-bef7-684803728c665&redirect_uri=https%3A%2F%2Fmyapi.azurewebsites.net%2Fsignin-oidc&response_type=code%20id_token&scope=openid%20profile%20user_access&response_mode=form_post&nonce=637373859487758409.MzhhYTAoeiudtMTdlNS00NzgxLWJjMTQtNzM1YWE3NsdlkelasdNGYxMmQtMjZmYS00YmI2LTgwY2UtNDEwMTNhMWNkN2Zi&state=CfDJ8KCu3Hr4UOhLjOspjLNEh0VtJd4GNXqwdibjSiZf7FpUJOL0EDlFso0g0s_iOZHDNbP2aiHVfdzqJSmHkesd-bMjP6ThYva6AfZBa8UZcnGcwgo2ldlg4Fx9vmNVDuSlvHyTlHkd8yNndslkgoyHtfM4RMXamq1wny1J39BZRRATn1RdAsgaLgKP_QkxLaDCwgvdzjp3dKls5UVQE1j7MD6bcKR__1-VmfVKhROn1coQh7OJrea6Jni4jdV7e0wv70TVprGtseJFg8fyHg3KKW14xeX2orlkgls5aLe1uG0c5ehlapFXBirBSgFU3uqOWw0_iLeJUbTL8-HPooixynQRWe1WoiLnQuFYUu7Lx-usdlglvM4WvLfAyTZ5uQY_KsOtr08MxWRlQ5HHVk8Moe1k_N_3BCz8sdkgowwZEKsGiKd_iwcXgzxmgg&x-client-SKU=ID_NETSTANDARD2_0&x-client-ver=5.3.0.0
How can I fix this? It seems like my api is redirecting the client request to the microsoft login, but I'm thinking the way this should work is that my api should validate the token in the request or the scopes and grant access without redirecting the request to a login.
The key point here is to separate SPA OAuth entirely from API OAuth, with the following behaviours:
SPA does the redirect handling and gets a token from the Authorization Server - this code is Javascript based and does not need a C# 'web back end'
API validates tokens via the token signing public key of the Authorization Server - this code is C# based, which is a good language for API development
Authorization Server is an out of the box component such as Azure AD, and you never code issuing of JWTs yourself (good to see you doing this already)
Many online articles I've seen mix up these concerns and can be very confusing to people who are new to OAuth technologies. So it's important to be clear about what you want from the end solution.
API OAUTH CODE
Your C# code should only need a few lines by default, starting by adding a package such as this one:
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="3.1.8" />
The code to configure the API's security would then look something like this. Note that there is nothing about OpenIdConnect / web behaviour here.
private void ConfigureOAuthTokenValidation(IServiceCollection services)
{
services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options => {
options.Authority = "https://login.microsoftonline.com/mytenantid";
options.Audience = "api://default";
});
REAL WORLD SAMPLE
My .Net Core API solution has some stuff that may be of interest. These samples are quite advanced but enable you to run a local API and SPA that work together.
.Net Core Blog Post
API Code
API Security Configuration Code
SPA Code
The goal is to get the best end result for both API and SPA, so perhaps the above links will help you think about what that is in your case.
I have a aspnetcore app that I'm writing and would like to be able to manage WVD resources. The problem I'm having is that the Bearer token I'm getting from Msal is giving me a 401 when I try to
GET https://rdweb.wvd.microsoft.com/api/feeddiscovery/webfeeddiscovery.aspx
I thought maybe I needed to add an API permission to my app in azure, but I've already added:
https://management.azure.com/user_impersonation
And I cant seem to locate anything that suggests it might work for WVD.
Maybe I'm way off track though.
I've tried looking at the source:
https://github.com/Azure/RDS-Templates/tree/master/wvd-templates/wvd-management-ux/deploy
But its been compiled and minified, so thats proving to be difficult.
Any help getting a valid token to call the WVD Rest API would be greatly appreciated.
Getting the token:
Full Code (minus the Microsoft.Identity.Web stuff)
var token = await TokenAcquisition.GetAccessTokenOnBehalfOfUserAsync(new[] { "https://mrs-Prod.ame.gbl/mrs-RDInfra-prod/user_impersonation" });
var httpClient = new HttpClient();
httpClient.BaseAddress = new Uri("https://rdweb.wvd.microsoft.com/");
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", $"{token}");
var result = await httpClient.GetAsync("api/hubdiscovery/eventhubdiscovery.aspx");
result = await httpClient.GetAsync("api/feeddiscovery/webfeeddiscovery.aspx");
This method is from the Microsoft.Identity.Web project.
The https://management.azure.com is for Azure Service Management API, in your case, it is not correct.
Please navigate to the AD App in the portal -> API permissions -> APIs my organization uses -> search by Windows Virtual Desktop, find it and click.
If you want the management tool to make Windows Virtual Desktop management calls on behalf of the user who's signed into the tool, choose Delegated permissions -> user_impersonation, complete the steps like the screenshot. You can also let the user consent the permission by himself without clicking the Grant admin consent button, it depends on you.
Then the permission appears like below.
For more details, see this Tutorial: Deploy a management tool and this step.
Update:
Try to use powershell New-RdsRoleAssignment to add user account as a RDS Owner role, make sure you have installed the Microsoft.RDInfra.RDPowerShell module first, refer to this link.
Add-RdsAccount -DeploymentUrl "https://rdbroker.wvd.microsoft.com"
Get-RdsTenant
New-RdsRoleAssignment -RoleDefinitionName "RDS Owner" -SignInName "xxxx#xxxx.onmicrosoft.com" -TenantName "joywvd"
Then I run the Get-RdsTenant command again, and use fiddler to catch the request, get the token, decode in the https://jwt.io/, it appears like below.
The aud and scp should be the same as your token, you can also decode your token to check, then I use postman to call the https://rdweb.wvd.microsoft.com/api/feeddiscovery/webfeeddiscovery.aspx, it works.
Omg I just figured it out by comparing the token I got from the msft rdweb application:
From the RDWeb App:
"aud": "https://mrs-prod.ame.gbl/mrs-RDInfra-prod",
From my App:
"aud": "https://mrs-Prod.ame.gbl/mrs-RDInfra-prod",
....
Yes I was using an uppercase P in - mrs-Prod. And the msft app was using a lowercase p in mrs-prod.
I'm flabbergasted, angry and excited all at the same time.
For the record I copied my value directly from Azure in my apps api permissions screen.
So I've been migrating an older app service and Xamarin mobile application away from the old versions of MSAL to the latest as well as re-directing my app from 'login.microsoft.com' to the new(er) 'b2clogin.com' issuer URIs. I've been following this guide to migrate to the new issuer URI while still remaining backwards compatible with applications currently out in the field.
However, I'm running this service as an Azure App Service and in the 'Authentication / Authorization' section of my service I have my Active Directory configured with the correct B2C Application 'Client ID' and there's another text box for 'Issuer URL'. I can't seem to get away with not having a URI in that text box whether it be:
https://[id].b2clogin.com/[app id]/B2C_1_SignInUp/v2.0/.well-known/openid-configuration
or
https://login.microsoftonline.com/[app id]/v2.0/.well-known/openid-configuration?p=B2C_1_SignIn
Now this does authenticate just fine as long as I have one issuer or the other issuer but in my code I have:
TokenValidationParameters tvps = new TokenValidationParameters
{
// Accept only those tokens where the audience of the token is equal to the client ID of this app
ValidAudience = ClientId,
AuthenticationType = Startup.DefaultPolicy,
ValidIssuers = new List<string> {
"https://login.microsoftonline.com/[app id]/oauth2/v2.0/",
"https://[id].b2clogin.com/[app id]/oauth2/v2.0/"
}
};
Which I believe should mean that both issuers should be valid (backwards compatible. I've put in a little bit of debug code to verify that this code is being executed at startup. It almost seems like the Azure service is overriding the multiple issuer code but I'm not sure?
Does this documentation work in the Azure App service or is there something more you have to do to configure it? Thanks!
The Azure Authentication / Authorization aka Easy Auth runs before your app code.
So it will only accept one issuer.
I would suggest doing authentication only in your code, and turning off Easy Auth as it cannot fulfill your requirements here.
I've been trying to get a Xamarin Forms app to get a token from AAD.
I've tried countless different ways of doing it and they all have problems, some are bugs, some I just haven't been able to figure out.
This link is one of the simplest examples I've come across, yet it fails because it says there's no client secret.
http://www.cloudidentity.com/blog/2015/07/22/using-adal-3-x-with-xamarin-forms/
When I add the client secret, by modifying the AuthenticationContext like so
AuthenticationContext ac = new AuthenticationContext("https://login.microsoftonline.com/common");
ClientCredential cc = new ClientCredential("------4ba8-4136-ad1c-f36be878af8a", "-----sDdG4/WZCyYU=");
AuthenticationResult result = await ac.AcquireTokenAsync("https://graph.windows.net", cc);
I get a new error saying there is no application matching graph.windows.net in my directory.
Please make sure the type of the azure ad application your register is Native Client Application , that type application are meant to run on a device and aren't trusted to maintain a secret .
The code you provide is using client credential flow to acquire token , that flow uses app's credentials instead of impersonating a user .
Why won't my Azure AD application allow an oauth client_credentials grant?
I want to use the Azure Graph API, but first I need an oauth token. To get the token, I am trying to use Microsoft.IdentityModel.Clients.ActiveDirectory aka ADAL version 1.0.3 (from NuGet).
I'm using the overload of AuthenticationContext.AcquireToken that takes a ClientCredential object. (I can't use the overload that prompts the user to login because I'm writing a service, not an app.)
I configured my Azure AD web application as described in various tutorials/samples (e.g. ADAL - Server to Server Authentication).
My code looks like:
AuthenticationContext ac = new AuthenticationContext("https://login.windows.net/thommmondago.onmicrosoft.com");
ClientCredential cc = new ClientCredential("41151135-61b8-40f4-aff7-8627e9eaf853", clientSecretKey);
AuthenticationResult result = ac.AcquireToken("https://graph.windows.net", cc);
The AcquireToken line throws an exception:
sts_token_request_failed: Token request to security token service failed. Check InnerException for more details
The inner exception is a WebException, and the response received looks like an oauth error:
{ "error":"invalid_client",
"error_description":"ACS50012: Authentication failed."
"error_codes":[50012],
"timestamp":"2014-03-17 12:26:19Z",
"trace_id":"a4ee6702-e07b-40f7-8248-589e49e96a8d",
"correlation_id":"b304af2e-2748-4067-99d0-2d7e55b121cd" }
Bypassing ADAL and using curl with the oauth endpoint also gives the same error.
My code works if I use the details of the Azure application that I found here:
AuthenticationContext ac = new AuthenticationContext("https://login.windows.net/graphDir1.onmicrosoft.com");
ClientCredential cc = new ClientCredential("b3b1fc59-84b8-4400-a715-ea8a7e40f4fe", "FStnXT1QON84B5o38aEmFdlNhEnYtzJ91Gg/JH/Jxiw=");
AuthenticationResult result = ac.AcquireToken("https://graph.windows.net", cc);
So it's not an error with my code. I think it's either an error with my Azure AD, or I've got the ClientCredential parameters wrong.
This turned out to be an error in Windows Azure, there was nothing wrong with my code or config.
After Microsoft fixed the problem in Azure, I had to create a new application and it started working.
Forum answer from Microsoft:
Hi,
We are seeing some errors with applications created in a several day time range, ending yesterday. We are continuing to fix up these applications but I don't have a good eta when this will be done. I'm apologize for the impact here.
Can you try creating a new application and retying the operation with the new client id?
thanks
Have a look at this link: https://azure.microsoft.com/en-gb/documentation/articles/resource-manager-net-sdk/
The latest version of Active Directory Authentication Library does not support AcquireToken method, instead you have to use AcquireTokenAsync method.
var result = await authenticationContext.AcquireTokenAsync(resource: "https://{domain}.onmicrosoft.com/{site-if applicable}", clientCredential: credential);
I was having the same issue but only running the code directly from Azure (inside an Azure Website).
I solved upgrading 'Microsoft.IdentityModel.Clients.ActiveDirectory' package to '2.6.1-alpha'
The azure version of the translator has changed things once more- the Oauth token request uses a new url and only needs your secret key, instead of all the other baggage. This page discusses it (but using PHP code): http://www.bradymoritz.com/php-code-for-bingmicrosoftazure-translator/
The key items are:
Post an empty request to https://api.cognitive.microsoft.com/sts/v1.0/issueToken
Pass it your secret key using the header "Ocp-Apim-Subscription-Key: "
Or, just use the querystring parameter: "Subscription-Key="
Then get the body of the return as the actual token- it's the whole body, not in json format.
This is a lot simpler than the method used before, but it'd definitely a pain that things have yet again changed.