Identity Server - Authorization code flow issue - Login page - authorization

The issue I am facing is after successful login from my MVC app to ID Server, I am not getting redirected to the applications secure page. instead, the identity server login page reappears.
I created the ID server using hte following template.
dotnet new is4inmem -n IdentityServerSample
My ID Server runs in port 5000 (http only)
I have another MVC application, which runs in port 5006 (http only).
my client settings and scope settings in ID Server config file is as below..
..., new Client
{
ClientId = "AuthCode_Flow_Client",
ClientSecrets = { new Secret("secret".Sha256()) },
AllowedGrantTypes = GrantTypes.Code,
RedirectUris = { "http://localhost:5006/signin-oidc" },
FrontChannelLogoutUri = "https://localhost:5006/signout-oidc",
PostLogoutRedirectUris = { "https://localhost:5006/signout-callback-oidc" },
AllowOfflineAccess = true,
AllowedScopes = { "openid", "profile", "ValuesAPI_ReadOnly" }
},...
public static IEnumerable<ApiScope> ApiScopes =>
new ApiScope[]
{
new ApiScope("scope1"),
new ApiScope("scope2"),
new ApiScope("ValuesAPI_ReadOnly"),
};
The configure serivice method in my MVC is as below.
services.AddAuthentication(opts =>
{
opts.DefaultScheme = "Cookies";
opts.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies")
.AddOpenIdConnect("oidc", opts =>
{
opts.Authority = "http://localhost:5000";
opts.RequireHttpsMetadata = false;
opts.ClientId = "AuthCode_Flow_Client";
opts.ClientSecret = "secret";
opts.SaveTokens = true;
opts.ResponseType = "code";
});
In my pipeline, I have added the UseAuthentication and UseAuthorization() middlewares.
ISSUE
When I hit a secure page in my MVC application, I get redirected to ID SErver login page. After giving valid credentials (bob / bob), I dont see any errors in id server console log but still I am getting redirected ot login page itself.
Any suggestions.

Related

ASP.NET core blazor webassembly getting token for Identity Server 4 Postman testing

I am trying to test my api with postman in a blazor webassembly asp.net core hosted app with identity server 4 individual accounts. Unfortunately, despite having tried many different configuration options to get a new token, I have been unable to get one. Here is what I've tried
This one results in the postman browser emulator pop up and never finishes.
This one fails but I get the more informative error that info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2] Authorization failed. These requirements were not met: DenyAnonymousAuthorizationRequirement: Requires an authenticated user.
However, when I then try and use the default testing username and password I get Error: unauthorized_client
I followed the set up step by step in this article using the API authorization options instead of the profile service option (and I'm developing locally, not using azure.) What do I need to do to get a token? I appreciate the help, thanks.
EDIT: attempted adding a new Client in ConfigureServices but the same behavior happens with the postman browser emulator pop up and never finishing.
services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options => {
options.IdentityResources["openid"].UserClaims.Add("name");
options.ApiResources.Single().UserClaims.Add("name");
options.IdentityResources["openid"].UserClaims.Add("role");
options.ApiResources.Single().UserClaims.Add("role");
options.Clients.Add(new IdentityServer4.Models.Client()
{
ClientId = "postman",
AllowedGrantTypes = GrantTypes.Code,
AllowOfflineAccess = true,
ClientSecrets = { new Secret("secret".Sha256()) },
RedirectUris = { "http://localhost:21402/signin-oidc", "https://oauth.pstmn.io/v1/browser-callback" },
PostLogoutRedirectUris = { "http://localhost:21402/" },
FrontChannelLogoutUri = "http://localhost:21402/signout-oidc",
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.Email,
"Onero.ServerAPI"
},
});
});
If you're using authorization code grant, use this URL for the callback URL and leave Authorize using browser unchecked. You also need to add the URL to the list of RedirectUris for your app.
https://oauth.pstmn.io/v1/browser-callback
This page just posts a message to the parent of the auth popup (i.e. Postman window)
<script>
let data = {
isAuthCallback: true,
queryString: window.location.search || '',
hash: window.location.hash || ''
};
window.opener.postMessage(data, '*');
</script>
If you don't want to allow this URL (you probably want to protect tokens from 3rd parties) you can host this page in your app.
[HttpGet("postman-callback")]
public IActionResult PostmanCallback()
{
return new ContentResult {
ContentType = "text/html",
StatusCode = 200,
Content = #"
<html><body><script>
let data = {
isAuthCallback: true,
queryString: window.location.search || '',
hash: window.location.hash || ''
};
window.opener.postMessage(data, '*');
</script></body></html>"
};
}
After days of reading the docs and blogs to get an overall picture I finally was able to do it! What I did was the following:
Looked closely at the output from starting up my Server project, which is where I saw this:
That made me realize that I had been using the wrong endpoint for the Auth URL in Postman. So I changed it to https://localhost:5001/connect/authorize. I then used this configuration in Postman
Combined with adding the Postman client like so in the Server's Startup.cs file
services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options => {
...
options.Clients.Add(new IdentityServer4.Models.Client()
{
ClientId = "Postman",
AllowedGrantTypes = GrantTypes.Code,
AllowOfflineAccess = true,
ClientSecrets = { new Secret("secret".Sha256()) },
RedirectUris = { "http://localhost:21402/signin-oidc", "https://oauth.pstmn.io/v1/browser-callback" },
PostLogoutRedirectUris = { "http://localhost:21402/" },
FrontChannelLogoutUri = "http://localhost:21402/signout-oidc",
AllowedScopes =
{
"Onero.ServerAPI"
},
});;
});
And that finally got that little Postman page to pop up, bring me to the default IdentityServer AuthUI page, login with my default user and there we go, finally get the darn token.
Biggest take away: make sure to read the server output to make sure your endpoints are correct so you can fill out the parameters in Postman correctly.
Thanks for the help!

