identity callback path in production Azure website? - asp.net-core

I have a asp.net core 2 mvc app with openid connect authentication. It works locally in Visual Studio Debug to IIS Express.
After I deploy to Azure, I see this error: invalid_request: The provided value for the input parameter 'redirect_uri' is not valid
This is my appsettings callback path: "/Identity/AuthResult/"
do i need to put in a full URI ,like https://mysite.azurewebsites.net/Identity/AuthResult/ ?
this is my startup code: ` services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
.AddAzureAD(options => Configuration.Bind("AzureAd", options));
services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
{
options.Authority = options.Authority + "/v2.0/"; // Microsoft identity platform
options.TokenValidationParameters.ValidateIssuer = false; // accept several tenants (here simplified)
});`
I am following this wiki Quickstart: Add sign-in with Microsoft to an ASP.NET Core web app

Related

How to combine multiple authentication schemes for different types of clients (user/pass and client/secret) in a Blazor WASM project?

I have a Blazor WASM project with a Blazor Client and ASP.NET core server. I can authenticate with user/password using the following code:
services
.AddDefaultIdentity<ApplicationUser>(
options => options.SignIn.RequireConfirmedAccount = true)
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
services
.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
services
.AddAuthentication()
.AddIdentityServerJwt();
services.AddTransient<IProfileService, ProfileService>();
services.AddAuthorization(options =>
{
options.AddPolicy("ApiScope", policy =>
{
policy.RequireAuthenticatedUser();
policy.RequireClaim("scope", "api1");
});
});
When I add the following code, I can successfully authenticate with clientcredentials from a console client. But then the Blazor client user/password authentication stops working.
...
services
.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>()
+.AddInMemoryApiScopes(Config.ApiScopes)
+.AddClientStore<ClientStore>()
+.AddDeveloperSigningCredential();
services
.AddAuthentication()
.AddIdentityServerJwt();
+services
+ .AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
+ .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>
+ {
+ options.Authority = "https://localhost:44311";
+ options.TokenValidationParameters = new TokenValidationParameters
+ {
+ ValidateAudience = false,
+ };
+ });
...
In the browser while trying to authenticate in the Blazor client, the console prints:
info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2]
Authorization failed. These requirements were not met:
DenyAnonymousAuthorizationRequirement: Requires an authenticated user.
I have tried a lot, but I'm not able to make both work together. It seems that somehow this configuration requires authentication for everything, even the pages/controllers that are marked AllowAnonymous. So, when I try to authenticate, it gives me an error telling me the user must be authenticated: DenyAnonymousAuthorizationRequirement. The policy, "ApiScope" is only intended for the clientcredentials client, not for the Blazor client. If removed, the RequireAuthenticatedUser call doesn't make a difference, same error.
Any help is appreciated.

Log in with Azure AD and get a UserManager

I have two websites, a "customer" website that contains local users stored in Identity tables in a SQL Server database, and a "management" website the logs in users via our Azure AD. Both websites share a common view of the SQL database (I put the migrations and DbContext in a shared library).
My management website wants to automatically redirect users to Azure AD if they are not authenticated. This is done in Startup.cs via:
// Use AzureAD for authentication
services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
.AddAzureAD(options => Configuration.Bind("AzureAd", options));
So far, so good... The above code causes the website to automatically log in via my Azure AD.
Now for the complication: Code in the the management website wants to manipulate "Identity" users created by the "customer" website. To do this, the management website needs UserManager and RoleManager instances. But the only way I know to wire up a UserManager or a 'RoleManager' is to call AddIdentity or AddDefaultIdentity, like this:
// Configure Identity
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
// Use AzureAD for authentication
services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
.AddAzureAD(options => Configuration.Bind("AzureAd", options));
This allows me to use DI to get a UserManager or RoleManager instance elsewhere in the code, but it turns off the automatic login via Azure AD and tries to redirect to the Identity login page (which, in my "management" website, doesn't exist).
How can I configure Identity while retaining the automatic Azure AD login behavior?
EDIT:
Microsoft tech support is working on this. I'll post the answer when I get it from them.
Use AddIdentityCore and inject UserManager and RoleManager separately like below
services.AddIdentityCore<AppUser>(options =>
options.SignIn.RequireConfirmedAccount = false)
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<AppUserContext>();
services.AddScoped<UserManager<AppUser>>();
services.AddScoped<RoleManager<IdentityRole>>();
services.AddScoped<IRoleStore<IdentityRole>, RoleStore<IdentityRole, ApplicationDbContext>>();
Reference on AddIdentityCore
Difference between AddIdentity and AddIdentityCore Refer
Github sample here
It seems that Identitys authentication theme Identity.Application is used in the default authorization policy for your authorized controllers. Try to explicitly set the default authorization policy to use the AzureAD authentication theme, e.g.:
services.AddAuthorization(options =>
{
options.DefaultPolicy = new AuthorizationPolicyBuilder()
.AddAuthenticationSchemes(AzureADDefaults.AuthenticationScheme)
.RequireAuthenticatedUser()
.Build();
});
Edit:
Have a look at the AddIdentity extension method in IdentityServiceCollectionExtensions.cs on GitHub, within that method AddAuthentication is called:
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = IdentityConstants.ApplicationScheme;
options.DefaultChallengeScheme = IdentityConstants.ApplicationScheme;
options.DefaultSignInScheme = IdentityConstants.ExternalScheme;
})
Perhaps you have to overwrite these settings with the corresponding constants from the AzureADDefaults in the AddAuthentication call on which you call AddAzureAd like:
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = AzureADDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = AzureADDefaults.AuthenticationScheme;
options.DefaultSignInScheme = AzureADDefaults.CookieScheme; // not sure
})
.AddAzureAD(options => Configuration.Bind("AzureAd", options));

