private HttpResponseMessage ProcessJwtRequest(TokenRequest request)
        {
            if (string.IsNullOrEmpty(request.Assertion))
            {
                Tracing.Error("ADFS integration authentication request (JWT) with empty assertion");
                return OAuthErrorResponseMessage(OAuth2Constants.Errors.InvalidGrant);
            }

            Tracing.Information("Starting ADFS integration authentication request (JWT) for scope: " + request.Scope);

            var bridge = new AdfsBridge(ConfigurationRepository);
            GenericXmlSecurityToken token;
            try
            {
                Tracing.Verbose("Starting ADFS integration authentication request (JWT) for assertion: " + request.Assertion);

                token = bridge.AuthenticateJwt(request.Assertion, request.Scope);
            }
            catch (Exception ex)
            {
                Tracing.Error("Error while communicating with ADFS: " + ex.ToString());
                return OAuthErrorResponseMessage(OAuth2Constants.Errors.InvalidRequest);
            }

            var response = CreateTokenResponse(token, request.Scope);
            Tracing.Verbose("ADFS integration JWT authentication successful");

            return response;
        }
        public HttpResponseMessage Post(TokenRequest request)
        {
            Tracing.Start("OIDC Token Endpoint");

            ValidatedRequest validatedRequest;

            try
            {
                var validator = new TokenRequestValidator(Clients, Grants);
                validatedRequest = validator.Validate(request, ClaimsPrincipal.Current);
            }
            catch (TokenRequestValidationException ex)
            {
                Tracing.Error("Aborting OIDC token request");
                return Request.CreateOAuthErrorResponse(ex.OAuthError);
            }

            // switch over the grant type
            if (validatedRequest.GrantType.Equals(OAuth2Constants.GrantTypes.AuthorizationCode))
            {
                return ProcessAuthorizationCodeRequest(validatedRequest);
            }
            else if (string.Equals(validatedRequest.GrantType, OAuth2Constants.GrantTypes.RefreshToken))
            {
                return ProcessRefreshTokenRequest(validatedRequest);
            }

            Tracing.Error("unsupported grant type: " + request.Grant_Type);
            return Request.CreateOAuthErrorResponse(OAuth2Constants.Errors.UnsupportedGrantType);
        }
        public HttpResponseMessage Post(TokenRequest tokenRequest)
        {
            Tracing.Information("OAuth2 endpoint called.");

            Client client = null;
            if (!ValidateClient(out client))
            {
                Tracing.Error("Invalid client: " + ClaimsPrincipal.Current.Identity.Name);
                return OAuthErrorResponseMessage(OAuth2Constants.Errors.InvalidClient);
            }

            Tracing.Information("Client: " + client.Name);

            var tokenType = ConfigurationRepository.Global.DefaultHttpTokenType;

            // validate scope
            EndpointReference appliesTo;
            try
            {
                appliesTo = new EndpointReference(tokenRequest.Scope);
                Tracing.Information("OAuth2 endpoint called for scope: " + tokenRequest.Scope);
            }
            catch
            {
                Tracing.Error("Malformed scope: " + tokenRequest.Scope);
                return OAuthErrorResponseMessage(OAuth2Constants.Errors.InvalidScope);
            }

            // check grant type
            if (string.Equals(tokenRequest.Grant_Type, OAuth2Constants.GrantTypes.Password, System.StringComparison.Ordinal))
            {
                if (ConfigurationRepository.OAuth2.EnableResourceOwnerFlow)
                {
                    if (client.AllowResourceOwnerFlow)
                    {
                        return ProcessResourceOwnerCredentialRequest(tokenRequest.UserName, tokenRequest.Password, appliesTo, tokenType, client);
                    }
                    else
                    {
                        Tracing.Error("Client is not allowed to use the resource owner password flow:" + client.Name);
                    }
                }
            }

            Tracing.Error("invalid grant type: " + tokenRequest.Grant_Type);
            return OAuthErrorResponseMessage(OAuth2Constants.Errors.UnsupportedGrantType);
        }
        private HttpResponseMessage ProcessResourceOwnerCredentialRequest(TokenRequest request, string tokenType, Client client)
        {
            Tracing.Information("Starting resource owner password credential flow for client: " + client.Name);
            var appliesTo = new EndpointReference(request.Scope);

            if (string.IsNullOrWhiteSpace(request.UserName) || string.IsNullOrWhiteSpace(request.Password))
            {
                Tracing.Error("Invalid resource owner credentials for: " + appliesTo.Uri.AbsoluteUri);
                return OAuthErrorResponseMessage(OAuth2Constants.Errors.InvalidGrant);
            }

            if (UserRepository.ValidateUser(request.UserName, request.Password))
            {
                return CreateTokenResponse(request.UserName, client, appliesTo, tokenType, includeRefreshToken: client.AllowRefreshToken);
            }
            else
            {
                Tracing.Error("Resource owner credential validation failed: " + request.UserName);
                return OAuthErrorResponseMessage(OAuth2Constants.Errors.InvalidGrant);
            }
        }
        public HttpResponseMessage Post(TokenRequest request)
        {
            if (request == null)
            {
                return OAuthErrorResponseMessage(OAuth2Constants.Errors.InvalidRequest);
            }

            Uri uri;
            if (string.IsNullOrEmpty(request.Scope) ||
                !Uri.TryCreate(request.Scope, UriKind.Absolute, out uri))
            {
                Tracing.Error("Starting ADFS integration request with invalid scope: " + request.Scope);
                return OAuthErrorResponseMessage(OAuth2Constants.Errors.InvalidScope);
            }

            if (request.Grant_Type.Equals(OAuth2Constants.GrantTypes.Password) &&
                ConfigurationRepository.AdfsIntegration.UsernameAuthenticationEnabled)
            {
                return ProcessUserNameRequest(request);
            }

            // federation via SAML
            if (request.Grant_Type.Equals(OAuth2Constants.GrantTypes.Saml2) &&
                ConfigurationRepository.AdfsIntegration.SamlAuthenticationEnabled)
            {
                return ProcessSamlRequest(request);
            }

            // federation via JWT
            if (request.Grant_Type.Equals(OAuth2Constants.GrantTypes.JWT) &&
                ConfigurationRepository.AdfsIntegration.JwtAuthenticationEnabled)
            {
                return ProcessJwtRequest(request);
            }

            Tracing.Error("Unsupported grant type: " + request.Grant_Type);
            return OAuthErrorResponseMessage(OAuth2Constants.Errors.UnsupportedGrantType);
        }
        private HttpResponseMessage ValidateRequest(TokenRequest request, out Client client)
        {
            client = null;

            // grant type is required
            if (string.IsNullOrWhiteSpace(request.Grant_Type))
            {
                return OAuthErrorResponseMessage(OAuth2Constants.Errors.UnsupportedGrantType);
            }

            // check supported grant types
            if (!request.Grant_Type.Equals(OAuth2Constants.GrantTypes.AuthorizationCode) &&
                !request.Grant_Type.Equals(OAuth2Constants.GrantTypes.Password) &&
                !request.Grant_Type.Equals(OAuth2Constants.GrantTypes.RefreshToken))
            {
                return OAuthErrorResponseMessage(OAuth2Constants.Errors.UnsupportedGrantType);
            }

            // resource owner password flow requires a well-formed scope
            EndpointReference appliesTo = null;
            if (request.Grant_Type.Equals(OAuth2Constants.GrantTypes.Password))
            {
                try
                {
                    appliesTo = new EndpointReference(request.Scope);
                    Tracing.Information("OAuth2 endpoint called for scope: " + request.Scope);
                }
                catch
                {
                    Tracing.Error("Malformed scope: " + request.Scope);
                    return OAuthErrorResponseMessage(OAuth2Constants.Errors.InvalidScope);
                }
            }

            if (!ValidateClient(out client))
            {
                Tracing.Error("Invalid client: " + ClaimsPrincipal.Current.Identity.Name);
                return OAuthErrorResponseMessage(OAuth2Constants.Errors.InvalidClient);
            }

            // validate grant types against global and client configuration
            if (request.Grant_Type.Equals(OAuth2Constants.GrantTypes.AuthorizationCode))
            {
                if (!ConfigurationRepository.OAuth2.EnableCodeFlow ||
                    !client.AllowCodeFlow)
                {
                    return OAuthErrorResponseMessage(OAuth2Constants.Errors.UnsupportedGrantType);
                }
            }

            if (request.Grant_Type.Equals(OAuth2Constants.GrantTypes.Password))
            {
                if (!ConfigurationRepository.OAuth2.EnableResourceOwnerFlow ||
                    !client.AllowResourceOwnerFlow)
                {
                    return OAuthErrorResponseMessage(OAuth2Constants.Errors.UnsupportedGrantType);
                }
            }

            if (request.Grant_Type.Equals(OAuth2Constants.GrantTypes.RefreshToken))
            {
                if (!client.AllowRefreshToken)
                {
                    return OAuthErrorResponseMessage(OAuth2Constants.Errors.UnsupportedGrantType);
                }
            }

            return null;
        }
        public ValidatedRequest Validate(TokenRequest request, ClaimsPrincipal clientPrincipal)
        {
            var validatedRequest = new ValidatedRequest();

            // validate request model binding
            if (request == null)
            {
                throw new TokenRequestValidationException(
                    "Invalid request parameters.",
                    OAuth2Constants.Errors.InvalidRequest);
            }

            // grant type is required
            if (string.IsNullOrWhiteSpace(request.Grant_Type))
            {
                throw new TokenRequestValidationException(
                    "Missing grant_type",
                    OAuth2Constants.Errors.UnsupportedGrantType);
            }

            // check supported grant types
            if (request.Grant_Type == OAuth2Constants.GrantTypes.AuthorizationCode ||
                request.Grant_Type == OAuth2Constants.GrantTypes.RefreshToken)
            {
                validatedRequest.GrantType = request.Grant_Type;
                Tracing.Information("Grant type: " + validatedRequest.GrantType);
            }
            else
            {
                throw new TokenRequestValidationException(
                    "Invalid grant_type: " + request.Grant_Type,
                    OAuth2Constants.Errors.UnsupportedGrantType);
            }

            // validate client credentials
            var client = ValidateClient(clientPrincipal);
            if (client == null)
            {
                throw new TokenRequestValidationException(
                    "Invalid client: " + clientPrincipal.Identity.Name,
                    OAuth2Constants.Errors.InvalidClient);
            }

            validatedRequest.Client = client;
            Tracing.InformationFormat("Client: {0} ({1})",
                validatedRequest.Client.Name,
                validatedRequest.Client.ClientId);

            switch (request.Grant_Type)
            {
                case OAuth2Constants.GrantTypes.AuthorizationCode:
                    ValidateCodeGrant(validatedRequest, request);
                    break;
                case OAuth2Constants.GrantTypes.RefreshToken:
                    ValidateRefreshTokenGrant(validatedRequest, request);
                    break;
                default:
                    throw new TokenRequestValidationException(
                        "Invalid grant_type: " + request.Grant_Type,
                        OAuth2Constants.Errors.UnsupportedGrantType);
            }

            Tracing.Information("Token request validation successful.");
            return validatedRequest;
        }
        private void ValidateCodeGrant(ValidatedRequest validatedRequest, TokenRequest request)
        {
            if (!validatedRequest.Client.AllowCodeFlow)
            {
                throw new TokenRequestValidationException(
                    "Code flow not allowed for client",
                    OAuth2Constants.Errors.UnauthorizedClient);
            }

            // code needs to be present
            if (string.IsNullOrWhiteSpace(request.Code))
            {
                throw new TokenRequestValidationException(
                    "Missing authorization code",
                    OAuth2Constants.Errors.InvalidGrant);
            }

            //validatedRequest.AuthorizationCode = request.Code;
            Tracing.Information("Authorization code: " + request.Code);

            // check for authorization code in datastore
            var grant = Grants.Get(request.Code);
            if (grant == null)
            {
                throw new TokenRequestValidationException(
                    "Authorization code not found: " + request.Code,
                    OAuth2Constants.Errors.InvalidGrant);
            }

            // make sure the handle is an authorization code
            if (grant.GrantType != StoredGrantType.AuthorizationCode)
            {
                throw new TokenRequestValidationException(
                    "Tampered authorization code: " + request.Code,
                    OAuth2Constants.Errors.InvalidGrant);
            }

            validatedRequest.Grant = grant;
            Tracing.Information("Token handle found: " + grant.GrantId);

            // check the client binding
            if (grant.ClientId != validatedRequest.Client.ClientId)
            {
                throw new TokenRequestValidationException(
                    string.Format("Client {0} is trying to request token using an authorization code from {1}.", validatedRequest.Client.ClientId, grant.ClientId),
                    OAuth2Constants.Errors.InvalidGrant);
            }

            // redirect URI is required
            if (string.IsNullOrWhiteSpace(request.Redirect_Uri))
            {
                throw new TokenRequestValidationException(
                    string.Format("Redirect URI is missing"),
                    OAuth2Constants.Errors.InvalidRequest);
            }

            // check if redirect URI from authorize and token request match
            if (!grant.RedirectUri.Equals(request.Redirect_Uri))
            {
                throw new TokenRequestValidationException(
                    string.Format("Redirect URI in token request ({0}), does not match redirect URI from authorize request ({1})", validatedRequest.RedirectUri, grant.RedirectUri),
                    OAuth2Constants.Errors.InvalidRequest);
            }
        }
        private void ValidateRefreshTokenGrant(ValidatedRequest validatedRequest, TokenRequest request)
        {
            if (!validatedRequest.Client.AllowRefreshToken)
            {
                throw new TokenRequestValidationException(
                    "Refresh token not allowed for client",
                    OAuth2Constants.Errors.UnauthorizedClient);
            }

            // code needs to be present
            if (string.IsNullOrWhiteSpace(request.Refresh_Token))
            {
                throw new TokenRequestValidationException(
                    "Missing refresh token",
                    OAuth2Constants.Errors.InvalidGrant);
            }

            Tracing.Information("Refresh token: " + request.Refresh_Token);

            // check for authorization code in datastore
            var grant = Grants.Get(request.Refresh_Token);
            if (grant == null)
            {
                throw new TokenRequestValidationException(
                    "Refresh token not found: " + request.Refresh_Token,
                    OAuth2Constants.Errors.InvalidGrant);
            }

            // make sure the handle is an authorization code
            if (grant.GrantType != StoredGrantType.RefreshToken)
            {
                throw new TokenRequestValidationException(
                    "Tampered refresh token: " + request.Refresh_Token,
                    OAuth2Constants.Errors.InvalidGrant);
            }

            validatedRequest.Grant = grant;
            Tracing.Information("Stored grant found: " + grant.GrantId);

            // check the client binding
            if (grant.ClientId != validatedRequest.Client.ClientId)
            {
                throw new TokenRequestValidationException(
                    string.Format("Client {0} is trying to request a token using a refresh token from {1}.", validatedRequest.Client.ClientId, grant.ClientId),
                    OAuth2Constants.Errors.InvalidGrant);
            }
        }
