Beispiel #1
0
 public void Validate(JwtSecurityToken jwt, OpenIdConnectProtocolValidator protocolValidator, OpenIdConnectProtocolValidationContext validationContext, ExpectedException ee)
 {
     try
     {
         protocolValidator.Validate(jwt, validationContext);
         ee.ProcessNoException();
     }
     catch (Exception ex)
     {
         ee.ProcessException(ex);
     }
 }
 public OpenIdConnectAuthenticationOptions(string authenticationType)
     : base(authenticationType)
 {
     AuthenticationMode         = Security.AuthenticationMode.Active;
     BackchannelTimeout         = TimeSpan.FromMinutes(1);
     Caption                    = OpenIdConnectAuthenticationDefaults.Caption;
     ProtocolValidator          = new OpenIdConnectProtocolValidator();
     RefreshOnIssuerKeyNotFound = true;
     ResponseType               = OpenIdConnectResponseTypes.CodeIdToken;
     Scope = OpenIdConnectScopes.OpenIdProfile;
     TokenValidationParameters = new TokenValidationParameters();
     UseTokenLifetime          = true;
 }
Beispiel #3
0
 public OpenIdConnectAuthenticationOptions(string authenticationScheme)
 {
     AuthenticationScheme = authenticationScheme;
     BackchannelTimeout   = TimeSpan.FromMinutes(1);
     Caption = OpenIdConnectAuthenticationDefaults.Caption;
     GetClaimsFromUserInfoEndpoint = false;
     ProtocolValidator             = new OpenIdConnectProtocolValidator();
     RefreshOnIssuerKeyNotFound    = true;
     ResponseMode = OpenIdConnectResponseModes.FormPost;
     ResponseType = OpenIdConnectResponseTypes.CodeIdToken;
     Scope        = OpenIdConnectScopes.OpenIdProfile;
     TokenValidationParameters = new TokenValidationParameters();
     UseTokenLifetime          = true;
 }
Beispiel #4
0
 public OpenIdConnectAuthenticationOptions(string authenticationScheme)
 {
     // REVIEW: why was this active by default??
     //AuthenticationMode = AuthenticationMode.Active;
     AuthenticationScheme = authenticationScheme;
     BackchannelTimeout   = TimeSpan.FromMinutes(1);
     Caption                    = OpenIdConnectAuthenticationDefaults.Caption;
     ProtocolValidator          = new OpenIdConnectProtocolValidator();
     RefreshOnIssuerKeyNotFound = true;
     ResponseType               = OpenIdConnectResponseTypes.CodeIdToken;
     Scope = OpenIdConnectScopes.OpenIdProfile;
     TokenValidationParameters = new TokenValidationParameters();
     UseTokenLifetime          = true;
 }
Beispiel #5
0
        public void OpenIdConnectProtocolValidator_GenerateNonce()
        {
            List <string> errors = new List <string>();
            OpenIdConnectProtocolValidator protocolValidator = new OpenIdConnectProtocolValidator();
            string nonce          = protocolValidator.GenerateNonce();
            int    endOfTimestamp = nonce.IndexOf('.');

            if (endOfTimestamp == -1)
            {
                errors.Add("nonce does not have '.' seperator");
            }
            else
            {
            }
        }
