use of oidc.exceptions.CodeVerifierMissingException in project OpenConext-oidcng by OpenConext.
the class TokenEndpoint method handleAuthorizationCodeGrant.
private ResponseEntity handleAuthorizationCodeGrant(AuthorizationCodeGrant authorizationCodeGrant, OpenIDClient client) {
String code = authorizationCodeGrant.getAuthorizationCode().getValue();
MDCContext.mdcContext("code", "code");
AuthorizationCode authorizationCode = concurrentAuthorizationCodeRepository.findByCodeNotAlreadyUsedAndMarkAsUsed(code);
if (authorizationCode == null) {
/*
* Now it become's tricky. Did we get an 'null' because the code was bogus or because it was already
* used? To both satisfy the - highly theoretical - risk of the audit race condition and the OIDC certification
* demand of deleting access_token issued with the re-used authorization code we need to query again.
*
* If they code was bogus this will result in a 404 exception by the authorizationCodeRepository#findByCode
* and if we find something then we know there was a re-use issue.
*/
AuthorizationCode byCode = authorizationCodeRepository.findByCode(code);
accessTokenRepository.deleteByAuthorizationCodeId(byCode.getId());
throw new TokenAlreadyUsedException("Authorization code already used");
}
if (!authorizationCode.getClientId().equals(client.getClientId())) {
throw new UnauthorizedException("Client is not authorized for the authorization code");
}
if (authorizationCodeGrant.getRedirectionURI() != null && !authorizationCodeGrant.getRedirectionURI().toString().equals(authorizationCode.getRedirectUri())) {
throw new RedirectMismatchException("Redirects do not match");
}
if (authorizationCode.isRedirectURIProvided() && authorizationCodeGrant.getRedirectionURI() == null) {
throw new RedirectMismatchException("Redirect URI is mandatory if specified in code request");
}
if (authorizationCode.isExpired(Clock.systemDefaultZone())) {
throw new UnauthorizedException("Authorization code expired");
}
CodeVerifier codeVerifier = authorizationCodeGrant.getCodeVerifier();
String codeChallenge = authorizationCode.getCodeChallenge();
if (codeVerifier != null) {
if (codeChallenge == null) {
throw new CodeVerifierMissingException("code_verifier present, but no code_challenge in the authorization_code");
}
CodeChallengeMethod codeChallengeMethod = CodeChallengeMethod.parse(authorizationCode.getCodeChallengeMethod());
CodeChallenge computed = CodeChallenge.compute(codeChallengeMethod, codeVerifier);
// Constant time comparison
if (!MessageDigest.isEqual(codeChallenge.getBytes(), computed.getValue().getBytes())) {
LOG.error(String.format("CodeVerifier %s with method %s does not match codeChallenge %s. Expected codeChallenge is %s", codeVerifier.getValue(), codeChallengeMethod, codeChallenge, computed.getValue()));
throw new CodeVerifierMissingException("code_verifier does not match code_challenge");
}
}
User user = userRepository.findUserBySub(authorizationCode.getSub());
MDCContext.mdcContext(user);
// User information is encrypted in access token
LOG.debug("Deleting user " + user.getSub());
userRepository.delete(user);
Map<String, Object> body = tokenEndpointResponse(Optional.of(user), client, authorizationCode.getScopes(), authorizationCode.getIdTokenClaims(), false, authorizationCode.getNonce(), Optional.of(authorizationCode.getAuthTime()), Optional.of(authorizationCode.getId()));
return new ResponseEntity<>(body, responseHttpHeaders, HttpStatus.OK);
}
use of oidc.exceptions.CodeVerifierMissingException in project OpenConext-oidcng by OpenConext.
the class TokenEndpoint method token.
@PostMapping(value = "oidc/token", consumes = { MediaType.APPLICATION_FORM_URLENCODED_VALUE })
public ResponseEntity token(HttpServletRequest request) throws IOException, ParseException, JOSEException, java.text.ParseException, CertificateException, BadJOSEException {
HTTPRequest httpRequest = ServletUtils.createHTTPRequest(request);
TokenRequest tokenRequest = TokenRequest.parse(httpRequest);
ClientAuthentication clientAuthentication = tokenRequest.getClientAuthentication();
if (clientAuthentication != null && !(clientAuthentication instanceof PlainClientSecret || clientAuthentication instanceof JWTAuthentication)) {
throw new IllegalArgumentException(String.format("Unsupported '%s' findByClientId authentication in token endpoint", clientAuthentication.getClass()));
}
AuthorizationGrant authorizationGrant = tokenRequest.getAuthorizationGrant();
if (clientAuthentication == null && authorizationGrant instanceof AuthorizationCodeGrant && ((AuthorizationCodeGrant) authorizationGrant).getCodeVerifier() == null) {
throw new CodeVerifierMissingException("code_verifier required without client authentication");
}
String clientId = clientAuthentication != null ? clientAuthentication.getClientID().getValue() : tokenRequest.getClientID().getValue();
OpenIDClient client = openIDClientRepository.findOptionalByClientId(clientId).orElseThrow(() -> new UnknownClientException(clientId));
if (clientAuthentication == null && !client.isPublicClient()) {
throw new UnauthorizedException("Non-public client requires authentication");
}
if (clientAuthentication != null) {
if (clientAuthentication instanceof PlainClientSecret && !secretsMatch((PlainClientSecret) clientAuthentication, client)) {
throw new UnauthorizedException("Invalid user / secret");
} else if (clientAuthentication instanceof JWTAuthentication && !verifySignature((JWTAuthentication) clientAuthentication, client, this.tokenEndpoint)) {
throw new UnauthorizedException("Invalid user / signature");
}
}
MDCContext.mdcContext("action", "Token", "rp", clientId, "grant", authorizationGrant.getType().getValue());
if (!client.getGrants().contains(authorizationGrant.getType().getValue())) {
throw new InvalidGrantException("Invalid grant: " + authorizationGrant.getType().getValue());
}
if (authorizationGrant instanceof AuthorizationCodeGrant) {
return handleAuthorizationCodeGrant((AuthorizationCodeGrant) authorizationGrant, client);
} else if (authorizationGrant instanceof ClientCredentialsGrant) {
return handleClientCredentialsGrant(client, tokenRequest);
} else if (authorizationGrant instanceof RefreshTokenGrant) {
return handleRefreshCodeGrant((RefreshTokenGrant) authorizationGrant, client);
}
throw new IllegalArgumentException("Not supported - yet - authorizationGrant " + authorizationGrant.getType().getValue());
}
Aggregations