コード例 #1
0
        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>();
        }
コード例 #2
0
        /// <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);
        }
コード例 #3
0
        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(),
            });
        }
コード例 #4
0
        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>();
        }
コード例 #5
0
        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 _);
        }
コード例 #6
0
        /// <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);
        }
コード例 #7
0
        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>();
            }
        }
コード例 #8
0
        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>();
        }
コード例 #9
0
        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,
                },
            });
        }
コード例 #10
0
        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);
        }
コード例 #11
0
        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 _);
            }
        }
コード例 #12
0
ファイル: Startup.cs プロジェクト: RailWiki/services
        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" }
                    }
                });
            });
        }