Logging Out With AspNet.Security.OpenIdConnect.Server (ASP.NET vNext) - asp.net

I am using Visual Studio 2015 Enterprise and ASP.NET vNext Beta8 to issue and consume JWT tokens as described here.
In our implementation we're storing some client details in Redis at token issuing time and we would like the flush this information when the user logs out.
My question is what is the best practices for logging out with OIDC?
While I could roll my own contoller for this purpose I couldn't help but notice Open ID Connect (OIDC) seems somewhat primed to handle this case. For example OIDC has an OnLogoutEndpoint handler and LogoutEndpointPath settings. But when I call the OIDC logout URI that handler appears to accept any random x-www-form-urlencoded form I throw at it and doesn't in any particular way seem to be demanding the presence of a token.
Any advice on proper OIDC logout practices would be very much appreciated.

In AspNet.Security.OpenIdConnect.Server, the logic used for the logout endpoint is left as an exercise.
In this sample, it is implemented using an MVC 6 controller, where you're - of course - free to add custom logic to remove cached details from your Redis server.
[HttpPost("~/connect/logout")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Logout() {
// When invoked, the logout endpoint might receive an unauthenticated request if the server cookie has expired.
// When the client application sends an id_token_hint parameter, the corresponding identity can be retrieved using AuthenticateAsync.
var identity = await HttpContext.Authentication.AuthenticateAsync(OpenIdConnectServerDefaults.AuthenticationScheme);
// Remove the cached details here. If you need to determine
// who's the authenticated user, you can use the identity variable.
// Remove the authentication cookie and return the user to the client application.
return SignOut("ServerCookie", OpenIdConnectServerDefaults.AuthenticationScheme);
}
You can also do something similar directly from the LogoutEndpoint event. Don't forget to call context.HandleResponse() to make sure the request is not intercepted by another middleware.

Related

IdentityServer4 Google sign callback doesn't include "IdentityConstants.ExternalScheme" cookie

I have an IdentityServer4 identity provider server. For the most part, I am using the template code from their repo. I am trying to add Google sign-in. I configured the GoogleSignIn in startup and added ClientId/ClientSecret.
When I don't configure the return URIs in the GCP project I get the following error from Google:
"The redirect URI in the request, https://localhost:44333/signin-google, does not match the ones authorized for the OAuth client. To update the authorized redirect URIs..."
When I add the URI
Then as soon as I call Challenge I immediately get a failed callback from Google.
[HttpGet]
public async Task<IActionResult> Callback()
{
var result = await HttpContext.AuthenticateAsync(IdentityConstants.ExternalScheme);
// Here, result.Succeeded is false
// Rest of the method...
}
What could be the problem?
If you have made it to the Callback method, then it sounds like Google auth has completed successfully. However, since the IdentityConstants.ExternalScheme cookie is not present, it sounds like you might have a little misconfiguration.
Once the Google authentication handler has completed, it will sign in using the auth scheme set in its SignInScheme property or the default sign-in scheme. It stores the claims from Google into a local auth method, such as a cookie.
What scheme is the Google authentication handler configured to use? If you're using the quickstarts, it may be using IdentityServerConstants.ExternalCookieAuthenticationScheme rather than ASP.NET Identity's IdentityConstants.ExternalScheme that you are looking for.

What mechanism does OWIN use to determine that a user is authenticated before reading their claims?

I've launched the sample project for ASP.Net MVC that provides single sign-on against Active Directory, and am using this Microsoft tutorial for reference.
Once the user has clicked to sign-in and gets redirect to their organisation's login page, upon returning to the web application the following code verifies that they are authenticated, and successfully reads their claims:
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.OpenIdConnect;
using Owin;
#if (Request.IsAuthenticated)
{
<dl>
#foreach (var claim in System.Security.Claims.ClaimsPrincipal.Current.Claims)
{
<text>
<dt>#claim.Type</dt>
<dd>#claim.Value</dd>
</text>
}
</dl>
}
Under the hood, what actually constitutes a true value of Request.IsAuthenticated?
Is it by the very nature that claims exist, or is there a specific value that is being used to provide a result before the claims are read?
That tutorial asks you to add authentication middleware into your request pipeline. In this case you're adding UseCookieAuthentication and UseOpenIdConnectAuthentication to register authentication middlewares. These, and any others you might add (JWT bearer token authentication for example), use their own internal mechanism for parsing the request and assigning a claims identity to your request context. For example, cookie authentication will look for a cookie that represents a persisted session and will decrypt and parse its details out as a claims identity. IsAuthenticated literally just returns true if one or more identities are available.
For more detail you can of course drill into the source code. For example, OWIN's cookie authentication middleware lives here: https://github.com/aspnet/AspNetKatana/tree/dev/src/Microsoft.Owin.Security.Cookies

IdentityServer IsActiveAsync method not being called on the profile service

I'm using IdentityServer v4 to handle authorisation for my ASP.NET application, using Resource Owner flow.
I've implemented the IdentityServer4.Core.Services.IProfileService interface which has two methods, GetProfileDataAsync and IsActiveAsync.
When making a request to the token endpoint, the GetProfileDataAsync gets called as expected. We use this method to issue our claims.
However the IsActiveAsync method does not get called. I'd like to implement this method to determine whether the user is active in our database. At what point is this method supposed to get called?
The comment in the IdentityServer source (see below) suggests it should get called during token issuance, but the method isn't called when requesting a token. I suspect I'm missing something. Any help would be appreciated.
// Summary:
// This method gets called whenever identity server needs to determine
// if the user is valid or active (e.g. if the user's account has been
// deactivated since they logged in). (e.g. during token issuance or
// validation).
Task IsActiveAsync(IsActiveContext context);
Right now IsActiveAsync does not get called for resource owner password requests. I guess the assumption was that you wouldn't successfully authenticate a user if the user is inactive.
These details are not yet decided on - if you have a strong opinion on how this should work - please open an issue on github. We will lock down the API in late August.

User.Identity.IsAuthenticated use in generic asp.net handler

I've set up an STS with WIF and want to expose whether a user is signed in so that an RP can determine if the user is signed in without requiring the user to redirect to the STS and return. If the user is signed in, a different process flow will occur on the RP so it's important to know but not to force the sign-in at this point in the process.
My plan was to create a simple generic handler on the STS which, when hit via an HttpWebRequest, returns the output of context.User.Identity.IsAuthenticated (where context is the HttpContext passed into the ProcessRequest method:
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain";
if (context.User != null && context.User.Identity.IsAuthenticated)
context.Response.Write("True");
else
context.Response.Write("False");
}
My problem is, if the user is signed in and I hit this handler directly, it returns True but if I programmatically hit the handler from the RP, it returns False (in fact the Identity is null).
Am I just completely wrong in doing this and hitting the handler from the RP will return the status of the User on the RP or could I be doing something wrong?
This handler will only work (return true), if you send the STS authentication cookies with the request. Only your web browser may have these cookies. Therefore it can't be done via HttpWebRequest. Also this is why it works, when you call the handler directly from the browser.
I know this is a bit old thread, but the answer may help others who land on this page.
The thing that does the magic behind the authentication is the session and authentication cookies which are sent to the user's client (e.g. browser) from your STS app. I'm not sure how your STS and RP apps are designed and communicate, so I will keep the answer generic. To notify your RP app of the authentication status, you need to:
1) either somehow share both cookies between the user's client and the your RP app. In this scenario, I'm afraid you will have to build your own client and make your users use it to visit the STS app. This is because you cannot get the cookies from the standard browsers. The client you build sends the cookies somewhere where your RP app can get them and place them in HttpWebRequest.CookieContainer which then can successfully get the result of your handler. I'm only explaining this method to say that it is doable and show how complex and twisted it is.
2) or you will have to track the login status of your users. Instead of checking the context.User, your handler must get the user ID from the calling RP app and then check if that user is logged in (that is there is an active session for that user). For example, you can track or store your sessions in the database, or have a look at the following thread for some methods of accessing active sessions:
List all active ASP.NET Sessions

