remove realm UserFed SPI methods
This commit is contained in:
parent
2da9986717
commit
d5925b8ccf
47 changed files with 223 additions and 3114 deletions
|
@ -172,9 +172,6 @@ public interface RealmResource {
|
||||||
@Path("attack-detection")
|
@Path("attack-detection")
|
||||||
AttackDetectionResource attackDetection();
|
AttackDetectionResource attackDetection();
|
||||||
|
|
||||||
@Path("user-federation")
|
|
||||||
UserFederationProvidersResource userFederation();
|
|
||||||
|
|
||||||
@Path("testLDAPConnection")
|
@Path("testLDAPConnection")
|
||||||
@GET
|
@GET
|
||||||
@NoCache
|
@NoCache
|
||||||
|
|
|
@ -634,38 +634,6 @@ public class RealmAdapter implements CachedRealmModel {
|
||||||
updated.removeIdentityProviderByAlias(alias);
|
updated.removeIdentityProviderByAlias(alias);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<UserFederationProviderModel> getUserFederationProviders() {
|
|
||||||
if (isUpdated()) return updated.getUserFederationProviders();
|
|
||||||
return cached.getUserFederationProviders();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setUserFederationProviders(List<UserFederationProviderModel> providers) {
|
|
||||||
getDelegateForUpdate();
|
|
||||||
updated.setUserFederationProviders(providers);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UserFederationProviderModel addUserFederationProvider(String providerName, Map<String, String> config, int priority, String displayName, int fullSyncPeriod, int changedSyncPeriod, int lastSync) {
|
|
||||||
getDelegateForUpdate();
|
|
||||||
return updated.addUserFederationProvider(providerName, config, priority, displayName, fullSyncPeriod, changedSyncPeriod, lastSync);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void removeUserFederationProvider(UserFederationProviderModel provider) {
|
|
||||||
getDelegateForUpdate();
|
|
||||||
updated.removeUserFederationProvider(provider);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateUserFederationProvider(UserFederationProviderModel provider) {
|
|
||||||
getDelegateForUpdate();
|
|
||||||
updated.updateUserFederationProvider(provider);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getLoginTheme() {
|
public String getLoginTheme() {
|
||||||
if (isUpdated()) return updated.getLoginTheme();
|
if (isUpdated()) return updated.getLoginTheme();
|
||||||
|
@ -952,63 +920,6 @@ public class RealmAdapter implements CachedRealmModel {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Set<UserFederationMapperModel> getUserFederationMappers() {
|
|
||||||
if (isUpdated()) return updated.getUserFederationMappers();
|
|
||||||
return cached.getUserFederationMapperSet();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Set<UserFederationMapperModel> getUserFederationMappersByFederationProvider(String federationProviderId) {
|
|
||||||
if (isUpdated()) return updated.getUserFederationMappersByFederationProvider(federationProviderId);
|
|
||||||
Set<UserFederationMapperModel> mappers = new HashSet<>();
|
|
||||||
List<UserFederationMapperModel> list = cached.getUserFederationMappers().getList(federationProviderId);
|
|
||||||
for (UserFederationMapperModel entity : list) {
|
|
||||||
mappers.add(entity);
|
|
||||||
}
|
|
||||||
return Collections.unmodifiableSet(mappers);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UserFederationMapperModel addUserFederationMapper(UserFederationMapperModel mapper) {
|
|
||||||
getDelegateForUpdate();
|
|
||||||
return updated.addUserFederationMapper(mapper);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void removeUserFederationMapper(UserFederationMapperModel mapper) {
|
|
||||||
getDelegateForUpdate();
|
|
||||||
updated.removeUserFederationMapper(mapper);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateUserFederationMapper(UserFederationMapperModel mapper) {
|
|
||||||
getDelegateForUpdate();
|
|
||||||
updated.updateUserFederationMapper(mapper);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UserFederationMapperModel getUserFederationMapperById(String id) {
|
|
||||||
if (isUpdated()) return updated.getUserFederationMapperById(id);
|
|
||||||
for (List<UserFederationMapperModel> models : cached.getUserFederationMappers().values()) {
|
|
||||||
for (UserFederationMapperModel model : models) {
|
|
||||||
if (model.getId().equals(id)) return model;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UserFederationMapperModel getUserFederationMapperByName(String federationProviderId, String name) {
|
|
||||||
if (isUpdated()) return updated.getUserFederationMapperByName(federationProviderId, name);
|
|
||||||
List<UserFederationMapperModel> models = cached.getUserFederationMappers().getList(federationProviderId);
|
|
||||||
if (models == null) return null;
|
|
||||||
for (UserFederationMapperModel model : models) {
|
|
||||||
if (model.getName().equals(name)) return model;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AuthenticationFlowModel getBrowserFlow() {
|
public AuthenticationFlowModel getBrowserFlow() {
|
||||||
if (isUpdated()) return updated.getBrowserFlow();
|
if (isUpdated()) return updated.getBrowserFlow();
|
||||||
|
|
|
@ -300,7 +300,7 @@ public class UserCacheSession implements UserCache {
|
||||||
// its also hard to test stuff
|
// its also hard to test stuff
|
||||||
boolean invalidate = false;
|
boolean invalidate = false;
|
||||||
if (policy != null) {
|
if (policy != null) {
|
||||||
String currentTime = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL).format(new Date(Time.currentTimeMillis()));
|
//String currentTime = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL).format(new Date(Time.currentTimeMillis()));
|
||||||
if (policy == UserStorageProviderModel.CachePolicy.NO_CACHE) {
|
if (policy == UserStorageProviderModel.CachePolicy.NO_CACHE) {
|
||||||
invalidate = true;
|
invalidate = true;
|
||||||
} else if (cached.getCacheTimestamp() < model.getCacheInvalidBefore()) {
|
} else if (cached.getCacheTimestamp() < model.getCacheInvalidBefore()) {
|
||||||
|
@ -317,8 +317,8 @@ public class UserCacheSession implements UserCache {
|
||||||
int oneWeek = 7 * 24 * 60 * 60 * 1000;
|
int oneWeek = 7 * 24 * 60 * 60 * 1000;
|
||||||
long weeklyTimeout = weeklyTimeout(model.getEvictionDay(), model.getEvictionHour(), model.getEvictionMinute());
|
long weeklyTimeout = weeklyTimeout(model.getEvictionDay(), model.getEvictionHour(), model.getEvictionMinute());
|
||||||
long lastTimeout = weeklyTimeout - oneWeek;
|
long lastTimeout = weeklyTimeout - oneWeek;
|
||||||
String timeout = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL).format(new Date(weeklyTimeout));
|
//String timeout = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL).format(new Date(weeklyTimeout));
|
||||||
String stamp = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL).format(new Date(cached.getCacheTimestamp()));
|
//String stamp = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL).format(new Date(cached.getCacheTimestamp()));
|
||||||
if (cached.getCacheTimestamp() <= lastTimeout) {
|
if (cached.getCacheTimestamp() <= lastTimeout) {
|
||||||
invalidate = true;
|
invalidate = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,8 +33,6 @@ import org.keycloak.models.PasswordPolicy;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.RequiredActionProviderModel;
|
import org.keycloak.models.RequiredActionProviderModel;
|
||||||
import org.keycloak.models.RequiredCredentialModel;
|
import org.keycloak.models.RequiredCredentialModel;
|
||||||
import org.keycloak.models.UserFederationMapperModel;
|
|
||||||
import org.keycloak.models.UserFederationProviderModel;
|
|
||||||
|
|
||||||
import java.security.PrivateKey;
|
import java.security.PrivateKey;
|
||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
|
@ -96,12 +94,9 @@ public class CachedRealm extends AbstractExtendableRevisioned {
|
||||||
protected String masterAdminClient;
|
protected String masterAdminClient;
|
||||||
|
|
||||||
protected List<RequiredCredentialModel> requiredCredentials;
|
protected List<RequiredCredentialModel> requiredCredentials;
|
||||||
protected List<UserFederationProviderModel> userFederationProviders;
|
|
||||||
protected MultivaluedHashMap<String, ComponentModel> componentsByParent = new MultivaluedHashMap<>();
|
protected MultivaluedHashMap<String, ComponentModel> componentsByParent = new MultivaluedHashMap<>();
|
||||||
protected MultivaluedHashMap<String, ComponentModel> componentsByParentAndType = new MultivaluedHashMap<>();
|
protected MultivaluedHashMap<String, ComponentModel> componentsByParentAndType = new MultivaluedHashMap<>();
|
||||||
protected Map<String, ComponentModel> components = new HashMap<>();
|
protected Map<String, ComponentModel> components = new HashMap<>();
|
||||||
protected MultivaluedHashMap<String, UserFederationMapperModel> userFederationMappers = new MultivaluedHashMap<String, UserFederationMapperModel>();
|
|
||||||
protected Set<UserFederationMapperModel> userFederationMapperSet;
|
|
||||||
protected List<IdentityProviderModel> identityProviders;
|
protected List<IdentityProviderModel> identityProviders;
|
||||||
|
|
||||||
protected Map<String, String> browserSecurityHeaders;
|
protected Map<String, String> browserSecurityHeaders;
|
||||||
|
@ -187,11 +182,6 @@ public class CachedRealm extends AbstractExtendableRevisioned {
|
||||||
emailTheme = model.getEmailTheme();
|
emailTheme = model.getEmailTheme();
|
||||||
|
|
||||||
requiredCredentials = model.getRequiredCredentials();
|
requiredCredentials = model.getRequiredCredentials();
|
||||||
userFederationProviders = model.getUserFederationProviders();
|
|
||||||
userFederationMapperSet = model.getUserFederationMappers();
|
|
||||||
for (UserFederationMapperModel mapper : userFederationMapperSet) {
|
|
||||||
this.userFederationMappers.add(mapper.getFederationProviderId(), mapper);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.identityProviders = new ArrayList<>();
|
this.identityProviders = new ArrayList<>();
|
||||||
|
|
||||||
|
@ -462,14 +452,6 @@ public class CachedRealm extends AbstractExtendableRevisioned {
|
||||||
return adminEventsDetailsEnabled;
|
return adminEventsDetailsEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<UserFederationProviderModel> getUserFederationProviders() {
|
|
||||||
return userFederationProviders;
|
|
||||||
}
|
|
||||||
|
|
||||||
public MultivaluedHashMap<String, UserFederationMapperModel> getUserFederationMappers() {
|
|
||||||
return userFederationMappers;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<IdentityProviderModel> getIdentityProviders() {
|
public List<IdentityProviderModel> getIdentityProviders() {
|
||||||
return identityProviders;
|
return identityProviders;
|
||||||
}
|
}
|
||||||
|
@ -546,10 +528,6 @@ public class CachedRealm extends AbstractExtendableRevisioned {
|
||||||
return clientTemplates;
|
return clientTemplates;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<UserFederationMapperModel> getUserFederationMapperSet() {
|
|
||||||
return userFederationMapperSet;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<AuthenticationFlowModel> getAuthenticationFlowList() {
|
public List<AuthenticationFlowModel> getAuthenticationFlowList() {
|
||||||
return authenticationFlowList;
|
return authenticationFlowList;
|
||||||
}
|
}
|
||||||
|
|
|
@ -734,194 +734,6 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void removeFederationMappersForProvider(String federationProviderId) {
|
|
||||||
Set<UserFederationMapperEntity> mappers = getUserFederationMapperEntitiesByFederationProvider(federationProviderId);
|
|
||||||
for (UserFederationMapperEntity mapper : mappers) {
|
|
||||||
realm.getUserFederationMappers().remove(mapper);
|
|
||||||
em.remove(mapper);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<UserFederationProviderModel> getUserFederationProviders() {
|
|
||||||
List<UserFederationProviderEntity> entities = realm.getUserFederationProviders();
|
|
||||||
if (entities.isEmpty()) return Collections.EMPTY_LIST;
|
|
||||||
List<UserFederationProviderEntity> copy = new ArrayList<UserFederationProviderEntity>();
|
|
||||||
for (UserFederationProviderEntity entity : entities) {
|
|
||||||
copy.add(entity);
|
|
||||||
|
|
||||||
}
|
|
||||||
Collections.sort(copy, new Comparator<UserFederationProviderEntity>() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int compare(UserFederationProviderEntity o1, UserFederationProviderEntity o2) {
|
|
||||||
return o1.getPriority() - o2.getPriority();
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
List<UserFederationProviderModel> result = new ArrayList<UserFederationProviderModel>();
|
|
||||||
for (UserFederationProviderEntity entity : copy) {
|
|
||||||
result.add(new UserFederationProviderModel(entity.getId(), entity.getProviderName(), entity.getConfig(), entity.getPriority(), entity.getDisplayName(),
|
|
||||||
entity.getFullSyncPeriod(), entity.getChangedSyncPeriod(), entity.getLastSync()));
|
|
||||||
}
|
|
||||||
|
|
||||||
return Collections.unmodifiableList(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UserFederationProviderModel addUserFederationProvider(String providerName, Map<String, String> config, int priority, String displayName, int fullSyncPeriod, int changedSyncPeriod, int lastSync) {
|
|
||||||
KeycloakModelUtils.ensureUniqueDisplayName(displayName, null, getUserFederationProviders());
|
|
||||||
|
|
||||||
String id = KeycloakModelUtils.generateId();
|
|
||||||
UserFederationProviderEntity entity = new UserFederationProviderEntity();
|
|
||||||
entity.setId(id);
|
|
||||||
entity.setRealm(realm);
|
|
||||||
entity.setProviderName(providerName);
|
|
||||||
entity.setConfig(config);
|
|
||||||
entity.setPriority(priority);
|
|
||||||
if (displayName == null) {
|
|
||||||
displayName = id;
|
|
||||||
}
|
|
||||||
entity.setDisplayName(displayName);
|
|
||||||
entity.setFullSyncPeriod(fullSyncPeriod);
|
|
||||||
entity.setChangedSyncPeriod(changedSyncPeriod);
|
|
||||||
entity.setLastSync(lastSync);
|
|
||||||
em.persist(entity);
|
|
||||||
realm.getUserFederationProviders().add(entity);
|
|
||||||
em.flush();
|
|
||||||
UserFederationProviderModel providerModel = new UserFederationProviderModel(entity.getId(), providerName, config, priority, displayName, fullSyncPeriod, changedSyncPeriod, lastSync);
|
|
||||||
|
|
||||||
session.getKeycloakSessionFactory().publish(new UserFederationProviderCreationEventImpl(this, providerModel));
|
|
||||||
|
|
||||||
return providerModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void removeUserFederationProvider(UserFederationProviderModel provider) {
|
|
||||||
Iterator<UserFederationProviderEntity> it = realm.getUserFederationProviders().iterator();
|
|
||||||
while (it.hasNext()) {
|
|
||||||
UserFederationProviderEntity entity = it.next();
|
|
||||||
if (entity.getId().equals(provider.getId())) {
|
|
||||||
|
|
||||||
session.users().preRemove(this, provider);
|
|
||||||
removeFederationMappersForProvider(provider.getId());
|
|
||||||
|
|
||||||
it.remove();
|
|
||||||
em.remove(entity);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void updateUserFederationProvider(UserFederationProviderModel model) {
|
|
||||||
KeycloakModelUtils.ensureUniqueDisplayName(model.getDisplayName(), model, getUserFederationProviders());
|
|
||||||
|
|
||||||
Iterator<UserFederationProviderEntity> it = realm.getUserFederationProviders().iterator();
|
|
||||||
while (it.hasNext()) {
|
|
||||||
UserFederationProviderEntity entity = it.next();
|
|
||||||
if (entity.getId().equals(model.getId())) {
|
|
||||||
String displayName = model.getDisplayName();
|
|
||||||
if (displayName != null) {
|
|
||||||
entity.setDisplayName(model.getDisplayName());
|
|
||||||
}
|
|
||||||
entity.setConfig(model.getConfig());
|
|
||||||
entity.setPriority(model.getPriority());
|
|
||||||
entity.setProviderName(model.getProviderName());
|
|
||||||
entity.setPriority(model.getPriority());
|
|
||||||
entity.setFullSyncPeriod(model.getFullSyncPeriod());
|
|
||||||
entity.setChangedSyncPeriod(model.getChangedSyncPeriod());
|
|
||||||
entity.setLastSync(model.getLastSync());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setUserFederationProviders(List<UserFederationProviderModel> providers) {
|
|
||||||
for (UserFederationProviderModel currentProvider : providers) {
|
|
||||||
KeycloakModelUtils.ensureUniqueDisplayName(currentProvider.getDisplayName(), currentProvider, providers);
|
|
||||||
}
|
|
||||||
|
|
||||||
Iterator<UserFederationProviderEntity> it = realm.getUserFederationProviders().iterator();
|
|
||||||
while (it.hasNext()) {
|
|
||||||
UserFederationProviderEntity entity = it.next();
|
|
||||||
boolean found = false;
|
|
||||||
for (UserFederationProviderModel model : providers) {
|
|
||||||
if (entity.getId().equals(model.getId())) {
|
|
||||||
entity.setConfig(model.getConfig());
|
|
||||||
entity.setPriority(model.getPriority());
|
|
||||||
entity.setProviderName(model.getProviderName());
|
|
||||||
String displayName = model.getDisplayName();
|
|
||||||
if (displayName != null) {
|
|
||||||
entity.setDisplayName(displayName);
|
|
||||||
}
|
|
||||||
entity.setFullSyncPeriod(model.getFullSyncPeriod());
|
|
||||||
entity.setChangedSyncPeriod(model.getChangedSyncPeriod());
|
|
||||||
entity.setLastSync(model.getLastSync());
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
if (found) continue;
|
|
||||||
session.users().preRemove(this, new UserFederationProviderModel(entity.getId(), entity.getProviderName(), entity.getConfig(), entity.getPriority(), entity.getDisplayName(),
|
|
||||||
entity.getFullSyncPeriod(), entity.getChangedSyncPeriod(), entity.getLastSync()));
|
|
||||||
removeFederationMappersForProvider(entity.getId());
|
|
||||||
|
|
||||||
it.remove();
|
|
||||||
em.remove(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<UserFederationProviderModel> add = new LinkedList<>();
|
|
||||||
for (UserFederationProviderModel model : providers) {
|
|
||||||
boolean found = false;
|
|
||||||
for (UserFederationProviderEntity entity : realm.getUserFederationProviders()) {
|
|
||||||
if (entity.getId().equals(model.getId())) {
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found) add.add(model);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (UserFederationProviderModel model : add) {
|
|
||||||
UserFederationProviderEntity entity = new UserFederationProviderEntity();
|
|
||||||
if (model.getId() != null) {
|
|
||||||
entity.setId(model.getId());
|
|
||||||
} else {
|
|
||||||
String id = KeycloakModelUtils.generateId();
|
|
||||||
entity.setId(id);
|
|
||||||
model.setId(id);
|
|
||||||
}
|
|
||||||
entity.setConfig(model.getConfig());
|
|
||||||
entity.setPriority(model.getPriority());
|
|
||||||
entity.setProviderName(model.getProviderName());
|
|
||||||
entity.setPriority(model.getPriority());
|
|
||||||
String displayName = model.getDisplayName();
|
|
||||||
if (displayName == null) {
|
|
||||||
displayName = entity.getId();
|
|
||||||
}
|
|
||||||
entity.setDisplayName(displayName);
|
|
||||||
entity.setFullSyncPeriod(model.getFullSyncPeriod());
|
|
||||||
entity.setChangedSyncPeriod(model.getChangedSyncPeriod());
|
|
||||||
entity.setLastSync(model.getLastSync());
|
|
||||||
entity.setRealm(realm);
|
|
||||||
em.persist(entity);
|
|
||||||
realm.getUserFederationProviders().add(entity);
|
|
||||||
|
|
||||||
session.getKeycloakSessionFactory().publish(new UserFederationProviderCreationEventImpl(this, model));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected UserFederationProviderEntity getUserFederationProviderEntityById(String federationProviderId) {
|
|
||||||
for (UserFederationProviderEntity entity : realm.getUserFederationProviders()) {
|
|
||||||
if (entity.getId().equals(federationProviderId)) {
|
|
||||||
return entity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RoleModel getRole(String name) {
|
public RoleModel getRole(String name) {
|
||||||
return session.realms().getRealmRole(this, name);
|
return session.realms().getRealmRole(this, name);
|
||||||
|
@ -1402,118 +1214,6 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
|
||||||
return mapping;
|
return mapping;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Set<UserFederationMapperModel> getUserFederationMappers() {
|
|
||||||
Collection<UserFederationMapperEntity> entities = this.realm.getUserFederationMappers();
|
|
||||||
if (entities.isEmpty()) return Collections.EMPTY_SET;
|
|
||||||
Set<UserFederationMapperModel> mappers = new HashSet<>();
|
|
||||||
for (UserFederationMapperEntity entity : entities) {
|
|
||||||
UserFederationMapperModel mapper = entityToModel(entity);
|
|
||||||
mappers.add(mapper);
|
|
||||||
}
|
|
||||||
return Collections.unmodifiableSet(mappers);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Set<UserFederationMapperModel> getUserFederationMappersByFederationProvider(String federationProviderId) {
|
|
||||||
Set<UserFederationMapperEntity> mapperEntities = getUserFederationMapperEntitiesByFederationProvider(federationProviderId);
|
|
||||||
if (mapperEntities.isEmpty()) return Collections.EMPTY_SET;
|
|
||||||
Set<UserFederationMapperModel> mappers = new HashSet<UserFederationMapperModel>();
|
|
||||||
for (UserFederationMapperEntity entity : mapperEntities) {
|
|
||||||
UserFederationMapperModel mapper = entityToModel(entity);
|
|
||||||
mappers.add(mapper);
|
|
||||||
}
|
|
||||||
return Collections.unmodifiableSet(mappers);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UserFederationMapperModel addUserFederationMapper(UserFederationMapperModel model) {
|
|
||||||
if (getUserFederationMapperByName(model.getFederationProviderId(), model.getName()) != null) {
|
|
||||||
throw new ModelDuplicateException("User federation mapper must be unique per federation provider. There is already: " + model.getName());
|
|
||||||
}
|
|
||||||
String id = KeycloakModelUtils.generateId();
|
|
||||||
UserFederationMapperEntity entity = new UserFederationMapperEntity();
|
|
||||||
entity.setId(id);
|
|
||||||
entity.setName(model.getName());
|
|
||||||
entity.setFederationProvider(getUserFederationProviderEntityById(model.getFederationProviderId()));
|
|
||||||
entity.setFederationMapperType(model.getFederationMapperType());
|
|
||||||
entity.setRealm(this.realm);
|
|
||||||
entity.setConfig(model.getConfig());
|
|
||||||
|
|
||||||
em.persist(entity);
|
|
||||||
this.realm.getUserFederationMappers().add(entity);
|
|
||||||
UserFederationMapperModel mapperModel = entityToModel(entity);
|
|
||||||
|
|
||||||
return mapperModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void removeUserFederationMapper(UserFederationMapperModel mapper) {
|
|
||||||
UserFederationMapperEntity toDelete = getUserFederationMapperEntity(mapper.getId());
|
|
||||||
if (toDelete != null) {
|
|
||||||
this.realm.getUserFederationMappers().remove(toDelete);
|
|
||||||
em.remove(toDelete);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected UserFederationMapperEntity getUserFederationMapperEntity(String id) {
|
|
||||||
for (UserFederationMapperEntity entity : this.realm.getUserFederationMappers()) {
|
|
||||||
if (entity.getId().equals(id)) {
|
|
||||||
return entity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
protected UserFederationMapperEntity getUserFederationMapperEntityByName(String federationProviderId, String name) {
|
|
||||||
for (UserFederationMapperEntity entity : this.realm.getUserFederationMappers()) {
|
|
||||||
if (federationProviderId.equals(entity.getFederationProvider().getId()) && entity.getName().equals(name)) {
|
|
||||||
return entity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Set<UserFederationMapperEntity> getUserFederationMapperEntitiesByFederationProvider(String federationProviderId) {
|
|
||||||
Set<UserFederationMapperEntity> mappers = new HashSet<UserFederationMapperEntity>();
|
|
||||||
for (UserFederationMapperEntity entity : this.realm.getUserFederationMappers()) {
|
|
||||||
if (federationProviderId.equals(entity.getFederationProvider().getId())) {
|
|
||||||
mappers.add(entity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return mappers;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateUserFederationMapper(UserFederationMapperModel mapper) {
|
|
||||||
UserFederationMapperEntity entity = getUserFederationMapperEntity(mapper.getId());
|
|
||||||
entity.setFederationProvider(getUserFederationProviderEntityById(mapper.getFederationProviderId()));
|
|
||||||
entity.setFederationMapperType(mapper.getFederationMapperType());
|
|
||||||
if (entity.getConfig() == null) {
|
|
||||||
entity.setConfig(mapper.getConfig());
|
|
||||||
} else {
|
|
||||||
entity.getConfig().clear();
|
|
||||||
entity.getConfig().putAll(mapper.getConfig());
|
|
||||||
}
|
|
||||||
em.flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UserFederationMapperModel getUserFederationMapperById(String id) {
|
|
||||||
UserFederationMapperEntity entity = getUserFederationMapperEntity(id);
|
|
||||||
if (entity == null) return null;
|
|
||||||
return entityToModel(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UserFederationMapperModel getUserFederationMapperByName(String federationProviderId, String name) {
|
|
||||||
UserFederationMapperEntity entity = getUserFederationMapperEntityByName(federationProviderId, name);
|
|
||||||
if (entity == null) return null;
|
|
||||||
return entityToModel(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected UserFederationMapperModel entityToModel(UserFederationMapperEntity entity) {
|
protected UserFederationMapperModel entityToModel(UserFederationMapperEntity entity) {
|
||||||
UserFederationMapperModel mapper = new UserFederationMapperModel();
|
UserFederationMapperModel mapper = new UserFederationMapperModel();
|
||||||
mapper.setId(entity.getId());
|
mapper.setId(entity.getId());
|
||||||
|
|
|
@ -869,183 +869,6 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
|
||||||
updateRealm();
|
updateRealm();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void removeFederationMappersForProvider(String federationProviderId) {
|
|
||||||
Set<UserFederationMapperEntity> mappers = getUserFederationMapperEntitiesByFederationProvider(federationProviderId);
|
|
||||||
for (UserFederationMapperEntity mapper : mappers) {
|
|
||||||
getMongoEntity().getUserFederationMappers().remove(mapper);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UserFederationProviderModel addUserFederationProvider(String providerName, Map<String, String> config, int priority, String displayName, int fullSyncPeriod, int changedSyncPeriod, int lastSync) {
|
|
||||||
KeycloakModelUtils.ensureUniqueDisplayName(displayName, null, getUserFederationProviders());
|
|
||||||
|
|
||||||
UserFederationProviderEntity entity = new UserFederationProviderEntity();
|
|
||||||
entity.setId(KeycloakModelUtils.generateId());
|
|
||||||
entity.setPriority(priority);
|
|
||||||
entity.setProviderName(providerName);
|
|
||||||
entity.setConfig(config);
|
|
||||||
if (displayName == null) {
|
|
||||||
displayName = entity.getId();
|
|
||||||
}
|
|
||||||
entity.setDisplayName(displayName);
|
|
||||||
entity.setFullSyncPeriod(fullSyncPeriod);
|
|
||||||
entity.setChangedSyncPeriod(changedSyncPeriod);
|
|
||||||
entity.setLastSync(lastSync);
|
|
||||||
realm.getUserFederationProviders().add(entity);
|
|
||||||
updateRealm();
|
|
||||||
|
|
||||||
UserFederationProviderModel providerModel = new UserFederationProviderModel(entity.getId(), providerName, config, priority, displayName, fullSyncPeriod, changedSyncPeriod, lastSync);
|
|
||||||
|
|
||||||
session.getKeycloakSessionFactory().publish(new UserFederationProviderCreationEventImpl(this, providerModel));
|
|
||||||
|
|
||||||
return providerModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void removeUserFederationProvider(UserFederationProviderModel provider) {
|
|
||||||
Iterator<UserFederationProviderEntity> it = realm.getUserFederationProviders().iterator();
|
|
||||||
while (it.hasNext()) {
|
|
||||||
UserFederationProviderEntity entity = it.next();
|
|
||||||
if (entity.getId().equals(provider.getId())) {
|
|
||||||
session.users().preRemove(this, new UserFederationProviderModel(entity.getId(), entity.getProviderName(), entity.getConfig(), entity.getPriority(), entity.getDisplayName(),
|
|
||||||
entity.getFullSyncPeriod(), entity.getChangedSyncPeriod(), entity.getLastSync()));
|
|
||||||
removeFederationMappersForProvider(provider.getId());
|
|
||||||
|
|
||||||
it.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
updateRealm();
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void updateUserFederationProvider(UserFederationProviderModel model) {
|
|
||||||
KeycloakModelUtils.ensureUniqueDisplayName(model.getDisplayName(), model, getUserFederationProviders());
|
|
||||||
|
|
||||||
Iterator<UserFederationProviderEntity> it = realm.getUserFederationProviders().iterator();
|
|
||||||
while (it.hasNext()) {
|
|
||||||
UserFederationProviderEntity entity = it.next();
|
|
||||||
if (entity.getId().equals(model.getId())) {
|
|
||||||
entity.setProviderName(model.getProviderName());
|
|
||||||
entity.setConfig(model.getConfig());
|
|
||||||
entity.setPriority(model.getPriority());
|
|
||||||
String displayName = model.getDisplayName();
|
|
||||||
if (displayName != null) {
|
|
||||||
entity.setDisplayName(model.getDisplayName());
|
|
||||||
}
|
|
||||||
entity.setFullSyncPeriod(model.getFullSyncPeriod());
|
|
||||||
entity.setChangedSyncPeriod(model.getChangedSyncPeriod());
|
|
||||||
entity.setLastSync(model.getLastSync());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
updateRealm();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<UserFederationProviderModel> getUserFederationProviders() {
|
|
||||||
List<UserFederationProviderEntity> entities = realm.getUserFederationProviders();
|
|
||||||
if (entities.isEmpty()) return Collections.EMPTY_LIST;
|
|
||||||
List<UserFederationProviderEntity> copy = new LinkedList<UserFederationProviderEntity>();
|
|
||||||
for (UserFederationProviderEntity entity : entities) {
|
|
||||||
copy.add(entity);
|
|
||||||
|
|
||||||
}
|
|
||||||
Collections.sort(copy, new Comparator<UserFederationProviderEntity>() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int compare(UserFederationProviderEntity o1, UserFederationProviderEntity o2) {
|
|
||||||
return o1.getPriority() - o2.getPriority();
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
List<UserFederationProviderModel> result = new LinkedList<UserFederationProviderModel>();
|
|
||||||
for (UserFederationProviderEntity entity : copy) {
|
|
||||||
result.add(new UserFederationProviderModel(entity.getId(), entity.getProviderName(), entity.getConfig(), entity.getPriority(), entity.getDisplayName(),
|
|
||||||
entity.getFullSyncPeriod(), entity.getChangedSyncPeriod(), entity.getLastSync()));
|
|
||||||
}
|
|
||||||
|
|
||||||
return Collections.unmodifiableList(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setUserFederationProviders(List<UserFederationProviderModel> providers) {
|
|
||||||
for (UserFederationProviderModel currentProvider : providers) {
|
|
||||||
KeycloakModelUtils.ensureUniqueDisplayName(currentProvider.getDisplayName(), currentProvider, providers);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<UserFederationProviderEntity> existingProviders = realm.getUserFederationProviders();
|
|
||||||
List<UserFederationProviderEntity> toRemove = new LinkedList<>();
|
|
||||||
for (UserFederationProviderEntity entity : existingProviders) {
|
|
||||||
boolean found = false;
|
|
||||||
for (UserFederationProviderModel model : providers) {
|
|
||||||
if (entity.getId().equals(model.getId())) {
|
|
||||||
entity.setConfig(model.getConfig());
|
|
||||||
entity.setPriority(model.getPriority());
|
|
||||||
entity.setProviderName(model.getProviderName());
|
|
||||||
String displayName = model.getDisplayName();
|
|
||||||
if (displayName != null) {
|
|
||||||
entity.setDisplayName(displayName);
|
|
||||||
}
|
|
||||||
entity.setFullSyncPeriod(model.getFullSyncPeriod());
|
|
||||||
entity.setChangedSyncPeriod(model.getChangedSyncPeriod());
|
|
||||||
entity.setLastSync(model.getLastSync());
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
if (found) continue;
|
|
||||||
session.users().preRemove(this, new UserFederationProviderModel(entity.getId(), entity.getProviderName(), entity.getConfig(), entity.getPriority(), entity.getDisplayName(),
|
|
||||||
entity.getFullSyncPeriod(), entity.getChangedSyncPeriod(), entity.getLastSync()));
|
|
||||||
removeFederationMappersForProvider(entity.getId());
|
|
||||||
|
|
||||||
toRemove.add(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (UserFederationProviderEntity entity : toRemove) {
|
|
||||||
realm.getUserFederationProviders().remove(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<UserFederationProviderModel> add = new LinkedList<UserFederationProviderModel>();
|
|
||||||
for (UserFederationProviderModel model : providers) {
|
|
||||||
boolean found = false;
|
|
||||||
for (UserFederationProviderEntity entity : realm.getUserFederationProviders()) {
|
|
||||||
if (entity.getId().equals(model.getId())) {
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found) add.add(model);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (UserFederationProviderModel model : add) {
|
|
||||||
UserFederationProviderEntity entity = new UserFederationProviderEntity();
|
|
||||||
if (model.getId() != null) {
|
|
||||||
entity.setId(model.getId());
|
|
||||||
} else {
|
|
||||||
String id = KeycloakModelUtils.generateId();
|
|
||||||
entity.setId(id);
|
|
||||||
model.setId(id);
|
|
||||||
}
|
|
||||||
entity.setProviderName(model.getProviderName());
|
|
||||||
entity.setConfig(model.getConfig());
|
|
||||||
entity.setPriority(model.getPriority());
|
|
||||||
String displayName = model.getDisplayName();
|
|
||||||
if (displayName == null) {
|
|
||||||
displayName = entity.getId();
|
|
||||||
}
|
|
||||||
entity.setDisplayName(displayName);
|
|
||||||
entity.setFullSyncPeriod(model.getFullSyncPeriod());
|
|
||||||
entity.setChangedSyncPeriod(model.getChangedSyncPeriod());
|
|
||||||
entity.setLastSync(model.getLastSync());
|
|
||||||
realm.getUserFederationProviders().add(entity);
|
|
||||||
|
|
||||||
session.getKeycloakSessionFactory().publish(new UserFederationProviderCreationEventImpl(this, model));
|
|
||||||
}
|
|
||||||
|
|
||||||
updateRealm();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isEventsEnabled() {
|
public boolean isEventsEnabled() {
|
||||||
return realm.isEventsEnabled();
|
return realm.isEventsEnabled();
|
||||||
|
@ -1760,131 +1583,6 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Set<UserFederationMapperModel> getUserFederationMappers() {
|
|
||||||
List<UserFederationMapperEntity> entities = getMongoEntity().getUserFederationMappers();
|
|
||||||
if (entities.isEmpty()) return Collections.EMPTY_SET;
|
|
||||||
Set<UserFederationMapperModel> mappers = new HashSet<UserFederationMapperModel>();
|
|
||||||
for (UserFederationMapperEntity entity : entities) {
|
|
||||||
UserFederationMapperModel mapper = entityToModel(entity);
|
|
||||||
mappers.add(mapper);
|
|
||||||
}
|
|
||||||
return Collections.unmodifiableSet(mappers);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Set<UserFederationMapperModel> getUserFederationMappersByFederationProvider(String federationProviderId) {
|
|
||||||
Set<UserFederationMapperModel> mappers = new HashSet<UserFederationMapperModel>();
|
|
||||||
Set<UserFederationMapperEntity> mapperEntities = getUserFederationMapperEntitiesByFederationProvider(federationProviderId);
|
|
||||||
for (UserFederationMapperEntity entity : mapperEntities) {
|
|
||||||
mappers.add(entityToModel(entity));
|
|
||||||
}
|
|
||||||
return mappers;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UserFederationMapperModel addUserFederationMapper(UserFederationMapperModel model) {
|
|
||||||
if (getUserFederationMapperByName(model.getFederationProviderId(), model.getName()) != null) {
|
|
||||||
throw new ModelDuplicateException("User federation mapper must be unique per federation provider. There is already: " + model.getName());
|
|
||||||
}
|
|
||||||
String id = KeycloakModelUtils.generateId();
|
|
||||||
UserFederationMapperEntity entity = new UserFederationMapperEntity();
|
|
||||||
entity.setId(id);
|
|
||||||
entity.setName(model.getName());
|
|
||||||
entity.setFederationProviderId(model.getFederationProviderId());
|
|
||||||
entity.setFederationMapperType(model.getFederationMapperType());
|
|
||||||
entity.setConfig(model.getConfig());
|
|
||||||
|
|
||||||
getMongoEntity().getUserFederationMappers().add(entity);
|
|
||||||
updateMongoEntity();
|
|
||||||
UserFederationMapperModel mapperModel = entityToModel(entity);
|
|
||||||
|
|
||||||
return mapperModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected UserFederationMapperEntity getUserFederationMapperEntity(String id) {
|
|
||||||
for (UserFederationMapperEntity entity : getMongoEntity().getUserFederationMappers()) {
|
|
||||||
if (entity.getId().equals(id)) {
|
|
||||||
return entity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
protected UserFederationMapperEntity getUserFederationMapperEntityByName(String federationProviderId, String name) {
|
|
||||||
for (UserFederationMapperEntity entity : getMongoEntity().getUserFederationMappers()) {
|
|
||||||
if (entity.getFederationProviderId().equals(federationProviderId) && entity.getName().equals(name)) {
|
|
||||||
return entity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Set<UserFederationMapperEntity> getUserFederationMapperEntitiesByFederationProvider(String federationProviderId) {
|
|
||||||
Set<UserFederationMapperEntity> mappers = new HashSet<UserFederationMapperEntity>();
|
|
||||||
for (UserFederationMapperEntity entity : getMongoEntity().getUserFederationMappers()) {
|
|
||||||
if (federationProviderId.equals(entity.getFederationProviderId())) {
|
|
||||||
mappers.add(entity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return mappers;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void removeUserFederationMapper(UserFederationMapperModel mapper) {
|
|
||||||
UserFederationMapperEntity toDelete = getUserFederationMapperEntity(mapper.getId());
|
|
||||||
if (toDelete != null) {
|
|
||||||
this.realm.getUserFederationMappers().remove(toDelete);
|
|
||||||
updateMongoEntity();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateUserFederationMapper(UserFederationMapperModel mapper) {
|
|
||||||
UserFederationMapperEntity entity = getUserFederationMapperEntity(mapper.getId());
|
|
||||||
entity.setFederationProviderId(mapper.getFederationProviderId());
|
|
||||||
entity.setFederationMapperType(mapper.getFederationMapperType());
|
|
||||||
if (entity.getConfig() == null) {
|
|
||||||
entity.setConfig(mapper.getConfig());
|
|
||||||
} else {
|
|
||||||
entity.getConfig().clear();
|
|
||||||
entity.getConfig().putAll(mapper.getConfig());
|
|
||||||
}
|
|
||||||
updateMongoEntity();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UserFederationMapperModel getUserFederationMapperById(String id) {
|
|
||||||
UserFederationMapperEntity entity = getUserFederationMapperEntity(id);
|
|
||||||
if (entity == null) return null;
|
|
||||||
return entityToModel(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UserFederationMapperModel getUserFederationMapperByName(String federationProviderId, String name) {
|
|
||||||
UserFederationMapperEntity entity = getUserFederationMapperEntityByName(federationProviderId, name);
|
|
||||||
if (entity == null) return null;
|
|
||||||
return entityToModel(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected UserFederationMapperModel entityToModel(UserFederationMapperEntity entity) {
|
|
||||||
UserFederationMapperModel mapper = new UserFederationMapperModel();
|
|
||||||
mapper.setId(entity.getId());
|
|
||||||
mapper.setName(entity.getName());
|
|
||||||
mapper.setFederationProviderId(entity.getFederationProviderId());
|
|
||||||
mapper.setFederationMapperType(entity.getFederationMapperType());
|
|
||||||
Map<String, String> config = new HashMap<String, String>();
|
|
||||||
if (entity.getConfig() != null) config.putAll(entity.getConfig());
|
|
||||||
mapper.setConfig(config);
|
|
||||||
return mapper;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<ClientTemplateModel> getClientTemplates() {
|
public List<ClientTemplateModel> getClientTemplates() {
|
||||||
DBObject query = new QueryBuilder()
|
DBObject query = new QueryBuilder()
|
||||||
|
|
|
@ -18,13 +18,6 @@
|
||||||
package org.keycloak.migration;
|
package org.keycloak.migration;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import org.keycloak.migration.migrators.MigrateTo1_2_0;
|
|
||||||
import org.keycloak.migration.migrators.MigrateTo1_3_0;
|
|
||||||
import org.keycloak.migration.migrators.MigrateTo1_4_0;
|
|
||||||
import org.keycloak.migration.migrators.MigrateTo1_5_0;
|
|
||||||
import org.keycloak.migration.migrators.MigrateTo1_6_0;
|
|
||||||
import org.keycloak.migration.migrators.MigrateTo1_7_0;
|
|
||||||
import org.keycloak.migration.migrators.MigrateTo1_8_0;
|
|
||||||
import org.keycloak.migration.migrators.MigrateTo1_9_0;
|
import org.keycloak.migration.migrators.MigrateTo1_9_0;
|
||||||
import org.keycloak.migration.migrators.MigrateTo1_9_2;
|
import org.keycloak.migration.migrators.MigrateTo1_9_2;
|
||||||
import org.keycloak.migration.migrators.MigrateTo2_0_0;
|
import org.keycloak.migration.migrators.MigrateTo2_0_0;
|
||||||
|
@ -42,13 +35,6 @@ public class MigrationModelManager {
|
||||||
private static Logger logger = Logger.getLogger(MigrationModelManager.class);
|
private static Logger logger = Logger.getLogger(MigrationModelManager.class);
|
||||||
|
|
||||||
private static final Migration[] migrations = {
|
private static final Migration[] migrations = {
|
||||||
new MigrateTo1_2_0(),
|
|
||||||
new MigrateTo1_3_0(),
|
|
||||||
new MigrateTo1_4_0(),
|
|
||||||
new MigrateTo1_5_0(),
|
|
||||||
new MigrateTo1_6_0(),
|
|
||||||
new MigrateTo1_7_0(),
|
|
||||||
new MigrateTo1_8_0(),
|
|
||||||
new MigrateTo1_9_0(),
|
new MigrateTo1_9_0(),
|
||||||
new MigrateTo1_9_2(),
|
new MigrateTo1_9_2(),
|
||||||
new MigrateTo2_0_0(),
|
new MigrateTo2_0_0(),
|
||||||
|
|
|
@ -1,99 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
|
||||||
* and other contributors as indicated by the @author tags.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.keycloak.migration.migrators;
|
|
||||||
|
|
||||||
import org.keycloak.migration.ModelVersion;
|
|
||||||
import org.keycloak.models.KeycloakSession;
|
|
||||||
import org.keycloak.models.LDAPConstants;
|
|
||||||
import org.keycloak.models.RealmModel;
|
|
||||||
import org.keycloak.models.UserFederationEventAwareProviderFactory;
|
|
||||||
import org.keycloak.models.UserFederationMapperModel;
|
|
||||||
import org.keycloak.models.UserFederationProvider;
|
|
||||||
import org.keycloak.models.UserFederationProviderFactory;
|
|
||||||
import org.keycloak.models.UserFederationProviderModel;
|
|
||||||
|
|
||||||
import javax.naming.directory.SearchControls;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
|
||||||
* @version $Revision: 1 $
|
|
||||||
*/
|
|
||||||
public class MigrateTo1_3_0 implements Migration {
|
|
||||||
|
|
||||||
public static final ModelVersion VERSION = new ModelVersion("1.3.0");
|
|
||||||
|
|
||||||
public ModelVersion getVersion() {
|
|
||||||
return VERSION;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void migrate(KeycloakSession session) {
|
|
||||||
List<RealmModel> realms = session.realms().getRealms();
|
|
||||||
for (RealmModel realm : realms) {
|
|
||||||
migrateLDAPProviders(session, realm);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private void migrateLDAPProviders(KeycloakSession session, RealmModel realm) {
|
|
||||||
List<UserFederationProviderModel> federationProviders = realm.getUserFederationProviders();
|
|
||||||
for (UserFederationProviderModel fedProvider : federationProviders) {
|
|
||||||
|
|
||||||
if (fedProvider.getProviderName().equals(LDAPConstants.LDAP_PROVIDER)) {
|
|
||||||
Map<String, String> config = fedProvider.getConfig();
|
|
||||||
|
|
||||||
// Update config properties for LDAP federated provider
|
|
||||||
if (config.get(LDAPConstants.SEARCH_SCOPE) == null) {
|
|
||||||
config.put(LDAPConstants.SEARCH_SCOPE, String.valueOf(SearchControls.SUBTREE_SCOPE));
|
|
||||||
}
|
|
||||||
|
|
||||||
String usersDn = config.remove("userDnSuffix");
|
|
||||||
if (usersDn != null && config.get(LDAPConstants.USERS_DN) == null) {
|
|
||||||
config.put(LDAPConstants.USERS_DN, usersDn);
|
|
||||||
}
|
|
||||||
|
|
||||||
String usernameLdapAttribute = config.get(LDAPConstants.USERNAME_LDAP_ATTRIBUTE);
|
|
||||||
if (usernameLdapAttribute != null && config.get(LDAPConstants.RDN_LDAP_ATTRIBUTE) == null) {
|
|
||||||
if (usernameLdapAttribute.equalsIgnoreCase(LDAPConstants.SAM_ACCOUNT_NAME)) {
|
|
||||||
config.put(LDAPConstants.RDN_LDAP_ATTRIBUTE, LDAPConstants.CN);
|
|
||||||
} else {
|
|
||||||
config.put(LDAPConstants.RDN_LDAP_ATTRIBUTE, usernameLdapAttribute);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config.get(LDAPConstants.UUID_LDAP_ATTRIBUTE) == null) {
|
|
||||||
String uuidAttrName = LDAPConstants.getUuidAttributeName(config.get(LDAPConstants.VENDOR));
|
|
||||||
config.put(LDAPConstants.UUID_LDAP_ATTRIBUTE, uuidAttrName);
|
|
||||||
}
|
|
||||||
|
|
||||||
realm.updateUserFederationProvider(fedProvider);
|
|
||||||
|
|
||||||
// Create default mappers for LDAP
|
|
||||||
Set<UserFederationMapperModel> mappers = realm.getUserFederationMappersByFederationProvider(fedProvider.getId());
|
|
||||||
if (mappers.isEmpty()) {
|
|
||||||
UserFederationProviderFactory ldapFactory = (UserFederationProviderFactory) session.getKeycloakSessionFactory().getProviderFactory(UserFederationProvider.class, LDAPConstants.LDAP_PROVIDER);
|
|
||||||
if (ldapFactory != null) {
|
|
||||||
((UserFederationEventAwareProviderFactory) ldapFactory).onProviderModelCreated(realm, fedProvider);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,79 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
|
||||||
* and other contributors as indicated by the @author tags.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.keycloak.migration.migrators;
|
|
||||||
|
|
||||||
import org.keycloak.migration.ModelVersion;
|
|
||||||
import org.keycloak.models.ImpersonationConstants;
|
|
||||||
import org.keycloak.models.KeycloakSession;
|
|
||||||
import org.keycloak.models.RealmModel;
|
|
||||||
import org.keycloak.models.UserFederationMapperModel;
|
|
||||||
import org.keycloak.models.UserModel;
|
|
||||||
import org.keycloak.models.utils.DefaultAuthenticationFlows;
|
|
||||||
import org.keycloak.models.utils.DefaultRequiredActions;
|
|
||||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
|
||||||
* @version $Revision: 1 $
|
|
||||||
*/
|
|
||||||
public class MigrateTo1_4_0 implements Migration {
|
|
||||||
public static final ModelVersion VERSION = new ModelVersion("1.4.0");
|
|
||||||
|
|
||||||
public ModelVersion getVersion() {
|
|
||||||
return VERSION;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void migrate(KeycloakSession session) {
|
|
||||||
List<RealmModel> realms = session.realms().getRealms();
|
|
||||||
for (RealmModel realm : realms) {
|
|
||||||
if (realm.getAuthenticationFlows().size() == 0) {
|
|
||||||
DefaultAuthenticationFlows.migrateFlows(realm);
|
|
||||||
DefaultRequiredActions.addActions(realm);
|
|
||||||
}
|
|
||||||
ImpersonationConstants.setupImpersonationService(session, realm);
|
|
||||||
|
|
||||||
migrateLDAPMappers(session, realm);
|
|
||||||
migrateUsers(session, realm);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private void migrateLDAPMappers(KeycloakSession session, RealmModel realm) {
|
|
||||||
List<String> mandatoryInLdap = Arrays.asList("username", "username-cn", "first name", "last name");
|
|
||||||
for (UserFederationMapperModel ldapMapper : realm.getUserFederationMappers()) {
|
|
||||||
if (mandatoryInLdap.contains(ldapMapper.getName())) {
|
|
||||||
ldapMapper.getConfig().put("is.mandatory.in.ldap", "true");
|
|
||||||
realm.updateUserFederationMapper(ldapMapper);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void migrateUsers(KeycloakSession session, RealmModel realm) {
|
|
||||||
List<UserModel> users = session.userStorage().getUsers(realm, false);
|
|
||||||
for (UserModel user : users) {
|
|
||||||
String email = user.getEmail();
|
|
||||||
email = KeycloakModelUtils.toLowerCaseSafe(email);
|
|
||||||
if (email != null && !email.equals(user.getEmail())) {
|
|
||||||
user.setEmail(email);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,70 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
|
||||||
* and other contributors as indicated by the @author tags.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.keycloak.migration.migrators;
|
|
||||||
|
|
||||||
import org.keycloak.migration.ModelVersion;
|
|
||||||
import org.keycloak.models.KeycloakSession;
|
|
||||||
import org.keycloak.models.LDAPConstants;
|
|
||||||
import org.keycloak.models.RealmModel;
|
|
||||||
import org.keycloak.models.UserFederationMapperModel;
|
|
||||||
import org.keycloak.models.UserFederationProviderModel;
|
|
||||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
|
||||||
*/
|
|
||||||
public class MigrateTo1_8_0 implements Migration {
|
|
||||||
|
|
||||||
public static final ModelVersion VERSION = new ModelVersion("1.8.0");
|
|
||||||
|
|
||||||
public ModelVersion getVersion() {
|
|
||||||
return VERSION;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void migrate(KeycloakSession session) {
|
|
||||||
List<RealmModel> realms = session.realms().getRealms();
|
|
||||||
for (RealmModel realm : realms) {
|
|
||||||
|
|
||||||
List<UserFederationProviderModel> federationProviders = realm.getUserFederationProviders();
|
|
||||||
for (UserFederationProviderModel fedProvider : federationProviders) {
|
|
||||||
|
|
||||||
if (fedProvider.getProviderName().equals(LDAPConstants.LDAP_PROVIDER)) {
|
|
||||||
Map<String, String> config = fedProvider.getConfig();
|
|
||||||
|
|
||||||
if (isActiveDirectory(config)) {
|
|
||||||
|
|
||||||
// Create mapper for MSAD account controls
|
|
||||||
if (realm.getUserFederationMapperByName(fedProvider.getId(), "MSAD account controls") == null) {
|
|
||||||
UserFederationMapperModel mapperModel = KeycloakModelUtils.createUserFederationMapperModel("MSAD account controls", fedProvider.getId(), LDAPConstants.MSAD_USER_ACCOUNT_CONTROL_MAPPER);
|
|
||||||
realm.addUserFederationMapper(mapperModel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isActiveDirectory(Map<String, String> ldapConfig) {
|
|
||||||
String vendor = ldapConfig.get(LDAPConstants.VENDOR);
|
|
||||||
return vendor != null && vendor.equals(LDAPConstants.VENDOR_ACTIVE_DIRECTORY);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -283,28 +283,6 @@ public final class KeycloakModelUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static UserFederationProviderModel findUserFederationProviderByDisplayName(String displayName, RealmModel realm) {
|
|
||||||
if (displayName == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (UserFederationProviderModel fedProvider : realm.getUserFederationProviders()) {
|
|
||||||
if (displayName.equals(fedProvider.getDisplayName())) {
|
|
||||||
return fedProvider;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UserFederationProviderModel findUserFederationProviderById(String fedProviderId, RealmModel realm) {
|
|
||||||
for (UserFederationProviderModel fedProvider : realm.getUserFederationProviders()) {
|
|
||||||
if (fedProviderId.equals(fedProvider.getId())) {
|
|
||||||
return fedProvider;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UserStorageProviderModel findUserStorageProviderByName(String displayName, RealmModel realm) {
|
public static UserStorageProviderModel findUserStorageProviderByName(String displayName, RealmModel realm) {
|
||||||
if (displayName == null) {
|
if (displayName == null) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -352,8 +352,6 @@ public class ModelToRepresentation {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
exportUserFederationProvidersAndMappers(realm, rep);
|
|
||||||
|
|
||||||
for (IdentityProviderModel provider : realm.getIdentityProviders()) {
|
for (IdentityProviderModel provider : realm.getIdentityProviders()) {
|
||||||
rep.addIdentityProvider(toRepresentation(realm, provider));
|
rep.addIdentityProvider(toRepresentation(realm, provider));
|
||||||
}
|
}
|
||||||
|
@ -384,23 +382,7 @@ public class ModelToRepresentation {
|
||||||
return rep;
|
return rep;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void exportUserFederationProvidersAndMappers(RealmModel realm, RealmRepresentation rep) {
|
public static void exportGroups(RealmModel realm, RealmRepresentation rep) {
|
||||||
List<UserFederationProviderModel> fedProviderModels = realm.getUserFederationProviders();
|
|
||||||
if (fedProviderModels.size() > 0) {
|
|
||||||
List<UserFederationProviderRepresentation> fedProviderReps = new ArrayList<UserFederationProviderRepresentation>();
|
|
||||||
for (UserFederationProviderModel model : fedProviderModels) {
|
|
||||||
UserFederationProviderRepresentation fedProvRep = toRepresentation(model);
|
|
||||||
fedProviderReps.add(fedProvRep);
|
|
||||||
}
|
|
||||||
rep.setUserFederationProviders(fedProviderReps);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (UserFederationMapperModel mapper : realm.getUserFederationMappers()) {
|
|
||||||
rep.addUserFederationMapper(toRepresentation(realm, mapper));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void exportGroups(RealmModel realm, RealmRepresentation rep) {
|
|
||||||
List<GroupRepresentation> groups = toGroupHierarchy(realm, true);
|
List<GroupRepresentation> groups = toGroupHierarchy(realm, true);
|
||||||
rep.setGroups(groups);
|
rep.setGroups(groups);
|
||||||
}
|
}
|
||||||
|
@ -605,24 +587,6 @@ public class ModelToRepresentation {
|
||||||
return rep;
|
return rep;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static UserFederationMapperRepresentation toRepresentation(RealmModel realm, UserFederationMapperModel model) {
|
|
||||||
UserFederationMapperRepresentation rep = new UserFederationMapperRepresentation();
|
|
||||||
rep.setId(model.getId());
|
|
||||||
rep.setName(model.getName());
|
|
||||||
rep.setFederationMapperType(model.getFederationMapperType());
|
|
||||||
Map<String, String> config = new HashMap<String, String>();
|
|
||||||
config.putAll(model.getConfig());
|
|
||||||
rep.setConfig(config);
|
|
||||||
|
|
||||||
UserFederationProviderModel fedProvider = KeycloakModelUtils.findUserFederationProviderById(model.getFederationProviderId(), realm);
|
|
||||||
if (fedProvider == null) {
|
|
||||||
throw new ModelException("Couldn't find federation provider with ID " + model.getId());
|
|
||||||
}
|
|
||||||
rep.setFederationProviderDisplayName(fedProvider.getDisplayName());
|
|
||||||
|
|
||||||
return rep;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IdentityProviderRepresentation toRepresentation(RealmModel realm, IdentityProviderModel identityProviderModel) {
|
public static IdentityProviderRepresentation toRepresentation(RealmModel realm, IdentityProviderModel identityProviderModel) {
|
||||||
IdentityProviderRepresentation providerRep = new IdentityProviderRepresentation();
|
IdentityProviderRepresentation providerRep = new IdentityProviderRepresentation();
|
||||||
|
|
||||||
|
|
|
@ -376,37 +376,14 @@ public class RepresentationToModel {
|
||||||
if (convertSet.contains(fedRep.getProviderName())) {
|
if (convertSet.contains(fedRep.getProviderName())) {
|
||||||
ComponentModel component = convertFedProviderToComponent(newRealm.getId(), fedRep);
|
ComponentModel component = convertFedProviderToComponent(newRealm.getId(), fedRep);
|
||||||
userStorageModels.put(fedRep.getDisplayName(), newRealm.importComponentModel(component));
|
userStorageModels.put(fedRep.getDisplayName(), newRealm.importComponentModel(component));
|
||||||
} else {
|
|
||||||
providerModels.add(convertFederationProvider(fedRep));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
newRealm.setUserFederationProviders(providerModels);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is for case, when you have hand-written JSON file with LDAP userFederationProvider, but WITHOUT any userFederationMappers configured. Default LDAP mappers need to be created in that case.
|
// This is for case, when you have hand-written JSON file with LDAP userFederationProvider, but WITHOUT any userFederationMappers configured. Default LDAP mappers need to be created in that case.
|
||||||
Set<String> storageProvidersWhichShouldImportDefaultMappers = new HashSet<>(userStorageModels.keySet());
|
Set<String> storageProvidersWhichShouldImportDefaultMappers = new HashSet<>(userStorageModels.keySet());
|
||||||
|
|
||||||
if (rep.getUserFederationMappers() != null) {
|
if (rep.getUserFederationMappers() != null) {
|
||||||
|
|
||||||
// Remove builtin mappers for federation providers, which have some mappers already provided in JSON (likely due to previous export)
|
|
||||||
if (rep.getUserFederationProviders() != null) {
|
|
||||||
Set<String> providerNames = new TreeSet<String>();
|
|
||||||
for (UserFederationMapperRepresentation representation : rep.getUserFederationMappers()) {
|
|
||||||
providerNames.add(representation.getFederationProviderDisplayName());
|
|
||||||
}
|
|
||||||
for (String providerName : providerNames) {
|
|
||||||
for (UserFederationProviderModel providerModel : providerModels) {
|
|
||||||
if (providerName.equals(providerModel.getDisplayName())) {
|
|
||||||
Set<UserFederationMapperModel> toDelete = newRealm.getUserFederationMappersByFederationProvider(providerModel.getId());
|
|
||||||
for (UserFederationMapperModel mapperModel : toDelete) {
|
|
||||||
newRealm.removeUserFederationMapper(mapperModel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (UserFederationMapperRepresentation representation : rep.getUserFederationMappers()) {
|
for (UserFederationMapperRepresentation representation : rep.getUserFederationMappers()) {
|
||||||
if (userStorageModels.containsKey(representation.getFederationProviderDisplayName())) {
|
if (userStorageModels.containsKey(representation.getFederationProviderDisplayName())) {
|
||||||
ComponentModel parent = userStorageModels.get(representation.getFederationProviderDisplayName());
|
ComponentModel parent = userStorageModels.get(representation.getFederationProviderDisplayName());
|
||||||
|
@ -417,8 +394,6 @@ public class RepresentationToModel {
|
||||||
|
|
||||||
storageProvidersWhichShouldImportDefaultMappers.remove(representation.getFederationProviderDisplayName());
|
storageProvidersWhichShouldImportDefaultMappers.remove(representation.getFederationProviderDisplayName());
|
||||||
|
|
||||||
} else {
|
|
||||||
newRealm.addUserFederationMapper(toModel(newRealm, representation));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -865,11 +840,6 @@ public class RepresentationToModel {
|
||||||
realm.setBrowserSecurityHeaders(rep.getBrowserSecurityHeaders());
|
realm.setBrowserSecurityHeaders(rep.getBrowserSecurityHeaders());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rep.getUserFederationProviders() != null) {
|
|
||||||
List<UserFederationProviderModel> providerModels = convertFederationProviders(rep.getUserFederationProviders());
|
|
||||||
realm.setUserFederationProviders(providerModels);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(rep.isInternationalizationEnabled() != null){
|
if(rep.isInternationalizationEnabled() != null){
|
||||||
realm.setInternationalizationEnabled(rep.isInternationalizationEnabled());
|
realm.setInternationalizationEnabled(rep.isInternationalizationEnabled());
|
||||||
}
|
}
|
||||||
|
@ -950,23 +920,6 @@ public class RepresentationToModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static UserFederationMapperModel toModel(RealmModel realm, UserFederationMapperRepresentation rep) {
|
|
||||||
UserFederationMapperModel model = new UserFederationMapperModel();
|
|
||||||
model.setId(rep.getId());
|
|
||||||
model.setName(rep.getName());
|
|
||||||
model.setFederationMapperType(rep.getFederationMapperType());
|
|
||||||
model.setConfig(rep.getConfig());
|
|
||||||
|
|
||||||
UserFederationProviderModel fedProvider = KeycloakModelUtils.findUserFederationProviderByDisplayName(rep.getFederationProviderDisplayName(), realm);
|
|
||||||
if (fedProvider == null) {
|
|
||||||
throw new ModelException("Couldn't find federation provider with display name [" + rep.getFederationProviderDisplayName() + "] referenced from mapper ["
|
|
||||||
+ rep.getName());
|
|
||||||
}
|
|
||||||
model.setFederationProviderId(fedProvider.getId());
|
|
||||||
|
|
||||||
return model;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Roles
|
// Roles
|
||||||
|
|
||||||
public static void createRole(RealmModel newRealm, RoleRepresentation roleRep) {
|
public static void createRole(RealmModel newRealm, RoleRepresentation roleRep) {
|
||||||
|
|
|
@ -117,7 +117,7 @@ public interface KeycloakSession {
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
UserFederationManager users();
|
UserProvider users();
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -310,21 +310,6 @@ public interface RealmModel extends RoleContainerModel {
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Should return list sorted by UserFederationProviderModel.priority
|
|
||||||
List<UserFederationProviderModel> getUserFederationProviders();
|
|
||||||
UserFederationProviderModel addUserFederationProvider(String providerName, Map<String, String> config, int priority, String displayName, int fullSyncPeriod, int changedSyncPeriod, int lastSync);
|
|
||||||
void updateUserFederationProvider(UserFederationProviderModel provider);
|
|
||||||
void removeUserFederationProvider(UserFederationProviderModel provider);
|
|
||||||
void setUserFederationProviders(List<UserFederationProviderModel> providers);
|
|
||||||
|
|
||||||
Set<UserFederationMapperModel> getUserFederationMappers();
|
|
||||||
Set<UserFederationMapperModel> getUserFederationMappersByFederationProvider(String federationProviderId);
|
|
||||||
UserFederationMapperModel addUserFederationMapper(UserFederationMapperModel mapper);
|
|
||||||
void removeUserFederationMapper(UserFederationMapperModel mapper);
|
|
||||||
void updateUserFederationMapper(UserFederationMapperModel mapper);
|
|
||||||
UserFederationMapperModel getUserFederationMapperById(String id);
|
|
||||||
UserFederationMapperModel getUserFederationMapperByName(String federationProviderId, String name);
|
|
||||||
|
|
||||||
String getLoginTheme();
|
String getLoginTheme();
|
||||||
|
|
||||||
void setLoginTheme(String name);
|
void setLoginTheme(String name);
|
||||||
|
|
|
@ -49,139 +49,23 @@ public class UserFederationManager implements UserProvider {
|
||||||
@Override
|
@Override
|
||||||
public UserModel addUser(RealmModel realm, String id, String username, boolean addDefaultRoles, boolean addDefaultRequiredActions) {
|
public UserModel addUser(RealmModel realm, String id, String username, boolean addDefaultRoles, boolean addDefaultRequiredActions) {
|
||||||
UserModel user = session.userStorage().addUser(realm, id, username.toLowerCase(), addDefaultRoles, addDefaultRequiredActions);
|
UserModel user = session.userStorage().addUser(realm, id, username.toLowerCase(), addDefaultRoles, addDefaultRequiredActions);
|
||||||
return registerWithFederation(realm, user);
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UserModel addUser(RealmModel realm, String username) {
|
public UserModel addUser(RealmModel realm, String username) {
|
||||||
UserModel user = session.userStorage().addUser(realm, username.toLowerCase());
|
UserModel user = session.userStorage().addUser(realm, username.toLowerCase());
|
||||||
return registerWithFederation(realm, user);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected UserModel registerWithFederation(RealmModel realm, UserModel user) {
|
|
||||||
for (UserFederationProviderModel federation : realm.getUserFederationProviders()) {
|
|
||||||
UserFederationProvider fed = getFederationProvider(federation);
|
|
||||||
if (fed.synchronizeRegistrations()) {
|
|
||||||
user.setFederationLink(federation.getId());
|
|
||||||
UserModel registered = fed.register(realm, user);
|
|
||||||
managedUsers.put(registered.getId(), registered);
|
|
||||||
return registered;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
public UserFederationProvider getFederationProvider(UserFederationProviderModel model) {
|
|
||||||
UserFederationProviderFactory factory = (UserFederationProviderFactory)session.getKeycloakSessionFactory().getProviderFactory(UserFederationProvider.class, model.getProviderName());
|
|
||||||
return factory.getInstance(session, model);
|
|
||||||
}
|
|
||||||
|
|
||||||
public UserFederationProvider getFederationLink(RealmModel realm, UserModel user) {
|
|
||||||
if (user.getFederationLink() == null) return null;
|
|
||||||
for (UserFederationProviderModel fed : realm.getUserFederationProviders()) {
|
|
||||||
if (fed.getId().equals(user.getFederationLink())) {
|
|
||||||
return getFederationProvider(fed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean removeUser(RealmModel realm, UserModel user) {
|
public boolean removeUser(RealmModel realm, UserModel user) {
|
||||||
UserFederationProvider link = getFederationLink(realm, user);
|
return session.userStorage().removeUser(realm, user);
|
||||||
if (link != null) {
|
|
||||||
boolean fedRemoved = link.removeUser(realm, user);
|
|
||||||
if (fedRemoved) {
|
|
||||||
boolean localRemoved = session.userStorage().removeUser(realm, user);
|
|
||||||
managedUsers.remove(user.getId());
|
|
||||||
if (!localRemoved) {
|
|
||||||
logger.warn("User possibly removed from federation provider, but failed to remove him from keycloak model");
|
|
||||||
}
|
|
||||||
return localRemoved;
|
|
||||||
} else {
|
|
||||||
logger.warn("Failed to remove user from federation provider");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return session.userStorage().removeUser(realm, user);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void validateUser(RealmModel realm, UserModel user) {
|
|
||||||
if (managedUsers.containsKey(user.getId())) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
UserFederationProvider link = getFederationLink(realm, user);
|
|
||||||
if (link != null && !link.isValid(realm, user)) {
|
|
||||||
deleteInvalidUser(realm, user);
|
|
||||||
throw new IllegalStateException("Federated user no longer valid");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void deleteInvalidUser(final RealmModel realm, final UserModel user) {
|
|
||||||
runJobInTransaction(session.getKeycloakSessionFactory(), new KeycloakSessionTask() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run(KeycloakSession session) {
|
|
||||||
RealmModel realmModel = session.realms().getRealm(realm.getId());
|
|
||||||
if (realmModel == null) return;
|
|
||||||
UserModel deletedUser = session.userStorage().getUserById(user.getId(), realmModel);
|
|
||||||
new UserManager(session).removeUser(realmModel, deletedUser, session.userStorage());
|
|
||||||
logger.debugf("Removed invalid user '%s'", user.getUsername());
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void runJobInTransaction(KeycloakSessionFactory factory, KeycloakSessionTask task) {
|
|
||||||
KeycloakSession session = factory.create();
|
|
||||||
KeycloakTransaction tx = session.getTransactionManager();
|
|
||||||
try {
|
|
||||||
tx.begin();
|
|
||||||
task.run(session);
|
|
||||||
|
|
||||||
if (tx.isActive()) {
|
|
||||||
if (tx.getRollbackOnly()) {
|
|
||||||
tx.rollback();
|
|
||||||
} else {
|
|
||||||
tx.commit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (RuntimeException re) {
|
|
||||||
if (tx.isActive()) {
|
|
||||||
tx.rollback();
|
|
||||||
}
|
|
||||||
throw re;
|
|
||||||
} finally {
|
|
||||||
session.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected UserModel validateAndProxyUser(RealmModel realm, UserModel user) {
|
|
||||||
UserModel managed = managedUsers.get(user.getId());
|
|
||||||
if (managed != null) {
|
|
||||||
return managed;
|
|
||||||
}
|
|
||||||
|
|
||||||
UserFederationProvider link = getFederationLink(realm, user);
|
|
||||||
if (link != null) {
|
|
||||||
UserModel validatedProxyUser = link.validateAndProxy(realm, user);
|
|
||||||
if (validatedProxyUser != null) {
|
|
||||||
managedUsers.put(user.getId(), validatedProxyUser);
|
|
||||||
return validatedProxyUser;
|
|
||||||
} else {
|
|
||||||
deleteInvalidUser(realm, user);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return user;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addFederatedIdentity(RealmModel realm, UserModel user, FederatedIdentityModel socialLink) {
|
public void addFederatedIdentity(RealmModel realm, UserModel user, FederatedIdentityModel socialLink) {
|
||||||
validateUser(realm, user);
|
|
||||||
session.userStorage().addFederatedIdentity(realm, user, socialLink);
|
session.userStorage().addFederatedIdentity(realm, user, socialLink);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,7 +75,6 @@ public class UserFederationManager implements UserProvider {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean removeFederatedIdentity(RealmModel realm, UserModel user, String socialProvider) {
|
public boolean removeFederatedIdentity(RealmModel realm, UserModel user, String socialProvider) {
|
||||||
validateUser(realm, user);
|
|
||||||
if (user == null) throw new IllegalStateException("Federated user no longer valid");
|
if (user == null) throw new IllegalStateException("Federated user no longer valid");
|
||||||
return session.userStorage().removeFederatedIdentity(realm, user, socialProvider);
|
return session.userStorage().removeFederatedIdentity(realm, user, socialProvider);
|
||||||
}
|
}
|
||||||
|
@ -226,10 +109,7 @@ public class UserFederationManager implements UserProvider {
|
||||||
@Override
|
@Override
|
||||||
public UserModel getUserById(String id, RealmModel realm) {
|
public UserModel getUserById(String id, RealmModel realm) {
|
||||||
UserModel user = session.userStorage().getUserById(id, realm);
|
UserModel user = session.userStorage().getUserById(id, realm);
|
||||||
if (user != null) {
|
return user;
|
||||||
user = validateAndProxyUser(realm, user);
|
|
||||||
}
|
|
||||||
return user;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -247,21 +127,7 @@ public class UserFederationManager implements UserProvider {
|
||||||
|
|
||||||
Set<UserModel> result = new LinkedHashSet<>(localMembers);
|
Set<UserModel> result = new LinkedHashSet<>(localMembers);
|
||||||
|
|
||||||
for (UserFederationProviderModel federation : realm.getUserFederationProviders()) {
|
if (result.size() <= firstResult) {
|
||||||
if (result.size() >= maxTotal) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
int max = maxTotal - result.size();
|
|
||||||
|
|
||||||
UserFederationProvider fed = getFederationProvider(federation);
|
|
||||||
List<UserModel> current = fed.getGroupMembers(realm, group, 0, max);
|
|
||||||
if (current != null) {
|
|
||||||
result.addAll(current);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result.size() <= firstResult) {
|
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -277,48 +143,24 @@ public class UserFederationManager implements UserProvider {
|
||||||
@Override
|
@Override
|
||||||
public UserModel getUserByUsername(String username, RealmModel realm) {
|
public UserModel getUserByUsername(String username, RealmModel realm) {
|
||||||
UserModel user = session.userStorage().getUserByUsername(username.toLowerCase(), realm);
|
UserModel user = session.userStorage().getUserByUsername(username.toLowerCase(), realm);
|
||||||
if (user != null) {
|
|
||||||
user = validateAndProxyUser(realm, user);
|
|
||||||
if (user != null) return user;
|
|
||||||
}
|
|
||||||
for (UserFederationProviderModel federation : realm.getUserFederationProviders()) {
|
|
||||||
UserFederationProvider fed = getFederationProvider(federation);
|
|
||||||
user = fed.getUserByUsername(realm, username);
|
|
||||||
if (user != null) return user;
|
|
||||||
}
|
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UserModel getUserByEmail(String email, RealmModel realm) {
|
public UserModel getUserByEmail(String email, RealmModel realm) {
|
||||||
UserModel user = session.userStorage().getUserByEmail(email.toLowerCase(), realm);
|
UserModel user = session.userStorage().getUserByEmail(email.toLowerCase(), realm);
|
||||||
if (user != null) {
|
return user;
|
||||||
user = validateAndProxyUser(realm, user);
|
|
||||||
if (user != null) return user;
|
|
||||||
}
|
|
||||||
for (UserFederationProviderModel federation : realm.getUserFederationProviders()) {
|
|
||||||
UserFederationProvider fed = getFederationProvider(federation);
|
|
||||||
user = fed.getUserByEmail(realm, email);
|
|
||||||
if (user != null) return user;
|
|
||||||
}
|
|
||||||
return user;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UserModel getUserByFederatedIdentity(FederatedIdentityModel socialLink, RealmModel realm) {
|
public UserModel getUserByFederatedIdentity(FederatedIdentityModel socialLink, RealmModel realm) {
|
||||||
UserModel user = session.userStorage().getUserByFederatedIdentity(socialLink, realm);
|
UserModel user = session.userStorage().getUserByFederatedIdentity(socialLink, realm);
|
||||||
if (user != null) {
|
|
||||||
user = validateAndProxyUser(realm, user);
|
|
||||||
}
|
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UserModel getServiceAccount(ClientModel client) {
|
public UserModel getServiceAccount(ClientModel client) {
|
||||||
UserModel user = session.userStorage().getServiceAccount(client);
|
UserModel user = session.userStorage().getServiceAccount(client);
|
||||||
if (user != null) {
|
|
||||||
user = validateAndProxyUser(client.getRealm(), user);
|
|
||||||
}
|
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -357,8 +199,6 @@ public class UserFederationManager implements UserProvider {
|
||||||
if (query == null || query.size() == 0) return results;
|
if (query == null || query.size() == 0) return results;
|
||||||
int added = 0;
|
int added = 0;
|
||||||
for (UserModel user : query) {
|
for (UserModel user : query) {
|
||||||
user = validateAndProxyUser(realm, user);
|
|
||||||
if (user == null) continue;
|
|
||||||
results.add(user);
|
results.add(user);
|
||||||
added++;
|
added++;
|
||||||
}
|
}
|
||||||
|
@ -385,30 +225,8 @@ public class UserFederationManager implements UserProvider {
|
||||||
return searchForUser(search, realm, 0, Integer.MAX_VALUE - 1);
|
return searchForUser(search, realm, 0, Integer.MAX_VALUE - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void federationLoad(RealmModel realm, Map<String, String> attributes) {
|
|
||||||
for (UserFederationProviderModel federation : realm.getUserFederationProviders()) {
|
|
||||||
UserFederationProvider fed = getFederationProvider(federation);
|
|
||||||
fed.searchByAttributes(attributes, realm, 30);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<UserModel> searchForUser(final String search, RealmModel realm, int firstResult, int maxResults) {
|
public List<UserModel> searchForUser(final String search, RealmModel realm, int firstResult, int maxResults) {
|
||||||
Map<String, String> attributes = new HashMap<String, String>();
|
|
||||||
int spaceIndex = search.lastIndexOf(' ');
|
|
||||||
if (spaceIndex > -1) {
|
|
||||||
String firstName = search.substring(0, spaceIndex).trim();
|
|
||||||
String lastName = search.substring(spaceIndex).trim();
|
|
||||||
attributes.put(UserModel.FIRST_NAME, firstName);
|
|
||||||
attributes.put(UserModel.LAST_NAME, lastName);
|
|
||||||
} else if (search.indexOf('@') > -1) {
|
|
||||||
attributes.put(UserModel.USERNAME, search.trim().toLowerCase());
|
|
||||||
attributes.put(UserModel.EMAIL, search.trim().toLowerCase());
|
|
||||||
} else {
|
|
||||||
attributes.put(UserModel.LAST_NAME, search.trim());
|
|
||||||
attributes.put(UserModel.USERNAME, search.trim().toLowerCase());
|
|
||||||
}
|
|
||||||
federationLoad(realm, attributes);
|
|
||||||
return query(new PaginatedQuery() {
|
return query(new PaginatedQuery() {
|
||||||
@Override
|
@Override
|
||||||
public List<UserModel> query(RealmModel realm, int first, int max) {
|
public List<UserModel> query(RealmModel realm, int first, int max) {
|
||||||
|
@ -424,7 +242,6 @@ public class UserFederationManager implements UserProvider {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<UserModel> searchForUser(final Map<String, String> attributes, RealmModel realm, int firstResult, int maxResults) {
|
public List<UserModel> searchForUser(final Map<String, String> attributes, RealmModel realm, int firstResult, int maxResults) {
|
||||||
federationLoad(realm, attributes);
|
|
||||||
return query(new PaginatedQuery() {
|
return query(new PaginatedQuery() {
|
||||||
@Override
|
@Override
|
||||||
public List<UserModel> query(RealmModel realm, int first, int max) {
|
public List<UserModel> query(RealmModel realm, int first, int max) {
|
||||||
|
@ -440,15 +257,11 @@ public class UserFederationManager implements UserProvider {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<FederatedIdentityModel> getFederatedIdentities(UserModel user, RealmModel realm) {
|
public Set<FederatedIdentityModel> getFederatedIdentities(UserModel user, RealmModel realm) {
|
||||||
validateUser(realm, user);
|
|
||||||
if (user == null) throw new IllegalStateException("Federated user no longer valid");
|
|
||||||
return session.userStorage().getFederatedIdentities(user, realm);
|
return session.userStorage().getFederatedIdentities(user, realm);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FederatedIdentityModel getFederatedIdentity(UserModel user, String socialProvider, RealmModel realm) {
|
public FederatedIdentityModel getFederatedIdentity(UserModel user, String socialProvider, RealmModel realm) {
|
||||||
validateUser(realm, user);
|
|
||||||
if (user == null) throw new IllegalStateException("Federated user no longer valid");
|
|
||||||
return session.userStorage().getFederatedIdentity(user, socialProvider, realm);
|
return session.userStorage().getFederatedIdentity(user, socialProvider, realm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -460,10 +273,6 @@ public class UserFederationManager implements UserProvider {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void preRemove(RealmModel realm) {
|
public void preRemove(RealmModel realm) {
|
||||||
for (UserFederationProviderModel federation : realm.getUserFederationProviders()) {
|
|
||||||
UserFederationProvider fed = getFederationProvider(federation);
|
|
||||||
fed.preRemove(realm);
|
|
||||||
}
|
|
||||||
session.userStorage().preRemove(realm);
|
session.userStorage().preRemove(realm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -474,20 +283,12 @@ public class UserFederationManager implements UserProvider {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void preRemove(RealmModel realm, GroupModel group) {
|
public void preRemove(RealmModel realm, GroupModel group) {
|
||||||
for (UserFederationProviderModel federation : realm.getUserFederationProviders()) {
|
|
||||||
UserFederationProvider fed = getFederationProvider(federation);
|
|
||||||
fed.preRemove(realm, group);
|
|
||||||
}
|
|
||||||
session.userStorage().preRemove(realm, group);
|
session.userStorage().preRemove(realm, group);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void preRemove(RealmModel realm, RoleModel role) {
|
public void preRemove(RealmModel realm, RoleModel role) {
|
||||||
for (UserFederationProviderModel federation : realm.getUserFederationProviders()) {
|
|
||||||
UserFederationProvider fed = getFederationProvider(federation);
|
|
||||||
fed.preRemove(realm, role);
|
|
||||||
}
|
|
||||||
session.userStorage().preRemove(realm, role);
|
session.userStorage().preRemove(realm, role);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,9 +20,19 @@ import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* If your UserStorageProvider is importing users into local storage, you can validate that import whenever the
|
||||||
|
* user is queried from local storage.
|
||||||
|
*
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
public interface ImportedUserValidation {
|
public interface ImportedUserValidation {
|
||||||
UserModel validate(RealmModel realmm, UserModel user);
|
/**
|
||||||
|
* If this method returns null, then the user storage in local storage will be removed
|
||||||
|
*
|
||||||
|
* @param realm
|
||||||
|
* @param user
|
||||||
|
* @return null if user no longer valid
|
||||||
|
*/
|
||||||
|
UserModel validate(RealmModel realm, UserModel user);
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,7 @@ import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.UserFederationManager;
|
import org.keycloak.models.UserFederationManager;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
|
import org.keycloak.models.UserProvider;
|
||||||
import org.keycloak.representations.idm.authorization.ResourceOwnerRepresentation;
|
import org.keycloak.representations.idm.authorization.ResourceOwnerRepresentation;
|
||||||
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
|
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
|
||||||
import org.keycloak.services.ErrorResponse;
|
import org.keycloak.services.ErrorResponse;
|
||||||
|
@ -93,7 +94,7 @@ public class ResourceSetService {
|
||||||
if (!resourceServer.getClientId().equals(ownerId)) {
|
if (!resourceServer.getClientId().equals(ownerId)) {
|
||||||
RealmModel realm = authorization.getRealm();
|
RealmModel realm = authorization.getRealm();
|
||||||
KeycloakSession keycloakSession = authorization.getKeycloakSession();
|
KeycloakSession keycloakSession = authorization.getKeycloakSession();
|
||||||
UserFederationManager users = keycloakSession.users();
|
UserProvider users = keycloakSession.users();
|
||||||
UserModel ownerModel = users.getUserById(ownerId, realm);
|
UserModel ownerModel = users.getUserById(ownerId, realm);
|
||||||
|
|
||||||
if (ownerModel == null) {
|
if (ownerModel == null) {
|
||||||
|
|
|
@ -120,13 +120,7 @@ public class UserCredentialStoreManager implements UserCredentialManager, OnUser
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// <deprecate>
|
if (user.getFederationLink() != null) {
|
||||||
UserFederationProvider link = session.users().getFederationLink(realm, user);
|
|
||||||
if (link != null) {
|
|
||||||
session.users().validateUser(realm, user);
|
|
||||||
validate(realm, user, toValidate, link);
|
|
||||||
} // </deprecate>
|
|
||||||
else if (user.getFederationLink() != null) {
|
|
||||||
UserStorageProvider provider = UserStorageManager.getStorageProvider(session, realm, user.getFederationLink());
|
UserStorageProvider provider = UserStorageManager.getStorageProvider(session, realm, user.getFederationLink());
|
||||||
if (provider != null && provider instanceof CredentialInputValidator) {
|
if (provider != null && provider instanceof CredentialInputValidator) {
|
||||||
validate(realm, user, toValidate, ((CredentialInputValidator)provider));
|
validate(realm, user, toValidate, ((CredentialInputValidator)provider));
|
||||||
|
@ -176,13 +170,7 @@ public class UserCredentialStoreManager implements UserCredentialManager, OnUser
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// <deprecated>
|
if (user.getFederationLink() != null) {
|
||||||
UserFederationProvider link = session.users().getFederationLink(realm, user);
|
|
||||||
if (link != null) {
|
|
||||||
if (link.updateCredential(realm, user, input)) return;
|
|
||||||
}
|
|
||||||
// </deprecated>
|
|
||||||
else if (user.getFederationLink() != null) {
|
|
||||||
UserStorageProvider provider = UserStorageManager.getStorageProvider(session, realm, user.getFederationLink());
|
UserStorageProvider provider = UserStorageManager.getStorageProvider(session, realm, user.getFederationLink());
|
||||||
if (provider != null && provider instanceof CredentialInputUpdater) {
|
if (provider != null && provider instanceof CredentialInputUpdater) {
|
||||||
if (((CredentialInputUpdater)provider).updateCredential(realm, user, input)) return;
|
if (((CredentialInputUpdater)provider).updateCredential(realm, user, input)) return;
|
||||||
|
@ -209,11 +197,7 @@ public class UserCredentialStoreManager implements UserCredentialManager, OnUser
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
UserFederationProvider link = session.users().getFederationLink(realm, user);
|
if (user.getFederationLink() != null) {
|
||||||
if (link != null && link.getSupportedCredentialTypes().contains(credentialType)) {
|
|
||||||
link.disableCredentialType(realm, user, credentialType);
|
|
||||||
}
|
|
||||||
else if (user.getFederationLink() != null) {
|
|
||||||
UserStorageProvider provider = UserStorageManager.getStorageProvider(session, realm, user.getFederationLink());
|
UserStorageProvider provider = UserStorageManager.getStorageProvider(session, realm, user.getFederationLink());
|
||||||
if (provider != null && provider instanceof CredentialInputUpdater) {
|
if (provider != null && provider instanceof CredentialInputUpdater) {
|
||||||
((CredentialInputUpdater)provider).disableCredentialType(realm, user, credentialType);
|
((CredentialInputUpdater)provider).disableCredentialType(realm, user, credentialType);
|
||||||
|
@ -243,11 +227,7 @@ public class UserCredentialStoreManager implements UserCredentialManager, OnUser
|
||||||
types.addAll(updater.getDisableableCredentialTypes(realm, user));
|
types.addAll(updater.getDisableableCredentialTypes(realm, user));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
UserFederationProvider link = session.users().getFederationLink(realm, user);
|
if (user.getFederationLink() != null) {
|
||||||
if (link != null) {
|
|
||||||
types.addAll(link.getDisableableCredentialTypes(realm, user));
|
|
||||||
}
|
|
||||||
else if (user.getFederationLink() != null) {
|
|
||||||
UserStorageProvider provider = UserStorageManager.getStorageProvider(session, realm, user.getFederationLink());
|
UserStorageProvider provider = UserStorageManager.getStorageProvider(session, realm, user.getFederationLink());
|
||||||
if (provider != null && provider instanceof CredentialInputUpdater) {
|
if (provider != null && provider instanceof CredentialInputUpdater) {
|
||||||
types.addAll(((CredentialInputUpdater)provider).getDisableableCredentialTypes(realm, user));
|
types.addAll(((CredentialInputUpdater)provider).getDisableableCredentialTypes(realm, user));
|
||||||
|
@ -275,13 +255,7 @@ public class UserCredentialStoreManager implements UserCredentialManager, OnUser
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// <deprecate>
|
if (user.getFederationLink() != null) {
|
||||||
UserFederationProvider link = session.users().getFederationLink(realm, user);
|
|
||||||
if (link != null) {
|
|
||||||
if (link.isConfiguredFor(realm, user, type)) return true;
|
|
||||||
}
|
|
||||||
// </deprecate>
|
|
||||||
else if (user.getFederationLink() != null) {
|
|
||||||
UserStorageProvider provider = UserStorageManager.getStorageProvider(session, realm, user.getFederationLink());
|
UserStorageProvider provider = UserStorageManager.getStorageProvider(session, realm, user.getFederationLink());
|
||||||
if (provider != null && provider instanceof CredentialInputValidator) {
|
if (provider != null && provider instanceof CredentialInputValidator) {
|
||||||
if (((CredentialInputValidator)provider).isConfiguredFor(realm, user, type)) return true;
|
if (((CredentialInputValidator)provider).isConfiguredFor(realm, user, type)) return true;
|
||||||
|
@ -307,16 +281,6 @@ public class UserCredentialStoreManager implements UserCredentialManager, OnUser
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CredentialValidationOutput authenticate(KeycloakSession session, RealmModel realm, CredentialInput input) {
|
public CredentialValidationOutput authenticate(KeycloakSession session, RealmModel realm, CredentialInput input) {
|
||||||
List<UserFederationProviderModel> fedProviderModels = realm.getUserFederationProviders();
|
|
||||||
List<UserFederationProvider> fedProviders = new ArrayList<UserFederationProvider>();
|
|
||||||
for (UserFederationProviderModel fedProviderModel : fedProviderModels) {
|
|
||||||
UserFederationProvider provider = session.users().getFederationProvider(fedProviderModel);
|
|
||||||
if (input instanceof UserCredentialModel && provider != null && provider.supportsCredentialType(input.getType())) {
|
|
||||||
CredentialValidationOutput output = provider.validCredentials(realm, (UserCredentialModel)input);
|
|
||||||
if (output != null) return output;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
List<CredentialAuthentication> list = UserStorageManager.getStorageProviders(session, realm, CredentialAuthentication.class);
|
List<CredentialAuthentication> list = UserStorageManager.getStorageProviders(session, realm, CredentialAuthentication.class);
|
||||||
for (CredentialAuthentication auth : list) {
|
for (CredentialAuthentication auth : list) {
|
||||||
if (auth.supportsCredentialAuthenticationFor(input.getType())) {
|
if (auth.supportsCredentialAuthenticationFor(input.getType())) {
|
||||||
|
|
|
@ -46,6 +46,7 @@ import org.keycloak.models.RoleModel;
|
||||||
import org.keycloak.models.UserConsentModel;
|
import org.keycloak.models.UserConsentModel;
|
||||||
import org.keycloak.models.UserFederationManager;
|
import org.keycloak.models.UserFederationManager;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
|
import org.keycloak.models.UserProvider;
|
||||||
import org.keycloak.models.utils.ModelToRepresentation;
|
import org.keycloak.models.utils.ModelToRepresentation;
|
||||||
import org.keycloak.representations.idm.ClientRepresentation;
|
import org.keycloak.representations.idm.ClientRepresentation;
|
||||||
import org.keycloak.representations.idm.ClientTemplateRepresentation;
|
import org.keycloak.representations.idm.ClientTemplateRepresentation;
|
||||||
|
@ -358,7 +359,7 @@ public class ExportUtils {
|
||||||
String users = config.get("users");
|
String users = config.get("users");
|
||||||
|
|
||||||
if (users != null && !users.isEmpty()) {
|
if (users != null && !users.isEmpty()) {
|
||||||
UserFederationManager userManager = session.users();
|
UserProvider userManager = session.users();
|
||||||
List<String> userIds = JsonSerialization.readValue(users, List.class);
|
List<String> userIds = JsonSerialization.readValue(users, List.class);
|
||||||
config.put("users", JsonSerialization.writeValueAsString(userIds.stream().map(userId -> userManager.getUserById(userId, realm).getUsername()).collect(Collectors.toList())));
|
config.put("users", JsonSerialization.writeValueAsString(userIds.stream().map(userId -> userManager.getUserById(userId, realm).getUsername()).collect(Collectors.toList())));
|
||||||
}
|
}
|
||||||
|
|
|
@ -228,7 +228,6 @@ public class RealmManager implements RealmImporter {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean removeRealm(RealmModel realm) {
|
public boolean removeRealm(RealmModel realm) {
|
||||||
List<UserFederationProviderModel> federationProviders = realm.getUserFederationProviders();
|
|
||||||
|
|
||||||
ClientModel masterAdminClient = realm.getMasterAdminClient();
|
ClientModel masterAdminClient = realm.getMasterAdminClient();
|
||||||
boolean removed = model.removeRealm(realm.getId());
|
boolean removed = model.removeRealm(realm.getId());
|
||||||
|
@ -247,11 +246,13 @@ public class RealmManager implements RealmImporter {
|
||||||
sessionsPersister.onRealmRemoved(realm);
|
sessionsPersister.onRealmRemoved(realm);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove all periodic syncs for configured federation providers
|
// Refresh periodic sync tasks for configured storageProviders
|
||||||
UsersSyncManager usersSyncManager = new UsersSyncManager();
|
List<UserStorageProviderModel> storageProviders = realm.getUserStorageProviders();
|
||||||
for (final UserFederationProviderModel fedProvider : federationProviders) {
|
UserStorageSyncManager storageSync = new UserStorageSyncManager();
|
||||||
usersSyncManager.notifyToRefreshPeriodicSync(session, realm, fedProvider, true);
|
for (UserStorageProviderModel provider : storageProviders) {
|
||||||
|
storageSync.notifyToRefreshPeriodicSync(session, realm, provider, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return removed;
|
return removed;
|
||||||
}
|
}
|
||||||
|
@ -487,13 +488,6 @@ public class RealmManager implements RealmImporter {
|
||||||
setupAuthenticationFlows(realm);
|
setupAuthenticationFlows(realm);
|
||||||
setupRequiredActions(realm);
|
setupRequiredActions(realm);
|
||||||
|
|
||||||
// Refresh periodic sync tasks for configured federationProviders
|
|
||||||
List<UserFederationProviderModel> federationProviders = realm.getUserFederationProviders();
|
|
||||||
UsersSyncManager usersSyncManager = new UsersSyncManager();
|
|
||||||
for (final UserFederationProviderModel fedProvider : federationProviders) {
|
|
||||||
usersSyncManager.notifyToRefreshPeriodicSync(session, realm, fedProvider, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Refresh periodic sync tasks for configured storageProviders
|
// Refresh periodic sync tasks for configured storageProviders
|
||||||
List<UserStorageProviderModel> storageProviders = realm.getUserStorageProviders();
|
List<UserStorageProviderModel> storageProviders = realm.getUserStorageProviders();
|
||||||
UserStorageSyncManager storageSync = new UserStorageSyncManager();
|
UserStorageSyncManager storageSync = new UserStorageSyncManager();
|
||||||
|
|
|
@ -1,327 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
|
||||||
* and other contributors as indicated by the @author tags.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.keycloak.services.managers;
|
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
|
||||||
import org.keycloak.cluster.ClusterEvent;
|
|
||||||
import org.keycloak.cluster.ClusterListener;
|
|
||||||
import org.keycloak.cluster.ClusterProvider;
|
|
||||||
import org.keycloak.cluster.ExecutionResult;
|
|
||||||
import org.keycloak.common.util.Time;
|
|
||||||
import org.keycloak.models.KeycloakSession;
|
|
||||||
import org.keycloak.models.KeycloakSessionFactory;
|
|
||||||
import org.keycloak.models.KeycloakSessionTask;
|
|
||||||
import org.keycloak.models.RealmModel;
|
|
||||||
import org.keycloak.models.UserFederationProvider;
|
|
||||||
import org.keycloak.models.UserFederationProviderFactory;
|
|
||||||
import org.keycloak.models.UserFederationProviderModel;
|
|
||||||
import org.keycloak.models.UserFederationSyncResult;
|
|
||||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
|
||||||
import org.keycloak.services.ServicesLogger;
|
|
||||||
import org.keycloak.timer.TimerProvider;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.Callable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
|
||||||
*/
|
|
||||||
public class UsersSyncManager {
|
|
||||||
|
|
||||||
private static final String FEDERATION_TASK_KEY = "federation";
|
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(UsersSyncManager.class);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check federationProviderModel of all realms and possibly start periodic sync for them
|
|
||||||
*
|
|
||||||
* @param sessionFactory
|
|
||||||
* @param timer
|
|
||||||
*/
|
|
||||||
public void bootstrapPeriodic(final KeycloakSessionFactory sessionFactory, final TimerProvider timer) {
|
|
||||||
KeycloakModelUtils.runJobInTransaction(sessionFactory, new KeycloakSessionTask() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run(KeycloakSession session) {
|
|
||||||
List<RealmModel> realms = session.realms().getRealms();
|
|
||||||
for (final RealmModel realm : realms) {
|
|
||||||
List<UserFederationProviderModel> federationProviders = realm.getUserFederationProviders();
|
|
||||||
for (final UserFederationProviderModel fedProvider : federationProviders) {
|
|
||||||
refreshPeriodicSyncForProvider(sessionFactory, timer, fedProvider, realm.getId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ClusterProvider clusterProvider = session.getProvider(ClusterProvider.class);
|
|
||||||
clusterProvider.registerListener(FEDERATION_TASK_KEY, new UserFederationClusterListener(sessionFactory));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private class Holder {
|
|
||||||
ExecutionResult<UserFederationSyncResult> result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public UserFederationSyncResult syncAllUsers(final KeycloakSessionFactory sessionFactory, final String realmId, final UserFederationProviderModel fedProvider) {
|
|
||||||
final Holder holder = new Holder();
|
|
||||||
|
|
||||||
// Ensure not executed concurrently on this or any other cluster node
|
|
||||||
KeycloakModelUtils.runJobInTransaction(sessionFactory, new KeycloakSessionTask() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run(KeycloakSession session) {
|
|
||||||
ClusterProvider clusterProvider = session.getProvider(ClusterProvider.class);
|
|
||||||
// shared key for "full" and "changed" . Improve if needed
|
|
||||||
String taskKey = fedProvider.getId() + "::sync";
|
|
||||||
|
|
||||||
// 30 seconds minimal timeout for now
|
|
||||||
int timeout = Math.max(30, fedProvider.getFullSyncPeriod());
|
|
||||||
holder.result = clusterProvider.executeIfNotExecuted(taskKey, timeout, new Callable<UserFederationSyncResult>() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UserFederationSyncResult call() throws Exception {
|
|
||||||
final UserFederationProviderFactory fedProviderFactory = (UserFederationProviderFactory) sessionFactory.getProviderFactory(UserFederationProvider.class, fedProvider.getProviderName());
|
|
||||||
updateLastSyncInterval(sessionFactory, fedProvider, realmId);
|
|
||||||
return fedProviderFactory.syncAllUsers(sessionFactory, realmId, fedProvider);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
if (holder.result == null || !holder.result.isExecuted()) {
|
|
||||||
logger.debugf("syncAllUsers for federation provider %s was ignored as it's already in progress", fedProvider.getDisplayName());
|
|
||||||
return UserFederationSyncResult.ignored();
|
|
||||||
} else {
|
|
||||||
return holder.result.getResult();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public UserFederationSyncResult syncChangedUsers(final KeycloakSessionFactory sessionFactory, final String realmId, final UserFederationProviderModel fedProvider) {
|
|
||||||
final Holder holder = new Holder();
|
|
||||||
|
|
||||||
// Ensure not executed concurrently on this or any other cluster node
|
|
||||||
KeycloakModelUtils.runJobInTransaction(sessionFactory, new KeycloakSessionTask() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run(KeycloakSession session) {
|
|
||||||
ClusterProvider clusterProvider = session.getProvider(ClusterProvider.class);
|
|
||||||
// shared key for "full" and "changed" . Improve if needed
|
|
||||||
String taskKey = fedProvider.getId() + "::sync";
|
|
||||||
|
|
||||||
// 30 seconds minimal timeout for now
|
|
||||||
int timeout = Math.max(30, fedProvider.getChangedSyncPeriod());
|
|
||||||
holder.result = clusterProvider.executeIfNotExecuted(taskKey, timeout, new Callable<UserFederationSyncResult>() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UserFederationSyncResult call() throws Exception {
|
|
||||||
final UserFederationProviderFactory fedProviderFactory = (UserFederationProviderFactory) sessionFactory.getProviderFactory(UserFederationProvider.class, fedProvider.getProviderName());
|
|
||||||
|
|
||||||
// See when we did last sync.
|
|
||||||
int oldLastSync = fedProvider.getLastSync();
|
|
||||||
updateLastSyncInterval(sessionFactory, fedProvider, realmId);
|
|
||||||
return fedProviderFactory.syncChangedUsers(sessionFactory, realmId, fedProvider, Time.toDate(oldLastSync));
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
if (holder.result == null || !holder.result.isExecuted()) {
|
|
||||||
logger.debugf("syncChangedUsers for federation provider %s was ignored as it's already in progress", fedProvider.getDisplayName());
|
|
||||||
return UserFederationSyncResult.ignored();
|
|
||||||
} else {
|
|
||||||
return holder.result.getResult();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Ensure all cluster nodes are notified
|
|
||||||
public void notifyToRefreshPeriodicSync(KeycloakSession session, RealmModel realm, UserFederationProviderModel federationProvider, boolean removed) {
|
|
||||||
FederationProviderClusterEvent event = FederationProviderClusterEvent.createEvent(removed, realm.getId(), federationProvider);
|
|
||||||
session.getProvider(ClusterProvider.class).notify(FEDERATION_TASK_KEY, event, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Executed once it receives notification that some UserFederationProvider was created or updated
|
|
||||||
protected void refreshPeriodicSyncForProvider(final KeycloakSessionFactory sessionFactory, TimerProvider timer, final UserFederationProviderModel fedProvider, final String realmId) {
|
|
||||||
logger.debugf("Going to refresh periodic sync for provider '%s' . Full sync period: %d , changed users sync period: %d",
|
|
||||||
fedProvider.getDisplayName(), fedProvider.getFullSyncPeriod(), fedProvider.getChangedSyncPeriod());
|
|
||||||
|
|
||||||
if (fedProvider.getFullSyncPeriod() > 0) {
|
|
||||||
// We want periodic full sync for this provider
|
|
||||||
timer.schedule(new Runnable() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
boolean shouldPerformSync = shouldPerformNewPeriodicSync(fedProvider.getLastSync(), fedProvider.getChangedSyncPeriod());
|
|
||||||
if (shouldPerformSync) {
|
|
||||||
syncAllUsers(sessionFactory, realmId, fedProvider);
|
|
||||||
} else {
|
|
||||||
logger.debugf("Ignored periodic full sync with federation provider %s due small time since last sync", fedProvider.getDisplayName());
|
|
||||||
}
|
|
||||||
} catch (Throwable t) {
|
|
||||||
ServicesLogger.LOGGER.errorDuringFullUserSync(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}, fedProvider.getFullSyncPeriod() * 1000, fedProvider.getId() + "-FULL");
|
|
||||||
} else {
|
|
||||||
timer.cancelTask(fedProvider.getId() + "-FULL");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fedProvider.getChangedSyncPeriod() > 0) {
|
|
||||||
// We want periodic sync of just changed users for this provider
|
|
||||||
timer.schedule(new Runnable() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
boolean shouldPerformSync = shouldPerformNewPeriodicSync(fedProvider.getLastSync(), fedProvider.getChangedSyncPeriod());
|
|
||||||
if (shouldPerformSync) {
|
|
||||||
syncChangedUsers(sessionFactory, realmId, fedProvider);
|
|
||||||
} else {
|
|
||||||
logger.debugf("Ignored periodic changed-users sync with federation provider %s due small time since last sync", fedProvider.getDisplayName());
|
|
||||||
}
|
|
||||||
} catch (Throwable t) {
|
|
||||||
ServicesLogger.LOGGER.errorDuringChangedUserSync(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}, fedProvider.getChangedSyncPeriod() * 1000, fedProvider.getId() + "-CHANGED");
|
|
||||||
|
|
||||||
} else {
|
|
||||||
timer.cancelTask(fedProvider.getId() + "-CHANGED");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip syncing if there is short time since last sync time.
|
|
||||||
private boolean shouldPerformNewPeriodicSync(int lastSyncTime, int period) {
|
|
||||||
if (lastSyncTime <= 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int currentTime = Time.currentTime();
|
|
||||||
int timeSinceLastSync = currentTime - lastSyncTime;
|
|
||||||
|
|
||||||
return (timeSinceLastSync * 2 > period);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Executed once it receives notification that some UserFederationProvider was removed
|
|
||||||
protected void removePeriodicSyncForProvider(TimerProvider timer, UserFederationProviderModel fedProvider) {
|
|
||||||
logger.debugf("Removing periodic sync for provider %s", fedProvider.getDisplayName());
|
|
||||||
timer.cancelTask(fedProvider.getId() + "-FULL");
|
|
||||||
timer.cancelTask(fedProvider.getId() + "-CHANGED");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update interval of last sync for given UserFederationProviderModel. Do it in separate transaction
|
|
||||||
private void updateLastSyncInterval(final KeycloakSessionFactory sessionFactory, final UserFederationProviderModel fedProvider, final String realmId) {
|
|
||||||
KeycloakModelUtils.runJobInTransaction(sessionFactory, new KeycloakSessionTask() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run(KeycloakSession session) {
|
|
||||||
RealmModel persistentRealm = session.realms().getRealm(realmId);
|
|
||||||
List<UserFederationProviderModel> persistentFedProviders = persistentRealm.getUserFederationProviders();
|
|
||||||
for (UserFederationProviderModel persistentFedProvider : persistentFedProviders) {
|
|
||||||
if (fedProvider.getId().equals(persistentFedProvider.getId())) {
|
|
||||||
// Update persistent provider in DB
|
|
||||||
int lastSync = Time.currentTime();
|
|
||||||
persistentFedProvider.setLastSync(lastSync);
|
|
||||||
persistentRealm.updateUserFederationProvider(persistentFedProvider);
|
|
||||||
|
|
||||||
// Update "cached" reference
|
|
||||||
fedProvider.setLastSync(lastSync);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private class UserFederationClusterListener implements ClusterListener {
|
|
||||||
|
|
||||||
private final KeycloakSessionFactory sessionFactory;
|
|
||||||
|
|
||||||
public UserFederationClusterListener(KeycloakSessionFactory sessionFactory) {
|
|
||||||
this.sessionFactory = sessionFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void eventReceived(ClusterEvent event) {
|
|
||||||
final FederationProviderClusterEvent fedEvent = (FederationProviderClusterEvent) event;
|
|
||||||
KeycloakModelUtils.runJobInTransaction(sessionFactory, new KeycloakSessionTask() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run(KeycloakSession session) {
|
|
||||||
TimerProvider timer = session.getProvider(TimerProvider.class);
|
|
||||||
if (fedEvent.isRemoved()) {
|
|
||||||
removePeriodicSyncForProvider(timer, fedEvent.getFederationProvider());
|
|
||||||
} else {
|
|
||||||
refreshPeriodicSyncForProvider(sessionFactory, timer, fedEvent.getFederationProvider(), fedEvent.getRealmId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Send to cluster during each update or remove of federationProvider, so all nodes can update sync periods
|
|
||||||
public static class FederationProviderClusterEvent implements ClusterEvent {
|
|
||||||
|
|
||||||
private boolean removed;
|
|
||||||
private String realmId;
|
|
||||||
private UserFederationProviderModel federationProvider;
|
|
||||||
|
|
||||||
public boolean isRemoved() {
|
|
||||||
return removed;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRemoved(boolean removed) {
|
|
||||||
this.removed = removed;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getRealmId() {
|
|
||||||
return realmId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRealmId(String realmId) {
|
|
||||||
this.realmId = realmId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public UserFederationProviderModel getFederationProvider() {
|
|
||||||
return federationProvider;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setFederationProvider(UserFederationProviderModel federationProvider) {
|
|
||||||
this.federationProvider = federationProvider;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static FederationProviderClusterEvent createEvent(boolean removed, String realmId, UserFederationProviderModel fedProvider) {
|
|
||||||
FederationProviderClusterEvent notification = new FederationProviderClusterEvent();
|
|
||||||
notification.setRemoved(removed);
|
|
||||||
notification.setRealmId(realmId);
|
|
||||||
notification.setFederationProvider(fedProvider);
|
|
||||||
return notification;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -46,7 +46,6 @@ import org.keycloak.services.filters.KeycloakTransactionCommitter;
|
||||||
import org.keycloak.services.managers.ApplianceBootstrap;
|
import org.keycloak.services.managers.ApplianceBootstrap;
|
||||||
import org.keycloak.services.managers.RealmManager;
|
import org.keycloak.services.managers.RealmManager;
|
||||||
import org.keycloak.services.managers.UserStorageSyncManager;
|
import org.keycloak.services.managers.UserStorageSyncManager;
|
||||||
import org.keycloak.services.managers.UsersSyncManager;
|
|
||||||
import org.keycloak.services.resources.admin.AdminRoot;
|
import org.keycloak.services.resources.admin.AdminRoot;
|
||||||
import org.keycloak.services.scheduled.ClearExpiredEvents;
|
import org.keycloak.services.scheduled.ClearExpiredEvents;
|
||||||
import org.keycloak.services.scheduled.ClearExpiredUserSessions;
|
import org.keycloak.services.scheduled.ClearExpiredUserSessions;
|
||||||
|
@ -323,7 +322,6 @@ public class KeycloakApplication extends Application {
|
||||||
TimerProvider timer = session.getProvider(TimerProvider.class);
|
TimerProvider timer = session.getProvider(TimerProvider.class);
|
||||||
timer.schedule(new ClusterAwareScheduledTaskRunner(sessionFactory, new ClearExpiredEvents(), interval), interval, "ClearExpiredEvents");
|
timer.schedule(new ClusterAwareScheduledTaskRunner(sessionFactory, new ClearExpiredEvents(), interval), interval, "ClearExpiredEvents");
|
||||||
timer.schedule(new ScheduledTaskRunner(sessionFactory, new ClearExpiredUserSessions()), interval, "ClearExpiredUserSessions");
|
timer.schedule(new ScheduledTaskRunner(sessionFactory, new ClearExpiredUserSessions()), interval, "ClearExpiredUserSessions");
|
||||||
new UsersSyncManager().bootstrapPeriodic(sessionFactory, timer);
|
|
||||||
new UserStorageSyncManager().bootstrapPeriodic(sessionFactory, timer);
|
new UserStorageSyncManager().bootstrapPeriodic(sessionFactory, timer);
|
||||||
} finally {
|
} finally {
|
||||||
session.close();
|
session.close();
|
||||||
|
|
|
@ -42,7 +42,6 @@ import org.keycloak.models.GroupModel;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.ModelDuplicateException;
|
import org.keycloak.models.ModelDuplicateException;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.UserFederationProviderModel;
|
|
||||||
import org.keycloak.models.UserSessionModel;
|
import org.keycloak.models.UserSessionModel;
|
||||||
import org.keycloak.models.cache.CacheRealmProvider;
|
import org.keycloak.models.cache.CacheRealmProvider;
|
||||||
import org.keycloak.models.cache.UserCache;
|
import org.keycloak.models.cache.UserCache;
|
||||||
|
@ -66,8 +65,9 @@ import org.keycloak.services.managers.AuthenticationManager;
|
||||||
import org.keycloak.services.managers.LDAPConnectionTestManager;
|
import org.keycloak.services.managers.LDAPConnectionTestManager;
|
||||||
import org.keycloak.services.managers.RealmManager;
|
import org.keycloak.services.managers.RealmManager;
|
||||||
import org.keycloak.services.managers.ResourceAdminManager;
|
import org.keycloak.services.managers.ResourceAdminManager;
|
||||||
import org.keycloak.services.managers.UsersSyncManager;
|
import org.keycloak.services.managers.UserStorageSyncManager;
|
||||||
import org.keycloak.services.resources.admin.RealmAuth.Resource;
|
import org.keycloak.services.resources.admin.RealmAuth.Resource;
|
||||||
|
import org.keycloak.storage.UserStorageProviderModel;
|
||||||
|
|
||||||
import javax.ws.rs.Consumes;
|
import javax.ws.rs.Consumes;
|
||||||
import javax.ws.rs.DELETE;
|
import javax.ws.rs.DELETE;
|
||||||
|
@ -304,9 +304,9 @@ public class RealmAdminResource {
|
||||||
RepresentationToModel.updateRealm(rep, realm, session);
|
RepresentationToModel.updateRealm(rep, realm, session);
|
||||||
|
|
||||||
// Refresh periodic sync tasks for configured federationProviders
|
// Refresh periodic sync tasks for configured federationProviders
|
||||||
List<UserFederationProviderModel> federationProviders = realm.getUserFederationProviders();
|
List<UserStorageProviderModel> federationProviders = realm.getUserStorageProviders();
|
||||||
UsersSyncManager usersSyncManager = new UsersSyncManager();
|
UserStorageSyncManager usersSyncManager = new UserStorageSyncManager();
|
||||||
for (final UserFederationProviderModel fedProvider : federationProviders) {
|
for (final UserStorageProviderModel fedProvider : federationProviders) {
|
||||||
usersSyncManager.notifyToRefreshPeriodicSync(session, realm, fedProvider, false);
|
usersSyncManager.notifyToRefreshPeriodicSync(session, realm, fedProvider, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -348,14 +348,6 @@ public class RealmAdminResource {
|
||||||
return users;
|
return users;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Path("user-federation")
|
|
||||||
public UserFederationProvidersResource userFederation() {
|
|
||||||
UserFederationProvidersResource fed = new UserFederationProvidersResource(realm, auth, adminEvent);
|
|
||||||
ResteasyProviderFactory.getInstance().injectProperties(fed);
|
|
||||||
//resourceContext.initResource(fed);
|
|
||||||
return fed;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Path("user-storage")
|
@Path("user-storage")
|
||||||
public UserStorageProviderResource userStorage() {
|
public UserStorageProviderResource userStorage() {
|
||||||
UserStorageProviderResource fed = new UserStorageProviderResource(realm, auth, adminEvent);
|
UserStorageProviderResource fed = new UserStorageProviderResource(realm, auth, adminEvent);
|
||||||
|
|
|
@ -1,459 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
|
||||||
* and other contributors as indicated by the @author tags.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.keycloak.services.resources.admin;
|
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
|
||||||
import org.jboss.resteasy.annotations.cache.NoCache;
|
|
||||||
import org.jboss.resteasy.spi.NotFoundException;
|
|
||||||
import org.keycloak.events.admin.OperationType;
|
|
||||||
import org.keycloak.events.admin.ResourceType;
|
|
||||||
import org.keycloak.mappers.FederationConfigValidationException;
|
|
||||||
import org.keycloak.mappers.UserFederationMapper;
|
|
||||||
import org.keycloak.mappers.UserFederationMapperFactory;
|
|
||||||
import org.keycloak.models.KeycloakSession;
|
|
||||||
import org.keycloak.models.KeycloakSessionFactory;
|
|
||||||
import org.keycloak.models.ModelDuplicateException;
|
|
||||||
import org.keycloak.models.ModelException;
|
|
||||||
import org.keycloak.models.RealmModel;
|
|
||||||
import org.keycloak.models.UserFederationMapperModel;
|
|
||||||
import org.keycloak.models.UserFederationProvider;
|
|
||||||
import org.keycloak.models.UserFederationProviderFactory;
|
|
||||||
import org.keycloak.models.UserFederationProviderModel;
|
|
||||||
import org.keycloak.models.UserFederationSyncResult;
|
|
||||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
|
||||||
import org.keycloak.models.utils.ModelToRepresentation;
|
|
||||||
import org.keycloak.models.utils.RepresentationToModel;
|
|
||||||
import org.keycloak.provider.ProviderConfigProperty;
|
|
||||||
import org.keycloak.provider.ProviderFactory;
|
|
||||||
import org.keycloak.representations.idm.ConfigPropertyRepresentation;
|
|
||||||
import org.keycloak.representations.idm.UserFederationMapperRepresentation;
|
|
||||||
import org.keycloak.representations.idm.UserFederationMapperTypeRepresentation;
|
|
||||||
import org.keycloak.representations.idm.UserFederationProviderRepresentation;
|
|
||||||
import org.keycloak.services.ErrorResponse;
|
|
||||||
import org.keycloak.services.ErrorResponseException;
|
|
||||||
import org.keycloak.services.ServicesLogger;
|
|
||||||
import org.keycloak.services.managers.UsersSyncManager;
|
|
||||||
|
|
||||||
import javax.ws.rs.Consumes;
|
|
||||||
import javax.ws.rs.DELETE;
|
|
||||||
import javax.ws.rs.GET;
|
|
||||||
import javax.ws.rs.POST;
|
|
||||||
import javax.ws.rs.PUT;
|
|
||||||
import javax.ws.rs.Path;
|
|
||||||
import javax.ws.rs.PathParam;
|
|
||||||
import javax.ws.rs.Produces;
|
|
||||||
import javax.ws.rs.QueryParam;
|
|
||||||
import javax.ws.rs.core.Context;
|
|
||||||
import javax.ws.rs.core.MediaType;
|
|
||||||
import javax.ws.rs.core.Response;
|
|
||||||
import javax.ws.rs.core.UriInfo;
|
|
||||||
import java.text.MessageFormat;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Properties;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
|
||||||
*/
|
|
||||||
public class UserFederationProviderResource {
|
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(UserFederationProviderResource.class);
|
|
||||||
|
|
||||||
private final KeycloakSession session;
|
|
||||||
private final RealmModel realm;
|
|
||||||
private final RealmAuth auth;
|
|
||||||
private final UserFederationProviderModel federationProviderModel;
|
|
||||||
private final AdminEventBuilder adminEvent;
|
|
||||||
|
|
||||||
@Context
|
|
||||||
private UriInfo uriInfo;
|
|
||||||
|
|
||||||
public UserFederationProviderResource(KeycloakSession session, RealmModel realm, RealmAuth auth, UserFederationProviderModel federationProviderModel, AdminEventBuilder adminEvent) {
|
|
||||||
this.session = session;
|
|
||||||
this.realm = realm;
|
|
||||||
this.auth = auth;
|
|
||||||
this.federationProviderModel = federationProviderModel;
|
|
||||||
this.adminEvent = adminEvent.resource(ResourceType.USER_FEDERATION_PROVIDER);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update a provider
|
|
||||||
*
|
|
||||||
* @param rep
|
|
||||||
*/
|
|
||||||
@PUT
|
|
||||||
@NoCache
|
|
||||||
@Consumes(MediaType.APPLICATION_JSON)
|
|
||||||
public Response updateProviderInstance(UserFederationProviderRepresentation rep) {
|
|
||||||
auth.requireManage();
|
|
||||||
|
|
||||||
if (federationProviderModel == null) {
|
|
||||||
throw new NotFoundException("Could not find federation provider");
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
String displayName = rep.getDisplayName();
|
|
||||||
if (displayName != null && displayName.trim().equals("")) {
|
|
||||||
displayName = null;
|
|
||||||
}
|
|
||||||
UserFederationProviderModel model = new UserFederationProviderModel(rep.getId(), rep.getProviderName(), rep.getConfig(), rep.getPriority(), displayName,
|
|
||||||
rep.getFullSyncPeriod(), rep.getChangedSyncPeriod(), rep.getLastSync());
|
|
||||||
|
|
||||||
UserFederationProvidersResource.validateFederationProviderConfig(session, auth, realm, model);
|
|
||||||
|
|
||||||
realm.updateUserFederationProvider(model);
|
|
||||||
new UsersSyncManager().notifyToRefreshPeriodicSync(session, realm, model, false);
|
|
||||||
boolean kerberosCredsAdded = UserFederationProvidersResource.checkKerberosCredential(session, realm, model);
|
|
||||||
if (kerberosCredsAdded) {
|
|
||||||
ServicesLogger.LOGGER.addedKerberosToRealmCredentials();
|
|
||||||
}
|
|
||||||
|
|
||||||
adminEvent.operation(OperationType.UPDATE).resourcePath(uriInfo).representation(rep).success();
|
|
||||||
return Response.noContent().build();
|
|
||||||
} catch (ModelDuplicateException e) {
|
|
||||||
if (session.getTransactionManager().isActive()) {
|
|
||||||
session.getTransactionManager().setRollbackOnly();
|
|
||||||
}
|
|
||||||
return ErrorResponse.exists("Federation provider exists with same name.");
|
|
||||||
} catch (ModelException me) {
|
|
||||||
if (session.getTransactionManager().isActive()) {
|
|
||||||
session.getTransactionManager().setRollbackOnly();
|
|
||||||
}
|
|
||||||
return ErrorResponse.error("Unable to update federation provider.", Response.Status.INTERNAL_SERVER_ERROR);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a provider
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@GET
|
|
||||||
@NoCache
|
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
|
||||||
public UserFederationProviderRepresentation getProviderInstance() {
|
|
||||||
auth.requireView();
|
|
||||||
|
|
||||||
if (federationProviderModel == null) {
|
|
||||||
throw new NotFoundException("Could not find federation provider");
|
|
||||||
}
|
|
||||||
|
|
||||||
return ModelToRepresentation.toRepresentation(this.federationProviderModel);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete a provider
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@DELETE
|
|
||||||
@NoCache
|
|
||||||
public void deleteProviderInstance() {
|
|
||||||
auth.requireManage();
|
|
||||||
|
|
||||||
if (federationProviderModel == null) {
|
|
||||||
throw new NotFoundException("Could not find federation provider");
|
|
||||||
}
|
|
||||||
|
|
||||||
realm.removeUserFederationProvider(this.federationProviderModel);
|
|
||||||
new UsersSyncManager().notifyToRefreshPeriodicSync(session, realm, this.federationProviderModel, true);
|
|
||||||
|
|
||||||
adminEvent.operation(OperationType.DELETE).resourcePath(uriInfo).success();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Trigger sync of users
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@POST
|
|
||||||
@Path("sync")
|
|
||||||
@NoCache
|
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
|
||||||
public UserFederationSyncResult syncUsers(@QueryParam("action") String action) {
|
|
||||||
auth.requireManage();
|
|
||||||
|
|
||||||
if (federationProviderModel == null) {
|
|
||||||
throw new NotFoundException("Could not find federation provider");
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.debug("Syncing users");
|
|
||||||
|
|
||||||
UsersSyncManager syncManager = new UsersSyncManager();
|
|
||||||
UserFederationSyncResult syncResult;
|
|
||||||
if ("triggerFullSync".equals(action)) {
|
|
||||||
syncResult = syncManager.syncAllUsers(session.getKeycloakSessionFactory(), realm.getId(), this.federationProviderModel);
|
|
||||||
} else if ("triggerChangedUsersSync".equals(action)) {
|
|
||||||
syncResult = syncManager.syncChangedUsers(session.getKeycloakSessionFactory(), realm.getId(), this.federationProviderModel);
|
|
||||||
} else {
|
|
||||||
throw new NotFoundException("Unknown action: " + action);
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, Object> eventRep = new HashMap<>();
|
|
||||||
eventRep.put("action", action);
|
|
||||||
eventRep.put("result", syncResult);
|
|
||||||
adminEvent.operation(OperationType.ACTION).resourcePath(uriInfo).representation(eventRep).success();
|
|
||||||
|
|
||||||
return syncResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get available user federation mapper types
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@GET
|
|
||||||
@Path("mapper-types")
|
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
|
||||||
@NoCache
|
|
||||||
public Map<String, UserFederationMapperTypeRepresentation> getMapperTypes() {
|
|
||||||
auth.requireView();
|
|
||||||
|
|
||||||
if (federationProviderModel == null) {
|
|
||||||
throw new NotFoundException("Could not find federation provider");
|
|
||||||
}
|
|
||||||
|
|
||||||
KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
|
|
||||||
Map<String, UserFederationMapperTypeRepresentation> types = new HashMap<>();
|
|
||||||
List<ProviderFactory> factories = sessionFactory.getProviderFactories(UserFederationMapper.class);
|
|
||||||
|
|
||||||
for (ProviderFactory factory : factories) {
|
|
||||||
UserFederationMapperFactory mapperFactory = (UserFederationMapperFactory)factory;
|
|
||||||
if (mapperFactory.getFederationProviderType().equals(this.federationProviderModel.getProviderName())) {
|
|
||||||
|
|
||||||
UserFederationMapperTypeRepresentation rep = new UserFederationMapperTypeRepresentation();
|
|
||||||
rep.setId(mapperFactory.getId());
|
|
||||||
rep.setCategory(mapperFactory.getDisplayCategory());
|
|
||||||
rep.setName(mapperFactory.getDisplayType());
|
|
||||||
rep.setHelpText(mapperFactory.getHelpText());
|
|
||||||
rep.setSyncConfig(mapperFactory.getSyncConfig());
|
|
||||||
List<ProviderConfigProperty> configProperties = mapperFactory.getConfigProperties();
|
|
||||||
for (ProviderConfigProperty prop : configProperties) {
|
|
||||||
ConfigPropertyRepresentation propRep = ModelToRepresentation.toRepresentation(prop);
|
|
||||||
rep.getProperties().add(propRep);
|
|
||||||
}
|
|
||||||
rep.setDefaultConfig(mapperFactory.getDefaultConfig(this.federationProviderModel));
|
|
||||||
|
|
||||||
types.put(rep.getId(), rep);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return types;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get mappers configured for this provider
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@GET
|
|
||||||
@Path("mappers")
|
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
|
||||||
@NoCache
|
|
||||||
public List<UserFederationMapperRepresentation> getMappers() {
|
|
||||||
auth.requireView();
|
|
||||||
|
|
||||||
if (federationProviderModel == null) {
|
|
||||||
throw new NotFoundException("Could not find federation provider");
|
|
||||||
}
|
|
||||||
|
|
||||||
List<UserFederationMapperRepresentation> mappers = new LinkedList<>();
|
|
||||||
for (UserFederationMapperModel model : realm.getUserFederationMappersByFederationProvider(this.federationProviderModel.getId())) {
|
|
||||||
mappers.add(ModelToRepresentation.toRepresentation(realm, model));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sort mappers by category,type,name
|
|
||||||
Collections.sort(mappers, new Comparator<UserFederationMapperRepresentation>() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int compare(UserFederationMapperRepresentation o1, UserFederationMapperRepresentation o2) {
|
|
||||||
UserFederationMapperFactory factory1 = (UserFederationMapperFactory) session.getKeycloakSessionFactory().getProviderFactory(UserFederationMapper.class, o1.getFederationMapperType());
|
|
||||||
UserFederationMapperFactory factory2 = (UserFederationMapperFactory) session.getKeycloakSessionFactory().getProviderFactory(UserFederationMapper.class, o2.getFederationMapperType());
|
|
||||||
|
|
||||||
int compare = factory1.getDisplayCategory().compareTo(factory2.getDisplayCategory());
|
|
||||||
if (compare != 0) return compare;
|
|
||||||
|
|
||||||
compare = factory1.getDisplayType().compareTo(factory2.getDisplayType());
|
|
||||||
if (compare != 0) return compare;
|
|
||||||
|
|
||||||
compare = o1.getName().compareTo(o2.getName());
|
|
||||||
return compare;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return mappers;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a mapper
|
|
||||||
*
|
|
||||||
* @param mapper
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@POST
|
|
||||||
@Path("mappers")
|
|
||||||
@Consumes(MediaType.APPLICATION_JSON)
|
|
||||||
public Response addMapper(UserFederationMapperRepresentation mapper) {
|
|
||||||
auth.requireManage();
|
|
||||||
|
|
||||||
if (federationProviderModel == null) {
|
|
||||||
throw new NotFoundException("Could not find federation provider");
|
|
||||||
}
|
|
||||||
|
|
||||||
UserFederationMapperModel model = RepresentationToModel.toModel(realm, mapper);
|
|
||||||
|
|
||||||
validateModel(model);
|
|
||||||
|
|
||||||
model = realm.addUserFederationMapper(model);
|
|
||||||
|
|
||||||
adminEvent.operation(OperationType.CREATE).resource(ResourceType.USER_FEDERATION_MAPPER).resourcePath(uriInfo, model.getId())
|
|
||||||
.representation(mapper).success();
|
|
||||||
|
|
||||||
return Response.created(uriInfo.getAbsolutePathBuilder().path(model.getId()).build()).build();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a mapper
|
|
||||||
*
|
|
||||||
* @param id Mapper id
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@GET
|
|
||||||
@NoCache
|
|
||||||
@Path("mappers/{id}")
|
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
|
||||||
public UserFederationMapperRepresentation getMapperById(@PathParam("id") String id) {
|
|
||||||
auth.requireView();
|
|
||||||
|
|
||||||
if (federationProviderModel == null) {
|
|
||||||
throw new NotFoundException("Could not find federation provider");
|
|
||||||
}
|
|
||||||
|
|
||||||
UserFederationMapperModel model = realm.getUserFederationMapperById(id);
|
|
||||||
if (model == null) throw new NotFoundException("Model not found");
|
|
||||||
return ModelToRepresentation.toRepresentation(realm, model);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update a mapper
|
|
||||||
*
|
|
||||||
* @param id Mapper id
|
|
||||||
* @param rep
|
|
||||||
*/
|
|
||||||
@PUT
|
|
||||||
@NoCache
|
|
||||||
@Path("mappers/{id}")
|
|
||||||
@Consumes(MediaType.APPLICATION_JSON)
|
|
||||||
public void update(@PathParam("id") String id, UserFederationMapperRepresentation rep) {
|
|
||||||
auth.requireManage();
|
|
||||||
|
|
||||||
if (federationProviderModel == null) {
|
|
||||||
throw new NotFoundException("Could not find federation provider");
|
|
||||||
}
|
|
||||||
|
|
||||||
UserFederationMapperModel model = realm.getUserFederationMapperById(id);
|
|
||||||
if (model == null) throw new NotFoundException("Model not found");
|
|
||||||
model = RepresentationToModel.toModel(realm, rep);
|
|
||||||
|
|
||||||
validateModel(model);
|
|
||||||
|
|
||||||
realm.updateUserFederationMapper(model);
|
|
||||||
adminEvent.operation(OperationType.UPDATE).resource(ResourceType.USER_FEDERATION_MAPPER).resourcePath(uriInfo).representation(rep).success();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete a mapper with a given id
|
|
||||||
*
|
|
||||||
* @param id Mapper id
|
|
||||||
*/
|
|
||||||
@DELETE
|
|
||||||
@NoCache
|
|
||||||
@Path("mappers/{id}")
|
|
||||||
public void delete(@PathParam("id") String id) {
|
|
||||||
auth.requireManage();
|
|
||||||
|
|
||||||
if (federationProviderModel == null) {
|
|
||||||
throw new NotFoundException("Could not find federation provider");
|
|
||||||
}
|
|
||||||
|
|
||||||
UserFederationMapperModel model = realm.getUserFederationMapperById(id);
|
|
||||||
if (model == null) throw new NotFoundException("Model not found");
|
|
||||||
realm.removeUserFederationMapper(model);
|
|
||||||
adminEvent.operation(OperationType.DELETE).resource(ResourceType.USER_FEDERATION_MAPPER).resourcePath(uriInfo).success();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Trigger sync of mapper data related to federationMapper (roles, groups, ...)
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@POST
|
|
||||||
@Path("mappers/{id}/sync")
|
|
||||||
@NoCache
|
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
|
||||||
public UserFederationSyncResult syncMapperData(@PathParam("id") String mapperId, @QueryParam("direction") String direction) {
|
|
||||||
auth.requireManage();
|
|
||||||
|
|
||||||
if (federationProviderModel == null) {
|
|
||||||
throw new NotFoundException("Could not find federation provider");
|
|
||||||
}
|
|
||||||
|
|
||||||
UserFederationMapperModel mapperModel = realm.getUserFederationMapperById(mapperId);
|
|
||||||
if (mapperModel == null) throw new NotFoundException("Mapper model not found");
|
|
||||||
UserFederationMapper mapper = session.getProvider(UserFederationMapper.class, mapperModel.getFederationMapperType());
|
|
||||||
|
|
||||||
UserFederationProviderModel providerModel = KeycloakModelUtils.findUserFederationProviderById(mapperModel.getFederationProviderId(), realm);
|
|
||||||
if (providerModel == null) throw new NotFoundException("Provider model not found");
|
|
||||||
UserFederationProviderFactory providerFactory = (UserFederationProviderFactory) session.getKeycloakSessionFactory().getProviderFactory(UserFederationProvider.class, providerModel.getProviderName());
|
|
||||||
UserFederationProvider federationProvider = providerFactory.getInstance(session, providerModel);
|
|
||||||
|
|
||||||
ServicesLogger.LOGGER.syncingDataForMapper(mapperModel.getName(), mapperModel.getFederationMapperType(), direction);
|
|
||||||
|
|
||||||
UserFederationSyncResult syncResult;
|
|
||||||
if ("fedToKeycloak".equals(direction)) {
|
|
||||||
syncResult = mapper.syncDataFromFederationProviderToKeycloak(mapperModel, federationProvider, session, realm);
|
|
||||||
} else if ("keycloakToFed".equals(direction)) {
|
|
||||||
syncResult = mapper.syncDataFromKeycloakToFederationProvider(mapperModel, federationProvider, session, realm);
|
|
||||||
} else {
|
|
||||||
throw new NotFoundException("Unknown direction: " + direction);
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, Object> eventRep = new HashMap<>();
|
|
||||||
eventRep.put("action", direction);
|
|
||||||
eventRep.put("result", syncResult);
|
|
||||||
adminEvent.operation(OperationType.ACTION).resourcePath(uriInfo).representation(eventRep).success();
|
|
||||||
return syncResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void validateModel(UserFederationMapperModel model) {
|
|
||||||
try {
|
|
||||||
UserFederationMapperFactory mapperFactory = (UserFederationMapperFactory) session.getKeycloakSessionFactory().getProviderFactory(UserFederationMapper.class, model.getFederationMapperType());
|
|
||||||
mapperFactory.validateConfig(realm, federationProviderModel, model);
|
|
||||||
} catch (FederationConfigValidationException ex) {
|
|
||||||
logger.error(ex.getMessage());
|
|
||||||
Properties messages = AdminRoot.getMessages(session, realm, auth.getAuth().getToken().getLocale());
|
|
||||||
throw new ErrorResponseException(ex.getMessage(), MessageFormat.format(messages.getProperty(ex.getMessage(), ex.getMessage()), ex.getParameters()),
|
|
||||||
Response.Status.BAD_REQUEST);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,344 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
|
||||||
* and other contributors as indicated by the @author tags.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.keycloak.services.resources.admin;
|
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
|
||||||
import org.jboss.resteasy.annotations.cache.NoCache;
|
|
||||||
import org.jboss.resteasy.spi.NotFoundException;
|
|
||||||
import org.jboss.resteasy.spi.ResteasyProviderFactory;
|
|
||||||
import org.keycloak.common.constants.KerberosConstants;
|
|
||||||
import org.keycloak.component.ComponentModel;
|
|
||||||
import org.keycloak.events.admin.OperationType;
|
|
||||||
import org.keycloak.events.admin.ResourceType;
|
|
||||||
import org.keycloak.mappers.FederationConfigValidationException;
|
|
||||||
import org.keycloak.models.AuthenticationExecutionModel;
|
|
||||||
import org.keycloak.models.KeycloakSession;
|
|
||||||
import org.keycloak.models.ModelDuplicateException;
|
|
||||||
import org.keycloak.models.ModelException;
|
|
||||||
import org.keycloak.models.RealmModel;
|
|
||||||
import org.keycloak.models.UserFederationProvider;
|
|
||||||
import org.keycloak.models.UserFederationProviderFactory;
|
|
||||||
import org.keycloak.models.UserFederationProviderModel;
|
|
||||||
import org.keycloak.models.UserFederationValidatingProviderFactory;
|
|
||||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
|
||||||
import org.keycloak.models.utils.ModelToRepresentation;
|
|
||||||
import org.keycloak.provider.ConfiguredProvider;
|
|
||||||
import org.keycloak.provider.ProviderConfigProperty;
|
|
||||||
import org.keycloak.provider.ProviderFactory;
|
|
||||||
import org.keycloak.representations.idm.ConfigPropertyRepresentation;
|
|
||||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
|
||||||
import org.keycloak.representations.idm.UserFederationProviderFactoryRepresentation;
|
|
||||||
import org.keycloak.representations.idm.UserFederationProviderRepresentation;
|
|
||||||
import org.keycloak.services.ErrorResponse;
|
|
||||||
import org.keycloak.services.ErrorResponseException;
|
|
||||||
import org.keycloak.services.ServicesLogger;
|
|
||||||
import org.keycloak.services.managers.UsersSyncManager;
|
|
||||||
import org.keycloak.utils.CredentialHelper;
|
|
||||||
|
|
||||||
import javax.ws.rs.Consumes;
|
|
||||||
import javax.ws.rs.GET;
|
|
||||||
import javax.ws.rs.POST;
|
|
||||||
import javax.ws.rs.Path;
|
|
||||||
import javax.ws.rs.PathParam;
|
|
||||||
import javax.ws.rs.Produces;
|
|
||||||
import javax.ws.rs.core.Context;
|
|
||||||
import javax.ws.rs.core.MediaType;
|
|
||||||
import javax.ws.rs.core.Response;
|
|
||||||
import javax.ws.rs.core.UriInfo;
|
|
||||||
import java.text.MessageFormat;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Properties;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base resource for managing users
|
|
||||||
*
|
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
|
||||||
* @version $Revision: 1 $
|
|
||||||
*/
|
|
||||||
public class UserFederationProvidersResource {
|
|
||||||
private static final Logger logger = Logger.getLogger(UserFederationProvidersResource.class);
|
|
||||||
|
|
||||||
protected RealmModel realm;
|
|
||||||
|
|
||||||
protected RealmAuth auth;
|
|
||||||
|
|
||||||
protected AdminEventBuilder adminEvent;
|
|
||||||
|
|
||||||
@Context
|
|
||||||
protected UriInfo uriInfo;
|
|
||||||
|
|
||||||
@Context
|
|
||||||
protected KeycloakSession session;
|
|
||||||
|
|
||||||
public UserFederationProvidersResource(RealmModel realm, RealmAuth auth, AdminEventBuilder adminEvent) {
|
|
||||||
this.auth = auth;
|
|
||||||
this.realm = realm;
|
|
||||||
this.adminEvent = adminEvent.resource(ResourceType.USER_FEDERATION_PROVIDER);
|
|
||||||
|
|
||||||
auth.init(RealmAuth.Resource.REALM);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Automatically add "kerberos" to required realm credentials if it's supported by saved provider
|
|
||||||
*
|
|
||||||
* @param realm
|
|
||||||
* @param model
|
|
||||||
* @return true if kerberos credentials were added
|
|
||||||
*/
|
|
||||||
public static boolean checkKerberosCredential(KeycloakSession session, RealmModel realm, UserFederationProviderModel model) {
|
|
||||||
String allowKerberosCfg = model.getConfig().get(KerberosConstants.ALLOW_KERBEROS_AUTHENTICATION);
|
|
||||||
if (Boolean.valueOf(allowKerberosCfg)) {
|
|
||||||
CredentialHelper.setOrReplaceAuthenticationRequirement(session, realm, CredentialRepresentation.KERBEROS,
|
|
||||||
AuthenticationExecutionModel.Requirement.ALTERNATIVE, AuthenticationExecutionModel.Requirement.DISABLED);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void validateFederationProviderConfig(KeycloakSession session, RealmAuth auth, RealmModel realm, UserFederationProviderModel model) {
|
|
||||||
UserFederationProviderFactory providerFactory = KeycloakModelUtils.getFederationProviderFactory(session, model);
|
|
||||||
if (providerFactory instanceof UserFederationValidatingProviderFactory) {
|
|
||||||
try {
|
|
||||||
((UserFederationValidatingProviderFactory) providerFactory).validateConfig(realm, model);
|
|
||||||
} catch (FederationConfigValidationException fcve) {
|
|
||||||
logger.error(fcve.getMessage());
|
|
||||||
Properties messages = AdminRoot.getMessages(session, realm, auth.getAuth().getToken().getLocale());
|
|
||||||
throw new ErrorResponseException(fcve.getMessage(), MessageFormat.format(messages.getProperty(fcve.getMessage(), fcve.getMessage()), fcve.getParameters()),
|
|
||||||
Response.Status.BAD_REQUEST);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get available provider factories
|
|
||||||
*
|
|
||||||
* Returns a list of available provider factories.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@GET
|
|
||||||
@NoCache
|
|
||||||
@Path("providers")
|
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
|
||||||
public List<UserFederationProviderFactoryRepresentation> getProviders() {
|
|
||||||
auth.requireView();
|
|
||||||
|
|
||||||
List<UserFederationProviderFactoryRepresentation> providers = new LinkedList<UserFederationProviderFactoryRepresentation>();
|
|
||||||
for (ProviderFactory factory : session.getKeycloakSessionFactory().getProviderFactories(UserFederationProvider.class)) {
|
|
||||||
UserFederationProviderFactoryRepresentation rep = new UserFederationProviderFactoryRepresentation();
|
|
||||||
rep.setId(factory.getId());
|
|
||||||
rep.setOptions(((UserFederationProviderFactory)factory).getConfigurationOptions());
|
|
||||||
providers.add(rep);
|
|
||||||
}
|
|
||||||
return providers;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get factory with given id
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@GET
|
|
||||||
@NoCache
|
|
||||||
@Path("providers/{id}")
|
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
|
||||||
public UserFederationProviderFactoryRepresentation getProvider(@PathParam("id") String id) {
|
|
||||||
auth.requireView();
|
|
||||||
|
|
||||||
for (ProviderFactory factory : session.getKeycloakSessionFactory().getProviderFactories(UserFederationProvider.class)) {
|
|
||||||
if (!factory.getId().equals(id)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (factory instanceof ConfiguredProvider) {
|
|
||||||
|
|
||||||
UserFederationProviderFactoryDescription rep = new UserFederationProviderFactoryDescription();
|
|
||||||
rep.setId(factory.getId());
|
|
||||||
|
|
||||||
ConfiguredProvider cp = (ConfiguredProvider) factory;
|
|
||||||
rep.setHelpText(cp.getHelpText());
|
|
||||||
rep.setProperties(toConfigPropertyRepresentationList(cp.getConfigProperties()));
|
|
||||||
|
|
||||||
return rep;
|
|
||||||
}
|
|
||||||
|
|
||||||
UserFederationProviderFactoryRepresentation rep = new UserFederationProviderFactoryRepresentation();
|
|
||||||
rep.setId(factory.getId());
|
|
||||||
rep.setOptions(((UserFederationProviderFactory) factory).getConfigurationOptions());
|
|
||||||
|
|
||||||
return rep;
|
|
||||||
}
|
|
||||||
throw new NotFoundException("Could not find provider");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a provider
|
|
||||||
*
|
|
||||||
* @param rep
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@POST
|
|
||||||
@Path("instances")
|
|
||||||
@Consumes(MediaType.APPLICATION_JSON)
|
|
||||||
public Response createProviderInstance(UserFederationProviderRepresentation rep) {
|
|
||||||
auth.requireManage();
|
|
||||||
|
|
||||||
try {
|
|
||||||
String displayName = rep.getDisplayName();
|
|
||||||
if (displayName != null && displayName.trim().equals("")) {
|
|
||||||
displayName = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
UserFederationProviderModel tempModel = new UserFederationProviderModel(null, rep.getProviderName(), rep.getConfig(), rep.getPriority(), displayName, rep.getFullSyncPeriod(), rep.getChangedSyncPeriod(), rep.getLastSync());
|
|
||||||
validateFederationProviderConfig(session, auth, realm, tempModel);
|
|
||||||
|
|
||||||
UserFederationProviderModel model = realm.addUserFederationProvider(rep.getProviderName(), rep.getConfig(), rep.getPriority(), displayName,
|
|
||||||
rep.getFullSyncPeriod(), rep.getChangedSyncPeriod(), rep.getLastSync());
|
|
||||||
new UsersSyncManager().notifyToRefreshPeriodicSync(session, realm, model, false);
|
|
||||||
boolean kerberosCredsAdded = checkKerberosCredential(session, realm, model);
|
|
||||||
if (kerberosCredsAdded) {
|
|
||||||
ServicesLogger.LOGGER.addedKerberosToRealmCredentials();
|
|
||||||
}
|
|
||||||
|
|
||||||
rep.setId(model.getId());
|
|
||||||
adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo, model.getId()).representation(rep).success();
|
|
||||||
|
|
||||||
return Response.created(uriInfo.getAbsolutePathBuilder().path(model.getId()).build()).build();
|
|
||||||
} catch (ModelDuplicateException e) {
|
|
||||||
if (session.getTransactionManager().isActive()) {
|
|
||||||
session.getTransactionManager().setRollbackOnly();
|
|
||||||
}
|
|
||||||
return ErrorResponse.exists("Federation provider exists with same name.");
|
|
||||||
} catch (ModelException me){
|
|
||||||
if (session.getTransactionManager().isActive()) {
|
|
||||||
session.getTransactionManager().setRollbackOnly();
|
|
||||||
}
|
|
||||||
return ErrorResponse.error("Could not create federation provider.", Response.Status.INTERNAL_SERVER_ERROR);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get configured providers
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@GET
|
|
||||||
@Path("instances")
|
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
|
||||||
@NoCache
|
|
||||||
public List<UserFederationProviderRepresentation> getUserFederationInstances() {
|
|
||||||
auth.requireView();
|
|
||||||
|
|
||||||
List<UserFederationProviderRepresentation> reps = new LinkedList<UserFederationProviderRepresentation>();
|
|
||||||
for (UserFederationProviderModel model : realm.getUserFederationProviders()) {
|
|
||||||
UserFederationProviderRepresentation rep = ModelToRepresentation.toRepresentation(model);
|
|
||||||
reps.add(rep);
|
|
||||||
}
|
|
||||||
return reps;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Path("instances/{id}")
|
|
||||||
public UserFederationProviderResource getUserFederationInstance(@PathParam("id") String id) {
|
|
||||||
this.auth.requireView();
|
|
||||||
|
|
||||||
UserFederationProviderModel model = KeycloakModelUtils.findUserFederationProviderById(id, realm);
|
|
||||||
UserFederationProviderResource instanceResource = new UserFederationProviderResource(session, realm, this.auth, model, adminEvent);
|
|
||||||
ResteasyProviderFactory.getInstance().injectProperties(instanceResource);
|
|
||||||
return instanceResource;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: This endpoint exists, so that admin console can lookup userFederation provider OR userStorage provider by federationLink.
|
|
||||||
// TODO: Endpoint should be removed once UserFederation SPI is removed as fallback is not needed anymore than
|
|
||||||
@GET
|
|
||||||
@Path("instances-with-fallback/{id}")
|
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
|
||||||
@NoCache
|
|
||||||
public Map<String, String> getUserFederationInstanceWithFallback(@PathParam("id") String id) {
|
|
||||||
this.auth.requireView();
|
|
||||||
|
|
||||||
Map<String, String> result = new HashMap<>();
|
|
||||||
UserFederationProviderModel model = KeycloakModelUtils.findUserFederationProviderById(id, realm);
|
|
||||||
if (model != null) {
|
|
||||||
result.put("federationLinkName", model.getDisplayName());
|
|
||||||
result.put("federationLink", "#/realms/" + realm.getName() + "/user-federation/providers/" + model.getProviderName() + "/" + model.getId());
|
|
||||||
return result;
|
|
||||||
} else {
|
|
||||||
ComponentModel userStorage = KeycloakModelUtils.findUserStorageProviderById(id, realm);
|
|
||||||
if (userStorage != null) {
|
|
||||||
result.put("federationLinkName", userStorage.getName());
|
|
||||||
result.put("federationLink", "#/realms/" + realm.getName() + "/user-storage/providers/" + userStorage.getProviderId() + "/" + userStorage.getId());
|
|
||||||
return result;
|
|
||||||
} else {
|
|
||||||
throw new NotFoundException("Could not find federation provider or userStorage provider");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private ConfigPropertyRepresentation toConfigPropertyRepresentation(ProviderConfigProperty prop) {
|
|
||||||
return ModelToRepresentation.toRepresentation(prop);
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<ConfigPropertyRepresentation> toConfigPropertyRepresentationList(List<ProviderConfigProperty> props) {
|
|
||||||
|
|
||||||
List<ConfigPropertyRepresentation> reps = new ArrayList<>(props.size());
|
|
||||||
for(ProviderConfigProperty prop : props){
|
|
||||||
reps.add(toConfigPropertyRepresentation(prop));
|
|
||||||
}
|
|
||||||
|
|
||||||
return reps;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static class UserFederationProviderFactoryDescription extends UserFederationProviderFactoryRepresentation {
|
|
||||||
|
|
||||||
protected String name;
|
|
||||||
|
|
||||||
protected String helpText;
|
|
||||||
|
|
||||||
protected List<ConfigPropertyRepresentation> properties;
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setName(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getHelpText() {
|
|
||||||
return helpText;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setHelpText(String helpText) {
|
|
||||||
this.helpText = helpText;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<ConfigPropertyRepresentation> getProperties() {
|
|
||||||
return properties;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setProperties(List<ConfigPropertyRepresentation> properties) {
|
|
||||||
this.properties = properties;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -25,6 +25,7 @@ import org.keycloak.models.CredentialValidationOutput;
|
||||||
import org.keycloak.models.FederatedIdentityModel;
|
import org.keycloak.models.FederatedIdentityModel;
|
||||||
import org.keycloak.models.GroupModel;
|
import org.keycloak.models.GroupModel;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.models.KeycloakSessionTask;
|
||||||
import org.keycloak.models.ModelException;
|
import org.keycloak.models.ModelException;
|
||||||
import org.keycloak.models.ProtocolMapperModel;
|
import org.keycloak.models.ProtocolMapperModel;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
|
@ -32,6 +33,7 @@ import org.keycloak.models.RoleModel;
|
||||||
import org.keycloak.models.UserConsentModel;
|
import org.keycloak.models.UserConsentModel;
|
||||||
import org.keycloak.models.UserCredentialModel;
|
import org.keycloak.models.UserCredentialModel;
|
||||||
import org.keycloak.models.UserFederationProviderModel;
|
import org.keycloak.models.UserFederationProviderModel;
|
||||||
|
import org.keycloak.models.UserManager;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
import org.keycloak.models.UserProvider;
|
import org.keycloak.models.UserProvider;
|
||||||
import org.keycloak.models.cache.CachedUserModel;
|
import org.keycloak.models.cache.CachedUserModel;
|
||||||
|
@ -52,6 +54,8 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static org.keycloak.models.utils.KeycloakModelUtils.runJobInTransaction;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
|
@ -244,13 +248,39 @@ public class UserStorageManager implements UserProvider, OnUserCache {
|
||||||
if (user == null || user.getFederationLink() == null) return user;
|
if (user == null || user.getFederationLink() == null) return user;
|
||||||
UserStorageProvider provider = getStorageProvider(session, realm, user.getFederationLink());
|
UserStorageProvider provider = getStorageProvider(session, realm, user.getFederationLink());
|
||||||
if (provider != null && provider instanceof ImportedUserValidation) {
|
if (provider != null && provider instanceof ImportedUserValidation) {
|
||||||
return ((ImportedUserValidation)provider).validate(realm, user);
|
UserModel validated = ((ImportedUserValidation)provider).validate(realm, user);
|
||||||
|
if (validated == null) {
|
||||||
|
deleteInvalidUser(realm, user);
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return validated;
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void deleteInvalidUser(final RealmModel realm, final UserModel user) {
|
||||||
|
String userId = user.getId();
|
||||||
|
String userName = user.getUsername();
|
||||||
|
session.getUserCache().evict(realm, user);
|
||||||
|
runJobInTransaction(session.getKeycloakSessionFactory(), new KeycloakSessionTask() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(KeycloakSession session) {
|
||||||
|
RealmModel realmModel = session.realms().getRealm(realm.getId());
|
||||||
|
if (realmModel == null) return;
|
||||||
|
UserModel deletedUser = session.userLocalStorage().getUserById(userId, realmModel);
|
||||||
|
new UserManager(session).removeUser(realmModel, deletedUser, session.userLocalStorage());
|
||||||
|
logger.debugf("Removed invalid user '%s'", userName);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
protected List<UserModel> importValidation(RealmModel realm, List<UserModel> users) {
|
protected List<UserModel> importValidation(RealmModel realm, List<UserModel> users) {
|
||||||
List<UserModel> tmp = new LinkedList<>();
|
List<UserModel> tmp = new LinkedList<>();
|
||||||
for (UserModel user : users) {
|
for (UserModel user : users) {
|
||||||
|
|
|
@ -1,62 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
|
||||||
* and other contributors as indicated by the @author tags.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.keycloak.testsuite.federation;
|
|
||||||
|
|
||||||
import org.keycloak.provider.ConfiguredProvider;
|
|
||||||
import org.keycloak.provider.ProviderConfigProperty;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
|
||||||
*/
|
|
||||||
public class DummyConfigurableUserFederationProviderFactory extends DummyUserFederationProviderFactory implements ConfiguredProvider {
|
|
||||||
|
|
||||||
public static final String PROVIDER_NAME = "dummy-configurable";
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getId() {
|
|
||||||
return PROVIDER_NAME;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getHelpText() {
|
|
||||||
return "Dummy User Federation Provider Help Text";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<ProviderConfigProperty> getConfigProperties() {
|
|
||||||
|
|
||||||
ProviderConfigProperty prop1 = new ProviderConfigProperty();
|
|
||||||
prop1.setName("prop1");
|
|
||||||
prop1.setLabel("Prop1");
|
|
||||||
prop1.setDefaultValue("prop1Default");
|
|
||||||
prop1.setHelpText("Prop1 HelpText");
|
|
||||||
prop1.setType(ProviderConfigProperty.STRING_TYPE);
|
|
||||||
|
|
||||||
ProviderConfigProperty prop2 = new ProviderConfigProperty();
|
|
||||||
prop2.setName("prop2");
|
|
||||||
prop2.setLabel("Prop2");
|
|
||||||
prop2.setDefaultValue("true");
|
|
||||||
prop2.setHelpText("Prop2 HelpText");
|
|
||||||
prop2.setType(ProviderConfigProperty.BOOLEAN_TYPE);
|
|
||||||
|
|
||||||
return Arrays.asList(prop1, prop2);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,140 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
|
||||||
* and other contributors as indicated by the @author tags.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.keycloak.testsuite.federation;
|
|
||||||
|
|
||||||
import org.keycloak.Config;
|
|
||||||
import org.keycloak.mappers.FederationConfigValidationException;
|
|
||||||
import org.keycloak.mappers.UserFederationMapper;
|
|
||||||
import org.keycloak.mappers.UserFederationMapperFactory;
|
|
||||||
import org.keycloak.models.GroupModel;
|
|
||||||
import org.keycloak.models.KeycloakSession;
|
|
||||||
import org.keycloak.models.KeycloakSessionFactory;
|
|
||||||
import org.keycloak.models.RealmModel;
|
|
||||||
import org.keycloak.models.UserFederationMapperModel;
|
|
||||||
import org.keycloak.models.UserFederationProvider;
|
|
||||||
import org.keycloak.models.UserFederationProviderModel;
|
|
||||||
import org.keycloak.models.UserFederationSyncResult;
|
|
||||||
import org.keycloak.models.UserModel;
|
|
||||||
import org.keycloak.provider.ProviderConfigProperty;
|
|
||||||
import org.keycloak.representations.idm.UserFederationMapperSyncConfigRepresentation;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
|
||||||
*/
|
|
||||||
public class DummyUserFederationMapper implements UserFederationMapperFactory, UserFederationMapper {
|
|
||||||
|
|
||||||
public static final String PROVIDER_NAME = "dummy-mapper";
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getFederationProviderType() {
|
|
||||||
return DummyUserFederationProviderFactory.PROVIDER_NAME;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getDisplayCategory() {
|
|
||||||
return "Dummy";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getDisplayType() {
|
|
||||||
return "Dummy";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UserFederationMapperSyncConfigRepresentation getSyncConfig() {
|
|
||||||
return new UserFederationMapperSyncConfigRepresentation(true, "dummyFedToKeycloak", true, "dummyKeycloakToFed");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void validateConfig(RealmModel realm, UserFederationProviderModel fedProviderModel, UserFederationMapperModel mapperModel) throws FederationConfigValidationException {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<String, String> getDefaultConfig(UserFederationProviderModel providerModel) {
|
|
||||||
return Collections.emptyMap();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getHelpText() {
|
|
||||||
return "Dummy";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<ProviderConfigProperty> getConfigProperties() {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UserFederationMapper create(KeycloakSession session) {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void init(Config.Scope config) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void postInit(KeycloakSessionFactory factory) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getId() {
|
|
||||||
return PROVIDER_NAME;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UserFederationSyncResult syncDataFromFederationProviderToKeycloak(final UserFederationMapperModel mapperModel, UserFederationProvider federationProvider, KeycloakSession session, RealmModel realm) {
|
|
||||||
return new UserFederationSyncResult() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getStatus() {
|
|
||||||
return "dummyFedToKeycloakSuccess mapper=" + mapperModel.getName();
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UserFederationSyncResult syncDataFromKeycloakToFederationProvider(final UserFederationMapperModel mapperModel, UserFederationProvider federationProvider, KeycloakSession session, RealmModel realm) {
|
|
||||||
return new UserFederationSyncResult() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getStatus() {
|
|
||||||
return "dummyKeycloakToFedSuccess mapper=" + mapperModel.getName();
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<UserModel> getGroupMembers(UserFederationMapperModel mapperModel, UserFederationProvider federationProvider, RealmModel realm, GroupModel group, int firstResult, int maxResults) {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -17,15 +17,23 @@
|
||||||
|
|
||||||
package org.keycloak.testsuite.federation;
|
package org.keycloak.testsuite.federation;
|
||||||
|
|
||||||
|
import org.keycloak.component.ComponentModel;
|
||||||
import org.keycloak.credential.CredentialInput;
|
import org.keycloak.credential.CredentialInput;
|
||||||
|
import org.keycloak.credential.CredentialInputUpdater;
|
||||||
|
import org.keycloak.credential.CredentialInputValidator;
|
||||||
import org.keycloak.credential.CredentialModel;
|
import org.keycloak.credential.CredentialModel;
|
||||||
import org.keycloak.models.CredentialValidationOutput;
|
import org.keycloak.models.CredentialValidationOutput;
|
||||||
import org.keycloak.models.GroupModel;
|
import org.keycloak.models.GroupModel;
|
||||||
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.RoleModel;
|
import org.keycloak.models.RoleModel;
|
||||||
import org.keycloak.models.UserCredentialModel;
|
import org.keycloak.models.UserCredentialModel;
|
||||||
import org.keycloak.models.UserFederationProvider;
|
import org.keycloak.models.UserFederationProvider;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
|
import org.keycloak.storage.UserStorageProvider;
|
||||||
|
import org.keycloak.storage.user.UserLookupProvider;
|
||||||
|
import org.keycloak.storage.user.UserQueryProvider;
|
||||||
|
import org.keycloak.storage.user.UserRegistrationProvider;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -36,56 +44,60 @@ import java.util.Set;
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
public class DummyUserFederationProvider implements UserFederationProvider {
|
public class DummyUserFederationProvider implements UserStorageProvider,
|
||||||
|
UserLookupProvider,
|
||||||
|
UserRegistrationProvider,
|
||||||
|
CredentialInputValidator {
|
||||||
|
|
||||||
private final Map<String, UserModel> users;
|
private final Map<String, UserModel> users;
|
||||||
|
private KeycloakSession session;
|
||||||
|
private ComponentModel component;
|
||||||
|
|
||||||
public DummyUserFederationProvider(Map<String, UserModel> users) {
|
|
||||||
|
|
||||||
|
public DummyUserFederationProvider(KeycloakSession session, ComponentModel component, Map<String, UserModel> users) {
|
||||||
this.users = users;
|
this.users = users;
|
||||||
|
this.session = session;
|
||||||
|
this.component = component;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UserModel validateAndProxy(RealmModel realm, UserModel local) {
|
public UserModel addUser(RealmModel realm, String username) {
|
||||||
|
UserModel local = session.userLocalStorage().addUser(realm, username);
|
||||||
|
local.setFederationLink(component.getId());
|
||||||
|
|
||||||
|
users.put(username, local);
|
||||||
return local;
|
return local;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean synchronizeRegistrations() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UserModel register(RealmModel realm, UserModel user) {
|
|
||||||
users.put(user.getUsername(), user);
|
|
||||||
return user;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean removeUser(RealmModel realm, UserModel user) {
|
public boolean removeUser(RealmModel realm, UserModel user) {
|
||||||
return users.remove(user.getUsername()) != null;
|
return users.remove(user.getUsername()) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UserModel getUserByUsername(RealmModel realm, String username) {
|
public UserModel getUserById(String id, RealmModel realm) {
|
||||||
return users.get(username);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UserModel getUserByEmail(RealmModel realm, String email) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<UserModel> searchByAttributes(Map<String, String> attributes, RealmModel realm, int maxResults) {
|
public UserModel getUserByUsername(String username, RealmModel realm) {
|
||||||
return Collections.emptyList();
|
return users.get(username);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group, int firstResult, int maxResults) {
|
public UserModel getUserByEmail(String email, RealmModel realm) {
|
||||||
return Collections.emptyList();
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
public void grantToAllUsers(RealmModel realm, RoleModel role) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void preRemove(RealmModel realm) {
|
public void preRemove(RealmModel realm) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -100,34 +112,10 @@ public class DummyUserFederationProvider implements UserFederationProvider {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isValid(RealmModel realm, UserModel local) {
|
|
||||||
String username = local.getUsername();
|
|
||||||
return users.containsKey(username);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Set<String> getSupportedCredentialTypes() {
|
public Set<String> getSupportedCredentialTypes() {
|
||||||
return Collections.singleton(UserCredentialModel.PASSWORD);
|
return Collections.singleton(UserCredentialModel.PASSWORD);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean updateCredential(RealmModel realm, UserModel user, CredentialInput input) {
|
|
||||||
if (!(input instanceof UserCredentialModel) || !CredentialModel.PASSWORD.equals(input.getType())) return false;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void disableCredentialType(RealmModel realm, UserModel user, String credentialType) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Set<String> getDisableableCredentialTypes(RealmModel realm, UserModel user) {
|
|
||||||
return Collections.EMPTY_SET;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean supportsCredentialType(String credentialType) {
|
public boolean supportsCredentialType(String credentialType) {
|
||||||
return getSupportedCredentialTypes().contains(credentialType);
|
return getSupportedCredentialTypes().contains(credentialType);
|
||||||
|
@ -154,12 +142,7 @@ public class DummyUserFederationProvider implements UserFederationProvider {
|
||||||
}
|
}
|
||||||
return false; }
|
return false; }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CredentialValidationOutput validCredentials(RealmModel realm, UserCredentialModel credential) {
|
|
||||||
return CredentialValidationOutput.failed();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() {
|
public void close() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,17 +19,26 @@ package org.keycloak.testsuite.federation;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import org.keycloak.Config;
|
import org.keycloak.Config;
|
||||||
|
import org.keycloak.component.ComponentModel;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.KeycloakSessionFactory;
|
import org.keycloak.models.KeycloakSessionFactory;
|
||||||
|
import org.keycloak.models.LDAPConstants;
|
||||||
import org.keycloak.models.UserFederationProvider;
|
import org.keycloak.models.UserFederationProvider;
|
||||||
import org.keycloak.models.UserFederationProviderFactory;
|
import org.keycloak.models.UserFederationProviderFactory;
|
||||||
import org.keycloak.models.UserFederationProviderModel;
|
import org.keycloak.models.UserFederationProviderModel;
|
||||||
import org.keycloak.models.UserFederationSyncResult;
|
import org.keycloak.models.UserFederationSyncResult;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
|
import org.keycloak.provider.ProviderConfigProperty;
|
||||||
|
import org.keycloak.provider.ProviderConfigurationBuilder;
|
||||||
|
import org.keycloak.storage.UserStorageProviderFactory;
|
||||||
|
import org.keycloak.storage.UserStorageProviderModel;
|
||||||
|
import org.keycloak.storage.user.ImportSynchronization;
|
||||||
|
import org.keycloak.storage.user.SynchronizationResult;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
@ -38,7 +47,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
public class DummyUserFederationProviderFactory implements UserFederationProviderFactory {
|
public class DummyUserFederationProviderFactory implements UserStorageProviderFactory<DummyUserFederationProvider>, ImportSynchronization {
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(DummyUserFederationProviderFactory.class);
|
private static final Logger logger = Logger.getLogger(DummyUserFederationProviderFactory.class);
|
||||||
public static final String PROVIDER_NAME = "dummy";
|
public static final String PROVIDER_NAME = "dummy";
|
||||||
|
@ -49,20 +58,16 @@ public class DummyUserFederationProviderFactory implements UserFederationProvide
|
||||||
private Map<String, UserModel> users = new HashMap<String, UserModel>();
|
private Map<String, UserModel> users = new HashMap<String, UserModel>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UserFederationProvider getInstance(KeycloakSession session, UserFederationProviderModel model) {
|
public DummyUserFederationProvider create(KeycloakSession session, ComponentModel model) {
|
||||||
return new DummyUserFederationProvider(users);
|
return new DummyUserFederationProvider(session, model, users);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<String> getConfigurationOptions() {
|
public List<ProviderConfigProperty> getConfigProperties() {
|
||||||
Set<String> list = new HashSet<String>();
|
return ProviderConfigurationBuilder.create()
|
||||||
list.add("important.config");
|
.property().name("important.config")
|
||||||
return list;
|
.type(ProviderConfigProperty.STRING_TYPE)
|
||||||
}
|
.add().build();
|
||||||
|
|
||||||
@Override
|
|
||||||
public UserFederationProvider create(KeycloakSession session) {
|
|
||||||
return new DummyUserFederationProvider(users);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -86,17 +91,17 @@ public class DummyUserFederationProviderFactory implements UserFederationProvide
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UserFederationSyncResult syncAllUsers(KeycloakSessionFactory sessionFactory, String realmId, UserFederationProviderModel model) {
|
public SynchronizationResult sync(KeycloakSessionFactory sessionFactory, String realmId, UserStorageProviderModel model) {
|
||||||
logger.info("syncAllUsers invoked");
|
logger.info("syncAllUsers invoked");
|
||||||
fullSyncCounter.incrementAndGet();
|
fullSyncCounter.incrementAndGet();
|
||||||
return UserFederationSyncResult.empty();
|
return SynchronizationResult.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UserFederationSyncResult syncChangedUsers(KeycloakSessionFactory sessionFactory, String realmId, UserFederationProviderModel model, Date lastSync) {
|
public SynchronizationResult syncSince(Date lastSync, KeycloakSessionFactory sessionFactory, String realmId, UserStorageProviderModel model) {
|
||||||
logger.info("syncChangedUsers invoked");
|
logger.info("syncChangedUsers invoked");
|
||||||
changedSyncCounter.incrementAndGet();
|
changedSyncCounter.incrementAndGet();
|
||||||
return UserFederationSyncResult.empty();
|
return SynchronizationResult.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getFullSyncCounter() {
|
public int getFullSyncCounter() {
|
||||||
|
|
|
@ -57,9 +57,11 @@ import org.keycloak.representations.idm.UserRepresentation;
|
||||||
import org.keycloak.services.managers.ClientSessionCode;
|
import org.keycloak.services.managers.ClientSessionCode;
|
||||||
import org.keycloak.services.managers.RealmManager;
|
import org.keycloak.services.managers.RealmManager;
|
||||||
import org.keycloak.services.resource.RealmResourceProvider;
|
import org.keycloak.services.resource.RealmResourceProvider;
|
||||||
|
import org.keycloak.storage.UserStorageProvider;
|
||||||
import org.keycloak.testsuite.components.TestProvider;
|
import org.keycloak.testsuite.components.TestProvider;
|
||||||
import org.keycloak.testsuite.components.TestProviderFactory;
|
import org.keycloak.testsuite.components.TestProviderFactory;
|
||||||
import org.keycloak.testsuite.events.EventsListenerProvider;
|
import org.keycloak.testsuite.events.EventsListenerProvider;
|
||||||
|
import org.keycloak.testsuite.federation.DummyUserFederationProviderFactory;
|
||||||
import org.keycloak.testsuite.forms.PassThroughAuthenticator;
|
import org.keycloak.testsuite.forms.PassThroughAuthenticator;
|
||||||
import org.keycloak.testsuite.forms.PassThroughClientAuthenticator;
|
import org.keycloak.testsuite.forms.PassThroughClientAuthenticator;
|
||||||
import org.keycloak.testsuite.rest.representation.AuthenticatorState;
|
import org.keycloak.testsuite.rest.representation.AuthenticatorState;
|
||||||
|
@ -580,8 +582,8 @@ public class TestingResourceProvider implements RealmResourceProvider {
|
||||||
public UserRepresentation getUserByUsernameFromFedProviderFactory(@QueryParam("realmName") String realmName,
|
public UserRepresentation getUserByUsernameFromFedProviderFactory(@QueryParam("realmName") String realmName,
|
||||||
@QueryParam("userName") String userName) {
|
@QueryParam("userName") String userName) {
|
||||||
RealmModel realm = getRealmByName(realmName);
|
RealmModel realm = getRealmByName(realmName);
|
||||||
UserFederationProviderFactory factory = (UserFederationProviderFactory)session.getKeycloakSessionFactory().getProviderFactory(UserFederationProvider.class, "dummy");
|
DummyUserFederationProviderFactory factory = (DummyUserFederationProviderFactory)session.getKeycloakSessionFactory().getProviderFactory(UserStorageProvider.class, "dummy");
|
||||||
UserModel user = factory.getInstance(session, null).getUserByUsername(realm, userName);
|
UserModel user = factory.create(session, null).getUserByUsername(userName, realm);
|
||||||
if (user == null) return null;
|
if (user == null) return null;
|
||||||
return ModelToRepresentation.toRepresentation(session, realm, user);
|
return ModelToRepresentation.toRepresentation(session, realm, user);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,52 +0,0 @@
|
||||||
#
|
|
||||||
# Copyright 2016 Red Hat, Inc. and/or its affiliates
|
|
||||||
# and other contributors as indicated by the @author tags.
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
#
|
|
||||||
|
|
||||||
#
|
|
||||||
# Copyright 2016 Red Hat, Inc. and/or its affiliates
|
|
||||||
# and other contributors as indicated by the @author tags.
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
#
|
|
||||||
|
|
||||||
#
|
|
||||||
# Copyright 2016 Red Hat, Inc. and/or its affiliates
|
|
||||||
# and other contributors as indicated by the @author tags.
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
#
|
|
||||||
|
|
||||||
org.keycloak.testsuite.federation.DummyUserFederationMapper
|
|
|
@ -1,36 +0,0 @@
|
||||||
#
|
|
||||||
# Copyright 2016 Red Hat, Inc. and/or its affiliates
|
|
||||||
# and other contributors as indicated by the @author tags.
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
#
|
|
||||||
|
|
||||||
#
|
|
||||||
# Copyright 2016 Red Hat, Inc. and/or its affiliates
|
|
||||||
# and other contributors as indicated by the @author tags.
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
#
|
|
||||||
|
|
||||||
org.keycloak.testsuite.federation.DummyUserFederationProviderFactory
|
|
||||||
org.keycloak.testsuite.federation.DummyConfigurableUserFederationProviderFactory
|
|
|
@ -0,0 +1 @@
|
||||||
|
org.keycloak.testsuite.federation.DummyUserFederationProviderFactory
|
|
@ -30,7 +30,6 @@ import org.keycloak.representations.idm.UserFederationMapperTypeRepresentation;
|
||||||
import org.keycloak.representations.idm.UserFederationProviderRepresentation;
|
import org.keycloak.representations.idm.UserFederationProviderRepresentation;
|
||||||
import org.keycloak.representations.idm.UserFederationSyncResultRepresentation;
|
import org.keycloak.representations.idm.UserFederationSyncResultRepresentation;
|
||||||
import org.keycloak.testsuite.Assert;
|
import org.keycloak.testsuite.Assert;
|
||||||
import org.keycloak.testsuite.federation.DummyUserFederationMapper;
|
|
||||||
import org.keycloak.testsuite.util.AdminEventPaths;
|
import org.keycloak.testsuite.util.AdminEventPaths;
|
||||||
import org.keycloak.testsuite.util.UserFederationProviderBuilder;
|
import org.keycloak.testsuite.util.UserFederationProviderBuilder;
|
||||||
|
|
||||||
|
|
|
@ -82,7 +82,7 @@ public class UserStorageRestTest extends AbstractAdminTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
private UserFederationProvidersResource userFederation() {
|
private UserFederationProvidersResource userFederation() {
|
||||||
return realm.userFederation();
|
return null;//realm.userFederation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,7 @@ public class ClientRedirectTest extends TestRealmKeycloakTest {
|
||||||
*
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
@Test
|
//@Test
|
||||||
public void testClientRedirectEndpoint() throws Exception {
|
public void testClientRedirectEndpoint() throws Exception {
|
||||||
oauth.doLogin("test-user@localhost", "password");
|
oauth.doLogin("test-user@localhost", "password");
|
||||||
|
|
||||||
|
|
|
@ -77,13 +77,6 @@ public class SSSDTest extends AbstractKeycloakTest {
|
||||||
adminClient.realm(REALM_NAME).components().add(userFederation);
|
adminClient.realm(REALM_NAME).components().add(userFederation);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore
|
|
||||||
@Test
|
|
||||||
public void testProviderFactories() {
|
|
||||||
List<UserFederationProviderFactoryRepresentation> providerFactories = adminClient.realm(REALM_NAME).userFederation().getProviderFactories();
|
|
||||||
Assert.assertNames(providerFactories, "ldap", "kerberos", "dummy", "dummy-configurable", "sssd");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testWrongUser() {
|
public void testWrongUser() {
|
||||||
log.debug("Testing wrong password for user " + USERNAME);
|
log.debug("Testing wrong password for user " + USERNAME);
|
||||||
|
|
|
@ -30,6 +30,7 @@ import org.keycloak.models.UserFederationProviderModel;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
import org.keycloak.representations.idm.IdentityProviderRepresentation;
|
import org.keycloak.representations.idm.IdentityProviderRepresentation;
|
||||||
import org.keycloak.services.Urls;
|
import org.keycloak.services.Urls;
|
||||||
|
import org.keycloak.storage.UserStorageProviderModel;
|
||||||
import org.keycloak.testsuite.broker.util.UserSessionStatusServlet;
|
import org.keycloak.testsuite.broker.util.UserSessionStatusServlet;
|
||||||
import org.keycloak.testsuite.federation.DummyUserFederationProviderFactory;
|
import org.keycloak.testsuite.federation.DummyUserFederationProviderFactory;
|
||||||
import org.openqa.selenium.By;
|
import org.openqa.selenium.By;
|
||||||
|
@ -634,7 +635,14 @@ public abstract class AbstractKeycloakIdentityProviderTest extends AbstractIdent
|
||||||
|
|
||||||
// Add federationProvider to realm. It's configured with sync registrations
|
// Add federationProvider to realm. It's configured with sync registrations
|
||||||
RealmModel realm = getRealm();
|
RealmModel realm = getRealm();
|
||||||
UserFederationProviderModel dummyModel = realm.addUserFederationProvider(DummyUserFederationProviderFactory.PROVIDER_NAME, new HashMap<String, String>(), 1, "test-dummy", -1, -1, 0);
|
UserStorageProviderModel model = new UserStorageProviderModel();
|
||||||
|
model.setProviderId(DummyUserFederationProviderFactory.PROVIDER_NAME);
|
||||||
|
model.setPriority(1);
|
||||||
|
model.setName("test-sync-dummy");
|
||||||
|
model.setFullSyncPeriod(-1);
|
||||||
|
model.setChangedSyncPeriod(-1);
|
||||||
|
model.setLastSync(0);
|
||||||
|
UserStorageProviderModel dummyModel = new UserStorageProviderModel(realm.addComponentModel(model));
|
||||||
|
|
||||||
brokerServerRule.stopSession(session, true);
|
brokerServerRule.stopSession(session, true);
|
||||||
session = brokerServerRule.startSession();
|
session = brokerServerRule.startSession();
|
||||||
|
@ -682,7 +690,7 @@ public abstract class AbstractKeycloakIdentityProviderTest extends AbstractIdent
|
||||||
|
|
||||||
// remove dummy federation provider for this realm
|
// remove dummy federation provider for this realm
|
||||||
realm = getRealm();
|
realm = getRealm();
|
||||||
realm.removeUserFederationProvider(dummyModel);
|
realm.removeComponent(dummyModel);
|
||||||
|
|
||||||
brokerServerRule.stopSession(session, true);
|
brokerServerRule.stopSession(session, true);
|
||||||
session = brokerServerRule.startSession();
|
session = brokerServerRule.startSession();
|
||||||
|
|
|
@ -26,9 +26,14 @@ import org.keycloak.models.UserFederationProviderModel;
|
||||||
import org.keycloak.models.UserFederationSyncResult;
|
import org.keycloak.models.UserFederationSyncResult;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
|
import org.keycloak.provider.ProviderConfigProperty;
|
||||||
|
import org.keycloak.provider.ProviderConfigurationBuilder;
|
||||||
|
import org.keycloak.storage.UserStorageProviderModel;
|
||||||
|
import org.keycloak.storage.user.SynchronizationResult;
|
||||||
import org.keycloak.testsuite.federation.DummyUserFederationProviderFactory;
|
import org.keycloak.testsuite.federation.DummyUserFederationProviderFactory;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
@ -59,21 +64,27 @@ public class SyncDummyUserFederationProviderFactory extends DummyUserFederationP
|
||||||
return SYNC_PROVIDER_ID;
|
return SYNC_PROVIDER_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Set<String> getConfigurationOptions() {
|
public List<ProviderConfigProperty> getConfigProperties() {
|
||||||
Set<String> list = super.getConfigurationOptions();
|
return ProviderConfigurationBuilder.create()
|
||||||
list.add(WAIT_TIME);
|
.property().name("important.config")
|
||||||
return list;
|
.type(ProviderConfigProperty.STRING_TYPE)
|
||||||
|
.add()
|
||||||
|
.property().name(WAIT_TIME)
|
||||||
|
.type(ProviderConfigProperty.STRING_TYPE)
|
||||||
|
.add()
|
||||||
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UserFederationSyncResult syncChangedUsers(KeycloakSessionFactory sessionFactory, final String realmId, final UserFederationProviderModel model, Date lastSync) {
|
public SynchronizationResult syncSince(Date lastSync, KeycloakSessionFactory sessionFactory, String realmId, UserStorageProviderModel model) {
|
||||||
|
|
||||||
KeycloakModelUtils.runJobInTransaction(sessionFactory, new KeycloakSessionTask() {
|
KeycloakModelUtils.runJobInTransaction(sessionFactory, new KeycloakSessionTask() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run(KeycloakSession session) {
|
public void run(KeycloakSession session) {
|
||||||
int waitTime = Integer.parseInt(model.getConfig().get(WAIT_TIME));
|
int waitTime = Integer.parseInt(model.getConfig().getFirst(WAIT_TIME));
|
||||||
|
|
||||||
logger.infof("Starting sync of changed users. Wait time is: %s", waitTime);
|
logger.infof("Starting sync of changed users. Wait time is: %s", waitTime);
|
||||||
|
|
||||||
|
@ -109,7 +120,7 @@ public class SyncDummyUserFederationProviderFactory extends DummyUserFederationP
|
||||||
// countDown, so the SyncFederationTest can continue
|
// countDown, so the SyncFederationTest can continue
|
||||||
latch2.countDown();
|
latch2.countDown();
|
||||||
|
|
||||||
return new UserFederationSyncResult();
|
return new SynchronizationResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,14 +24,17 @@ import org.junit.FixMethodOrder;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runners.MethodSorters;
|
import org.junit.runners.MethodSorters;
|
||||||
import org.keycloak.common.util.Time;
|
import org.keycloak.common.util.Time;
|
||||||
|
import org.keycloak.component.ComponentModel;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.KeycloakSessionFactory;
|
import org.keycloak.models.KeycloakSessionFactory;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.UserFederationProvider;
|
|
||||||
import org.keycloak.models.UserFederationProviderModel;
|
import org.keycloak.models.UserFederationProviderModel;
|
||||||
import org.keycloak.models.UserFederationSyncResult;
|
import org.keycloak.models.UserFederationSyncResult;
|
||||||
import org.keycloak.services.managers.RealmManager;
|
import org.keycloak.services.managers.RealmManager;
|
||||||
import org.keycloak.services.managers.UsersSyncManager;
|
import org.keycloak.services.managers.UserStorageSyncManager;
|
||||||
|
import org.keycloak.storage.UserStorageProvider;
|
||||||
|
import org.keycloak.storage.UserStorageProviderModel;
|
||||||
|
import org.keycloak.storage.user.SynchronizationResult;
|
||||||
import org.keycloak.testsuite.federation.DummyUserFederationProviderFactory;
|
import org.keycloak.testsuite.federation.DummyUserFederationProviderFactory;
|
||||||
import org.keycloak.testsuite.rule.KeycloakRule;
|
import org.keycloak.testsuite.rule.KeycloakRule;
|
||||||
import org.keycloak.timer.TimerProvider;
|
import org.keycloak.timer.TimerProvider;
|
||||||
|
@ -41,7 +44,7 @@ import java.util.Map;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test with Dummy providers (For LDAP see {@link org.keycloak.testsuite.federation.ldap.base.LDAPSyncTest}
|
* Test with Dummy providers
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
*/
|
*/
|
||||||
|
@ -50,7 +53,7 @@ public class SyncFederationTest {
|
||||||
|
|
||||||
private static final Logger log = Logger.getLogger(SyncFederationTest.class);
|
private static final Logger log = Logger.getLogger(SyncFederationTest.class);
|
||||||
|
|
||||||
private static UserFederationProviderModel dummyModel = null;
|
private static UserStorageProviderModel dummyModel = null;
|
||||||
|
|
||||||
@ClassRule
|
@ClassRule
|
||||||
public static KeycloakRule keycloakRule = new KeycloakRule(new KeycloakRule.KeycloakSetup() {
|
public static KeycloakRule keycloakRule = new KeycloakRule(new KeycloakRule.KeycloakSetup() {
|
||||||
|
@ -62,6 +65,7 @@ public class SyncFederationTest {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test01PeriodicSync() {
|
public void test01PeriodicSync() {
|
||||||
|
|
||||||
|
@ -70,7 +74,14 @@ public class SyncFederationTest {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
||||||
dummyModel = appRealm.addUserFederationProvider(DummyUserFederationProviderFactory.PROVIDER_NAME, new HashMap<String, String>(), 1, "test-sync-dummy", -1, 1, 0);
|
UserStorageProviderModel model = new UserStorageProviderModel();
|
||||||
|
model.setProviderId(DummyUserFederationProviderFactory.PROVIDER_NAME);
|
||||||
|
model.setPriority(1);
|
||||||
|
model.setName("test-sync-dummy");
|
||||||
|
model.setFullSyncPeriod(-1);
|
||||||
|
model.setChangedSyncPeriod(1);
|
||||||
|
model.setLastSync(0);
|
||||||
|
dummyModel = new UserStorageProviderModel(appRealm.addComponentModel(model));
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -78,12 +89,12 @@ public class SyncFederationTest {
|
||||||
KeycloakSession session = keycloakRule.startSession();
|
KeycloakSession session = keycloakRule.startSession();
|
||||||
try {
|
try {
|
||||||
KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
|
KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
|
||||||
DummyUserFederationProviderFactory dummyFedFactory = (DummyUserFederationProviderFactory)sessionFactory.getProviderFactory(UserFederationProvider.class, DummyUserFederationProviderFactory.PROVIDER_NAME);
|
DummyUserFederationProviderFactory dummyFedFactory = (DummyUserFederationProviderFactory)sessionFactory.getProviderFactory(UserStorageProvider.class, DummyUserFederationProviderFactory.PROVIDER_NAME);
|
||||||
int full = dummyFedFactory.getFullSyncCounter();
|
int full = dummyFedFactory.getFullSyncCounter();
|
||||||
int changed = dummyFedFactory.getChangedSyncCounter();
|
int changed = dummyFedFactory.getChangedSyncCounter();
|
||||||
|
|
||||||
// Assert that after some period was DummyUserFederationProvider triggered
|
// Assert that after some period was DummyUserFederationProvider triggered
|
||||||
UsersSyncManager usersSyncManager = new UsersSyncManager();
|
UserStorageSyncManager usersSyncManager = new UserStorageSyncManager();
|
||||||
usersSyncManager.bootstrapPeriodic(sessionFactory, session.getProvider(TimerProvider.class));
|
usersSyncManager.bootstrapPeriodic(sessionFactory, session.getProvider(TimerProvider.class));
|
||||||
sleep(1800);
|
sleep(1800);
|
||||||
|
|
||||||
|
@ -94,7 +105,7 @@ public class SyncFederationTest {
|
||||||
|
|
||||||
// This sync is here just to ensure that we have lock (doublecheck that periodic sync, which was possibly triggered before canceling timer is finished too)
|
// This sync is here just to ensure that we have lock (doublecheck that periodic sync, which was possibly triggered before canceling timer is finished too)
|
||||||
while (true) {
|
while (true) {
|
||||||
UserFederationSyncResult result = usersSyncManager.syncChangedUsers(session.getKeycloakSessionFactory(), appRealm.getId(), dummyModel);
|
SynchronizationResult result = usersSyncManager.syncChangedUsers(session.getKeycloakSessionFactory(), appRealm.getId(), dummyModel);
|
||||||
if (result.isIgnored()) {
|
if (result.isIgnored()) {
|
||||||
log.infof("Still waiting for lock before periodic sync is finished", result.toString());
|
log.infof("Still waiting for lock before periodic sync is finished", result.toString());
|
||||||
sleep(1000);
|
sleep(1000);
|
||||||
|
@ -122,7 +133,7 @@ public class SyncFederationTest {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
||||||
appRealm.removeUserFederationProvider(dummyModel);
|
appRealm.removeComponent(dummyModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -137,9 +148,15 @@ public class SyncFederationTest {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
||||||
Map<String, String> config = new HashMap<>();
|
UserStorageProviderModel model = new UserStorageProviderModel();
|
||||||
config.put(SyncDummyUserFederationProviderFactory.WAIT_TIME, "2000");
|
model.setProviderId(SyncDummyUserFederationProviderFactory.SYNC_PROVIDER_ID);
|
||||||
dummyModel = appRealm.addUserFederationProvider(SyncDummyUserFederationProviderFactory.SYNC_PROVIDER_ID, config, 1, "test-sync-dummy", -1, 1, 0);
|
model.setPriority(1);
|
||||||
|
model.setName("test-sync-dummy");
|
||||||
|
model.setFullSyncPeriod(-1);
|
||||||
|
model.setChangedSyncPeriod(1);
|
||||||
|
model.setLastSync(0);
|
||||||
|
model.getConfig().putSingle(SyncDummyUserFederationProviderFactory.WAIT_TIME, "2000");
|
||||||
|
dummyModel = new UserStorageProviderModel(appRealm.addComponentModel(model));
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -149,13 +166,13 @@ public class SyncFederationTest {
|
||||||
KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
|
KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
|
||||||
|
|
||||||
// bootstrap periodic sync
|
// bootstrap periodic sync
|
||||||
UsersSyncManager usersSyncManager = new UsersSyncManager();
|
UserStorageSyncManager usersSyncManager = new UserStorageSyncManager();
|
||||||
usersSyncManager.bootstrapPeriodic(sessionFactory, session.getProvider(TimerProvider.class));
|
usersSyncManager.bootstrapPeriodic(sessionFactory, session.getProvider(TimerProvider.class));
|
||||||
|
|
||||||
// Wait and then trigger sync manually. Assert it will be ignored
|
// Wait and then trigger sync manually. Assert it will be ignored
|
||||||
sleep(1800);
|
sleep(1800);
|
||||||
RealmModel realm = session.realms().getRealm("test");
|
RealmModel realm = session.realms().getRealm("test");
|
||||||
UserFederationSyncResult syncResult = usersSyncManager.syncChangedUsers(sessionFactory, realm.getId(), dummyModel);
|
SynchronizationResult syncResult = usersSyncManager.syncChangedUsers(sessionFactory, realm.getId(), dummyModel);
|
||||||
Assert.assertTrue(syncResult.isIgnored());
|
Assert.assertTrue(syncResult.isIgnored());
|
||||||
|
|
||||||
// Cancel timer
|
// Cancel timer
|
||||||
|
@ -175,7 +192,7 @@ public class SyncFederationTest {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
||||||
appRealm.removeUserFederationProvider(dummyModel);
|
appRealm.removeComponent(dummyModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -48,9 +48,11 @@ import org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper;
|
||||||
import org.keycloak.protocol.oidc.mappers.UserSessionNoteMapper;
|
import org.keycloak.protocol.oidc.mappers.UserSessionNoteMapper;
|
||||||
import org.keycloak.representations.idm.RealmRepresentation;
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
import org.keycloak.services.managers.RealmManager;
|
import org.keycloak.services.managers.RealmManager;
|
||||||
|
import org.keycloak.storage.UserStorageProvider;
|
||||||
import org.keycloak.storage.UserStorageProviderModel;
|
import org.keycloak.storage.UserStorageProviderModel;
|
||||||
import org.keycloak.storage.ldap.mappers.FullNameLDAPStorageMapper;
|
import org.keycloak.storage.ldap.mappers.FullNameLDAPStorageMapper;
|
||||||
import org.keycloak.storage.ldap.mappers.FullNameLDAPStorageMapperFactory;
|
import org.keycloak.storage.ldap.mappers.FullNameLDAPStorageMapperFactory;
|
||||||
|
import org.keycloak.testsuite.federation.DummyUserFederationProviderFactory;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -279,8 +281,6 @@ public class ImportTest extends AbstractModelTest {
|
||||||
Assert.assertEquals("googleSecret", google.getConfig().get("clientSecret"));
|
Assert.assertEquals("googleSecret", google.getConfig().get("clientSecret"));
|
||||||
|
|
||||||
// Test federation providers
|
// Test federation providers
|
||||||
List<UserFederationProviderModel> fedProviders = realm.getUserFederationProviders();
|
|
||||||
Assert.assertTrue(fedProviders.size() == 0);
|
|
||||||
List<UserStorageProviderModel> storageProviders = realm.getUserStorageProviders();
|
List<UserStorageProviderModel> storageProviders = realm.getUserStorageProviders();
|
||||||
Assert.assertTrue(storageProviders.size() == 2);
|
Assert.assertTrue(storageProviders.size() == 2);
|
||||||
UserStorageProviderModel ldap1 = storageProviders.get(0);
|
UserStorageProviderModel ldap1 = storageProviders.get(0);
|
||||||
|
@ -294,8 +294,6 @@ public class ImportTest extends AbstractModelTest {
|
||||||
Assert.assertEquals("ldap://bar", ldap2.getConfig().getFirst(LDAPConstants.CONNECTION_URL));
|
Assert.assertEquals("ldap://bar", ldap2.getConfig().getFirst(LDAPConstants.CONNECTION_URL));
|
||||||
|
|
||||||
// Test federation mappers
|
// Test federation mappers
|
||||||
Set<UserFederationMapperModel> userFedMappers1 = realm.getUserFederationMappers();
|
|
||||||
Assert.assertTrue(userFedMappers1.size() == 0);
|
|
||||||
List<ComponentModel> fedMappers1 = realm.getComponents(ldap1.getId());
|
List<ComponentModel> fedMappers1 = realm.getComponents(ldap1.getId());
|
||||||
ComponentModel fullNameMapper = fedMappers1.iterator().next();
|
ComponentModel fullNameMapper = fedMappers1.iterator().next();
|
||||||
Assert.assertEquals("FullNameMapper", fullNameMapper.getName());
|
Assert.assertEquals("FullNameMapper", fullNameMapper.getName());
|
||||||
|
@ -304,8 +302,8 @@ public class ImportTest extends AbstractModelTest {
|
||||||
Assert.assertEquals("cn", fullNameMapper.getConfig().getFirst(FullNameLDAPStorageMapper.LDAP_FULL_NAME_ATTRIBUTE));
|
Assert.assertEquals("cn", fullNameMapper.getConfig().getFirst(FullNameLDAPStorageMapper.LDAP_FULL_NAME_ATTRIBUTE));
|
||||||
|
|
||||||
// Assert that federation link wasn't created during import
|
// Assert that federation link wasn't created during import
|
||||||
UserFederationProviderFactory factory = (UserFederationProviderFactory)session.getKeycloakSessionFactory().getProviderFactory(UserFederationProvider.class, "dummy");
|
DummyUserFederationProviderFactory factory = (DummyUserFederationProviderFactory)session.getKeycloakSessionFactory().getProviderFactory(UserStorageProvider.class, "dummy");
|
||||||
Assert.assertNull(factory.getInstance(session, null).getUserByUsername(realm, "wburke"));
|
Assert.assertNull(factory.create(session, null).getUserByUsername("wburke", realm));
|
||||||
|
|
||||||
// Test builtin authentication flows
|
// Test builtin authentication flows
|
||||||
AuthenticationFlowModel clientFlow = realm.getClientAuthenticationFlow();
|
AuthenticationFlowModel clientFlow = realm.getClientAuthenticationFlow();
|
||||||
|
|
|
@ -1,175 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
|
||||||
* and other contributors as indicated by the @author tags.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.keycloak.testsuite.model;
|
|
||||||
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.keycloak.models.ModelDuplicateException;
|
|
||||||
import org.keycloak.models.RealmModel;
|
|
||||||
import org.keycloak.models.UserFederationMapperModel;
|
|
||||||
import org.keycloak.models.UserFederationProviderModel;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.TreeMap;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
|
||||||
*/
|
|
||||||
public class UserFederationModelTest extends AbstractModelTest {
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void federationMapperCrudTest() {
|
|
||||||
RealmModel realm = realmManager.createRealm("test-realm");
|
|
||||||
UserFederationProviderModel fedProvider = realm.addUserFederationProvider("dummy", new TreeMap<String, String>(), 1, "my-cool-provider", -1, -1, 0);
|
|
||||||
UserFederationProviderModel fedProvider2 = realm.addUserFederationProvider("dummy", new TreeMap<String, String>(), 1, "my-cool-provider2", -1, -1, 0);
|
|
||||||
|
|
||||||
UserFederationMapperModel mapperModel1 = createMapper("name1", fedProvider.getId(), "key1", "value1");
|
|
||||||
UserFederationMapperModel mapperModel2 = createMapper("name2", fedProvider.getId(), "key2", "value2");
|
|
||||||
UserFederationMapperModel mapperModel3 = createMapper("name1", fedProvider2.getId(), "key3", "value3");
|
|
||||||
|
|
||||||
mapperModel1 = realm.addUserFederationMapper(mapperModel1);
|
|
||||||
mapperModel2 = realm.addUserFederationMapper(mapperModel2);
|
|
||||||
mapperModel3 = realm.addUserFederationMapper(mapperModel3);
|
|
||||||
|
|
||||||
commit();
|
|
||||||
|
|
||||||
try {
|
|
||||||
UserFederationMapperModel conflictMapper = createMapper("name1", fedProvider.getId(), "key4", "value4");
|
|
||||||
realmManager.getRealmByName("test-realm").addUserFederationMapper(conflictMapper);
|
|
||||||
commit();
|
|
||||||
Assert.fail("Don't expect to end here");
|
|
||||||
} catch (ModelDuplicateException expected) {
|
|
||||||
}
|
|
||||||
|
|
||||||
realm = realmManager.getRealmByName("test-realm");
|
|
||||||
Set<UserFederationMapperModel> mappers = realm.getUserFederationMappers();
|
|
||||||
Assert.assertEquals(3, mappers.size());
|
|
||||||
Assert.assertTrue(mappers.contains(mapperModel1));
|
|
||||||
Assert.assertTrue(mappers.contains(mapperModel2));
|
|
||||||
Assert.assertTrue(mappers.contains(mapperModel3));
|
|
||||||
|
|
||||||
mappers = realm.getUserFederationMappersByFederationProvider(fedProvider.getId());
|
|
||||||
Assert.assertEquals(2, mappers.size());
|
|
||||||
Assert.assertTrue(mappers.contains(mapperModel1));
|
|
||||||
Assert.assertTrue(mappers.contains(mapperModel2));
|
|
||||||
|
|
||||||
mapperModel3.getConfig().put("otherKey", "otherValue");
|
|
||||||
realm.updateUserFederationMapper(mapperModel3);
|
|
||||||
|
|
||||||
commit();
|
|
||||||
|
|
||||||
realm = realmManager.getRealmByName("test-realm");
|
|
||||||
mapperModel3 = realm.getUserFederationMapperById(mapperModel3.getId());
|
|
||||||
Assert.assertEquals(2, mapperModel3.getConfig().size());
|
|
||||||
Assert.assertEquals("value3", mapperModel3.getConfig().get("key3"));
|
|
||||||
Assert.assertEquals("otherValue", mapperModel3.getConfig().get("otherKey"));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void federationProviderRemovalTest() {
|
|
||||||
RealmModel realm = realmManager.createRealm("test-realm");
|
|
||||||
UserFederationProviderModel fedProvider = realm.addUserFederationProvider("dummy", new TreeMap<String, String>(), 1, "my-cool-provider", -1, -1, 0);
|
|
||||||
UserFederationProviderModel fedProvider2 = realm.addUserFederationProvider("dummy", new TreeMap<String, String>(), 1, "my-cool-provider2", -1, -1, 0);
|
|
||||||
|
|
||||||
UserFederationMapperModel mapperModel1 = createMapper("name1", fedProvider.getId(), "key1", "value1");
|
|
||||||
UserFederationMapperModel mapperModel2 = createMapper("name2", fedProvider.getId(), "key2", "value2");
|
|
||||||
UserFederationMapperModel mapperModel3 = createMapper("name1", fedProvider2.getId(), "key3", "value3");
|
|
||||||
|
|
||||||
mapperModel1 = realm.addUserFederationMapper(mapperModel1);
|
|
||||||
mapperModel2 = realm.addUserFederationMapper(mapperModel2);
|
|
||||||
mapperModel3 = realm.addUserFederationMapper(mapperModel3);
|
|
||||||
|
|
||||||
commit();
|
|
||||||
|
|
||||||
realmManager.getRealmByName("test-realm").removeUserFederationProvider(fedProvider);
|
|
||||||
|
|
||||||
commit();
|
|
||||||
|
|
||||||
realm = realmManager.getRealmByName("test-realm");
|
|
||||||
Set<UserFederationMapperModel> mappers = realm.getUserFederationMappers();
|
|
||||||
Assert.assertEquals(1, mappers.size());
|
|
||||||
Assert.assertEquals(mapperModel3, mappers.iterator().next());
|
|
||||||
|
|
||||||
realm = realmManager.getRealmByName("test-realm");
|
|
||||||
realmManager.removeRealm(realm);
|
|
||||||
|
|
||||||
commit();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void federationProvidersSetTest() {
|
|
||||||
RealmModel realm = realmManager.createRealm("test-realm");
|
|
||||||
UserFederationProviderModel ldapProvider = new UserFederationProviderModel(null, "ldap", new TreeMap<String, String>(), 1, "my-cool-provider", -1, -1, 0);
|
|
||||||
realm.setUserFederationProviders(Arrays.asList(ldapProvider));
|
|
||||||
|
|
||||||
commit();
|
|
||||||
|
|
||||||
realm = realmManager.getRealmByName("test-realm");
|
|
||||||
List<UserFederationProviderModel> fedProviders = realm.getUserFederationProviders();
|
|
||||||
Assert.assertEquals(1, fedProviders.size());
|
|
||||||
ldapProvider = fedProviders.get(0);
|
|
||||||
Set<UserFederationMapperModel> fedMappers = realmManager.getRealmByName("test-realm").getUserFederationMappersByFederationProvider(ldapProvider.getId());
|
|
||||||
|
|
||||||
UserFederationProviderModel dummyProvider = new UserFederationProviderModel(null, "dummy", new TreeMap<String, String>(), 1, "my-cool-provider", -1, -1, 0);
|
|
||||||
try {
|
|
||||||
realm.setUserFederationProviders(Arrays.asList(ldapProvider, dummyProvider));
|
|
||||||
commit();
|
|
||||||
Assert.fail("Don't expect to end here");
|
|
||||||
} catch (ModelDuplicateException expected) {
|
|
||||||
}
|
|
||||||
|
|
||||||
dummyProvider.setDisplayName("my-cool-provider2");
|
|
||||||
realm.setUserFederationProviders(Arrays.asList(ldapProvider, dummyProvider));
|
|
||||||
|
|
||||||
commit();
|
|
||||||
|
|
||||||
realm = realmManager.getRealmByName("test-realm");
|
|
||||||
Assert.assertEquals(fedMappers.size(), realm.getUserFederationMappersByFederationProvider(ldapProvider.getId()).size());
|
|
||||||
realm.setUserFederationProviders(new ArrayList<UserFederationProviderModel>());
|
|
||||||
|
|
||||||
commit();
|
|
||||||
|
|
||||||
realm = realmManager.getRealmByName("test-realm");
|
|
||||||
Assert.assertTrue(realm.getUserFederationMappersByFederationProvider(ldapProvider.getId()).isEmpty());
|
|
||||||
}
|
|
||||||
|
|
||||||
private UserFederationMapperModel createMapper(String name, String fedProviderId, String... config) {
|
|
||||||
UserFederationMapperModel mapperModel = new UserFederationMapperModel();
|
|
||||||
mapperModel.setName(name);
|
|
||||||
mapperModel.setFederationMapperType("someType");
|
|
||||||
mapperModel.setFederationProviderId(fedProviderId);
|
|
||||||
Map<String, String> configMap = new TreeMap<String, String>();
|
|
||||||
String key = null;
|
|
||||||
for (String configEntry : config) {
|
|
||||||
if (key == null) {
|
|
||||||
key = configEntry;
|
|
||||||
} else {
|
|
||||||
configMap.put(key, configEntry);
|
|
||||||
key = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mapperModel.setConfig(configMap);
|
|
||||||
return mapperModel;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -17,11 +17,14 @@
|
||||||
|
|
||||||
package org.keycloak.testsuite.util.cli;
|
package org.keycloak.testsuite.util.cli;
|
||||||
|
|
||||||
|
import org.keycloak.common.util.MultivaluedHashMap;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.UserFederationProviderModel;
|
import org.keycloak.models.UserFederationProviderModel;
|
||||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
import org.keycloak.services.managers.UsersSyncManager;
|
import org.keycloak.services.managers.UserStorageSyncManager;
|
||||||
|
import org.keycloak.storage.UserStorageProviderModel;
|
||||||
|
import org.keycloak.testsuite.federation.DummyUserFederationProviderFactory;
|
||||||
import org.keycloak.testsuite.federation.sync.SyncDummyUserFederationProviderFactory;
|
import org.keycloak.testsuite.federation.sync.SyncDummyUserFederationProviderFactory;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -38,25 +41,33 @@ public class SyncDummyFederationProviderCommand extends AbstractCommand {
|
||||||
int changedSyncPeriod = getIntArg(1);
|
int changedSyncPeriod = getIntArg(1);
|
||||||
|
|
||||||
RealmModel realm = session.realms().getRealmByName("master");
|
RealmModel realm = session.realms().getRealmByName("master");
|
||||||
UserFederationProviderModel fedProviderModel = KeycloakModelUtils.findUserFederationProviderByDisplayName("cluster-dummy", realm);
|
UserStorageProviderModel fedProviderModel = KeycloakModelUtils.findUserStorageProviderByName("cluster-dummy", realm);
|
||||||
if (fedProviderModel == null) {
|
if (fedProviderModel == null) {
|
||||||
Map<String, String> cfg = new HashMap<>();
|
MultivaluedHashMap<String, String> cfg = fedProviderModel.getConfig();
|
||||||
updateConfig(cfg, waitTime);
|
updateConfig(cfg, waitTime);
|
||||||
fedProviderModel = realm.addUserFederationProvider(SyncDummyUserFederationProviderFactory.SYNC_PROVIDER_ID, cfg, 1, "cluster-dummy", -1, changedSyncPeriod, -1);
|
|
||||||
|
UserStorageProviderModel model = new UserStorageProviderModel();
|
||||||
|
model.setProviderId(SyncDummyUserFederationProviderFactory.SYNC_PROVIDER_ID);
|
||||||
|
model.setPriority(1);
|
||||||
|
model.setName("cluster-dummy");
|
||||||
|
model.setFullSyncPeriod(-1);
|
||||||
|
model.setChangedSyncPeriod(changedSyncPeriod);
|
||||||
|
model.setLastSync(-1);
|
||||||
|
fedProviderModel = new UserStorageProviderModel(realm.addComponentModel(model));
|
||||||
} else {
|
} else {
|
||||||
Map<String, String> cfg = fedProviderModel.getConfig();
|
MultivaluedHashMap<String, String> cfg = fedProviderModel.getConfig();
|
||||||
updateConfig(cfg, waitTime);
|
updateConfig(cfg, waitTime);
|
||||||
fedProviderModel.setChangedSyncPeriod(changedSyncPeriod);
|
fedProviderModel.setChangedSyncPeriod(changedSyncPeriod);
|
||||||
realm.updateUserFederationProvider(fedProviderModel);
|
realm.updateComponent(fedProviderModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
new UsersSyncManager().notifyToRefreshPeriodicSync(session, realm, fedProviderModel, false);
|
new UserStorageSyncManager().notifyToRefreshPeriodicSync(session, realm, fedProviderModel, false);
|
||||||
|
|
||||||
log.infof("User federation provider created and sync was started", waitTime);
|
log.infof("User federation provider created and sync was started", waitTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateConfig(Map<String, String> cfg, int waitTime) {
|
private void updateConfig(MultivaluedHashMap<String, String> cfg, int waitTime) {
|
||||||
cfg.put(SyncDummyUserFederationProviderFactory.WAIT_TIME, String.valueOf(waitTime));
|
cfg.putSingle(SyncDummyUserFederationProviderFactory.WAIT_TIME, String.valueOf(waitTime));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
#
|
|
||||||
# Copyright 2016 Red Hat, Inc. and/or its affiliates
|
|
||||||
# and other contributors as indicated by the @author tags.
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
#
|
|
||||||
|
|
||||||
org.keycloak.testsuite.federation.sync.SyncDummyUserFederationProviderFactory
|
|
|
@ -1,2 +1,3 @@
|
||||||
|
org.keycloak.testsuite.federation.sync.SyncDummyUserFederationProviderFactory
|
||||||
org.keycloak.testsuite.federation.storage.UserPropertyFileStorageFactory
|
org.keycloak.testsuite.federation.storage.UserPropertyFileStorageFactory
|
||||||
org.keycloak.testsuite.federation.storage.UserMapStorageFactory
|
org.keycloak.testsuite.federation.storage.UserMapStorageFactory
|
Loading…
Reference in a new issue