Search in sources :

Example 1 with LDAPStorageMapper

use of org.keycloak.storage.ldap.mappers.LDAPStorageMapper in project keycloak by keycloak.

the class LDAPStorageProvider method importUserFromLDAP.

protected UserModel importUserFromLDAP(KeycloakSession session, RealmModel realm, LDAPObject ldapUser) {
    String ldapUsername = LDAPUtils.getUsername(ldapUser, ldapIdentityStore.getConfig());
    LDAPUtils.checkUuid(ldapUser, ldapIdentityStore.getConfig());
    UserModel imported = null;
    if (model.isImportEnabled()) {
        // Search if there is already an existing user, which means the username might have changed in LDAP without Keycloak knowing about it
        UserModel existingLocalUser = session.userLocalStorage().searchForUserByUserAttributeStream(realm, LDAPConstants.LDAP_ID, ldapUser.getUuid()).findFirst().orElse(null);
        if (existingLocalUser != null) {
            imported = existingLocalUser;
            // Need to evict the existing user from cache
            if (session.userCache() != null) {
                session.userCache().evict(realm, existingLocalUser);
            }
        } else {
            imported = session.userLocalStorage().addUser(realm, ldapUsername);
        }
    } else {
        InMemoryUserAdapter adapter = new InMemoryUserAdapter(session, realm, new StorageId(model.getId(), ldapUsername).getId());
        adapter.addDefaults();
        imported = adapter;
    }
    imported.setEnabled(true);
    UserModel finalImported = imported;
    realm.getComponentsStream(model.getId(), LDAPStorageMapper.class.getName()).sorted(ldapMappersComparator.sortDesc()).forEachOrdered(mapperModel -> {
        if (logger.isTraceEnabled()) {
            logger.tracef("Using mapper %s during import user from LDAP", mapperModel);
        }
        LDAPStorageMapper ldapMapper = mapperManager.getMapper(mapperModel);
        ldapMapper.onImportUserFromLDAP(ldapUser, finalImported, realm, true);
    });
    String userDN = ldapUser.getDn().toString();
    if (model.isImportEnabled())
        imported.setFederationLink(model.getId());
    imported.setSingleAttribute(LDAPConstants.LDAP_ID, ldapUser.getUuid());
    imported.setSingleAttribute(LDAPConstants.LDAP_ENTRY_DN, userDN);
    if (getLdapIdentityStore().getConfig().isTrustEmail()) {
        imported.setEmailVerified(true);
    }
    logger.debugf("Imported new user from LDAP to Keycloak DB. Username: [%s], Email: [%s], LDAP_ID: [%s], LDAP Entry DN: [%s]", imported.getUsername(), imported.getEmail(), ldapUser.getUuid(), userDN);
    UserModel proxy = proxy(realm, imported, ldapUser, false);
    return proxy;
}
Also used : CachedUserModel(org.keycloak.models.cache.CachedUserModel) UserModel(org.keycloak.models.UserModel) LDAPStorageMapper(org.keycloak.storage.ldap.mappers.LDAPStorageMapper) InMemoryUserAdapter(org.keycloak.storage.adapter.InMemoryUserAdapter) StorageId(org.keycloak.storage.StorageId)

Example 2 with LDAPStorageMapper

use of org.keycloak.storage.ldap.mappers.LDAPStorageMapper in project keycloak by keycloak.

the class LDAPStorageProvider method proxy.

