public TokenGeneratingContext( ClaimsPrincipal user, ClaimsPrincipal application, OpenIdConnectMessage requestParameters, RequestGrants requestGrants) { if (user == null) { throw new ArgumentNullException(nameof(user)); } if (application == null) { throw new ArgumentNullException(nameof(application)); } if (requestParameters == null) { throw new ArgumentNullException(nameof(requestParameters)); } if (requestGrants == null) { throw new ArgumentNullException(nameof(requestGrants)); } User = user; Application = application; RequestParameters = requestParameters; RequestGrants = requestGrants; }
public static TokenRequest Valid( OpenIdConnectMessage request, string userId, string clientId, RequestGrants grants) { return(new TokenRequest(request, userId, clientId, grants)); }
private TokenRequest( OpenIdConnectMessage request, string userId, string clientId, RequestGrants grants) { IsValid = true; Request = request; UserId = userId; ClientId = clientId; RequestGrants = grants; }
public void CreateTokenGenerationContext_CorrectlyCreatesContext_FromTheAuthorizationRequest( string responseTypes, string expectedRequestedTokens) { // Arrange var authorizationRequest = new Dictionary <string, string[]> { [OpenIdConnectParameterNames.ClientId] = new[] { "clientId" }, [OpenIdConnectParameterNames.RedirectUri] = new[] { "http://localhost:123/callback" }, [OpenIdConnectParameterNames.ResponseType] = new[] { responseTypes }, [OpenIdConnectParameterNames.ResponseMode] = new[] { OpenIdConnectResponseMode.FormPost }, [OpenIdConnectParameterNames.Scope] = new[] { "openid" }, [OpenIdConnectParameterNames.Nonce] = new[] { "asdf" }, [OpenIdConnectParameterNames.State] = new[] { "state" } }; var message = new OpenIdConnectMessage(authorizationRequest); var requestGrants = new RequestGrants { RedirectUri = "http://localhost:123/callback", ResponseMode = OpenIdConnectResponseMode.FormPost, Scopes = new List <ApplicationScope> { ApplicationScope.OpenId }, Tokens = expectedRequestedTokens.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries) }; var request = AuthorizationRequest.Valid(message, requestGrants); var user = new ClaimsPrincipal(); var application = new ClaimsPrincipal(); // Act var context = request.CreateTokenGeneratingContext(user, application); // Assert Assert.NotNull(context); Assert.Equal(expectedRequestedTokens.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries), context.RequestGrants.Tokens); Assert.Equal("http://localhost:123/callback", context.RequestParameters.RedirectUri); Assert.Equal("openid", context.RequestParameters.Scope); Assert.Equal("asdf", context.RequestParameters.Nonce); }
public async Task <TokenRequest> CreateTokenRequestAsync(IDictionary <string, string[]> requestParameters) { var(clientId, clientIdParameterError) = RequestParametersHelper.ValidateParameterIsUnique(requestParameters, OpenIdConnectParameterNames.ClientId, _errorProvider); if (clientIdParameterError != null) { return(TokenRequest.Invalid(clientIdParameterError)); } if (!await _clientIdValidator.ValidateClientIdAsync(clientId)) { return(TokenRequest.Invalid(_errorProvider.InvalidClientId(clientId))); } var(clientSecret, clientSecretParameterError) = RequestParametersHelper.ValidateOptionalParameterIsUnique(requestParameters, OpenIdConnectParameterNames.ClientSecret, _errorProvider); if (clientSecretParameterError != null) { return(TokenRequest.Invalid(clientSecretParameterError)); } if (!await _clientIdValidator.ValidateClientCredentialsAsync(clientId, clientSecret)) { return(TokenRequest.Invalid(_errorProvider.InvalidClientCredentials())); } var(grantType, grantTypeError) = RequestParametersHelper.ValidateParameterIsUnique( requestParameters, OpenIdConnectParameterNames.GrantType, _errorProvider); if (grantTypeError != null) { return(TokenRequest.Invalid(grantTypeError)); } var grantTypeParameter = GetGrantTypeParameter(requestParameters, grantType); if (grantTypeParameter == null) { return(TokenRequest.Invalid(_errorProvider.InvalidGrantType(grantType))); } var(grantValue, grantValueError) = RequestParametersHelper.ValidateParameterIsUnique( requestParameters, grantTypeParameter, _errorProvider); if (grantValueError != null) { return(TokenRequest.Invalid(clientIdParameterError)); } var message = new OpenIdConnectMessage(requestParameters) { RequestType = OpenIdConnectRequestType.Token }; // TODO: File a bug to track we might want to redesign this if we want to consider other flows like // client credentials or resource owner credentials. var consentGrant = await _tokenManager.ExchangeTokenAsync(message); if (!consentGrant.IsValid) { return(TokenRequest.Invalid(consentGrant.Error)); } if (!_timeStampManager.IsValidPeriod(consentGrant.Token.NotBefore, consentGrant.Token.Expires)) { return(TokenRequest.Invalid(_errorProvider.InvalidLifetime())); } if (!string.Equals(clientId, consentGrant.ClientId, StringComparison.Ordinal)) { return(TokenRequest.Invalid(_errorProvider.InvalidGrant())); } var(scope, requestScopesError) = RequestParametersHelper.ValidateOptionalParameterIsUnique(requestParameters, OpenIdConnectParameterNames.Scope, _errorProvider); if (requestScopesError != null) { return(TokenRequest.Invalid(requestScopesError)); } var grantedScopes = consentGrant.GrantedScopes; var parsedScope = scope?.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); if (parsedScope != null) { var scopeResolutionResult = await _scopeResolver.ResolveScopesAsync(clientId, parsedScope); if (!scopeResolutionResult.IsValid) { return(TokenRequest.Invalid(scopeResolutionResult.Error)); } if (grantType.Equals(OpenIdConnectGrantTypes.AuthorizationCode, StringComparison.Ordinal) || grantType.Equals(OpenIdConnectGrantTypes.RefreshToken, StringComparison.Ordinal)) { if (scopeResolutionResult.Scopes.Any(rs => !consentGrant.GrantedScopes.Contains(rs))) { return(TokenRequest.Invalid(_errorProvider.UnauthorizedScope())); } } grantedScopes = scopeResolutionResult.Scopes; } if (grantType.Equals(OpenIdConnectGrantTypes.AuthorizationCode, StringComparison.Ordinal)) { var authorizationCodeError = await ValidateAuthorizationCode( requestParameters, clientId, consentGrant); if (authorizationCodeError != null) { return(TokenRequest.Invalid(authorizationCodeError)); } } var requestGrants = new RequestGrants { Tokens = consentGrant.GrantedTokens.ToList(), Claims = consentGrant.Token.ToList(), Scopes = grantedScopes.ToList() }; return(await ValidateRequestAsync(TokenRequest.Valid( message, consentGrant.UserId, consentGrant.ClientId, requestGrants))); }
public static AuthorizationRequest Valid( OpenIdConnectMessage request, RequestGrants requestGrants) { return(new AuthorizationRequest(request, requestGrants)); }
private AuthorizationRequest(OpenIdConnectMessage request, RequestGrants requestGrants) { IsValid = true; Message = request; RequestGrants = requestGrants; }
public async Task <AuthorizationRequest> CreateAuthorizationRequestAsync(IDictionary <string, string[]> requestParameters) { // Parameters sent without a value MUST be treated as if they were // omitted from the request.The authorization server MUST ignore // unrecognized request parameters.Request and response parameters // MUST NOT be included more than once. // Validate that we only got send one state property as it needs to be included in all responses (including error ones) var(state, stateError) = RequestParametersHelper.ValidateOptionalParameterIsUnique(requestParameters, OpenIdConnectParameterNames.State, _errorProvider); // Start by validating the client_id and redirect_uri as any of them being invalid indicates that we need to // return a 400 response instead of a 302 response with the error. This is signaled by the result not containing // a url to redirect to. var(clientId, redirectUri, clientError) = await ValidateClientIdAndRedirectUri(requestParameters, state); if (clientError != null) { // Send first the state error if there was one. return(AuthorizationRequest.Invalid(new AuthorizationRequestError( stateError ?? clientError, redirectUri: null, responseMode: null))); } // We need to determine what response mode to use to send the errors in case there are any. // In case the response type and response modes are valid, we should use those values when // notifying clients of the errors. // In case there is an issue with the response type or the response mode we need to determine // how to notify the relying party of the errors. // We can divide this in two situations: // The response mode is invalid: // * We ignore the response mode and base our response based on the response type specified. // If a token was requested we send the error response on the fragment of the redirect uri. // If no token was requested we send the error response on the query of the redirect uri. // The response type is invalid: // * We try to determine if this is a hybrid or implicit flow: // If the invalid response type contained a request for an id_token or an access_token, or // contained more than one space separated value, we send the response on the fragment, // unless the response mode is specified and form_post. // If the invalid response type only contained one value and we can not determine is an // implicit request flow, we return the error on the query string unless the response mode // is specified and form_post or fragment. var(responseType, parsedResponseType, tokenRequested, responseTypeError) = ValidateResponseType(requestParameters); var(responseMode, responseModeError) = ValidateResponseMode(requestParameters); var invalidCombinationError = ValidateResponseModeTypeCombination(responseType, tokenRequested, responseMode); if (responseModeError != null || responseMode == null) { responseMode = GetResponseMode(parsedResponseType, tokenRequested); } if (responseTypeError != null) { responseTypeError.State = state; return(AuthorizationRequest.Invalid( new AuthorizationRequestError(stateError ?? responseTypeError, redirectUri, responseMode))); } if (responseModeError != null) { responseModeError.State = state; return(AuthorizationRequest.Invalid( new AuthorizationRequestError(stateError ?? responseModeError, redirectUri, responseMode))); } if (invalidCombinationError != null) { invalidCombinationError.State = state; return(AuthorizationRequest.Invalid( new AuthorizationRequestError(stateError ?? invalidCombinationError, redirectUri, responseMode))); } var(nonce, nonceError) = tokenRequested ? RequestParametersHelper.ValidateParameterIsUnique(requestParameters, OpenIdConnectParameterNames.Nonce, _errorProvider) : RequestParametersHelper.ValidateOptionalParameterIsUnique(requestParameters, OpenIdConnectParameterNames.Nonce, _errorProvider); if (nonceError != null) { nonceError.State = state; return(AuthorizationRequest.Invalid(new AuthorizationRequestError(nonceError, redirectUri, responseMode))); } var(scope, scopeError) = RequestParametersHelper.ValidateParameterIsUnique(requestParameters, OpenIdConnectParameterNames.Scope, _errorProvider); if (scopeError != null) { scopeError.State = state; return(AuthorizationRequest.Invalid(new AuthorizationRequestError(scopeError, redirectUri, responseMode))); } var parsedScope = scope.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); var allWhiteSpace = true; for (int i = 0; i < parsedScope.Length; i++) { allWhiteSpace = string.IsNullOrWhiteSpace(parsedScope[i]); if (!allWhiteSpace) { break; } } if (allWhiteSpace) { scopeError = _errorProvider.MissingRequiredParameter(OpenIdConnectParameterNames.Scope); scopeError.State = state; return(AuthorizationRequest.Invalid(new AuthorizationRequestError( scopeError, redirectUri, responseMode))); } if (parsedResponseType.Contains(OpenIdConnectResponseType.IdToken) && !parsedScope.Contains(OpenIdConnectScope.OpenId)) { scopeError = _errorProvider.MissingOpenIdScope(); scopeError.State = state; return(AuthorizationRequest.Invalid(new AuthorizationRequestError( scopeError, redirectUri, responseMode))); } var resolvedScopes = await _scopeValidator.ResolveScopesAsync(clientId, parsedScope); if (!resolvedScopes.IsValid) { resolvedScopes.Error.State = state; return(AuthorizationRequest.Invalid(new AuthorizationRequestError(resolvedScopes.Error, redirectUri, responseMode))); } var(prompt, promptError) = RequestParametersHelper.ValidateOptionalParameterIsUnique(requestParameters, OpenIdConnectParameterNames.Prompt, _errorProvider); if (promptError != null) { promptError.State = state; return(AuthorizationRequest.Invalid(new AuthorizationRequestError(promptError, redirectUri, responseMode))); } if (prompt != null) { var parsedPrompt = prompt.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); promptError = ValidatePrompt(parsedPrompt); if (promptError != null) { promptError.State = state; return(AuthorizationRequest.Invalid(new AuthorizationRequestError(promptError, redirectUri, responseMode))); } } var(codeChallenge, codeChallengeError) = RequestParametersHelper.ValidateOptionalParameterIsUnique(requestParameters, ProofOfKeyForCodeExchangeParameterNames.CodeChallenge, _errorProvider); if (codeChallengeError != null) { codeChallengeError.State = state; return(AuthorizationRequest.Invalid(new AuthorizationRequestError(codeChallengeError, redirectUri, responseMode))); } if (codeChallenge != null) { // The code challenge needs to be 43 characters long as its the result of Base64URLEncode(SHA256(code_verifier)). // We do this check here because the code challenge might get saved in the serialized authorization code and we // want to prevent it from getting unnecessarily big. if (codeChallenge.Length != 43) { var invalidCodeChallenge = _errorProvider.InvalidCodeChallenge(); invalidCodeChallenge.State = state; return(AuthorizationRequest.Invalid(new AuthorizationRequestError( invalidCodeChallenge, redirectUri, responseMode))); } var(codeChallengeMethod, codeChallengeMethodError) = RequestParametersHelper.ValidateParameterIsUnique(requestParameters, ProofOfKeyForCodeExchangeParameterNames.CodeChallengeMethod, _errorProvider); if (codeChallengeMethodError != null) { codeChallengeMethodError.State = state; return(AuthorizationRequest.Invalid(new AuthorizationRequestError(codeChallengeMethodError, redirectUri, responseMode))); } if (!codeChallengeMethod.Equals(ProofOfKeyForCodeExchangeChallengeMethods.SHA256, StringComparison.Ordinal)) { var invalidChallengeMethod = _errorProvider.InvalidCodeChallengeMethod(codeChallengeMethod); invalidChallengeMethod.State = state; return(AuthorizationRequest.Invalid(new AuthorizationRequestError(invalidChallengeMethod, redirectUri, responseMode))); } } var result = new OpenIdConnectMessage(requestParameters); result.RequestType = OpenIdConnectRequestType.Authentication; var requestGrants = new RequestGrants { Tokens = GetRequestedTokens(parsedResponseType, resolvedScopes.Scopes), Scopes = resolvedScopes.Scopes.ToList(), ResponseMode = responseMode, RedirectUri = redirectUri }; return(await ValidateRequestAsync(AuthorizationRequest.Valid(result, requestGrants))); }