Search in sources :

Example 71 with ClientModel

use of org.keycloak.models.ClientModel in project keycloak by keycloak.

the class TokenEndpoint method permissionGrant.

public Response permissionGrant() {
    event.detail(Details.AUTH_METHOD, "oauth_credentials");
    String accessTokenString = null;
    String authorizationHeader = headers.getRequestHeaders().getFirst(HttpHeaders.AUTHORIZATION);
    if (authorizationHeader != null && authorizationHeader.toLowerCase().startsWith("bearer")) {
        accessTokenString = new AppAuthManager().extractAuthorizationHeaderToken(headers);
    }
    // public clients don't have secret and should be able to obtain a RPT by providing an access token previously issued by the server
    if (accessTokenString != null) {
        AccessToken accessToken = Tokens.getAccessToken(session);
        if (accessToken == null) {
            try {
                // In case the access token is invalid because it's expired or the user is disabled, identify the client
                // from the access token anyway in order to set correct CORS headers.
                AccessToken invalidToken = new JWSInput(accessTokenString).readJsonContent(AccessToken.class);
                ClientModel client = realm.getClientByClientId(invalidToken.getIssuedFor());
                cors.allowedOrigins(session, client);
                event.client(client);
            } catch (JWSInputException ignore) {
            }
            event.error(Errors.INVALID_TOKEN);
            throw new CorsErrorResponseException(cors, OAuthErrorException.INVALID_GRANT, "Invalid bearer token", Status.UNAUTHORIZED);
        }
        ClientModel client = realm.getClientByClientId(accessToken.getIssuedFor());
        session.getContext().setClient(client);
        cors.allowedOrigins(session, client);
        event.client(client);
    }
    String claimToken = null;
    // claim_token is optional, if provided we just grab it from the request
    if (formParams.containsKey("claim_token")) {
        claimToken = formParams.get("claim_token").get(0);
    }
    String claimTokenFormat = formParams.getFirst("claim_token_format");
    if (claimToken != null && claimTokenFormat == null) {
        claimTokenFormat = AuthorizationTokenService.CLAIM_TOKEN_FORMAT_ID_TOKEN;
    }
    String subjectToken = formParams.getFirst("subject_token");
    if (accessTokenString == null) {
        // in case no bearer token is provided, we force client authentication
        checkClient();
        // if a claim token is provided, we check if the format is a OpenID Connect IDToken and assume the token represents the identity asking for permissions
        if (AuthorizationTokenService.CLAIM_TOKEN_FORMAT_ID_TOKEN.equalsIgnoreCase(claimTokenFormat)) {
            accessTokenString = claimToken;
        } else if (subjectToken != null) {
            accessTokenString = subjectToken;
        } else {
            // Clients need to authenticate in order to obtain a RPT from the server.
            // In order to support cases where the client is obtaining permissions on its on behalf, we issue a temporary access token
            accessTokenString = AccessTokenResponse.class.cast(clientCredentialsGrant().getEntity()).getToken();
        }
    }
    AuthorizationTokenService.KeycloakAuthorizationRequest authorizationRequest = new AuthorizationTokenService.KeycloakAuthorizationRequest(session.getProvider(AuthorizationProvider.class), tokenManager, event, this.request, cors, clientConnection);
    authorizationRequest.setTicket(formParams.getFirst("ticket"));
    authorizationRequest.setClaimToken(claimToken);
    authorizationRequest.setClaimTokenFormat(claimTokenFormat);
    authorizationRequest.setPct(formParams.getFirst("pct"));
    String rpt = formParams.getFirst("rpt");
    if (rpt != null) {
        AccessToken accessToken = session.tokens().decode(rpt, AccessToken.class);
        if (accessToken == null) {
            event.error(Errors.INVALID_REQUEST);
            throw new CorsErrorResponseException(cors, "invalid_rpt", "RPT signature is invalid", Status.FORBIDDEN);
        }
        authorizationRequest.setRpt(accessToken);
    }
    authorizationRequest.setScope(formParams.getFirst("scope"));
    String audienceParam = formParams.getFirst("audience");
    authorizationRequest.setAudience(audienceParam);
    authorizationRequest.setSubjectToken(accessTokenString);
    event.detail(Details.AUDIENCE, audienceParam);
    String submitRequest = formParams.getFirst("submit_request");
    authorizationRequest.setSubmitRequest(submitRequest == null ? true : Boolean.valueOf(submitRequest));
    // permissions have a format like RESOURCE#SCOPE1,SCOPE2
    List<String> permissions = formParams.get("permission");
    if (permissions != null) {
        event.detail(Details.PERMISSION, String.join("|", permissions));
        for (String permission : permissions) {
            String[] parts = permission.split("#");
            String resource = parts[0];
            if (parts.length == 1) {
                authorizationRequest.addPermission(resource);
            } else {
                String[] scopes = parts[1].split(",");
                authorizationRequest.addPermission(parts[0], scopes);
            }
        }
    }
    Metadata metadata = new Metadata();
    String responseIncludeResourceName = formParams.getFirst("response_include_resource_name");
    if (responseIncludeResourceName != null) {
        metadata.setIncludeResourceName(Boolean.parseBoolean(responseIncludeResourceName));
    }
    String responsePermissionsLimit = formParams.getFirst("response_permissions_limit");
    if (responsePermissionsLimit != null) {
        metadata.setLimit(Integer.parseInt(responsePermissionsLimit));
    }
    metadata.setResponseMode(formParams.getFirst("response_mode"));
    authorizationRequest.setMetadata(metadata);
    Response authorizationResponse = AuthorizationTokenService.instance().authorize(authorizationRequest);
    event.success();
    return authorizationResponse;
}
Also used : AuthorizationProvider(org.keycloak.authorization.AuthorizationProvider) Metadata(org.keycloak.representations.idm.authorization.AuthorizationRequest.Metadata) JWSInputException(org.keycloak.jose.jws.JWSInputException) JWSInput(org.keycloak.jose.jws.JWSInput) AccessTokenResponse(org.keycloak.representations.AccessTokenResponse) Response(javax.ws.rs.core.Response) HttpResponse(org.jboss.resteasy.spi.HttpResponse) ClientModel(org.keycloak.models.ClientModel) AuthorizationTokenService(org.keycloak.authorization.authorization.AuthorizationTokenService) AccessToken(org.keycloak.representations.AccessToken) CorsErrorResponseException(org.keycloak.services.CorsErrorResponseException) AccessTokenResponse(org.keycloak.representations.AccessTokenResponse) AppAuthManager(org.keycloak.services.managers.AppAuthManager)