protected UserModel proxy(RealmModel realm, UserModel local, LDAPObject ldapObject, boolean newUser) {
    UserModel existing = userManager.getManagedProxiedUser(local.getId());
    if (existing != null) {
        return existing;
    }
    // We need to avoid having CachedUserModel as cache is upper-layer then LDAP. Hence having CachedUserModel here may cause StackOverflowError
    if (local instanceof CachedUserModel) {
        local = session.userStorageManager().getUserById(realm, local.getId());
        existing = userManager.getManagedProxiedUser(local.getId());
        if (existing != null) {
            return existing;
        }
    }
    UserModel proxied = local;
    checkDNChanged(realm, local, ldapObject);
    switch(editMode) {
        case READ_ONLY:
            if (model.isImportEnabled()) {
                proxied = new ReadonlyLDAPUserModelDelegate(local);
            } else {
                proxied = new ReadOnlyUserModelDelegate(local);
            }
            break;
        case WRITABLE:
        case UNSYNCED:
            // This check is skipped when register new user as there are many "generic" attributes always written (EG. enabled, emailVerified) and those are usually unsupported by LDAP schema
            if (!model.isImportEnabled() && !newUser) {
                UserModel readOnlyDelegate = new ReadOnlyUserModelDelegate(local, ModelException::new);
                proxied = new LDAPWritesOnlyUserModelDelegate(readOnlyDelegate, this);
            }
            break;
    }
    AtomicReference<UserModel> proxy = new AtomicReference<>(proxied);
    realm.getComponentsStream(model.getId(), LDAPStorageMapper.class.getName()).sorted(ldapMappersComparator.sortAsc()).forEachOrdered(mapperModel -> {
        LDAPStorageMapper ldapMapper = mapperManager.getMapper(mapperModel);
        proxy.set(ldapMapper.proxy(ldapObject, proxy.get(), realm));
    });
    proxied = proxy.get();
    if (!model.isImportEnabled()) {
        proxied = new UpdateOnlyChangeUserModelDelegate(proxied);
    }
    userManager.setManagedProxiedUser(proxied, ldapObject);
    return proxied;
}
Also used : CachedUserModel(org.keycloak.models.cache.CachedUserModel) UserModel(org.keycloak.models.UserModel) ReadOnlyUserModelDelegate(org.keycloak.models.utils.ReadOnlyUserModelDelegate) LDAPStorageMapper(org.keycloak.storage.ldap.mappers.LDAPStorageMapper) ModelException(org.keycloak.models.ModelException) CachedUserModel(org.keycloak.models.cache.CachedUserModel) AtomicReference(java.util.concurrent.atomic.AtomicReference) UpdateOnlyChangeUserModelDelegate(org.keycloak.storage.adapter.UpdateOnlyChangeUserModelDelegate)

Example 3 with LDAPStorageMapper

use of org.keycloak.storage.ldap.mappers.LDAPStorageMapper in project keycloak by keycloak.

the class LDAPQuery method getResultList.

public List<LDAPObject> getResultList() {
    // Apply mappers now
    LDAPMappersComparator ldapMappersComparator = new LDAPMappersComparator(ldapFedProvider.getLdapIdentityStore().getConfig());
    Collections.sort(mappers, ldapMappersComparator.sortAsc());
    for (ComponentModel mapperModel : mappers) {
        LDAPStorageMapper fedMapper = ldapFedProvider.getMapperManager().getMapper(mapperModel);
        fedMapper.beforeLDAPQuery(this);
    }
    List<LDAPObject> result = new ArrayList<LDAPObject>();
    try {
        for (LDAPObject ldapObject : ldapFedProvider.getLdapIdentityStore().fetchQueryResults(this)) {
            result.add(ldapObject);
        }
    } catch (Exception e) {
        throw new ModelException("LDAP Query failed", e);
    }
    return result;
}
Also used : LDAPStorageMapper(org.keycloak.storage.ldap.mappers.LDAPStorageMapper) LDAPMappersComparator(org.keycloak.storage.ldap.mappers.LDAPMappersComparator) ModelException(org.keycloak.models.ModelException) ComponentModel(org.keycloak.component.ComponentModel) LDAPObject(org.keycloak.storage.ldap.idm.model.LDAPObject) NamingException(javax.naming.NamingException) ModelException(org.keycloak.models.ModelException) ModelDuplicateException(org.keycloak.models.ModelDuplicateException)

Example 4 with LDAPStorageMapper

use of org.keycloak.storage.ldap.mappers.LDAPStorageMapper in project keycloak by keycloak.

the class LDAPUtils method addUserToLDAP.

/**
 * @param ldapProvider
 * @param realm
 * @param user
 * @return newly created LDAPObject with all the attributes, uuid and DN properly set
 */