Beispiel #6
0
 public OpenIdConnectAuthenticationOptions(string authenticationType)
     : base(authenticationType)
 {
     AuthenticationMode = AuthenticationMode.Active;
     BackchannelTimeout = TimeSpan.FromMinutes(1);
     Caption            = OpenIdConnectAuthenticationDefaults.Caption;
     ProtocolValidator  = new OpenIdConnectProtocolValidator()
     {
         RequireStateValidation = false,
         NonceLifetime          = TimeSpan.FromMinutes(15)
     };
     RefreshOnIssuerKeyNotFound = true;
     ResponseType              = OpenIdConnectResponseType.CodeIdToken;
     Scope                     = OpenIdConnectScope.OpenIdProfile;
     SecurityTokenValidator    = new JwtSecurityTokenHandler();
     RequireHttpsMetadata      = true;
     TokenValidationParameters = new TokenValidationParameters();
     UseTokenLifetime          = true;
     CookieManager             = new CookieManager();
 }
        /// <summary>
        ///     Gets the authorization code request URL for the specified identity provider.
        /// </summary>
        /// <param name="idpLoginRequest">The oidc provider.</param>
        /// <param name="requestBaseUrl">The base url message.</param>
        /// <returns>Task&lt;Uri&gt;.</returns>
        /// <exception cref="System.ArgumentNullException">
        /// </exception>
        public async Task <Uri> GetAuthorizationCodeRequestUrl(IdentityProviderLoginRequest idpLoginRequest, Uri requestBaseUrl)
        {
            if (idpLoginRequest == null)
            {
                throw new ArgumentNullException(nameof(idpLoginRequest));
            }

            if (requestBaseUrl == null)
            {
                throw new ArgumentNullException(nameof(requestBaseUrl));
            }

            if (string.IsNullOrWhiteSpace(idpLoginRequest.Tenant))
            {
                throw new ArgumentException(@"The tenant is invalid.", nameof(idpLoginRequest));
            }

            if (idpLoginRequest.IdentityProviderId <= 0)
            {
                throw new ArgumentException(@"The identity provider is invalid.", nameof(idpLoginRequest));
            }

            if (string.IsNullOrWhiteSpace(idpLoginRequest.RedirectUrl))
            {
                throw new ArgumentException(@"The redirect url is invalid.", nameof(idpLoginRequest));
            }

            long   tenantId;
            long   oidcProviderId;
            string oidcConfigurationUrl;
            string oidcClientId;
            bool   alwaysPrompt;

            using (new SecurityBypassContext())
                using (new TenantAdministratorContext(idpLoginRequest.Tenant))
                {
                    var oidcIdentityProvider = ReadiNow.Model.Entity.Get <OidcIdentityProvider>(idpLoginRequest.IdentityProviderId, GetOidcProviderFieldsToLoad());

                    if (oidcIdentityProvider == null)
                    {
                        throw new AuthenticationException("The identity provider does not exist.");
                    }

                    ValidateOidcProviderFields(oidcIdentityProvider);

                    // Store any required entity model fields upfront.
                    // Any code running after the await statement may run a different thread
                    tenantId             = RequestContext.TenantId;
                    oidcProviderId       = oidcIdentityProvider.Id;
                    oidcClientId         = oidcIdentityProvider.OidcClientId;
                    oidcConfigurationUrl = oidcIdentityProvider.OidcIdentityProviderConfigurationUrl;
                    alwaysPrompt         = oidcIdentityProvider.OidcAlwaysPrompt ?? true;
                }

            OpenIdConnectConfiguration oidcConfig;

            try
            {
                // Get the configuration
                oidcConfig = await _configurationManager.GetIdentityProviderConfigurationAsync(oidcConfigurationUrl);
            }
            catch (Exception ex)
            {
                throw new OidcProviderInvalidConfigurationException(ex);
            }

            var oidcProtocolValidator = new OpenIdConnectProtocolValidator();

            // Create authorization state
            var authStateObject = new OpenIdConnectAuthorizationState
            {
                Timestamp          = DateTime.UtcNow.Ticks,
                RedirectUrl        = idpLoginRequest.RedirectUrl,
                IdentityProviderId = oidcProviderId,
                TenantId           = tenantId,
                Nonce = oidcProtocolValidator.GenerateNonce()
            };

            // Serialize and encrypt state
            var stateJson      = JSON.Serialize(authStateObject);
            var cryptoProvider = new EncodingCryptoProvider();
            var encryptedState = cryptoProvider.EncryptAndEncode(stateJson);

            // Create code request oidc message
            var oidcMessage = new OpenIdConnectMessage
            {
                ClientId      = oidcClientId,
                IssuerAddress = oidcConfig.AuthorizationEndpoint,
                RedirectUri   = GetOidcAuthResponseUri(requestBaseUrl, idpLoginRequest.Tenant),
                Scope         = "openid email",
                ResponseType  = "code",
                State         = encryptedState,
                Nonce         = authStateObject.Nonce,
                Prompt        = alwaysPrompt ? "login" : null
            };

            // Get request url
            return(new Uri(oidcMessage.CreateAuthenticationRequestUrl()));
        }
        /// <summary>
        ///     Validates the identity token.
        /// </summary>
        /// <param name="idToken">The identifier token.</param>
        /// <param name="oidcClientId">The oidc client identifier.</param>
        /// <param name="nonce">The nonce.</param>
        /// <param name="oidcConfig">The oidc configuration.</param>
        /// <returns>JwtSecurityToken.</returns>
        /// <exception cref="System.ArgumentNullException">
        /// </exception>
        private JwtSecurityToken ValidateIdentityToken(string idToken, string oidcClientId, string nonce, OpenIdConnectConfiguration oidcConfig)
        {
            if (string.IsNullOrWhiteSpace(idToken))
            {
                throw new ArgumentNullException(nameof(idToken));
            }

            if (string.IsNullOrWhiteSpace(oidcClientId))
            {
                throw new ArgumentNullException(nameof(oidcClientId));
            }

            if (string.IsNullOrWhiteSpace(nonce))
            {
                throw new ArgumentNullException(nameof(nonce));
            }

            if (oidcConfig == null)
            {
                throw new ArgumentNullException(nameof(oidcConfig));
            }

            var idTokenValidationParameters = new TokenValidationParameters
            {
                ValidAudience       = oidcClientId,
                ValidIssuer         = oidcConfig.Issuer,
                IssuerSigningTokens = oidcConfig.JsonWebKeySet.GetSigningTokens()
            };

            if (IsTokenValidationDisabled)
            {
                idTokenValidationParameters.LifetimeValidator = (before, expires, token, parameters) => true;
            }

            try
            {
                SecurityToken validatedToken;
                var           jwtTokenHandler = new JwtSecurityTokenHandler();
                jwtTokenHandler.ValidateToken(idToken, idTokenValidationParameters, out validatedToken);

                var validationContext = new OpenIdConnectProtocolValidationContext
                {
                    Nonce = IsTokenValidationDisabled ? null : nonce
                };

                var validatedJwtToken = validatedToken as JwtSecurityToken;

                var oidcProtocolValidator = new OpenIdConnectProtocolValidator();
                if (IsTokenValidationDisabled)
                {
                    oidcProtocolValidator.RequireNonce = false;
                }
                oidcProtocolValidator.Validate(validatedJwtToken, validationContext);

                return(validatedJwtToken);
            }
            catch (Exception ex)
            {
                throw new AuthenticationException("An error occurred validating the Id token.", ex);
            }
        }
