Search in sources :

Example 6 with ModelDuplicateException

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

the class ClientScopeAdapter method addProtocolMapper.

@Override
public ProtocolMapperModel addProtocolMapper(ProtocolMapperModel model) {
    if (getProtocolMapperByName(model.getProtocol(), model.getName()) != null) {
        throw new ModelDuplicateException("Protocol mapper name must be unique per protocol");
    }
    String id = model.getId() != null ? model.getId() : KeycloakModelUtils.generateId();
    ProtocolMapperEntity entity = new ProtocolMapperEntity();
    entity.setId(id);
    entity.setName(model.getName());
    entity.setProtocol(model.getProtocol());
    entity.setProtocolMapper(model.getProtocolMapper());
    entity.setClientScope(this.entity);
    entity.setConfig(model.getConfig());
    em.persist(entity);
    this.entity.getProtocolMappers().add(entity);
    return entityToModel(entity);
}
Also used : ProtocolMapperEntity(org.keycloak.models.jpa.entities.ProtocolMapperEntity) ModelDuplicateException(org.keycloak.models.ModelDuplicateException)

Example 7 with ModelDuplicateException

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

the class X509ClientCertificateAuthenticator method authenticate.

@Override
public void authenticate(AuthenticationFlowContext context) {
    try {
        dumpContainerAttributes(context);
        X509Certificate[] certs = getCertificateChain(context);
        if (certs == null || certs.length == 0) {
            // No x509 client cert, fall through and
            // continue processing the rest of the authentication flow
            logger.debug("[X509ClientCertificateAuthenticator:authenticate] x509 client certificate is not available for mutual SSL.");
            context.attempted();
            return;
        }
        saveX509CertificateAuditDataToAuthSession(context, certs[0]);
        recordX509CertificateAuditDataViaContextEvent(context);
        X509AuthenticatorConfigModel config = null;
        if (context.getAuthenticatorConfig() != null && context.getAuthenticatorConfig().getConfig() != null) {
            config = new X509AuthenticatorConfigModel(context.getAuthenticatorConfig());
        }
        if (config == null) {
            logger.warn("[X509ClientCertificateAuthenticator:authenticate] x509 Client Certificate Authentication configuration is not available.");
            context.challenge(createInfoResponse(context, "X509 client authentication has not been configured yet"));
            context.attempted();
            return;
        }
        // Validate X509 client certificate
        try {
            CertificateValidator.CertificateValidatorBuilder builder = certificateValidationParameters(context.getSession(), config);
            CertificateValidator validator = builder.build(certs);
            validator.checkRevocationStatus().validateTrust().validateKeyUsage().validateExtendedKeyUsage().validatePolicy().validateTimestamps();
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            // TODO use specific locale to load error messages
            String errorMessage = "Certificate validation's failed.";
            // TODO is calling form().setErrors enough to show errors on login screen?
            context.challenge(createErrorResponse(context, certs[0].getSubjectDN().getName(), errorMessage, e.getMessage()));
            context.attempted();
            return;
        }
        Object userIdentity = getUserIdentityExtractor(config).extractUserIdentity(certs);
        if (userIdentity == null) {
            context.getEvent().error(Errors.INVALID_USER_CREDENTIALS);
            logger.warnf("[X509ClientCertificateAuthenticator:authenticate] Unable to extract user identity from certificate.");
            // TODO use specific locale to load error messages
            String errorMessage = "Unable to extract user identity from specified certificate";
            // TODO is calling form().setErrors enough to show errors on login screen?
            context.challenge(createErrorResponse(context, certs[0].getSubjectDN().getName(), errorMessage));
            context.attempted();
            return;
        }
        UserModel user;
        try {
            context.getEvent().detail(Details.USERNAME, userIdentity.toString());
            context.getAuthenticationSession().setAuthNote(AbstractUsernameFormAuthenticator.ATTEMPTED_USERNAME, userIdentity.toString());
            user = getUserIdentityToModelMapper(config).find(context, userIdentity);
        } catch (ModelDuplicateException e) {
            logger.modelDuplicateException(e);
            String errorMessage = "X509 certificate authentication's failed.";
            // TODO is calling form().setErrors enough to show errors on login screen?
            context.challenge(createErrorResponse(context, certs[0].getSubjectDN().getName(), errorMessage, e.getMessage()));
            context.attempted();
            return;
        }
        if (invalidUser(context, user)) {
            // TODO use specific locale to load error messages
            String errorMessage = "X509 certificate authentication's failed.";
            // TODO is calling form().setErrors enough to show errors on login screen?
            context.challenge(createErrorResponse(context, certs[0].getSubjectDN().getName(), errorMessage, "Invalid user"));
            context.attempted();
            return;
        }
        String bruteForceError = getDisabledByBruteForceEventError(context.getProtector(), context.getSession(), context.getRealm(), user);
        if (bruteForceError != null) {
            context.getEvent().user(user);
            context.getEvent().error(bruteForceError);
            // TODO use specific locale to load error messages
            String errorMessage = "X509 certificate authentication's failed.";
            // TODO is calling form().setErrors enough to show errors on login screen?
            context.challenge(createErrorResponse(context, certs[0].getSubjectDN().getName(), errorMessage, "Invalid user"));
            context.attempted();
            return;
        }
        if (!userEnabled(context, user)) {
            // TODO use specific locale to load error messages
            String errorMessage = "X509 certificate authentication's failed.";
            // TODO is calling form().setErrors enough to show errors on login screen?
            context.challenge(createErrorResponse(context, certs[0].getSubjectDN().getName(), errorMessage, "User is disabled"));
            context.attempted();
            return;
        }
        context.setUser(user);
        // Check whether to display the identity confirmation
        if (!config.getConfirmationPageDisallowed()) {
            // FIXME calling forceChallenge was the only way to display
            // a form to let users either choose the user identity from certificate
            // or to ignore it and proceed to a normal login screen. Attempting
            // to call the method "challenge" results in a wrong/unexpected behavior.
            // The question is whether calling "forceChallenge" here is ok from
            // the design viewpoint?
            context.forceChallenge(createSuccessResponse(context, certs[0].getSubjectDN().getName()));
        // Do not set the flow status yet, we want to display a form to let users
        // choose whether to accept the identity from certificate or to specify username/password explicitly
        } else {
            // Bypass the confirmation page and log the user in
            context.success();
        }
    } catch (Exception e) {
        logger.errorf("[X509ClientCertificateAuthenticator:authenticate] Exception: %s", e.getMessage());
        context.attempted();
    }
}
Also used : UserModel(org.keycloak.models.UserModel) ModelDuplicateException(org.keycloak.models.ModelDuplicateException) X509Certificate(java.security.cert.X509Certificate) ModelDuplicateException(org.keycloak.models.ModelDuplicateException)

