Windows authentication in blazor server with custom AuthenticationStateProvider for JWT - authentication

I have Blazor server application what uses JWT tokens for authentication. For that there is implementation of custom AuthenticationStateProvder. This works just fine but now i need to add option to use Windows authentication to the application. I have added the required code to Program.cs:
builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme).AddNegotiate();
builder.Services.AddAuthorization(options =>
{
// By default, all incoming requests will be authorized according to the default policy.
options.FallbackPolicy = options.DefaultPolicy;
});
But since i am using custom AuthenticationStateProvider its just doesnt work. Authentication state is always asked from the custom GetAuthenticationStateAsync. If i remove that the authentication state is properly filled with windows authentication information.
Is there a way to use both of these methods same time or is the only solution to have seperate project for windows authentication?

Related

Single sign-out in ASP.NET Core OpenID Connect

I have a number of applications that authenticate users through single sign-on (SSO) with Auth0. One of these is an ASP.NET Core MVC application, which uses the ASP.NET Core OpenID Connect (OIDC) middleware. The single sign-on works fine. For single sign-out from the current app, I'm calling Auth0's /v2/logout endpoint from the OnRedirectToIdentityProviderForSignOut event, per Auth0's quickstart example. However, I don't know how to configure the app to clear the local session when there is an SSO session sign-out from another app. Auth0 mentions:
Redirecting users to the logout endpoint does not cover the scenario where users need to be signed out of all of the applications they used. If you need to provide this functionality you will have to handle this in one of two ways:
Have short timeouts on your local session and redirect to Auth0 at short intervals to re-authenticate. This can be done by calling checkSession from the client which does this redirect in a hidden iFrame. If you take the hidden iFrame approach you need to be aware of rate limits and third-party cookie issues.
Handle this entirely at the application level by providing your applications a way to notify all other applications when a logout occurs.
I get the impression that the checkSession suggestion is intended for SPAs. How does the ASP.NET Core OpenID Connect middleware handle such SSO session sign-outs? Does it automatically re-authenticate with the authentication server at regular intervals? If so, how can this frequency be configured?
The AddOpenIDConnect middleware module have a dedicated URL that it listens on and that the external provider can call after it has signed out the user.
The URL is defined in the source here and looks like this:
SignedOutCallbackPath = new PathString("/signout-callback-oidc");
RemoteSignOutPath = new PathString("/signout-oidc");
/// <summary>
/// The request path within the application's base path where the user agent will be returned after sign out from the identity provider.
/// See post_logout_redirect_uri from http://openid.net/specs/openid-connect-session-1_0.html#RedirectionAfterLogout.
/// </summary>
public PathString SignedOutCallbackPath { get; set; }
/// <summary>
/// Requests received on this path will cause the handler to invoke SignOut using the SignOutScheme.
/// </summary>
public PathString RemoteSignOutPath { get; set; }
So you could try to configure Auth0 to call the RemoteSignOutPath then that could perhaps work for you. However if you many many clients, then you need to have a different strategy. Perhaps use shorter access-token lifetime?
I've accepted Tore's answer since it's the best approach when front-channel logout is supported by the OpenID identity provider. In my case, Auth0 doesn't support OpenID Connect front- or back-channel logout:
Other than when Auth0 is using SAML, Auth0 does not natively support Single Logout. Single Logout can be achieved by having each application check the active session after their tokens expire, or you can force log out by terminating your application sessions at the application level.
I managed to achieve this in ASP.NET Core MVC 3.1 by reducing the ExpireTimeSpan in the AddCookie configuration:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(/* ... */)
.AddCookie(options =>
{
options.ExpireTimeSpan = TimeSpan.FromMinutes(1);
});
// ...
}
}
Consequently, any controller method decorated with [Authorize] would automatically re-authenticate with Auth0 every minute. If the Auth0 session is still active, the user would get immediately redirected to the target page. If not, they would be presented with the Auth0 login page.

Can System.Web be used within a class library that targets .net standard 2.0

