public void RejectExpiredToken() { var fakeIssuer = "example.okta.com"; var fakeAudience = "aud://default"; var credentials = new SigningCredentials( new SymmetricSecurityKey(Encoding.UTF8.GetBytes("fakesigningsecret!")), SecurityAlgorithms.HmacSha256); // Create the JWT and write it to a string var jwtContents = new JwtSecurityToken( issuer: fakeIssuer, audience: fakeAudience, expires: DateTime.UtcNow.Subtract(TimeSpan.FromMinutes(3)), // Default clock skew of 2 minutes signingCredentials: credentials); var jwtHandler = new JwtSecurityTokenHandler(); var jwt = jwtHandler.WriteToken(jwtContents); var fakeOktaWebOptions = new OktaWebOptions { OktaDomain = fakeIssuer, }; var validationParameters = new DefaultTokenValidationParameters(fakeOktaWebOptions, fakeIssuer) { IssuerSigningKey = credentials.Key, ValidAudience = fakeAudience, }; Action act = () => jwtHandler.ValidateToken(jwt, validationParameters, out _); act.Should().Throw <SecurityTokenExpiredException>(); }
/// <summary> /// Creates a new instance of OpenIdConnectAuthenticationOptions. /// </summary> /// <param name="oktaMvcOptions">The <see cref="OktaMvcOptions"/> options.</param> /// <returns>A new instance of OpenIdConnectAuthenticationOptions.</returns> public OpenIdConnectAuthenticationOptions BuildOpenIdConnectAuthenticationOptions() { var tokenValidationParameters = new DefaultTokenValidationParameters(_oktaMvcOptions, _issuer) { NameClaimType = "name", ValidAudience = _oktaMvcOptions.ClientId, }; var userInfoProvider = new UserInformationProvider(_oktaMvcOptions, _issuer, _configurationManager); var definedScopes = _oktaMvcOptions.Scope?.ToArray() ?? OktaDefaults.Scope; var scopeString = string.Join(" ", definedScopes); var oidcOptions = new OpenIdConnectAuthenticationOptions { ClientId = _oktaMvcOptions.ClientId, ClientSecret = _oktaMvcOptions.ClientSecret, Authority = _issuer, RedirectUri = _oktaMvcOptions.RedirectUri, ResponseType = OpenIdConnectResponseType.Code, RedeemCode = true, Scope = scopeString, PostLogoutRedirectUri = _oktaMvcOptions.PostLogoutRedirectUri, TokenValidationParameters = tokenValidationParameters, SecurityTokenValidator = new StrictSecurityTokenValidator(), AuthenticationMode = (_oktaMvcOptions.LoginMode == LoginMode.SelfHosted) ? AuthenticationMode.Passive : AuthenticationMode.Active, SaveTokens = true, Notifications = new OpenIdConnectAuthenticationNotifications { RedirectToIdentityProvider = BeforeRedirectToIdentityProviderAsync, SecurityTokenValidated = SecurityTokenValidatedAsync, }, }; return(oidcOptions); }
private static void AddJwtBearerAuthentication(IAppBuilder app, OktaWebApiOptions options) { var issuer = UrlHelper.CreateIssuerUrl(options.OktaDomain, options.AuthorizationServerId); var httpClient = new HttpClient(new UserAgentHandler("okta-aspnet", typeof(OktaMiddlewareExtensions).Assembly.GetName().Version)); var configurationManager = new ConfigurationManager <OpenIdConnectConfiguration>( issuer + "/.well-known/openid-configuration", new OpenIdConnectConfigurationRetriever(), new HttpDocumentRetriever(httpClient)); // Stop the default behavior of remapping JWT claim names to legacy MS/SOAP claim names JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); var signingKeyProvider = new DiscoveryDocumentSigningKeyProvider(configurationManager); var tokenValidationParameters = new DefaultTokenValidationParameters(options, issuer) { ValidAudience = options.Audience, IssuerSigningKeyResolver = (token, securityToken, keyId, validationParameters) => { var signingKeys = signingKeyProvider.GetSigningKeysAsync().GetAwaiter().GetResult(); return(signingKeys.Where(x => x.KeyId == keyId)); }, // CLIST: 2019-11-08 - save the claims token into the bootstrap context for k2 SaveSigninToken = true, }; app.UseJwtBearerAuthentication(new JwtBearerAuthenticationOptions { AuthenticationMode = AuthenticationMode.Active, TokenValidationParameters = tokenValidationParameters, TokenHandler = new StrictTokenHandler(), }); }
public void RejectUnsignedToken() { var fakeIssuer = "example.okta.com"; var fakeAudience = "aud://default"; // Create the JWT and write it to a string var jwtContents = new JwtSecurityToken( issuer: fakeIssuer, audience: fakeAudience, expires: DateTime.UtcNow.Add(TimeSpan.FromMinutes(1))); // No signing credentials! var jwtHandler = new JwtSecurityTokenHandler(); var jwt = jwtHandler.WriteToken(jwtContents); var fakeOktaWebOptions = new OktaWebOptions { OktaDomain = fakeIssuer, }; var validationParameters = new DefaultTokenValidationParameters(fakeOktaWebOptions, fakeIssuer) { ValidAudience = fakeAudience, }; Action act = () => jwtHandler.ValidateToken(jwt, validationParameters, out _); act.Should().Throw <SecurityTokenInvalidSignatureException>(); }
public void AllowGoodToken() { var fakeIssuer = "example.okta.com"; var fakeAudience = "aud://default"; var credentials = new SigningCredentials( new SymmetricSecurityKey(Encoding.UTF8.GetBytes("fakesigningsecret!")), SecurityAlgorithms.HmacSha256); // Create the JWT and write it to a string var jwtContents = new JwtSecurityToken( issuer: fakeIssuer, audience: fakeAudience, expires: DateTime.UtcNow.Add(TimeSpan.FromMinutes(1)), signingCredentials: credentials); var jwtHandler = new JwtSecurityTokenHandler(); var jwt = jwtHandler.WriteToken(jwtContents); var fakeOktaWebOptions = new OktaWebOptions { OktaDomain = fakeIssuer, }; var validationParameters = new DefaultTokenValidationParameters(fakeOktaWebOptions, fakeIssuer) { IssuerSigningKey = credentials.Key, ValidAudience = fakeAudience, }; jwtHandler.ValidateToken(jwt, validationParameters, out _); }
/// <summary> /// Creates a new instance of OpenIdConnectAuthenticationOptions. /// </summary> /// <param name="oktaMvcOptions">The <see cref="OktaMvcOptions"/> options.</param> /// <param name="notifications">The OpenIdConnectAuthenticationNotifications notifications.</param> /// <returns>A new instance of OpenIdConnectAuthenticationOptions.</returns> public static OpenIdConnectAuthenticationOptions BuildOpenIdConnectAuthenticationOptions(OktaMvcOptions oktaMvcOptions, OpenIdConnectAuthenticationNotifications notifications) { var issuer = UrlHelper.CreateIssuerUrl(oktaMvcOptions.OktaDomain, oktaMvcOptions.AuthorizationServerId); var httpClient = new HttpClient(new UserAgentHandler("okta-aspnet", typeof(OktaMiddlewareExtensions).Assembly.GetName().Version)); var configurationManager = new ConfigurationManager <OpenIdConnectConfiguration>( issuer + "/.well-known/openid-configuration", new OpenIdConnectConfigurationRetriever(), new HttpDocumentRetriever(httpClient)); var tokenValidationParameters = new DefaultTokenValidationParameters(oktaMvcOptions, issuer) { NameClaimType = "name", ValidAudience = oktaMvcOptions.ClientId, // CLIST: 2019-11-08 - save the claims token into the bootstrap context for k2 SaveSigninToken = true, }; var tokenExchanger = new TokenExchanger(oktaMvcOptions, issuer, configurationManager); var definedScopes = oktaMvcOptions.Scope?.ToArray() ?? OktaDefaults.Scope; var scopeString = string.Join(" ", definedScopes); var oidcOptions = new OpenIdConnectAuthenticationOptions { ClientId = oktaMvcOptions.ClientId, ClientSecret = oktaMvcOptions.ClientSecret, Authority = issuer, RedirectUri = oktaMvcOptions.RedirectUri, ResponseType = OpenIdConnectResponseType.CodeIdToken, Scope = scopeString, PostLogoutRedirectUri = oktaMvcOptions.PostLogoutRedirectUri, TokenValidationParameters = tokenValidationParameters, SecurityTokenValidator = new StrictSecurityTokenValidator(), AuthenticationMode = (oktaMvcOptions.LoginMode == LoginMode.SelfHosted) ? AuthenticationMode.Passive : AuthenticationMode.Active, Notifications = new OpenIdConnectAuthenticationNotifications { AuthorizationCodeReceived = tokenExchanger.ExchangeCodeForTokenAsync, RedirectToIdentityProvider = notifications.RedirectToIdentityProvider, }, }; if (oktaMvcOptions.SecurityTokenValidated != null) { oidcOptions.Notifications.SecurityTokenValidated = oktaMvcOptions.SecurityTokenValidated; } return(oidcOptions); }
public void RejectWrongAudience() { var fakeIssuer = "example.okta.com"; var fakeAudience = "aud://default"; var fakeClient = "fakeClient"; var claims = new Claim[] { new Claim("cid", fakeClient), }; using (RSACryptoServiceProvider rsaCryptoServiceProvider = new RSACryptoServiceProvider(2048)) { RSAParameters rsaKeyInfo = rsaCryptoServiceProvider.ExportParameters(true); var rsaSecurityKey = new RsaSecurityKey(rsaKeyInfo); var signingCredentials = new SigningCredentials(rsaSecurityKey, SecurityAlgorithms.RsaSha256); // Create the JWT and write it to a string var jwtContents = new JwtSecurityToken( issuer: fakeIssuer, audience: "http://myapi", claims: claims, expires: DateTime.UtcNow.Add(TimeSpan.FromMinutes(1)), signingCredentials: signingCredentials); var jwt = new JwtSecurityTokenHandler().WriteToken(jwtContents); var fakeOktaWebOptions = new OktaWebOptions { OktaDomain = fakeIssuer, }; var handler = new StrictTokenHandler(); var validationParameters = new DefaultTokenValidationParameters(fakeOktaWebOptions, fakeIssuer) { IssuerSigningKey = signingCredentials.Key, ValidAudience = fakeAudience, }; Action act = () => handler.ValidateToken(jwt, validationParameters, out _); act.Should().Throw <SecurityTokenInvalidAudienceException>(); } }
public void RejectWrongAudience() { var fakeIssuer = "example.okta.com"; var fakeAudience = "aud://default"; var fakeClient = "fakeClient"; var claims = new Claim[] { new Claim("cid", fakeClient), }; var credentials = new SigningCredentials( new SymmetricSecurityKey(Encoding.UTF8.GetBytes("fakesigningsecret!")), SecurityAlgorithms.HmacSha256); // Create the JWT and write it to a string var jwtContents = new JwtSecurityToken( issuer: fakeIssuer, audience: "http://myapi", claims: claims, expires: DateTime.UtcNow.Add(TimeSpan.FromMinutes(1)), signingCredentials: credentials); var jwt = new JwtSecurityTokenHandler().WriteToken(jwtContents); var fakeOktaWebOptions = new OktaWebOptions { ClientId = fakeClient, OktaDomain = fakeIssuer, }; var handler = new StrictTokenHandler(fakeOktaWebOptions); var validationParameters = new DefaultTokenValidationParameters(fakeOktaWebOptions, fakeIssuer) { IssuerSigningKey = credentials.Key, ValidAudience = fakeAudience, }; Action act = () => handler.ValidateToken(jwt, validationParameters, out _); act.Should().Throw <SecurityTokenInvalidAudienceException>(); }
private static void AddOpenIdConnectAuthentication(IAppBuilder app, OktaMvcOptions options) { var issuer = UrlHelper.CreateIssuerUrl(options.OktaDomain, options.AuthorizationServerId); var httpClient = new HttpClient(new UserAgentHandler("okta-aspnet", typeof(OktaMiddlewareExtensions).Assembly.GetName().Version)); var configurationManager = new ConfigurationManager <OpenIdConnectConfiguration>( issuer + "/.well-known/openid-configuration", new OpenIdConnectConfigurationRetriever(), new HttpDocumentRetriever(httpClient)); var tokenValidationParameters = new DefaultTokenValidationParameters(options, issuer) { NameClaimType = "name", ValidAudience = options.ClientId, }; var tokenExchanger = new TokenExchanger(options, issuer, configurationManager); // Stop the default behavior of remapping JWT claim names to legacy MS/SOAP claim names JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); var definedScopes = options.Scope?.ToArray() ?? OktaDefaults.Scope; var scopeString = string.Join(" ", definedScopes); app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions { ClientId = options.ClientId, ClientSecret = options.ClientSecret, Authority = issuer, RedirectUri = options.RedirectUri, ResponseType = OpenIdConnectResponseType.CodeIdToken, Scope = scopeString, PostLogoutRedirectUri = options.PostLogoutRedirectUri, TokenValidationParameters = tokenValidationParameters, SecurityTokenValidator = new StrictSecurityTokenValidator(), Notifications = new OpenIdConnectAuthenticationNotifications { AuthorizationCodeReceived = tokenExchanger.ExchangeCodeForTokenAsync, RedirectToIdentityProvider = BeforeRedirectToIdentityProviderAsync, }, }); }
private static AuthenticationBuilder AddJwtValidation(AuthenticationBuilder builder, OktaWebApiOptions options) { var issuer = UrlHelper.CreateIssuerUrl(options.OktaDomain, options.AuthorizationServerId); var tokenValidationParameters = new DefaultTokenValidationParameters(options, issuer) { ValidAudience = options.Audience, }; builder.AddJwtBearer(opt => { opt.Audience = options.Audience; opt.Authority = issuer; opt.TokenValidationParameters = tokenValidationParameters; opt.BackchannelHttpHandler = new UserAgentHandler("okta-aspnetcore", typeof(OktaAuthenticationOptionsExtensions).Assembly.GetName().Version); opt.SecurityTokenValidators.Clear(); opt.SecurityTokenValidators.Add(new StrictSecurityTokenValidator()); }); return(builder); }
public void AllowGoodToken() { var fakeIssuer = "example.okta.com"; var fakeAudience = "aud://default"; using (RSACryptoServiceProvider rsaCryptoServiceProvider = new RSACryptoServiceProvider(2048)) { RSAParameters rsaKeyInfo = rsaCryptoServiceProvider.ExportParameters(true); var rsaSecurityKey = new RsaSecurityKey(rsaKeyInfo); var signingCredentials = new SigningCredentials(rsaSecurityKey, SecurityAlgorithms.RsaSha256); var jwtContents = new JwtSecurityToken( issuer: fakeIssuer, audience: fakeAudience, expires: DateTime.UtcNow.Add(TimeSpan.FromMinutes(1)), signingCredentials: signingCredentials); var jwt = new JwtSecurityTokenHandler().WriteToken(jwtContents); var fakeOktaWebOptions = new OktaWebOptions { OktaDomain = fakeIssuer, }; var handler = new StrictTokenHandler(); var validationParameters = new DefaultTokenValidationParameters(fakeOktaWebOptions, fakeIssuer) { IssuerSigningKey = signingCredentials.Key, ValidAudience = fakeAudience, }; handler.ValidateToken(jwt, validationParameters, out _); } }
public void ConfigureServices(IServiceCollection services) { services.AddControllers(); services.AddCors(options => { options.AddDefaultPolicy(policy => { policy.AllowAnyHeader(); policy.AllowAnyMethod(); policy.WithOrigins( "http://localhost:8080" ); policy.WithExposedHeaders( "X-Pagination-Total", "X-Pagination-PageCount", "X-Pagination-PageSize", "X-Pagination-Page", "X-Pagination-HasPrevious", "X-Pagination-HasNext"); }); }); services.AddDataAccess(Configuration); services.AddServices(Configuration); services.AddAmazonServices(Configuration); services.AddAutoMapper(typeof(MappingProfile)); var oktaDomain = Configuration["Okta:OktaDomain"]; services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { var issuer = $"{oktaDomain}/oauth2/default"; var oktaOptions = new OktaWebApiOptions(); var tokenValidationParams = new DefaultTokenValidationParameters(oktaOptions, issuer) { ValidAudience = oktaOptions.Audience }; options.Authority = issuer; options.Audience = oktaOptions.Audience; options.SecurityTokenValidators.Clear(); options.SecurityTokenValidators.Add(new StrictSecurityTokenValidator()); options.Events = new JwtBearerEvents { OnTokenValidated = async context => { // TODO: Replace with service var userEmail = context.Principal.FindFirstValue(ClaimTypes.NameIdentifier); var userRepository = context.HttpContext.RequestServices.GetRequiredService <IRepository <User> >(); var user = await userRepository.TableNoTracking.FirstOrDefaultAsync(x => x.EmailAddress == userEmail); if (user != null) { var appClaims = new List <Claim> { new Claim(AppClaimTypes.UserId, user.Id.ToString(CultureInfo.InvariantCulture), null, AppClaimTypes.AppClaimsIssuer), }; var appIdentity = new ClaimsIdentity(appClaims); context.Principal.AddIdentity(appIdentity); } } }; }); // Policies are defined in ServiceCollectionExtensions.AddServices() services.AddAuthorization(); services.AddSwaggerGen(options => { options.SwaggerDoc("v1", new OpenApiInfo { Title = "RailWiki API", Version = "v1" }); // Set the comments path for the Swagger JSON and UI. var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); options.IncludeXmlComments(xmlPath); options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme { Type = SecuritySchemeType.OAuth2, OpenIdConnectUrl = new Uri($"{oktaDomain}/oauth2/default/v1/.well-known/openid-configuration"), Flows = new OpenApiOAuthFlows { Implicit = new OpenApiOAuthFlow { AuthorizationUrl = new Uri($"{oktaDomain}/oauth2/default/v1/authorize"), TokenUrl = new Uri($"{oktaDomain}/oauth2/default/v1/token"), Scopes = new Dictionary <string, string> { { "openid", "" }, { "profile", "" } } } } }); options.AddSecurityRequirement(new OpenApiSecurityRequirement { { new OpenApiSecurityScheme { Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "oauth2" } }, new[] { "read" } } }); }); }