Search in sources :

Example 1 with EventBuilder

use of org.keycloak.events.EventBuilder in project keycloak by keycloak.

the class IdpReviewProfileAuthenticator method actionImpl.

@Override
protected void actionImpl(AuthenticationFlowContext context, SerializedBrokeredIdentityContext userCtx, BrokeredIdentityContext brokerContext) {
    EventBuilder event = context.getEvent();
    // velias: looks like UPDATE_PROFILE event is not fired. IMHO it should not be fired here as user record in keycloak is not changed, user doesn't exist yet
    event.event(EventType.UPDATE_PROFILE).detail(Details.CONTEXT, UserProfileContext.IDP_REVIEW.name());
    MultivaluedMap<String, String> formData = context.getHttpRequest().getDecodedFormParameters();
    UserModelDelegate updatedProfile = new UserModelDelegate(null) {

        @Override
        public String getId() {
            return userCtx.getId();
        }

        @Override
        public Map<String, List<String>> getAttributes() {
            return userCtx.getAttributes();
        }

        @Override
        public Stream<String> getAttributeStream(String name) {
            return userCtx.getAttribute(name).stream();
        }

        @Override
        public void setAttribute(String name, List<String> values) {
            userCtx.setAttribute(name, values);
        }

        @Override
        public void removeAttribute(String name) {
            userCtx.getAttributes().remove(name);
        }

        @Override
        public String getFirstAttribute(String name) {
            return userCtx.getFirstAttribute(name);
        }

        @Override
        public String getUsername() {
            return userCtx.getUsername();
        }
    };
    UserProfileProvider profileProvider = context.getSession().getProvider(UserProfileProvider.class);
    UserProfile profile = profileProvider.create(UserProfileContext.IDP_REVIEW, formData, updatedProfile);
    try {
        String oldEmail = userCtx.getEmail();
        profile.update((attributeName, userModel, oldValue) -> {
            if (attributeName.equals(UserModel.EMAIL)) {
                context.getAuthenticationSession().setAuthNote(UPDATE_PROFILE_EMAIL_CHANGED, "true");
                event.clone().event(EventType.UPDATE_EMAIL).detail(Details.CONTEXT, UserProfileContext.IDP_REVIEW.name()).detail(Details.PREVIOUS_EMAIL, oldEmail).detail(Details.UPDATED_EMAIL, profile.getAttributes().getFirstValue(UserModel.EMAIL)).success();
            }
        });
    } catch (ValidationException pve) {
        List<FormMessage> errors = Validation.getFormErrorsFromValidation(pve.getErrors());
        Response challenge = context.form().setErrors(errors).setAttribute(LoginFormsProvider.UPDATE_PROFILE_CONTEXT_ATTR, userCtx).setFormData(formData).createUpdateProfilePage();
        context.challenge(challenge);
        return;
    }
    userCtx.saveToAuthenticationSession(context.getAuthenticationSession(), BROKERED_CONTEXT_NOTE);
    logger.debugf("Profile updated successfully after first authentication with identity provider '%s' for broker user '%s'.", brokerContext.getIdpConfig().getAlias(), userCtx.getUsername());
    String newEmail = profile.getAttributes().getFirstValue(UserModel.EMAIL);
    event.detail(Details.UPDATED_EMAIL, newEmail);
    // Ensure page is always shown when user later returns to it - for example with form "back" button
    context.getAuthenticationSession().setAuthNote(ENFORCE_UPDATE_PROFILE, "true");
    context.success();
}
Also used : Response(javax.ws.rs.core.Response) EventBuilder(org.keycloak.events.EventBuilder) UserModelDelegate(org.keycloak.models.utils.UserModelDelegate) ValidationException(org.keycloak.userprofile.ValidationException) UserProfile(org.keycloak.userprofile.UserProfile) UserProfileProvider(org.keycloak.userprofile.UserProfileProvider) List(java.util.List)

Example 2 with EventBuilder

use of org.keycloak.events.EventBuilder in project keycloak by keycloak.

the class UserInfoEndpoint method issueUserInfo.

