Where does the application cookie go when created? - c#

I'm playing around with the authentication using Owin according to a blog and when I execute the following, I'm supposed to get an (application) cookie. I'm unsure how to verify that I actually got one. So it very well might be there, somewhere in the memory or on the disk but I'm too ignorant of security issues to determine that.
List<Claim> claims = new List<Claim> { new Claim("Donkey", "Hazaa") };
ClaimsIdentity identity = new ClaimsIdentity(
claims, DefaultAuthenticationTypes.ApplicationCookie);
HttpContext.GetOwinContext().Authentication.SignIn(new AuthenticationProperties
{
AllowRefresh = false,
IsPersistent = false,
ExpiresUtc = DateTime.Now.AddMinutes(1)
});
I can't verify by being able/unable to log in, since this is just a dummy without any backbone yet. The only thing I need to do at this stage is to confirm that something gets somewhere and that it vanishes when a minute has passed. It'd be awesomely awesome if there was an actual cookie file popping up somewhere and then poofing away after a while. Is there such?

Of course it is, but the Cookie is sent to the browser once the authentication was requested and validated. The cookie has the same behavior as in previous version of cookie auth with forms authentication, so is a task for the browser to receive and manage the cookie; on each HTTP request, the browser sends its cookies, which are processed by OWIN to check authentication.
Take the code and implement a simple authorization on memory (like user: abc, pass: 123) and check how the browser receives the cookie. By the way, the only difference between cookie and token validation is that the cookie is automatically sent on every request, whilst on token auth you need to explicitly send the token information on header.
Be aware that cookie authentication is intended for browsers, as mobile applications or other applications that need to connect to your API will not have access to the cookie response, like in a desktop app.
Regards

Related

.AddOpenIdConnect() Middleware Clarification