I have an Asp.net application that uses form authentication. I am building an asp.net core API that will receive a JWT token that has user information included in the payload. This API needs to call asp.net application for serving the user request. In order for asp.net application to serve this request, it needs the form authentication cookie to recognize it as valid logged in user.
In other words, the API needs to generate and send an authentication cookie in the request forwarding stimulating scenario that actual user is making the request.
Note:
The API is being created to expose features of the asp.net application as a public API without user having to log in to the asp.net application UI directly first.
I am creating a class library that target .net standard 2.0 that can be used in my api that takes care of creating cookie part and add it to the request before it forwards the request to my asp.net application. How can I create FormAuthenication cookie in my class library? I found following code and wondering how can I do similar in my library?
string userData = string.Join("|",GetCustomUserRoles());
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
1, // ticket version
username, // authenticated username
DateTime.Now, // issueDate
DateTime.Now.AddMinutes(30), // expiryDate
isPersistent, // true to persist across browser sessions
userData, // can be used to store additional user data
FormsAuthentication.FormsCookiePath); // the path for the cookie
// Encrypt the ticket using the machine key
string encryptedTicket = FormsAuthentication.Encrypt(ticket);
// Add the cookie to the request to save it
HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
cookie.HttpOnly = true;
No. System.Web is .NET Framework only. It is not included nor compatible with .NET Standard, any version. Additionally, Forms Auth, in general, is deprecated (as part of ASP.NET Membership), so nothing but ASP.NET (.NET Framework) will ever be able to work with it.
Going forward, if you need to share authentication, you must switch to ASP.NET (Core) Identity and utilize the data protection API, rather than the old-style machine key encryption Forms Auth depends on.
For what it's worth though, an API should not be using cookie authentication. Cookies are a non-standard way for clients to interact with an API, and they're also a form of state, whereas APIs should be stateless (REST). Instead, you should be doing something like basic or bearer authentication, using the Authorization header to authorize each request either with user/pass (basic) or token (bearer).

Identity Server 4 User management API

I've managed to get a solution working with a single page application project (ReactJS), an API running on ASP.net Core project and an IdentityServer 4 project.
I want to be able to call an API on the IdentityServer 4 project from the single page application project.
I created a simple controller class in the IdentityServer 4 application, with the authorize attribute. If I call it via Postman, however, I get the HTML for the login page back.
This happens after I already logged in on the API, and I use that same token.
How am I supposed to log in to identity server to make calls to it to manage users?
As stated in the comments, you should definitely add more information to your question. Your controller is part of the identity server's mvc application? Are you using AspnetCore.Identity?
If so, your controller is protected by AspnetCore.Identities's cookie authentication scheme. You need to send the cookie to access the controller. This has nothing to do with identity server as you are on the local MVC application, it's just plain vanilla MVC.
Postman has problems sending cookies, you need the interceptor chrome extension. You also need to login though postman.
This will probably work if the SPA is hosted by the same MVC application. If not you will need to configure your mvc applications to validate access tokens (not just issue them), like this:
// Adds IdentityServer
app.UseIdentityServer();
// Accept access tokens from identity server
app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions
{
Authority = "http://localhost:5000",
RequireHttpsMetadata = false,
AuthenticationScheme = "Bearer"
ApiName = "api1"
});
This way you can request access tokens for your local api through identity server, (You also need to configure an api scope for 'api1').
To validate them in your api-controller add this to your controller:
[Authorize(ActiveAuthenticationSchemes = "Bearer")]
[HttpGet]
public string Bearer()
{
return "Access Token Accepted";
}

How to set up cookie based authentication with NancyFx and IdentityServer3 (non-API website)