private Response issueUserInfo(String tokenString) {
    cors = Cors.add(request).auth().allowedMethods(request.getHttpMethod()).auth().exposedHeaders(Cors.ACCESS_CONTROL_ALLOW_METHODS);
    try {
        session.clientPolicy().triggerOnEvent(new UserInfoRequestContext(tokenString));
    } catch (ClientPolicyException cpe) {
        throw new CorsErrorResponseException(cors.allowAllOrigins(), cpe.getError(), cpe.getErrorDetail(), cpe.getErrorStatus());
    }
    EventBuilder event = new EventBuilder(realm, session, clientConnection).event(EventType.USER_INFO_REQUEST).detail(Details.AUTH_METHOD, Details.VALIDATE_ACCESS_TOKEN);
    if (tokenString == null) {
        event.error(Errors.INVALID_TOKEN);
        throw new CorsErrorResponseException(cors.allowAllOrigins(), OAuthErrorException.INVALID_REQUEST, "Token not provided", Response.Status.BAD_REQUEST);
    }
    AccessToken token;
    ClientModel clientModel = null;
    try {
        TokenVerifier<AccessToken> verifier = TokenVerifier.create(tokenString, AccessToken.class).withDefaultChecks().realmUrl(Urls.realmIssuer(session.getContext().getUri().getBaseUri(), realm.getName()));
        SignatureVerifierContext verifierContext = session.getProvider(SignatureProvider.class, verifier.getHeader().getAlgorithm().name()).verifier(verifier.getHeader().getKeyId());
        verifier.verifierContext(verifierContext);
        token = verifier.verify().getToken();
        clientModel = realm.getClientByClientId(token.getIssuedFor());
        if (clientModel == null) {
            event.error(Errors.CLIENT_NOT_FOUND);
            throw new CorsErrorResponseException(cors.allowAllOrigins(), OAuthErrorException.INVALID_REQUEST, "Client not found", Response.Status.BAD_REQUEST);
        }
        cors.allowedOrigins(session, clientModel);
        TokenVerifier.createWithoutSignature(token).withChecks(NotBeforeCheck.forModel(clientModel), new TokenManager.TokenRevocationCheck(session)).verify();
    } catch (VerificationException e) {
        if (clientModel == null) {
            cors.allowAllOrigins();
        }
        event.error(Errors.INVALID_TOKEN);
        throw newUnauthorizedErrorResponseException(OAuthErrorException.INVALID_TOKEN, "Token verification failed");
    }
    if (!clientModel.getProtocol().equals(OIDCLoginProtocol.LOGIN_PROTOCOL)) {
        event.error(Errors.INVALID_CLIENT);
        throw new CorsErrorResponseException(cors, Errors.INVALID_CLIENT, "Wrong client protocol.", Response.Status.BAD_REQUEST);
    }
    session.getContext().setClient(clientModel);
    event.client(clientModel);
    if (!clientModel.isEnabled()) {
        event.error(Errors.CLIENT_DISABLED);
        throw new CorsErrorResponseException(cors, OAuthErrorException.INVALID_REQUEST, "Client disabled", Response.Status.BAD_REQUEST);
    }
    UserSessionModel userSession = findValidSession(token, event, clientModel);
    UserModel userModel = userSession.getUser();
    if (userModel == null) {
        event.error(Errors.USER_NOT_FOUND);
        throw new CorsErrorResponseException(cors, OAuthErrorException.INVALID_REQUEST, "User not found", Response.Status.BAD_REQUEST);
    }
    event.user(userModel).detail(Details.USERNAME, userModel.getUsername());
    // https://tools.ietf.org/html/draft-ietf-oauth-mtls-08#section-3
    if (OIDCAdvancedConfigWrapper.fromClientModel(clientModel).isUseMtlsHokToken()) {
        if (!MtlsHoKTokenUtil.verifyTokenBindingWithClientCertificate(token, request, session)) {
            event.error(Errors.NOT_ALLOWED);
            throw newUnauthorizedErrorResponseException(OAuthErrorException.UNAUTHORIZED_CLIENT, "Client certificate missing, or its thumbprint and one in the refresh token did NOT match");
        }
    }
    // Existence of authenticatedClientSession for our client already handled before
    AuthenticatedClientSessionModel clientSession = userSession.getAuthenticatedClientSessionByClient(clientModel.getId());
    // Retrieve by latest scope parameter
    ClientSessionContext clientSessionCtx = DefaultClientSessionContext.fromClientSessionScopeParameter(clientSession, session);
    AccessToken userInfo = new AccessToken();
    tokenManager.transformUserInfoAccessToken(session, userInfo, userSession, clientSessionCtx);
    Map<String, Object> claims = tokenManager.generateUserInfoClaims(userInfo, userModel);
    Response.ResponseBuilder responseBuilder;
    OIDCAdvancedConfigWrapper cfg = OIDCAdvancedConfigWrapper.fromClientModel(clientModel);
    if (cfg.isUserInfoSignatureRequired()) {
        String issuerUrl = Urls.realmIssuer(session.getContext().getUri().getBaseUri(), realm.getName());
        String audience = clientModel.getClientId();
        claims.put("iss", issuerUrl);
        claims.put("aud", audience);
        String signatureAlgorithm = session.tokens().signatureAlgorithm(TokenCategory.USERINFO);
        SignatureProvider signatureProvider = session.getProvider(SignatureProvider.class, signatureAlgorithm);
        SignatureSignerContext signer = signatureProvider.signer();
        String signedUserInfo = new JWSBuilder().type("JWT").jsonContent(claims).sign(signer);
        responseBuilder = Response.ok(signedUserInfo).header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JWT);
        event.detail(Details.SIGNATURE_REQUIRED, "true");
        event.detail(Details.SIGNATURE_ALGORITHM, cfg.getUserInfoSignedResponseAlg().toString());
    } else {
        responseBuilder = Response.ok(claims).header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON);
        event.detail(Details.SIGNATURE_REQUIRED, "false");
    }
    event.success();
    return cors.builder(responseBuilder).build();
}
Also used : UserSessionModel(org.keycloak.models.UserSessionModel) SignatureVerifierContext(org.keycloak.crypto.SignatureVerifierContext) OIDCAdvancedConfigWrapper(org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper) SignatureSignerContext(org.keycloak.crypto.SignatureSignerContext) AuthenticatedClientSessionModel(org.keycloak.models.AuthenticatedClientSessionModel) ClientPolicyException(org.keycloak.services.clientpolicy.ClientPolicyException) JWSBuilder(org.keycloak.jose.jws.JWSBuilder) UserModel(org.keycloak.models.UserModel) Response(javax.ws.rs.core.Response) HttpResponse(org.jboss.resteasy.spi.HttpResponse) ClientModel(org.keycloak.models.ClientModel) SignatureProvider(org.keycloak.crypto.SignatureProvider) UserInfoRequestContext(org.keycloak.services.clientpolicy.context.UserInfoRequestContext) EventBuilder(org.keycloak.events.EventBuilder) DefaultClientSessionContext(org.keycloak.services.util.DefaultClientSessionContext) ClientSessionContext(org.keycloak.models.ClientSessionContext) AccessToken(org.keycloak.representations.AccessToken) VerificationException(org.keycloak.common.VerificationException) CorsErrorResponseException(org.keycloak.services.CorsErrorResponseException)

