I'm having some difficulty understanding how to use Windows Authentication to authenticate a user, but then return a JWT to the client containing that authenticated user's claims. This is using .Net Core 2.0.
I've put the following in Startup.cs.
services.AddAuthentication
(
IISDefaults.AuthenticationScheme
).AddJwtBearer("Bearer", options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = false,
ValidateIssuer = false,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("someKey")),
ValidateLifetime = true,
};
}
);
However, it doesn't seem that this is sufficient to generate the token. Some other guidance I've read suggests the token should be generate manually as part of an authorization routine but this seems to be tailored for when validating a username/password against a database or other provider. (For instance: https://fullstackmark.com/post/13/jwt-authentication-with-aspnet-core-2-web-api-angular-5-net-core-identity-and-facebook-login.) But with windows auth there does not appear to be an event or other structure that allows me to do this.
Any ideas?
Related
On startup I have the following
var keys = GetKeys();
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
RequireExpirationTime = true,
ValidateIssuer = false,
ValidateAudience = false,
IssuerSigningKeys = keys
};
});
The list of valid keys can change at runtime - is it possible to update the list that the authentication layer is using without having to restart the server?
The idea is that we have multiple client servers calling our API and they all have their own keys they use for signing the JWT.
New clients can be added at any time (via another API).
This is a requirement that I've received from above and it's unlikely I can get the design changed.
There is a delegate IssuerSigningKeyResolver, in the TokenValidationParameters, that you can set while configuring the other options. On every request authentication, your delegate will be executed. You can dynamically return the the SecurityKey.This post can refer toļ¼ASP.NET Core - change JWT SecurityKey during runtime
I have a few endpoints in an ASP.NET core application that's also hosting IdentityServer.
When I issue a JWT token to a client, and that client calls an [AllowAnonymous] endpoint with the JWT as a bearer token, the User principal is empty. It looks like the token isn't being parsed by any middleware, and there doesn't seem to be an option to specify always attempting to parse a JWT.
Is there a way to get this handled automatically or do I need to use the .AddJwtBearer extension? If the latter I can't seem to find an easy way for me to populate the signingkey such that it matches the ones configured for identity server.
var tokenValidationParameters = new TokenValidationParameters
{
// The signing key must match!
ValidateIssuerSigningKey = true,
IssuerSigningKey = ?? signing keys from Identity Server,
// Validate the JWT Issuer (iss) claim
ValidateIssuer = true,
ValidIssuer = // I guess this is typically the public URL for this instance,
// Validate the token expiry
ValidateLifetime = true,
// If you want to allow a certain amount of clock drift, set that here:
ClockSkew = TimeSpan.Zero
};
app.UseJwtBearerAuthentication(new JwtBearerOptions
{
AutomaticAuthenticate = true,
AutomaticChallenge = true,
TokenValidationParameters = tokenValidationParameters
});
I would guess that for the SigningKey I could pass through the X509 that I'm configuring on IdentityServer via the x509SecurityKey class
UseJwtBearerAuthentication is obsolete. Configure JwtBearer authentication with AddAuthentication().AddJwtBearer in ConfigureServices.
Also make sure app.UseAuthentication(); is added in your startup class.
I find a best practice is to always host IdentityServer, client and API on separate ASP.NET Core instances, because otherwise its hard to reason about what is what. IdentityServer issues its own User and cookie so I think your system is confused about what user to use?
Reference:
JwtBearerAppBuilderExtensions.UseJwtBearerAuthentication Method
Auth 2.0 Migration announcement
I need to configure my .Net Core Web Api (.Net Framework) to use ADFS 3.0 (2012) to validate the Bearer tokens sent by our mobile clients.
I am able to generate the access_token from the ADFS server, and I pass it in the Authorization header.
My problem is in the API: how do I configure it to validate and autorize the user?
I searched in many places and I could not find a definitive method of doing it.
What I tried so far:
Used IdentityServer4 (Failed because it uses JWT and ADFS doesn't offer OpenID
Tried UseOpenIdConnectAuthentication (found example at IdentityServer4)
a custom Middleware
I can't use another method, I need to support oAuth2.
So, how do I do it?
Here is my latest try:
var connectOptions = new OpenIdConnectOptions
{
AuthenticationScheme = "adfs",
SignInScheme = "idsrv.external", //IdentityServerConstants.ExternalCookieAuthenticationScheme,
SignOutScheme = "idsrv", //IdentityServerConstants.SignoutScheme,
AutomaticChallenge = false,
DisplayName = "ADFS",
Authority = $"https://{options.AdfsHostName}/adfs/oauth2",
ClientId = options.ClientID,
ResponseType = "id_token",
Scope = { "openid profile" },
CallbackPath = new PathString("/signin-adfs"),
SignedOutCallbackPath = new PathString("/signout-callback-adfs"),
RemoteSignOutPath = new PathString("/signout-adfs"),
ClaimsIssuer = $"https://{options.AdfsHostName}/adfs/services/trust",
//TokenValidationParameters = new TokenValidationParameters
//{
// ValidateIssuer = true,
// ValidIssuer = $"https://{options.AdfsHostName}/adfs/services/trust"
//},
};
app.UseOpenIdConnectAuthentication(connectOptions);
I get a very quick 401 on every calls, with a valid token. In fact, while I see the connection in the console window, I don't see any other log in the Roslyn console window regarding the security validation.
I'm currently using ASP.Net Core 1.1.X, and if I can I'd avoid moving to .Net Core 2.0, as we are late in the project and it contains many breaking changes...
Feel free to ask for more info, and I'll appreciate all the good advices!
As it turns out, we can use the JwtBearerAuthentication with ADFS 3.0.
My initial problem with it was that it went to fetch the metadata at /.well-known/openid-configuration, but ADFS 3.0 does not support OpenID and this returns a 404.
I read in another post (I'll update it when I find it) that if with the right configuration, it won't need to fetch the config. But what configuration?
Well I found deep in the (MS) code that if one pass an OpenIdConnectConfiguration object to the Configuration property of the JwtBearerOptions, it wont fetch the metadata.
So here is my code now:
var rawCertData = Convert.FromBase64String(options.X509SigninCertificate);
X509Certificate2 cert = new X509Certificate2(rawCertData);
SecurityKey signingKey = new X509SecurityKey(cert);
The X509 cert data comes from the supported adfs metadata at this url
https://Your.ADFS.Site/FederationMetadata/2007-06/FederationMetadata.xml
It contains this:
<KeyDescriptor use="signing">
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<X509Data>
<X509Certificate>SOMEUUENCDODEDSTRING=</X509Certificate>
</X509Data>
</KeyInfo>
</KeyDescriptor>
I simply copied the UUEncoded string in my settings' X509SigninCertificate property.
var tokenValidationParameters = new TokenValidationParameters
{
// The signing key must match!
ValidateIssuerSigningKey = true,
IssuerSigningKey = signingKey,
// Validate the JWT Issuer (iss) claim
ValidateIssuer = true,
ValidIssuer = $"https://{options.AdfsHostName}/adfs/services/trust",
// Validate the JWT Audience (aud) claim
ValidateAudience = true,
ValidAudience = options.ClientUri, //"https://YOUR-AUDIENCE/",
// Validate the token expiry
ValidateLifetime = true,
// If you want to allow a certain amount of clock drift, set that here:
ClockSkew = TimeSpan.Zero
};
var connectOptions = new OpenIdConnectConfiguration
{
Issuer = $"https://{options.AdfsHostName}/adfs/services/trust",
};
app.UseJwtBearerAuthentication(new JwtBearerOptions
{
AutomaticAuthenticate = true,
AutomaticChallenge = true,
TokenValidationParameters = tokenValidationParameters,
Configuration = connectOptions
});
The important line here is
Configuration = connectOptions
By doing this, you tell the validator to not fetch the metadata. Simple as that.
I was able to validate my token (AUD, ISS and SIGN) and I can use ADFS in my project.
Only ADFS 2016 supports OpenID Connect. If you want to use the OAuth endpoint in 2012, you need to write your own authorisation handler. An example to build on would be ASP.NET Core's own Twitter implementation. Note that these handlers need to be implemented differently in ASP.NET Core 1.* vs 2.0+.
In .NETCore asp net I am using UseJwtBearerAuthentication to protect controllers using access tokens in a manner similar to this:
app.UseJwtBearerAuthentication(new JwtBearerOptions
{
AutomaticAuthenticate = true,
AutomaticChallenge = true,
TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = "TestIssuer",
ValidateAudience = true,
ValidAudience = "TestAudience",
ValidateLifetime = true,
}
});
However, I want to provide more than one set of options as there is the potential that different audiences will require different levels of access. For instance, access tokens may need to have different lifetimes.
I can achieve this by adding the different options like this:
app.UseJwtBearerAuthentication(jwtBearerOptions1);
app.UseJwtBearerAuthentication(jwtBearerOptions2);
This works fine. And access is granted to the controllers as expected.
However, the problem I've found is that while I'm correctly granted or denied access as expected, the debug console receives a lot of verbose exception messages as the .NET authentication code tries to authenticate against each of the available JwtBearerOptions.
It will record that one has been successful but also every one that has failed (example below).
My question: Is there a way to suppress this message as I expect there to be these failures? Or should I use a different method to allow multiple JwtBearerOptions to be added?
Microsoft.IdentityModel.Tokens.SecurityTokenInvalidSignatureException: IDX10503: Signature validation failed. Keys tried: 'Microsoft.IdentityModel.Tokens.SymmetricSecurityKey , KeyId:
'.
Exceptions caught:
''.
token: '{"alg":"HS256","typ":"JWT"}.{"sub":"testuser","jti":"c98bb91a-5dcd-4fd7-97ff-c10cddf18989","nbf":1497015309,"exp":1497101709,"iss":"TestIssuer","aud":"TestAudience"}'.
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.<HandleAuthenticateAsync>d__1.MoveNext()
info: Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerMiddleware[7]
Bearer was not authenticated. Failure message: IDX10503: Signature validation failed. Keys tried: 'Microsoft.IdentityModel.Tokens.SymmetricSecurityKey , KeyId:
'.
I've been working at this for over a week now. I have successfully set up Owin using UseWsFederationAuthentication with UseCookieAuthentication for a client recently, but I'm struggling with Google's OpenID Connect for another project. I have registered my application with Google using the Google API dashboard. In the browser I am able to use
gapi.auth2.getAuthInstance();
to get a JWT token. In my Owin ConfigureAuth I tried using the following:
AppBuilder.UseJwtBearerAuthentication(
new JwtBearerAuthenticationOptions
{
AllowedAudiences = new string[] { audience },
AuthenticationMode = AuthenticationMode.Active,
IssuerSecurityTokenProviders = new
IIssuerSecurityTokenProvider[]
{
new SymmetricKeyIssuerSecurityTokenProvider(issuer, secret)
}
});
I've also tried setting the TokenValidationParameters to basically not do any validation.
new TokenValidationParameters
{
ValidateActor = false,
ValidateAudience = false,
ValidateIssuer = false,
ValidateIssuerSigningKey = false,
RequireSignedTokens = false,
ValidateLifetime = false,
RequireExpirationTime = false,
}
I've also tried setting the TokenValidationParameters similar to the way it was done here https://github.com/googleplus/gplus-verifytoken-csharp/blob/master/verifytoken.ashx.cs.
I've tried a lot of other things as well, but with no Joy. My requirements are to have an SPA call a .Net Web API with an authentication token that will be used to verify his ID. The application cannot rely on cookies and the JWT must be processed each time.
I'm at my wits end, or in other words help me, Obi-Wan Kenobi, you're my only hope!