We have an environment with the following:
Standalone IdentityServer3 instance (issues reference tokens, not jwt)
ASP.NET WebAPI resource server
.NET client applications that authenticate against IdSvr (via resource owner flow)
...and now we'd like to start adding an OWIN-hosted web app that will use NancyFx to serve server-rendered pages as well as a couple AngularJS SPAs. This Nancy website will NOT host any APIs, but may consume data from our existing API. I'd like to add authentication in the OWIN pipeline to help secure our Angular applications from being sent down to users who don't have access.
This would be in contrast to sending down the SPA code, and having Angular determine if the user should see anything. In that case we've already exposed the javascript code base, and this we want to avoid.
I'm trying to understand how I should configure this Nancy site to authenticate users against IdentityServer using the implicit flow. I have implemented this authentication scheme in standalone SPAs before (where all authentication was handled by AngularJS code and tokens were stored in HTML5 local storage), but I'm a bit lost on how to properly tackle this within the OWIN pipeline.
I'm thinking that the OWIN cookie authentication middle-ware is the answer, but does that mean the following?
I need to redirect the user to IdentityServer (using the proper url arguments for implicit flow)?
IdentityServer will redirect the user back to my site on a successful login, so is that where I hook into the OWIN Authorization manager to set the appropriate cookie?
...or am I thinking about this all wrong?
For reference, I've read through the following posts, and they're very helpful but I'm not quite seeing the big picture with OWIN. I'm going to experiment with the UseOpenIdConnectAuthentication middle-ware next, but I would appreciate any guidance SO might have here.
http://brockallen.com/2013/10/24/a-primer-on-owin-cookie-authentication-middleware-for-the-asp-net-developer/
https://github.com/IdentityServer/IdentityServer3/issues/487
Fundamentally, implementing OpenID Connect authentication in a Nancy app hosted via OWIN is really not different from implementing it in any MVC/Katana app (the Thinktecture team has a sample for this scenario: https://github.com/IdentityServer/IdentityServer3.Samples/tree/master/source/Clients/MVC%20OWIN%20Client)
You basically need 3 things: the cookie middleware, the OpenID Connect middleware and the Nancy middleware:
public class Startup {
public void Configuration(IAppBuilder app) {
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions {
AuthenticationMode = AuthenticationMode.Active,
AuthenticationType = CookieAuthenticationDefaults.AuthenticationType
});
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions {
AuthenticationMode = AuthenticationMode.Active,
// Set the address of your OpenID Connect server:
Authority = "http://localhost:54541/"
// Set your client identifier here:
ClientId = "myClient",
// Set the redirect_uri and post_logout_redirect_uri
// corresponding to your application:
RedirectUri = "http://localhost:56765/oidc",
PostLogoutRedirectUri = "http://localhost:56765/"
});
app.UseNancy(options => options.PerformPassThrough = context => context.Response.StatusCode == HttpStatusCode.NotFound);
}
}
If you're looking for a functional demo, you can take a look at https://github.com/aspnet-contrib/AspNet.Security.OpenIdConnect.Server/tree/dev/samples/Nancy/Nancy.Client (note: it doesn't use IdentityServer3 for the OIDC server part but it shouldn't make any difference for the client app).

What are the correct authentication settings for an on-premise ADFS flow?

