Search in sources :

Example 1 with InvalidClientException

use of org.maxkey.authz.oauth2.common.exceptions.InvalidClientException in project OpenID-Connect-Java-Spring-Server by mitreid-connect.

the class DeviceEndpoint method requestDeviceCode.

@RequestMapping(value = "/" + URL, method = RequestMethod.POST, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public String requestDeviceCode(@RequestParam("client_id") String clientId, @RequestParam(name = "scope", required = false) String scope, Map<String, String> parameters, ModelMap model) {
    ClientDetailsEntity client;
    try {
        client = clientService.loadClientByClientId(clientId);
        // make sure this client can do the device flow
        Collection<String> authorizedGrantTypes = client.getAuthorizedGrantTypes();
        if (authorizedGrantTypes != null && !authorizedGrantTypes.isEmpty() && !authorizedGrantTypes.contains(DeviceTokenGranter.GRANT_TYPE)) {
            throw new InvalidClientException("Unauthorized grant type: " + DeviceTokenGranter.GRANT_TYPE);
        }
    } catch (IllegalArgumentException e) {
        logger.error("IllegalArgumentException was thrown when attempting to load client", e);
        model.put(HttpCodeView.CODE, HttpStatus.BAD_REQUEST);
        return HttpCodeView.VIEWNAME;
    }
    if (client == null) {
        logger.error("could not find client " + clientId);
        model.put(HttpCodeView.CODE, HttpStatus.NOT_FOUND);
        return HttpCodeView.VIEWNAME;
    }
    // make sure the client is allowed to ask for those scopes
    Set<String> requestedScopes = OAuth2Utils.parseParameterList(scope);
    Set<String> allowedScopes = client.getScope();
    if (!scopeService.scopesMatch(allowedScopes, requestedScopes)) {
        // client asked for scopes it can't have
        logger.error("Client asked for " + requestedScopes + " but is allowed " + allowedScopes);
        model.put(HttpCodeView.CODE, HttpStatus.BAD_REQUEST);
        model.put(JsonErrorView.ERROR, "invalid_scope");
        return JsonErrorView.VIEWNAME;
    }
    try {
        DeviceCode dc = deviceCodeService.createNewDeviceCode(requestedScopes, client, parameters);
        Map<String, Object> response = new HashMap<>();
        response.put("device_code", dc.getDeviceCode());
        response.put("user_code", dc.getUserCode());
        response.put("verification_uri", config.getIssuer() + USER_URL);
        if (client.getDeviceCodeValiditySeconds() != null) {
            response.put("expires_in", client.getDeviceCodeValiditySeconds());
        }
        if (config.isAllowCompleteDeviceCodeUri()) {
            URI verificationUriComplete = new URIBuilder(config.getIssuer() + USER_URL).addParameter("user_code", dc.getUserCode()).build();
            response.put("verification_uri_complete", verificationUriComplete.toString());
        }
        model.put(JsonEntityView.ENTITY, response);
        return JsonEntityView.VIEWNAME;
    } catch (DeviceCodeCreationException dcce) {
        model.put(HttpCodeView.CODE, HttpStatus.BAD_REQUEST);
        model.put(JsonErrorView.ERROR, dcce.getError());
        model.put(JsonErrorView.ERROR_MESSAGE, dcce.getMessage());
        return JsonErrorView.VIEWNAME;
    } catch (URISyntaxException use) {
        logger.error("unable to build verification_uri_complete due to wrong syntax of uri components");
        model.put(HttpCodeView.CODE, HttpStatus.INTERNAL_SERVER_ERROR);
        return HttpCodeView.VIEWNAME;
    }
}
Also used : ClientDetailsEntity(org.mitre.oauth2.model.ClientDetailsEntity) HashMap(java.util.HashMap) DeviceCodeCreationException(org.mitre.oauth2.exception.DeviceCodeCreationException) URISyntaxException(java.net.URISyntaxException) URI(java.net.URI) URIBuilder(org.apache.http.client.utils.URIBuilder) InvalidClientException(org.springframework.security.oauth2.common.exceptions.InvalidClientException) DeviceCode(org.mitre.oauth2.model.DeviceCode) RequestMapping(org.springframework.web.bind.annotation.RequestMapping)

Example 2 with InvalidClientException

use of org.maxkey.authz.oauth2.common.exceptions.InvalidClientException in project OpenID-Connect-Java-Spring-Server by mitreid-connect.

the class JWTBearerAuthenticationProvider method authenticate.

/**
 * Try to validate the client credentials by parsing and validating the JWT.
 */
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
    JWTBearerAssertionAuthenticationToken jwtAuth = (JWTBearerAssertionAuthenticationToken) authentication;
    try {
        ClientDetailsEntity client = clientService.loadClientByClientId(jwtAuth.getName());
        JWT jwt = jwtAuth.getJwt();
        JWTClaimsSet jwtClaims = jwt.getJWTClaimsSet();
        if (!(jwt instanceof SignedJWT)) {
            throw new AuthenticationServiceException("Unsupported JWT type: " + jwt.getClass().getName());
        }
        // check the signature with nimbus
        SignedJWT jws = (SignedJWT) jwt;
        JWSAlgorithm alg = jws.getHeader().getAlgorithm();
        if (client.getTokenEndpointAuthSigningAlg() != null && !client.getTokenEndpointAuthSigningAlg().equals(alg)) {
            throw new AuthenticationServiceException("Client's registered token endpoint signing algorithm (" + client.getTokenEndpointAuthSigningAlg() + ") does not match token's actual algorithm (" + alg.getName() + ")");
        }
        if (client.getTokenEndpointAuthMethod() == null || client.getTokenEndpointAuthMethod().equals(AuthMethod.NONE) || client.getTokenEndpointAuthMethod().equals(AuthMethod.SECRET_BASIC) || client.getTokenEndpointAuthMethod().equals(AuthMethod.SECRET_POST)) {
            // this client doesn't support this type of authentication
            throw new AuthenticationServiceException("Client does not support this authentication method.");
        } else if ((client.getTokenEndpointAuthMethod().equals(AuthMethod.PRIVATE_KEY) && (alg.equals(JWSAlgorithm.RS256) || alg.equals(JWSAlgorithm.RS384) || alg.equals(JWSAlgorithm.RS512) || alg.equals(JWSAlgorithm.ES256) || alg.equals(JWSAlgorithm.ES384) || alg.equals(JWSAlgorithm.ES512) || alg.equals(JWSAlgorithm.PS256) || alg.equals(JWSAlgorithm.PS384) || alg.equals(JWSAlgorithm.PS512))) || (client.getTokenEndpointAuthMethod().equals(AuthMethod.SECRET_JWT) && (alg.equals(JWSAlgorithm.HS256) || alg.equals(JWSAlgorithm.HS384) || alg.equals(JWSAlgorithm.HS512)))) {
            // double-check the method is asymmetrical if we're in HEART mode
            if (config.isHeartMode() && !client.getTokenEndpointAuthMethod().equals(AuthMethod.PRIVATE_KEY)) {
                throw new AuthenticationServiceException("[HEART mode] Invalid authentication method");
            }
            JWTSigningAndValidationService validator = validators.getValidator(client, alg);
            if (validator == null) {
                throw new AuthenticationServiceException("Unable to create signature validator for client " + client + " and algorithm " + alg);
            }
            if (!validator.validateSignature(jws)) {
                throw new AuthenticationServiceException("Signature did not validate for presented JWT authentication.");
            }
        } else {
            throw new AuthenticationServiceException("Unable to create signature validator for method " + client.getTokenEndpointAuthMethod() + " and algorithm " + alg);
        }
        // check the issuer
        if (jwtClaims.getIssuer() == null) {
            throw new AuthenticationServiceException("Assertion Token Issuer is null");
        } else if (!jwtClaims.getIssuer().equals(client.getClientId())) {
            throw new AuthenticationServiceException("Issuers do not match, expected " + client.getClientId() + " got " + jwtClaims.getIssuer());
        }
        // check expiration
        if (jwtClaims.getExpirationTime() == null) {
            throw new AuthenticationServiceException("Assertion Token does not have required expiration claim");
        } else {
            // it's not null, see if it's expired
            Date now = new Date(System.currentTimeMillis() - (timeSkewAllowance * 1000));
            if (now.after(jwtClaims.getExpirationTime())) {
                throw new AuthenticationServiceException("Assertion Token is expired: " + jwtClaims.getExpirationTime());
            }
        }
        // check not before
        if (jwtClaims.getNotBeforeTime() != null) {
            Date now = new Date(System.currentTimeMillis() + (timeSkewAllowance * 1000));
            if (now.before(jwtClaims.getNotBeforeTime())) {
                throw new AuthenticationServiceException("Assertion Token not valid untill: " + jwtClaims.getNotBeforeTime());
            }
        }
        // check issued at
        if (jwtClaims.getIssueTime() != null) {
            // since it's not null, see if it was issued in the future
            Date now = new Date(System.currentTimeMillis() + (timeSkewAllowance * 1000));
            if (now.before(jwtClaims.getIssueTime())) {
                throw new AuthenticationServiceException("Assertion Token was issued in the future: " + jwtClaims.getIssueTime());
            }
        }
        // check audience
        if (jwtClaims.getAudience() == null) {
            throw new AuthenticationServiceException("Assertion token audience is null");
        } else if (!(jwtClaims.getAudience().contains(config.getIssuer()) || jwtClaims.getAudience().contains(config.getIssuer() + "token"))) {
            throw new AuthenticationServiceException("Audience does not match, expected " + config.getIssuer() + " or " + (config.getIssuer() + "token") + " got " + jwtClaims.getAudience());
        }
        // IFF we managed to get all the way down here, the token is valid
        // add in the ROLE_CLIENT authority
        Set<GrantedAuthority> authorities = new HashSet<>(client.getAuthorities());
        authorities.add(ROLE_CLIENT);
        return new JWTBearerAssertionAuthenticationToken(jwt, authorities);
    } catch (InvalidClientException e) {
        throw new UsernameNotFoundException("Could not find client: " + jwtAuth.getName());
    } catch (ParseException e) {
        logger.error("Failure during authentication, error was: ", e);
        throw new AuthenticationServiceException("Invalid JWT format");
    }
}
Also used : UsernameNotFoundException(org.springframework.security.core.userdetails.UsernameNotFoundException) ClientDetailsEntity(org.mitre.oauth2.model.ClientDetailsEntity) JWT(com.nimbusds.jwt.JWT) SignedJWT(com.nimbusds.jwt.SignedJWT) SimpleGrantedAuthority(org.springframework.security.core.authority.SimpleGrantedAuthority) GrantedAuthority(org.springframework.security.core.GrantedAuthority) SignedJWT(com.nimbusds.jwt.SignedJWT) JWSAlgorithm(com.nimbusds.jose.JWSAlgorithm) AuthenticationServiceException(org.springframework.security.authentication.AuthenticationServiceException) Date(java.util.Date) JWTClaimsSet(com.nimbusds.jwt.JWTClaimsSet) JWTSigningAndValidationService(org.mitre.jwt.signer.service.JWTSigningAndValidationService) InvalidClientException(org.springframework.security.oauth2.common.exceptions.InvalidClientException) ParseException(java.text.ParseException) HashSet(java.util.HashSet)

