OAuth Authentication fails with error AADSTS65005 in ios Xamarin - azure

The authentication used to work for us earlier but has stopped suddenly.
We have an app built in Xamamin iOs and have registered the application in Azure AD account, provided the ClientID and redirect URL as specified. But it throws an error when "authContext.AcquireToken" is being called
Exception: Microsoft.IdentityModel.Clients.ActiveDirectory.AdalServiceException: AADSTS65005: The client application has requested access to resource 'example.com/'. This request has failed because the client has not specified this resource in its requiredResourceAccess list.
Trace ID: ea22c27c-9913-4423-92dc-6fff1cf9904d
Correlation ID: 4c19258b-2391-4585-911e-853157dde073
Timestamp: 2017-01-24 09:28:49Z
Code we are using to acquire token:
var authContext = new AuthenticationContext(authority);
if (authContext.TokenCache.ReadItems().Any())
authContext = new AuthenticationContext(authContext.TokenCache.ReadItems().First().Authority);
var authResult = await authContext.AcquireTokenAsync(resource, clientId, new Uri(returnUri),
new PlatformParameters(UIApplication.SharedApplication.KeyWindow.RootViewController));
And for authority variable, we are using "https://login.microsoftonline.com/common" to authenticate. We also tried "https://login.windows.net/common" but with no luck.
Has there been any microsoft updates lately which could have stopped this code from running?

Based on the error message, you were trying to access the resource example.com/.
However this resource was removed to grant to that app.
To fix this issue, you can login the Azure portal to grant this resource to your app again like figure below(switch your Azure AD->App registrations->You App->Settings->Required permissions->Add):

Related

Trying to use Managed Identity with Azure Service Bus