nopCommerce Authentication using Identity Server4 Implementation Issue

I am using NopCommerce 4.40.3 and Identity Server 4. I am trying to integrate Identity Server authentication with NopCommerce. I have followed the existing ExternalAuth.Facebook project approach and created the plugin. I am able to install and configure the plugin successfully. I am able to show the "Identity Server Authentication" button and when I click it is redirecting to Identity Server Login Page and I am able to authenticate to Identity Server with out any issues. I can able to see the claims and I can see the success message in the identity server console. But NopCommerce site still shows not logged in and when I try to access different pages in NopCommerce, It is redirecting me to login page.
After login, I am able to see the Identity Server cookies like "idsrv" and "idsrv.session". When I logout from Identity Server, I can see both cookies are cleared out.
My question is, how can I set successful login to NopCommerce site. Here's my implementation code. I don't know what I have missed in the configuration or in the implementation. Please help me.
Identity Server Client Configuration:
new Client
{
ClientName = "MiniApple.App.NopCommerce",
ClientId = "MiniApple.App.NopCommerce",
AllowedGrantTypes =GrantTypes.HybridAndClientCredentials,
RedirectUris = new List<string>{ "https://localhost:44369/signin-oidc" }, //Client Application Address
RequirePkce = false,
RequireConsent = true,
AllowedScopes = {
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.Address,
IdentityServerConstants.StandardScopes.Email,
"MiniApple.API.Employee",
"roles"},
ClientSecrets = { new Secret("abcdefghijklmnopqrstuvwxyz".Sha512()) },
AllowAccessTokensViaBrowser = true,
AlwaysSendClientClaims = true,
PostLogoutRedirectUris = new List<string> { "https://localhost:44369/signout-callback-oidc" }
},
NopCommerce Authentication Registration:
public class IdentityServerAuthenticationRegistrar : IExternalAuthenticationRegistrar
{
/// <summary>
/// Configure
/// </summary>
/// <param name="builder">Authentication builder</param>
public void Configure(AuthenticationBuilder builder)
{
builder.AddOpenIdConnect("oidc", options => {
var settings = EngineContext.Current.Resolve<IdentityServerExternalAuthSettings>();
options.SignInScheme = "Cookies";
options.Authority = settings.Authority;
options.ClientId = settings.ClientKeyIdentifier;
options.ResponseType = settings.ResponseType;
options.SaveTokens = true;
options.ClientSecret = settings.ClientSecret;
options.GetClaimsFromUserInfoEndpoint = true;
options.Scope.Add(settings.Scope);
options.Scope.Add("roles");
options.ClaimActions.MapUniqueJsonKey("role", "role");
options.TokenValidationParameters = new TokenValidationParameters
{
RoleClaimType = "role"
};
});
}
}
Identity Server Console Output:
info: IdentityServer4.Validation.TokenRequestValidator[0]
Token request validation success, {
"ClientId": "MiniApple.App.NopCommerce",
"ClientName": "MiniApple.App.NopCommerce",
"GrantType": "authorization_code",
"AuthorizationCode": "****F988",
"RefreshToken": "********",
"Raw": {
"client_id": "MiniApple.App.NopCommerce",
"client_secret": "***REDACTED***",
"code": "18978F1D183EDFA3E3F5918B85F43DDFEAFE74D49E207E2449F59A9490BFF988",
"grant_type": "authorization_code",
"redirect_uri": "https://localhost:44369/signin-oidc"
}
}
info: IdentityServer4.Hosting.IdentityServerMiddleware[0]
Invoking IdentityServer endpoint: IdentityServer4.Endpoints.UserInfoEndpoint for /connect/userinfo
info: IdentityServer4.ResponseHandling.UserInfoResponseGenerator[0]
Profile service returned the following claim types: given_name family_name role
After successful login with identity server, it is redirecting to https://localhost:44369/signin-oidc and I am getting 404 error.
The issue is similar to the below
[question]: https://www.nopcommerce.com/en/boards/topic/60547/problems-making-custom-externalauth-plugin-for-openidconnect-to-auth0
Once I have changed the code as below, the authentication is works fine.
public void Configure(AuthenticationBuilder builder)
{
builder.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options => {
//Set Open Id Parameters
var settings = EngineContext.Current.Resolve<IdentityServerExternalAuthSettings>();
options.Authority = settings.Authority;
options.ClientId = settings.ClientId;
options.ClientSecret = settings.ClientSecret;
options.ResponseType = settings.ResponseType;
options.GetClaimsFromUserInfoEndpoint = true;
options.Scope.Add(settings.Scope);
options.Scope.Add("roles");
options.Scope.Add("openid");
options.Scope.Add("profile");
//options.Scope.Add("email");
options.SaveTokens = true;
options.ClaimActions.MapUniqueJsonKey("role", "role");
options.TokenValidationParameters = new TokenValidationParameters
{
RoleClaimType = "role"
};
options.Events = new OpenIdConnectEvents
{
OnRemoteFailure = context =>
{
context.HandleResponse();
var errorUrl = context.Properties.GetString(IdentityServerAuthenticationDefaults.ErrorCallback);
context.Response.Redirect(errorUrl);
return Task.FromResult(0);
}
};
});
}