Share authentication cookie across subdomains in ASP.NET Core - cannot login

I am trying to implement sharing authentication cookie across two subdomains in ASP.NET Core web apps. I have changed Startup.cs and added following code in ConfigureServices:
services.AddDataProtection()
.PersistKeysToAzureBlobStorage(new Uri("{{my_url_to_blob_storage}}"))
.SetApplicationName("myapp");
services.AddAuthentication(sharedOptions =>
{
sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
{
options.Cookie.Name = "myapp";
options.Cookie.Domain = ".azurewebsites.net";
});
I have published the web app to Azure, but when trying HttpContext.SignInAsync(), nothing happens - HttpContext.User is not set.
Thanks for any help
Solved! When using custom domain, everything runs as expected

aspnet core and AzureAD: is there a way to intercept the authentication?

When creating an ASP.NET Core MVC 2.1 project, I can set the authentication method to Azure AD. Now, the generated code does work and I've noticed that the authentication is set up like this:
services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
.AddAzureAD(options => Configuration.Bind("AzureAd", options));
Now, when if I setup the OpenIdConnect provider directly, I can set up the Events property which would let me hook up code during the authentication process:
services.AddOpenIdConnect(options => {
options.Events = new OpenIdConnectEvents {
OnTokenValidated = PerformExtraValidationsBeforeLoggingIn,
}
});
Is there a way to do the same with the Azure Ad helpers that are used by the Wizard or must I go use the openid connect directly in order to achieve this?
Thanks,
Luis

Asp.Net Core 2.0 and Azure AD B2C for authentication on WebApp and API

I have an existing small app that I use for test, it is in Asp.Net Core 1.1 for both the Web App and the API, the authentication is done using Azure AD B2C.
I am trying to move it to .Net Core 2.0 but I can't figure how to get it working, I tried using both sample from GitHub Azure-Samples for Web App and API, but I have either an unauthorized or 500 error when trying to access the api, if you have a working example for calling a web api from a web app using 2.0 and protected by AD B2C it will be greatly appreciated.
Edit:
The sample I use to test are :
Web App : WebApp-OpenIDConnect-DotNet core2.0
Web Api : B2C-WebApi core2.0
, I changed the appsettings values to match my b2c directory.
For my asp.net core 1.1 test app I use the same samples as above but from the master branch, with the same value for appsettings.
Edit 2
by default, in startup.cs I have this :
services.AddAuthentication()
.AddJwtBearer(option => new JwtBearerOptions
{
Authority = string.Format("https://login.microsoftonline.com/tfp/{0}/{1}/v2.0/",
Configuration["Authentication:AzureAd:Tenant"], Configuration["Authentication:AzureAd:Policy"]),
Audience = Configuration["Authentication:AzureAd:ClientId"],
Events = new JwtBearerEvents
{
OnAuthenticationFailed = AuthenticationFailed
}
});
which gives me the following error:
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 GET http://localhost:44352/api/values/5
Microsoft.AspNetCore.Server.Kestrel:Error: Connection id "0HL89JHF4VBLM", Request id "0HL89JHF4VBLM:00000001": An unhandled exception was thrown by the application.
System.InvalidOperationException: No authenticationScheme was specified, and there was no DefaultChallengeScheme found.
if modified services.AddAuthentication like that
services.AddAuthentication(sharedOption =>
{
sharedOption.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
the error is now
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler:Information: Failed to validate the token xxx.
Microsoft.IdentityModel.Tokens.SecurityTokenInvalidSignatureException: IDX10500: Signature validation failed. No security keys were provided to validate the signature.
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(String token, TokenValidationParameters validationParameters)
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateToken(String token, TokenValidationParameters validationParameters, SecurityToken& validatedToken)
at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.d__6.MoveNext()
I saw a pull request on the sample which correct this issue (Link), the services.AddAuthentication must be change to:
services.AddAuthentication(options =>
{
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(jwtOptions =>
{
jwtOptions.Authority = $"https://login.microsoftonline.com/tfp/{Configuration["Authentication:AzureAd:Tenant"]}/{Configuration["Authentication:AzureAd:Policy"]}/v2.0/";
jwtOptions.Audience = Configuration["Authentication:AzureAd:ClientId"];
jwtOptions.Events = new JwtBearerEvents
{
OnAuthenticationFailed = AuthenticationFailed
};
});
I got this example working both for Core 1.1 and Core 2.0, please add the Oath Authentication as below,
services.AddAuthentication(sharedOptions =>
{
sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
sharedOptions.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddAzureAdB2C(options => Configuration.Bind("Authentication:AzureAdB2C", options))
You configuration options will be defined inside of the class "AzureAdB2CAuthenticationBuilderExtensions", which is found inside of the
azure b2c project
Looks like your token is not being update it from the Azure, are you able to get the token from your web app? could you please verify that you are not getting null
Did you register your api scopes on your azure b2c tenant web app?
"ApiScopes": "https://fabrikamb2c.onmicrosoft.com/demoapi/demo.read"
you have to set scope in your web api and allows to be read on the web app, please follow click the link in order to set it up