Example 3 with EventBuilder

use of org.keycloak.events.EventBuilder in project keycloak by keycloak.

the class UserResource method impersonate.

/**
 * Impersonate the user
 *
 * @return
 */
@Path("impersonation")
@POST
@NoCache
@Produces(MediaType.APPLICATION_JSON)
public Map<String, Object> impersonate() {
    ProfileHelper.requireFeature(Profile.Feature.IMPERSONATION);
    auth.users().requireImpersonate(user);
    RealmModel authenticatedRealm = auth.adminAuth().getRealm();
    // if same realm logout before impersonation
    boolean sameRealm = false;
    String sessionState = auth.adminAuth().getToken().getSessionState();
    if (authenticatedRealm.getId().equals(realm.getId()) && sessionState != null) {
        sameRealm = true;
        UserSessionModel userSession = session.sessions().getUserSession(authenticatedRealm, sessionState);
        AuthenticationManager.expireIdentityCookie(realm, session.getContext().getUri(), clientConnection);
        AuthenticationManager.expireRememberMeCookie(realm, session.getContext().getUri(), clientConnection);
        AuthenticationManager.backchannelLogout(session, authenticatedRealm, userSession, session.getContext().getUri(), clientConnection, headers, true);
    }
    EventBuilder event = new EventBuilder(realm, session, clientConnection);
    UserSessionModel userSession = session.sessions().createUserSession(realm, user, user.getUsername(), clientConnection.getRemoteAddr(), "impersonate", false, null, null);
    UserModel adminUser = auth.adminAuth().getUser();
    String impersonatorId = adminUser.getId();
    String impersonator = adminUser.getUsername();
    userSession.setNote(IMPERSONATOR_ID.toString(), impersonatorId);
    userSession.setNote(IMPERSONATOR_USERNAME.toString(), impersonator);
    AuthenticationManager.createLoginCookie(session, realm, userSession.getUser(), userSession, session.getContext().getUri(), clientConnection);
    URI redirect = AccountFormService.accountServiceBaseUrl(session.getContext().getUri()).build(realm.getName());
    Map<String, Object> result = new HashMap<>();
    result.put("sameRealm", sameRealm);
    result.put("redirect", redirect.toString());
    event.event(EventType.IMPERSONATE).session(userSession).user(user).detail(Details.IMPERSONATOR_REALM, authenticatedRealm.getName()).detail(Details.IMPERSONATOR, impersonator).success();
    return result;
}
Also used : RealmModel(org.keycloak.models.RealmModel) UserModel(org.keycloak.models.UserModel) UserSessionModel(org.keycloak.models.UserSessionModel) EventBuilder(org.keycloak.events.EventBuilder) HashMap(java.util.HashMap) URI(java.net.URI) Path(javax.ws.rs.Path) POST(javax.ws.rs.POST) Produces(javax.ws.rs.Produces) NoCache(org.jboss.resteasy.annotations.cache.NoCache)

