Search in sources :

Example 1 with AuthorizationCode

use of oidc.model.AuthorizationCode in project OpenConext-oidcng by OpenConext.

the class AuthorizationEndpoint method createAndSaveAuthorizationCode.

private AuthorizationCode createAndSaveAuthorizationCode(AuthorizationRequest authorizationRequest, OpenIDClient client, User user) {
    URI redirectionURI = authorizationRequest.getRedirectionURI();
    Scope scope = authorizationRequest.getScope();
    List<String> scopes = scope != null ? scope.toStringList() : Collections.emptyList();
    // Optional code challenges for PKCE
    CodeChallenge codeChallenge = authorizationRequest.getCodeChallenge();
    String codeChallengeValue = codeChallenge != null ? codeChallenge.getValue() : null;
    CodeChallengeMethod codeChallengeMethod = authorizationRequest.getCodeChallengeMethod();
    String codeChallengeMethodValue = codeChallengeMethod != null ? codeChallengeMethod.getValue() : (codeChallengeValue != null ? CodeChallengeMethod.getDefault().getValue() : null);
    List<String> idTokenClaims = getClaims(authorizationRequest);
    String code = tokenGenerator.generateAuthorizationCode();
    Nonce nonce = authorizationRequest instanceof AuthenticationRequest ? AuthenticationRequest.class.cast(authorizationRequest).getNonce() : null;
    AuthorizationCode authorizationCode = new AuthorizationCode(code, user.getSub(), client.getClientId(), scopes, redirectionURI, codeChallengeValue, codeChallengeMethodValue, nonce != null ? nonce.getValue() : null, idTokenClaims, redirectionURI != null, tokenValidity(10 * 60));
    authorizationCodeRepository.insert(authorizationCode);
    return authorizationCode;
}
Also used : Nonce(com.nimbusds.openid.connect.sdk.Nonce) AuthorizationCode(oidc.model.AuthorizationCode) Scope(com.nimbusds.oauth2.sdk.Scope) CodeChallengeMethod(com.nimbusds.oauth2.sdk.pkce.CodeChallengeMethod) CodeChallenge(com.nimbusds.oauth2.sdk.pkce.CodeChallenge) AuthenticationRequest(com.nimbusds.openid.connect.sdk.AuthenticationRequest) ProvidedRedirectURI(oidc.model.ProvidedRedirectURI) URI(java.net.URI)

Example 2 with AuthorizationCode

use of oidc.model.AuthorizationCode in project OpenConext-oidcng by OpenConext.

the class AuthorizationEndpoint method authorizationEndpointResponse.

private Map<String, Object> authorizationEndpointResponse(User user, OpenIDClient client, AuthorizationRequest authorizationRequest, List<String> scopes, ResponseType responseType, State state) {
    Map<String, Object> result = new LinkedHashMap<>();
    EncryptedTokenValue encryptedAccessToken = tokenGenerator.generateAccessTokenWithEmbeddedUserInfo(user, client, scopes);
    if (responseType.contains(ResponseType.Value.TOKEN.getValue()) || !isOpenIDRequest(authorizationRequest)) {
        String unspecifiedUrnHash = KeyGenerator.oneWayHash(user.getUnspecifiedNameId(), this.salt);
        AccessToken accessToken = new AccessToken(encryptedAccessToken.getJwtId(), user.getSub(), client.getClientId(), scopes, encryptedAccessToken.getKeyId(), accessTokenValidity(client), false, null, unspecifiedUrnHash);
        accessTokenRepository.insert(accessToken);
        result.put("access_token", encryptedAccessToken.getValue());
        result.put("token_type", "Bearer");
    }
    if (responseType.contains(ResponseType.Value.CODE.getValue())) {
        AuthorizationCode authorizationCode = createAndSaveAuthorizationCode(authorizationRequest, client, user);
        result.put("code", authorizationCode.getCode());
    }
    if (responseType.contains(OIDCResponseTypeValue.ID_TOKEN.getValue()) && isOpenIDRequest(scopes) && isOpenIDRequest(authorizationRequest)) {
        AuthenticationRequest authenticationRequest = (AuthenticationRequest) authorizationRequest;
        List<String> claims = getClaims(authorizationRequest);
        TokenValue tokenValue = tokenGenerator.generateIDTokenForAuthorizationEndpoint(user, client, authenticationRequest.getNonce(), responseType, encryptedAccessToken.getValue(), claims, Optional.ofNullable((String) result.get("code")), state);
        result.put("id_token", tokenValue.getValue());
    }
    result.put("expires_in", client.getAccessTokenValidity());
    if (state != null) {
        result.put("state", state.getValue());
    }
    return result;
}
Also used : AuthorizationCode(oidc.model.AuthorizationCode) AccessToken(oidc.model.AccessToken) EncryptedTokenValue(oidc.model.EncryptedTokenValue) AuthenticationRequest(com.nimbusds.openid.connect.sdk.AuthenticationRequest) LinkedHashMap(java.util.LinkedHashMap) TokenValue(oidc.model.TokenValue) EncryptedTokenValue(oidc.model.EncryptedTokenValue)