public static LDAPObject addUserToLDAP(LDAPStorageProvider ldapProvider, RealmModel realm, UserModel user) {
    LDAPObject ldapUser = new LDAPObject();
    LDAPIdentityStore ldapStore = ldapProvider.getLdapIdentityStore();
    LDAPConfig ldapConfig = ldapStore.getConfig();
    ldapUser.setRdnAttributeName(ldapConfig.getRdnLdapAttribute());
    ldapUser.setObjectClasses(ldapConfig.getUserObjectClasses());
    LDAPMappersComparator ldapMappersComparator = new LDAPMappersComparator(ldapConfig);
    realm.getComponentsStream(ldapProvider.getModel().getId(), LDAPStorageMapper.class.getName()).sorted(ldapMappersComparator.sortAsc()).forEachOrdered(mapperModel -> {
        LDAPStorageMapper ldapMapper = ldapProvider.getMapperManager().getMapper(mapperModel);
        ldapMapper.onRegisterUserToLDAP(ldapUser, user, realm);
    });
    LDAPUtils.computeAndSetDn(ldapConfig, ldapUser);
    ldapStore.add(ldapUser);
    return ldapUser;
}
Also used : LDAPIdentityStore(org.keycloak.storage.ldap.idm.store.ldap.LDAPIdentityStore) LDAPStorageMapper(org.keycloak.storage.ldap.mappers.LDAPStorageMapper) LDAPMappersComparator(org.keycloak.storage.ldap.mappers.LDAPMappersComparator) LDAPObject(org.keycloak.storage.ldap.idm.model.LDAPObject)

Example 5 with LDAPStorageMapper

use of org.keycloak.storage.ldap.mappers.LDAPStorageMapper in project keycloak by keycloak.

the class LDAPStorageProviderFactory method importLdapUsers.