Example 4 with EventBuilder

use of org.keycloak.events.EventBuilder in project keycloak by keycloak.

the class VerifyUserProfile method requiredActionChallenge.

@Override
public void requiredActionChallenge(RequiredActionContext context) {
    UserProfileProvider provider = context.getSession().getProvider(UserProfileProvider.class);
    UserProfile profile = provider.create(UserProfileContext.UPDATE_PROFILE, context.getUser());
    try {
        profile.validate();
        context.success();
    } catch (ValidationException ve) {
        List<FormMessage> errors = Validation.getFormErrorsFromValidation(ve.getErrors());
        MultivaluedMap<String, String> parameters;
        if (context.getHttpRequest().getHttpMethod().equalsIgnoreCase(HttpMethod.GET)) {
            parameters = new MultivaluedHashMap<>();
        } else {
            parameters = context.getHttpRequest().getDecodedFormParameters();
        }
        context.challenge(createResponse(context, parameters, errors));
        EventBuilder event = context.getEvent().clone();
        event.event(EventType.VERIFY_PROFILE);
        event.detail("fields_to_update", collectFields(errors));
        event.success();
    }
}
Also used : MultivaluedHashMap(javax.ws.rs.core.MultivaluedHashMap) ValidationException(org.keycloak.userprofile.ValidationException) EventBuilder(org.keycloak.events.EventBuilder) UserProfile(org.keycloak.userprofile.UserProfile) UserProfileProvider(org.keycloak.userprofile.UserProfileProvider) List(java.util.List) MultivaluedMap(javax.ws.rs.core.MultivaluedMap)

Example 5 with EventBuilder

use of org.keycloak.events.EventBuilder in project keycloak by keycloak.

the class AuthorizationTokenService method authorize.