Example 72 with ClientModel

use of org.keycloak.models.ClientModel in project keycloak by keycloak.

the class TokenManager method validateTokenReuseForIntrospection.

private boolean validateTokenReuseForIntrospection(KeycloakSession session, RealmModel realm, AccessToken token) {
    UserSessionModel userSession = null;
    if (token.getType().equals(TokenUtil.TOKEN_TYPE_REFRESH)) {
        userSession = session.sessions().getUserSession(realm, token.getSessionState());
    } else {
        UserSessionManager sessionManager = new UserSessionManager(session);
        userSession = sessionManager.findOfflineUserSession(realm, token.getSessionState());
    }
    ClientModel client = realm.getClientByClientId(token.getIssuedFor());
    AuthenticatedClientSessionModel clientSession = userSession.getAuthenticatedClientSessionByClient(client.getId());
    try {
        validateTokenReuse(session, realm, token, clientSession, false);
        return true;
    } catch (OAuthErrorException e) {
        return false;
    }
}
Also used : UserSessionManager(org.keycloak.services.managers.UserSessionManager) ClientModel(org.keycloak.models.ClientModel) UserSessionModel(org.keycloak.models.UserSessionModel) OAuthErrorException(org.keycloak.OAuthErrorException) AuthenticatedClientSessionModel(org.keycloak.models.AuthenticatedClientSessionModel)

Example 73 with ClientModel

use of org.keycloak.models.ClientModel in project keycloak by keycloak.

the class TokenManager method validateToken.

