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;
}
}
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");
}
}
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;
}
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";
}
}
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));
}
Aggregations