KEYCLOAK-19056 EDIT MODE field should not be leave empty (#8380)
This commit is contained in:
parent
6d0708d263
commit
11e5f66c60
7 changed files with 62 additions and 9 deletions
|
@ -654,8 +654,8 @@ public class LDAPStorageProvider implements UserStorageProvider,
|
||||||
String password = input.getChallengeResponse();
|
String password = input.getChallengeResponse();
|
||||||
LDAPObject ldapUser = loadAndValidateUser(realm, user);
|
LDAPObject ldapUser = loadAndValidateUser(realm, user);
|
||||||
if (ldapIdentityStore.getConfig().isValidatePasswordPolicy()) {
|
if (ldapIdentityStore.getConfig().isValidatePasswordPolicy()) {
|
||||||
PolicyError error = session.getProvider(PasswordPolicyManagerProvider.class).validate(realm, user, password);
|
PolicyError error = session.getProvider(PasswordPolicyManagerProvider.class).validate(realm, user, password);
|
||||||
if (error != null) throw new ModelException(error.getMessage(), error.getParameters());
|
if (error != null) throw new ModelException(error.getMessage(), error.getParameters());
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
LDAPOperationDecorator operationDecorator = null;
|
LDAPOperationDecorator operationDecorator = null;
|
||||||
|
|
|
@ -281,6 +281,18 @@ public class LDAPStorageProviderFactory implements UserStorageProviderFactory<LD
|
||||||
throw new ComponentValidationException("ldapErrorCantEnableStartTlsAndConnectionPooling");
|
throw new ComponentValidationException("ldapErrorCantEnableStartTlsAndConnectionPooling");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// editMode is mandatory
|
||||||
|
if (config.get(LDAPConstants.EDIT_MODE) == null) {
|
||||||
|
throw new ComponentValidationException("ldapErrorEditModeMandatory");
|
||||||
|
}
|
||||||
|
|
||||||
|
// validatePasswordPolicy applicable only for WRITABLE mode
|
||||||
|
if (cfg.getEditMode() != UserStorageProvider.EditMode.WRITABLE) {
|
||||||
|
if (cfg.isValidatePasswordPolicy()) {
|
||||||
|
throw new ComponentValidationException("ldapErrorValidatePasswordPolicyAvailableForWritableOnly");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!userStorageModel.isImportEnabled() && cfg.getEditMode() == UserStorageProvider.EditMode.UNSYNCED) {
|
if (!userStorageModel.isImportEnabled() && cfg.getEditMode() == UserStorageProvider.EditMode.UNSYNCED) {
|
||||||
throw new ComponentValidationException("ldapErrorCantEnableUnsyncedAndImportOff");
|
throw new ComponentValidationException("ldapErrorCantEnableUnsyncedAndImportOff");
|
||||||
}
|
}
|
||||||
|
|
|
@ -233,7 +233,7 @@ public class UserStorageRestTest extends AbstractAdminTest {
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testValidateAndCreateLdapProvider() {
|
public void testValidateAndCreateLdapProviderCustomSearchFilter() {
|
||||||
// Invalid filter
|
// Invalid filter
|
||||||
|
|
||||||
ComponentRepresentation ldapRep = createBasicLDAPProviderRep();
|
ComponentRepresentation ldapRep = createBasicLDAPProviderRep();
|
||||||
|
@ -271,6 +271,7 @@ public class UserStorageRestTest extends AbstractAdminTest {
|
||||||
ldapRep2.setProviderType(UserStorageProvider.class.getName());
|
ldapRep2.setProviderType(UserStorageProvider.class.getName());
|
||||||
ldapRep2.setConfig(new MultivaluedHashMap<>());
|
ldapRep2.setConfig(new MultivaluedHashMap<>());
|
||||||
ldapRep2.getConfig().putSingle("priority", Integer.toString(2));
|
ldapRep2.getConfig().putSingle("priority", Integer.toString(2));
|
||||||
|
ldapRep2.getConfig().putSingle(LDAPConstants.EDIT_MODE, UserStorageProvider.EditMode.UNSYNCED.name());
|
||||||
ldapRep2.getConfig().putSingle(LDAPConstants.BIND_DN, "cn=manager");
|
ldapRep2.getConfig().putSingle(LDAPConstants.BIND_DN, "cn=manager");
|
||||||
ldapRep2.getConfig().putSingle(LDAPConstants.BIND_CREDENTIAL, "password");
|
ldapRep2.getConfig().putSingle(LDAPConstants.BIND_CREDENTIAL, "password");
|
||||||
String id2 = createComponent(ldapRep2);
|
String id2 = createComponent(ldapRep2);
|
||||||
|
@ -284,6 +285,40 @@ public class UserStorageRestTest extends AbstractAdminTest {
|
||||||
removeComponent(id2);
|
removeComponent(id2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateAndCreateLdapProviderEditMode() {
|
||||||
|
// Test provider without editMode should fail
|
||||||
|
ComponentRepresentation ldapRep = createBasicLDAPProviderRep();
|
||||||
|
ldapRep.getConfig().remove(LDAPConstants.EDIT_MODE);
|
||||||
|
|
||||||
|
Response resp = realm.components().add(ldapRep);
|
||||||
|
Assert.assertEquals(400, resp.getStatus());
|
||||||
|
resp.close();
|
||||||
|
|
||||||
|
// Test provider with READ_ONLY edit mode and validatePasswordPolicy will fail
|
||||||
|
ldapRep = createBasicLDAPProviderRep();
|
||||||
|
ldapRep.getConfig().putSingle(LDAPConstants.EDIT_MODE, UserStorageProvider.EditMode.READ_ONLY.name());
|
||||||
|
ldapRep.getConfig().putSingle(LDAPConstants.VALIDATE_PASSWORD_POLICY, "true");
|
||||||
|
resp = realm.components().add(ldapRep);
|
||||||
|
Assert.assertEquals(400, resp.getStatus());
|
||||||
|
resp.close();
|
||||||
|
|
||||||
|
// Test provider with UNSYNCED edit mode and validatePasswordPolicy will fail
|
||||||
|
ldapRep.getConfig().putSingle(LDAPConstants.EDIT_MODE, UserStorageProvider.EditMode.UNSYNCED.name());
|
||||||
|
ldapRep.getConfig().putSingle(LDAPConstants.VALIDATE_PASSWORD_POLICY, "true");
|
||||||
|
resp = realm.components().add(ldapRep);
|
||||||
|
Assert.assertEquals(400, resp.getStatus());
|
||||||
|
resp.close();
|
||||||
|
|
||||||
|
// Test provider with WRITABLE edit mode and validatePasswordPolicy will fail
|
||||||
|
ldapRep.getConfig().putSingle(LDAPConstants.EDIT_MODE, UserStorageProvider.EditMode.WRITABLE.name());
|
||||||
|
ldapRep.getConfig().putSingle(LDAPConstants.SYNC_REGISTRATIONS, "true");
|
||||||
|
String id1 = createComponent(ldapRep);
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
removeComponent(id1);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUpdateProvider() {
|
public void testUpdateProvider() {
|
||||||
ComponentRepresentation ldapRep = createBasicLDAPProviderRep();
|
ComponentRepresentation ldapRep = createBasicLDAPProviderRep();
|
||||||
|
@ -392,6 +427,7 @@ public class UserStorageRestTest extends AbstractAdminTest {
|
||||||
ldapRep.setProviderType(UserStorageProvider.class.getName());
|
ldapRep.setProviderType(UserStorageProvider.class.getName());
|
||||||
ldapRep.setConfig(new MultivaluedHashMap<>());
|
ldapRep.setConfig(new MultivaluedHashMap<>());
|
||||||
ldapRep.getConfig().putSingle("priority", Integer.toString(2));
|
ldapRep.getConfig().putSingle("priority", Integer.toString(2));
|
||||||
|
ldapRep.getConfig().putSingle(LDAPConstants.EDIT_MODE, UserStorageProvider.EditMode.WRITABLE.name());
|
||||||
return ldapRep;
|
return ldapRep;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,8 @@
|
||||||
"providerName": "ldap",
|
"providerName": "ldap",
|
||||||
"priority": 1,
|
"priority": 1,
|
||||||
"config": {
|
"config": {
|
||||||
"connectionUrl": "ldap://foo"
|
"connectionUrl": "ldap://foo",
|
||||||
|
"editMode": "WRITABLE"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -64,7 +65,8 @@
|
||||||
"providerName": "ldap",
|
"providerName": "ldap",
|
||||||
"priority": 2,
|
"priority": 2,
|
||||||
"config": {
|
"config": {
|
||||||
"connectionUrl": "ldap://bar"
|
"connectionUrl": "ldap://bar",
|
||||||
|
"editMode": "WRITABLE"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
|
@ -1184,7 +1184,7 @@ ldap.edit-mode.tooltip=READ_ONLY is a read-only LDAP store. WRITABLE means data
|
||||||
update-profile-first-login=Update Profile First Login
|
update-profile-first-login=Update Profile First Login
|
||||||
update-profile-first-login.tooltip=Update profile on first login
|
update-profile-first-login.tooltip=Update profile on first login
|
||||||
sync-registrations=Sync Registrations
|
sync-registrations=Sync Registrations
|
||||||
ldap.sync-registrations.tooltip=Should newly created users be created within LDAP store? Priority effects which provider is chosen to sync the new user.
|
ldap.sync-registrations.tooltip=Should newly created users be created within LDAP store? Priority effects which provider is chosen to sync the new user. This setting is effectively appplied only with WRITABLE edit mode.
|
||||||
import-enabled=Import Users
|
import-enabled=Import Users
|
||||||
ldap.import-enabled.tooltip=If true, LDAP users will be imported into Keycloak DB and synced by the configured sync policies.
|
ldap.import-enabled.tooltip=If true, LDAP users will be imported into Keycloak DB and synced by the configured sync policies.
|
||||||
vendor=Vendor
|
vendor=Vendor
|
||||||
|
@ -1247,7 +1247,7 @@ ldap-connection-timeout=Connection Timeout
|
||||||
ldap.connection-timeout.tooltip=LDAP Connection Timeout in milliseconds
|
ldap.connection-timeout.tooltip=LDAP Connection Timeout in milliseconds
|
||||||
ldap-read-timeout=Read Timeout
|
ldap-read-timeout=Read Timeout
|
||||||
ldap.read-timeout.tooltip=LDAP Read Timeout in milliseconds. This timeout applies for LDAP read operations
|
ldap.read-timeout.tooltip=LDAP Read Timeout in milliseconds. This timeout applies for LDAP read operations
|
||||||
ldap.validate-password-policy.tooltip=Determines if Keycloak should validate the password with the realm password policy before updating it
|
ldap.validate-password-policy.tooltip=Determines if Keycloak should validate the password with the realm password policy before updating the LDAP mapped user. When this is false, Keycloak password policy would not be applied, which means that password will be updated on LDAP server unless LDAP server itself has some password policy rules. This setting is possible only with WRITABLE edit mode.
|
||||||
ldap.connection-pooling.tooltip=Determines if Keycloak should use connection pooling for accessing LDAP server
|
ldap.connection-pooling.tooltip=Determines if Keycloak should use connection pooling for accessing LDAP server
|
||||||
ldap.connection-pooling.authentication.tooltip=A list of space-separated authentication types of connections that may be pooled. Valid types are "none", "simple", and "DIGEST-MD5".
|
ldap.connection-pooling.authentication.tooltip=A list of space-separated authentication types of connections that may be pooled. Valid types are "none", "simple", and "DIGEST-MD5".
|
||||||
ldap.connection-pooling.debug.tooltip=A string that indicates the level of debug output to produce. Valid values are "fine" (trace connection creation and removal) and "all" (all debugging information).
|
ldap.connection-pooling.debug.tooltip=A string that indicates the level of debug output to produce. Valid values are "fine" (trace connection creation and removal) and "all" (all debugging information).
|
||||||
|
|
|
@ -11,6 +11,7 @@ invalidPasswordHistoryMessage=Invalid password: must not be equal to any of last
|
||||||
invalidPasswordBlacklistedMessage=Invalid password: password is blacklisted.
|
invalidPasswordBlacklistedMessage=Invalid password: password is blacklisted.
|
||||||
invalidPasswordGenericMessage=Invalid password: new password does not match password policies.
|
invalidPasswordGenericMessage=Invalid password: new password does not match password policies.
|
||||||
|
|
||||||
|
ldapErrorEditModeMandatory=Edit Mode is mandatory
|
||||||
ldapErrorInvalidCustomFilter=Custom configured LDAP filter does not start with "(" or does not end with ")".
|
ldapErrorInvalidCustomFilter=Custom configured LDAP filter does not start with "(" or does not end with ")".
|
||||||
ldapErrorConnectionTimeoutNotNumber=Connection Timeout must be a number
|
ldapErrorConnectionTimeoutNotNumber=Connection Timeout must be a number
|
||||||
ldapErrorReadTimeoutNotNumber=Read Timeout must be a number
|
ldapErrorReadTimeoutNotNumber=Read Timeout must be a number
|
||||||
|
@ -21,6 +22,7 @@ ldapErrorCantWriteOnlyAndReadOnly=Can not set write-only and read-only together
|
||||||
ldapErrorCantEnableStartTlsAndConnectionPooling=Can not enable both StartTLS and connection pooling.
|
ldapErrorCantEnableStartTlsAndConnectionPooling=Can not enable both StartTLS and connection pooling.
|
||||||
ldapErrorCantEnableUnsyncedAndImportOff=Can not disable Importing users when LDAP provider mode is UNSYNCED
|
ldapErrorCantEnableUnsyncedAndImportOff=Can not disable Importing users when LDAP provider mode is UNSYNCED
|
||||||
ldapErrorMissingGroupsPathGroup=Groups path group does not exist - please create the group on specified path first
|
ldapErrorMissingGroupsPathGroup=Groups path group does not exist - please create the group on specified path first
|
||||||
|
ldapErrorValidatePasswordPolicyAvailableForWritableOnly=Validate Password Policy is applicable only with WRITABLE edit mode
|
||||||
|
|
||||||
clientRedirectURIsFragmentError=Redirect URIs must not contain an URI fragment
|
clientRedirectURIsFragmentError=Redirect URIs must not contain an URI fragment
|
||||||
clientRootURLFragmentError=Root URL must not contain an URL fragment
|
clientRootURLFragmentError=Root URL must not contain an URL fragment
|
||||||
|
|
|
@ -46,11 +46,12 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="col-md-2 control-label" for="editMode">{{:: 'edit-mode' | translate}}</label>
|
<label class="col-md-2 control-label" for="editMode"><span class="required">*</span> {{:: 'edit-mode' | translate}}</label>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<div>
|
<div>
|
||||||
<select class="form-control" id="editMode"
|
<select class="form-control" id="editMode"
|
||||||
ng-model="instance.config['editMode'][0]">
|
ng-model="instance.config['editMode'][0]"
|
||||||
|
required>
|
||||||
<option>READ_ONLY</option>
|
<option>READ_ONLY</option>
|
||||||
<option>WRITABLE</option>
|
<option>WRITABLE</option>
|
||||||
<option>UNSYNCED</option>
|
<option>UNSYNCED</option>
|
||||||
|
|
Loading…
Reference in a new issue