IdentityServer4 with ADFS as external Identity Provider - identityserver4

I'm having a ASP.NET MVC test app who should work as an implicit OIDC client having access and id tokens from an IdentityServer4 app (both are dotnet core 3.1). IdSvr has a couple of external OIDC IdPs configured: A KeyCloak instance, and a ADFS (4.0) ditto.
My IdSvr configuration of ADFS is as follows:
.AddOpenIdConnect("oidc_adfs", "ADFS", options =>
{
options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
options.SignOutScheme = IdentityServerConstants.SignoutScheme;
options.SaveTokens = true;
options.Authority = "<<ADFS endpoint>>";
options.ClientId = "<<ADFS defined client id>>";
options.ClientSecret = "<<ADFS defined client secret>>";
options.Resource = "<<My resource identifier in ADFS>>";
options.TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = "name",
RoleClaimType = "role"
};
options.ResponseType = "id_token";
options.GetClaimsFromUserInfoEndpoint = true;
options.Scope.Add("openid");
options.Scope.Add("profile");
});
In the KeyCloak case, everything goes fine - the callback request to IdSvr's "/signin-oidc" goes fine and the front-channel user agent ends at the destination test app's post-auth endpoint and the tokens are available.
When I use ADFS, the flow stops with a HTTP 500 after the user is authenticated in ADFS, and the "/signin-oidc" endpoint is hit, and IdSvr log reads:
CORS request made for path: /signin-oidc from origin:
<<ADFS_endpoint>> but was ignored because path was not for an
allowed IdentityServer CORS endpoint 2020-09-20 12:34:01.157 +02:00
[INF] Error from RemoteAuthentication: Unable to unprotect the
message.State..
I've setup CORS according to the IdentityServer4 docs, so the problem might be something else?
When inspecting differences in KeyCloak and ADFS callback requests to "/signin-oicd", I can see that ADFS does add Referer/Origin to the request and KeyCloak does not. Apart from that, the two requests seem quite similar.
Hope someone can help.

If you see the Origin header from ADFS, then I guess you need to add the ADFS domain to the list of allowed CORS endpoints.

What error is shown in the ADFS event log?
The problem may also be that ADFS 4.0 does not support CORS?

Related

Identity Server Invalid Request Because Of Http Redirection

