Creating resource groups from Azure Web App Managed Service Identity - c#

I'm trying to build a Bot using MS Bot framework and this bot is hosted as an Azure Web App. I've added code to create resource groups using the Microsoft.Azure.Management.Fluent APIs
AzureCredentialsFactory f = new AzureCredentialsFactory();
var msi = new MSILoginInformation(MSIResourceType.AppService);
var msiCred = f.FromMSI(msi, AzureEnvironment.AzureGlobalCloud);
var azureAuth = Azure.Configure()
.WithLogLevel(HttpLoggingDelegatingHandler.Level.BodyAndHeaders)
.Authenticate(msiCred);
var azure = azureAuth.WithSubscription(subscription);
var resourceGroup = azure.ResourceGroups.Define(rg)
.WithRegion(Region.EuropeWest)
.Create();
This code is levering the Managed Service Identity of the Web app. I've made this web app "Owner" of the Azure subscription.
when i execute this code i keep getting this exception
Exception: The access token has been obtained from wrong audience or resource ’https://management.core.windows.net'. It should exactly match (including forward slash) with one of the allowed audiences ‘https://management.core.windows.net/’,’https://management.azure.com/’.
I never set the audience or resource by hand and don't see any option on how to do this.
When i change my code to use a service principal i created myself it works great
ServicePrincipalLoginInformation loginInfo = new ServicePrincipalLoginInformation()
{
ClientId = _clientId,
ClientSecret = _clientSecret
};
var credentials = new AzureCredentials(loginInfo, _tenantId, AzureEnvironment.AzureGlobalCloud);
var azureAuth = Azure.Configure()
.WithLogLevel(HttpLoggingDelegatingHandler.Level.BodyAndHeaders)
.Authenticate(credentials);
How to set this audience or resource or what am i doing wrong?

How to set this audience or resource or what am i doing wrong?
I also can reproduce this issue on my side. It seems it is the SDK issue. You could report it to the Azure SDK github issue.
Update:
According to issue-4090, it has been fixed in version 1.7, you could test again if it is released.

Related

Not able to get all users from Azure Active Directory

I am using solution mentioned here to get all users from Active Directory however I suspect the code is pulling disabled users from our old Active Directory. The new one is Azure Active Directory. Please let me know what change is required to get below details of only active users from Azure Active Directory:
First Name
Last Name
Email
Enterprise ID
Getting all users in Azure AD can use Microsoft Graph API. Here's the API for listing users. But it doesn't support personal Microsoft account, it only supports work or school accounts. By the way, I'm not sure what is Enterprise ID, could you pls take a look at this section to check if this API contained it?
I assume you have an asp.net core WEB API which is used to getting user list. So you should use code like below.
using Microsoft.Graph;
using Azure.Identity;
var scopes = new[] { "https://graph.microsoft.com/.default" };
var tenantId = "tenant_name.onmicrosoft.com";
var clientId = "aad_app_id";
var clientSecret = "client_secret";
var clientSecretCredential = new ClientSecretCredential(
tenantId, clientId, clientSecret);
var graphClient = new GraphServiceClient(clientSecretCredential, scopes);
var users = await graphClient.Users.Request().GetAsync();
Then an Azure AD application is required for the variables in code above. Pls follow this document to register the Azure AD app. Since my assumption is based on a web API, no need to add redirect URL here. Now we can get tenantId , clientId in Overview blade, and created the client secret. We also need to modify API permissions blade and add required API permissions. What we need is Application permission User.Read.All,User.ReadWrite.All,Directory.Read.All, Directory.ReadWrite.All.

Authenticate Office 365 IMAP Account using Unattended C# Console

