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);
}
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();
}
}
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();
}
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");
}
}
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);
}
}
}
Aggregations