I am using .net core mvc as identity server client application. When going to the identity server in localhost, the redirect uri goes as https and connects, no problem. But it goes as http on the test server. And cause it is defined as https on the identity server, invalid request returns. How do I make this http part https?
Eror picture:
https://ibb.co/2k2LK5j
I am using UserHttpsRedirection()
I marked with ** related parts in requests.
Working request:
https://test.identityserversite.com/im/connect/authorize?client_id=bla_bla_client&redirect_uri=**https**://localhost:5001/signin-oidc&response_type=id_token
token&scope=openid
profile&response_mode=form_post&nonce=637975263254748013.MTUyNTc5OTgtYmJlMS00ZTAyLTgxMjAtNTNjZDNmZDBjMjY3MWIyNzg2ZDEtNmE1OS00NTUyLWEwNWMtNDI1N2ZiODAwMGVk&state=CfDJ8N9E0C7WvvpEoty-MgpSP4cRET_Y6sOuFDy58PjxCQcyD64gal_CBwXNx6DbTf7FyF8sQ9sJxeGZH1dAQPRn6mVHvUULG3FFz99XW7O9fpq8lTRvDSSxmBMoyBmSt4KwjbXdE60mbnllnlC7kbWT1ytqArRRKj8YtzkGQp2eg69TbuTJkgwIJsnFFbsfZ0Uo0A9xdYBP7eQRuMi9HrCZ6RU8l28E-U4fByg5Qzss2dcmLJDhPxWJd94z17MJwgEK6d1L34Kivc33NsGhXtwvFSypp6m2sgkSR3fT_bwvH-yy&x-client-SKU=ID_NETSTANDARD2_0&x-client-ver=6.10.0.0
Not Working request:
https://test.identityserversite.com/im/connect/authorize?client_id=bla_bla_client&redirect_uri=**http**://clienttestsite.com/signin-oidc&response_type=id_token
token&scope=openid
profile&response_mode=form_post&nonce=637975265040994314.NmNiY2Q1MWQtOGJmYy00OWE0LTgxNGMtODk5MjkyY2QwOGNhYTJkMzdlZmItMzI4Ny00NmFkLTg3YjgtYjA4M2UzZDQ5OGZj&state=CfDJ8BWH8w1S3EBHujbHFc1L6rvNMx0jXRaUdB5aDFJ5wMA4IF5h17dNCV78tPAPLThXL6lS937Rz6mt3Jrbhn1cjozAeIL4bFu5YRkQLQeBKdGeAYA2Ikh610MqPSrG7bnCezbpdKrsGVNIKYZqIBuECh_gEm45T_b5HcuhzucF2du1Cz8sDtDmDzYKuSjBUo49b4-YNxM1zkGH8v2dkWxhNpduYYMQJwV53yy_BogGgaaT_8i9bffFKl_rYfOgtNAiw2OzZRpEqaqdvjCNQEetaNPcNnZiJYBEnloBSeG73njLAHIEoWD-OveWAT5-216OBw&x-client-SKU=ID_NETSTANDARD2_0&x-client-ver=6.10.0.0
Error Update:
We must use server as http without ssl behind the load balancer by company policy.
We have conf page like this:
options.Authority = identitySettings.Issuer;
options.ClientId = identitySettings.ClientId;
options.ClientSecret = identitySettings.ClientSecret;
options.RequireHttpsMetadata = true;
options.UsePkce = true;
options.SaveTokens = true;
options.TokenValidationParameters.NameClaimType = "given_name";
options.TokenValidationParameters.RoleClaimType = "role";
options.ClaimActions.DeleteClaim("s_hash");
//options.SignedOutCallbackPath = "/account/accessdenied";
//options.SignedOutRedirectUri = "/account/accessdenied";
Func<RedirectContext, Task> redirectToIdentityProvider = (ctx) =>
{
if (!ctx.ProtocolMessage.RedirectUri.StartsWith("https"))
ctx.ProtocolMessage.RedirectUri = ctx.ProtocolMessage.RedirectUri.Replace("http", "https");
return Task.FromResult(0);
};
options.Events = new OpenIdConnectEvents
{
OnRedirectToIdentityProvider = redirectToIdentityProvider
};
// this code changes http redirectUri to https redirectUri
options.CorrelationCookie.SameSite = SameSiteMode.None;
options.NonceCookie.SameSite = SameSiteMode.None;
//options.TokenValidationParameters.ValidateIssuer = false;
//options.TokenValidationParameters.ValidAudience = "9cd9c695-cd02-4b70-a10b-df669cd77ed8";
options.ResponseType = "id_token token";
options.Scope.Clear();
var scopes = identitySettings.Scopes.Split(',');
foreach (var scope in scopes)
{
options.Scope.Add(scope);
}
When we send request from browser our site redirects to identity server with http(issue at top). Identity server wants us to come with https. First identity server return us to "invalid reqquest". Cause allowedRedirectUri is "https:localhost:5001" So we manipulate the redirectUri http to https.(with event OnRedirectToIdentityProvider . You can see on top code). Now our site returns "correlation failed".
UPDATE
Type of our problem has been changed in a while. We figured out problen at the top with assigning ssl to server, not only load balancer.
You should not try to use OpenID connect over HTTP using a browser. Why? Besides security, the browsers will not accept the cookies involved when sent over HTTP.
This is due to the samesite=none attribute set on some of the cookies. Browsers will reject these cookies if sent over HTTP.
HTTP problem
your client seems in development since it is on local host. the client will deploy as http service behind reverse proxy and the domain/subdomains is configured with ssl in the front as your identity is referred as https address. (SSL offloading)
https://test.identityserversite.com
so i dont think you have any problem in that. my services including identity server are http behind reverse proxy and i have subdomain with ssl configuration in nginx and i dont have any problem. and ofcourse for dployment you configure forward headers.
Corelation
in my case it happens when i played around samesite cookies.the configurations for cookie are mismatch between identity server and the client. i was able to reach login but after login i got the error.but it seems you stay samesite to none i guess. how ever it is mostly related to you cookies between client and identityserver

Microsoft.Identity.Web OpenIdConnect was not authenticated. Failure message: Not authenticated