public Response authorize(KeycloakAuthorizationRequest request) {
    EventBuilder event = request.getEvent();
    // it is not secure to allow public clients to push arbitrary claims because message can be tampered
    if (isPublicClientRequestingEntitlementWithClaims(request)) {
        CorsErrorResponseException forbiddenClientException = new CorsErrorResponseException(request.getCors(), OAuthErrorException.INVALID_GRANT, "Public clients are not allowed to send claims", Status.FORBIDDEN);
        fireErrorEvent(event, Errors.INVALID_REQUEST, forbiddenClientException);
        throw forbiddenClientException;
    }
    try {
        PermissionTicketToken ticket = getPermissionTicket(request);
        request.setClaims(ticket.getClaims());
        EvaluationContext evaluationContext = createEvaluationContext(request);
        KeycloakIdentity identity = KeycloakIdentity.class.cast(evaluationContext.getIdentity());
        if (identity != null) {
            event.user(identity.getId());
        }
        ResourceServer resourceServer = getResourceServer(ticket, request);
        Collection<Permission> permissions;
        if (request.getTicket() != null) {
            permissions = evaluateUserManagedPermissions(request, ticket, resourceServer, evaluationContext);
        } else if (ticket.getPermissions().isEmpty() && request.getRpt() == null) {
            permissions = evaluateAllPermissions(request, resourceServer, evaluationContext);
        } else {
            permissions = evaluatePermissions(request, ticket, resourceServer, evaluationContext, identity);
        }
        if (isGranted(ticket, request, permissions)) {
            AuthorizationProvider authorization = request.getAuthorization();
            ClientModel targetClient = authorization.getRealm().getClientById(resourceServer.getId());
            Metadata metadata = request.getMetadata();
            String responseMode = metadata != null ? metadata.getResponseMode() : null;
            if (responseMode != null) {
                if (RESPONSE_MODE_DECISION.equals(metadata.getResponseMode())) {
                    Map<String, Object> responseClaims = new HashMap<>();
                    responseClaims.put(RESPONSE_MODE_DECISION_RESULT, true);
                    return createSuccessfulResponse(responseClaims, request);
                } else if (RESPONSE_MODE_PERMISSIONS.equals(metadata.getResponseMode())) {
                    return createSuccessfulResponse(permissions, request);
                } else {
                    CorsErrorResponseException invalidResponseModeException = new CorsErrorResponseException(request.getCors(), OAuthErrorException.INVALID_REQUEST, "Invalid response_mode", Status.BAD_REQUEST);
                    fireErrorEvent(event, Errors.INVALID_REQUEST, invalidResponseModeException);
                    throw invalidResponseModeException;
                }
            } else {
                return createSuccessfulResponse(createAuthorizationResponse(identity, permissions, request, targetClient), request);
            }
        }
        if (request.isSubmitRequest()) {
            CorsErrorResponseException submittedRequestException = new CorsErrorResponseException(request.getCors(), OAuthErrorException.ACCESS_DENIED, "request_submitted", Status.FORBIDDEN);
            fireErrorEvent(event, Errors.ACCESS_DENIED, submittedRequestException);
            throw submittedRequestException;
        } else {
            CorsErrorResponseException notAuthorizedException = new CorsErrorResponseException(request.getCors(), OAuthErrorException.ACCESS_DENIED, "not_authorized", Status.FORBIDDEN);
            fireErrorEvent(event, Errors.ACCESS_DENIED, notAuthorizedException);
            throw notAuthorizedException;
        }
    } catch (ErrorResponseException | CorsErrorResponseException cause) {
        if (logger.isDebugEnabled()) {
            logger.debug("Error while evaluating permissions", cause);
        }
        throw cause;
    } catch (Exception cause) {
        logger.error("Unexpected error while evaluating permissions", cause);
        throw new CorsErrorResponseException(request.getCors(), OAuthErrorException.SERVER_ERROR, "Unexpected error while evaluating permissions", Status.INTERNAL_SERVER_ERROR);
    }
}
Also used : PermissionTicketToken(org.keycloak.representations.idm.authorization.PermissionTicketToken) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) AuthorizationProvider(org.keycloak.authorization.AuthorizationProvider) Metadata(org.keycloak.representations.idm.authorization.AuthorizationRequest.Metadata) OAuthErrorException(org.keycloak.OAuthErrorException) ErrorResponseException(org.keycloak.services.ErrorResponseException) CorsErrorResponseException(org.keycloak.services.CorsErrorResponseException) ClientModel(org.keycloak.models.ClientModel) EventBuilder(org.keycloak.events.EventBuilder) KeycloakIdentity(org.keycloak.authorization.common.KeycloakIdentity) ResourcePermission(org.keycloak.authorization.permission.ResourcePermission) Permission(org.keycloak.representations.idm.authorization.Permission) ErrorResponseException(org.keycloak.services.ErrorResponseException) CorsErrorResponseException(org.keycloak.services.CorsErrorResponseException) CorsErrorResponseException(org.keycloak.services.CorsErrorResponseException) DefaultEvaluationContext(org.keycloak.authorization.common.DefaultEvaluationContext) EvaluationContext(org.keycloak.authorization.policy.evaluation.EvaluationContext) ResourceServer(org.keycloak.authorization.model.ResourceServer)

Aggregations

EventBuilder (org.keycloak.events.EventBuilder)27 RealmModel (org.keycloak.models.RealmModel)14 UserModel (org.keycloak.models.UserModel)9 Response (javax.ws.rs.core.Response)8 Path (javax.ws.rs.Path)7 AuthenticationSessionModel (org.keycloak.sessions.AuthenticationSessionModel)6 List (java.util.List)4 ClientModel (org.keycloak.models.ClientModel)4 KeycloakSession (org.keycloak.models.KeycloakSession)4 UserSessionModel (org.keycloak.models.UserSessionModel)4 HashMap (java.util.HashMap)3 EmailException (org.keycloak.email.EmailException)3 FormMessage (org.keycloak.models.utils.FormMessage)3 ValidationException (org.keycloak.userprofile.ValidationException)3 URI (java.net.URI)2 NotFoundException (javax.ws.rs.NotFoundException)2 POST (javax.ws.rs.POST)2 UriBuilder (javax.ws.rs.core.UriBuilder)2 AuthenticatedClientSessionModel (org.keycloak.models.AuthenticatedClientSessionModel)2 ClientSessionContext (org.keycloak.models.ClientSessionContext)2