keycloak-aplcache
Changes
distribution/examples-dist/build.xml 6(+6 -0)
examples/kerberos/kerberosrealm.json 1(+0 -1)
examples/kerberos/README.md 27(+16 -11)
examples/kerberos/users.ldif 90(+90 -0)
examples/ldap/embedded-ldap/src/main/java/org/keycloak/example/ldap/embedded/EmbeddedLDAPLauncher.java 6(+4 -2)
examples/ldap/ldap-app/ldaprealm.json 278(+278 -0)
examples/ldap/ldap-app/pom.xml 10(+0 -10)
examples/ldap/ldap-app/users.ldif 67(+67 -0)
examples/ldap/README.md 38(+38 -0)
misc/Testsuite.md 11(+5 -6)
Details
distribution/examples-dist/build.xml 6(+6 -0)
diff --git a/distribution/examples-dist/build.xml b/distribution/examples-dist/build.xml
index 32b4c99..dd2b86f 100755
--- a/distribution/examples-dist/build.xml
+++ b/distribution/examples-dist/build.xml
@@ -107,6 +107,12 @@
<exclude name="**/*.iml"/>
</fileset>
</copy>
+ <copy todir="target/examples/ldap" overwrite="true">
+ <fileset dir="../../examples/ldap">
+ <exclude name="**/target/**"/>
+ <exclude name="**/*.iml"/>
+ </fileset>
+ </copy>
<copy todir="target/examples/kerberos" overwrite="true">
<fileset dir="../../examples/kerberos">
<exclude name="**/target/**"/>
examples/kerberos/kerberosrealm.json 1(+0 -1)
diff --git a/examples/kerberos/kerberosrealm.json b/examples/kerberos/kerberosrealm.json
index 6b2b999..c2deeac 100644
--- a/examples/kerberos/kerberosrealm.json
+++ b/examples/kerberos/kerberosrealm.json
@@ -81,7 +81,6 @@
"usernameLDAPAttribute" : "uid",
"userObjectClasses" : "inetOrgPerson, organizationalPerson",
"connectionUrl" : "ldap://localhost:10389",
- "baseDn" : "dc=keycloak,dc=org",
"userDnSuffix" : "ou=People,dc=keycloak,dc=org",
"bindDn" : "uid=admin,ou=system",
"bindCredential" : "secret",
examples/kerberos/README.md 27(+16 -11)
diff --git a/examples/kerberos/README.md b/examples/kerberos/README.md
index 5993a1f..c39786b 100644
--- a/examples/kerberos/README.md
+++ b/examples/kerberos/README.md
@@ -4,7 +4,7 @@ Keycloak Example - Kerberos Credential Delegation
This example requires that Keycloak is configured with Kerberos/SPNEGO authentication. It's showing how the forwardable TGT is sent from
the Keycloak auth-server to the application, which deserializes it and authenticates with it to further Kerberized service, which in the example is LDAP server.
-Example is using built-in ApacheDS Kerberos server from the keycloak testsuite and the realm with preconfigured federation provider and `gss delegation credential` protocol mapper.
+Example is using built-in ApacheDS Kerberos server and the realm with preconfigured federation provider and `gss delegation credential` protocol mapper.
It also needs to enable forwardable ticket support in Kerberos configuration and your browser.
Detailed steps:
@@ -28,7 +28,7 @@ added to the application.
**WARNING:** It's recommended to use JDK8 to run Keycloak server. For JDK7 you may be faced with the bug described [here](http://darranl.blogspot.cz/2014/09/kerberos-encrypteddata-null-key-keytype.html) .
Alternatively you can use OpenJDK7 but in this case you will need to use aes256-cts-hmac-sha1-96 for both KDC and Kerberos client configuration. For server,
-you can add system property to the maven command when running ApacheDS Kerberos server `-Dkerberos.encTypes=aes256-cts-hmac-sha1-96` (see below) and for
+you can add system property to the command when running ApacheDS Kerberos server `-Dkerberos.encTypes=aes256-cts-hmac-sha1-96` (see below) and for
client add encryption types to configuration file like `/etc/krb5.conf` (but they should be already available. See below).
Also if you are on Linux, make sure that record like:
@@ -43,22 +43,27 @@ is in your `/etc/hosts` before other records for the 127.0.0.1 host to avoid iss
for credential delegation example, as application needs to forward Kerberos ticket and authenticate with it against LDAP server.
See [this file](https://github.com/keycloak/keycloak/blob/master/testsuite/integration/src/test/resources/kerberos/test-krb5.conf) for inspiration.
-**6)** Run ApacheDS based Kerberos server embedded in Keycloak. Easiest is to checkout keycloak sources, build and then run KerberosEmbeddedServer
-as shown here:
+**6)** Run ApacheDS based Kerberos server . The [LDAP Example](../ldap) contains the embedded server, which you can run for example
+with these commands (assuming you're in `kerberos` directory with this example)
```
-git clone https://github.com/keycloak/keycloak.git
-mvn clean install -DskipTests=true
-cd testsuite/integration
-mvn exec:java -Pkerberos
+cd ..
+java -jar ldap/embedded-ldap/target/embedded-ldap.jar kerberos
```
-More details about embedded Kerberos server in [testsuite README](https://github.com/keycloak/keycloak/blob/master/misc/Testsuite.md#kerberos-server).
+This will also automatically import the LDIF from `users.ldif` of kerberos example into the LDAP server. If you want to import your own LDIF file,
+you can add the system property `ldap.ldif` with the path of the LDIF file to the command. For example:
+```
+java -jar -Dldap.ldif=/tmp/my-users.ldif ldap/embedded-ldap/target/embedded-ldap.jar kerberos
+```
+
+A bit more details about embedded Kerberos server in [testsuite README](https://github.com/keycloak/keycloak/blob/master/misc/Testsuite.md#kerberos-server).
**7)** Configure browser (Firefox, Chrome or other) and enable SPNEGO authentication and credential delegation for `localhost` .
-In Firefox it can be done by adding `localhost` to both `network.negotiate-auth.trusted-uris` and `network.negotiate-auth.delegation-uris` .
-More info in [testsuite README](https://github.com/keycloak/keycloak/blob/master/misc/Testsuite.md#kerberos-server).
+Consult the documentation of your browser and OS on how to do it. For example in Firefox it can be done by adding `localhost` to
+both `network.negotiate-auth.trusted-uris` and `network.negotiate-auth.delegation-uris` and switch `network.negotiate-auth.allow-non-fqdn` to `true`.
+A bit more details in [testsuite README](https://github.com/keycloak/keycloak/blob/master/misc/Testsuite.md#kerberos-server) .
**8)** Test the example. Obtain kerberos ticket by running command from CMD (on linux):
examples/kerberos/users.ldif 90(+90 -0)
diff --git a/examples/kerberos/users.ldif b/examples/kerberos/users.ldif
index e69de29..fd9936c 100644
--- a/examples/kerberos/users.ldif
+++ b/examples/kerberos/users.ldif
@@ -0,0 +1,90 @@
+dn: dc=keycloak,dc=org
+objectclass: dcObject
+objectclass: organization
+o: Keycloak
+dc: Keycloak
+
+dn: ou=People,dc=keycloak,dc=org
+objectClass: organizationalUnit
+objectClass: top
+ou: People
+
+dn: uid=krbtgt,ou=People,dc=keycloak,dc=org
+objectClass: top
+objectClass: person
+objectClass: inetOrgPerson
+objectClass: krb5principal
+objectClass: krb5kdcentry
+cn: KDC Service
+sn: Service
+uid: krbtgt
+userPassword: secret
+krb5PrincipalName: krbtgt/KEYCLOAK.ORG@KEYCLOAK.ORG
+krb5KeyVersionNumber: 0
+
+dn: uid=ldap,ou=People,dc=keycloak,dc=org
+objectClass: top
+objectClass: person
+objectClass: inetOrgPerson
+objectClass: krb5principal
+objectClass: krb5kdcentry
+cn: LDAP
+sn: Service
+uid: ldap
+userPassword: randall
+krb5PrincipalName: ${ldapSaslPrincipal}
+krb5KeyVersionNumber: 0
+
+dn: uid=HTTP,ou=People,dc=keycloak,dc=org
+objectClass: top
+objectClass: person
+objectClass: inetOrgPerson
+objectClass: krb5principal
+objectClass: krb5kdcentry
+cn: HTTP
+sn: Service
+uid: HTTP
+userPassword: httppwd
+krb5PrincipalName: HTTP/${hostname}@KEYCLOAK.ORG
+krb5KeyVersionNumber: 0
+
+dn: uid=hnelson,ou=People,dc=keycloak,dc=org
+objectClass: top
+objectClass: person
+objectClass: inetOrgPerson
+objectClass: krb5principal
+objectClass: krb5kdcentry
+cn: Horatio
+sn: Nelson
+mail: hnelson@keycloak.org
+uid: hnelson
+userPassword: secret
+krb5PrincipalName: hnelson@KEYCLOAK.ORG
+krb5KeyVersionNumber: 0
+
+dn: uid=jduke,ou=People,dc=keycloak,dc=org
+objectClass: top
+objectClass: person
+objectClass: inetOrgPerson
+objectClass: krb5principal
+objectClass: krb5kdcentry
+cn: Java
+sn: Duke
+mail: jduke@keycloak.org
+uid: jduke
+userPassword: theduke
+krb5PrincipalName: jduke@KEYCLOAK.ORG
+krb5KeyVersionNumber: 0
+
+dn: uid=gsstestserver,ou=People,dc=keycloak,dc=org
+objectClass: top
+objectClass: person
+objectClass: inetOrgPerson
+objectClass: krb5principal
+objectClass: krb5kdcentry
+cn: gsstestserver
+sn: Service
+uid: gsstestserver
+userPassword: gsstestpwd
+krb5PrincipalName: gsstestserver/xxx@KEYCLOAK.ORG
+krb5KeyVersionNumber: 0
diff --git a/examples/ldap/embedded-ldap/src/main/java/org/keycloak/example/ldap/embedded/EmbeddedLDAPLauncher.java b/examples/ldap/embedded-ldap/src/main/java/org/keycloak/example/ldap/embedded/EmbeddedLDAPLauncher.java
index b3941d5..191d633 100644
--- a/examples/ldap/embedded-ldap/src/main/java/org/keycloak/example/ldap/embedded/EmbeddedLDAPLauncher.java
+++ b/examples/ldap/embedded-ldap/src/main/java/org/keycloak/example/ldap/embedded/EmbeddedLDAPLauncher.java
@@ -14,8 +14,10 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
- * This is supposed to be executed from JAR file (java -jar target/embedded-ldap.jar ). For executing from IDE or Maven use directly
- * the proper class (LDAPEmbeddedServer, KerberosEmbeddedServer or KerberosKeytabCreator)
+ * Allows to run embedded ApacheDS LDAP or Kerberos server
+ *
+ * It is supposed to be executed from JAR file. For example:
+ * java -jar target/embedded-ldap.jar ldap
*
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
examples/ldap/ldap-app/ldaprealm.json 278(+278 -0)
diff --git a/examples/ldap/ldap-app/ldaprealm.json b/examples/ldap/ldap-app/ldaprealm.json
new file mode 100644
index 0000000..ef1e2ae
--- /dev/null
+++ b/examples/ldap/ldap-app/ldaprealm.json
@@ -0,0 +1,278 @@
+{
+ "id": "ldap-demo",
+ "realm": "ldap-demo",
+ "enabled": true,
+ "sslRequired": "external",
+ "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
+ "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+ "requiredCredentials": [ "password" ],
+ "clients": [
+ {
+ "clientId": "finance",
+ "enabled": true,
+ "bearerOnly": true
+ },
+ {
+ "clientId": "ldap-app",
+ "enabled": true,
+ "baseUrl": "/ldap-portal",
+ "redirectUris": [
+ "/ldap-portal/*"
+ ],
+ "adminUrl": "/ldap-portal",
+ "secret": "password",
+ "fullScopeAllowed": true,
+ "protocolMappers": [
+ {
+ "protocolMapper" : "oidc-usermodel-property-mapper",
+ "protocol" : "openid-connect",
+ "name" : "username",
+ "consentText" : "${username}",
+ "consentRequired" : true,
+ "config" : {
+ "Claim JSON Type" : "String",
+ "user.attribute" : "username",
+ "claim.name" : "preferred_username",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true"
+ }
+ },
+ {
+ "protocolMapper" : "oidc-full-name-mapper",
+ "protocol" : "openid-connect",
+ "name" : "full name",
+ "consentText" : "${fullName}",
+ "consentRequired" : true,
+ "config" : {
+ "id.token.claim" : "true",
+ "access.token.claim" : "true"
+ }
+ },
+ {
+ "protocolMapper" : "oidc-usermodel-property-mapper",
+ "protocol" : "openid-connect",
+ "name" : "given name",
+ "consentText" : "${givenName}",
+ "consentRequired" : true,
+ "config" : {
+ "Claim JSON Type" : "String",
+ "user.attribute" : "firstName",
+ "claim.name" : "given_name",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true"
+ }
+ },
+ {
+ "protocolMapper" : "oidc-usermodel-property-mapper",
+ "protocol" : "openid-connect",
+ "name" : "family name",
+ "consentText" : "${familyName}",
+ "consentRequired" : true,
+ "config" : {
+ "Claim JSON Type" : "String",
+ "user.attribute" : "lastName",
+ "claim.name" : "family_name",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true"
+ }
+ },
+ {
+ "protocolMapper" : "oidc-usermodel-property-mapper",
+ "protocol" : "openid-connect",
+ "name" : "email",
+ "consentText" : "${email}",
+ "consentRequired" : true,
+ "config" : {
+ "Claim JSON Type" : "String",
+ "user.attribute" : "email",
+ "claim.name" : "email",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true"
+ }
+ },
+ {
+ "protocolMapper" : "oidc-usermodel-attribute-mapper",
+ "protocol" : "openid-connect",
+ "name" : "postal code",
+ "consentText" : "${postal_code}",
+ "consentRequired" : true,
+ "config" : {
+ "Claim JSON Type" : "String",
+ "user.attribute" : "postal_code",
+ "claim.name" : "postal_code",
+ "multivalued": "true",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true"
+ }
+ },
+ {
+ "protocolMapper" : "oidc-usermodel-attribute-mapper",
+ "protocol" : "openid-connect",
+ "name" : "street",
+ "consentText" : "${street}",
+ "consentRequired" : true,
+ "config" : {
+ "Claim JSON Type" : "String",
+ "user.attribute" : "street",
+ "claim.name" : "street",
+ "multivalued": "false",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true"
+ }
+ }
+ ]
+ }
+ ],
+ "userFederationProviders": [
+ {
+ "displayName": "ldap-apacheds",
+ "providerName": "ldap",
+ "priority": 1,
+ "fullSyncPeriod": -1,
+ "changedSyncPeriod": -1,
+ "config": {
+ "pagination" : "true",
+ "debug" : "false",
+ "searchScope" : "1",
+ "connectionPooling" : "true",
+ "usersDn" : "ou=People,dc=keycloak,dc=org",
+ "userObjectClasses" : "inetOrgPerson, organizationalPerson",
+ "usernameLDAPAttribute" : "uid",
+ "bindDn" : "uid=admin,ou=system",
+ "bindCredential" : "secret",
+ "rdnLDAPAttribute" : "uid",
+ "vendor" : "other",
+ "editMode" : "WRITABLE",
+ "uuidLDAPAttribute" : "entryUUID",
+ "connectionUrl" : "ldap://localhost:10389",
+ "syncRegistrations" : "true",
+ "authType" : "simple"
+ }
+ }
+ ],
+ "userFederationMappers" : [
+ {
+ "name" : "username",
+ "federationMapperType" : "user-attribute-ldap-mapper",
+ "federationProviderDisplayName" : "ldap-apacheds",
+ "config" : {
+ "ldap.attribute" : "uid",
+ "user.model.attribute" : "username",
+ "is.mandatory.in.ldap" : "true",
+ "read.only" : "false",
+ "always.read.value.from.ldap" : "false"
+ }
+ },
+ {
+ "name" : "first name",
+ "federationMapperType" : "user-attribute-ldap-mapper",
+ "federationProviderDisplayName" : "ldap-apacheds",
+ "config" : {
+ "ldap.attribute" : "cn",
+ "user.model.attribute" : "firstName",
+ "is.mandatory.in.ldap" : "true",
+ "read.only" : "false",
+ "always.read.value.from.ldap" : "false"
+ }
+ },
+ {
+ "name" : "last name",
+ "federationMapperType" : "user-attribute-ldap-mapper",
+ "federationProviderDisplayName" : "ldap-apacheds",
+ "config" : {
+ "ldap.attribute" : "sn",
+ "user.model.attribute" : "lastName",
+ "is.mandatory.in.ldap" : "true",
+ "read.only" : "false",
+ "always.read.value.from.ldap" : "false"
+ }
+ },
+ {
+ "name" : "email",
+ "federationMapperType" : "user-attribute-ldap-mapper",
+ "federationProviderDisplayName" : "ldap-apacheds",
+ "config" : {
+ "ldap.attribute" : "mail",
+ "user.model.attribute" : "email",
+ "is.mandatory.in.ldap" : "false",
+ "read.only" : "false",
+ "always.read.value.from.ldap" : "false"
+ }
+ },
+ {
+ "name" : "creation date",
+ "federationMapperType" : "user-attribute-ldap-mapper",
+ "federationProviderDisplayName" : "ldap-apacheds",
+ "config" : {
+ "ldap.attribute" : "createTimestamp",
+ "user.model.attribute" : "createTimestamp",
+ "is.mandatory.in.ldap" : "false",
+ "read.only" : "true",
+ "always.read.value.from.ldap" : "false"
+ }
+ },
+ {
+ "name" : "modify date",
+ "federationMapperType" : "user-attribute-ldap-mapper",
+ "federationProviderDisplayName" : "ldap-apacheds",
+ "config" : {
+ "ldap.attribute" : "modifyTimestamp",
+ "user.model.attribute" : "modifyTimestamp",
+ "is.mandatory.in.ldap" : "false",
+ "read.only" : "true",
+ "always.read.value.from.ldap" : "false"
+ }
+ },
+ {
+ "name" : "postal code",
+ "federationMapperType" : "user-attribute-ldap-mapper",
+ "federationProviderDisplayName" : "ldap-apacheds",
+ "config" : {
+ "ldap.attribute" : "postalCode",
+ "user.model.attribute" : "postal_code",
+ "is.mandatory.in.ldap" : "false",
+ "read.only" : "false",
+ "always.read.value.from.ldap" : "false"
+ }
+ },
+ {
+ "name" : "street",
+ "federationMapperType" : "user-attribute-ldap-mapper",
+ "federationProviderDisplayName" : "ldap-apacheds",
+ "config" : {
+ "ldap.attribute" : "street",
+ "user.model.attribute" : "street",
+ "is.mandatory.in.ldap" : "false",
+ "read.only" : "false",
+ "always.read.value.from.ldap" : "false"
+ }
+ },
+ {
+ "name" : "realm roles",
+ "federationMapperType" : "role-ldap-mapper",
+ "federationProviderDisplayName" : "ldap-apacheds",
+ "config" : {
+ "roles.dn" : "ou=RealmRoles,dc=keycloak,dc=org",
+ "membership.ldap.attribute" : "member",
+ "role.name.ldap.attribute" : "cn",
+ "role.object.classes" : "groupOfNames",
+ "mode" : "LDAP_ONLY",
+ "use.realm.roles.mapping" : "true"
+ }
+ },
+ {
+ "name" : "finance roles",
+ "federationMapperType" : "role-ldap-mapper",
+ "federationProviderDisplayName" : "ldap-apacheds",
+ "config" : {
+ "roles.dn" : "ou=FinanceRoles,dc=keycloak,dc=org",
+ "membership.ldap.attribute" : "member",
+ "role.name.ldap.attribute" : "cn",
+ "role.object.classes" : "groupOfNames",
+ "mode" : "LDAP_ONLY",
+ "use.realm.roles.mapping" : "false",
+ "client.id" : "finance"
+ }
+ }
+ ]
+}
\ No newline at end of file
examples/ldap/ldap-app/pom.xml 10(+0 -10)
diff --git a/examples/ldap/ldap-app/pom.xml b/examples/ldap/ldap-app/pom.xml
index d080ba6..d7c79f4 100644
--- a/examples/ldap/ldap-app/pom.xml
+++ b/examples/ldap/ldap-app/pom.xml
@@ -33,16 +33,6 @@
<artifactId>keycloak-core</artifactId>
<scope>provided</scope>
</dependency>
- <dependency>
- <groupId>org.keycloak</groupId>
- <artifactId>keycloak-adapter-core</artifactId>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>org.apache.httpcomponents</groupId>
- <artifactId>httpclient</artifactId>
- <scope>provided</scope>
- </dependency>
</dependencies>
<build>
diff --git a/examples/ldap/ldap-app/src/main/webapp/index.jsp b/examples/ldap/ldap-app/src/main/webapp/index.jsp
new file mode 100644
index 0000000..f2bf4cb
--- /dev/null
+++ b/examples/ldap/ldap-app/src/main/webapp/index.jsp
@@ -0,0 +1,66 @@
+<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
+ pageEncoding="ISO-8859-1" %>
+<%@ page import="org.keycloak.constants.ServiceUrlConstants" %>
+<%@ page import="org.keycloak.util.KeycloakUriBuilder" %>
+<%@ page import="org.keycloak.KeycloakSecurityContext" %>
+<%@ page import="org.keycloak.representations.IDToken" %>
+<%@ page import="org.keycloak.representations.AccessToken" %>
+<%@ page import="org.keycloak.representations.AccessToken.Access" %>
+<%@ page import="java.util.Map" %>
+<%@ page session="false" %>
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <title>LDAP Example</title>
+ </head>
+ <body bgcolor="#ffffff">
+ <h1>LDAP Example</h1>
+ <hr />
+
+<%
+ String logoutUri = KeycloakUriBuilder.fromUri("/auth").path(ServiceUrlConstants.TOKEN_SERVICE_LOGOUT_PATH)
+ .queryParam("redirect_uri", "/ldap-portal").build("ldap-demo").toString();
+
+ KeycloakSecurityContext securityContext = (KeycloakSecurityContext) request.getAttribute(KeycloakSecurityContext.class.getName());
+ IDToken idToken = securityContext.getIdToken();
+ AccessToken accessToken = securityContext.getToken();
+%>
+ <a href="<%=logoutUri%>">Logout</a><br />
+ <hr />
+
+
+ <h2>ID Token - basic claims</h2>
+ <p><b>Username: </b><%=idToken.getPreferredUsername()%></p>
+ <p><b>Email: </b><%=idToken.getEmail()%></p>
+ <p><b>Full Name: </b><%=idToken.getName()%></p>
+ <p><b>First: </b><%=idToken.getGivenName()%></p>
+ <p><b>Last: </b><%=idToken.getFamilyName()%></p>
+ <hr />
+
+
+ <h2>ID Token - other claims</h2>
+<%
+ for (Map.Entry<String, Object> claim : idToken.getOtherClaims().entrySet()) {
+%>
+ <p><b><%= claim.getKey() %>: </b><%= claim.getValue().toString() %>
+<%
+ }
+%>
+ <hr />
+
+
+ <h2>Access Token - roles</h2>
+ <p><b>Realm roles: </b><%= accessToken.getRealmAccess().getRoles().toString() %></p>
+<%
+ for (Map.Entry<String, Access> acc : accessToken.getResourceAccess().entrySet()) {
+%>
+ <p><b>Resource: </b><%= acc.getKey() %>, <b>Roles: </b><%= acc.getValue().getRoles().toString() %></p>
+<%
+ }
+%>
+ <hr />
+
+ </body>
+</html>
\ No newline at end of file
diff --git a/examples/ldap/ldap-app/src/main/webapp/WEB-INF/keycloak.json b/examples/ldap/ldap-app/src/main/webapp/WEB-INF/keycloak.json
new file mode 100644
index 0000000..84e1129
--- /dev/null
+++ b/examples/ldap/ldap-app/src/main/webapp/WEB-INF/keycloak.json
@@ -0,0 +1,10 @@
+{
+ "realm" : "ldap-demo",
+ "resource" : "ldap-app",
+ "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+ "auth-server-url": "/auth",
+ "ssl-required" : "external",
+ "credentials": {
+ "secret": "password"
+ }
+}
\ No newline at end of file
diff --git a/examples/ldap/ldap-app/src/main/webapp/WEB-INF/web.xml b/examples/ldap/ldap-app/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000..e6ec7c8
--- /dev/null
+++ b/examples/ldap/ldap-app/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+ version="3.0">
+
+ <module-name>ldap-portal</module-name>
+
+ <security-constraint>
+ <web-resource-collection>
+ <web-resource-name>LDAPApp</web-resource-name>
+ <url-pattern>/*</url-pattern>
+ </web-resource-collection>
+ <auth-constraint>
+ <role-name>ldap-user</role-name>
+ </auth-constraint>
+ </security-constraint>
+
+ <!--
+ <security-constraint>
+ <web-resource-collection>
+ <url-pattern>/*</url-pattern>
+ </web-resource-collection>
+ <user-data-constraint>
+ <transport-guarantee>CONFIDENTIAL</transport-guarantee>
+ </user-data-constraint>
+ </security-constraint> -->
+
+ <login-config>
+ <auth-method>KEYCLOAK</auth-method>
+ <realm-name>does-not-matter</realm-name>
+ </login-config>
+
+ <security-role>
+ <role-name>ldap-user</role-name>
+ </security-role>
+</web-app>
\ No newline at end of file
examples/ldap/ldap-app/users.ldif 67(+67 -0)
diff --git a/examples/ldap/ldap-app/users.ldif b/examples/ldap/ldap-app/users.ldif
index e69de29..520d477 100644
--- a/examples/ldap/ldap-app/users.ldif
+++ b/examples/ldap/ldap-app/users.ldif
@@ -0,0 +1,67 @@
+dn: dc=keycloak,dc=org
+objectclass: dcObject
+objectclass: organization
+o: Keycloak
+dc: Keycloak
+
+dn: ou=People,dc=keycloak,dc=org
+objectclass: top
+objectclass: organizationalUnit
+ou: People
+
+dn: ou=RealmRoles,dc=keycloak,dc=org
+objectclass: top
+objectclass: organizationalUnit
+ou: RealmRoles
+
+dn: ou=FinanceRoles,dc=keycloak,dc=org
+objectclass: top
+objectclass: organizationalUnit
+ou: FinanceRoles
+
+dn: uid=jbrown,ou=People,dc=keycloak,dc=org
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: jbrown
+cn: James
+sn: Brown
+mail: jbrown@keycloak.org
+postalCode: 88441
+userPassword: password
+
+dn: uid=bwilson,ou=People,dc=keycloak,dc=org
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: bwilson
+cn: Bruce
+sn: Wilson
+mail: bwilson@keycloak.org
+postalCode: 88441
+postalCode: 77332
+postalCode: 66221
+street: Elm 5
+userPassword: password
+
+dn: cn=ldap-user,ou=RealmRoles,dc=keycloak,dc=org
+objectclass: top
+objectclass: groupOfNames
+cn: ldap-user
+member: uid=jbrown,ou=People,dc=keycloak,dc=org
+member: uid=bwilson,ou=People,dc=keycloak,dc=org
+
+dn: cn=ldap-admin,ou=RealmRoles,dc=keycloak,dc=org
+objectclass: top
+objectclass: groupOfNames
+cn: ldap-admin
+member: uid=jbrown,ou=People,dc=keycloak,dc=org
+
+dn: cn=accountant,ou=FinanceRoles,dc=keycloak,dc=org
+objectclass: top
+objectclass: groupOfNames
+cn: accountant
+member: uid=bwilson,ou=People,dc=keycloak,dc=org
+
examples/ldap/README.md 38(+38 -0)
diff --git a/examples/ldap/README.md b/examples/ldap/README.md
new file mode 100644
index 0000000..ab3c978
--- /dev/null
+++ b/examples/ldap/README.md
@@ -0,0 +1,38 @@
+Keycloak Example - LDAP
+=======================
+
+This example shows how to configure Keycloak with LDAP and use LDAP for authenticating users into Keycloak and provision data about users.
+
+Example is using built-in ApacheDS LDAP server with preconfigured LDIF file with some example LDAP data (you can override with your own LDIF file)
+and preconfigured realm JSON file with LDAP Federation provider and sample set of preconfigured LDAP mappers and protocol mappers.
+This shows mapping of basic LDAP data (username, firstName, lastName, email), but also some custom attributes ( postal code, street) and also
+propagation of role mappings from LDAP to the Keycloak. LDAP mappers are used to import data from LDAP user records into user records in Keycloak database.
+Then there are protocol mappers, which are used to propagate the data from user record in Keycloak database into the IDToken and Access Token, which is then shown in the example application.
+
+The example application is then showing all the basic claims of current user together with custom claims and role mappings.
+
+Detailed steps how to make the example working:
+
+**1)** Build and deploy this sample's WAR file in `ldap-app/target/ldap-portal.war` . For this example, deploy on the same server that is running the Keycloak Server,
+although this is not required for real world scenarios.
+
+
+**2)** Run ApacheDS based LDAP server. You can run the command like this (assuming you're in the "ldap" directory with this example):
+
+```
+java -jar embedded-ldap/target/embedded-ldap.jar ldap
+```
+
+This will also automatically import the LDIF from `ldap-app/users.ldif` into the LDAP server. If you want to import your own LDIF file,
+you can add the system property `ldap.ldif` with the path of the LDIF file to the command. For example:
+```
+java -jar -Dldap.ldif=/tmp/my-users.ldif embedded-ldap/target/embedded-ldap.jar ldap
+```
+
+
+**3)** Run Keycloak server and import `ldap-app/ldaprealm.json` into it through admin console. This contains the realm with preconfigured LDAP federation provider and LDAP mappers
+and protocol mappers. Note that there are not any roles or users in this file. All of users, roles and role mappings data will be imported automatically from LDAP.
+
+
+**4)** Test the example. In your web browser open `http://localhost:8080/ldap-portal` . You can login either as `jbrown` with password `password` or as
+`bwilson` with password `password` . You can see that access token contains all the claims and role mappings corresponding to the LDAP data provided in LDIF.
\ No newline at end of file
misc/Testsuite.md 11(+5 -6)
diff --git a/misc/Testsuite.md b/misc/Testsuite.md
index ebaee4b..41a578c 100644
--- a/misc/Testsuite.md
+++ b/misc/Testsuite.md
@@ -94,11 +94,10 @@ To start a ApacheDS based LDAP server for testing LDAP sending run:
mvn exec:java -Pldap
-There are additional system properties you can use to configure (See EmbeddedServersFactory class for details). Once done, you can create LDAP Federation provider
+There are additional system properties you can use to configure (See LDAPEmbeddedServer class for details). Once done, you can create LDAP Federation provider
in Keycloak admin console with the settings like:
* Vendor: Other
* Connection URL: ldap://localhost:10389
-* Base DN: dc=keycloak,dc=org
* User DN Suffix: ou=People,dc=keycloak,dc=org
* Bind DN: uid=admin,ou=system
* Bind credential: secret
@@ -110,18 +109,18 @@ To start a ApacheDS based Kerberos server for testing Kerberos + LDAP sending ru
mvn exec:java -Pkerberos
-There are additional system properties you can use to configure (See EmbeddedServersFactory class for details) but for testing purposes default values should be good.
-By default ApacheDS LDAP server will be running on localhost:10389 and Kerberos KDC on localhost:6088 . LDAP will import initial data from [src/main/resources/kerberos/users-kerberos.ldif](src/main/resources/kerberos/users-kerberos.ldif) .
+There are additional system properties you can use to configure (See LDAPEmbeddedServer and KerberosEmbeddedServer class for details) but for testing purposes default values should be good.
+By default ApacheDS LDAP server will be running on localhost:10389 and Kerberos KDC on localhost:6088 .
Once kerberos is running, you can create LDAP Federation provider in Keycloak admin console with same settings like mentioned in previous LDAP section.
But additionally you can enable Kerberos authentication in LDAP provider with the settings like:
* Kerberos realm: KEYCLOAK.ORG
* Server Principal: HTTP/localhost@KEYCLOAK.ORG
-* KeyTab: $KEYCLOAK_SOURCES/testsuite/integration/src/main/resources/kerberos/http.keytab (Replace $KEYCLOAK_SOURCES with correct absolute path of your sources)
+* KeyTab: $KEYCLOAK_SOURCES/testsuite/integration/src/test/resources/kerberos/http.keytab (Replace $KEYCLOAK_SOURCES with correct absolute path of your sources)
Once you do this, you should also ensure that your Kerberos client configuration file is properly configured with KEYCLOAK.ORG domain.
-See [src/main/resources/kerberos/test-krb5.conf](src/main/resources/kerberos/test-krb5.conf) for inspiration. The location of Kerberos configuration file
+See [../testsuite/integration/src/test/resources/kerberos/test-krb5.conf](../testsuite/integration/src/test/resources/kerberos/test-krb5.conf) for inspiration. The location of Kerberos configuration file
is platform dependent (In linux it's file `/etc/krb5.conf` )
Then you need to configure your browser to allow SPNEGO/Kerberos login from `localhost` .
diff --git a/util/embedded-ldap/src/main/resources/ldap/default-users.ldif b/util/embedded-ldap/src/main/resources/ldap/default-users.ldif
index 4d6d87e..ac3ffcb 100644
--- a/util/embedded-ldap/src/main/resources/ldap/default-users.ldif
+++ b/util/embedded-ldap/src/main/resources/ldap/default-users.ldif
@@ -45,3 +45,22 @@ postalCode: 88441
postalCode: 77332
street: Elm 5
userPassword: password
+
+dn: cn=ldap-user,ou=RealmRoles,dc=keycloak,dc=org
+objectclass: top
+objectclass: groupOfNames
+cn: ldap-user
+member: uid=jbrown,ou=People,dc=keycloak,dc=org
+member: uid=bwilson,ou=People,dc=keycloak,dc=org
+
+dn: cn=ldap-admin,ou=RealmRoles,dc=keycloak,dc=org
+objectclass: top
+objectclass: groupOfNames
+cn: ldap-admin
+member: uid=jbrown,ou=People,dc=keycloak,dc=org
+
+dn: cn=accountant,ou=FinanceRoles,dc=keycloak,dc=org
+objectclass: top
+objectclass: groupOfNames
+cn: accountant
+member: uid=bwilson,ou=People,dc=keycloak,dc=org