I'm trying to get my backend API to authenticate that requests are from Azure APIM using managed identities, previously this was done with certificate authentication but for various reasons I'm looking to change that.
When I make requests to the APIM, I get the following error in application insights.
Managed service identity must be configured to use authentication-token policy.
In the backend I'm using Owin's Windows Azure Active Directory Bearer Authentication.
app.UseWindowsAzureActiveDirectoryBearerAuthentication(
new WindowsAzureActiveDirectoryBearerAuthenticationOptions
{
Tenant = "https://tennant.co.uk/AzureADDAuth",
TokenValidationParameters = new TokenValidationParameters
{
ValidAudience = "11111111-1111-1111-1111-111111111111"
},
});
In the APIM the inbound policy is as follows
<authentication-managed-identity resource="https://tennant.co.uk/AzureAADAuth" client-id="11111111-1111-1111-1111-111111111111" output-token-variable-name="msi-access-token" ignore-error="false" />
<set-header name="Authorization" exists-action="override">
<value>#("Bearer " + (string)context.Variables["msi-access-token"])</value>
</set-header>
I find the error message quite vague though and I've not found any help online so I'm not sure what I need to do to set up this configuration. I've looked through several docs and blog posts on this topic and can't find anything about what to change in the Azure Active Directory. If you could point me in the right direct I'd appreciate it.
I fixed this by removing the client id from the APIM inbound policy.
Related
I am trying to pass a bearer token from another API that I have subscribed to via my API into my APIM.
I had the idea of adding inbound processing that adds a set-header that adds "authorization" and "Bearer xxxxxxxxxxxxxxxxxxxxx".
So I was wondering if this is safe enough, as I don't want my bearer token to be public, I'm not sure if this can be traced outside of the APIM itself.
Could there be a better solution?
I found this https://learn.microsoft.com/en-us/azure/api-management/policies/use-oauth2-for-authorization in the Microsoft docs, but I'm not sure if it also works if it's a bearer token not linked to Azure AD. But maybe using "send-request" puts me on the right track?
Kind regards
You can store your secrets in Azure key vault. Define the secrets in APIM named properties. You should be good to securely send your token - "myToken"
<set-header name="Authorization" exists-action="override">
<value>Bearer {{myToken}}</value>
</set-header>
Ref : https://learn.microsoft.com/en-us/azure/api-management/api-management-howto-properties?tabs=azure-portal
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 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.
I am coding an integration that has to call Sharepoint-online API's. My integration is not a webapp and has to work without a user present.
As I understand it I need two setup steps:
1. User has to log in to Azure and set up an application and obtain a client ID.
2. I have to call a service with client ID and username and password I will then obtain an Access Token, Refresh Token and ID Token
Once the two setup steps are complete I then can call the service using the access token, but sometimes this will expire and I need to use the refresh token to get a new one.
Step 2 seems odd to me. Why isn't there a user interface where a user can log in and obtain the Access Refresh and ID tokens? Has someone built a utility website that just does this, or have I mis-understood something?
Thanks
Robert
The recommended OAuth flow for service and daemons apps is the Client Credential Flow (in that flow, there no refresh tokens involved; a client ID and a client secret is used to obtain an access token which eventually expires and then you need to get a new access token using the same client ID and secret). In the case of SharePoint Online, you have 2 options for this scenario:
SharePoint Online + Azure Access Control Service (ACS) integration. Details here. In short, you create a service principal (add in only policy) for instance at the site collection level - follow the "Creating the AppPrincipal" section in the blog I linked for this. Then you need to assign the specific permissions your app will need, in the application manifest. See a sample for that in the "Giving the App Principal Permissions" sections - again, you should first define what permissions your app needs. Then, you can use the service principal from a console application:
Program.cs
static void Main(string[] args)
{
Uri siteUri = new Uri("https://tenant.sharepoint.com/teams/test");
//Get the realm for the URL
string realm = TokenHelper.GetRealmFromTargetUrl(siteUri);
//Get the access token for the URL.
// Requires this app to be registered with the tenant
string accessToken = TokenHelper.GetAppOnlyAccessToken(
TokenHelper.SharePointPrincipal,
siteUri.Authority, realm).AccessToken;
HttpWebRequest endpointRequest =
(HttpWebRequest)HttpWebRequest.Create(
"https://tenant.sharepoint.com/teams/test/_api/web/lists/GetByTitle('Documents')/items");
endpointRequest.Method = "GET";
endpointRequest.Accept = "application/json;odata=verbose";
endpointRequest.Headers.Add("Authorization", "Bearer " + accessToken);
HttpWebResponse endpointResponse =
(HttpWebResponse)endpointRequest.GetResponse();
}
}
app.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
<appSettings>
<add key="ClientId" value="65e674ca-3827-4134-852b-1196ff935e08"/>
<add key="ClientSecret" value="xxxxxxx"/>
</appSettings>
</configuration>
SharePoint Online + Azure Active Directory (AAD) integration. Details here. In that link you will find a sample code. The difference between the first approach is that in this one you are not using ACS but AAD. The permission that the app needs is defined in AAD - as of today, as far as I know, the application permissions that you can define in AAD are not as granular as the ones you can define via ACS - i.e. with ACS you can define an app at the site collection level, with AAD you can't the app will have tenant wide permissions (i.e. all site collections)
I'm in the process of migrating from Azure Mobile Services to App Services and currently struggling to find the AAD User objectidentifier with the new OWIN authentication configured in Startup.MobileApp.cs. `
MobileAppSettingsDictionary settings = config.GetMobileAppSettingsProvider().GetMobileAppSettings();
app.UseWindowsAzureActiveDirectoryBearerAuthentication(
new WindowsAzureActiveDirectoryBearerAuthenticationOptions
{
TokenValidationParameters = new TokenValidationParameters { ValidAudience = ConfigurationManager.AppSettings["MS_AadClientID"]},
Tenant = ConfigurationManager.AppSettings["MS_AadTenants"]
});
Previously I was looking for:
claim.Type.Contains("urn:microsoft:credentials")
but none of the Claims on the User.Identity provide an objectidentifier.
Claims
The objectidentifier is available on https://myapp.azurewebsites.net/.auth/me.
{"typ":"http:\/\/schemas.microsoft.com\/identity\/claims\/objectidentifier",
"val":"xxxxxxxx-xxxx-xxxx-xxxxx-xxxxxxxxxxxx"}
Does anybody know if it's possible to access the value without making a call to the URL?
Thanks,
Viv
After digging through both the iOS and .NET server code, I found a method in the Microsoft.Azure.Mobile.Server.Authentication IPrincipalExtensions class.
by making a call to user.GetAppServiceIdentityAsync<AzureActiveDirectoryCredentials>(request);
you can get the AzureActiveDirectoryCredentials.ObjectId.
Be warned though as this is not available if you authenticate directly through the webservice.