Search in sources :

Example 1 with OpenIDClient

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

the class AuthorizationEndpoint method doConsent.

private ModelAndView doConsent(MultiValueMap<String, String> parameters, OpenIDClient client, Set<String> scopes, List<OpenIDClient> resourceServers) {
    Map<String, Object> body = new HashMap<>();
    body.put("parameters", parameters.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().get(0))));
    body.put("client", client);
    body.put("resourceServers", resourceServers.stream().filter(rs -> StringUtils.hasText(rs.getLogoUrl())).collect(toList()));
    body.put("scopes", resourceServers.stream().map(OpenIDClient::getScopes).flatMap(List::stream).filter(scope -> scopes.contains(scope.getName().toLowerCase())).collect(Collectors.toSet()));
    Locale locale = LocaleContextHolder.getLocale();
    body.put("lang", locale.getLanguage());
    body.put("environment", environment);
    return new ModelAndView("consent", body);
}
Also used : Locale(java.util.Locale) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) OpenIDClient(oidc.model.OpenIDClient) ModelAndView(org.springframework.web.servlet.ModelAndView)

Example 2 with OpenIDClient

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

the class AuthorizationEndpoint method validateRedirectionURI.

public static ProvidedRedirectURI validateRedirectionURI(URI redirectionURI, OpenIDClient client) throws UnsupportedEncodingException {
    List<String> registeredRedirectUrls = client.getRedirectUrls();
    if (registeredRedirectUrls == null) {
        throw new IllegalArgumentException(String.format("Client %s must have at least one redirectURI configured to use the Authorization flow", client.getClientId()));
    }
    if (redirectionURI == null) {
        return registeredRedirectUrls.stream().findFirst().map(s -> new ProvidedRedirectURI(s, false)).orElseThrow(() -> new IllegalArgumentException(String.format("Client %s must have at least one redirectURI configured to use the Authorization flow", client.getClientId())));
    }
    String redirectURI = URLDecoder.decode(redirectionURI.toString(), "UTF-8");
    Optional<ProvidedRedirectURI> optionalProvidedRedirectURI = registeredRedirectUrls.stream().map(url -> new ProvidedRedirectURI(url, true)).filter(providedRedirectURI -> providedRedirectURI.equalsIgnorePort(redirectURI)).findFirst();
    if (!optionalProvidedRedirectURI.isPresent()) {
        throw new RedirectMismatchException(String.format("Client %s with registered redirect URI's %s requested authorization with redirectURI %s", client.getClientId(), registeredRedirectUrls, redirectURI));
    }
    return optionalProvidedRedirectURI.get();
}
Also used : LocaleContextHolder(org.springframework.context.i18n.LocaleContextHolder) UriComponentsBuilder(org.springframework.web.util.UriComponentsBuilder) AuthorizationCodeRepository(oidc.repository.AuthorizationCodeRepository) RequestParam(org.springframework.web.bind.annotation.RequestParam) Arrays(java.util.Arrays) Prompt(com.nimbusds.openid.connect.sdk.Prompt) ProvidedRedirectURI(oidc.model.ProvidedRedirectURI) URLDecoder(java.net.URLDecoder) URISyntaxException(java.net.URISyntaxException) JOSEException(com.nimbusds.jose.JOSEException) User(oidc.model.User) OidcSamlAuthentication(oidc.user.OidcSamlAuthentication) Autowired(org.springframework.beans.factory.annotation.Autowired) ResponseMode(com.nimbusds.oauth2.sdk.ResponseMode) ResponseType(com.nimbusds.oauth2.sdk.ResponseType) RedirectView(org.springframework.web.servlet.view.RedirectView) Locale(java.util.Locale) Map(java.util.Map) UnsupportedPromptValueException(oidc.exceptions.UnsupportedPromptValueException) URI(java.net.URI) SecurityContextHolder(org.springframework.security.core.context.SecurityContextHolder) Collectors.toSet(java.util.stream.Collectors.toSet) HttpSession(javax.servlet.http.HttpSession) PostMapping(org.springframework.web.bind.annotation.PostMapping) MediaType(org.springframework.http.MediaType) Set(java.util.Set) Collectors(java.util.stream.Collectors) ModelAndView(org.springframework.web.servlet.ModelAndView) List(java.util.List) AuthenticationRequest(com.nimbusds.openid.connect.sdk.AuthenticationRequest) OIDCResponseTypeValue(com.nimbusds.openid.connect.sdk.OIDCResponseTypeValue) CollectionUtils(org.springframework.util.CollectionUtils) InvalidScopeException(oidc.exceptions.InvalidScopeException) OpenIDClientRepository(oidc.repository.OpenIDClientRepository) Optional(java.util.Optional) TokenGenerator(oidc.secure.TokenGenerator) LogFactory(org.apache.commons.logging.LogFactory) Authentication(org.springframework.security.core.Authentication) Nonce(com.nimbusds.openid.connect.sdk.Nonce) UnsupportedEncodingException(java.io.UnsupportedEncodingException) CodeChallengeMethod(com.nimbusds.oauth2.sdk.pkce.CodeChallengeMethod) AuthorizationCode(oidc.model.AuthorizationCode) GrantType(com.nimbusds.oauth2.sdk.GrantType) RedirectMismatchException(oidc.exceptions.RedirectMismatchException) HashMap(java.util.HashMap) UnknownClientException(oidc.exceptions.UnknownClientException) Controller(org.springframework.stereotype.Controller) ArrayList(java.util.ArrayList) Value(org.springframework.beans.factory.annotation.Value) LinkedHashMap(java.util.LinkedHashMap) CodeChallenge(com.nimbusds.oauth2.sdk.pkce.CodeChallenge) KeyGenerator(oidc.crypto.KeyGenerator) HttpServletRequest(javax.servlet.http.HttpServletRequest) TokenValue(oidc.model.TokenValue) GetMapping(org.springframework.web.bind.annotation.GetMapping) ParseException(com.nimbusds.oauth2.sdk.ParseException) OpenIDClient(oidc.model.OpenIDClient) MDCContext(oidc.log.MDCContext) JWTRequest(oidc.secure.JWTRequest) Scope(com.nimbusds.oauth2.sdk.Scope) State(com.nimbusds.oauth2.sdk.id.State) MultiValueMap(org.springframework.util.MultiValueMap) InvalidGrantException(oidc.exceptions.InvalidGrantException) IOException(java.io.IOException) CertificateException(java.security.cert.CertificateException) AccessTokenRepository(oidc.repository.AccessTokenRepository) EncryptedTokenValue(oidc.model.EncryptedTokenValue) AuthorizationRequest(com.nimbusds.oauth2.sdk.AuthorizationRequest) UserRepository(oidc.repository.UserRepository) AccessToken(oidc.model.AccessToken) Collectors.toList(java.util.stream.Collectors.toList) BadJOSEException(com.nimbusds.jose.proc.BadJOSEException) Log(org.apache.commons.logging.Log) Collections(java.util.Collections) LinkedMultiValueMap(org.springframework.util.LinkedMultiValueMap) StringUtils(org.springframework.util.StringUtils) ProvidedRedirectURI(oidc.model.ProvidedRedirectURI) RedirectMismatchException(oidc.exceptions.RedirectMismatchException)