protected SynchronizationResult importLdapUsers(KeycloakSessionFactory sessionFactory, final String realmId, final ComponentModel fedModel, List<LDAPObject> ldapUsers) {
    final SynchronizationResult syncResult = new SynchronizationResult();
    class BooleanHolder {

        private boolean value = true;
    }
    final BooleanHolder exists = new BooleanHolder();
    for (final LDAPObject ldapUser : ldapUsers) {
        try {
            // Process each user in it's own transaction to avoid global fail
            KeycloakModelUtils.runJobInTransaction(sessionFactory, new KeycloakSessionTask() {

                @Override
                public void run(KeycloakSession session) {
                    LDAPStorageProvider ldapFedProvider = (LDAPStorageProvider) session.getProvider(UserStorageProvider.class, fedModel);
                    RealmModel currentRealm = session.realms().getRealm(realmId);
                    session.getContext().setRealm(currentRealm);
                    String username = LDAPUtils.getUsername(ldapUser, ldapFedProvider.getLdapIdentityStore().getConfig());
                    exists.value = true;
                    LDAPUtils.checkUuid(ldapUser, ldapFedProvider.getLdapIdentityStore().getConfig());
                    UserModel currentUserLocal = session.userLocalStorage().getUserByUsername(currentRealm, username);
                    Optional<UserModel> userModelOptional = session.userLocalStorage().searchForUserByUserAttributeStream(currentRealm, LDAPConstants.LDAP_ID, ldapUser.getUuid()).findFirst();
                    if (!userModelOptional.isPresent() && currentUserLocal == null) {
                        // Add new user to Keycloak
                        exists.value = false;
                        ldapFedProvider.importUserFromLDAP(session, currentRealm, ldapUser);
                        syncResult.increaseAdded();
                    } else {
                        UserModel currentUser = userModelOptional.isPresent() ? userModelOptional.get() : currentUserLocal;
                        if ((fedModel.getId().equals(currentUser.getFederationLink())) && (ldapUser.getUuid().equals(currentUser.getFirstAttribute(LDAPConstants.LDAP_ID)))) {
                            // Update keycloak user
                            LDAPMappersComparator ldapMappersComparator = new LDAPMappersComparator(ldapFedProvider.getLdapIdentityStore().getConfig());
                            currentRealm.getComponentsStream(fedModel.getId(), LDAPStorageMapper.class.getName()).sorted(ldapMappersComparator.sortDesc()).forEachOrdered(mapperModel -> {
                                LDAPStorageMapper ldapMapper = ldapFedProvider.getMapperManager().getMapper(mapperModel);
                                ldapMapper.onImportUserFromLDAP(ldapUser, currentUser, currentRealm, false);
                            });
                            UserCache userCache = session.userCache();
                            if (userCache != null) {
                                userCache.evict(currentRealm, currentUser);
                            }
                            logger.debugf("Updated user from LDAP: %s", currentUser.getUsername());
                            syncResult.increaseUpdated();
                        } else {
                            logger.warnf("User with ID '%s' is not updated during sync as he already exists in Keycloak database but is not linked to federation provider '%s'", ldapUser.getUuid(), fedModel.getName());
                            syncResult.increaseFailed();
                        }
                    }
                }
            });
        } catch (ModelException me) {
            logger.error("Failed during import user from LDAP", me);
            syncResult.increaseFailed();
            // Remove user if we already added him during this transaction
            if (!exists.value) {
                KeycloakModelUtils.runJobInTransaction(sessionFactory, new KeycloakSessionTask() {

                    @Override
                    public void run(KeycloakSession session) {
                        LDAPStorageProvider ldapFedProvider = (LDAPStorageProvider) session.getProvider(UserStorageProvider.class, fedModel);
                        RealmModel currentRealm = session.realms().getRealm(realmId);
                        session.getContext().setRealm(currentRealm);
                        String username = null;
                        try {
                            username = LDAPUtils.getUsername(ldapUser, ldapFedProvider.getLdapIdentityStore().getConfig());
                        } catch (ModelException ignore) {
                        }
                        if (username != null) {
                            UserModel existing = session.userLocalStorage().getUserByUsername(currentRealm, username);
                            if (existing != null) {
                                UserCache userCache = session.userCache();
                                if (userCache != null) {
                                    userCache.evict(currentRealm, existing);
                                }
                                session.userLocalStorage().removeUser(currentRealm, existing);
                            }
                        }
                    }
                });
            }
        }
    }
    return syncResult;
}
Also used : SPNEGOAuthenticator(org.keycloak.federation.kerberos.impl.SPNEGOAuthenticator) FullNameLDAPStorageMapperFactory(org.keycloak.storage.ldap.mappers.FullNameLDAPStorageMapperFactory) Date(java.util.Date) LDAPStorageMapper(org.keycloak.storage.ldap.mappers.LDAPStorageMapper) Config(org.keycloak.Config) FullNameLDAPStorageMapper(org.keycloak.storage.ldap.mappers.FullNameLDAPStorageMapper) ProviderConfigurationBuilder(org.keycloak.provider.ProviderConfigurationBuilder) LDAPConstants(org.keycloak.models.LDAPConstants) Map(java.util.Map) ComponentModel(org.keycloak.component.ComponentModel) CredentialRepresentation(org.keycloak.representations.idm.CredentialRepresentation) UserStorageProviderModel(org.keycloak.storage.UserStorageProviderModel) UserAttributeLDAPStorageMapperFactory(org.keycloak.storage.ldap.mappers.UserAttributeLDAPStorageMapperFactory) UserStorageProviderFactory(org.keycloak.storage.UserStorageProviderFactory) HardcodedLDAPAttributeMapper(org.keycloak.storage.ldap.mappers.HardcodedLDAPAttributeMapper) HardcodedLDAPAttributeMapperFactory(org.keycloak.storage.ldap.mappers.HardcodedLDAPAttributeMapperFactory) RealmModel(org.keycloak.models.RealmModel) LDAPConfigDecorator(org.keycloak.storage.ldap.mappers.LDAPConfigDecorator) CredentialHelper(org.keycloak.utils.CredentialHelper) CommonKerberosConfig(org.keycloak.federation.kerberos.CommonKerberosConfig) Collectors(java.util.stream.Collectors) LDAPObject(org.keycloak.storage.ldap.idm.model.LDAPObject) ImportSynchronization(org.keycloak.storage.user.ImportSynchronization) List(java.util.List) UserAttributeLDAPStorageMapper(org.keycloak.storage.ldap.mappers.UserAttributeLDAPStorageMapper) KerberosUsernamePasswordAuthenticator(org.keycloak.federation.kerberos.impl.KerberosUsernamePasswordAuthenticator) KeycloakSessionFactory(org.keycloak.models.KeycloakSessionFactory) Optional(java.util.Optional) Condition(org.keycloak.storage.ldap.idm.query.Condition) ComponentValidationException(org.keycloak.component.ComponentValidationException) KeycloakModelUtils(org.keycloak.models.utils.KeycloakModelUtils) Logger(org.jboss.logging.Logger) ProviderConfigProperty(org.keycloak.provider.ProviderConfigProperty) Function(java.util.function.Function) LDAPIdentityStore(org.keycloak.storage.ldap.idm.store.ldap.LDAPIdentityStore) UserModel(org.keycloak.models.UserModel) AuthenticationExecutionModel(org.keycloak.models.AuthenticationExecutionModel) KeycloakSessionTask(org.keycloak.models.KeycloakSessionTask) LDAPQueryConditionsBuilder(org.keycloak.storage.ldap.idm.query.internal.LDAPQueryConditionsBuilder) KerberosConstants(org.keycloak.common.constants.KerberosConstants) UserStorageProvider(org.keycloak.storage.UserStorageProvider) LDAPMappersComparator(org.keycloak.storage.ldap.mappers.LDAPMappersComparator) KerberosServerSubjectAuthenticator(org.keycloak.federation.kerberos.impl.KerberosServerSubjectAuthenticator) KeycloakSession(org.keycloak.models.KeycloakSession) LDAPQuery(org.keycloak.storage.ldap.idm.query.internal.LDAPQuery) UserCache(org.keycloak.models.cache.UserCache) MSADUserAccountControlStorageMapperFactory(org.keycloak.storage.ldap.mappers.msad.MSADUserAccountControlStorageMapperFactory) ModelException(org.keycloak.models.ModelException) SynchronizationResult(org.keycloak.storage.user.SynchronizationResult) LDAPStorageMapper(org.keycloak.storage.ldap.mappers.LDAPStorageMapper) FullNameLDAPStorageMapper(org.keycloak.storage.ldap.mappers.FullNameLDAPStorageMapper) UserAttributeLDAPStorageMapper(org.keycloak.storage.ldap.mappers.UserAttributeLDAPStorageMapper) Optional(java.util.Optional) LDAPMappersComparator(org.keycloak.storage.ldap.mappers.LDAPMappersComparator) ModelException(org.keycloak.models.ModelException) UserCache(org.keycloak.models.cache.UserCache) RealmModel(org.keycloak.models.RealmModel) UserModel(org.keycloak.models.UserModel) UserStorageProvider(org.keycloak.storage.UserStorageProvider) KeycloakSessionTask(org.keycloak.models.KeycloakSessionTask) KeycloakSession(org.keycloak.models.KeycloakSession) LDAPObject(org.keycloak.storage.ldap.idm.model.LDAPObject) SynchronizationResult(org.keycloak.storage.user.SynchronizationResult)

Aggregations

LDAPStorageMapper (org.keycloak.storage.ldap.mappers.LDAPStorageMapper)6 ComponentModel (org.keycloak.component.ComponentModel)3 ModelException (org.keycloak.models.ModelException)3 UserModel (org.keycloak.models.UserModel)3 LDAPObject (org.keycloak.storage.ldap.idm.model.LDAPObject)3 LDAPMappersComparator (org.keycloak.storage.ldap.mappers.LDAPMappersComparator)3 CachedUserModel (org.keycloak.models.cache.CachedUserModel)2 UserStorageProvider (org.keycloak.storage.UserStorageProvider)2 LDAPIdentityStore (org.keycloak.storage.ldap.idm.store.ldap.LDAPIdentityStore)2 SynchronizationResult (org.keycloak.storage.user.SynchronizationResult)2 Date (java.util.Date)1 HashMap (java.util.HashMap)1 List (java.util.List)1 Map (java.util.Map)1 Optional (java.util.Optional)1 AtomicReference (java.util.concurrent.atomic.AtomicReference)1 Function (java.util.function.Function)1 Collectors (java.util.stream.Collectors)1 NamingException (javax.naming.NamingException)1 BadRequestException (javax.ws.rs.BadRequestException)1