Example 8 with ModelDuplicateException

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

the class ValidateX509CertificateUsername method authenticate.

@Override
public void authenticate(AuthenticationFlowContext context) {
    X509Certificate[] certs = getCertificateChain(context);
    if (certs == null || certs.length == 0) {
        logger.debug("[ValidateX509CertificateUsername:authenticate] x509 client certificate is not available for mutual SSL.");
        context.getEvent().error(Errors.USER_NOT_FOUND);
        Response challengeResponse = errorResponse(Response.Status.UNAUTHORIZED.getStatusCode(), "invalid_request", "X509 client certificate is missing.");
        context.failure(AuthenticationFlowError.INVALID_USER, challengeResponse);
        return;
    }
    saveX509CertificateAuditDataToAuthSession(context, certs[0]);
    recordX509CertificateAuditDataViaContextEvent(context);
    X509AuthenticatorConfigModel config = null;
    if (context.getAuthenticatorConfig() != null && context.getAuthenticatorConfig().getConfig() != null) {
        config = new X509AuthenticatorConfigModel(context.getAuthenticatorConfig());
    }
    if (config == null) {
        logger.warn("[ValidateX509CertificateUsername:authenticate] x509 Client Certificate Authentication configuration is not available.");
        context.getEvent().error(Errors.USER_NOT_FOUND);
        Response challengeResponse = errorResponse(Response.Status.UNAUTHORIZED.getStatusCode(), "invalid_request", "Configuration is missing.");
        context.failure(AuthenticationFlowError.INVALID_USER, challengeResponse);
        return;
    }
    // Validate X509 client certificate
    try {
        CertificateValidator.CertificateValidatorBuilder builder = certificateValidationParameters(context.getSession(), config);
        CertificateValidator validator = builder.build(certs);
        validator.checkRevocationStatus().validateTrust().validateKeyUsage().validateExtendedKeyUsage().validateTimestamps().validatePolicy();
    } catch (Exception e) {
        logger.error(e.getMessage(), e);
        // TODO use specific locale to load error messages
        Response challengeResponse = errorResponse(Response.Status.UNAUTHORIZED.getStatusCode(), "invalid_request", e.getMessage());
        context.failure(AuthenticationFlowError.INVALID_USER, challengeResponse);
        return;
    }
    Object userIdentity = getUserIdentityExtractor(config).extractUserIdentity(certs);
    if (userIdentity == null) {
        context.getEvent().error(Errors.INVALID_USER_CREDENTIALS);
        logger.errorf("[ValidateX509CertificateUsername:authenticate] Unable to extract user identity from certificate.");
        // TODO use specific locale to load error messages
        String errorMessage = "Unable to extract user identity from specified certificate";
        Response challengeResponse = errorResponse(Response.Status.UNAUTHORIZED.getStatusCode(), "invalid_request", errorMessage);
        context.failure(AuthenticationFlowError.INVALID_USER, challengeResponse);
        return;
    }
    UserModel user;
    try {
        context.getEvent().detail(Details.USERNAME, userIdentity.toString());
        context.getAuthenticationSession().setAuthNote(AbstractUsernameFormAuthenticator.ATTEMPTED_USERNAME, userIdentity.toString());
        user = getUserIdentityToModelMapper(config).find(context, userIdentity);
    } catch (ModelDuplicateException e) {
        logger.modelDuplicateException(e);
        String errorMessage = String.format("X509 certificate authentication's failed. Reason: \"%s\"", e.getMessage());
        Response challengeResponse = errorResponse(Response.Status.UNAUTHORIZED.getStatusCode(), "invalid_request", errorMessage);
        context.failure(AuthenticationFlowError.INVALID_USER, challengeResponse);
        return;
    } catch (Exception e) {
        logger.error(e.getMessage(), e);
        String errorMessage = String.format("X509 certificate authentication's failed. Reason: \"%s\"", e.getMessage());
        Response challengeResponse = errorResponse(Response.Status.UNAUTHORIZED.getStatusCode(), "invalid_request", errorMessage);
        context.failure(AuthenticationFlowError.INVALID_USER, challengeResponse);
        return;
    }
    if (user == null) {
        context.getEvent().error(Errors.INVALID_USER_CREDENTIALS);
        Response challengeResponse = errorResponse(Response.Status.UNAUTHORIZED.getStatusCode(), "invalid_grant", "Invalid user credentials");
        context.failure(AuthenticationFlowError.INVALID_USER, challengeResponse);
        return;
    }
    String bruteForceError = getDisabledByBruteForceEventError(context.getProtector(), context.getSession(), context.getRealm(), user);
    if (bruteForceError != null) {
        context.getEvent().user(user);
        context.getEvent().error(bruteForceError);
        Response challengeResponse = errorResponse(Response.Status.BAD_REQUEST.getStatusCode(), "invalid_grant", "Invalid user credentials");
        context.failure(AuthenticationFlowError.INVALID_USER, challengeResponse);
        return;
    }
    if (!user.isEnabled()) {
        context.getEvent().user(user);
        context.getEvent().error(Errors.USER_DISABLED);
        Response challengeResponse = errorResponse(Response.Status.BAD_REQUEST.getStatusCode(), "invalid_grant", "Account disabled");
        context.failure(AuthenticationFlowError.INVALID_USER, challengeResponse);
        return;
    }
    context.setUser(user);
    context.success();
}
Also used : Response(javax.ws.rs.core.Response) UserModel(org.keycloak.models.UserModel) ModelDuplicateException(org.keycloak.models.ModelDuplicateException) X509Certificate(java.security.cert.X509Certificate) ModelDuplicateException(org.keycloak.models.ModelDuplicateException)

