Exception: Correlation failed. Unknown location (Azure AD B2C) - c#

I have an ASP.NET Core 2.2 application with the following configuration:
And this is my Startup.cs class
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies")
.AddOpenIdConnect("oidc", options =>
{
options.SignInScheme = "Cookies";
options.Authority = $"{ Configuration.GetValue<string>("AzureAdB2C:Instance") }/{ Configuration.GetValue<string>("AzureAdB2C:Tenant") }/{ Configuration.GetValue<string>("AzureAdB2C:SignUpSignInPolicyId") }/v2.0";
options.ClientId = Configuration.GetValue<string>("AzureAdB2C:ClientId");
options.ResponseType = "code id_token";
options.SaveTokens = true;
options.ClientSecret = Configuration.GetValue<string>("AzureAdB2C:ClientSecret");
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
When I run this the B2C login page pops-up, however once I enter the credentials I get the error below. URL is redirected to https://localhost:xxxx/signin-oidc
How can I solve this problem?

This is the similar issue, the same error occurred when external login is canceled and redirects to the source application. You could use OnRemoteFailure to handle the exception.
AddOpenIdConnect("oidc", options => {
// ...
options.Events = new OpenIdConnectEvents
{
OnRemoteFailure = ctx =>
{
ctx.Response.Redirect("/error?FailureMessage=" + UrlEncoder.Default.Encode(ctx.Failure.Message));
ctx.HandleResponse();
return Task.FromResult(0);
}
};
});

Related

IdentityServer4 with ASP.NET Identity and client credentials flow

I have IdentityServer4 (IDS4) working with multiple apps (Blazor WASM, ASP.NET Core API) using authorization_code. I'm using ASP.NET Identity for all apps.
I added one more API controller to Identityserver4 app (Controllers/Api/AccountController) and added one client for client_credentials flow. Purpose of this client is to access AccountController from API projects with authorization.
When I call IDS/api/Account/Register, it redirects to login page. Without [Authorize] attribute, it works fine.
How can I configure authorization for a client_credentials flow client?
Here are my IDS configs:
var services = builder.Services;
var configuration = builder.Configuration;
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
//options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.Lax;
});
builder.Services.AddControllersWithViews()
.AddSessionStateTempDataProvider()
.AddRazorPagesOptions(options =>
{
//options.AllowAreas = true;
//options.Conventions.AuthorizeAreaFolder("Identity", "/Account/Manage");
});
var connectionString = configuration.GetConnectionString("MSSQLConnection");
var applicationName = builder.Environment.ApplicationName;
services.AddDbContext<AppDbContext>(builder => builder.UseSqlServer(connectionString,
options => options.MigrationsAssembly(applicationName)));
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<AppDbContext>()
.AddDefaultTokenProviders();
//.AddDefaultUI();
services.AddLogging(options =>
{
options.AddConsole();
});
services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
});
// ..or configures IIS out-of-proc settings
services.Configure<IISOptions>(iis =>
{
iis.AuthenticationDisplayName = "Windows";
iis.AutomaticAuthentication = false;
});
// ..or configures IIS in-proc settings
services.Configure<IISServerOptions>(iis =>
{
iis.AuthenticationDisplayName = "Windows";
iis.AutomaticAuthentication = false;
});
services.AddIdentityServer(options =>
{
options.Events.RaiseErrorEvents = true;
options.Events.RaiseFailureEvents = true;
options.Events.RaiseInformationEvents = true;
options.Events.RaiseSuccessEvents = true;
options.Discovery.ShowIdentityScopes = false;
options.Discovery.ShowApiScopes = false;
options.Discovery.ShowClaims = false;
options.Discovery.ShowExtensionGrantTypes = false;
options.UserInteraction.LoginUrl = "/Account/Login";
options.UserInteraction.LogoutUrl = "/Account/Logout";
options.Authentication = new IdentityServer4.Configuration.AuthenticationOptions()
{
CookieLifetime = TimeSpan.FromHours(10), // ID server cookie timeout set to 10 hours
CookieSlidingExpiration = true
};
})
.AddOperationalStore(options => options.ConfigureDbContext = builder =>
builder.UseSqlServer(connectionString, options => options.MigrationsAssembly(applicationName)))
.AddConfigurationStore(options => options.ConfigureDbContext = builder =>
builder.UseSqlServer(connectionString, options => options.MigrationsAssembly(applicationName)))
.AddAspNetIdentity<ApplicationUser>()
.AddInMemoryCaching()
.AddResourceOwnerValidator<ResourceOwnerPasswordValidatorService>()
.AddSigningCredential(certificate);
services.AddAuthentication();
services.AddLocalApiAuthentication();
services.AddAuthorization(options =>
{
options.AddPolicy(Roles.Admin,
policy => policy.RequireClaim(JwtClaimTypes.Role, Roles.GetRoleName(UserRole.Admin)));
options.AddPolicy(Roles.SuperAdmin, policy =>
policy.RequireAssertion(context =>
context.User.HasClaim(JwtClaimTypes.Role, Roles.SuperAdmin) || context.User.HasClaim(JwtClaimTypes.Role, Roles.Admin)));
});
services.AddSession(options => {
options.IdleTimeout = TimeSpan.FromMinutes(10);
});
Update (Resolution)
Finally resolved using Bearer AuthenticationScheme support to IDS for Api Endpoints
In Program.cs
services.AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme)
.AddIdentityServerAuthentication(options =>
{
options.Authority = IdentityServerUtility.Authority;
options.ApiName = "IDS_API";
});
In Controller Authorization including policy works fine.
[Route("api/[controller]")]
[ApiController]
[Authorize(AuthenticationSchemes = IdentityServerAuthenticationDefaults.AuthenticationScheme)]
public class AccountController : ControllerBase
{
[Authorize(Policy=Roles.Admin)]
[HttpPost("Register")]
public async Task<AppActionResult> Register([FromBody] UserDto model)
{
//...
}
}
Thank you.