asp.net, wcf authentication and caching

I need to place my app business logic into a WCF service. The service shouldn't be dependent on ASP.NET and there is a lot of data regarding the authenticated user which is frequently used in the business logic hence it's supposed to be cached (probably using a distributed cache). As for authentication - I'm going to use two level authentication:
Front-End - forms authentication back-end
(WCF Service) - message username authentication.
For both authentications the same custom membership provider is supposed to be used.
To cache the authenticated user data, I'm going to implement two service methods:
1) Authenticate - will retrieve the needed data and place it into the cache(where username will be used as a key)
2) SignOut - will remove the data from the cache
Question 1. Is correct to perform authentication that way (in two places) ?
Question 2. Is this caching strategy worth using or should I look at using aspnet compatible service and asp.net session ?
Maybe, these questions are too general. But, anyway I'd like to get any suggestions or recommendations.
Any Idea
Question 1:
From my experience the ASP forms authentication would be enough. No reason to send credentials as POST and certainly not GET. You can use that for a change password or account info method. You might want to look into Membership and Roles.
Question 2:
I would stick with the ASP.NET session. This might make your application more prone to issues and vulnerabilities in the end, and I see it as unnecessary.
Passing the password to between the services is not a good practice. You should consider creating a custom security token in your front-end application and passing this token to the WCF service. WCF service can validate the token using a certificate. With this approach you can
insert any user data into the security token and use in the WCF service
cache the token in the front-end application session, therefore you don't need any distributed cache
centralize login and avoid authenticating user twice
If you don't want to be dependant on ASP.NET then you shouldn't use any session
What I could advice:
Use a UserNameValidator, so that you need to send username/password on each request to the wcf service (there are a lot of article on the web on how to configure a UserNameValidator)
Implement an IAuthorizationPolicy where you can retrieve user data to set the roles etc. This object is created once then reused
The problem is that if you only use these 2 components, you'll need to fetch the data for each request as you've no way to transfert the username from the UserNameValidator to the IAuthorizationPolicy
To avoid that, you'll need to implement the complete authentication mechanism in WCF. It's not hard at all, and here is a very nice link that help me to do it in 1 or 2 hours:
http://www.neovolve.com/post/2008/04/07/wcf-security-getting-the-password-of-the-user.aspx
The "PasswordAuthorizationPolicy" (in the link above) is created once, then reused. And for each request the Evaluate method is called.
It means that you can add any custom property on this class, fill them in the constructor, and then use them forever. You don't need to manage this cache lifetime as it's binded to the client channel, so once the client close the connection the channel will expire all these data will be removed from memory
My suggestion is to create class Authentication (or something else) on WCF side:
public class Authentication<T>
{
public static Dictionary<string, T> Users { get; set; }
}
And if you have User class:
public class User
{
public string FirstName { get; set; }
public string LastName { get; set; }
...
}
You can manage users like this:
Authentication<User>.Users.Add("username", new User());

Resources