Example 9 with ModelDuplicateException

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

the class TestingResourceProvider method generateAudienceClientScope.

/**
 * Generate new client scope for specified service client. The "Frontend" clients, who will use this client scope, will be able to
 * send their access token to authenticate against specified service client
 *
 * @param clientId Client ID of service client (typically bearer-only client)
 * @return ID of the newly generated clientScope
 */
@Path("generate-audience-client-scope")
@POST
@NoCache
public String generateAudienceClientScope(@QueryParam("realm") final String realmName, @QueryParam("clientId") final String clientId) {
    try {
        RealmModel realm = getRealmByName(realmName);
        ClientModel serviceClient = realm.getClientByClientId(clientId);
        if (serviceClient == null) {
            throw new NotFoundException("Referenced service client doesn't exist");
        }
        ClientScopeModel clientScopeModel = realm.addClientScope(clientId);
        clientScopeModel.setProtocol(serviceClient.getProtocol() == null ? OIDCLoginProtocol.LOGIN_PROTOCOL : serviceClient.getProtocol());
        clientScopeModel.setDisplayOnConsentScreen(true);
        clientScopeModel.setConsentScreenText(clientId);
        clientScopeModel.setIncludeInTokenScope(true);
        // Add audience protocol mapper
        ProtocolMapperModel audienceMapper = AudienceProtocolMapper.createClaimMapper("Audience for " + clientId, clientId, null, true, false);
        clientScopeModel.addProtocolMapper(audienceMapper);
        return clientScopeModel.getId();
    } catch (ModelDuplicateException e) {
        throw new BadRequestException("Client Scope " + clientId + " already exists");
    }
}
Also used : RealmModel(org.keycloak.models.RealmModel) ClientModel(org.keycloak.models.ClientModel) ModelDuplicateException(org.keycloak.models.ModelDuplicateException) NotFoundException(javax.ws.rs.NotFoundException) BadRequestException(javax.ws.rs.BadRequestException) ClientScopeModel(org.keycloak.models.ClientScopeModel) ProtocolMapperModel(org.keycloak.models.ProtocolMapperModel) Path(javax.ws.rs.Path) POST(javax.ws.rs.POST) NoCache(org.jboss.resteasy.annotations.cache.NoCache)