Example 3 with InvalidClientException

use of org.maxkey.authz.oauth2.common.exceptions.InvalidClientException in project OpenID-Connect-Java-Spring-Server by mitreid-connect.

the class DefaultOAuth2ProviderTokenService method refreshAccessToken.

@Override
@Transactional(value = "defaultTransactionManager")
public OAuth2AccessTokenEntity refreshAccessToken(String refreshTokenValue, TokenRequest authRequest) throws AuthenticationException {
    if (Strings.isNullOrEmpty(refreshTokenValue)) {
        // throw an invalid token exception if there's no refresh token value at all
        throw new InvalidTokenException("Invalid refresh token: " + refreshTokenValue);
    }
    OAuth2RefreshTokenEntity refreshToken = clearExpiredRefreshToken(tokenRepository.getRefreshTokenByValue(refreshTokenValue));
    if (refreshToken == null) {
        // throw an invalid token exception if we couldn't find the token
        throw new InvalidTokenException("Invalid refresh token: " + refreshTokenValue);
    }
    ClientDetailsEntity client = refreshToken.getClient();
    AuthenticationHolderEntity authHolder = refreshToken.getAuthenticationHolder();
    // make sure that the client requesting the token is the one who owns the refresh token
    ClientDetailsEntity requestingClient = clientDetailsService.loadClientByClientId(authRequest.getClientId());
    if (!client.getClientId().equals(requestingClient.getClientId())) {
        tokenRepository.removeRefreshToken(refreshToken);
        throw new InvalidClientException("Client does not own the presented refresh token");
    }
    // Make sure this client allows access token refreshing
    if (!client.isAllowRefresh()) {
        throw new InvalidClientException("Client does not allow refreshing access token!");
    }
    // clear out any access tokens
    if (client.isClearAccessTokensOnRefresh()) {
        tokenRepository.clearAccessTokensForRefreshToken(refreshToken);
    }
    if (refreshToken.isExpired()) {
        tokenRepository.removeRefreshToken(refreshToken);
        throw new InvalidTokenException("Expired refresh token: " + refreshTokenValue);
    }
    OAuth2AccessTokenEntity token = new OAuth2AccessTokenEntity();
    // get the stored scopes from the authentication holder's authorization request; these are the scopes associated with the refresh token
    Set<String> refreshScopesRequested = new HashSet<>(refreshToken.getAuthenticationHolder().getAuthentication().getOAuth2Request().getScope());
    Set<SystemScope> refreshScopes = scopeService.fromStrings(refreshScopesRequested);
    // remove any of the special system scopes
    refreshScopes = scopeService.removeReservedScopes(refreshScopes);
    Set<String> scopeRequested = authRequest.getScope() == null ? new HashSet<String>() : new HashSet<>(authRequest.getScope());
    Set<SystemScope> scope = scopeService.fromStrings(scopeRequested);
    // remove any of the special system scopes
    scope = scopeService.removeReservedScopes(scope);
    if (scope != null && !scope.isEmpty()) {
        // ensure a proper subset of scopes
        if (refreshScopes != null && refreshScopes.containsAll(scope)) {
            // set the scope of the new access token if requested
            token.setScope(scopeService.toStrings(scope));
        } else {
            String errorMsg = "Up-scoping is not allowed.";
            logger.error(errorMsg);
            throw new InvalidScopeException(errorMsg);
        }
    } else {
        // otherwise inherit the scope of the refresh token (if it's there -- this can return a null scope set)
        token.setScope(scopeService.toStrings(refreshScopes));
    }
    token.setClient(client);
    if (client.getAccessTokenValiditySeconds() != null) {
        Date expiration = new Date(System.currentTimeMillis() + (client.getAccessTokenValiditySeconds() * 1000L));
        token.setExpiration(expiration);
    }
    if (client.isReuseRefreshToken()) {
        // if the client re-uses refresh tokens, do that
        token.setRefreshToken(refreshToken);
    } else {
        // otherwise, make a new refresh token
        OAuth2RefreshTokenEntity newRefresh = createRefreshToken(client, authHolder);
        token.setRefreshToken(newRefresh);
        // clean up the old refresh token
        tokenRepository.removeRefreshToken(refreshToken);
    }
    token.setAuthenticationHolder(authHolder);
    tokenEnhancer.enhance(token, authHolder.getAuthentication());
    tokenRepository.saveAccessToken(token);
    return token;
}
Also used : InvalidTokenException(org.springframework.security.oauth2.common.exceptions.InvalidTokenException) ClientDetailsEntity(org.mitre.oauth2.model.ClientDetailsEntity) Date(java.util.Date) InvalidClientException(org.springframework.security.oauth2.common.exceptions.InvalidClientException) OAuth2RefreshTokenEntity(org.mitre.oauth2.model.OAuth2RefreshTokenEntity) OAuth2AccessTokenEntity(org.mitre.oauth2.model.OAuth2AccessTokenEntity) AuthenticationHolderEntity(org.mitre.oauth2.model.AuthenticationHolderEntity) SystemScope(org.mitre.oauth2.model.SystemScope) InvalidScopeException(org.springframework.security.oauth2.common.exceptions.InvalidScopeException) HashSet(java.util.HashSet) Transactional(org.springframework.transaction.annotation.Transactional)

