ldap edit mode

This commit is contained in:
Bill Burke 2014-07-31 17:28:48 -04:00
parent a084695978
commit 9f6c206078
10 changed files with 484 additions and 201 deletions

View file

@ -1,6 +1,7 @@
package org.keycloak.federation.ldap; package org.keycloak.federation.ldap;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.keycloak.models.UserCredentialValueModel;
import org.keycloak.models.UserFederationProvider; import org.keycloak.models.UserFederationProvider;
import org.keycloak.models.UserFederationProviderModel; import org.keycloak.models.UserFederationProviderModel;
import org.keycloak.models.KeycloakSession; 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.model.basic.User;
import org.picketlink.idm.query.IdentityQuery; import org.picketlink.idm.query.IdentityQuery;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedList; import java.util.LinkedList;
@ -35,10 +37,12 @@ public class LDAPFederationProvider implements UserFederationProvider {
private static final Logger logger = Logger.getLogger(LDAPFederationProvider.class); private static final Logger logger = Logger.getLogger(LDAPFederationProvider.class);
public static final String LDAP_ID = "LDAP_ID"; public static final String LDAP_ID = "LDAP_ID";
public static final String SYNC_REGISTRATIONS = "syncRegistrations"; public static final String SYNC_REGISTRATIONS = "syncRegistrations";
public static final String EDIT_MODE = "editMode";
protected KeycloakSession session; protected KeycloakSession session;
protected UserFederationProviderModel model; protected UserFederationProviderModel model;
protected PartitionManager partitionManager; protected PartitionManager partitionManager;
protected EditMode editMode;
protected static final Set<String> supportedCredentialTypes = new HashSet<String>(); protected static final Set<String> supportedCredentialTypes = new HashSet<String>();
@ -51,6 +55,9 @@ public class LDAPFederationProvider implements UserFederationProvider {
this.session = session; this.session = session;
this.model = model; this.model = model;
this.partitionManager = partitionManager; 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) { private ModelException convertIDMException(IdentityManagementException ie) {
@ -77,22 +84,37 @@ public class LDAPFederationProvider implements UserFederationProvider {
@Override @Override
public UserModel proxy(UserModel local) { public UserModel proxy(UserModel local) {
// todo switch (editMode) {
return new LDAPUserModelDelegate(local, this); 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 @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; return supportedCredentialTypes;
} }
@Override @Override
public boolean synchronizeRegistrations() { public boolean synchronizeRegistrations() {
return "true".equalsIgnoreCase(model.getConfig().get(SYNC_REGISTRATIONS)); return "true".equalsIgnoreCase(model.getConfig().get(SYNC_REGISTRATIONS)) && editMode == EditMode.WRITABLE;
} }
@Override @Override
public UserModel register(RealmModel realm, UserModel user) { 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"); if (!synchronizeRegistrations()) throw new IllegalStateException("Registration is not supported by this ldap server");
IdentityManager identityManager = getIdentityManager(); IdentityManager identityManager = getIdentityManager();
@ -112,6 +134,8 @@ public class LDAPFederationProvider implements UserFederationProvider {
@Override @Override
public boolean removeUser(RealmModel realm, UserModel user) { public boolean removeUser(RealmModel realm, UserModel user) {
if (editMode == EditMode.READ_ONLY || editMode == EditMode.UNSYNCED) return false;
IdentityManager identityManager = getIdentityManager(); IdentityManager identityManager = getIdentityManager();
try { try {

View file

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

View file

@ -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;
}
}

View file

@ -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);
}
}

View file

@ -33,6 +33,19 @@
<input class="form-control" id="priority" type="text" ng-model="instance.priority"> <input class="form-control" id="priority" type="text" ng-model="instance.priority">
</div> </div>
</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"> <div class="form-group clearfix block">
<label class="col-sm-2 control-label" for="syncRegistrations">Sync Registrations</label> <label class="col-sm-2 control-label" for="syncRegistrations">Sync Registrations</label>
<div class="col-sm-4"> <div class="col-sm-4">

View file

@ -307,7 +307,7 @@ public class UserFederationManager implements UserProvider {
UserFederationProvider link = getFederationLink(realm, user); UserFederationProvider link = getFederationLink(realm, user);
if (link != null) { if (link != null) {
validateUser(realm, user); validateUser(realm, user);
if (link.getSupportedCredentialTypes().size() > 0) { if (link.getSupportedCredentialTypes(user).size() > 0) {
List<UserCredentialModel> fedCreds = new ArrayList<UserCredentialModel>(); List<UserCredentialModel> fedCreds = new ArrayList<UserCredentialModel>();
List<UserCredentialModel> localCreds = new ArrayList<UserCredentialModel>(); List<UserCredentialModel> localCreds = new ArrayList<UserCredentialModel>();
for (UserCredentialModel cred : input) { for (UserCredentialModel cred : input) {
@ -331,7 +331,7 @@ public class UserFederationManager implements UserProvider {
UserFederationProvider link = getFederationLink(realm, user); UserFederationProvider link = getFederationLink(realm, user);
if (link != null) { if (link != null) {
validateUser(realm, user); validateUser(realm, user);
Set<String> supportedCredentialTypes = link.getSupportedCredentialTypes(); Set<String> supportedCredentialTypes = link.getSupportedCredentialTypes(user);
if (supportedCredentialTypes.size() > 0) { if (supportedCredentialTypes.size() > 0) {
List<UserCredentialModel> fedCreds = new ArrayList<UserCredentialModel>(); List<UserCredentialModel> fedCreds = new ArrayList<UserCredentialModel>();
List<UserCredentialModel> localCreds = new ArrayList<UserCredentialModel>(); List<UserCredentialModel> localCreds = new ArrayList<UserCredentialModel>();

View file

@ -19,6 +19,28 @@ public interface UserFederationProvider extends Provider {
public static final String FIRST_NAME = UserModel.EMAIL; public static final String FIRST_NAME = UserModel.EMAIL;
public static final String LAST_NAME = UserModel.LAST_NAME; 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. * Gives the provider an option to proxy UserModels loaded from local storage.
* This method is called whenever a UserModel is pulled 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); 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. * validCredentials() with the credential types specified in this method.
* *
* @return * @return
*/ */
Set<String> getSupportedCredentialTypes(); Set<String> getSupportedCredentialTypes(UserModel user);
/** /**
* Validate credentials for this 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, List<UserCredentialModel> input);
boolean validCredentials(RealmModel realm, UserModel user, UserCredentialModel... input); boolean validCredentials(RealmModel realm, UserModel user, UserCredentialModel... input);
void close();} void close();
}

View file

@ -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.ApplicationModel;
import org.keycloak.models.AuthenticationLinkModel; import org.keycloak.models.AuthenticationLinkModel;
import org.keycloak.models.ModelException;
import org.keycloak.models.RoleModel; import org.keycloak.models.RoleModel;
import org.keycloak.models.UserCredentialModel; import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserCredentialValueModel; import org.keycloak.models.UserCredentialValueModel;
import org.keycloak.models.UserModel; 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.List;
import java.util.Map; import java.util.Map;
@ -23,15 +15,11 @@ 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 LDAPUserModelDelegate implements UserModel { public class UserModelDelegate implements UserModel {
private static final Logger logger = Logger.getLogger(LDAPUserModelDelegate.class);
protected UserModel delegate; protected UserModel delegate;
protected LDAPFederationProvider provider;
public LDAPUserModelDelegate(UserModel delegate, LDAPFederationProvider provider) { public UserModelDelegate(UserModel delegate) {
this.delegate = delegate; this.delegate = delegate;
this.provider = provider;
} }
@Override @Override
@ -40,13 +28,33 @@ public class LDAPUserModelDelegate implements UserModel {
} }
@Override @Override
public void setAttribute(String name, String value) { public String getUsername() {
delegate.setAttribute(name, value); return delegate.getUsername();
} }
@Override @Override
public boolean isEmailVerified() { public void setUsername(String username) {
return delegate.isEmailVerified(); 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 @Override
@ -54,14 +62,89 @@ public class LDAPUserModelDelegate implements UserModel {
delegate.removeAttribute(name); 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 @Override
public String getLastName() { public String getLastName() {
return delegate.getLastName(); return delegate.getLastName();
} }
@Override @Override
public void setFederationLink(String link) { public void setLastName(String lastName) {
delegate.setFederationLink(link); 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 @Override
@ -70,8 +153,18 @@ public class LDAPUserModelDelegate implements UserModel {
} }
@Override @Override
public Map<String, String> getAttributes() { public void setAuthenticationLink(AuthenticationLinkModel authenticationLink) {
return delegate.getAttributes(); delegate.setAuthenticationLink(authenticationLink);
}
@Override
public Set<RoleModel> getRealmRoleMappings() {
return delegate.getRealmRoleMappings();
}
@Override
public Set<RoleModel> getApplicationRoleMappings(ApplicationModel app) {
return delegate.getApplicationRoleMappings(app);
} }
@Override @Override
@ -85,13 +178,8 @@ public class LDAPUserModelDelegate implements UserModel {
} }
@Override @Override
public void setEnabled(boolean enabled) { public Set<RoleModel> getRoleMappings() {
delegate.setEnabled(enabled); return delegate.getRoleMappings();
}
@Override
public void removeRequiredAction(UserModel.RequiredAction action) {
delegate.removeRequiredAction(action);
} }
@Override @Override
@ -99,171 +187,13 @@ public class LDAPUserModelDelegate implements UserModel {
delegate.deleteRoleMapping(role); 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 @Override
public String getFederationLink() { public String getFederationLink() {
return delegate.getFederationLink(); return delegate.getFederationLink();
} }
@Override @Override
public Set<RoleModel> getRealmRoleMappings() { public void setFederationLink(String link) {
return delegate.getRealmRoleMappings(); delegate.setFederationLink(link);
}
@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);
} }
} }

View file

@ -67,7 +67,7 @@ public class DummyUserFederationProvider implements UserFederationProvider {
} }
@Override @Override
public Set<String> getSupportedCredentialTypes() { public Set<String> getSupportedCredentialTypes(UserModel user) {
return Collections.emptySet(); return Collections.emptySet();
} }

View file

@ -12,6 +12,8 @@ import org.junit.runners.MethodSorters;
import org.keycloak.OAuth2Constants; import org.keycloak.OAuth2Constants;
import org.keycloak.federation.ldap.LDAPFederationProvider; import org.keycloak.federation.ldap.LDAPFederationProvider;
import org.keycloak.federation.ldap.LDAPFederationProviderFactory; import org.keycloak.federation.ldap.LDAPFederationProviderFactory;
import org.keycloak.models.UserCredentialValueModel;
import org.keycloak.models.UserFederationProvider;
import org.keycloak.models.UserFederationProviderModel; import org.keycloak.models.UserFederationProviderModel;
import org.keycloak.testutils.LDAPEmbeddedServer; import org.keycloak.testutils.LDAPEmbeddedServer;
import org.keycloak.testsuite.LDAPTestUtils; import org.keycloak.testsuite.LDAPTestUtils;
@ -66,10 +68,11 @@ public class FederationProvidersIntegrationTest {
String vendor = ldapServer.getVendor(); String vendor = ldapServer.getVendor();
ldapConfig.put(LDAPConstants.VENDOR, vendor); ldapConfig.put(LDAPConstants.VENDOR, vendor);
ldapConfig.put(LDAPFederationProvider.SYNC_REGISTRATIONS, "true"); 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 // Configure LDAP
ldapRule.getEmbeddedServer().setupLdapInRealm(appRealm); ldapRule.getEmbeddedServer().setupLdapInRealm(appRealm);
@ -201,4 +204,76 @@ public class FederationProvidersIntegrationTest {
Assert.assertEquals(user.getFederationLink(), ldapModel.getId()); Assert.assertEquals(user.getFederationLink(), ldapModel.getId());
keycloakRule.stopSession(session, false); 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);
}
} }