So, I'm trying to implement an OIDC client application using ASP.NET Core 3.1. I am trying to leverage the .AddOpenIdConnect() and .AddJswtBearer() middleware. However, I need some clarification on what this middleware is doing.
Here is what I currently have for the middleware configuration:
.AddOpenIdConnect(options =>
{
options.Authority = Configuration["auth:oidc:authority"];
options.ClientId = Configuration["auth:oidc:clientid"];
options.ClientSecret = Configuration["auth:oidc:clientsecret"];
options.ResponseType = OpenIdConnectResponseType.Code;
options.GetClaimsFromUserInfoEndpoint = true;
options.SaveTokens = true;
})
.AddJwtBearer(options =>
{
options.Authority = Configuration["auth:oidc:authority"];
options.Audience = Configuration["auth:oidc:clientid"];
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidIssuer = Configuration["auth:oidc:authority"],
ValidAudience = Configuration["auth:oidc:clientid"],
ValidateIssuerSigningKey = true,
ClockSkew = TimeSpan.Zero
};
}
I notice that requests to the Authorization server's /.well-known/oidc-configuration and /.well-known/keys endpoints are requested when the application is first started, based on my Fiddler capture below
Where does it do that?
I'm trying to also validate that the JWT received from the authorization server is valid (that it hasn't been tampered with between the time the server sent it, and the time that the client has received it). I understood this to happen when I added the TokenValidationParameters object in the .AddJwtBearer() middleware. To test this, I tried changing Valid Audience in the TokenValidationParameters to something like asdkwewrj which I know is not the valid audience for my token. But, I never got an error from the client saying that the audience was invalid. The authentication still worked, and I was able to access my secure dashboard still.
Another thing I'm trying to implement is refresh_token grant_type with this OIDC client. I thought that the options.saveTokens in the .AddOpenIdConnect() middleware would allow me to save the tokens. It looks like they're save as cookies, but these cookies look nothing like my token values (my access token is a JWT, but out of the cookies I see, none of them begin with ey).
In a nutshell, I'm trying to understand the following:
Does this .AddJwtBearer() middleware validate the ID Token for me if I have the correct JwtBearerOptions defined (like I do above)? Or do I need to manually validate the ID token against the JWKs from the JWKs URI?
If I have to manually validate the ID token using the JWKs from the JWKs URI, how do I store these JWKs when the middleware makes the request to the /.well-known/keys endpoint?
How do I get the cookies that correspond to the access token and refresh token, and then send the refresh token to my authorization server?
I noticed that I can utilize options.Events in both of these middlewares. Would any of those solve any of the items I'm trying to accomplish?
Overall, what do these two middlewares handle for me, that I shouldn't need to manually do (i.e token validation and/or token renewal)?
Thank you! I am still fairly new to in-depth ASP.NET development like this, so I appreciate any responses.
First of all, the OIDC authentication scheme and the JWT bearer authentication scheme are independent of each other. OIDC is mostly used for server-side authentication and will pretty much never be used on its own but always with the cookie scheme. The reason for this is that the OIDC scheme will just be used for the authentication but is not able to persist the information on its own. I’ve went into more details in a different answer of mine that also explains how the authentication flow works with OIDC.
As for JWT bearer, this authentication scheme will run on every request since it is completely stateless and expects clients to authenticate themselves using the Authorization header all the time. This makes it primarily used for protecting APIs since browsers wouldn’t be able to provide a JWT for normal browser requests.
So you should first ask yourself whether you are protecting your server-side web application (e.g. using Razor views or Razor pages) in which case you want to use OIDC and the cookies authentication scheme, or if you are protecting your API. Of course, the answer could be “both” in which case you want all of those three schemes but ASP.NET Core will not support this without further configuration.
With that being clarified, let’s get into your questions:
The requests to /.well-known/oidc-configuration and /.well-known/keys are done by both the OIDC and the JWT bearer scheme in order to retrieve information from your identity provider. They will do that regularly to update their data, including information about the signining keys which they will use to validate the tokens. This happens within the scheme handler and is usually not visible to you.
Correctly set up, the JWT bearer authentication will validate the token for you. It will do that by verifying the signatures using the retrieved signing keys, and then it may check additional properties like the specified audience or its lifetime.
You shouldn’t ever need to validate tokens manually. That’s the job of the authentication scheme. You are using the authentication stack so you can just access the user principal within your app without doing anything.
Cookies are protected using data protection so that they are safe against forgery. In order to retrieve the tokens stored with SaveTokens = true, you can use the GetTokenAsync method on your HTTP context.
You can use the authentication events to add to the default behavior of the authentication schemes. For validating your tokens using the standard mechanisms, you shouldn’t need to though.
There is just one middleware: The authentication middleware. It uses the configured authentication schemes to perform the authentication of users so that—once set up correctly—the authenticated user is available throughout the application, e.g. in controllers, MVC filters, Razor views, etc.
Does this .AddJwtBearer() middleware validate the ID Token for me if I
have the correct JwtBearerOptions defined (like I do above)? Or do I
need to manually validate the ID token against the JWKs from the JWKs
URI?
AddJwtBearer is only used by APIs to validate the access token and create a user (ClaimsPrincipal) out of it. It's all it does. It does not deal with id token.
In general its easier to put the API on a separate service, to make it more clear who is doing what. when you mix both the client and API in the same service, it can be harder to reason about it.
If I have to manually validate the ID token using the JWKs from the
JWKs URI, how do I store these JWKs when the middleware makes the
request to the /.well-known/keys endpoint? How do I get the cookies
that correspond to the access token and refresh token, and then send
the refresh token to my authorization server?
The ID token is validated and handled for you by AddOpenIdConnect. You dont need to validate the ID-token by yourself. AddOpenIdConnect will create the cookie and optionally store the tokens as well in the cookie.
Overall, what do these two middlewares handle for me, that I shouldn't
need to manually do (i.e token validation and/or token renewal)?
To summarize:
Ues .AddOpenIdConnect() for the client, that allows the user to login.
Use .AddJswtBearer() for the backend APIs.
Token renewal is a different story that none of them handles out of the box. For that, you can consider to use IdentityModel.AspNetCore or do something by yourself.

SignOutAsync() not logging user out

I have a MVC app that has a couple of WebAPI endpoints. The reason for this is we have an app that should be able to communicate with the application. For authentication, I am using Identity.
After I logged in and want to log out again, it works in the UI. So I implemented the same logic in the Logout actions in one of my API endpoints:
public async Task<JsonResult> LogOut()
{
await _signInManager.SignOutAsync();
_logger.LogInformation("User logged out.");
return new JsonResult(new { Anything = "Logout successful." });
}
I also tried most of the approaches I found here when I search for the same question. However, no matter what I do, the cookie ".AspNetCore.Identity.Application" is always in the next request and I am still authenticated.
I am using Postman to test the API endpoints, if that makes any difference.
Right now you only have cookie authentication and when you call SignOutAsync() a response is being generated which indicates to delete the authentication cookie and in response to that browser deletes the authentication cookie so in the next call there is no cookie and you are not logged in anymore but if you store the authentication cookie before sign out and then add it to the browser after you sign out you are still logged in because your credential is in the cookie.
So this is how browser behaves, and you don't have this behaviour in postman or HttpClient.
Your options are to either use Reference Token for your apis
or
You can config a Session Store with your Cookie Authentication

IdentityServer v3 and custom cookies

I'm updating our MVC application to use IdentityServer v3 to implement OpenID Connect authentication using implicit flow.
I've overridden the IdentityServer AuthenticateLocalAsync method of the UserServiceBase class to call into our existing authentication service to validate the supplied credentials. This service also sets various cookies required by our application.
The issue I'm encountering is that upon entering the credentials in the login page, it doesn't redirect to the ReturnUri specified in the OpenIdConnectAuthenticationOptions parameter of UseOpenIdConnectAuthentication method. Instead it remains on the login page and appears to go into an infinite loop, alternating between calls to the notification handlers SecurityTokenValidated and SecurityTokenReceived. There is no indication of any error in the IdentityServer logs.
I think the cause of the issue is related to setting the application-specific cookies in our authentication service. If I comment out the following, it then successfully redirects upon logging in:
var cookie = new HttpCookie("AppCookie") { HttpOnly = false, Secure = true };
cookie ["CustomField1"] = HttpUtility.UrlEncode(customValue1);
cookie ["CustomField2"] = HttpUtility.UrlEncode(customValue2);
this._httpContext.Response.Cookies.Set(cookie);
However these cookies are required by our application and so need to be set in the response. Why would setting these cookies prevent it from redirecting? Are there any workarounds? Any assistance would be much appreciated.

How do I make the AuthorizeEndpointPath work in ASP.NET Oauth 2.0 framework