Beispiel #9
0
        public void OpenIdConnectProtocolValidator_GetSets()
        {
            OpenIdConnectProtocolValidator validationParameters = new OpenIdConnectProtocolValidator();
            Type type = typeof(OpenIdConnectProtocolValidator);

            PropertyInfo[] properties = type.GetProperties();
            if (properties.Length != 9)
            {
                Assert.Fail("Number of properties has changed from 9 to: " + properties.Length + ", adjust tests");
            }

            GetSetContext context =
                new GetSetContext
            {
                PropertyNamesAndSetGetValue = new List <KeyValuePair <string, List <object> > >
                {
                    new KeyValuePair <string, List <object> >("NonceLifetime", new List <object> {
                        TimeSpan.FromMinutes(60), TimeSpan.FromMinutes(10), TimeSpan.FromMinutes(100)
                    }),
                    new KeyValuePair <string, List <object> >("RequireAcr", new List <object> {
                        false, true, false
                    }),
                    new KeyValuePair <string, List <object> >("RequireAmr", new List <object> {
                        false, true, false
                    }),
                    new KeyValuePair <string, List <object> >("RequireAuthTime", new List <object> {
                        false, true, false
                    }),
                    new KeyValuePair <string, List <object> >("RequireAzp", new List <object> {
                        false, true, false
                    }),
                    new KeyValuePair <string, List <object> >("RequireNonce", new List <object> {
                        true, false, true
                    }),
                    new KeyValuePair <string, List <object> >("RequireSub", new List <object> {
                        false, true, false
                    }),
                    new KeyValuePair <string, List <object> >("RequireTimeStampInNonce", new List <object> {
                        true, false, true
                    }),
                },
                Object = validationParameters,
            };

            TestUtilities.GetSet(context);
            TestUtilities.AssertFailIfErrors(MethodInfo.GetCurrentMethod().Name, context.Errors);

            ExpectedException ee = ExpectedException.ArgumentNullException();

            Assert.IsNotNull(validationParameters.HashAlgorithmMap);
            Assert.AreEqual(validationParameters.HashAlgorithmMap.Count, 9);

            ee = ExpectedException.ArgumentOutOfRangeException();
            try
            {
                validationParameters.NonceLifetime = TimeSpan.Zero;
                ee.ProcessNoException();
            }
            catch (Exception ex)
            {
                ee.ProcessException(ex);
            }
        }