Example 4 with InvalidClientException

use of org.maxkey.authz.oauth2.common.exceptions.InvalidClientException in project OpenID-Connect-Java-Spring-Server by mitreid-connect.

the class EndSessionEndpoint method endSession.

@RequestMapping(value = "/" + URL, method = RequestMethod.GET)
public String endSession(@RequestParam(value = "id_token_hint", required = false) String idTokenHint, @RequestParam(value = "post_logout_redirect_uri", required = false) String postLogoutRedirectUri, @RequestParam(value = STATE_KEY, required = false) String state, HttpServletRequest request, HttpServletResponse response, HttpSession session, Authentication auth, Model m) {
    // conditionally filled variables
    // pulled from the parsed and validated ID token
    JWTClaimsSet idTokenClaims = null;
    // pulled from ID token's audience field
    ClientDetailsEntity client = null;
    if (!Strings.isNullOrEmpty(postLogoutRedirectUri)) {
        session.setAttribute(REDIRECT_URI_KEY, postLogoutRedirectUri);
    }
    if (!Strings.isNullOrEmpty(state)) {
        session.setAttribute(STATE_KEY, state);
    }
    // parse the ID token hint to see if it's valid
    if (!Strings.isNullOrEmpty(idTokenHint)) {
        try {
            JWT idToken = JWTParser.parse(idTokenHint);
            if (validator.isValid(idToken)) {
                // we issued this ID token, figure out who it's for
                idTokenClaims = idToken.getJWTClaimsSet();
                String clientId = Iterables.getOnlyElement(idTokenClaims.getAudience());
                client = clientService.loadClientByClientId(clientId);
                // save a reference in the session for us to pick up later
                // session.setAttribute("endSession_idTokenHint_claims", idTokenClaims);
                session.setAttribute(CLIENT_KEY, client);
            }
        } catch (ParseException e) {
            // it's not a valid ID token, ignore it
            logger.debug("Invalid id token hint", e);
        } catch (InvalidClientException e) {
            // couldn't find the client, ignore it
            logger.debug("Invalid client", e);
        }
    }
    // are we logged in or not?
    if (auth == null || !request.isUserInRole("ROLE_USER")) {
        // we're not logged in anyway, process the final redirect bits if needed
        return processLogout(null, request, response, session, auth, m);
    } else {
        // we are logged in, need to prompt the user before we log out
        // see who the current user is
        UserInfo ui = userInfoService.getByUsername(auth.getName());
        if (idTokenClaims != null) {
            String subject = idTokenClaims.getSubject();
            // TODO: should we do anything different in these cases?
            if (!Strings.isNullOrEmpty(subject) && subject.equals(ui.getSub())) {
            // it's the same user
            } else {
            // it's not the same user
            }
        }
        m.addAttribute("client", client);
        m.addAttribute("idToken", idTokenClaims);
        // display the log out confirmation page
        return "logoutConfirmation";
    }
}
Also used : ClientDetailsEntity(org.mitre.oauth2.model.ClientDetailsEntity) JWTClaimsSet(com.nimbusds.jwt.JWTClaimsSet) JWT(com.nimbusds.jwt.JWT) InvalidClientException(org.springframework.security.oauth2.common.exceptions.InvalidClientException) UserInfo(org.mitre.openid.connect.model.UserInfo) ParseException(java.text.ParseException) RequestMapping(org.springframework.web.bind.annotation.RequestMapping)

