Problem with custom claims when Windows authentication is used - c#

I'm trying to implement Windows authentication for Identity Server 4.
In my code, I use similar solutions to the one described in Identity server 4 windows authentication using extension Grant not working
First of all, I use the HttpSys server with a proper scheme
builder.WebHost.UseHttpSys(options =>
{
options.Authentication.Schemes = AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM;;
options.Authentication.AllowAnonymous = false;
});
then I add Negotiate for Authentication:
builder.Services.AddAuthentication(IdentityServerConstants.LocalApi.AuthenticationScheme)
.AddIdentityServerAuthentication(options =>
{
options.Authority = "http://localhost:5000";
options.ApiName = "server.api";
})
.AddNegotiate()
.AddLocalApi();
I also extend Identity Server with such code:
.AddExtensionGrantValidator<WinAuthGrantValidator>()
(the code of WinAuthGrantValidator can be found in this answer Identity server 4 windows authentication using extension Grant not working)
This seems to work and the user is authenticated. WindowsIdentity is in HttpContext.User.Identity - so far, so good.
Now is my problem, I have also registered ProfileService in the Identity Server 4 like so:
.AddProfileService<ProfileService>()
which adds some data to the logged in user (as an additional Claim) - this works if the user is logged in with username and password.
Unfortunately when I use Windows Authentication for logging, then ProfileService is invoked and adds some claims to IssuedClaims but later (in application code) I try to read those Claims from HttpContext.User it doesn't have it. Would you help me figure out why this is happening?
Thanks a lot!

Related

How to Authenticate two subdomain by one login in IdentityServer?

