keycloak-memoizeit
Changes
forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/realm.js 32(+30 -2)
picketlink/keycloak-picketlink-realm/src/main/java/org/keycloak/picketlink/idm/KeycloakLDAPIdentityStore.java 2(+0 -2)
picketlink/keycloak-picketlink-realm/src/main/java/org/keycloak/picketlink/idm/LDAPKeycloakCredentialHandler.java 2(+1 -1)
Details
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/app.js b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/app.js
index 8053a5c..bf1f0fc 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/app.js
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/app.js
@@ -168,7 +168,7 @@ module.config([ '$routeProvider', function($routeProvider) {
return RealmLoader();
}
},
- controller : 'RealmLdapSettingsCtrl'
+ controller : 'RealmLDAPSettingsCtrl'
})
.when('/realms/:realm/audit', {
templateUrl : 'partials/realm-audit.html',
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/realm.js b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/realm.js
index 270b65f..392e726 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/realm.js
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/realm.js
@@ -896,8 +896,8 @@ module.controller('RealmSMTPSettingsCtrl', function($scope, Current, Realm, real
}
});
-module.controller('RealmLdapSettingsCtrl', function($scope, $location, Notifications, Realm, realm) {
- console.log('RealmLdapSettingsCtrl');
+module.controller('RealmLDAPSettingsCtrl', function($scope, $location, Notifications, Realm, realm, RealmLDAPConnectionTester) {
+ console.log('RealmLDAPSettingsCtrl');
$scope.ldapVendors = [
{ "id": "ad", "name": "Active Directory" },
@@ -943,6 +943,34 @@ module.controller('RealmLdapSettingsCtrl', function($scope, $location, Notificat
$scope.changed = false;
$scope.lastVendor = $scope.realm.ldapServer.vendor;
};
+
+ var initConnectionTest = function(testAction, ldapConfig) {
+ return {
+ action: testAction,
+ realm: $scope.realm.realm,
+ connectionUrl: ldapConfig.connectionUrl,
+ bindDn: ldapConfig.bindDn,
+ bindCredential: ldapConfig.bindCredential
+ };
+ };
+
+ $scope.testConnection = function() {
+ console.log('RealmLDAPSettingsCtrl: testConnection');
+ RealmLDAPConnectionTester.get(initConnectionTest("testConnection", $scope.realm.ldapServer), function() {
+ Notifications.success("LDAP connection successful.");
+ }, function() {
+ Notifications.error("Error when trying to connect to LDAP. See server.log for details.");
+ });
+ }
+
+ $scope.testAuthentication = function() {
+ console.log('RealmLDAPSettingsCtrl: testAuthentication');
+ RealmLDAPConnectionTester.get(initConnectionTest("testAuthentication", $scope.realm.ldapServer), function() {
+ Notifications.success("LDAP authentication successful.");
+ }, function() {
+ Notifications.error("LDAP authentication failed. See server.log for details");
+ });
+ }
});
module.controller('RealmAuthSettingsCtrl', function($scope, realm) {
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/services.js b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/services.js
index b88c6b9..415734a 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/services.js
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/services.js
@@ -180,6 +180,10 @@ module.factory('RealmAuditEvents', function($resource) {
});
});
+module.factory('RealmLDAPConnectionTester', function($resource) {
+ return $resource(authUrl + '/admin/realms/:realm/testLDAPConnection');
+});
+
module.factory('ServerInfo', function($resource) {
return $resource(authUrl + '/admin/serverinfo');
});
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-ldap.html b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-ldap.html
index 1a657fe..6cbf269 100644
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-ldap.html
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-ldap.html
@@ -40,6 +40,9 @@
<div class="col-sm-4">
<input class="form-control" id="ldapConnectionUrl" type="text" ng-model="realm.ldapServer.connectionUrl" placeholder="LDAP connection URL" required>
</div>
+ <div class="col-sm-4" data-ng-show="access.manageRealm">
+ <a class="btn btn-primary" data-ng-click="testConnection()">Test connection</a>
+ </div>
</div>
<div class="form-group clearfix">
<label class="col-sm-2 control-label" for="ldapBaseDn">Base DN <span class="required">*</span></label>
@@ -64,6 +67,9 @@
<div class="col-sm-4">
<input class="form-control" id="ldapBindCredential" type="text" ng-model="realm.ldapServer.bindCredential" placeholder="LDAP Bind Credentials" required>
</div>
+ <div class="col-sm-4" data-ng-show="access.manageRealm">
+ <a class="btn btn-primary" data-ng-click="testAuthentication()">Test authentication</a>
+ </div>
</div>
</fieldset>
diff --git a/model/tests/src/main/java/org/keycloak/model/test/LDAPEmbeddedServer.java b/model/tests/src/main/java/org/keycloak/model/test/LDAPEmbeddedServer.java
index 70c149f..354bc86 100644
--- a/model/tests/src/main/java/org/keycloak/model/test/LDAPEmbeddedServer.java
+++ b/model/tests/src/main/java/org/keycloak/model/test/LDAPEmbeddedServer.java
@@ -17,8 +17,8 @@ import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
+import org.keycloak.models.LDAPConstants;
import org.keycloak.models.RealmModel;
-import org.keycloak.picketlink.idm.LdapConstants;
import org.picketbox.test.ldap.AbstractLDAPTest;
/**
@@ -130,12 +130,12 @@ public class LDAPEmbeddedServer extends AbstractLDAPTest {
public void setupLdapInRealm(RealmModel realm) {
Map<String,String> ldapConfig = new HashMap<String,String>();
- ldapConfig.put(LdapConstants.CONNECTION_URL, getConnectionUrl());
- ldapConfig.put(LdapConstants.BASE_DN, getBaseDn());
- ldapConfig.put(LdapConstants.BIND_DN, getBindDn());
- ldapConfig.put(LdapConstants.BIND_CREDENTIAL, getBindCredential());
- ldapConfig.put(LdapConstants.USER_DN_SUFFIX, getUserDnSuffix());
- ldapConfig.put(LdapConstants.VENDOR, getVendor());
+ ldapConfig.put(LDAPConstants.CONNECTION_URL, getConnectionUrl());
+ ldapConfig.put(LDAPConstants.BASE_DN, getBaseDn());
+ ldapConfig.put(LDAPConstants.BIND_DN, getBindDn());
+ ldapConfig.put(LDAPConstants.BIND_CREDENTIAL, getBindCredential());
+ ldapConfig.put(LDAPConstants.USER_DN_SUFFIX, getUserDnSuffix());
+ ldapConfig.put(LDAPConstants.VENDOR, getVendor());
realm.setLdapServerConfig(ldapConfig);
}
diff --git a/model/tests/src/test/java/org/keycloak/model/test/AuthProvidersLDAPTest.java b/model/tests/src/test/java/org/keycloak/model/test/AuthProvidersLDAPTest.java
index 155b235..a59a12a 100755
--- a/model/tests/src/test/java/org/keycloak/model/test/AuthProvidersLDAPTest.java
+++ b/model/tests/src/test/java/org/keycloak/model/test/AuthProvidersLDAPTest.java
@@ -5,8 +5,6 @@ import java.util.Collections;
import javax.ws.rs.core.MultivaluedMap;
-import org.jboss.resteasy.spi.ResteasyProviderFactory;
-import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
@@ -78,7 +76,7 @@ public class AuthProvidersLDAPTest extends AbstractModelTest {
MultivaluedMap<String, String> formData = AuthProvidersExternalModelTest.createFormData("johnkeycloak", "password");
// Set password of user in LDAP
- LdapTestUtils.setLdapPassword(providerSession, realm, "johnkeycloak", "password");
+ LDAPTestUtils.setLdapPassword(providerSession, realm, "johnkeycloak", "password");
// Verify that user doesn't exists in realm2 and can't authenticate here
Assert.assertEquals(AuthenticationManager.AuthenticationStatus.INVALID_USER, am.authenticateForm(null, realm, formData));
@@ -142,7 +140,7 @@ public class AuthProvidersLDAPTest extends AbstractModelTest {
// Add ldap
setupAuthenticationProviders();
- LdapTestUtils.setLdapPassword(providerSession, realm, "johnkeycloak", "password");
+ LDAPTestUtils.setLdapPassword(providerSession, realm, "johnkeycloak", "password");
// First authenticate successfully to sync john into realm
MultivaluedMap<String, String> formData = AuthProvidersExternalModelTest.createFormData("johnkeycloak", "password");
diff --git a/picketlink/keycloak-picketlink-realm/src/main/java/org/keycloak/picketlink/idm/KeycloakLDAPIdentityStore.java b/picketlink/keycloak-picketlink-realm/src/main/java/org/keycloak/picketlink/idm/KeycloakLDAPIdentityStore.java
index 8296854..124bb82 100644
--- a/picketlink/keycloak-picketlink-realm/src/main/java/org/keycloak/picketlink/idm/KeycloakLDAPIdentityStore.java
+++ b/picketlink/keycloak-picketlink-realm/src/main/java/org/keycloak/picketlink/idm/KeycloakLDAPIdentityStore.java
@@ -22,7 +22,6 @@ import static org.picketlink.common.constants.LDAPConstants.EQUAL;
*/
public class KeycloakLDAPIdentityStore extends LDAPIdentityStore {
- public static Method GET_BINDING_DN_METHOD;
public static Method GET_OPERATION_MANAGER_METHOD;
public static Method CREATE_SEARCH_FILTER_METHOD;
public static Method EXTRACT_ATTRIBUTES_METHOD;
@@ -31,7 +30,6 @@ public class KeycloakLDAPIdentityStore extends LDAPIdentityStore {
public static final String SAM_ACCOUNT_NAME = "sAMAccountName";
static {
- GET_BINDING_DN_METHOD = getMethodOnLDAPStore("getBindingDN", AttributedType.class);
GET_OPERATION_MANAGER_METHOD = getMethodOnLDAPStore("getOperationManager");
CREATE_SEARCH_FILTER_METHOD = getMethodOnLDAPStore("createIdentityTypeSearchFilter", IdentityQuery.class, LDAPMappingConfiguration.class);
EXTRACT_ATTRIBUTES_METHOD = getMethodOnLDAPStore("extractAttributes", AttributedType.class, boolean.class);
diff --git a/picketlink/keycloak-picketlink-realm/src/main/java/org/keycloak/picketlink/idm/LDAPKeycloakCredentialHandler.java b/picketlink/keycloak-picketlink-realm/src/main/java/org/keycloak/picketlink/idm/LDAPKeycloakCredentialHandler.java
index 38827e7..6f13dac 100644
--- a/picketlink/keycloak-picketlink-realm/src/main/java/org/keycloak/picketlink/idm/LDAPKeycloakCredentialHandler.java
+++ b/picketlink/keycloak-picketlink-realm/src/main/java/org/keycloak/picketlink/idm/LDAPKeycloakCredentialHandler.java
@@ -143,7 +143,7 @@ public class LDAPKeycloakCredentialHandler extends LDAPPlainTextPasswordCredenti
}
}
- // TODO: remove later... It's needed just because LDAPIdentityStore.getBindingName, which always uses idProperty as first part of DN, but in AD it doesn't work as we may have idProperty 'sAMAccountName'
+ // TODO: remove later... It's needed just because LDAPIdentityStore.getBindingDN, which always uses idProperty as first part of DN, but in AD it doesn't work as we may have idProperty 'sAMAccountName'
// but DN like: cn=John Doe,OU=foo,DC=bar
protected String getDNOfUser(User user, IdentityManager identityManager, LDAPIdentityStore ldapStore, LDAPOperationManager operationManager) {
diff --git a/picketlink/keycloak-picketlink-realm/src/main/java/org/keycloak/picketlink/realm/PartitionManagerRegistry.java b/picketlink/keycloak-picketlink-realm/src/main/java/org/keycloak/picketlink/realm/PartitionManagerRegistry.java
index fb40f84..84a62c2 100644
--- a/picketlink/keycloak-picketlink-realm/src/main/java/org/keycloak/picketlink/realm/PartitionManagerRegistry.java
+++ b/picketlink/keycloak-picketlink-realm/src/main/java/org/keycloak/picketlink/realm/PartitionManagerRegistry.java
@@ -6,10 +6,10 @@ import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import org.jboss.logging.Logger;
+import org.keycloak.models.LDAPConstants;
import org.keycloak.models.RealmModel;
import org.keycloak.picketlink.idm.KeycloakLDAPIdentityStore;
import org.keycloak.picketlink.idm.LDAPKeycloakCredentialHandler;
-import org.keycloak.picketlink.idm.LdapConstants;
import org.picketlink.idm.PartitionManager;
import org.picketlink.idm.config.AbstractIdentityStoreConfiguration;
import org.picketlink.idm.config.IdentityConfiguration;
@@ -45,7 +45,7 @@ public class PartitionManagerRegistry {
// Ldap config might have changed for the realm. In this case, we must re-initialize
if (context == null || !ldapConfig.equals(context.config)) {
logger.infof("Creating new partition manager for the realm: %s, LDAP Connection URL: %s, LDAP Base DN: %s, LDAP Vendor: %s", realm.getId(),
- ldapConfig.get(LdapConstants.CONNECTION_URL), ldapConfig.get(LdapConstants.BASE_DN), ldapConfig.get(LdapConstants.VENDOR));
+ ldapConfig.get(LDAPConstants.CONNECTION_URL), ldapConfig.get(LDAPConstants.BASE_DN), ldapConfig.get(LDAPConstants.VENDOR));
PartitionManager manager = createPartitionManager(ldapConfig);
context = new PartitionManagerContext(ldapConfig, manager);
partitionManagers.put(realm.getId(), context);
@@ -71,16 +71,16 @@ public class PartitionManagerRegistry {
checkSystemProperty("com.sun.jndi.ldap.connect.pool.protocol", "plain");
checkSystemProperty("com.sun.jndi.ldap.connect.pool.debug", "off");
- String vendor = ldapConfig.get(LdapConstants.VENDOR);
+ String vendor = ldapConfig.get(LDAPConstants.VENDOR);
// RHDS is using "nsuniqueid" as unique identifier instead of "entryUUID"
- if (vendor != null && vendor.equals(LdapConstants.VENDOR_RHDS)) {
+ if (vendor != null && vendor.equals(LDAPConstants.VENDOR_RHDS)) {
checkSystemProperty(LDAPIdentityStoreConfiguration.ENTRY_IDENTIFIER_ATTRIBUTE_NAME, "nsuniqueid");
}
- boolean activeDirectory = vendor != null && vendor.equals(LdapConstants.VENDOR_ACTIVE_DIRECTORY);
+ boolean activeDirectory = vendor != null && vendor.equals(LDAPConstants.VENDOR_ACTIVE_DIRECTORY);
- String ldapLoginNameMapping = ldapConfig.get(LdapConstants.USERNAME_LDAP_ATTRIBUTE);
+ String ldapLoginNameMapping = ldapConfig.get(LDAPConstants.USERNAME_LDAP_ATTRIBUTE);
if (ldapLoginNameMapping == null) {
ldapLoginNameMapping = activeDirectory ? CN : UID;
}
@@ -100,14 +100,14 @@ public class PartitionManagerRegistry {
.ldap()
.connectionProperties(connectionProps)
.addCredentialHandler(LDAPKeycloakCredentialHandler.class)
- .baseDN(ldapConfig.get(LdapConstants.BASE_DN))
- .bindDN(ldapConfig.get(LdapConstants.BIND_DN))
- .bindCredential(ldapConfig.get(LdapConstants.BIND_CREDENTIAL))
- .url(ldapConfig.get(LdapConstants.CONNECTION_URL))
+ .baseDN(ldapConfig.get(LDAPConstants.BASE_DN))
+ .bindDN(ldapConfig.get(LDAPConstants.BIND_DN))
+ .bindCredential(ldapConfig.get(LDAPConstants.BIND_CREDENTIAL))
+ .url(ldapConfig.get(LDAPConstants.CONNECTION_URL))
.activeDirectory(activeDirectory)
.supportAllFeatures()
.mapping(User.class)
- .baseDN(ldapConfig.get(LdapConstants.USER_DN_SUFFIX))
+ .baseDN(ldapConfig.get(LDAPConstants.USER_DN_SUFFIX))
.objectClasses("inetOrgPerson", "organizationalPerson")
.attribute("loginName", ldapLoginNameMapping, true)
.attribute("firstName", ldapFirstNameMapping)
diff --git a/services/src/main/java/org/keycloak/services/managers/LDAPConnectionTestManager.java b/services/src/main/java/org/keycloak/services/managers/LDAPConnectionTestManager.java
new file mode 100644
index 0000000..a11fd74
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/managers/LDAPConnectionTestManager.java
@@ -0,0 +1,64 @@
+package org.keycloak.services.managers;
+
+import java.util.Hashtable;
+import java.util.Map;
+
+import javax.naming.Context;
+import javax.naming.NamingException;
+import javax.naming.ldap.InitialLdapContext;
+
+import org.jboss.logging.Logger;
+import org.keycloak.models.LDAPConstants;
+import org.keycloak.models.RealmModel;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class LDAPConnectionTestManager {
+
+ protected static final Logger logger = Logger.getLogger(LDAPConnectionTestManager.class);
+
+ public static final String TEST_CONNECTION = "testConnection";
+ public static final String TEST_AUTHENTICATION = "testAuthentication";
+
+ public boolean testLDAP(String action, String connectionUrl, String bindDn, String bindCredential) {
+ if (!TEST_CONNECTION.equals(action) && !TEST_AUTHENTICATION.equals(action)) {
+ logger.error("Unknown action: " + action);
+ return false;
+ }
+
+ Context ldapContext = null;
+ try {
+ Hashtable<String, Object> env = new Hashtable<String, Object>();
+ env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
+ env.put(Context.SECURITY_AUTHENTICATION, "simple");
+
+ env.put(Context.PROVIDER_URL, connectionUrl);
+
+ if (TEST_AUTHENTICATION.equals(action)) {
+ env.put(Context.SECURITY_PRINCIPAL, bindDn);
+
+ char[] bindCredentialChar = null;
+ if (bindCredential != null) {
+ bindCredentialChar = bindCredential.toCharArray();
+ }
+ env.put(Context.SECURITY_CREDENTIALS, bindCredentialChar);
+ }
+
+ ldapContext = new InitialLdapContext(env, null);
+ return true;
+ } catch (NamingException ne) {
+ String errorMessage = (TEST_AUTHENTICATION.equals(action)) ? "Error when authenticating to LDAP: " : "Error when connecting to LDAP: ";
+ logger.error(errorMessage + ne.getMessage(), ne);
+ return false;
+ } finally {
+ if (ldapContext != null) {
+ try {
+ ldapContext.close();
+ } catch (NamingException ne) {
+ logger.warn("Error when closing LDAP connection", ne);
+ }
+ }
+ }
+ }
+}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
index cc2903f..0a6059e 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
@@ -17,6 +17,7 @@ import org.keycloak.provider.ProviderSession;
import org.keycloak.representations.adapters.action.SessionStats;
import org.keycloak.representations.idm.RealmAuditRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.services.managers.LDAPConnectionTestManager;
import org.keycloak.services.managers.ModelToRepresentation;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.managers.ResourceAdminManager;
@@ -359,4 +360,14 @@ public class RealmAdminResource {
AuditProvider audit = providers.getProvider(AuditProvider.class);
audit.clear(realm.getId());
}
+
+ @Path("testLDAPConnection")
+ @GET
+ public Response testLDAPConnection(@QueryParam("action") String action, @QueryParam("connectionUrl") String connectionUrl,
+ @QueryParam("bindDn") String bindDn, @QueryParam("bindCredential") String bindCredential) {
+ auth.init(RealmAuth.Resource.REALM).requireManage();
+
+ boolean result = new LDAPConnectionTestManager().testLDAP(action, connectionUrl, bindDn, bindCredential);
+ return result ? Response.noContent().build() : Flows.errors().error("LDAP test error", Response.Status.BAD_REQUEST);
+ }
}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/AuthProvidersIntegrationTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/AuthProvidersIntegrationTest.java
index 6f7469a..461b8a8 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/AuthProvidersIntegrationTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/AuthProvidersIntegrationTest.java
@@ -9,7 +9,7 @@ import org.junit.rules.RuleChain;
import org.junit.rules.TestRule;
import org.junit.runners.MethodSorters;
import org.keycloak.OAuth2Constants;
-import org.keycloak.model.test.LdapTestUtils;
+import org.keycloak.model.test.LDAPTestUtils;
import org.keycloak.models.AuthenticationProviderModel;
import org.keycloak.models.PasswordPolicy;
import org.keycloak.models.RealmModel;
@@ -62,7 +62,7 @@ public class AuthProvidersIntegrationTest {
// Configure LDAP
ldapRule.getEmbeddedServer().setupLdapInRealm(appRealm);
- LdapTestUtils.setLdapPassword(providerSession, appRealm, "johnkeycloak", "password");
+ LDAPTestUtils.setLdapPassword(providerSession, appRealm, "johnkeycloak", "password");
}
});