Identity Server 4 ASP.NET certificate authentication

I'm trying to implement client certificate authentication with ASP.NET and IdentityServer4, but can't seem to make it work. Through Postman I get "Error: invalid_client", in debug console "Client secret validation failed for client: ISCCA.". I'm running the application with Kestrel on localhost.
Based on documentation and examples i've been through, this is my result so far:
Kestrel configuration:
webBuilder.ConfigureKestrel(builderOptions => {
builderOptions.ConfigureHttpsDefaults(httpOptions => {
httpOptions.AllowAnyClientCertificate();
httpOptions.ClientCertificateMode = ClientCertificateMode.AllowCertificate;
httpOptions.CheckCertificateRevocation = false;
});
});
Identity server configuration with in memory clients, resources and scopes:
services
.AddIdentityServer(options => {
// MTLS for client certificate authentication endpoints with default scheme set as Certificate
options.MutualTls.Enabled = true;
options.MutualTls.ClientCertificateAuthenticationScheme = CertificateAuthenticationDefaults.AuthenticationScheme;
// Use subdomain endpoints (mtls.host)
options.MutualTls.DomainName = "mtls";
})
.AddMutualTlsSecretValidators() // So that Identity Server knows to validate thumbprint or certificate name
.AddDeveloperSigningCredential()
.AddInMemoryApiResources(new List<ApiResource> {
new ApiResource(
name: "MyAPI", // Api resource name
displayName: "My API Set", // Display name
userClaims: new List<string> { "access" } // Claims to be included in access token
)
})
.AddInMemoryIdentityResources(GetIdentityResources()) // Contains only IdentityResources.OpenId()
.AddInMemoryClients(new List<Client>() {
new Client {
Enabled = true,
ClientId = "ISCCA",
ClientSecrets = {
// Testing env client certificate thumbprint secret
new Secret() {
Value = "<thumbprint>",
Type = SecretTypes.X509CertificateThumbprint
}
},
AccessTokenLifetime = 60 * 60 * 24,
AllowedGrantTypes = GrantTypes.ClientCredentials,
AllowedScopes = { "MyAPI" }
}
})
.AddInMemoryApiScopes(new List<ApiScope> {
new ApiScope {
Name = "MyAPI",
DisplayName = "Some API",
UserClaims = { "access" }
}
});
Authentication and authorization:
services
.AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme)
.AddCertificate(options => {
options.AllowedCertificateTypes = CertificateTypes.All;
options.RevocationMode = X509RevocationMode.NoCheck;
})
.AddIdentityServerJwt();
services.AddAuthorization(options => {
options.AddPolicy("ApiScope", policy => {
policy.RequireAuthenticatedUser();
policy.RequireClaim("access");
});
});
If i use a secret without defined type, the token is returned as expected, but when i want it to use the thumbprint, i get errors above.
I have set up the certificate in Postman and it is included in request, but i'm not sure if it comes to the server (everything is run localy on the same PC). As for token request and server response, below are screenshots of what is in auth header and response and Kestrel log:
I don't know what i did wrong. Also i have included
app.UseAuthentication();
app.UseIdentityServer();
app.UseAuthorization();
in Configure method.