Example 3 with OpenIDClient

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

the class IntrospectEndpoint method introspect.

@PostMapping(value = { "oidc/introspect" }, consumes = { MediaType.APPLICATION_FORM_URLENCODED_VALUE })
public ResponseEntity<Map<String, Object>> introspect(HttpServletRequest request) throws ParseException, IOException, java.text.ParseException {
    HTTPRequest httpRequest = ServletUtils.createHTTPRequest(request);
    TokenIntrospectionRequest tokenIntrospectionRequest = TokenIntrospectionRequest.parse(httpRequest);
    ClientAuthentication clientAuthentication = tokenIntrospectionRequest.getClientAuthentication();
    String accessTokenValue = tokenIntrospectionRequest.getToken().getValue();
    // https://tools.ietf.org/html/rfc7662 is vague about the authorization requirements, but we enforce basic auth
    if (!(clientAuthentication instanceof PlainClientSecret)) {
        LOG.warn("No authentication present");
        throw new UnauthorizedException("Invalid user / secret");
    }
    String clientId = clientAuthentication.getClientID().getValue();
    OpenIDClient resourceServer = openIDClientRepository.findOptionalByClientId(clientId).orElseThrow(() -> new UnknownClientException(clientId));
    MDCContext.mdcContext("action", "Introspect", "rp", resourceServer.getClientId(), "accessTokenValue", accessTokenValue);
    if (!secretsMatch((PlainClientSecret) clientAuthentication, resourceServer)) {
        LOG.warn("Secret does not match for RS " + resourceServer.getClientId());
        throw new UnauthorizedException("Invalid user / secret");
    }
    if (!resourceServer.isResourceServer()) {
        LOG.warn("RS required for not configured for RP " + resourceServer.getClientId());
        throw new UnauthorizedException("Requires ResourceServer");
    }
    Optional<SignedJWT> optionalSignedJWT = tokenGenerator.parseAndValidateSignedJWT(accessTokenValue);
    if (!optionalSignedJWT.isPresent()) {
        LOG.warn("Invalid access_token " + accessTokenValue);
        return ResponseEntity.ok(Collections.singletonMap("active", false));
    }
    SignedJWT signedJWT = optionalSignedJWT.get();
    String jwtId = signedJWT.getJWTClaimsSet().getJWTID();
    Optional<AccessToken> optionalAccessToken = accessTokenRepository.findByJwtId(jwtId);
    if (!optionalAccessToken.isPresent()) {
        LOG.warn("No access_token found " + accessTokenValue);
        return ResponseEntity.ok(Collections.singletonMap("active", false));
    }
    AccessToken accessToken = optionalAccessToken.get();
    if (accessToken.isExpired(Clock.systemDefaultZone())) {
        LOG.warn("Access token is expired " + accessTokenValue);
        return ResponseEntity.ok(Collections.singletonMap("active", false));
    }
    List<String> scopes = accessToken.getScopes();
    Map<String, Object> result = new TreeMap<>();
    boolean isUserAccessToken = !accessToken.isClientCredentials();
    if (isUserAccessToken) {
        OpenIDClient openIDClient = openIDClientRepository.findOptionalByClientId(accessToken.getClientId()).orElseThrow(() -> new UnknownClientException(accessToken.getClientId()));
        if (!openIDClient.getClientId().equals(resourceServer.getClientId()) && !openIDClient.getAllowedResourceServers().contains(resourceServer.getClientId())) {
            throw new UnauthorizedException(String.format("RP %s is not allowed to use the API of resource server %s. Allowed resource servers are %s", accessToken.getClientId(), resourceServer.getClientId(), openIDClient.getAllowedResourceServers()));
        }
        User user = tokenGenerator.decryptAccessTokenWithEmbeddedUserInfo(signedJWT);
        result.put("updated_at", user.getUpdatedAt());
        if (resourceServer.isIncludeUnspecifiedNameID()) {
            result.put("unspecified_id", user.getUnspecifiedNameId());
        }
        result.put("authenticating_authority", user.getAuthenticatingAuthority());
        result.put("sub", user.getSub());
        result.putAll(user.getAttributes());
        List<String> acrClaims = user.getAcrClaims();
        if (!CollectionUtils.isEmpty(acrClaims)) {
            result.put("acr", String.join(" ", acrClaims));
        }
        boolean validPseudonymisation = validPseudonymisation(result, resourceServer, openIDClient);
        if (!validPseudonymisation && enforceEduidResourceServerLinkedAccount) {
            LOG.warn(String.format("Pseudonymisation failed. No eduperson_principal_name for RS %s", resourceServer.getClientId()));
            return ResponseEntity.ok(Collections.singletonMap("active", false));
        }
    }
    // The following claims can not be overridden by the
    result.put("active", true);
    result.put("scope", String.join(" ", scopes));
    result.put("client_id", accessToken.getClientId());
    result.put("exp", accessToken.getExpiresIn().getTime() / 1000L);
    result.put("sub", accessToken.getSub());
    result.put("iss", issuer);
    result.put("token_type", "Bearer");
    LOG.debug(String.format("Returning introspect active %s for RS %s", true, resourceServer.getClientId()));
    return ResponseEntity.ok(result);
}
Also used : HTTPRequest(com.nimbusds.oauth2.sdk.http.HTTPRequest) User(oidc.model.User) UnknownClientException(oidc.exceptions.UnknownClientException) OpenIDClient(oidc.model.OpenIDClient) TokenIntrospectionRequest(com.nimbusds.oauth2.sdk.TokenIntrospectionRequest) SignedJWT(com.nimbusds.jwt.SignedJWT) TreeMap(java.util.TreeMap) PlainClientSecret(com.nimbusds.oauth2.sdk.auth.PlainClientSecret) AccessToken(oidc.model.AccessToken) UnauthorizedException(oidc.exceptions.UnauthorizedException) ClientAuthentication(com.nimbusds.oauth2.sdk.auth.ClientAuthentication) PostMapping(org.springframework.web.bind.annotation.PostMapping)