Example 3 with AuthorizationCode

use of oidc.model.AuthorizationCode 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);
}
Also used : AuthorizationCode(oidc.model.AuthorizationCode) User(oidc.model.User) CodeChallengeMethod(com.nimbusds.oauth2.sdk.pkce.CodeChallengeMethod) CodeVerifierMissingException(oidc.exceptions.CodeVerifierMissingException) TokenAlreadyUsedException(oidc.exceptions.TokenAlreadyUsedException) CodeVerifier(com.nimbusds.oauth2.sdk.pkce.CodeVerifier) ResponseEntity(org.springframework.http.ResponseEntity) UnauthorizedException(oidc.exceptions.UnauthorizedException) RedirectMismatchException(oidc.exceptions.RedirectMismatchException) CodeChallenge(com.nimbusds.oauth2.sdk.pkce.CodeChallenge)

Example 4 with AuthorizationCode

use of oidc.model.AuthorizationCode in project OpenConext-oidcng by OpenConext.

the class ResourceCleanerTest method clean.

@Test
public void clean() throws URISyntaxException {
    Class[] classes = { User.class, UserConsent.class, AccessToken.class, RefreshToken.class, AuthorizationCode.class, AuthenticationRequest.class };
    Stream.of(classes).forEach(clazz -> mongoTemplate.remove(new Query(), clazz));
    Date expiresIn = Date.from(LocalDateTime.now().minusDays(1).atZone(ZoneId.systemDefault()).toInstant());
    Stream.of(accessToken("value", expiresIn), refreshToken(expiresIn), new AuthorizationCode("code", "sub", "clientId", emptyList(), new URI("http://redirectURI"), "codeChallenge", "codeChallengeMethod", "nonce", emptyList(), true, expiresIn), new User("nope", "unspecifiedNameId", "authenticatingAuthority", "clientId", Collections.emptyMap(), Collections.emptyList()), new AuthenticationRequest(UUID.randomUUID().toString(), expiresIn, "clientID", "http://localhost/authorize"), userConsent()).forEach(o -> mongoTemplate.insert(o));
    subject.clean();
    Stream.of(classes).forEach(clazz -> assertEquals(0, mongoTemplate.findAll(clazz).size()));
}
Also used : AuthorizationCode(oidc.model.AuthorizationCode) User(oidc.model.User) Query(org.springframework.data.mongodb.core.query.Query) AuthenticationRequest(oidc.model.AuthenticationRequest) URI(java.net.URI) Date(java.util.Date) AbstractIntegrationTest(oidc.AbstractIntegrationTest) Test(org.junit.Test) SpringBootTest(org.springframework.boot.test.context.SpringBootTest)

Example 5 with AuthorizationCode

use of oidc.model.AuthorizationCode in project OpenConext-oidcng by OpenConext.

the class AuthorizationCodeRepositoryTest method findSub.

@Test
public void findSub() {
    IntStream.range(0, 3).forEach(i -> {
        try {
            subject.insert(new AuthorizationCode(UUID.randomUUID().toString(), "sub" + i, "clientId", emptyList(), new URI("http://redirectURI"), "codeChallenge", "codeChallengeMethod", "nonce", emptyList(), true, new Date()));
        } catch (URISyntaxException e) {
            throw new RuntimeException(e);
        }
    });
    List<String> subs = subject.findSub().stream().map(AuthorizationCode::getSub).collect(Collectors.toList());
    assertEquals(3, subs.size());
}
Also used : AuthorizationCode(oidc.model.AuthorizationCode) URISyntaxException(java.net.URISyntaxException) URI(java.net.URI) Date(java.util.Date) Test(org.junit.Test) AbstractIntegrationTest(oidc.AbstractIntegrationTest)

Aggregations

AuthorizationCode (oidc.model.AuthorizationCode)10 URI (java.net.URI)6 AbstractIntegrationTest (oidc.AbstractIntegrationTest)6 Test (org.junit.Test)6 Date (java.util.Date)5 User (oidc.model.User)4 AuthenticationRequest (com.nimbusds.openid.connect.sdk.AuthenticationRequest)3 Scope (com.nimbusds.oauth2.sdk.Scope)2 CodeChallenge (com.nimbusds.oauth2.sdk.pkce.CodeChallenge)2 CodeChallengeMethod (com.nimbusds.oauth2.sdk.pkce.CodeChallengeMethod)2 LinkedHashMap (java.util.LinkedHashMap)2 JWTClaimsSet (com.nimbusds.jwt.JWTClaimsSet)1 AuthorizationRequest (com.nimbusds.oauth2.sdk.AuthorizationRequest)1 ResponseMode (com.nimbusds.oauth2.sdk.ResponseMode)1 ResponseType (com.nimbusds.oauth2.sdk.ResponseType)1 State (com.nimbusds.oauth2.sdk.id.State)1 CodeVerifier (com.nimbusds.oauth2.sdk.pkce.CodeVerifier)1 Nonce (com.nimbusds.openid.connect.sdk.Nonce)1 Prompt (com.nimbusds.openid.connect.sdk.Prompt)1 Response (io.restassured.response.Response)1