use of org.keycloak.broker.provider.IdentityProviderMapper in project keycloak by keycloak.
the class DefaultTokenExchangeProvider method importUserFromExternalIdentity.
protected UserModel importUserFromExternalIdentity(BrokeredIdentityContext context) {
IdentityProviderModel identityProviderConfig = context.getIdpConfig();
String providerId = identityProviderConfig.getAlias();
// do we need this?
// AuthenticationSessionModel authenticationSession = clientCode.getClientSession();
// context.setAuthenticationSession(authenticationSession);
// session.getContext().setClient(authenticationSession.getClient());
context.getIdp().preprocessFederatedIdentity(session, realm, context);
Set<IdentityProviderMapperModel> mappers = realm.getIdentityProviderMappersByAliasStream(context.getIdpConfig().getAlias()).collect(Collectors.toSet());
KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
for (IdentityProviderMapperModel mapper : mappers) {
IdentityProviderMapper target = (IdentityProviderMapper) sessionFactory.getProviderFactory(IdentityProviderMapper.class, mapper.getIdentityProviderMapper());
target.preprocessFederatedIdentity(session, realm, mapper, context);
}
FederatedIdentityModel federatedIdentityModel = new FederatedIdentityModel(providerId, context.getId(), context.getUsername(), context.getToken());
UserModel user = this.session.users().getUserByFederatedIdentity(realm, federatedIdentityModel);
if (user == null) {
logger.debugf("Federated user not found for provider '%s' and broker username '%s'.", providerId, context.getUsername());
String username = context.getModelUsername();
if (username == null) {
if (this.realm.isRegistrationEmailAsUsername() && !Validation.isBlank(context.getEmail())) {
username = context.getEmail();
} else if (context.getUsername() == null) {
username = context.getIdpConfig().getAlias() + "." + context.getId();
} else {
username = context.getUsername();
}
}
username = username.trim();
context.setModelUsername(username);
if (context.getEmail() != null && !realm.isDuplicateEmailsAllowed()) {
UserModel existingUser = session.users().getUserByEmail(realm, context.getEmail());
if (existingUser != null) {
event.error(Errors.FEDERATED_IDENTITY_EXISTS);
throw new CorsErrorResponseException(cors, Errors.INVALID_TOKEN, "User already exists", Response.Status.BAD_REQUEST);
}
}
UserModel existingUser = session.users().getUserByUsername(realm, username);
if (existingUser != null) {
event.error(Errors.FEDERATED_IDENTITY_EXISTS);
throw new CorsErrorResponseException(cors, Errors.INVALID_TOKEN, "User already exists", Response.Status.BAD_REQUEST);
}
user = session.users().addUser(realm, username);
user.setEnabled(true);
user.setEmail(context.getEmail());
user.setFirstName(context.getFirstName());
user.setLastName(context.getLastName());
federatedIdentityModel = new FederatedIdentityModel(context.getIdpConfig().getAlias(), context.getId(), context.getUsername(), context.getToken());
session.users().addFederatedIdentity(realm, user, federatedIdentityModel);
context.getIdp().importNewUser(session, realm, user, context);
for (IdentityProviderMapperModel mapper : mappers) {
IdentityProviderMapper target = (IdentityProviderMapper) sessionFactory.getProviderFactory(IdentityProviderMapper.class, mapper.getIdentityProviderMapper());
target.importNewUser(session, realm, user, mapper, context);
}
if (context.getIdpConfig().isTrustEmail() && !Validation.isBlank(user.getEmail())) {
logger.debugf("Email verified automatically after registration of user '%s' through Identity provider '%s' ", user.getUsername(), context.getIdpConfig().getAlias());
user.setEmailVerified(true);
}
} else {
if (!user.isEnabled()) {
event.error(Errors.USER_DISABLED);
throw new CorsErrorResponseException(cors, Errors.INVALID_TOKEN, "Invalid Token", Response.Status.BAD_REQUEST);
}
String bruteForceError = getDisabledByBruteForceEventError(session.getProvider(BruteForceProtector.class), session, realm, user);
if (bruteForceError != null) {
event.error(bruteForceError);
throw new CorsErrorResponseException(cors, Errors.INVALID_TOKEN, "Invalid Token", Response.Status.BAD_REQUEST);
}
context.getIdp().updateBrokeredUser(session, realm, user, context);
for (IdentityProviderMapperModel mapper : mappers) {
IdentityProviderMapper target = (IdentityProviderMapper) sessionFactory.getProviderFactory(IdentityProviderMapper.class, mapper.getIdentityProviderMapper());
IdentityProviderMapperSyncModeDelegate.delegateUpdateBrokeredUser(session, realm, user, mapper, context, target);
}
}
return user;
}
use of org.keycloak.broker.provider.IdentityProviderMapper in project keycloak by keycloak.
the class SAMLIdentityProvider method export.
@Override
public Response export(UriInfo uriInfo, RealmModel realm, String format) {
try {
URI authnBinding = JBossSAMLURIConstants.SAML_HTTP_REDIRECT_BINDING.getUri();
if (getConfig().isPostBindingAuthnRequest()) {
authnBinding = JBossSAMLURIConstants.SAML_HTTP_POST_BINDING.getUri();
}
URI endpoint = uriInfo.getBaseUriBuilder().path("realms").path(realm.getName()).path("broker").path(getConfig().getAlias()).path("endpoint").build();
boolean wantAuthnRequestsSigned = getConfig().isWantAuthnRequestsSigned();
boolean wantAssertionsSigned = getConfig().isWantAssertionsSigned();
boolean wantAssertionsEncrypted = getConfig().isWantAssertionsEncrypted();
String entityId = getEntityId(uriInfo, realm);
String nameIDPolicyFormat = getConfig().getNameIDPolicyFormat();
List<Element> signingKeys = new LinkedList<>();
List<Element> encryptionKeys = new LinkedList<>();
session.keys().getKeysStream(realm, KeyUse.SIG, Algorithm.RS256).filter(Objects::nonNull).filter(key -> key.getCertificate() != null).sorted(SamlService::compareKeys).forEach(key -> {
try {
Element element = SPMetadataDescriptor.buildKeyInfoElement(key.getKid(), PemUtils.encodeCertificate(key.getCertificate()));
signingKeys.add(element);
if (key.getStatus() == KeyStatus.ACTIVE) {
encryptionKeys.add(element);
}
} catch (ParserConfigurationException e) {
logger.warn("Failed to export SAML SP Metadata!", e);
throw new RuntimeException(e);
}
});
// Prepare the metadata descriptor model
StringWriter sw = new StringWriter();
XMLStreamWriter writer = StaxUtil.getXMLStreamWriter(sw);
SAMLMetadataWriter metadataWriter = new SAMLMetadataWriter(writer);
EntityDescriptorType entityDescriptor = SPMetadataDescriptor.buildSPdescriptor(authnBinding, authnBinding, endpoint, endpoint, wantAuthnRequestsSigned, wantAssertionsSigned, wantAssertionsEncrypted, entityId, nameIDPolicyFormat, signingKeys, encryptionKeys);
// Create the AttributeConsumingService if at least one attribute importer mapper exists
List<Entry<IdentityProviderMapperModel, SamlMetadataDescriptorUpdater>> metadataAttrProviders = new ArrayList<>();
realm.getIdentityProviderMappersByAliasStream(getConfig().getAlias()).forEach(mapper -> {
IdentityProviderMapper target = (IdentityProviderMapper) session.getKeycloakSessionFactory().getProviderFactory(IdentityProviderMapper.class, mapper.getIdentityProviderMapper());
if (target instanceof SamlMetadataDescriptorUpdater)
metadataAttrProviders.add(new java.util.AbstractMap.SimpleEntry<>(mapper, (SamlMetadataDescriptorUpdater) target));
});
if (!metadataAttrProviders.isEmpty()) {
int attributeConsumingServiceIndex = getConfig().getAttributeConsumingServiceIndex() != null ? getConfig().getAttributeConsumingServiceIndex() : 1;
String attributeConsumingServiceName = getConfig().getAttributeConsumingServiceName();
// default value for attributeConsumingServiceName
if (attributeConsumingServiceName == null)
attributeConsumingServiceName = realm.getDisplayName() != null ? realm.getDisplayName() : realm.getName();
AttributeConsumingServiceType attributeConsumingService = new AttributeConsumingServiceType(attributeConsumingServiceIndex);
attributeConsumingService.setIsDefault(true);
String currentLocale = realm.getDefaultLocale() == null ? "en" : realm.getDefaultLocale();
LocalizedNameType attributeConsumingServiceNameElement = new LocalizedNameType(currentLocale);
attributeConsumingServiceNameElement.setValue(attributeConsumingServiceName);
attributeConsumingService.addServiceName(attributeConsumingServiceNameElement);
// Look for the SP descriptor and add the attribute consuming service
for (EntityDescriptorType.EDTChoiceType choiceType : entityDescriptor.getChoiceType()) {
List<EntityDescriptorType.EDTDescriptorChoiceType> descriptors = choiceType.getDescriptors();
for (EntityDescriptorType.EDTDescriptorChoiceType descriptor : descriptors) {
descriptor.getSpDescriptor().addAttributeConsumerService(attributeConsumingService);
}
}
// Add the attribute mappers
metadataAttrProviders.forEach(mapper -> {
SamlMetadataDescriptorUpdater metadataAttrProvider = mapper.getValue();
metadataAttrProvider.updateMetadata(mapper.getKey(), entityDescriptor);
});
}
// Write the metadata and export it to a string
metadataWriter.writeEntityDescriptor(entityDescriptor);
String descriptor = sw.toString();
// Metadata signing
if (getConfig().isSignSpMetadata()) {
KeyManager.ActiveRsaKey activeKey = session.keys().getActiveRsaKey(realm);
String keyName = getConfig().getXmlSigKeyInfoKeyNameTransformer().getKeyName(activeKey.getKid(), activeKey.getCertificate());
KeyPair keyPair = new KeyPair(activeKey.getPublicKey(), activeKey.getPrivateKey());
Document metadataDocument = DocumentUtil.getDocument(descriptor);
SAML2Signature signatureHelper = new SAML2Signature();
signatureHelper.setSignatureMethod(getSignatureAlgorithm().getXmlSignatureMethod());
signatureHelper.setDigestMethod(getSignatureAlgorithm().getXmlSignatureDigestMethod());
Node nextSibling = metadataDocument.getDocumentElement().getFirstChild();
signatureHelper.setNextSibling(nextSibling);
signatureHelper.signSAMLDocument(metadataDocument, keyName, keyPair, CanonicalizationMethod.EXCLUSIVE);
descriptor = DocumentUtil.getDocumentAsString(metadataDocument);
}
return Response.ok(descriptor, MediaType.APPLICATION_XML_TYPE).build();
} catch (Exception e) {
logger.warn("Failed to export SAML SP Metadata!", e);
throw new RuntimeException(e);
}
}
use of org.keycloak.broker.provider.IdentityProviderMapper in project keycloak by keycloak.
the class IdentityBrokerService method authenticated.
public Response authenticated(BrokeredIdentityContext context) {
IdentityProviderModel identityProviderConfig = context.getIdpConfig();
AuthenticationSessionModel authenticationSession = context.getAuthenticationSession();
String providerId = identityProviderConfig.getAlias();
if (!identityProviderConfig.isStoreToken()) {
if (isDebugEnabled()) {
logger.debugf("Token will not be stored for identity provider [%s].", providerId);
}
context.setToken(null);
}
StatusResponseType loginResponse = (StatusResponseType) context.getContextData().get(SAMLEndpoint.SAML_LOGIN_RESPONSE);
if (loginResponse != null) {
for (Iterator<SamlAuthenticationPreprocessor> it = SamlSessionUtils.getSamlAuthenticationPreprocessorIterator(session); it.hasNext(); ) {
loginResponse = it.next().beforeProcessingLoginResponse(loginResponse, authenticationSession);
}
}
session.getContext().setClient(authenticationSession.getClient());
context.getIdp().preprocessFederatedIdentity(session, realmModel, context);
KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
realmModel.getIdentityProviderMappersByAliasStream(context.getIdpConfig().getAlias()).forEach(mapper -> {
IdentityProviderMapper target = (IdentityProviderMapper) sessionFactory.getProviderFactory(IdentityProviderMapper.class, mapper.getIdentityProviderMapper());
target.preprocessFederatedIdentity(session, realmModel, mapper, context);
});
FederatedIdentityModel federatedIdentityModel = new FederatedIdentityModel(providerId, context.getId(), context.getUsername(), context.getToken());
this.event.event(EventType.IDENTITY_PROVIDER_LOGIN).detail(Details.REDIRECT_URI, authenticationSession.getRedirectUri()).detail(Details.IDENTITY_PROVIDER, providerId).detail(Details.IDENTITY_PROVIDER_USERNAME, context.getUsername());
UserModel federatedUser = this.session.users().getUserByFederatedIdentity(this.realmModel, federatedIdentityModel);
boolean shouldMigrateId = false;
// try to find the user using legacy ID
if (federatedUser == null && context.getLegacyId() != null) {
federatedIdentityModel = new FederatedIdentityModel(federatedIdentityModel, context.getLegacyId());
federatedUser = this.session.users().getUserByFederatedIdentity(this.realmModel, federatedIdentityModel);
shouldMigrateId = true;
}
// Check if federatedUser is already authenticated (this means linking social into existing federatedUser account)
UserSessionModel userSession = new AuthenticationSessionManager(session).getUserSession(authenticationSession);
if (shouldPerformAccountLinking(authenticationSession, userSession, providerId)) {
return performAccountLinking(authenticationSession, userSession, context, federatedIdentityModel, federatedUser);
}
if (federatedUser == null) {
logger.debugf("Federated user not found for provider '%s' and broker username '%s'", providerId, context.getUsername());
String username = context.getModelUsername();
if (username == null) {
if (this.realmModel.isRegistrationEmailAsUsername() && !Validation.isBlank(context.getEmail())) {
username = context.getEmail();
} else if (context.getUsername() == null) {
username = context.getIdpConfig().getAlias() + "." + context.getId();
} else {
username = context.getUsername();
}
}
username = username.trim();
context.setModelUsername(username);
SerializedBrokeredIdentityContext ctx0 = SerializedBrokeredIdentityContext.readFromAuthenticationSession(authenticationSession, AbstractIdpAuthenticator.BROKERED_CONTEXT_NOTE);
if (ctx0 != null) {
SerializedBrokeredIdentityContext ctx1 = SerializedBrokeredIdentityContext.serialize(context);
ctx1.saveToAuthenticationSession(authenticationSession, AbstractIdpAuthenticator.NESTED_FIRST_BROKER_CONTEXT);
logger.warnv("Nested first broker flow detected: {0} -> {1}", ctx0.getIdentityProviderId(), ctx1.getIdentityProviderId());
logger.debug("Resuming last execution");
URI redirect = new AuthenticationFlowURLHelper(session, realmModel, session.getContext().getUri()).getLastExecutionUrl(authenticationSession);
return Response.status(Status.FOUND).location(redirect).build();
}
logger.debug("Redirecting to flow for firstBrokerLogin");
boolean forwardedPassiveLogin = "true".equals(authenticationSession.getAuthNote(AuthenticationProcessor.FORWARDED_PASSIVE_LOGIN));
// Redirect to firstBrokerLogin after successful login and ensure that previous authentication state removed
AuthenticationProcessor.resetFlow(authenticationSession, LoginActionsService.FIRST_BROKER_LOGIN_PATH);
// Set the FORWARDED_PASSIVE_LOGIN note (if needed) after resetting the session so it is not lost.
if (forwardedPassiveLogin) {
authenticationSession.setAuthNote(AuthenticationProcessor.FORWARDED_PASSIVE_LOGIN, "true");
}
SerializedBrokeredIdentityContext ctx = SerializedBrokeredIdentityContext.serialize(context);
ctx.saveToAuthenticationSession(authenticationSession, AbstractIdpAuthenticator.BROKERED_CONTEXT_NOTE);
URI redirect = LoginActionsService.firstBrokerLoginProcessor(session.getContext().getUri()).queryParam(Constants.CLIENT_ID, authenticationSession.getClient().getClientId()).queryParam(Constants.TAB_ID, authenticationSession.getTabId()).build(realmModel.getName());
return Response.status(302).location(redirect).build();
} else {
Response response = validateUser(authenticationSession, federatedUser, realmModel);
if (response != null) {
return response;
}
updateFederatedIdentity(context, federatedUser);
if (shouldMigrateId) {
migrateFederatedIdentityId(context, federatedUser);
}
authenticationSession.setAuthenticatedUser(federatedUser);
return finishOrRedirectToPostBrokerLogin(authenticationSession, context, false);
}
}
use of org.keycloak.broker.provider.IdentityProviderMapper in project keycloak by keycloak.
the class IdentityBrokerService method updateFederatedIdentity.
private void updateFederatedIdentity(BrokeredIdentityContext context, UserModel federatedUser) {
FederatedIdentityModel federatedIdentityModel = this.session.users().getFederatedIdentity(this.realmModel, federatedUser, context.getIdpConfig().getAlias());
if (context.getIdpConfig().getSyncMode() == IdentityProviderSyncMode.FORCE) {
setBasicUserAttributes(context, federatedUser);
}
// Skip DB write if tokens are null or equal
updateToken(context, federatedUser, federatedIdentityModel);
context.getIdp().updateBrokeredUser(session, realmModel, federatedUser, context);
KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
realmModel.getIdentityProviderMappersByAliasStream(context.getIdpConfig().getAlias()).forEach(mapper -> {
IdentityProviderMapper target = (IdentityProviderMapper) sessionFactory.getProviderFactory(IdentityProviderMapper.class, mapper.getIdentityProviderMapper());
IdentityProviderMapperSyncModeDelegate.delegateUpdateBrokeredUser(session, realmModel, federatedUser, mapper, context, target);
});
}
use of org.keycloak.broker.provider.IdentityProviderMapper in project keycloak by keycloak.
the class IdentityBrokerService method afterFirstBrokerLogin.
private Response afterFirstBrokerLogin(AuthenticationSessionModel authSession) {
try {
this.event.detail(Details.CODE_ID, authSession.getParentSession().getId()).removeDetail("auth_method");
SerializedBrokeredIdentityContext serializedCtx = SerializedBrokeredIdentityContext.readFromAuthenticationSession(authSession, AbstractIdpAuthenticator.BROKERED_CONTEXT_NOTE);
if (serializedCtx == null) {
throw new IdentityBrokerException("Not found serialized context in clientSession");
}
BrokeredIdentityContext context = serializedCtx.deserialize(session, authSession);
String providerId = context.getIdpConfig().getAlias();
event.detail(Details.IDENTITY_PROVIDER, providerId);
event.detail(Details.IDENTITY_PROVIDER_USERNAME, context.getUsername());
// Ensure the first-broker-login flow was successfully finished
String authProvider = authSession.getAuthNote(AbstractIdpAuthenticator.FIRST_BROKER_LOGIN_SUCCESS);
if (authProvider == null || !authProvider.equals(providerId)) {
throw new IdentityBrokerException("Invalid request. Not found the flag that first-broker-login flow was finished");
}
// firstBrokerLogin workflow finished. Removing note now
authSession.removeAuthNote(AbstractIdpAuthenticator.BROKERED_CONTEXT_NOTE);
UserModel federatedUser = authSession.getAuthenticatedUser();
if (federatedUser == null) {
throw new IdentityBrokerException("Couldn't found authenticated federatedUser in authentication session");
}
event.user(federatedUser);
event.detail(Details.USERNAME, federatedUser.getUsername());
if (context.getIdpConfig().isAddReadTokenRoleOnCreate()) {
ClientModel brokerClient = realmModel.getClientByClientId(Constants.BROKER_SERVICE_CLIENT_ID);
if (brokerClient == null) {
throw new IdentityBrokerException("Client 'broker' not available. Maybe realm has not migrated to support the broker token exchange service");
}
RoleModel readTokenRole = brokerClient.getRole(Constants.READ_TOKEN_ROLE);
federatedUser.grantRole(readTokenRole);
}
// Add federated identity link here
FederatedIdentityModel federatedIdentityModel = new FederatedIdentityModel(context.getIdpConfig().getAlias(), context.getId(), context.getUsername(), context.getToken());
session.users().addFederatedIdentity(realmModel, federatedUser, federatedIdentityModel);
String isRegisteredNewUser = authSession.getAuthNote(AbstractIdpAuthenticator.BROKER_REGISTERED_NEW_USER);
if (Boolean.parseBoolean(isRegisteredNewUser)) {
logger.debugf("Registered new user '%s' after first login with identity provider '%s'. Identity provider username is '%s' . ", federatedUser.getUsername(), providerId, context.getUsername());
context.getIdp().importNewUser(session, realmModel, federatedUser, context);
KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
realmModel.getIdentityProviderMappersByAliasStream(providerId).forEach(mapper -> {
IdentityProviderMapper target = (IdentityProviderMapper) sessionFactory.getProviderFactory(IdentityProviderMapper.class, mapper.getIdentityProviderMapper());
target.importNewUser(session, realmModel, federatedUser, mapper, context);
});
if (context.getIdpConfig().isTrustEmail() && !Validation.isBlank(federatedUser.getEmail()) && !Boolean.parseBoolean(authSession.getAuthNote(AbstractIdpAuthenticator.UPDATE_PROFILE_EMAIL_CHANGED))) {
logger.debugf("Email verified automatically after registration of user '%s' through Identity provider '%s' ", federatedUser.getUsername(), context.getIdpConfig().getAlias());
federatedUser.setEmailVerified(true);
}
event.event(EventType.REGISTER).detail(Details.REGISTER_METHOD, "broker").detail(Details.EMAIL, federatedUser.getEmail()).success();
} else {
logger.debugf("Linked existing keycloak user '%s' with identity provider '%s' . Identity provider username is '%s' .", federatedUser.getUsername(), providerId, context.getUsername());
event.event(EventType.FEDERATED_IDENTITY_LINK).success();
updateFederatedIdentity(context, federatedUser);
}
return finishOrRedirectToPostBrokerLogin(authSession, context, true);
} catch (Exception e) {
return redirectToErrorPage(authSession, Response.Status.INTERNAL_SERVER_ERROR, Messages.IDENTITY_PROVIDER_UNEXPECTED_ERROR, e);
}
}
Aggregations