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 { } }
/// <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<Uri>.</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())); }
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); }