示例#10
0
        private HttpResponseMessage ValidateRequest(TokenRequest request, out Client client)
        {
            client = null;

            if (request == null)
            {
                return(OAuthErrorResponseMessage(OAuth2Constants.Errors.InvalidRequest));
            }

            // grant type is required
            if (string.IsNullOrWhiteSpace(request.Grant_Type))
            {
                return(OAuthErrorResponseMessage(OAuth2Constants.Errors.UnsupportedGrantType));
            }

            // check supported grant types
            if (!request.Grant_Type.Equals(OAuth2Constants.GrantTypes.AuthorizationCode) &&
                !request.Grant_Type.Equals(OAuth2Constants.GrantTypes.Password) &&
                !request.Grant_Type.Equals(OAuth2Constants.GrantTypes.RefreshToken))
            {
                return(OAuthErrorResponseMessage(OAuth2Constants.Errors.UnsupportedGrantType));
            }

            // resource owner password flow requires a well-formed scope
            if (request.Grant_Type.Equals(OAuth2Constants.GrantTypes.Password))
            {
                Uri appliesTo;
                if (!Uri.TryCreate(request.Scope, UriKind.Absolute, out appliesTo))
                {
                    Tracing.Error("Malformed scope: " + request.Scope);
                    return(OAuthErrorResponseMessage(OAuth2Constants.Errors.InvalidScope));
                }

                Tracing.Information("OAuth2 endpoint called for scope: " + request.Scope);
            }

            if (!ValidateClient(out client))
            {
                Tracing.Error("Invalid client: " + ClaimsPrincipal.Current.Identity.Name);
                return(OAuthErrorResponseMessage(OAuth2Constants.Errors.InvalidClient));
            }

            // validate grant types against global and client configuration
            if (request.Grant_Type.Equals(OAuth2Constants.GrantTypes.AuthorizationCode))
            {
                if (!ConfigurationRepository.OAuth2.EnableCodeFlow ||
                    !client.AllowCodeFlow)
                {
                    Tracing.Error("Code flow not allowed for client");
                    return(OAuthErrorResponseMessage(OAuth2Constants.Errors.UnsupportedGrantType));
                }
            }

            if (request.Grant_Type.Equals(OAuth2Constants.GrantTypes.Password))
            {
                if (!ConfigurationRepository.OAuth2.EnableResourceOwnerFlow ||
                    !client.AllowResourceOwnerFlow)
                {
                    Tracing.Error("Resource owner password flow not allowed for client");
                    return(OAuthErrorResponseMessage(OAuth2Constants.Errors.UnsupportedGrantType));
                }
            }

            if (request.Grant_Type.Equals(OAuth2Constants.GrantTypes.RefreshToken))
            {
                if (!client.AllowRefreshToken)
                {
                    Tracing.Error("Refresh tokens not allowed for client");
                    return(OAuthErrorResponseMessage(OAuth2Constants.Errors.UnsupportedGrantType));
                }
            }

            return(null);
        }
        private HttpResponseMessage ProcessUserNameRequest(TokenRequest request)
        {
            if (string.IsNullOrEmpty(request.UserName) ||
                string.IsNullOrEmpty(request.Password))
            {
                Tracing.Error("ADFS integration username authentication request with empty username or password");
                return OAuthErrorResponseMessage(OAuth2Constants.Errors.InvalidGrant);
            }

            Tracing.Information("Starting ADFS integration username authentication request for scope: " + request.Scope);

            var bridge = new AdfsBridge(ConfigurationRepository);
            GenericXmlSecurityToken token;
            try
            {
                Tracing.Verbose("ADFS integration username authentication request for user: "******"Error while communicating with ADFS: " + ex.ToString());
                return OAuthErrorResponseMessage(OAuth2Constants.Errors.InvalidRequest);
            }

            var response = CreateTokenResponse(token, request.Scope);
            Tracing.Verbose("ADFS integration username authentication request successful");

            return response;
        }
        private HttpResponseMessage ProcessSamlRequest(TokenRequest request)
        {
            if (string.IsNullOrEmpty(request.Assertion))
            {
                Tracing.Error("ADFS integration SAML authentication request with empty assertion");
                return OAuthErrorResponseMessage(OAuth2Constants.Errors.InvalidGrant);
            }

            // un-base64 saml token string
            string incomingSamlToken;
            try
            {
                incomingSamlToken = Encoding.UTF8.GetString(Convert.FromBase64String(request.Assertion));
            }
            catch
            {
                Tracing.Error("ADFS integration SAML authentication request with malformed SAML assertion: " + request.Assertion);
                return OAuthErrorResponseMessage(OAuth2Constants.Errors.InvalidGrant);
            }

            Tracing.Information("Starting ADFS integration SAML authentication request for scope: " + request.Scope);

            var bridge = new AdfsBridge(ConfigurationRepository);
            GenericXmlSecurityToken token;
            try
            {
                Tracing.Verbose("ADFS integration SAML authentication request for assertion: " + request.Assertion);

                token = bridge.AuthenticateSaml(incomingSamlToken, request.Scope);
            }
            catch (Exception ex)
            {
                Tracing.Error("Error while communicating with ADFS: " + ex.ToString());
                return OAuthErrorResponseMessage(OAuth2Constants.Errors.InvalidRequest);
            }

            var response = CreateTokenResponse(token, request.Scope);
            Tracing.Verbose("ADFS integration SAML authentication request successful");

            return response;
        }
        private HttpResponseMessage ValidateRequest(TokenRequest request, out Client client)
        {
            client = null;

            if (request == null)
            {
                return OAuthErrorResponseMessage(OAuth2Constants.Errors.InvalidRequest);
            }

            // grant type is required
            if (string.IsNullOrWhiteSpace(request.Grant_Type))
            {
                return OAuthErrorResponseMessage(OAuth2Constants.Errors.UnsupportedGrantType);
            }

            // check supported grant types
            if (!request.Grant_Type.Equals(OAuth2Constants.GrantTypes.AuthorizationCode) &&
                !request.Grant_Type.Equals(OAuth2Constants.GrantTypes.Password) &&
                !request.Grant_Type.Equals(OAuth2Constants.GrantTypes.RefreshToken))
            {
                return OAuthErrorResponseMessage(OAuth2Constants.Errors.UnsupportedGrantType);
            }

            // resource owner password flow requires a well-formed scope
            if (request.Grant_Type.Equals(OAuth2Constants.GrantTypes.Password))
            {
                Uri appliesTo;
                if (!Uri.TryCreate(request.Scope, UriKind.Absolute, out appliesTo))
                {
                    logger.Error("Malformed scope: " + request.Scope);
                    return OAuthErrorResponseMessage(OAuth2Constants.Errors.InvalidScope);
                }

                logger.Info("OAuth2 endpoint called for scope: " + request.Scope);
            }

            if (!ValidateClient(out client))
            {
                logger.Error("Invalid client: " + ClaimsPrincipal.Current.Identity.Name); 
                return OAuthErrorResponseMessage(OAuth2Constants.Errors.InvalidClient);
            }

            // validate grant types against global and client configuration
            if (request.Grant_Type.Equals(OAuth2Constants.GrantTypes.AuthorizationCode))
            {
                if (!ConfigurationRepository.OAuth2.EnableCodeFlow ||
                    !client.AllowCodeFlow) 
                {
                    logger.Error("Code flow not allowed for client");

                    return OAuthErrorResponseMessage(OAuth2Constants.Errors.UnsupportedGrantType);
                }
            }

            if (request.Grant_Type.Equals(OAuth2Constants.GrantTypes.Password))
            {
                if (!ConfigurationRepository.OAuth2.EnableResourceOwnerFlow ||
                    !client.AllowResourceOwnerFlow)
                {

                    logger.Error("Resource owner password flow not allowed for client");

                    return OAuthErrorResponseMessage(OAuth2Constants.Errors.UnsupportedGrantType);
                }
            }

            if (request.Grant_Type.Equals(OAuth2Constants.GrantTypes.RefreshToken))
            {
                if (!client.AllowRefreshToken)
                {

                    logger.Error("Refresh tokens not allowed for client");

                    return OAuthErrorResponseMessage(OAuth2Constants.Errors.UnsupportedGrantType);
                }
            }

            return null;
        }