Azure MSI using app services - azure

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.

Related

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

Getting error when trying to secure aspnet core web api with B2C authentication: Unable to retrieve openid config

I'm trying to secure my aspnet core web API server by making it authenticate against Azure B2C using user-provided JWT bearer tokens. I've followed some sample code found on official microsoft github pages, but can't seem to get it working.
In my B2C policy, I've got it set to use the default issuer URL format: https:////v2.0/
In my web application, I've got that same URL specified as the Authority in the JWT options.
When I submit an HTTP request to my server, the identity server code fails as it tries to reach out to B2C to fetch the openid-configuration. It fails with the following error ...
HttpRequestException: Response status code does not indicate success: 404 (Not Found).
System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode()
IOException: IDX20804: Unable to retrieve document from: 'https://innovativelitfoundry.b2clogin.com/0f55bfb6-6af5-4293-8963-29ae099183cc/v2.0/.well-known/openid-configuration'.
Microsoft.IdentityModel.Protocols.HttpDocumentRetriever.GetDocumentAsync(string address, CancellationToken cancel)
InvalidOperationException: IDX20803: Unable to obtain configuration from: 'https://innovativelitfoundry.b2clogin.com/0f55bfb6-6af5-4293-8963-29ae099183cc/v2.0/.well-known/openid-configuration'.
Microsoft.IdentityModel.Protocols.ConfigurationManager<T>.GetConfigurationAsync(CancellationToken cancel)
Indeed, that URL will not work because it does not appear to be including the policy name, from the used token, in the query string. So, that URL does indeed not work.
I'm unsure how to make the code provide that policy name in the query string, though? Or should it be doing that automatically?
Here is the code, in my aspnet core web api application, where I configure the authentication settings ...
public void ConfigureServices(IServiceCollection services)
{
IdentityModelEventSource.ShowPII = true;
services
.AddAuthentication(ConfigureAuthentication)
.AddJwtBearer(ConfigureJwt);
services
.AddCors();
services
.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services
.AddSingleton(Configuration);
}
private void ConfigureAuthentication(AuthenticationOptions options)
{
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
}
private void ConfigureJwt(JwtBearerOptions options)
{
var tenant = Configuration["AzureAd:TenantId"];
options.Audience = Configuration["AzureAd:ApplicationId"];
options.Authority = $"https://innovativelitfoundry.b2clogin.com/{tenant}/v2.0/";
}
Does anybody perhaps know what I may be doing incorrectly here? How can I get my aspnet core web api application to correctly pull down that openid configuration document?
You must set options.Authority to an authority URL that includes the policy ID:
options.Authority = $"https://innovativelitfoundry.b2clogin.com/{tenant}/{policy}/v2.0/";
As long as you have set the issuer claim for all policies to the issuer URL that doesn't contain the policy ID, then your API application can download the configuration document for any policy and then validate tokens that are issued for all policies.

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.

ASP.NET Core Web App using Work (Azure AD) Authentication works debugging locally, but not after publish to Azure

My ASP.NET Core web app works great when running and debugging locally, but fails to run once published to Azure.
I enabled Organizational Authentication and selected the appropriate domain upon publishing.
The appropriate reply URL was registered
After I publish to Azure I get this error:
An unhandled exception occurred while processing the request.
OpenIdConnectProtocolException: Message contains error: 'invalid_client', error_description: 'AADSTS70002: The request body must contain the following parameter: 'client_secret or client_assertion'.
Trace ID: 640186d6-9a50-4fce-ae39-bbfc1caf2400
Correlation ID: 622758b2-ca52-4bb0-9a98-e14d5a45cf80
Timestamp: 2017-04-19 16:36:32Z', error_uri: 'error_uri is null'.
I'm assuming that it's because the Client Secret needs to be stored in Azure somewhere; however, the value in secrets.json did not work when I added it as an App Setting (invalid client secret error) as I saw someone was able to do on another post. Also not sure if putting the value of "Authentication:AzureAd:ClientSecret" in AzureĀ AppSettings is a good idea anyway.
Not sure if this is useful to anyone or not. But i receive a similar error message.
OpenIdConnectProtocolException: Message contains error: 'invalid_client', error_description: 'error_description is null', error_uri: 'error_uri is null'.
Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler+<RedeemAuthorizationCodeAsync>d__22.MoveNext()
The solution for me was to provide a secret in the token service
,new Client
{
ClientId = "Testclient",
ClientName = "client",
ClientSecrets =
{
new Secret("secret".Sha256())
},
//Hybrid is a mix between implicit and authorization flow
AllowedGrantTypes = GrantTypes.Hybrid,
And provide the secret in the client
app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions
{
//The name of the authentication configuration.. just incase we have multiple
AuthenticationScheme = "oidc",
//Represents where to store the identity information -> which points to the cookie middleware declared above
SignInScheme = "Cookies",
//where the token service reside -> system will configure itself by invoking the discovery endpoint for the token service
Authority = "http://localhost:5000",
RequireHttpsMetadata = false,
ClientId = "Testclient",
ClientSecret = "secret",
//hybrid flow -grant type
ResponseType = "code id_token",
Hopefully this helps someone
Somehow I the Azure AD IDs needed for the proper Azure Active Directory App Registration were mixed up. There were 2 App Registration entries and the ClientID and TenentID's didn't match up with the local. So I synchronized the Client and Tenent IDs with one of the App Registration entries, and made sure the Client Secret was in App Settings, and it worked properly.
I verified these steps with this fine example Win's GitHub repository and they match now.

OAuth Authentication fails with error AADSTS65005 in ios Xamarin

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):

Resources