I've tried following this tutorial in order to authenticate my service bus against DefaultAzureCredentials, however, I get a 401.
I'm using the following code in the set-up:
services.AddAzureClients(x =>
{
x.AddServiceBusClientWithNamespace("myns.servicebus.windows.net")
.WithCredential(new Azure.Identity.DefaultAzureCredential());
});
I then call the SB client like this:
var sender = client.CreateSender("myqueue");
var message = new ServiceBusMessage(Encoding.UTF8.GetBytes("test"));
await sender.SendMessageAsync(message);
When I call SendMessageAsync I get a 401 error:
fail: Azure-Messaging-ServiceBus[82]
An exception occurred while creating send link for Identifier: myqueue-578624f3-f732-4a9b-2ab0-9adc01949a5a. Error Message:
'System.UnauthorizedAccessException: Put token failed. status-code:
401, status-description: InvalidIssuer: Token issuer is invalid.
TrackingId:cde3a89c-8108-48d1-8b8f-dacde18e176f,
SystemTracker:NoSystemTracker, Timestamp:2021-05-19T07:18:44.
Before I run this, I call az login. I have access to the the namespace to both send and receive. My guess is that I need to allocate some kind of permission between the service bus and ... something - but since I'm running this as a console app, I'm running with my own credentials. Clearly there's something about managed identity that I don't understand.
EDIT:
Following advice from #juunas, I tried the following:
services.AddHostedService<ConsoleHostedService>();
services.AddAzureClients(x =>
{
//var creds = new Azure.Identity.EnvironmentCredential(); // 1st - EnvironmentCredential authentication unavailable. Environment variables are not fully configured.'
//var creds = new Azure.Identity.ManagedIdentityCredential(); // 2nd - No Managed Identity endpoint found
//var creds = new Azure.Identity.SharedTokenCacheCredential(); // 3rd - 'SharedTokenCacheCredential authentication unavailable. No accounts were found in the cache.'
//var creds = new Azure.Identity.VisualStudioCodeCredential(); // 4th - 'Stored credentials not found. Need to authenticate user in VSCode Azure Account.'
//var creds = new Azure.Identity.AzureCliCredential(); // 5th
var creds = new Azure.Identity.DefaultAzureCredential();
x.AddServiceBusClientWithNamespace("myns.servicebus.windows.net")
.WithCredential(creds);
It says the "token issuer is invalid".
That means it got an access token, but it was issued by the wrong Azure AD tenant.
The Az CLI allows you to specify the Azure AD tenant id with the -t tenant-id-here argument on az login.
DefaultAzureCredential could also be using some other credential (it attempts multiple credentials like VisualStudioCredential before the AzureCliCredential).
You could instead try to use AzureCliCredential directly and see if it works.
That of course won't use Managed Identity so you'd need to use ChainedTokenCredential with the AZ CLI credential + ManagedIdentityCredential to support both.

Retrieve Azure KeyVault secret using client secret

I'm experimenting with various Azure features and currently want to retrieve a secret from KeyVault.
Straight to the case:
I'm using this nuget package to interact with my azure resources.
I've developed a simple .NET Core console app and run it locally.
I have a KeyVault resource with one secret defined which is active and not expired.
I've registered an App in AAD so my locally shipped .NET Core console app has an identity within AAD.
Than I've created a "client secret" within this registered app in AAD to use it to authenticate myself as an app.
After that I've added access policy in my KeyVault resource to allow GET operation for secrets for this registered app:
Then I've developed a small piece of code which should retrieve the desired secret:
public class AzureAuthentication
{
public async Task<string> GetAdminPasswordFromKeyVault()
{
const string clientId = "--my-client-id--";
const string tenantId = "--my-tenant-id--";
const string clientSecret = "--my-client-secret--";
var credentials = new ClientSecretCredential(tenantId, clientId, clientSecret);
var client = new SecretClient(new Uri("https://mykeyvaultresource.vault.azure.net"), credentials);
var secret = await client.GetSecretAsync("admincreds");
return secret.Value.Value;
}
}
However when I'm trying to do this I'm getting an AccessDenied error:
Am I missing something painfully obvious here? Or there is some latency (>30 min for this moment) for which changes from Access policies screen in KeyVault resource are applied?
I test your code and Get permission, it works fine.
From your screenshot, it looks you didn't add the correct service principal related to the AD App to the Access policies.
If you add the service principal related to the AD App, it will appear as APPLICATION, not COMPOUND IDENTITY.
So when you add it, you could search for the client Id(i.e. application Id) or the name of your App Registration directly, make sure you add the correct one.
Make sure your AD App(service principal) has the correct permission in your keyvault -> Access policies

Azure MSI using app services

I am trying to protect my backing services to my frontend webapp using MSI and AAD auth.
I keep getting a 401 when I call my backing services form the public facing webapp. I have added the public webapp as a reader in the IAM section of the backing services.
What I can't figure out is how to obtain the access token, it seems that no matter which endpoint I use for obtaining the access token, it says that it is not found.
Here is my code:
{
var azureServiceTokenProvider = new AzureServiceTokenProvider();
string accessToken = azureServiceTokenProvider.GetAccessTokenAsync("https://<mywebapi>.azurewebsites.net").GetAwaiter().GetResult();
var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Authorization = new
AuthenticationHeaderValue("Bearer", accessToken);
RemoteIp = httpClient.GetStringAsync("https://<mywebapi>.azurewebsites.net/api/default/remoteIp").GetAwaiter().GetResult();
LocalIp = httpClient.GetStringAsync("https://<mywebapi>.azurewebsites.net/api/default/localIp").GetAwaiter().GetResult();
ConnectionId = httpClient.GetStringAsync("https://<mywebapi>.azurewebsites.net/api/default/connectionId").GetAwaiter().GetResult();
}
And here is the error message:
Parameters: Connectionstring: [No connection string specified], Resource: https://<mywebapi>.azurewebsites.net, Authority: .
Exception Message: Tried to get token using Managed Service Identity.
Unable to connect to the Managed Service Identity (MSI) endpoint.
Please check that you are running on an Azure resource that has MSI setup.
UPDATE:
<mywebapi> is obviously the actual endpoint value, but not exposed here on stackoverflow. Furthermore I should mention that calling the API endpoints directly works fine, after I have authorized with my personal credentials xxx#xxx.xxx. The issue is related to the webapp trying to identify itself to the webapi, even though it is a registered application which has been assigned the necessary IAM rights on the webapi resource.
The error says it tried to use MSI, but could not. Are you sure you are running this code on the Web App with MSI enabled?
Also, you need to replace "https://<mywebapi>.azurewebsites.net" with the App Id URI or Application Id of your API in Azure AD.
In other words, this needs to match the valid audience that you have configured for the API.

How to consume Graph API with a ADAL token?

in my Xamarin.forms project, I use ADAL (Microsoft.IdentityModel.Clients.ActiveDirectory) to authenticate on the Azure portal (Auth 1.0 endpoint). That part work great, but I need to get the security group of the user. So I use this code and passing the token received with ADAL:
HttpClient client = new HttpClient();
HttpRequestMessage message = new HttpRequestMessage(HttpMethod.Get, "https://graph.microsoft.com/v1.0/me/memberOf");
message.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("bearer", token);
HttpResponseMessage response = await client.SendAsync(message);
string responseString = await response.Content.ReadAsStringAsync();
I always got StatusCode: 401, ReasonPhrase: 'Unauthorized'.
In my azure AD app registration, I add the Graph API and these permissions:
I think I miss something. Any idea?
----- EDIT 1 ---
Here my payload. I changed it for a picture for lisibility. I don't know how to post json here
----- EDIT 2 ---
OH! I see. I think I need to understand more the Azure Login process. For now I follow an example of ADAL and Azure that let my log and use some function in my backend. So the login process use:
var authContext = new AuthenticationContext(authority); var authResult = await authContext.AcquireTokenAsync(resource, clientId, uri, platformParams);
Where authority = https://login.microsoftonline.com/mysite.com, ResourceID is my backend app ID and clientID is my native app ID. So Shawn is correct, I do not use the Graph.microsoft.com to get the token. Do we have another way to achieve all that? The need of using Graph is only to get the AD group the user has to adjust permission inside the app.
You are correct in your comment. If you add a new permission to your application, you must ask the user to re-consent to the app.
You can force re-consent through ADAL by setting the PromptBehavior to Always:
platformParams.PromptBehavior = PromptBehavior.Always
Or you can simply modify your Login URL to force it, by adding the query string:
&prompt=consent
In terms of building an app to help overcome this problem, if you think your app will be changing permissions after release, you can integrate logic which detects Unauthorized, and then sends the user to re-consent.
Another option is for your app to track changes which may require a new consent prompt, and detect when the user uses this new version of your application the first time, and asks them to consent.
In our new App Model V2, we support the concept of Incremental and Dynamic Consent, which should get rid of this problem all together for you.

Simple Directory Lookup in Azure Active Directory

I am writing a simple desktop application that needs to retrieve some basic properties about a user from Microsoft’ directory. Specifically:
I am writing a single tenant native LOB application.
The application runs on my desktop.
The application runs as my logged on domain account.
The organization' domain accounts are synced to AAD.
I am not trying to secure a native web app or a Web API or anything like that. I do not need users to sign in.
I have email addresses of folks in my organization from an external event management tool. I need to lookup the AAD account profile data (address book info - specifically job title) from AAD based on the email address. I will only be reading AAD data.
So far, I have done the following:-
It appears that the Azure AD Graph API is the right way to fetch the profile information. In particular, the information is available at the endpoint: https://graph.windows.net/{tenant}/users/{email}?api-version=1.6
When registering the native application in AAD, no key was provided. So I don't have a client secret.
Looked at the sample in GitHub here: https://github.com/Azure-Samples/active-directory-dotnet-graphapi-console. The instructions here seem to be wrong because no Keys section is available [see (2)].
Based on the sample above, I wrote a simple function. Code is below:
private static async Task PrintAADUserData(string email)
{
string clientId = "0a202b2c-6220-438d-9501-036d4e05037f";
Uri redirectUri = new Uri("http://localhost:4000");
string resource = "https://graph.windows.net/{tenant}";
string authority = "https://login.microsoftonline.com/{tenant}/oauth2/authorize";
AuthenticationContext authContext = new AuthenticationContext(authority);
AuthenticationResult authResult = await authContext.AcquireTokenAsync(resource, clientId, redirectUri, new PlatformParameters(PromptBehavior.Auto));
string api = String.Format("https://graph.windows.net/{tenant}/users/{0}?api-version=1.6", email);
LOG.DebugFormat("Using API URL {0}", api);
// Create an HTTP client and add the token to the Authorization header
HttpClient httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(authResult.AccessTokenType, authResult.AccessToken);
HttpResponseMessage response = await httpClient.GetAsync(api);
string data = await response.Content.ReadAsStringAsync();
LOG.Debug(data);
}
Questions
The application when run was able to bring up the authentication page. Why do I need that? The application already runs as my domain account. Is an additional authentication necessary? If I were to run this application in Azure as a worker process, then I would not want to use my domain credentials.
The primary problem seems to be the resource URL which is wrong. What resource do I need to specify to access the Azure AD Graph API?
Thanks,
Vijai.
EDITS
Based on the comments from #Saca, the code and application has been edited.
Code
string clientId = ConfigurationManager.AppSettings["AADClientId"];
string clientSecret = ConfigurationManager.AppSettings["AADClientSecret"];
string appIdUri = ConfigurationManager.AppSettings["AADAppIdURI"];
string authEndpoint = ConfigurationManager.AppSettings["AADGraphAuthority"];
string graphEndpoint = ConfigurationManager.AppSettings["AADGraphEndpoint"];
AuthenticationContext authContext = new AuthenticationContext(authEndpoint, false);
AuthenticationResult authResult = await authContext.AcquireTokenAsync("https://graph.windows.net", new ClientCredential(clientId, clientSecret));
ExistingTokenWrapper wrapper = new ExistingTokenWrapper(authResult.AccessToken);
ActiveDirectoryClient client = new ActiveDirectoryClient(new Uri(graphEndpoint), async () => await wrapper.GetToken());
IUser user = client.Users.Where(_ => _.UserPrincipalName.Equals(email.ToLowerInvariant())).Take(1).ExecuteSingleAsync().Result;
App
Error
Unhandled Exception: System.AggregateException: One or more errors occurred. ---> System.AggregateException: One or more errors occurred. ---> Microsoft.Data.OData.ODataErrorException: Insufficient privileges to complete the operation. ---> System.Data.Services.Client.DataServiceQueryException: An error occurred while processing this request. ---> System.Data.Services.Client.DataServiceClientException: {"odata.error":{"code":"Authorization_RequestDenied","message":{"lang":"en","value":"Insufficient privileges to complete the operation."}}}
It appears that despite giving the right permissions, the correct resource and being able to acquire a token, there is still something missing.
The key thing to consider here is if your application will be a headless client run from a secure server or desktop client run by users on their machines.
If the former, then your application is considered a confidential client and can be trusted with secrets, i.e. the keys. If this is your scenario, which is the scenario covered by the sample, then you need to use clientId and clientSecret.
The most likely reason you are not seeing a Keys section in the your application's Configure page is that, instead of selecting Web Application and/or Web API as per step #7 in the sample, you selected Native Client Application when first creating the application. This "type" can't be changed, so you'll need to create a new application.
If your scenario is the latter, then your application is considered a public client and can't be trusted with secrets, in which case, your only options is to prompt the user for credentials. Otherwise, even if your app has it's own authorization layer, it can easily be decompiled and the secret extracted and used.
Your resource URL is correct by the way.
Turns out the real issue was not with the code. I am not an AAD administrator. It appears that any application needing to perform authentication against AAD in our tenant needs to have permissions enabled by the AAD administrators. Once they enabled permissions for my application (and took ownership of the AAD registration as well), this started working.
Hope help some one that are using GraphClient:
var userPriNam = "johndoe#cloudalloc.com";
var userLookupTask = activeDirectoryClient.Users.Where(
user => user.UserPrincipalName.Equals(userPriNam, StringComparison.CurrentCultureIgnoreCase)).ExecuteSingleAsync();
User userJohnDoe = (User)await userLookupTask;
from https://www.simple-talk.com/cloud/security-and-compliance/azure-active-directory-part-5-graph-api/

Resources