Example 4 with OpenIDClient

use of oidc.model.OpenIDClient 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());
}
Also used : HTTPRequest(com.nimbusds.oauth2.sdk.http.HTTPRequest) JWTAuthentication(com.nimbusds.oauth2.sdk.auth.JWTAuthentication) UnknownClientException(oidc.exceptions.UnknownClientException) OpenIDClient(oidc.model.OpenIDClient) RefreshTokenGrant(com.nimbusds.oauth2.sdk.RefreshTokenGrant) CodeVerifierMissingException(oidc.exceptions.CodeVerifierMissingException) InvalidGrantException(oidc.exceptions.InvalidGrantException) AuthorizationCodeGrant(com.nimbusds.oauth2.sdk.AuthorizationCodeGrant) PlainClientSecret(com.nimbusds.oauth2.sdk.auth.PlainClientSecret) ClientCredentialsGrant(com.nimbusds.oauth2.sdk.ClientCredentialsGrant) TokenRequest(com.nimbusds.oauth2.sdk.TokenRequest) UnauthorizedException(oidc.exceptions.UnauthorizedException) ClientAuthentication(com.nimbusds.oauth2.sdk.auth.ClientAuthentication) AuthorizationGrant(com.nimbusds.oauth2.sdk.AuthorizationGrant) PostMapping(org.springframework.web.bind.annotation.PostMapping)