I am developing a .NET Core Console Application (C#) that needs to authenticate to an Office 365 IMAP account. The purpose is to retrieve mail and process CSV file attachments unattended.
The app has been registered on Azure as a Mobile/Desktop app with the RedirectUri set as http://localhost.
The following code causes a new tab to open in Chrome web browser and asks for the Outlook account to use for login. I need to stop the browser from opening and handle authentication completely from code.
Current Code:
using var client = new ImapClient(new ProtocolLogger("imap.log"));
var options = new PublicClientApplicationOptions
{
ClientId = _options.ClientId,
TenantId = _options.TenantId,
RedirectUri = "http://localhost"
};
var publicClientApplication = PublicClientApplicationBuilder
.CreateWithApplicationOptions(options)
.Build();
var scopes = new[]
{
"email",
"offline_access",
"https://outlook.office.com/IMAP.AccessAsUser.All" // Only needed for IMAP
//"https://outlook.office.com/POP.AccessAsUser.All", // Only needed for POP
//"https://outlook.office.com/SMTP.AccessAsUser.All", // Only needed for SMTP
};
var cancellationToken = new CancellationToken();
var authToken = await publicClientApplication
.AcquireTokenInteractive(scopes)
.ExecuteAsync(cancellationToken);
await publicClientApplication
.AcquireTokenSilent(scopes, authToken.Account)
.ExecuteAsync(cancellationToken);
SaslMechanism oauth2;
if (client.AuthenticationMechanisms.Contains("OAUTHBEARER"))
{
oauth2 = new SaslMechanismOAuthBearer(authToken.Account.Username, authToken.AccessToken);
}
else
{
oauth2 = new SaslMechanismOAuth2(authToken.Account.Username, authToken.AccessToken);
}
await client.AuthenticateAsync(oauth2);
await client.DisconnectAsync (true);
This line triggers a browser window to open https://login.microsoftonline.com/:
var authToken = await publicClientApplication
.AcquireTokenInteractive(scopes)
.ExecuteAsync(cancellationToken);
This console application will be run unattended. How do I obtain the token and authenticate without a web browser opening up?
This is an answear to your latest comment, as it's my final recommendation. So, first of all, you should decide if you want to acess the data on behalf of user, or as an app granted permissions by admin.
First step is to register your app.
Second step is getting the acess token. This is going to differ based on the method you chose. Tutorial for each: acting on behalf of the user or acting without the user, but granted permission from admin.
Once you have the acess token, you can call the Microsoft Graph API. The important thing is, you always have to call Microsoft Graph API. There is no other official way (as far as I know) of comunicating with Microsoft's services. You can try the requests with the Microsoft Graph Explorer, however it's VERY limited with it's defaul urls/parameters, so I suggest taking a look at the docs.
From what you've described, you first want to obtain UserID. The way of doing this is going to vary based on what type of auth you chose.
If you chose to act on behalf of user, you should be able to get that (ID) using this endpoint: https://graph.microsoft.com/v1.0/me/
If you chose to act as an app with admin consent, you should be able to search for user using the https://graph.microsoft.com/v1.0/me/people/?$search= with search query parameters. Here are the docs for this endpoint
Now, the only thing left, is to supply that ID to one of the Outlook api methods. You can find docs for them here. Specifically, it seems like you want to list all messages and then read a specific message.
Also, keep an eye on what methods you use with which type of auth. On behalf of user, you usually want url's that contain /me, on behalf of app with given admin privelages, you usually want some endpoint that enables you to pass user id.
Hope I helped!
PS: There is no code in this response, because there is a lot of stuff that just cannot be coded without your decisions, actions on Azure and so on. I suggest you read a little bit about auth and graph api using microsoft docs I linked earlier.
This code worked for me using MSAL after registering the app in azure and getting a client secret.
var options = new ConfidentialClientApplicationOptions
{
ClientId = "<ClientID or Application ID>",
TenantId = "<Azure TenantId>",
RedirectUri = "http://localhost"
};
string clientSecret = "<Client Secret Goes here>";
var confidentialClientApplication = ConfidentialClientApplicationBuilder
.CreateWithApplicationOptions(options)
.WithClientSecret(clientSecret)
.Build();
var scopes = new string[] {
"https://outlook.office365.com/.default"
};
var authToken = await confidentialClientApplication.AcquireTokenForClient(scopes).ExecuteAsync();

Call Azure AD protected Azure Function from console app/PowerShell w/delegated permission

What I want to do is have the user log in to the AAD prompt on their Windows Desktop machines, so I get a Bearer token that will work with my Azure Function.
I've followed the tutorial from this article on adatum but it only covers the application permission (not delegated permissions)
I already have an Azure Function that is set up for Azure AD
authentication.
I already have a client app that I registered (under
App Registrations).
I've configured it to use delegated permissions
for the Azure Function.
Here's my client code:
var clientId = "client id for my console app";//console app
var clientUrl = new Uri("https://login.microsoftonline.com/common/oauth2/nativeclient");
var tenant = "tenantid here";
string authority = "https://login.windows.net/" + tenant;
string resource = "https://myaadProtectedFunc.azurewebsites.net";
AuthenticationContext authenticationContext = new AuthenticationContext(authority, false);
var pp = new PlatformParameters(PromptBehavior.Auto);
var token = authenticationContext.AcquireTokenAsync(resource, clientId, clientUrl,
pp, UserIdentifier.AnyUser).Result;
Console.WriteLine("Got the token: {0}", token.AccessToken);
I get an error saying "[my client app] needs permission to access resources in your organization that only an admin can grant. Please ask an admin to grant permission to this app before you can use it."
Is there some other way to get a Bearer token that will work with my Azure Function?
I did a test and your code does work if you set up the azure side correctly. most likely in the azure function you do not have it set up correctly.
in the azure function did you set up the service principal?
eg. function app -> platform features -> authentication / authorization -> App Service Authentication to ON -> select azure active directory -> express -> create. -> press ok. -> save.
then in your app registration, you will now see 2. the app reg for your client, and app reg for your function app. in the app reg for your client go to api permissions and add the app registration for your function app with the user impersonation selected.
finally make sure your enterprise application has the user/groups you want to be allowed to access for each of the enterprise apps. (client and function app registration)
Hope that helps.
Ok it turns out that I don't need to make a separate client application at all.
I can just use the Client ID of the Azure Function.
The thing is that you will have to go to 'Advance' instead of 'Express' because the library Microsoft.Identity.Client uses v2.0 tokens.
This is to configure your Azure Function - keep all fields the same, but add a /v2.0 to the Issuer URL:
This is the code to get the delegated bearer token for the Azure Function, which uses the v2.0 token - I don't know how to change it to use the v1 token:
string[] scopes = new string[] { "profile", "email", "openid" };
string ClientId = [clientId of Azure Function];
string Tenant = [tenantId];
string Instance = "https://login.microsoftonline.com/";
var _clientApp = PublicClientApplicationBuilder.Create(ClientId)
.WithAuthority($"{Instance}{Tenant}")
.WithDefaultRedirectUri()
.Build();
var accounts = _clientApp.GetAccountsAsync().Result;
var authResult = _clientApp.AcquireTokenInteractive(scopes)
.WithAccount(accounts.FirstOrDefault())
.WithPrompt(Prompt.SelectAccount)
.ExecuteAsync().Result;
var bearerTokenForAzureFunction = authResult.IdToken;
Now I don't understand the need to register a client application at all if I can get the delegated bearer token this way...

Should Managed Service Identities be used for Azure App Service access from Console App

I have a console app that is running inside our enterprise that needs to access as App Service Web API. What is the best way to handle authentication. I tried registering the App with AD, but it still seems like it cant't see the App Service. I tried the following code, but I am not sure this is even the right API to use.
var App = ConfidentialClientApplicationBuilder.Create(CoreConstants.Auth_ClientId)
.WithAuthority(CoreConstants.Auth_Authority)
.WithClientSecret("xxxxxxxxxxxxxx")
.Build();
var token = App.AcquireTokenForClient(scopes).ExecuteAsync();
token.Wait();
This fails saying the scope is not defined. It looks like it is in Azure.
First of all, you need to create role assignments for your App identity. And then you can get the access tokens from the identity. The code will like this:
using Microsoft.Azure.Services.AppAuthentication;
using Microsoft.Azure.KeyVault;
// ...
var azureServiceTokenProvider = new AzureServiceTokenProvider();
string accessToken = await azureServiceTokenProvider.GetAccessTokenAsync("https://vault.azure.net");
// OR
var kv = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
Do not forget to add references to the Microsoft.Azure.Services.AppAuthentication and any other necessary NuGet packages to your application. For more details, see Obtaining tokens for Azure resources with App MSI.

Accessing SharePoint with Microsoft Graph using the Microsoft App Registration Portal

I am trying to access SharePoint through Microsoft Graph using the v2.0 endpoint (Microsoft App Registration Portal) but I am unable to authenticate.
I am using the following code.
var cca = new ConfidentialClientApplication(client_id, "https://login.microsoftonline.com/testtest.onmicrosoft.com/v2.0/", "http://localhost:61716/", new ClientCredential(password), null, null);
AuthenticationResult authResult = cca.AcquireTokenForClientAsync(new string[] { "https://graph.microsoft.com/.default" }).GetAwaiter().GetResult();
var graph = new GraphServiceClient(new DelegateAuthenticationProvider((message) =>
{
message.Headers.Authorization = new AuthenticationHeaderValue("bearer", authResult.AccessToken);
return Task.FromResult(0);
}));
I am currently getting the error "Message: Either scp or roles claim need to be present in the token."
How do I add the appropriate permissions to the app registration portal and how do I apply them / access SharePoint from my C# application.
Edit: I would like to clarify that I do not want to use the Azure AD, I would like to use the Microsoft App Registration Portal.
The permission need to add in your Application project.
Sites.Read.All, Sites.ReadWrite.All
If you use aspnet MVC, just modify the GraphScopes to in web config(get started).
If you use NetCore, just get started from the Github sample. Then modify the GraphScopes in appsettings
If you use Angular, just get started from here,choose SDK-based or Rest-based for your requirement. Then set the GraphScopes in config.js

Categories