How to fix 'client_id is missing or too long' while trying to login from an asp.net core 2.2 web app

I'm setting up my identity server to get access from a temporary port forwarded ip. The login works perfectly when I run everything localy but when I start using my public IP, it says that my client_id is missing or too long.
First I got an error that it couldnt access a local http request. This was because of the endpoints not using the right redirect URI's. I changed this by changing the public origin of the identityserver.
After that I could reach my login page and try to login to get an error
Sorry, there was an error : invalid_request
Invalid client_id
I checked the client id, but it's the right one.
In the console I get
fail: IdentityServer4.Validation.AuthorizeRequestValidator[0]
client_id is missing or too long
{
"SubjectId": "anonymous",
"RequestedScopes": "",
"Raw": {
"ReturnUrl": "/connect/authorize/callback?client_id=pokemon_code&redirect_uri=http%3A%2F%2Fbackendpokemonsite.azurewebsites.net%2Fsignin-oidc&response_type=id_token%20code&scope=openid%20profile%20pokemon%20role%20offline_access%20email&response_mode=form_post&nonce=636932445888919509.YTM5OTBlNDMtNWJkNC00MTJiLWI3YjAtNTIzMzY0ZmNkOGEyNzNlMjVhZjQtZGJhNC00MDk2LWIxYjItY2MwNWFmYTczNmU0&state=CfDJ8IxZ9MXLdlhLon2k58KSiTd3i19Dt1TM93X6-L-_SyUK_xpG5zn90n4y9RtMGlieCkdOPPnAg2VXrLoy1EXTZgGlLmsd7EIqORzq37XbF6Zj23rr7_shXOQcLY87Dywalv4VrRj6HKqUnNFGUE8cCKSXc6uiH0LDBTDPqAuU2QWWRJf-a07TAZw2YdbvanEbueXDKAL9ty57_O2pY1rS5_7ViiVVu_GP3ct8ytW6wY8_BBArqQZW7BspbQV5YzDfseVcSnh1dIRPXZTSvUyHWMvBIQTYb_xhctLoOpdzQC41XMCjP9lpkTBm2Vwv-izxlDWbT58DnVwNKnYTYUn0nhA",
"Username": "username",
"Password": "password",
"button": "login",
"__RequestVerificationToken": "CfDJ8N6qinc1TjFHrjbGhp-Exm0qSNXoKKJC77ipFBHfZWz2ukCowIEjgzRUy3ZRex2SEVLByyYCDoOfjxR-JUfdBj6IDUZAI5EHcFklOPLssWob-yJrrCio3VyrClZnlYkHSif3-yDvU0w-2GDs6S2lIKM",
"RememberLogin": "false"
}
}
fail: IdentityServer4.Endpoints.AuthorizeEndpoint[0]
Request validation failed
My onconfigure services from my identity server where I change my endpoint locations to my public IP:
services.AddIdentityServer(options=> options.PublicOrigin= "http://public-endpoint")
.AddSigningCredential(new X509Certificate2(AppDomain.CurrentDomain.BaseDirectory + "Configuration/pokemon.pfx","secretpassword")) .AddResourceOwnerValidator<ResourceOwnerPasswordValidator>()
.AddConfigurationStore(options => options.ConfigureDbContext = builder => builder.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"), dboptions => dboptions.MigrationsAssembly(assembly)))
.AddOperationalStore(options => options.ConfigureDbContext = builder => builder.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"), dboptions => dboptions.MigrationsAssembly(assembly)))
.AddAspNetIdentity<IdentityUser>();
This is my onconfigure for my web project:
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
services.AddAuthentication(options=> {
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
}).AddCookie("Cookies").AddOpenIdConnect("oidc",openid=> {
openid.SignInScheme = "Cookies";
openid.AuthenticationMethod = Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectRedirectBehavior.FormPost;
openid.Authority = "http://public-endpoint/";
openid.RequireHttpsMetadata = false;
openid.ClaimActions.Add(new RoleClaimAction());
openid.ClientId = "pokemon_code";
openid.ClientSecret = "secret";
openid.ResponseType = "id_token code";
openid.Scope.Add("pokemon");
openid.Scope.Add("role");
openid.Scope.Add("offline_access");
openid.Scope.Add("email");
openid.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
{
RoleClaimType = "role",
NameClaimType="role"
};
openid.GetClaimsFromUserInfoEndpoint = true;
openid.SaveTokens = true;
});
I expect the website to login ask for permission to use the account details. but now I get the error:
"Sorry, there was an error : invalid_request
Invalid client_id".
I'm pretty new to identity server so did i miss something?

Identity Server 4 Consent Screen Never Shows

I'm trying to get the Consent Screen to show from the Identity Server 4 Samples,
I've configured the client so it requires consent like so:
new Client
{
ClientId = "openIdConnectClient",
ClientName = "Example Implicit Client Application",
AllowedGrantTypes = GrantTypes.Implicit,
RequireConsent = true,
AllowedScopes = new List<string>
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.Email,
"role",
"customAPI"
},
RedirectUris = new List<string> {"https://localhost:44330/signin-oidc"},
PostLogoutRedirectUris = new List<string> { "https://localhost:44330" }
}
The project contains controllers and views for the Consent Screen However I cannot get it to load. If needed I can show the classes or views for the Consent.
Does anyone know how to configure IdentityServer4 to Display the Consent Screen?
You can force the consent screen to always be shown in your client by setting the Prompt property when you register the OpenIDConnect scheme:
.AddOpenIdConnect(options =>
{
options.Authority = "https://localhost:6001";
options.ClientId = "xxx";
options.ClientSecret = "xxxx";
options.ResponseType = "code";
...
options.Prompt = "consent";
});
Maybe Identity Server is remembering your previous consent. Just add this to the client options (the default value is true):
AllowRememberConsent = false,