I currently have a website where I am trying to implement the OAuth server framework. The website is currently a combination of Web Forms (not MVC) and Web API 2. For the purposes of what I am trying to do, we cannot change the overall architecture of the system.
So far, I have OAuth working via the Web API for validating clients, generating access tokens, and handling refresh tokens.
The last piece I am trying to implement is the Authorize Code workflow. This will allow us to grant access to our application so integration tools can access our APIs without having to locally store the user credentials.
My understanding of how it should function is the following:
User is directed to the AuthorizeEndpointPath that I define in the Startup.Auth file
User either sees a login page (if they don't already have an authentication cookie for the website), or they see a special page where they have to grant permission to access the account (similar to what Google has)
Once the user clicks the "grant" button, the OWIN middleware will process the request, and redirect them back to the original client URL that requested access
However, after all of my configuration, whenever I access the AuthorizeEndpointPath directly, the "grant access permission" page is never actually displayed.
I've ensured the following configuration, but there isn't much documentation on what the correct configuration is.
var oAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/api/token"),
AuthorizeEndpointPath = new PathString("/LoginAuthorize.aspx"),
//AuthorizeEndpointPath = new PathString("/api/authorize"),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(10),
Provider = new ApiAuthorizationServerProvider(),
RefreshTokenProvider = new ApiRefreshTokenProvider(),
AuthorizationCodeProvider = new ApiAuthoirzationCodeProvider()
};
Currently the "AuthorizeEndpointPath" property maps to an actual page, where I ask the user confirmation, but that page is not being displayed at all
Through debugging, I can see the framework hits the following method even before the authorization page would be loaded
ValidateClientRedirectUri(OAuthValidateClientRedirectUriContext context)
I have tried to overload that method, and one of 2 things happens. If I make a call to context.Validated();, the user is immediately redirected without the authorization page being displayed. If don't "validate" the redirect URI, then a blank page is displayed indicating an "invalid_request".
So the big question is how do I actually make OWIN display my custom authorization page?
When the authorization page is finally displayed, what would I need to do when the user clicks on the "grant" button. Is there any configuration I need to setup, or any calls to OWIN I need to make?
Also, how do I ensure the user authenticates before that page is displayed? Do I simply have my code redirect the user to the login page if they are not logged in? If so, how will OWIN handle the real redirect back to the client (if the user would be redirected to the authorization page once they login)?
Finally, once this is all configured properly, will I still be able to support the current OAuth workflow I have of allowing clients to manually pass in their credentials for the "token" API? The reason I ask is because we also have mobile apps that have their own sign-in screen, and will be using OAuth to connect (in addition to other web-based clients).
I had a question that turned out to be similar to yours.
So, after quite some searching online, I got some success by searching github. Apparently, OAuthAuthorizationServerProvider offers AuthorizeEndpoint and that method should be used for both "Hey, you're not authorized, go log in you!" as well as for "Ahh, okay you're cool, here's an authorization code.". I had expected that OAuthAuthorizationServerProvider would have two separate methods for that, but it doesn't. That explains why on github, I find some projects that implement AuthorizeEndpoint in a rather peculiar way. I've adopted this. Here's an example:
public override async Task AuthorizeEndpoint(OAuthAuthorizeEndpointContext context)
{
if (context.Request.User != null && context.Request.User.Identity.IsAuthenticated)
{
var redirectUri = context.Request.Query["redirect_uri"];
var clientId = context.Request.Query["client_id"];
var authorizeCodeContext = new AuthenticationTokenCreateContext(
context.OwinContext,
context.Options.AuthorizationCodeFormat,
new AuthenticationTicket(
(ClaimsIdentity)context.Request.User.Identity,
new AuthenticationProperties(new Dictionary<string, string>
{
{"client_id", clientId},
{"redirect_uri", redirectUri}
})
{
IssuedUtc = DateTimeOffset.UtcNow,
ExpiresUtc = DateTimeOffset.UtcNow.Add(context.Options.AuthorizationCodeExpireTimeSpan)
}));
await context.Options.AuthorizationCodeProvider.CreateAsync(authorizeCodeContext);
context.Response.Redirect(redirectUri + "?code=" + Uri.EscapeDataString(authorizeCodeContext.Token));
}
else
{
context.Response.Redirect("/account/login?returnUrl=" + Uri.EscapeDataString(context.Request.Uri.ToString()));
}
context.RequestCompleted();
}
Source: https://github.com/wj60387/WebApiOAUthBase/blob/master/OwinWebApiBase/WebApiOwinBase/Providers/OAuthServerProvider.cs
You create a separate login page at /account/login. What this does is sign the user in. If your WebAPI uses cookie-based authentication, you can just redirect the user back to the AuthorizeEndpoint again. If you use access tokens, your login page has to make a request to `AuthorizeEndpoint' with the access token to obtain an authorization code. (Don't give the access token to the third party. Your login page requests the authorization code and sends that back.) In other words, if you use access tokens then there are two clients involved in this flow.

Persisting the OAuth2 bearer token when using Thinktecture Identity Server

I've been following the Thinktecture Identity Server example of OAuth2 Resource Owner Password Flow found at http://leastprivilege.com/2012/11/01/oauth2-in-thinktecture-identityserver-v2-resource-owner-password-flow/
I have the example working and returning JWT tokens successfully via the following process
Use the Thinktecture OAuth2Client to retrieve the access token
Retrieve the signing certificate from the "Trusted People" store on the client machine
Using the certificate and creating a new JwtSecurityTokenHandler and TokenValidationParameters and calling tokenHandler.ValidateToken to get a ClaimsPrincipal
From here I am authorized, but I am uncertain of the best way to persist the token for further requests. I tried using
var sessionToken = new SessionSecurityToken(principal, TimeSpan.FromHour(8));
FederatedAuthentication.SessionAuthenticationModule.WriteSessionTokenToCookie(sessionToken);
But I do not have a SessionAuthenticationModule registered. I tried using the Identity and Access wizard to get this in place, but it makes many changes to config and tries to set things up for passive authentication.
I could use a traditional FormsAuthentication cookie (.aspnetAuth) but I remember discussion that an advantage of the .FedAuth cookie was that it was naturally split into several cookies if the size grew too big.
I'm struggling to find an article that completes the picture for me. I need the bearer token for accessing various APIs further down the stack. I have working examples of this for SSO/passive authentication, because most of the work is done for you. I'm just not sure of the best pattern for use when using the Resource Owner Password flow.
So
Have I missed a more straightforward way to achieve this with Thinktecture Identity Model and Server?
Should I try to create a FedAuth cookie so that I can reuse the various Messagehandler/filter components that are already setup for WIF?
Otherwise - is there anything particularly wrong with simply putting the access token in the UserData section of the FormsAuthentication cookie?
Try to look at this question: WIF Security Token Caching.
I believe this code might do
var sessionSecurityToken = new SessionSecurityToken(principal, TimeSpan.FromHours(Convert.ToInt32(System.Web.Configuration.WebConfigurationManager.AppSettings["SessionSecurityTokenLifeTime"])))
{
IsPersistent = true, // Make persistent
IsReferenceMode = true // Cache on server
};
FederatedAuthentication.SessionAuthenticationModule.WriteSessionTokenToCookie(sessionSecurityToken);

Categories

Resources