My app had been working with Microsoft.Identity for the past couple of years and something changed that is causing users to have to clear cache to authenticate. I have verified reply url's, the tenant id, client id and client secret and they all have not changed and are correctly setup. I updated to the latest nuget package. And after clearing browser cache the authentication works perfectly. What could be causing this?
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
options.CheckConsentNeeded = context => false;
options.MinimumSameSitePolicy = SameSiteMode.Unspecified;
options.HandleSameSiteCookieCompatibility();
});
services.AddMicrosoftIdentityWebAppAuthentication(Configuration, "AzureAd");
//services.AddSignIn(Configuration);
// Token acquisition service based on MSAL.NET
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseRouting();
app.UseCors(MyAllowSpecificOrigins);
app.UseAuthentication();
app.UseSession();
app.UseMiddleware<UserClaims>();
app.UseAuthorization();
Microsoft.AspNetCore.Hosting.Diagnostics: Information: Request starting HTTP/2.0 POST https://localhost:44326/signin-oidc application/x-www-form-urlencoded 3217
Microsoft.AspNetCore.Cors.Infrastructure.CorsService: Information: CORS policy execution successful.
Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler: Information: AuthenticationScheme: Cookies signed in.
Microsoft.AspNetCore.Hosting.Diagnostics: Information: Request finished in 626.0063ms 302
Microsoft.AspNetCore.Hosting.Diagnostics: Information: Request starting HTTP/2.0 GET https://localhost:44326/
Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler: Information: OpenIdConnect was not authenticated. Failure message: Not authenticated
Microsoft.AspNetCore.Authorization.DefaultAuthorizationService: Information: Authorization failed.
Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler: Information: AuthenticationScheme: OpenIdConnect was challenged.
Microsoft.AspNetCore.Hosting.Diagnostics: Information: Request finished in 225.1113ms 302
Please make sure to add authentication middleware in order that app.UseAuthentication(); comes before app.UseMvc();
app.UseAuthentication();
app.UseAuthorization();
Note that AddMicrosoftIdentityWebApp is using its own cookie (auth) provider
instead using the existing one (maybe After being upgraded).
Try using by making cookiescheme to null
services.AddAuthentication() .AddMicrosoftIdentityWebApp(Configuration,"AzureAd", "AzureAD", cookieScheme: null);
or
try to explicity add the schemes so that scheme is able to handles exceptions of challenge errors like 401.
For that you may need to call AddAuthentication() and configure a default challenge schemes something like this.
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAd"))
NOTE: AddAuthentication() method actually configures the service to add cookie-based authentication.This cookie used in browser scenarios and also to set the challenge to OpenID Connect.
and register Microsoft Identity routes with one call minumum to endpoints.MapControllerRoute() or a call to endpoints.MapControllers().
or
services.Configure<CookiePolicyOptions>(options =>
{
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
.AddAzureAD(options => Configuration.Bind("AzureAd", options));
services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
{
options.Authority = options.Authority + "/v2.0/";
options.TokenValidationParameters.ValidateIssuer = false;
});
Please check microsoft-identity-web issues in github
References:
aspnetcore-webapp-openidconnect-v2 (github.com)
asp.net mvc - IdentityServer4 - Stack Overflow
Stack Overflow reference

AADSTS50011 after creating CNAME

I had my IdenityServer4 oidc service running correctly as an AppService on Azure. Now I created a DNS entry in my hosting to create better names for all the services. For Azure-AD I keep getting this error:
AADSTS50011: The reply URL specified in the request does not match the reply URLs configured for the application: '<my app id>'.
I have these two reply-urls setup in Azure AD portal:
https://account.mysite.com/signin-microsoft
https://myapp-oidc.azurewebsites.net/signin-microsoft
The second one works but the first does not, giving the error. Is there any way for me to debug this and see what reply url apparently is different that the one configured?
Here's the setup in startup.cs:
services
.AddAuthentication()
.AddMicrosoftAccount("Microsoft", options => {
options.SignInScheme = "Identity.External";
options.ClientId = "xxx";
options.ClientSecret = "xxx";
})
I did the same for google (https://account.mysite.com/signin-google) and that worked right away but I can't get Azure to work on the new address.

Secure .Net Core 3 Web API with AAD Token

Due to some technical constraints, we are doing Username/Password AAD authentication when user login.
Users will input their username and password into our custom login page and our application calls IPublicClientApplication.AcquireTokenByUsernamePassword.
I'm planning to use the returned token to call another Web API application(also connecting to the same AAD). In the Web API application, I did the following:
Added the following code in startup services.AddAuthentication(AzureADDefaults.JwtBearerAuthenticationScheme).AddAzureADBearer(options => Configuration.Bind("AzureAd", options));
include the following settings in my appsettings.json file
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"ClientId": "<Application ID>",
"TenantId": "<Tenant ID>"
}
Secure my web api using [Authorize]
I then use Postman to construct a call to the Web API based on the returned token. I included Authorization: Bearer <JWT Token>. The Web API returns
Bearer error="invalid_token", error_description="The signature is invalid"
My questions are
Can Web API application validate the username/password acquired token?
If the token can be validated in Web API application, how can I do it since I'm getting the above error?
I test in my site and it work well, you could refer to the following steps:
1.Register Webapi app in azure ad.
2.Click Expose an API and Add a scope e.g. webread.
3.Click Manifest, change accessTokenAcceptedVersion to 2.0.
4.In visual studio webapi ConfigureServices:
services.AddAuthentication(AzureADDefaults.JwtBearerAuthenticationScheme).AddAzureADBearer(options => Configuration.Bind("AzureAd", options));
services.Configure<JwtBearerOptions>(AzureADDefaults.JwtBearerAuthenticationScheme,
options =>
{
options.Authority += "/v2.0";
options.TokenValidationParameters.ValidAudiences = new[]
{
options.Audience,
$"api://{options.Audience}"
};
});
5.Register client app in azure ad.
6.Click Authentication, set Default client type as Yes.
7.Click Api Permission>Add a permission, select My APIs and choose the webapi your registered before.
8.In visual studio client app, set scope with webread:
string[] scopes = new string[] { "api://1890e822-xxxxxxxxxxxxxxxx/webread" };
Hope it helps you.
From the document you provided you are using MSAL to get access token using Resource Owner Flow in Azure AD V2.0 endpoint .
From document , when validating access token which issued from Azure AD V2.0 , you should add /v2.0 to Authority :
services.Configure<JwtBearerOptions>(AzureADDefaults.JwtBearerAuthenticationScheme, options =>
{
// This is a Microsoft identity platform web API.
options.Authority += "/v2.0";
// The web API accepts as audiences both the Client ID (options.Audience) and api://{ClientID}.
options.TokenValidationParameters.ValidAudiences = new []
{
options.Audience,
$"api://{options.Audience}"
};
});

IdentityServer4 and Azure AD - Getting blank page 404 to login.live after entering credentials

I am trying to setup Azure AD as an external provider for IdentityServer4 in a development environment. Google and Facebook providers already are hooked up successfully.
I'm directed to the login page on login.microsoft.com where I enter my login id and select an MS account, it then directs me to login.live.com as a blank page (404) instead of redirecting back to my IdentityServer instance.
I've tried a bunch of things but have had no luck.
Do I need to enable Enterprise Applications in Azure?
Am I missing something?
IdentityServer URL:
http://localhost:5000
IdentityServer URL:
http://localhost:47740
...
app.UseOpenIdConnectAuthentication(CreateAzureAdOptions(clientId, tenantId));
...
public static OpenIdConnectOptions CreateAzureAdOptions(string clientId, string tenentId)
{
return new OpenIdConnectOptions
{
DisplayName = "Azure Active Directory",
AuthenticationScheme = "Azure",
ClientId = clientId,
Authority = string.Format(CultureInfo.InvariantCulture, "https://login.microsoftonline.com/{0}", tenentId),
ResponseType = "id_token",
Scope = { "openid" },
SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme,
AutomaticChallenge = true,
AutomaticAuthenticate = true,
RequireHttpsMetadata = false,
TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = false
}
};
}
This probably is related to the size of the url when returning from AAD. This is actualy a 404.15 IIS specific status code. If you have a lot of claims returned from your External identity provider (ie a profile image base64) then you will always hit the cap in url length HTTP Error 404.15 - query url too long RSS.
IdenitityServer4 has a topic in the docs that addresses this issue by using the distributed cache underneath. It is located under Sign-in with External Identity Providers - State, URL length, and ISecureDataFormat
Abstract:
Fortunately, IdentityServer provides an implementation of this for you, backed by the IDistributedCache implementation registered in the DI container (e.g. the standard MemoryDistributedCache). To use the IdentityServer provided secure data format implementation, simply call the AddOidcStateDataFormatterCache extension method on the IServiceCollection when configuring DI. If no parameters are passed, then all OpenID Connect handlers configured will use the IdentityServer provided secure data format implementation.

Resources