public TokenValidation validateToken(KeycloakSession session, UriInfo uriInfo, ClientConnection connection, RealmModel realm, RefreshToken oldToken, HttpHeaders headers) throws OAuthErrorException {
    UserSessionModel userSession = null;
    boolean offline = TokenUtil.TOKEN_TYPE_OFFLINE.equals(oldToken.getType());
    if (offline) {
        UserSessionManager sessionManager = new UserSessionManager(session);
        userSession = sessionManager.findOfflineUserSession(realm, oldToken.getSessionState());
        if (userSession != null) {
            // Revoke timeouted offline userSession
            if (!AuthenticationManager.isOfflineSessionValid(realm, userSession)) {
                sessionManager.revokeOfflineUserSession(userSession);
                throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Offline session not active", "Offline session not active");
            }
        } else {
            throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Offline user session not found", "Offline user session not found");
        }
    } else {
        // Find userSession regularly for online tokens
        userSession = session.sessions().getUserSession(realm, oldToken.getSessionState());
        if (!AuthenticationManager.isSessionValid(realm, userSession)) {
            AuthenticationManager.backchannelLogout(session, realm, userSession, uriInfo, connection, headers, true);
            throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Session not active", "Session not active");
        }
    }
    UserModel user = userSession.getUser();
    if (user == null) {
        throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Invalid refresh token", "Unknown user");
    }
    if (!user.isEnabled()) {
        throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "User disabled", "User disabled");
    }
    if (oldToken.isIssuedBeforeSessionStart(userSession.getStarted())) {
        logger.debug("Refresh toked issued before the user session started");
        throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Refresh toked issued before the user session started");
    }
    ClientModel client = session.getContext().getClient();
    AuthenticatedClientSessionModel clientSession = userSession.getAuthenticatedClientSessionByClient(client.getId());
    // Can theoretically happen in cross-dc environment. Try to see if userSession with our client is available in remoteCache
    if (clientSession == null) {
        userSession = new UserSessionCrossDCManager(session).getUserSessionWithClient(realm, userSession.getId(), offline, client.getId());
        if (userSession != null) {
            clientSession = userSession.getAuthenticatedClientSessionByClient(client.getId());
        } else {
            throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Session doesn't have required client", "Session doesn't have required client");
        }
    }
    if (oldToken.isIssuedBeforeSessionStart(clientSession.getStarted())) {
        logger.debug("Refresh toked issued before the client session started");
        throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Refresh toked issued before the client session started");
    }
    if (!client.getClientId().equals(oldToken.getIssuedFor())) {
        throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Unmatching clients", "Unmatching clients");
    }
    try {
        TokenVerifier.createWithoutSignature(oldToken).withChecks(NotBeforeCheck.forModel(client), NotBeforeCheck.forModel(session, realm, user)).verify();
    } catch (VerificationException e) {
        throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Stale token");
    }
    // Setup clientScopes from refresh token to the context
    String oldTokenScope = oldToken.getScope();
    // Case when offline token is migrated from previous version
    if (oldTokenScope == null && userSession.isOffline()) {
        logger.debugf("Migrating offline token of user '%s' for client '%s' of realm '%s'", user.getUsername(), client.getClientId(), realm.getName());
        MigrationUtils.migrateOldOfflineToken(session, realm, client, user);
        oldTokenScope = OAuth2Constants.OFFLINE_ACCESS;
    }
    ClientSessionContext clientSessionCtx = DefaultClientSessionContext.fromClientSessionAndScopeParameter(clientSession, oldTokenScope, session);
    // Check user didn't revoke granted consent
    if (!verifyConsentStillAvailable(session, user, client, clientSessionCtx.getClientScopesStream())) {
        throw new OAuthErrorException(OAuthErrorException.INVALID_SCOPE, "Client no longer has requested consent from user");
    }
    clientSessionCtx.setAttribute(OIDCLoginProtocol.NONCE_PARAM, oldToken.getNonce());
    // recreate token.
    AccessToken newToken = createClientAccessToken(session, realm, client, user, userSession, clientSessionCtx);
    return new TokenValidation(user, userSession, clientSessionCtx, newToken);
}
Also used : UserSessionModel(org.keycloak.models.UserSessionModel) OAuthErrorException(org.keycloak.OAuthErrorException) AuthenticatedClientSessionModel(org.keycloak.models.AuthenticatedClientSessionModel) UserSessionCrossDCManager(org.keycloak.services.managers.UserSessionCrossDCManager) UserSessionManager(org.keycloak.services.managers.UserSessionManager) UserModel(org.keycloak.models.UserModel) ClientModel(org.keycloak.models.ClientModel) DefaultClientSessionContext(org.keycloak.services.util.DefaultClientSessionContext) ClientSessionContext(org.keycloak.models.ClientSessionContext) AccessToken(org.keycloak.representations.AccessToken) VerificationException(org.keycloak.common.VerificationException)