Example 5 with InvalidClientException

use of org.maxkey.authz.oauth2.common.exceptions.InvalidClientException in project OpenID-Connect-Java-Spring-Server by mitreid-connect.

the class TestJWTBearerAuthenticationProvider method should_throw_UsernameNotFoundException_when_clientService_throws_InvalidClientException.

@Test
public void should_throw_UsernameNotFoundException_when_clientService_throws_InvalidClientException() {
    when(clientService.loadClientByClientId(CLIENT_ID)).thenThrow(new InvalidClientException("invalid client"));
    Throwable thrown = authenticateAndReturnThrownException();
    assertThat(thrown, instanceOf(UsernameNotFoundException.class));
    assertThat(thrown.getMessage(), is("Could not find client: " + CLIENT_ID));
}
Also used : UsernameNotFoundException(org.springframework.security.core.userdetails.UsernameNotFoundException) InvalidClientException(org.springframework.security.oauth2.common.exceptions.InvalidClientException) Test(org.junit.Test)

Aggregations

InvalidClientException (org.springframework.security.oauth2.common.exceptions.InvalidClientException)35 Test (org.junit.Test)11 Authentication (org.springframework.security.core.Authentication)11 RequestMapping (org.springframework.web.bind.annotation.RequestMapping)10 ClientDetailsEntity (org.mitre.oauth2.model.ClientDetailsEntity)9 OAuth2Authentication (org.springframework.security.oauth2.provider.OAuth2Authentication)7 OAuth2Exception (org.springframework.security.oauth2.common.exceptions.OAuth2Exception)6 RedirectMismatchException (org.springframework.security.oauth2.common.exceptions.RedirectMismatchException)6 Date (java.util.Date)5 InvalidRequestException (org.springframework.security.oauth2.common.exceptions.InvalidRequestException)5 ClientDetails (org.springframework.security.oauth2.provider.ClientDetails)5 HashMap (java.util.HashMap)4 HashSet (java.util.HashSet)4 InsufficientAuthenticationException (org.springframework.security.authentication.InsufficientAuthenticationException)4 UsernameNotFoundException (org.springframework.security.core.userdetails.UsernameNotFoundException)4 AuthorizationRequest (org.springframework.security.oauth2.provider.AuthorizationRequest)4 OAuth2Request (org.springframework.security.oauth2.provider.OAuth2Request)4 ModelAndView (org.springframework.web.servlet.ModelAndView)4 ObjectMapper (com.fasterxml.jackson.databind.ObjectMapper)3 JWT (com.nimbusds.jwt.JWT)3