I have an IDP server implemented by Duende IdentityServer assume which is hosted on idp.com and there are two separate ReactJS applications hosted on app.mysite.com and profile.mysite.com and they are using JWT token for authentication and authorization process. now when I login into app.mysite.com through idp.com profile.mysite.com is un unauthenticated and needs another login. I use the same client configuration for both of these sites. I know there are some methods such as using an IFRAME inside client code to share the JWT token between these two app but I am looking for a built-in approach inside the Identity server to solve this issue?
First of all, if you have 2 CLIENTS, you should configure 2 separate configurations for both of them.
Afer separation of clients you should rely on cookie set on idp.com after first authentication. (Good to know - How to setup cookie authentication basic cookie authentication: https://learn.microsoft.com/pl-pl/aspnet/core/security/authentication/cookie?view=aspnetcore-6.0)
Anyway, if you configured IdentityServer properly, it handles cookie authentication "out-of-the-box" - so probably the only thing you have to do is to Signin the user.
AuthenticationProperties props = new AuthenticationProperties
{
IsPersistent = true,
ExpiresUtc = DateTimeOffset.UtcNow.Add(LoginOptions.RememberMeLoginDuration)
};
var issuer = new IdentityServerUser(user.SubjectId)
{
DisplayName = user.Username
};
await HttpContext.SignInAsync(issuer, props);
When the youser want to login to second application, after start of the flow (eg. code flow) and redirect to the idp.com, idp.com knows that the user is already signed-in (cookie) and should immediately generate token and redirect back to the return url.
If you need you can adjust custom behaviours using IProfileService.

ASP Net Identity - Adding a second authentication cookie

I'm trying to use a second cookie so that other applications in a subdomain can validate, if a user is logged in in my application. However i don't trust the other applications thats why I'm planning to use two Authentication Cookies. One for my own Application (IdentityCookie) and one so that the other Apps can access the login status (SubCookie).
I'm using ASP.NET Identity for cookie creation and account management.
services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>().AddSignInManager<AuthSignInManager<ApplicationUser>>();
services.ConfigureApplicationCookie(options =>
{
options.Cookie.SameSite = Microsoft.AspNetCore.Http.SameSiteMode.Strict;
options.CookieManager = new CookieManager();
});
The custom CookieManager is responsible for creating and deleting both Cookies at the same time.
My issue now is that I can't find a way to validate the cookies. I attempted to use a custom Authenticationhandler for the validation of the subCookie, but if I add the following code the IdentityCookie validation stops working:
services.AddAuthentication("CookieBearer").AddScheme<BasicAuthenticationOptions, BasicAuthenticationHandler>("CookieBearer", o => {});
It seemes like after adding this line only the Custom Handler is used and the one provided by Identity is ignored. Is there any way to add multiple AuthenticationHandlers with ASP.NET Identity? I want to use the custom AuthenticationHandler just as a fallback option. So that if authentication by Identity fails the custom AuthenticationHandler is used.
I know I can chain Authentication Schemes/Methods like this, but I'm not sure how to do it in combination with Identity.
services
.AddAuthentication()
.AddJwtBearer("Custom1", options =>
{
//Configure here
})
.AddJwtBearer("Custom2", options =>
{
// Configure here
});

Confusion about Google OAuth packages in ASP.NET Core

I need to access some Google APIs (via Google.Apis.* NuGet Packages). Therefore I need to use the Google.Apis.Auth.AspNetCore package as described in the
official documentation:
services
.AddAuthentication(o =>
{
o.DefaultChallengeScheme = GoogleOpenIdConnectDefaults.AuthenticationScheme;
o.DefaultForbidScheme = GoogleOpenIdConnectDefaults.AuthenticationScheme;
o.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddGoogleOpenIdConnect(options =>
{
options.ClientId = googleClientId;
options.ClientSecret = googleClientSecret;
});
On the other hand, I use classical ASP.NET Core Identity, especially the Google external login setup
using the
Microsoft.AspNetCore.Authentication.Google NuGet package which is initialized like this:
services
.AddAuthentication()
.AddGoogle(options =>
{
options.ClientId = googleClientId;
options.ClientSecret = googleClientSecret;
});
Is there a way to share the OAuth configurations, logins, ...? 🤔 Both packages use their own OAuth intialization code... 💭 Will I face problems calling both AddGoogle() and AddGoogleOpenIdConnect()?
Background info
Authorization is OAuth2. You would use it for example to request access to a users google drive account. Once you have been granted access you would be given a refresh token and you would be able to access the users data when ever you need.
Open id connect its authentication or login. It tells you that a user is in fact logged in it doesn't give you access to more then the users profile information by default.
Google.Apis.Auth.AspNetCore
Strictly speaking the Google APIs library normally only gave you access to authorization. However Google.Apis.Auth.AspNetCore does add an open id connect component to to the authentication in the form of AddGoogleOpenIdConnect which will give you both authentication and authorization at the same time.
Microsoft.AspNetCore.Authentication.Google
Is as its states Authentication or login. The user is logging in and authenticating that they are currently accessing your application.
recap
Microsoft.AspNetCore.Authentication.Google only gives you authentication or login, while Google.Apis.Auth.AspNetCore will potentially give you login and authorization.
Adding both
TBH I question why you would add both. Technically if you did and they didn't bash heads with each other which they might. You may end up with a double login. As these two libraries will both be trying to Authenticate the user. You will need two access tokens one for each library. I'm not sure if they set different cookies or not if they set the same cookie then they will reset each other cookies causing the user to need to login or authorize the application again to reset the cookie for each library you are trying to use.
Not to mention what adding [Authorize] attribute to a method is going to do how will it know which one to pick if your adding to authorization forms

Microsoft authentication automatically signing in account. Causing "Correlation failed" error when user manually selects account

We've been leveraging Cookie authentication within our .NET Core 2.2 application & logging users in after verifying their identity via Microsoft external 3rd party provider. Just recently, we've observed an error in this workflow which states:
Microsoft.AspNetCore.Authentication.MicrosoftAccount.MicrosoftAccountHandler:Information: Error from RemoteAuthentication: Correlation failed.."
We've narrowed it down to the scenario where if a user is already logged in to their Microsoft account (only one account logged in/active)... and if they then log in to our website they are automatically signed in without having to select their account name or any other interaction. What's more, if the user DOES click on their account name, this fires off another sign in request & I believe is resulting in the "Correlation failed.." error due to the request/response cookies being in conflict.
I am able to reproduce the issue from localhost, though our actual hosting provider is within Azure (App Services).
I've already explored some of the solutions/approaches mentioned within the following Microsoft docs which mention configuration for load balancers and proxy servers (Forwarding Headers)... as well as enforcing HTTPS in ASP.NET Core:
https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/proxy-load-balancer?view=aspnetcore-2.1
https://learn.microsoft.com/en-us/aspnet/core/security/enforcing-ssl?view=aspnetcore-2.1&tabs=visual-studio
These do not appear to address the root of the issue which I understand to be the automatic sign-on/selection of the user account when the security Challenge is made to the Microsoft provider.
Here is a snippet from our Startup.cs service configuration for the 3rd party authentication config.
// Authentication is added via Cookie
services.ConfigureApplicationCookie(options => options.LoginPath = "/Login");
services.AddAuthentication(opts =>
{
opts.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
opts.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie(opts =>
{
opts.Cookie.SecurePolicy = CookieSecurePolicy.Always;
opts.LoginPath = "/auth/login";
opts.LogoutPath = "/auth/logout";
opts.ClaimsIssuer = "<ISSUER_HERE>"; // *** redacted for privacy
})
.AddMicrosoftAccount(options =>
{
options.ClientId = Configuration["Authentication:ApplicationId"];
options.ClientSecret = Configuration["Authentication:Password"];
options.Events.OnRemoteFailure = ctx =>
{
// React to the error here. See the notes below.
ctx.Response.Redirect("/error?FailureMessage=" + UrlEncoder.Default.Encode(ctx.Failure.Message));
ctx.HandleResponse();
return Task.FromResult(0);
};
});
Ideally, the "automatic sign-on" behavior is prevented so the user must select their account from the Microsoft account selection prompt (even if they've previously signed in).
For now, we're redirecting the user to an error page, where we can clear all cookies and have the user re-attempt the login. This poses a problem if they continually select their user account during the login process & both requests are conflicting.
Any insight would be greatly appreciated!
Alrighty then, I got it.
It seems a bit hacky, but hey, it works.
.AddMicrosoftAccount(options =>
{
// Your configuration here
options.Events.OnRedirectToAuthorizationEndpoint = context =>
{
context.HttpContext.Response.Redirect(context.RedirectUri + "&prompt=select_account");
return Task.FromResult(0);
};
})

IdentityServer4 - Using External Authentication

I am trying to implement an Authorization server using IdentityServer4, using the Hybrid Flow.
let's say url is : auth.company.com
To authenticate users, the company uses a simple .NET MVC login/password form.
url : client.company.com/login.html
My question is : how can i plug the authentication system into the IdentityServer4 ?
I've tried adding this :
Startup.cs / ConfigureServices()
services.AddIdentityServer(SetupIdentityServer)
private static void SetupIdentityServer(IdentityServerOptions options)
{
options.UserInteraction.LoginUrl = #"client.company.com/login.html";
options.UserInteraction.LoginReturnUrlParameter = "referrer";
}
But it resulted in too many redirections error between auth server and authentication server
Thank you
I just replied to another question very similar to this so this is a shameless copy and paste of that:
This will not work as the identity server needs to issue its own cookie once authentication has taken place. This cookie is what allows the authorise endpoint to know who is signed in.
The intention of this model is that authentication takes place on the IDP or it’s negotiated with an external provider via a suitable protocol. Therefore the appropriate approach in this case is to move the login UI into your identity server application. It’s entirely up to you exactly how that is done and where it gets it’s data from but it must be your identityserver4 that issues the cookie.

Categories