Example 10 with ModelDuplicateException

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

the class UserAttributeLDAPStorageMapper method checkDuplicateEmail.

// throw ModelDuplicateException if there is different user in model with same email
protected void checkDuplicateEmail(String userModelAttrName, String email, RealmModel realm, KeycloakSession session, UserModel user) {
    if (email == null || realm.isDuplicateEmailsAllowed())
        return;
    if (UserModel.EMAIL.equalsIgnoreCase(userModelAttrName)) {
        // lowercase before search
        email = KeycloakModelUtils.toLowerCaseSafe(email);
        UserModel that = session.userLocalStorage().getUserByEmail(realm, email);
        if (that != null && !that.getId().equals(user.getId())) {
            session.getTransactionManager().setRollbackOnly();
            String exceptionMessage = String.format("Can't import user '%s' from LDAP because email '%s' already exists in Keycloak. Existing user with this email is '%s'", user.getUsername(), email, that.getUsername());
            throw new ModelDuplicateException(exceptionMessage, UserModel.EMAIL);
        }
    }
}
Also used : UserModel(org.keycloak.models.UserModel) ModelDuplicateException(org.keycloak.models.ModelDuplicateException)

Aggregations

ModelDuplicateException (org.keycloak.models.ModelDuplicateException)42 Consumes (javax.ws.rs.Consumes)12 UserModel (org.keycloak.models.UserModel)11 POST (javax.ws.rs.POST)9 Response (javax.ws.rs.core.Response)6 NotFoundException (javax.ws.rs.NotFoundException)5 ClientModel (org.keycloak.models.ClientModel)5 RealmModel (org.keycloak.models.RealmModel)5 BadRequestException (javax.ws.rs.BadRequestException)4 PUT (javax.ws.rs.PUT)4 Path (javax.ws.rs.Path)4 ModelException (org.keycloak.models.ModelException)4 X509Certificate (java.security.cert.X509Certificate)3 NoCache (org.jboss.resteasy.annotations.cache.NoCache)3 ErrorResponseException (org.keycloak.services.ErrorResponseException)3 ClientPolicyException (org.keycloak.services.clientpolicy.ClientPolicyException)3 URI (java.net.URI)2 WebApplicationException (javax.ws.rs.WebApplicationException)2 ClientScopeModel (org.keycloak.models.ClientScopeModel)2 ProtocolMapperModel (org.keycloak.models.ProtocolMapperModel)2