Example 74 with ClientModel

use of org.keycloak.models.ClientModel in project keycloak by keycloak.

the class OIDCLoginProtocol method frontchannelLogout.

@Override
public Response frontchannelLogout(UserSessionModel userSession, AuthenticatedClientSessionModel clientSession) {
    if (clientSession != null) {
        ClientModel client = clientSession.getClient();
        if (OIDCAdvancedConfigWrapper.fromClientModel(client).isFrontChannelLogoutEnabled()) {
            FrontChannelLogoutHandler logoutInfo = FrontChannelLogoutHandler.currentOrCreate(session, clientSession);
            logoutInfo.addClient(client);
        }
        clientSession.setAction(AuthenticationSessionModel.Action.LOGGED_OUT.name());
    }
    return null;
}
Also used : ClientModel(org.keycloak.models.ClientModel)

Example 75 with ClientModel

use of org.keycloak.models.ClientModel in project keycloak by keycloak.

the class DockerAuthV2Protocol method authenticated.

@Override
public Response authenticated(final AuthenticationSessionModel authSession, final UserSessionModel userSession, final ClientSessionContext clientSessionCtx) {
    // First, create a base response token with realm + user values populated
    final AuthenticatedClientSessionModel clientSession = clientSessionCtx.getClientSession();
    final ClientModel client = clientSession.getClient();
    DockerResponseToken responseToken = new DockerResponseToken().id(KeycloakModelUtils.generateId()).type(TokenUtil.TOKEN_TYPE_BEARER).issuer(authSession.getClientNote(DockerAuthV2Protocol.ISSUER)).subject(userSession.getUser().getUsername()).issuedNow().audience(client.getClientId()).issuedFor(client.getClientId());
    // since realm access token is given in seconds
    final int accessTokenLifespan = realm.getAccessTokenLifespan();
    responseToken.notBefore(responseToken.getIssuedAt()).expiration(responseToken.getIssuedAt() + accessTokenLifespan);
    // Next, allow mappers to decorate the token to add/remove scopes as appropriate
    AtomicReference<DockerResponseToken> finalResponseToken = new AtomicReference<>(responseToken);
    ProtocolMapperUtils.getSortedProtocolMappers(session, clientSessionCtx).filter(mapper -> mapper.getValue() instanceof DockerAuthV2AttributeMapper).filter(mapper -> ((DockerAuthV2AttributeMapper) mapper.getValue()).appliesTo(finalResponseToken.get())).forEach(mapper -> finalResponseToken.set(((DockerAuthV2AttributeMapper) mapper.getValue()).transformDockerResponseToken(finalResponseToken.get(), mapper.getKey(), session, userSession, clientSession)));
    responseToken = finalResponseToken.get();
    try {
        // Finally, construct the response to the docker client with the token + metadata
        if (event.getEvent() != null && EventType.LOGIN.equals(event.getEvent().getType())) {
            final KeyManager.ActiveRsaKey activeKey = session.keys().getActiveRsaKey(realm);
            final String encodedToken = new JWSBuilder().kid(new DockerKeyIdentifier(activeKey.getPublicKey()).toString()).type("JWT").jsonContent(responseToken).rsa256(activeKey.getPrivateKey());
            final String expiresInIso8601String = new SimpleDateFormat(ISO_8601_DATE_FORMAT).format(new Date(responseToken.getIssuedAt() * 1000L));
            final DockerResponse responseEntity = new DockerResponse().setToken(encodedToken).setExpires_in(accessTokenLifespan).setIssued_at(expiresInIso8601String);
            return new ResponseBuilderImpl().status(Response.Status.OK).header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON).entity(responseEntity).build();
        } else {
            logger.errorv("Unable to handle request for event type {0}.  Currently only LOGIN event types are supported by docker protocol.", event.getEvent() == null ? "null" : event.getEvent().getType());
            throw new ErrorResponseException("invalid_request", "Event type not supported", Response.Status.BAD_REQUEST);
        }
    } catch (final InstantiationException e) {
        logger.errorv("Error attempting to create Key ID for Docker JOSE header: ", e.getMessage());
        throw new ErrorResponseException("token_error", "Unable to construct JOSE header for JWT", Response.Status.INTERNAL_SERVER_ERROR);
    }
}
Also used : DockerAuthV2AttributeMapper(org.keycloak.protocol.docker.mapper.DockerAuthV2AttributeMapper) ClientModel(org.keycloak.models.ClientModel) KeycloakModelUtils(org.keycloak.models.utils.KeycloakModelUtils) Date(java.util.Date) Logger(org.jboss.logging.Logger) SimpleDateFormat(java.text.SimpleDateFormat) ResponseBuilderImpl(org.jboss.resteasy.specimpl.ResponseBuilderImpl) AtomicReference(java.util.concurrent.atomic.AtomicReference) KeyManager(org.keycloak.models.KeyManager) TokenUtil(org.keycloak.util.TokenUtil) MediaType(javax.ws.rs.core.MediaType) ClientSessionContext(org.keycloak.models.ClientSessionContext) JWSBuilder(org.keycloak.jose.jws.JWSBuilder) EventBuilder(org.keycloak.events.EventBuilder) AuthenticatedClientSessionModel(org.keycloak.models.AuthenticatedClientSessionModel) ErrorResponseException(org.keycloak.services.ErrorResponseException) DockerResponseToken(org.keycloak.representations.docker.DockerResponseToken) AuthenticationSessionModel(org.keycloak.sessions.AuthenticationSessionModel) RealmModel(org.keycloak.models.RealmModel) KeycloakSession(org.keycloak.models.KeycloakSession) EventType(org.keycloak.events.EventType) UserSessionModel(org.keycloak.models.UserSessionModel) DockerResponse(org.keycloak.representations.docker.DockerResponse) HttpHeaders(javax.ws.rs.core.HttpHeaders) Response(javax.ws.rs.core.Response) ProtocolMapperUtils(org.keycloak.protocol.ProtocolMapperUtils) UriInfo(javax.ws.rs.core.UriInfo) DockerAuthV2AttributeMapper(org.keycloak.protocol.docker.mapper.DockerAuthV2AttributeMapper) LoginProtocol(org.keycloak.protocol.LoginProtocol) DockerResponse(org.keycloak.representations.docker.DockerResponse) AuthenticatedClientSessionModel(org.keycloak.models.AuthenticatedClientSessionModel) AtomicReference(java.util.concurrent.atomic.AtomicReference) DockerResponseToken(org.keycloak.representations.docker.DockerResponseToken) Date(java.util.Date) JWSBuilder(org.keycloak.jose.jws.JWSBuilder) ClientModel(org.keycloak.models.ClientModel) ResponseBuilderImpl(org.jboss.resteasy.specimpl.ResponseBuilderImpl) ErrorResponseException(org.keycloak.services.ErrorResponseException) KeyManager(org.keycloak.models.KeyManager) SimpleDateFormat(java.text.SimpleDateFormat)

Aggregations

ClientModel (org.keycloak.models.ClientModel)344 RealmModel (org.keycloak.models.RealmModel)148 UserModel (org.keycloak.models.UserModel)88 RoleModel (org.keycloak.models.RoleModel)74 KeycloakSession (org.keycloak.models.KeycloakSession)67 Test (org.junit.Test)64 UserSessionModel (org.keycloak.models.UserSessionModel)41 ResourceServer (org.keycloak.authorization.model.ResourceServer)39 Policy (org.keycloak.authorization.model.Policy)38 HashMap (java.util.HashMap)37 AuthorizationProvider (org.keycloak.authorization.AuthorizationProvider)36 AbstractTestRealmKeycloakTest (org.keycloak.testsuite.AbstractTestRealmKeycloakTest)34 ModelTest (org.keycloak.testsuite.arquillian.annotation.ModelTest)34 List (java.util.List)32 Map (java.util.Map)32 Path (javax.ws.rs.Path)29 LinkedList (java.util.LinkedList)28 ClientScopeModel (org.keycloak.models.ClientScopeModel)28 ArrayList (java.util.ArrayList)27 AuthenticatedClientSessionModel (org.keycloak.models.AuthenticatedClientSessionModel)27