Example 5 with OpenIDClient

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

the class TokenController method convertToken.

private Map<String, Object> convertToken(AccessToken token) {
    Map<String, Object> result = new HashMap<>();
    result.put("id", token.getId());
    Optional<OpenIDClient> optionalClient = openIDClientRepository.findOptionalByClientId(token.getClientId());
    if (!optionalClient.isPresent()) {
        return result;
    }
    OpenIDClient openIDClient = optionalClient.get();
    result.put("clientId", openIDClient.getClientId());
    result.put("clientName", openIDClient.getName());
    List<OpenIDClient> resourceServers = openIDClient.getAllowedResourceServers().stream().map(rs -> openIDClientRepository.findOptionalByClientId(rs)).filter(Optional::isPresent).map(Optional::get).collect(toList());
    result.put("audiences", resourceServers.stream().map(OpenIDClient::getName));
    result.put("createdAt", token.getCreatedAt());
    result.put("expiresIn", token.getExpiresIn());
    result.put("type", token instanceof RefreshToken ? TokenType.REFRESH : TokenType.ACCESS);
    Map<String, Scope> allScopes = resourceServers.stream().map(OpenIDClient::getScopes).flatMap(List::stream).filter(distinctByKey(Scope::getName)).collect(toMap(Scope::getName, s -> s));
    List<Scope> scopes = token.getScopes().stream().filter(name -> !name.equalsIgnoreCase("openid")).map(allScopes::get).filter(Objects::nonNull).collect(toList());
    result.put("scopes", scopes);
    return result;
}
Also used : TokenType(oidc.model.TokenType) RequestParam(org.springframework.web.bind.annotation.RequestParam) java.util(java.util) URLDecoder(java.net.URLDecoder) PreAuthorize(org.springframework.security.access.prepost.PreAuthorize) RefreshTokenRepository(oidc.repository.RefreshTokenRepository) Function(java.util.function.Function) Value(org.springframework.beans.factory.annotation.Value) RequestBody(org.springframework.web.bind.annotation.RequestBody) KeyGenerator(oidc.crypto.KeyGenerator) PutMapping(org.springframework.web.bind.annotation.PutMapping) Charset(java.nio.charset.Charset) Collectors.toMap(java.util.stream.Collectors.toMap) GetMapping(org.springframework.web.bind.annotation.GetMapping) OpenIDClient(oidc.model.OpenIDClient) TokenRepresentation(oidc.model.TokenRepresentation) Predicate(java.util.function.Predicate) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) AccessTokenRepository(oidc.repository.AccessTokenRepository) RestController(org.springframework.web.bind.annotation.RestController) Collectors(java.util.stream.Collectors) HttpStatus(org.springframework.http.HttpStatus) AccessToken(oidc.model.AccessToken) Collectors.toList(java.util.stream.Collectors.toList) Stream(java.util.stream.Stream) OpenIDClientRepository(oidc.repository.OpenIDClientRepository) Scope(oidc.model.Scope) Log(org.apache.commons.logging.Log) ResponseEntity(org.springframework.http.ResponseEntity) LogFactory(org.apache.commons.logging.LogFactory) Authentication(org.springframework.security.core.Authentication) UnsupportedEncodingException(java.io.UnsupportedEncodingException) RefreshToken(oidc.model.RefreshToken) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) OpenIDClient(oidc.model.OpenIDClient) RefreshToken(oidc.model.RefreshToken) Scope(oidc.model.Scope) Collectors.toList(java.util.stream.Collectors.toList)

Aggregations

OpenIDClient (oidc.model.OpenIDClient)40 Test (org.junit.Test)22 AbstractIntegrationTest (oidc.AbstractIntegrationTest)12 SignedJWT (com.nimbusds.jwt.SignedJWT)9 HashMap (java.util.HashMap)9 Map (java.util.Map)9 UnknownClientException (oidc.exceptions.UnknownClientException)8 User (oidc.model.User)8 AuthorizationRequest (com.nimbusds.oauth2.sdk.AuthorizationRequest)6 Scope (com.nimbusds.oauth2.sdk.Scope)6 URI (java.net.URI)6 HttpServletRequest (javax.servlet.http.HttpServletRequest)6 OpenIDClientRepository (oidc.repository.OpenIDClientRepository)6 AuthenticationRequest (com.nimbusds.openid.connect.sdk.AuthenticationRequest)5 Collectors (java.util.stream.Collectors)5 ClientID (com.nimbusds.oauth2.sdk.id.ClientID)4 UnsupportedEncodingException (java.io.UnsupportedEncodingException)4 LinkedHashMap (java.util.LinkedHashMap)4 HttpSession (javax.servlet.http.HttpSession)4 EncryptedTokenValue (oidc.model.EncryptedTokenValue)4