Beispiel #10
0
        public void OpenIdConnectProtocolValidator_Validate()
        {
            JwtSecurityToken jwt = new JwtSecurityToken();
            OpenIdConnectProtocolValidationContext validationContext = new OpenIdConnectProtocolValidationContext();
            OpenIdConnectProtocolValidator         protocolValidator = new OpenIdConnectProtocolValidator();

            // jwt null
            Validate(jwt: null, protocolValidator: protocolValidator, validationContext: null, ee: ExpectedException.ArgumentNullException());

            // validationContext null
            Validate(jwt: jwt, protocolValidator: protocolValidator, validationContext: null, ee: ExpectedException.ArgumentNullException());

            // aud missing
            Validate(jwt: jwt, protocolValidator: protocolValidator, validationContext: validationContext, ee: new ExpectedException(typeExpected: typeof(OpenIdConnectProtocolException), substringExpected: "IDX10309:"));

            // exp missing
            jwt.Payload.AddClaim(new Claim(JwtRegisteredClaimNames.Aud, IdentityUtilities.DefaultAudience));
            Validate(jwt: jwt, protocolValidator: protocolValidator, validationContext: validationContext, ee: new ExpectedException(typeExpected: typeof(OpenIdConnectProtocolException), substringExpected: "IDX10309:"));

            // iat missing
            jwt.Payload.AddClaim(new Claim(JwtRegisteredClaimNames.Exp, EpochTime.GetIntDate(DateTime.UtcNow).ToString()));
            Validate(jwt: jwt, protocolValidator: protocolValidator, validationContext: validationContext, ee: new ExpectedException(typeExpected: typeof(OpenIdConnectProtocolException), substringExpected: "IDX10309:"));

            // iss missing
            jwt.Payload.AddClaim(new Claim(JwtRegisteredClaimNames.Iat, EpochTime.GetIntDate(DateTime.UtcNow).ToString()));
            Validate(jwt: jwt, protocolValidator: protocolValidator, validationContext: validationContext, ee: new ExpectedException(typeExpected: typeof(OpenIdConnectProtocolException), substringExpected: "IDX10309:"));

            // add iis, nonce is not retuired.
            protocolValidator.RequireNonce = false;
            jwt.Payload.AddClaim(new Claim(JwtRegisteredClaimNames.Iss, IdentityUtilities.DefaultIssuer));
            Validate(jwt: jwt, protocolValidator: protocolValidator, validationContext: validationContext, ee: ExpectedException.NoExceptionExpected);

            // nonce invalid
            string validNonce = protocolValidator.GenerateNonce();

            // add the valid 'nonce' but set validationContext.Nonce to a different 'nonce'.
            protocolValidator.RequireNonce = true;
            jwt.Payload.AddClaim(new Claim(JwtRegisteredClaimNames.Nonce, validNonce));
            validationContext.Nonce = protocolValidator.GenerateNonce();
            Validate(jwt: jwt, protocolValidator: protocolValidator, validationContext: validationContext, ee: new ExpectedException(typeExpected: typeof(OpenIdConnectProtocolInvalidNonceException), substringExpected: "IDX10301:"));

            // sub missing, default not required
            validationContext.Nonce = validNonce;
            Validate(jwt: jwt, protocolValidator: protocolValidator, validationContext: validationContext, ee: ExpectedException.NoExceptionExpected);

            protocolValidator.RequireSub = true;
            Validate(jwt: jwt, protocolValidator: protocolValidator, validationContext: validationContext, ee: new ExpectedException(typeExpected: typeof(OpenIdConnectProtocolException), substringExpected: "IDX10309:"));

            // authorizationCode invalid
            string validAuthorizationCode = protocolValidator.GenerateNonce();
            string validChash             = IdentityUtilities.CreateCHash(validAuthorizationCode, "SHA256");

            JwtSecurityToken jwtWithSignatureChash =
                new JwtSecurityToken
                (
                    audience: IdentityUtilities.DefaultAudience,
                    claims: new List <Claim>
            {
                new Claim(JwtRegisteredClaimNames.CHash, validChash),
                new Claim(JwtRegisteredClaimNames.Iat, EpochTime.GetIntDate(DateTime.UtcNow).ToString()),
                new Claim(JwtRegisteredClaimNames.Nonce, validNonce),
                new Claim(JwtRegisteredClaimNames.Sub, "sub"),
            },
                    expires: DateTime.UtcNow + TimeSpan.FromHours(1),
                    issuer: IdentityUtilities.DefaultIssuer,
                    signingCredentials: IdentityUtilities.DefaultAsymmetricSigningCredentials
                );

            Dictionary <string, string> algmap = new Dictionary <string, string>(protocolValidator.HashAlgorithmMap);

            protocolValidator.HashAlgorithmMap.Clear();
            protocolValidator.HashAlgorithmMap.Add(JwtAlgorithms.RSA_SHA256, "SHA256");

            validationContext.Nonce             = validNonce;
            validationContext.AuthorizationCode = validNonce;
            Validate(jwt: jwtWithSignatureChash, protocolValidator: protocolValidator, validationContext: validationContext, ee: new ExpectedException(typeExpected: typeof(OpenIdConnectProtocolInvalidCHashException), substringExpected: "IDX10304:"));

            // nonce and authorizationCode valid
            validationContext.AuthorizationCode = validAuthorizationCode;
            Validate(jwt: jwtWithSignatureChash, protocolValidator: protocolValidator, validationContext: validationContext, ee: ExpectedException.NoExceptionExpected);

            // validate optional claims
            protocolValidator.RequireAcr = true;
            Validate(jwt: jwtWithSignatureChash, protocolValidator: protocolValidator, validationContext: validationContext, ee: new ExpectedException(typeExpected: typeof(OpenIdConnectProtocolException), substringExpected: "IDX10312:"));
            jwtWithSignatureChash.Payload.AddClaim(new Claim(JwtRegisteredClaimNames.Acr, "acr"));

            protocolValidator.RequireAmr = true;
            Validate(jwt: jwtWithSignatureChash, protocolValidator: protocolValidator, validationContext: validationContext, ee: new ExpectedException(typeExpected: typeof(OpenIdConnectProtocolException), substringExpected: "IDX10313:"));
            jwtWithSignatureChash.Payload.AddClaim(new Claim(JwtRegisteredClaimNames.Amr, "amr"));

            protocolValidator.RequireAuthTime = true;
            Validate(jwt: jwtWithSignatureChash, protocolValidator: protocolValidator, validationContext: validationContext, ee: new ExpectedException(typeExpected: typeof(OpenIdConnectProtocolException), substringExpected: "IDX10314:"));
            jwtWithSignatureChash.Payload.AddClaim(new Claim(JwtRegisteredClaimNames.AuthTime, "authTime"));

            protocolValidator.RequireAzp = true;
            Validate(jwt: jwtWithSignatureChash, protocolValidator: protocolValidator, validationContext: validationContext, ee: new ExpectedException(typeExpected: typeof(OpenIdConnectProtocolException), substringExpected: "IDX10315:"));
            jwtWithSignatureChash.Payload.AddClaim(new Claim(JwtRegisteredClaimNames.Azp, "azp"));

            Validate(jwt: jwtWithSignatureChash, protocolValidator: protocolValidator, validationContext: validationContext, ee: ExpectedException.NoExceptionExpected);
        }