I am in the process of configuring an Scim API with Azure AD. What does this "Test Connection" do when configuring an Enterprise Application?
In my case my API endpoint I want to configure is "https://myapi.company.com/api/v2" where resource URL's are in the form of "https://myapi.company.com/api/v2/scim/[Resource]". I don't include 'scim' in the Tenant URL (as per the image attached) as Azure AD adds that by default when sending requests (which is bit weird in a way). [AzureAD adds /scim/[Resource] e.g. /scim/Users to the base URL provided.] [Reference]1.
When I try (click 'Test Connection' or try to Save without testing connection) 'https://myapi.company.com/api/v2' for tenant URL Test Connection fails.
Error message 'You appear to have entered invalid credentials. Please confirm you are using the correct information for an administrative account.'. Which does not make any sense to me.
As experiments,
When try 'https://myapi.company.com/api/v2/scim/' it is successful.
When try 'https://myapi.company.com/api/v2' it is successful.
All 3 URLs above gives 404 when tried from Postman or from browser.
Can't understand what AzureAD do with Test Connection.
The test connection sends a request such as this:
GET /Users?filter=userName eq "non-existent user"
and expects a response such as this:
HTTP/1.1 200 OK
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
"totalResults": 0,
"Resources": [],
"startIndex": 1,
"itemsPerPage": 20
}
https://learn.microsoft.com/en-us/azure/active-directory/app-provisioning/use-scim-to-provision-users-and-groups#get-user-by-query---zero-results
When you press Test Connection a couple of request will be sent to the Tenant URL(SCIM endpoint):
GET /scim/v2/Groups?excludedAttributes=members&filter=displayName+eq+%22AzureAD_Test-d3951745-df3d-40ae-a0a4-cc3099c34c47%22
GET /scim/v2/Users?filter=userName+eq+%22AzureAD_Test-d3951745-df3d-40ae-a0a4-cc3099c34c47%22
the actual displayName and userName requested are randomly generated, so an empty ListResponse is expected (with status code 200 OK):
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
"totalResults": 0,
"Resources": [],
"startIndex": 1,
"itemsPerPage": 20
}
This behaviour is mentioned in the docs :
Microsoft Azure AD makes requests to fetch a random user and group to
ensure that the endpoint and the credentials are valid. It's also done
as a part of Test Connection flow in the Azure portal.
Related
I have a .net Core 3.1 app running in an azure web app for containers(linux) service. This app is a web api project with an angular 9 front end. It uses Identity server 4 for authorization.
For reference I am using this clean architecture framework template for my project (the add docker support pr).
The app runs in the service just fine. The front end works and I can "log in" using ID4 and I can see that the authorization token are returned when I log in.
THE PROBLEM:
When I make a call to the backend web api from the front end angular client app I get the following error:
HTTP/1.1 401 Unauthorized
Server: Kestrel
WWW-Authenticate: Bearer error="invalid_token", error_description="The issuer 'https://*********.azurewebsites.net' is invalid"
I am tempted to add a manual setting for the IssuerUri but the identity server 4 docs recommend against doing this so I did not. Maybe having this run in docker makes it different.
I did have to add support for forwarding headers to get IS4 to work properly in startup.cs configureServices according to these docs for proxy load balancers. I had to add ASPNETCORE_FORWARDEDHEADERS_ENABLED=true to my application settings
When I compare fiddler results for the requests, I can see that the AspNetCore.Antiforgery is the same for login and web api calls but the .AspNetCore.Identity.Application value is different.
I am using nSwag to auto generate api service calls for angular if that makes a difference.
QUESTION:
can someone help me figure out why I can login but all web api requests fail with the unauthorized error above?
thanks in advance.
JK
EDIT 1
I used fiddler to get the authorization token for the request and used jwt.io to parse it. The iss value was the same as the app/web api:
"iss": "https://******.azurewebsites.net",
IS4 used this domain to log in and that worked properly. If that value is correct, is there another thing that might be wrong?
EDIT 2:
Just for more context.
My app uses in statup.cs Configure:
app.UseHsts();
app.UseHttpsRedirection();
As a result I needed to add the following code to make sure the headers get forwarded in the requests between app service's handling of the TSL, load balancer/proxy and my docker container (starup.cs ConfigureServices):
// the following is documented here:
// https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/proxy-load-balancer?view=aspnetcore-2.1#forward-the-scheme-for-linux-and-non-iis-reverse-proxies-1
// it is needed to run kestrel in azure app service in http with header forwarding
if (string.Equals(
Environment.GetEnvironmentVariable("ASPNETCORE_FORWARDEDHEADERS_ENABLED"),
"true", StringComparison.OrdinalIgnoreCase))
{
services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor |
ForwardedHeaders.XForwardedProto;
// Only loopback proxies are allowed by default.
// Clear that restriction because forwarders are enabled by explicit
// configuration.
options.KnownNetworks.Clear();
options.KnownProxies.Clear();
});
}
I get the following error in the logs which confirm the same error above as an Issuer mismatch
Microsoft.IdentityModel.Tokens.SecurityTokenInvalidIssuerException:
IDX10205: Issuer validation failed. Issuer: '[PII is hidden. For more
details, see https://aka.ms/IdentityModel/PII.]'. Did not match:
validationParameters.ValidIssuer ...
I am using the following default setup for the Jwt token:
services.AddAuthentication().AddIdentityServerJwt();
If i navigate to the https://*******.azurewebsites.net/.well-known/openid-configuration/jwks I get the following JSON setting for my OIDC setup:
{
"issuer": "https://*******.azurewebsites.net",
"jwks_uri": "https://*******.azurewebsites.net/.well-known/openid-configuration/jwks",
"authorization_endpoint": "https://*******.azurewebsites.net/connect/authorize",
"token_endpoint": "https://*******.azurewebsites.net/connect/token",
"userinfo_endpoint": "https://*******.azurewebsites.net/connect/userinfo",
"end_session_endpoint": "https://*******.azurewebsites.net/connect/endsession",
"check_session_iframe": "https://*******.azurewebsites.net/connect/checksession",
"revocation_endpoint": "https://*******.azurewebsites.net/connect/revocation",
"introspection_endpoint": "https://*******.azurewebsites.net/connect/introspect",
"device_authorization_endpoint": "https://*******.azurewebsites.net/connect/deviceauthorization",
"frontchannel_logout_supported": true,
"frontchannel_logout_session_supported": true,
"backchannel_logout_supported": true,
"backchannel_logout_session_supported": true,
"scopes_supported": [
"openid",
"profile",
"CleanArchitecture.WebUIAPI",
"offline_access"
],
"claims_supported": [
"sub",
"name",
....
"updated_at"
],
"grant_types_supported": [
"authorization_code",
"client_credentials",
"refresh_token",
"implicit",
"password",
"urn:ietf:params:oauth:grant-type:device_code"
],
"response_types_supported": [
"code",
"token",
"id_token",
"id_token token",
"code id_token",
"code token",
"code id_token token"
],
"response_modes_supported": ["form_post", "query", "fragment"],
"token_endpoint_auth_methods_supported": [
"client_secret_basic",
"client_secret_post"
],
"id_token_signing_alg_values_supported": ["RS256"],
"subject_types_supported": ["public"],
"code_challenge_methods_supported": ["plain", "S256"],
"request_parameter_supported": true
}
I compared the Issuer in this document and they are the same as the one in the token as shown decoded above.
I am still not sure how to debug this to figure out where the issuer mismatch is happening.
NOTE: I have narrowed this down a bit. All calls to the built in/default IS4 endpoints work. Its only the custom webAPI endpoints I define in my controllers that are not validating the token properly.
Any webAPI endpoint with [Authorize] attribute fails with invalid issuer
EDIT 3:
Thanks to #d_f comment I used the IS4 docs for adding local API
I added the following call to my services initialization in startu.ca configure services:
services.AddIdentityServer().AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
services.AddLocalApiAuthentication(); // I added this line after the above line
I then changed the [Authorize] attribute at the top of my webAPI controller to:
//[Authorize]
[Authorize(IdentityServerConstants.LocalApi.PolicyName)]
However, I am still getting the same error. Only on my custom webAPI endpoints, the IS4 endpoints all work. Login works but not any web api endpoints that have [Authorize] attribute.
EDIT 4:
I removed the above settings and chnaged my services.AddAUthentication() to the following:
services.AddAuthentication()
.AddIdentityServerJwt()
.AddLocalApi(options =>
options.ExpectedScope = "IdentityServer4");
I also tried:
services.AddAuthentication()
.AddIdentityServerJwt()
.AddLocalApi();
I used the policy name "IdentityServer4" because it appears to be a default policy within IS4
Here is what the full context looks like:
services.AddDefaultIdentity<ApplicationUser>()
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
services.AddAuthentication()
.AddIdentityServerJwt()
.AddLocalApi(options =>
options.ExpectedScope = "IdentityServer4");
This works locally on my machine with all these variations. Its just when run inside container in azure web app that I get the issuer failure for my custom webAPI endpoints.
SOLUTION:
I found a solution thanks to all the help here. IS4 out of the box attempts to set the ISS / Issuer automatically. This works locally but in my production environment my container run in azure web apps for containers. Azure places my container inside of another container for load balancing/proxy to handle the https encryption as well. As a result there is a difference between the auto detected IS4 issuer in my container and the azure web app URL.
By manually setting the issuer in my code the error went away and everything works.
You can do this in two places
in your appsettings.jsson like:
"IdentityServer": {
"IssuerUri": "https://yourapp.azurewebsites.net",
or in code like this:
services.AddIdentityServer(options =>
{
options.IssuerUri = "https://your.azurewebsites.net/";
})
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
Hope this helps someone else and thanks again to all who helped here
You need to capture your token and use https://jwt.ms to parse it.
According to your error message: invalid token The issuer is invalid, so you should check the iss Claims in the token to make sure it is as expected in the API The issuer matches. see here.
SOLUTION:
I found a solution thanks to all the help here. IS4 out of the box attempts to set the ISS / Issuer automatically. This works locally but in my production environment my container run in azure web apps for containers. Azure places my container inside of another container for load balancing/proxy to handle the https encryption as well. As a result there is a difference between the auto detected IS4 issuer in my container and the azure web app URL.
By manually setting the issuer in my code the error went away and everything works.
You can do this in two places
in your appsettings.jsson like:
"IdentityServer": {
"IssuerUri": "https://yourapp.azurewebsites.net",
or in code like this:
services.AddIdentityServer(options =>
{
options.IssuerUri = "https://your.azurewebsites.net/";
})
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
Hope this helps someone else and thanks again to all who helped here
I had seen multiple examples how to use Azure API manager using powershell to retreive password for SCM but unable to find any example using it without powershell i.e. something execution in shell command line. i am also looking for example for saving and deploying my api
You can always inspect any Azure service API in action by doing what you need in Azure portal and seeing what requests get sent. Correlating them with documentation helps. So to get access token for SCM endpoint in APIM you need:
With any Azure credentials make a GET call to https://management.azure.com/subscriptions/.../resourceGroups/.../providers/Microsoft.ApiManagement/service/.../tenant/access/git?api-version=2018-01-01
in response you will get a payload similar to:
{
"id": "XXX",
...
}
Take "id" from that payload and make a POST call to https://management.azure.com/subscriptions/.../resourceGroups/.../providers/Microsoft.ApiManagement/service/.../users/XXX/token?api-version=2018-01-01
you will get your token:
{
"value":"..."
}
I'm developing an API using VS 2017, which I'm testing using Postman. I've been following this blog post Getting started with Windows Azure AD Authentication using Postman. I finally got it to give me an access token and a refresh token. About 3 quarters of the way through the post I came across this:
resource : https://management.core.windows.net
which has to be put into Postman (I'm using the Windows app version of Postman). I wasn't sure what that was for, so I left it off. I eventually got an access token and a refresh token, but when I when to get more info for all subscriptions, I got errors saying that I had specified a valid resource. So, I thought what I'd have to do was start over again, but re-authenticating and getting a code from Azure. I did so, and put that into Postman, as the blog post instructs. However, issuing this POST results in this error:
"error": "unauthorized_client",
"error_description": "AADSTS70002: Error validating credentials. AADSTS65005: Invalid resource. The client has requested access to a resource which is not listed in the requested permissions in the client's application registration. Client app ID: d37abf69-42ce-4571-b146-f3422e73f041. Resource value from request: https://management.core.windows.net. Resource app ID: 797f4846-ba00-4fd7-ba43-dac1f8f63013. List of valid resources from app registration: 00000002-0000-0000-c000-000000000000.\r\nTrace ID: 9f028899-6d03-409e-8db4-4e9905000300\r\nCorrelation ID: ec253a1b-9fdc-495f-9310-6b40a42e5d93\r\nTimestamp: 2018-11-19 22:20:02Z",
"error_codes": [
70002,
65005
]
I don't understand why nor what I could have done wrong. I've prespecified the resource as the tutorial instructed, so what have I done wrong?
Looking at the error message, it seems you could have missed adding relevant permissions for "Windows Azure Service Management API" to your app registration.
Steps:
Go to Azure Portal > Azure AD > App registrations > Your app (with app id: d37abf69-42ce-4571-b146-f3422e73f041)
Go to Settings > Required permissions > Add > Select "Windows Azure Service Management API"
Select the relevant permission under Delegated permissions section. Click on select and then "Done". You should get a notification in portal that successfully added permissions. You should see Windows Azure Service Management API listed under required permissions as well.
After these steps, continue as per the blog post you've mentioned with Postman steps to get the access token again.
I found myself in the same situation when i was trying to setup Postman. Its not as complicated as most blogs make seem. I created a tutorial to try to make the process easy.
http://hazelnest.com/blog/blog/2018/11/17/azure-postman-configuration/
https://youtu.be/2bfgeBKRxl4
Hope this helps.
I have an account on Azure where we run various applications in docker containers.
I would like to connect to Active Directory on this account and be able to manage various aspects such as creating new users, etc.
I found following API browser:
https://learn.microsoft.com/en-us/rest/api/graphrbac/users/list
Unfortunately when I log in as a user with admin rights (Global Administrator) and provide tenant ID, when I call users/list endpoint, I get following error with 401 status:
{
"odata.error": {
"code": "Authentication_MissingOrMalformed",
"message": {
"lang": "en",
"value": "Access Token missing or malformed."
},
"date": "2018-07-20T14:01:24",
"requestId": "9f070c46-a949-41bf-85c9-f1ccf97975db",
"values": null
}
}
What is interesting - if I use any other random endpoint, for example: https://learn.microsoft.com/en-us/rest/api/servermanagement/node/list - it works fine. In this case it returns empty set, but at least it doesn't fail with strange authentication error.
I also can reproduce the issue that you metioned if I test Users - List Rest API directly from the site.
https://learn.microsoft.com/en-us/rest/api/graphrbac/Users/List
According to exception, the root cause of the issue is token audience. You could check the actual access token in the JWT.io.
You could get that the audience is https://management.core.windows.net/. The token that is acquired will work for other Azure Services like webapps, compute, ResourceManager, etc. but not for Graph.
You could test it with Azue AD graph explorer, then it will work for you.
The audience should be https://graph.windows.net
We have an O365 tenant, everything is configured out of the box. The tenant is placed in the German cloud and not in global (office.de).
We also developed an Office Add-in that authorize access to sharepoint using OAuth 2.0.
First, we initiate a request for a code to this url:
http://login.microsoftonline.com/common/oauth2/authorize?response_type=code&client_id=client_id&redirect_uri=redirect_uri&state=state
and we get all values back including the code.
Then, we initiate a request for the Discovery Service to discover the services using this url:
https://login.windows.net/common/oauth2/token?client_id=client_id&redirect_uri=redirect_uri&resource=https://api.office.com/discovery/&grant_type=authorization_code&code=code
In the global cloud everything is ok and we get the list of services we need but in the German cloud we get the following error:
{
"error": "invalid_grant",
"error_description": "AADSTS90051: Invalid Delegation Token. Invalid national Cloud ID (1) is specified.\r\nTrace ID: 52f8aa2b-9f98-4ba6-b778-c0ba484a3c00\r\nCorrelation ID: 67100192-82c8-41ea-a5ca-fd9872caaf2e\r\nTimestamp: 2018-02-08 06:31:18Z",
"error_codes": [
90051
],
"timestamp": "2018-02-08 06:31:18Z",
"trace_id": "52f8aa2b-9f98-4ba6-b778-c0ba484a3c00",
"correlation_id": "67100192-82c8-41ea-a5ca-fd9872caaf2e"
}
The same error occurs when we try to change the url to https://login.windows.de/common/oauth2/token
I think that you can use client crendetials flow to achieve that:
1.Request the access token for the Office Discovery service API:
POST https://login.microsoftonline.de/{{yourtenantId}}/oauth2/token?client_id={{client_id}}&client_secret={{client_secret}}&grant_type=client_credentials&resource=https://api.office.com/discovery/
2.Use the access token in the head and use the Office Discovery API:
Additional: If you want to get id_token and use it, try to use https://login.microsoftonline.de as the AAD Athorization endpoint in your request. I didn't test, but it should work.
Hope this helps!