.Net Core Identity User not populated when using OpenIdConnect

I'm implementing OpenIdConnect into a .Net Core app, which associates an external login with a user stored in an internal (default Identity) database, and attempts to log in. The log in method reports success, but the User object isn't populated.
The login process was scaffolded in, so it's all boilerplate, including the external login process.
I'd appreciate any help in understanding what I'm doing wrong.
services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
options.DefaultAuthenticateScheme = "oidc";
options.DefaultSignInScheme = IdentityConstants.ExternalScheme;
})
.AddCookie()
.AddOpenIdConnect(options =>
{
options.Authority = oauthSettings.Location.AbsoluteUri;
options.RequireHttpsMetadata = false;
options.ClientId = oauthSettings.ClientID;
options.ClientSecret = oauthSettings.ClientSecret;
options.ResponseType = "id_token token";
options.Scope.Add("openid");
options.Scope.Add("profile");
options.Scope.Add("email");
});
//In Login.cshtml.cs
public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
returnUrl = returnUrl ?? Url.Content("~/");
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
if (ModelState.IsValid)
{
// This doesn't count login failures towards account lockout
// To enable password failures to trigger account lockout, set lockoutOnFailure: true
var result = await _signInManager.PasswordSignInAsync(Input.Email, Input.Password, Input.RememberMe, lockoutOnFailure: false);
if (result.Succeeded)
{
_logger.LogInformation("User logged in.");
return LocalRedirect(returnUrl);
}
if (result.RequiresTwoFactor)
{
return RedirectToPage("./LoginWith2fa", new { ReturnUrl = returnUrl, RememberMe = Input.RememberMe });
}
if (result.IsLockedOut)
{
_logger.LogWarning("User account locked out.");
return RedirectToPage("./Lockout");
}
else
{
ModelState.AddModelError(string.Empty, "Invalid login attempt.");
return Page();
}
}
// If we got this far, something failed, redisplay form
return Page();
}
EDIT: I've found that when I remove the AddAuthentication method in Startup the login works, but obviously that disabled the external auth. Something about adding OpenIdConnect is breaking the login process.
To fix this I did the following in the startup:
services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
options.DefaultAuthenticateScheme = "oidc";
options.DefaultSignInScheme = IdentityConstants.ExternalScheme;
})
.AddCookie()
.AddOpenIdConnect(options =>
{
options.Authority = oauthSettings.Location.AbsoluteUri;
options.RequireHttpsMetadata = false;
options.ClientId = oauthSettings.ClientID;
options.ClientSecret = oauthSettings.ClientSecret;
options.ResponseType = "id_token token";
options.Scope.Add("openid");
options.Scope.Add("profile");
options.Scope.Add("email");
});
So I left it to its defaults and it worked. I'm not 100% why.

Why is it not possible to set options in IdentityServer?

I have been tried to apply several kind of setting on Startup.cs as shown ob the given link:
https://identityserver4.readthedocs.io/en/latest/quickstarts/2_interactive_aspnetcore.html
But unfortunately I cannot set the base url for Authority parameter when I check on the following url:
https://my-pc-id:8085/_configuration/MyApp.WebUI
It seems to be weird, because if we cannot set this parameter, why there is such an option on this config?
using System.IdentityModel.Tokens.Jwt;
// ...
JwtSecurityTokenHandler.DefaultMapInboundClaims = false;
services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies")
.AddOpenIdConnect("oidc", options =>
{
options.Authority = "my-pc-id:8085";
options.ClientId = "mvc";
options.ClientSecret = "secret";
options.ResponseType = "code";
options.SaveTokens = true;
});
Change the Authority property like so:
// base-address of your identityserver
.Authority = "https://my-pc-id:8085/_configuration/MyApp.WebUI";

Unknown client or client not enabled Identity Server 4

I have been getting this error and i have searched for answer online and almost all of them has been talking about requesturis and i have double checked to make sure that my uris are configured properly. I did not find any clue about it. Any thoughts.
Identity Server 4 settings:-
public static IEnumerable<Client> GetClients()
{
return new List<Client>()
{
new Client
{
ClientName="KtsWeb App",
ClientId="ktswebclient",
AllowedGrantTypes= GrantTypes.Hybrid,
AccessTokenType = AccessTokenType.Reference,
RedirectUris = new List<string>()
{
"https://localhost:44355/signin-oidc" //Client URL Address
},
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile
}
}
};
}
Client settings:-
services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
}).AddCookie("Cookies",
(options) =>
{
options.AccessDeniedPath = "/Authorization/AccessDenied";
})
.AddOpenIdConnect("oidc", options =>
{
options.SignInScheme = "Cookies";
options.Authority = "https://localhost:44380"; //Identity Server URL Address
options.ClientId = "ktswebclient";
options.ResponseType = "code id_token";
options.Scope.Add("openid");
options.Scope.Add("profile");
options.SaveTokens = true;
});
You should always check the identity server logs it would have given you a clear error message probably unsupported grant type.
You have created a hybrid client but forgot to add the secret.
new Client
{
ClientId = "mvc",
ClientName = "MVC Client",
AllowedGrantTypes = GrantTypes.Hybrid,
ClientSecrets =
{
new Secret("secret".Sha256())
},
RedirectUris = { "http://localhost:5002/signin-oidc" },
PostLogoutRedirectUris = { "http://localhost:5002/signout-callback-oidc" },
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
"api1"
},
AllowOfflineAccess = true
}
};
Your code isnt supplying the secret
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies")
.AddOpenIdConnect("oidc", options =>
{
options.SignInScheme = "Cookies";
options.Authority = "http://localhost:5000";
options.RequireHttpsMetadata = false;
options.ClientId = "mvc";
options.ClientSecret = "secret";
options.ResponseType = "code id_token";
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
options.Scope.Add("api1");
options.Scope.Add("offline_access");
options.ClaimActions.MapJsonKey("website", "website");
});

Authenticating an ASP.NET Core WebAPI using an ASP.NET Core MVC with Azure AD

I have two web applications: one ASP.NET Core MVC Website and one ASP.NET Core Web API (using ASP.NET Core 2.1).
I authenticate the users in the website using Azure AD. When I pass the access_token from the website to the API (using the Authorization header with "Bearer access_token"); I have this error:
Microsoft.IdentityModel.Tokens.SecurityTokenInvalidSignatureException:
IDX10503: Signature validation failed. Keys tried:
'Microsoft.IdentityModel.Tokens.X509SecurityKey , KeyId: ... '.
I don't understand why.
Here is the configuration of the Website:
services.AddAuthentication(o =>
{
o.DefaultChallengeScheme = "aad";
o.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
o.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, o =>
{
o.Authority = azureAdsettings.Authority;
o.Audience = azureAdsettings.ClientId;
})
.AddCookie()
.AddOpenIdConnect("aad", o =>
{
o.Authority = azureAdsettings.Authority;
o.AuthenticationMethod = OpenIdConnectRedirectBehavior.RedirectGet;
o.ClientId = azureAdsettings.ClientId;
o.ClientSecret = azureAdsettings.ClientSecret;
o.ResponseType = OpenIdConnectResponseType.CodeIdToken;
o.SaveTokens = true;
o.TokenValidationParameters = new TokenValidationParameters
{
ValidIssuer = azureAdsettings.Authority
};
o.Events = new OpenIdConnectEvents
{
OnTicketReceived = ctx =>
{
return Task.CompletedTask;
},
OnAuthorizationCodeReceived = async ctx =>
{
TokenProvider tokenProvider = (TokenProvider)ctx.HttpContext.RequestServices.GetRequiredService<ITokenProvider>();
await tokenProvider.AcquireTokenByAuthorizationCodeAsync(ctx);
},
OnAuthenticationFailed = context =>
{
context.Response.Redirect("/Error");
context.HandleResponse(); // Suppress the exception
return Task.CompletedTask;
},
};
});
And here is the configuration of the API:
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
options.Authority = this.Configuration["AzureAd:Authority"];
options.Audience = this.Configuration["AzureAd:ClientId"];
options.TokenValidationParameters.ValidateIssuer = true;
options.TokenValidationParameters.IssuerValidator = ValidateIssuer;
});
The azureAdsettings object is exaclty the same in both appsettings.json.
The authentication on the website seems to work nicely. I can get the authorization code and retreive access token.

Categories

Resources