I've been reading Vittorio Bertocci's blog to try to get up to speed on using ADFS to manage authentication and claims in either an MVC app or WebApi service. It looks like it's getting to be very approachable.
I am now trying to build out a POC using ADFS to do common claims resolution for internal sites/services in our enterprise. Our users would be on the internal network along with our endpoints. Right now we use Windows Integrated auth by default and each site does the work of looking up a user’s name, email, and other AD details and inspecting the claims principal for roles via IsInRole. The claims we get with integrated auth includes just a SamIdentifier and a bunch of group SIDs. I’d like ADFS to do that work for us but still give our users a challenge-free experience. Long term, we will likely add support for non-domain-joined devices on some sites/services, so that is another motivation to explore ADFS.
So I've set up a simple sample app in VS2013 using Organizational Accounts (On Premise) that will dump out a current user's claims, configured the metadata endpoint and audience uri, communicated that info along with the claims I'd like mapped to my ADFS admin (2012, btw), and deployed my site to a development server. So my host is still IIS, though I hope to use Owin middleware to set up authentication rather than web.config (WIF-style).
Given that IIS is my host, how do I configure authentication for my site: anonymous? And my web.config should specify "None" for the authentication mode and deny="?" for authorization, correct?
The other question I have that Vittorio didn't get into in his post about on-premise adfs was the nature of the bearer token and whether or not we need to explicitly configure the middleware to use cookies. My startup config looks like this right now:
public void ConfigureAuth(IAppBuilder app)
{
app.UseActiveDirectoryFederationServicesBearerAuthentication(
new ActiveDirectoryFederationServicesBearerAuthenticationOptions
{
MetadataEndpoint = ConfigurationManager.AppSettings["ida:AdfsMetadataEndpoint"],
TokenValidationParameters = new TokenValidationParameters() { ValidAudience = ConfigurationManager.AppSettings["ida:Audience"] }
});
}
It looks like this middleware is expecting JWT tokens (given that there is a JwtSecurityTokenHandler on the class). Is there any configuration we need to do on the ADFS side to issue JWT tokens? My understanding is that I'll receive a SAML token by default.
And should we expect to use the CookieAuthentication middleware to manage the token or will the browser just keep including it for the life of the session?
Thanks, all!
UPDATE:
So based on Vittorio's help below and some further research, I now have a simple website with just one page protected with an [Authorize] attribute. My startup class's ConfigureAuth method now looks like this:
public void ConfigureAuth(IAppBuilder app)
{
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseActiveDirectoryFederationServicesBearerAuthentication(
new ActiveDirectoryFederationServicesBearerAuthenticationOptions
{
MetadataEndpoint = ConfigurationManager.AppSettings["ida:AdfsMetadataEndpoint"],
TokenValidationParameters = new TokenValidationParameters() { ValidAudience = ConfigurationManager.AppSettings["ida:Audience"] }
});
}
We've added my website as a relying party trust in ADFS and created a half dozen claims rules. Everything seems correct so far, but I'm still struggling. I hit the protected "claims" page and get a 401 response with a WWW-Authenticate:Bearer header. So far, so good.
But that's it. How does the browser know where to get authenticated and receive a token? If I was proving out the separate client scenario, my client would be configured with the location of the token authority, but in this simple website scenario, I'm clearly missing something.
UPDATE 2:
I wonder if the implementation for on-premise ADFS just isn't ready yet? Or perhaps the documentation just isn't there yet - or both...
I pulled out all the Owin packages and reverted to using the WSFederationAuthenticationModule and SessionAuthenticationModule, along with all the web.config settings in system.identityModel and system-identityModel.services that have been around a while. Basically, I made the solution look like the one you get from VS2013 when you selected Organizational Accounts --> On Premise. Everything works beautifully and I have all my configured claims coming from ADFS. I see the initial 302 redirect to ADFS, the challenge-response, and ultimately have a SAML token serialized into a secure session cookie. On the website, I echo back the claims like so:
var user = User as ClaimsPrincipal;
ViewBag.Claims = user.Claims;
return View();
This is why I suspect the middleware is incomplete: when you use that new template in VS2013, the wizard goes to the federation metadata endpoint you specify and builds out all the web.config settings by reading that xml and, in addition, sets some intelligent defaults. That's sort of what I expected to happen in the Owin middleware - it should have everything it needs to know since I pass in the same metadata endpoint. I was hoping that "magic" would replace using the FAM/SAM modules and all the accompanying config.
1) If you are configuring a web UX app, that is something meant to be consumed through browser redirects, you want to use http://www.cloudidentity.com/blog/2014/04/29/use-the-owin-security-components-in-asp-net-to-implement-web-sign-on-with-adfs/. You'll see that the cookie middleware does come into play in that case.
2) If you are configuring a web API, as in something that is consumed by a rich client or another server, or in general anything that is not a browser roundtripping, see http://www.cloudidentity.com/blog/2013/10/25/securing-a-web-api-with-adfs-on-ws2012-r2-got-even-easier/. In that case you do not need cookies, given that there is no session -every single call must carry the token.
HTH
V.
As Vittorio said you need to differentiate if you create a web page with web api or web api only. Follow his blog posts they are great!!
If you host a webapi only project in an IIS you need to set the authentication to "forms authentication".
This works also if your web api is covered behind a web application proxy. make sure that you configure your endpoint (published web application) not to preauthenticate. the value for "preauthenticate" should be "pass through".
bg Andrej