commit
2eae9c17a4
10 changed files with 484 additions and 201 deletions
|
@ -1,6 +1,7 @@
|
|||
package org.keycloak.federation.ldap;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.models.UserCredentialValueModel;
|
||||
import org.keycloak.models.UserFederationProvider;
|
||||
import org.keycloak.models.UserFederationProviderModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
|
@ -19,6 +20,7 @@ import org.picketlink.idm.model.basic.BasicModel;
|
|||
import org.picketlink.idm.model.basic.User;
|
||||
import org.picketlink.idm.query.IdentityQuery;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
|
@ -35,10 +37,12 @@ public class LDAPFederationProvider implements UserFederationProvider {
|
|||
private static final Logger logger = Logger.getLogger(LDAPFederationProvider.class);
|
||||
public static final String LDAP_ID = "LDAP_ID";
|
||||
public static final String SYNC_REGISTRATIONS = "syncRegistrations";
|
||||
public static final String EDIT_MODE = "editMode";
|
||||
|
||||
protected KeycloakSession session;
|
||||
protected UserFederationProviderModel model;
|
||||
protected PartitionManager partitionManager;
|
||||
protected EditMode editMode;
|
||||
|
||||
protected static final Set<String> supportedCredentialTypes = new HashSet<String>();
|
||||
|
||||
|
@ -51,6 +55,9 @@ public class LDAPFederationProvider implements UserFederationProvider {
|
|||
this.session = session;
|
||||
this.model = model;
|
||||
this.partitionManager = partitionManager;
|
||||
String editModeString = model.getConfig().get(EDIT_MODE);
|
||||
if (editModeString == null) editMode = EditMode.READ_ONLY;
|
||||
editMode = EditMode.valueOf(editModeString);
|
||||
}
|
||||
|
||||
private ModelException convertIDMException(IdentityManagementException ie) {
|
||||
|
@ -77,22 +84,37 @@ public class LDAPFederationProvider implements UserFederationProvider {
|
|||
|
||||
@Override
|
||||
public UserModel proxy(UserModel local) {
|
||||
// todo
|
||||
return new LDAPUserModelDelegate(local, this);
|
||||
switch (editMode) {
|
||||
case READ_ONLY:
|
||||
return new ReadonlyLDAPUserModelDelegate(local, this);
|
||||
case WRITABLE:
|
||||
return new WritableLDAPUserModelDelegate(local, this);
|
||||
case UNSYNCED:
|
||||
return new UnsyncedLDAPUserModelDelegate(local, this);
|
||||
}
|
||||
return local;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getSupportedCredentialTypes() {
|
||||
public Set<String> getSupportedCredentialTypes(UserModel local) {
|
||||
if (editMode == EditMode.UNSYNCED ) {
|
||||
for (UserCredentialValueModel cred : local.getCredentialsDirectly()) {
|
||||
if (cred.getType().equals(UserCredentialModel.PASSWORD)) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
}
|
||||
}
|
||||
return supportedCredentialTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean synchronizeRegistrations() {
|
||||
return "true".equalsIgnoreCase(model.getConfig().get(SYNC_REGISTRATIONS));
|
||||
return "true".equalsIgnoreCase(model.getConfig().get(SYNC_REGISTRATIONS)) && editMode == EditMode.WRITABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserModel register(RealmModel realm, UserModel user) {
|
||||
if (editMode == EditMode.READ_ONLY || editMode == EditMode.UNSYNCED) throw new IllegalStateException("Registration is not supported by this ldap server");;
|
||||
if (!synchronizeRegistrations()) throw new IllegalStateException("Registration is not supported by this ldap server");
|
||||
IdentityManager identityManager = getIdentityManager();
|
||||
|
||||
|
@ -112,6 +134,8 @@ public class LDAPFederationProvider implements UserFederationProvider {
|
|||
|
||||
@Override
|
||||
public boolean removeUser(RealmModel realm, UserModel user) {
|
||||
if (editMode == EditMode.READ_ONLY || editMode == EditMode.UNSYNCED) return false;
|
||||
|
||||
IdentityManager identityManager = getIdentityManager();
|
||||
|
||||
try {
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
package org.keycloak.federation.ldap;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.models.ModelException;
|
||||
import org.keycloak.models.UserCredentialModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.utils.UserModelDelegate;
|
||||
import org.picketlink.idm.IdentityManagementException;
|
||||
import org.picketlink.idm.IdentityManager;
|
||||
import org.picketlink.idm.credential.Password;
|
||||
import org.picketlink.idm.credential.TOTPCredential;
|
||||
import org.picketlink.idm.model.basic.BasicModel;
|
||||
import org.picketlink.idm.model.basic.User;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class ReadonlyLDAPUserModelDelegate extends UserModelDelegate implements UserModel {
|
||||
private static final Logger logger = Logger.getLogger(ReadonlyLDAPUserModelDelegate.class);
|
||||
|
||||
protected LDAPFederationProvider provider;
|
||||
|
||||
public ReadonlyLDAPUserModelDelegate(UserModel delegate, LDAPFederationProvider provider) {
|
||||
super(delegate);
|
||||
this.provider = provider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUsername(String username) {
|
||||
throw new IllegalStateException("Federated storage is not writable");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLastName(String lastName) {
|
||||
throw new IllegalStateException("Federated storage is not writable");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFirstName(String first) {
|
||||
throw new IllegalStateException("Federated storage is not writable");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateCredential(UserCredentialModel cred) {
|
||||
if (provider.getSupportedCredentialTypes(delegate).contains(cred.getType())) {
|
||||
throw new IllegalStateException("Federated storage is not writable");
|
||||
}
|
||||
delegate.updateCredential(cred);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEmail(String email) {
|
||||
throw new IllegalStateException("Federated storage is not writable");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package org.keycloak.federation.ldap;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.models.ModelException;
|
||||
import org.keycloak.models.UserCredentialModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.utils.UserModelDelegate;
|
||||
import org.picketlink.idm.IdentityManagementException;
|
||||
import org.picketlink.idm.IdentityManager;
|
||||
import org.picketlink.idm.credential.Password;
|
||||
import org.picketlink.idm.credential.TOTPCredential;
|
||||
import org.picketlink.idm.model.basic.BasicModel;
|
||||
import org.picketlink.idm.model.basic.User;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class UnsyncedLDAPUserModelDelegate extends UserModelDelegate implements UserModel {
|
||||
private static final Logger logger = Logger.getLogger(UnsyncedLDAPUserModelDelegate.class);
|
||||
|
||||
protected LDAPFederationProvider provider;
|
||||
|
||||
public UnsyncedLDAPUserModelDelegate(UserModel delegate, LDAPFederationProvider provider) {
|
||||
super(delegate);
|
||||
this.provider = provider;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
package org.keycloak.federation.ldap;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.models.ApplicationModel;
|
||||
import org.keycloak.models.AuthenticationLinkModel;
|
||||
import org.keycloak.models.ModelException;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.UserCredentialModel;
|
||||
import org.keycloak.models.UserCredentialValueModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.utils.UserModelDelegate;
|
||||
import org.picketlink.idm.IdentityManagementException;
|
||||
import org.picketlink.idm.IdentityManager;
|
||||
import org.picketlink.idm.credential.Password;
|
||||
import org.picketlink.idm.credential.TOTPCredential;
|
||||
import org.picketlink.idm.model.basic.BasicModel;
|
||||
import org.picketlink.idm.model.basic.User;
|
||||
|
||||
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 WritableLDAPUserModelDelegate extends UserModelDelegate implements UserModel {
|
||||
private static final Logger logger = Logger.getLogger(WritableLDAPUserModelDelegate.class);
|
||||
|
||||
protected LDAPFederationProvider provider;
|
||||
|
||||
public WritableLDAPUserModelDelegate(UserModel delegate, LDAPFederationProvider provider) {
|
||||
super(delegate);
|
||||
this.provider = provider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUsername(String username) {
|
||||
IdentityManager identityManager = provider.getIdentityManager();
|
||||
|
||||
try {
|
||||
User picketlinkUser = BasicModel.getUser(identityManager, delegate.getUsername());
|
||||
if (picketlinkUser == null) {
|
||||
throw new IllegalStateException("User not found in LDAP storage!");
|
||||
}
|
||||
picketlinkUser.setLoginName(username);
|
||||
identityManager.update(picketlinkUser);
|
||||
} catch (IdentityManagementException ie) {
|
||||
throw new ModelException(ie);
|
||||
}
|
||||
delegate.setUsername(username);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLastName(String lastName) {
|
||||
IdentityManager identityManager = provider.getIdentityManager();
|
||||
|
||||
try {
|
||||
User picketlinkUser = BasicModel.getUser(identityManager, delegate.getUsername());
|
||||
if (picketlinkUser == null) {
|
||||
throw new IllegalStateException("User not found in LDAP storage!");
|
||||
}
|
||||
picketlinkUser.setLastName(lastName);
|
||||
identityManager.update(picketlinkUser);
|
||||
} catch (IdentityManagementException ie) {
|
||||
throw new ModelException(ie);
|
||||
}
|
||||
delegate.setLastName(lastName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFirstName(String first) {
|
||||
IdentityManager identityManager = provider.getIdentityManager();
|
||||
|
||||
try {
|
||||
User picketlinkUser = BasicModel.getUser(identityManager, delegate.getUsername());
|
||||
if (picketlinkUser == null) {
|
||||
throw new IllegalStateException("User not found in LDAP storage!");
|
||||
}
|
||||
picketlinkUser.setFirstName(first);
|
||||
identityManager.update(picketlinkUser);
|
||||
} catch (IdentityManagementException ie) {
|
||||
throw new ModelException(ie);
|
||||
}
|
||||
delegate.setFirstName(first);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateCredential(UserCredentialModel cred) {
|
||||
if (!provider.getSupportedCredentialTypes(delegate).contains(cred.getType())) {
|
||||
delegate.updateCredential(cred);
|
||||
return;
|
||||
}
|
||||
IdentityManager identityManager = provider.getIdentityManager();
|
||||
|
||||
try {
|
||||
User picketlinkUser = BasicModel.getUser(identityManager, getUsername());
|
||||
if (picketlinkUser == null) {
|
||||
logger.debugf("User '%s' doesn't exists. Skip password update", getUsername());
|
||||
throw new IllegalStateException("User doesn't exist in LDAP storage");
|
||||
}
|
||||
if (cred.getType().equals(UserCredentialModel.PASSWORD)) {
|
||||
identityManager.updateCredential(picketlinkUser, new Password(cred.getValue().toCharArray()));
|
||||
} else if (cred.getType().equals(UserCredentialModel.TOTP)) {
|
||||
TOTPCredential credential = new TOTPCredential(cred.getValue());
|
||||
credential.setDevice(cred.getDevice());
|
||||
identityManager.updateCredential(picketlinkUser, credential);
|
||||
}
|
||||
} catch (IdentityManagementException ie) {
|
||||
throw new ModelException(ie);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEmail(String email) {
|
||||
IdentityManager identityManager = provider.getIdentityManager();
|
||||
|
||||
try {
|
||||
User picketlinkUser = BasicModel.getUser(identityManager, delegate.getUsername());
|
||||
if (picketlinkUser == null) {
|
||||
throw new IllegalStateException("User not found in LDAP storage!");
|
||||
}
|
||||
picketlinkUser.setEmail(email);
|
||||
identityManager.update(picketlinkUser);
|
||||
} catch (IdentityManagementException ie) {
|
||||
throw new ModelException(ie);
|
||||
}
|
||||
delegate.setEmail(email);
|
||||
}
|
||||
|
||||
}
|
|
@ -33,6 +33,19 @@
|
|||
<input class="form-control" id="priority" type="text" ng-model="instance.priority">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="editMode">Edit mode</label>
|
||||
<div class="col-sm-4">
|
||||
<div class="select-kc">
|
||||
<select id="editMode"
|
||||
ng-model="instance.config.editMode">
|
||||
<option>READ_ONLY</option>
|
||||
<option>WRITABLE</option>
|
||||
<option>UNSYNCED</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group clearfix block">
|
||||
<label class="col-sm-2 control-label" for="syncRegistrations">Sync Registrations</label>
|
||||
<div class="col-sm-4">
|
||||
|
|
|
@ -307,7 +307,7 @@ public class UserFederationManager implements UserProvider {
|
|||
UserFederationProvider link = getFederationLink(realm, user);
|
||||
if (link != null) {
|
||||
validateUser(realm, user);
|
||||
if (link.getSupportedCredentialTypes().size() > 0) {
|
||||
if (link.getSupportedCredentialTypes(user).size() > 0) {
|
||||
List<UserCredentialModel> fedCreds = new ArrayList<UserCredentialModel>();
|
||||
List<UserCredentialModel> localCreds = new ArrayList<UserCredentialModel>();
|
||||
for (UserCredentialModel cred : input) {
|
||||
|
@ -331,7 +331,7 @@ public class UserFederationManager implements UserProvider {
|
|||
UserFederationProvider link = getFederationLink(realm, user);
|
||||
if (link != null) {
|
||||
validateUser(realm, user);
|
||||
Set<String> supportedCredentialTypes = link.getSupportedCredentialTypes();
|
||||
Set<String> supportedCredentialTypes = link.getSupportedCredentialTypes(user);
|
||||
if (supportedCredentialTypes.size() > 0) {
|
||||
List<UserCredentialModel> fedCreds = new ArrayList<UserCredentialModel>();
|
||||
List<UserCredentialModel> localCreds = new ArrayList<UserCredentialModel>();
|
||||
|
|
|
@ -19,6 +19,28 @@ public interface UserFederationProvider extends Provider {
|
|||
public static final String FIRST_NAME = UserModel.EMAIL;
|
||||
public static final String LAST_NAME = UserModel.LAST_NAME;
|
||||
|
||||
/**
|
||||
* Optional type that can be by implementations to describe edit mode of federation storage
|
||||
*
|
||||
*/
|
||||
enum EditMode {
|
||||
/**
|
||||
* federation storage is read-only
|
||||
*/
|
||||
READ_ONLY,
|
||||
/**
|
||||
* federation storage is writable
|
||||
*
|
||||
*/
|
||||
WRITABLE,
|
||||
/**
|
||||
* updates to user are stored locally and not synced with federation storage.
|
||||
*
|
||||
*/
|
||||
UNSYNCED
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gives the provider an option to proxy UserModels loaded from local storage.
|
||||
* This method is called whenever a UserModel is pulled from local storage.
|
||||
|
@ -81,12 +103,12 @@ public interface UserFederationProvider extends Provider {
|
|||
boolean isValid(UserModel local);
|
||||
|
||||
/**
|
||||
* What UserCredentialModel types are supported by this provider. Keycloak will only call
|
||||
* What UserCredentialModel types should be handled by this provider for this user? Keycloak will only call
|
||||
* validCredentials() with the credential types specified in this method.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Set<String> getSupportedCredentialTypes();
|
||||
Set<String> getSupportedCredentialTypes(UserModel user);
|
||||
|
||||
/**
|
||||
* Validate credentials for this user.
|
||||
|
@ -98,4 +120,6 @@ public interface UserFederationProvider extends Provider {
|
|||
*/
|
||||
boolean validCredentials(RealmModel realm, UserModel user, List<UserCredentialModel> input);
|
||||
boolean validCredentials(RealmModel realm, UserModel user, UserCredentialModel... input);
|
||||
void close();}
|
||||
void close();
|
||||
|
||||
}
|
||||
|
|
|
@ -1,19 +1,11 @@
|
|||
package org.keycloak.federation.ldap;
|
||||
package org.keycloak.models.utils;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.models.ApplicationModel;
|
||||
import org.keycloak.models.AuthenticationLinkModel;
|
||||
import org.keycloak.models.ModelException;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.UserCredentialModel;
|
||||
import org.keycloak.models.UserCredentialValueModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.picketlink.idm.IdentityManagementException;
|
||||
import org.picketlink.idm.IdentityManager;
|
||||
import org.picketlink.idm.credential.Password;
|
||||
import org.picketlink.idm.credential.TOTPCredential;
|
||||
import org.picketlink.idm.model.basic.BasicModel;
|
||||
import org.picketlink.idm.model.basic.User;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -23,15 +15,11 @@ import java.util.Set;
|
|||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class LDAPUserModelDelegate implements UserModel {
|
||||
private static final Logger logger = Logger.getLogger(LDAPUserModelDelegate.class);
|
||||
|
||||
public class UserModelDelegate implements UserModel {
|
||||
protected UserModel delegate;
|
||||
protected LDAPFederationProvider provider;
|
||||
|
||||
public LDAPUserModelDelegate(UserModel delegate, LDAPFederationProvider provider) {
|
||||
public UserModelDelegate(UserModel delegate) {
|
||||
this.delegate = delegate;
|
||||
this.provider = provider;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -40,13 +28,33 @@ public class LDAPUserModelDelegate implements UserModel {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void setAttribute(String name, String value) {
|
||||
delegate.setAttribute(name, value);
|
||||
public String getUsername() {
|
||||
return delegate.getUsername();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmailVerified() {
|
||||
return delegate.isEmailVerified();
|
||||
public void setUsername(String username) {
|
||||
delegate.setUsername(username);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return delegate.isEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTotp() {
|
||||
return delegate.isTotp();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnabled(boolean enabled) {
|
||||
delegate.setEnabled(enabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttribute(String name, String value) {
|
||||
delegate.setAttribute(name, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -54,14 +62,89 @@ public class LDAPUserModelDelegate implements UserModel {
|
|||
delegate.removeAttribute(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAttribute(String name) {
|
||||
return delegate.getAttribute(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getAttributes() {
|
||||
return delegate.getAttributes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<RequiredAction> getRequiredActions() {
|
||||
return delegate.getRequiredActions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addRequiredAction(RequiredAction action) {
|
||||
delegate.addRequiredAction(action);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeRequiredAction(RequiredAction action) {
|
||||
delegate.removeRequiredAction(action);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFirstName() {
|
||||
return delegate.getFirstName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFirstName(String firstName) {
|
||||
delegate.setFirstName(firstName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLastName() {
|
||||
return delegate.getLastName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFederationLink(String link) {
|
||||
delegate.setFederationLink(link);
|
||||
public void setLastName(String lastName) {
|
||||
delegate.setLastName(lastName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEmail() {
|
||||
return delegate.getEmail();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEmail(String email) {
|
||||
delegate.setEmail(email);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmailVerified() {
|
||||
return delegate.isEmailVerified();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEmailVerified(boolean verified) {
|
||||
delegate.setEmailVerified(verified);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTotp(boolean totp) {
|
||||
delegate.setTotp(totp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateCredential(UserCredentialModel cred) {
|
||||
delegate.updateCredential(cred);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserCredentialValueModel> getCredentialsDirectly() {
|
||||
return delegate.getCredentialsDirectly();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateCredentialDirectly(UserCredentialValueModel cred) {
|
||||
delegate.updateCredentialDirectly(cred);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -70,8 +153,18 @@ public class LDAPUserModelDelegate implements UserModel {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getAttributes() {
|
||||
return delegate.getAttributes();
|
||||
public void setAuthenticationLink(AuthenticationLinkModel authenticationLink) {
|
||||
delegate.setAuthenticationLink(authenticationLink);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<RoleModel> getRealmRoleMappings() {
|
||||
return delegate.getRealmRoleMappings();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<RoleModel> getApplicationRoleMappings(ApplicationModel app) {
|
||||
return delegate.getApplicationRoleMappings(app);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -85,13 +178,8 @@ public class LDAPUserModelDelegate implements UserModel {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void setEnabled(boolean enabled) {
|
||||
delegate.setEnabled(enabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeRequiredAction(UserModel.RequiredAction action) {
|
||||
delegate.removeRequiredAction(action);
|
||||
public Set<RoleModel> getRoleMappings() {
|
||||
return delegate.getRoleMappings();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -99,171 +187,13 @@ public class LDAPUserModelDelegate implements UserModel {
|
|||
delegate.deleteRoleMapping(role);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUsername(String username) {
|
||||
IdentityManager identityManager = provider.getIdentityManager();
|
||||
|
||||
try {
|
||||
User picketlinkUser = BasicModel.getUser(identityManager, delegate.getUsername());
|
||||
if (picketlinkUser == null) {
|
||||
throw new IllegalStateException("User not found in LDAP storage!");
|
||||
}
|
||||
picketlinkUser.setLoginName(username);
|
||||
identityManager.update(picketlinkUser);
|
||||
} catch (IdentityManagementException ie) {
|
||||
throw new ModelException(ie);
|
||||
}
|
||||
delegate.setUsername(username);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return delegate.isEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFirstName() {
|
||||
return delegate.getFirstName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLastName(String lastName) {
|
||||
IdentityManager identityManager = provider.getIdentityManager();
|
||||
|
||||
try {
|
||||
User picketlinkUser = BasicModel.getUser(identityManager, delegate.getUsername());
|
||||
if (picketlinkUser == null) {
|
||||
throw new IllegalStateException("User not found in LDAP storage!");
|
||||
}
|
||||
picketlinkUser.setLastName(lastName);
|
||||
identityManager.update(picketlinkUser);
|
||||
} catch (IdentityManagementException ie) {
|
||||
throw new ModelException(ie);
|
||||
}
|
||||
delegate.setLastName(lastName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEmailVerified(boolean verified) {
|
||||
delegate.setEmailVerified(verified);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateCredential(UserCredentialModel cred) {
|
||||
if (!provider.getSupportedCredentialTypes().contains(cred.getType())) {
|
||||
delegate.updateCredential(cred);
|
||||
return;
|
||||
}
|
||||
IdentityManager identityManager = provider.getIdentityManager();
|
||||
|
||||
try {
|
||||
User picketlinkUser = BasicModel.getUser(identityManager, getUsername());
|
||||
if (picketlinkUser == null) {
|
||||
logger.debugf("User '%s' doesn't exists. Skip password update", getUsername());
|
||||
throw new IllegalStateException("User doesn't exist in LDAP storage");
|
||||
}
|
||||
if (cred.getType().equals(UserCredentialModel.PASSWORD)) {
|
||||
identityManager.updateCredential(picketlinkUser, new Password(cred.getValue().toCharArray()));
|
||||
} else if (cred.getType().equals(UserCredentialModel.TOTP)) {
|
||||
TOTPCredential credential = new TOTPCredential(cred.getValue());
|
||||
credential.setDevice(cred.getDevice());
|
||||
identityManager.updateCredential(picketlinkUser, credential);
|
||||
}
|
||||
} catch (IdentityManagementException ie) {
|
||||
throw new ModelException(ie);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEmail(String email) {
|
||||
IdentityManager identityManager = provider.getIdentityManager();
|
||||
|
||||
try {
|
||||
User picketlinkUser = BasicModel.getUser(identityManager, delegate.getUsername());
|
||||
if (picketlinkUser == null) {
|
||||
throw new IllegalStateException("User not found in LDAP storage!");
|
||||
}
|
||||
picketlinkUser.setEmail(email);
|
||||
identityManager.update(picketlinkUser);
|
||||
} catch (IdentityManagementException ie) {
|
||||
throw new ModelException(ie);
|
||||
}
|
||||
delegate.setEmail(email);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addRequiredAction(UserModel.RequiredAction action) {
|
||||
delegate.addRequiredAction(action);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserCredentialValueModel> getCredentialsDirectly() {
|
||||
return delegate.getCredentialsDirectly();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTotp() {
|
||||
return delegate.isTotp();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFirstName(String firstName) {
|
||||
delegate.setFirstName(firstName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<UserModel.RequiredAction> getRequiredActions() {
|
||||
return delegate.getRequiredActions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEmail() {
|
||||
return delegate.getEmail();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTotp(boolean totp) {
|
||||
delegate.setTotp(totp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAuthenticationLink(AuthenticationLinkModel authenticationLink) {
|
||||
delegate.setAuthenticationLink(authenticationLink);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return delegate.getUsername();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFederationLink() {
|
||||
return delegate.getFederationLink();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<RoleModel> getRealmRoleMappings() {
|
||||
return delegate.getRealmRoleMappings();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<RoleModel> getRoleMappings() {
|
||||
return delegate.getRoleMappings();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<RoleModel> getApplicationRoleMappings(ApplicationModel app) {
|
||||
return delegate.getApplicationRoleMappings(app);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAttribute(String name) {
|
||||
return delegate.getAttribute(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateCredentialDirectly(UserCredentialValueModel cred) {
|
||||
delegate.updateCredentialDirectly(cred);
|
||||
public void setFederationLink(String link) {
|
||||
delegate.setFederationLink(link);
|
||||
}
|
||||
}
|
|
@ -67,7 +67,7 @@ public class DummyUserFederationProvider implements UserFederationProvider {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getSupportedCredentialTypes() {
|
||||
public Set<String> getSupportedCredentialTypes(UserModel user) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,8 @@ import org.junit.runners.MethodSorters;
|
|||
import org.keycloak.OAuth2Constants;
|
||||
import org.keycloak.federation.ldap.LDAPFederationProvider;
|
||||
import org.keycloak.federation.ldap.LDAPFederationProviderFactory;
|
||||
import org.keycloak.models.UserCredentialValueModel;
|
||||
import org.keycloak.models.UserFederationProvider;
|
||||
import org.keycloak.models.UserFederationProviderModel;
|
||||
import org.keycloak.testutils.LDAPEmbeddedServer;
|
||||
import org.keycloak.testsuite.LDAPTestUtils;
|
||||
|
@ -66,10 +68,11 @@ public class FederationProvidersIntegrationTest {
|
|||
String vendor = ldapServer.getVendor();
|
||||
ldapConfig.put(LDAPConstants.VENDOR, vendor);
|
||||
ldapConfig.put(LDAPFederationProvider.SYNC_REGISTRATIONS, "true");
|
||||
ldapConfig.put(LDAPFederationProvider.EDIT_MODE, UserFederationProvider.EditMode.WRITABLE.toString());
|
||||
|
||||
|
||||
|
||||
ldapModel = appRealm.addUserFederationProvider(LDAPFederationProviderFactory.PROVIDER_NAME, ldapConfig, 0, null);
|
||||
ldapModel = appRealm.addUserFederationProvider(LDAPFederationProviderFactory.PROVIDER_NAME, ldapConfig, 0, "test-ldap");
|
||||
|
||||
// Configure LDAP
|
||||
ldapRule.getEmbeddedServer().setupLdapInRealm(appRealm);
|
||||
|
@ -201,4 +204,76 @@ public class FederationProvidersIntegrationTest {
|
|||
Assert.assertEquals(user.getFederationLink(), ldapModel.getId());
|
||||
keycloakRule.stopSession(session, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadonly() {
|
||||
KeycloakSession session = keycloakRule.startSession();
|
||||
RealmModel appRealm = session.realms().getRealmByName("test");
|
||||
|
||||
UserFederationProviderModel model = new UserFederationProviderModel(ldapModel.getId(), ldapModel.getProviderName(), ldapModel.getConfig(), ldapModel.getPriority(), ldapModel.getDisplayName());
|
||||
model.getConfig().put(LDAPFederationProvider.EDIT_MODE, UserFederationProvider.EditMode.READ_ONLY.toString());
|
||||
appRealm.updateUserFederationProvider(model);
|
||||
UserModel user = session.users().getUserByUsername("johnkeycloak", appRealm);
|
||||
Assert.assertNotNull(user);
|
||||
Assert.assertNotNull(user.getFederationLink());
|
||||
Assert.assertEquals(user.getFederationLink(), ldapModel.getId());
|
||||
try {
|
||||
user.setEmail("error@error.com");
|
||||
Assert.fail("should fail");
|
||||
} catch (Exception e) {
|
||||
|
||||
}
|
||||
try {
|
||||
user.setLastName("Berk");
|
||||
Assert.fail("should fail");
|
||||
} catch (Exception e) {
|
||||
|
||||
}
|
||||
try {
|
||||
user.setFirstName("Bilbo");
|
||||
Assert.fail("should fail");
|
||||
} catch (Exception e) {
|
||||
|
||||
}
|
||||
try {
|
||||
UserCredentialModel cred = UserCredentialModel.password("poop");
|
||||
user.updateCredential(cred);
|
||||
Assert.fail("should fail");
|
||||
} catch (Exception e) {
|
||||
|
||||
}
|
||||
session.getTransaction().rollback();
|
||||
session.close();
|
||||
session = keycloakRule.startSession();
|
||||
appRealm = session.realms().getRealmByName("test");
|
||||
Assert.assertEquals(UserFederationProvider.EditMode.WRITABLE.toString(), appRealm.getUserFederationProviders().get(0).getConfig().get(LDAPFederationProvider.EDIT_MODE));
|
||||
keycloakRule.stopSession(session, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsynced() {
|
||||
KeycloakSession session = keycloakRule.startSession();
|
||||
RealmModel appRealm = session.realms().getRealmByName("test");
|
||||
|
||||
UserFederationProviderModel model = new UserFederationProviderModel(ldapModel.getId(), ldapModel.getProviderName(), ldapModel.getConfig(), ldapModel.getPriority(), ldapModel.getDisplayName());
|
||||
model.getConfig().put(LDAPFederationProvider.EDIT_MODE, UserFederationProvider.EditMode.UNSYNCED.toString());
|
||||
appRealm.updateUserFederationProvider(model);
|
||||
UserModel user = session.users().getUserByUsername("johnkeycloak", appRealm);
|
||||
Assert.assertNotNull(user);
|
||||
Assert.assertNotNull(user.getFederationLink());
|
||||
Assert.assertEquals(user.getFederationLink(), ldapModel.getId());
|
||||
|
||||
UserCredentialModel cred = UserCredentialModel.password("candy");
|
||||
user.updateCredential(cred);
|
||||
UserCredentialValueModel userCredentialValueModel = user.getCredentialsDirectly().get(0);
|
||||
Assert.assertEquals(UserCredentialModel.PASSWORD, userCredentialValueModel.getType());
|
||||
Assert.assertTrue(session.users().validCredentials(appRealm, user, cred));
|
||||
session.getTransaction().rollback();
|
||||
session.close();
|
||||
session = keycloakRule.startSession();
|
||||
appRealm = session.realms().getRealmByName("test");
|
||||
Assert.assertEquals(UserFederationProvider.EditMode.WRITABLE.toString(), appRealm.getUserFederationProviders().get(0).getConfig().get(LDAPFederationProvider.EDIT_MODE));
|
||||
keycloakRule.stopSession(session, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue