From 69cc28dd4bbc5cee3f4cf240615893c9e6f8b8be Mon Sep 17 00:00:00 2001 From: mposolda Date: Thu, 9 Jul 2015 19:50:25 +0200 Subject: [PATCH] KEYCLOAK-1531 LDAP example and update Kerberos example to use example embedded LDAP --- distribution/examples-dist/build.xml | 6 + examples/kerberos/README.md | 27 +- examples/kerberos/kerberosrealm.json | 1 - examples/kerberos/users.ldif | 90 ++++++ examples/ldap/README.md | 38 +++ .../ldap/embedded/EmbeddedLDAPLauncher.java | 6 +- examples/ldap/ldap-app/ldaprealm.json | 278 ++++++++++++++++++ examples/ldap/ldap-app/pom.xml | 10 - .../src/main/webapp/WEB-INF/keycloak.json | 10 + .../ldap-app/src/main/webapp/WEB-INF/web.xml | 37 +++ .../ldap/ldap-app/src/main/webapp/index.jsp | 66 +++++ examples/ldap/ldap-app/users.ldif | 67 +++++ misc/Testsuite.md | 11 +- .../main/resources/ldap/default-users.ldif | 19 ++ 14 files changed, 636 insertions(+), 30 deletions(-) create mode 100644 examples/ldap/README.md create mode 100644 examples/ldap/ldap-app/ldaprealm.json create mode 100644 examples/ldap/ldap-app/src/main/webapp/WEB-INF/keycloak.json create mode 100644 examples/ldap/ldap-app/src/main/webapp/WEB-INF/web.xml create mode 100644 examples/ldap/ldap-app/src/main/webapp/index.jsp diff --git a/distribution/examples-dist/build.xml b/distribution/examples-dist/build.xml index 32b4c99211..dd2b86f0a0 100755 --- a/distribution/examples-dist/build.xml +++ b/distribution/examples-dist/build.xml @@ -107,6 +107,12 @@ + + + + + + diff --git a/examples/kerberos/README.md b/examples/kerberos/README.md index 5993a1f473..c39786b3e0 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): diff --git a/examples/kerberos/kerberosrealm.json b/examples/kerberos/kerberosrealm.json index 6b2b999fc7..c2deeac3bd 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", diff --git a/examples/kerberos/users.ldif b/examples/kerberos/users.ldif index e69de29bb2..fd9936cfa9 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/README.md b/examples/ldap/README.md new file mode 100644 index 0000000000..ab3c978efc --- /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 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 b3941d5a4e..191d63315a 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 Marek Posolda */ diff --git a/examples/ldap/ldap-app/ldaprealm.json b/examples/ldap/ldap-app/ldaprealm.json new file mode 100644 index 0000000000..ef1e2ae7bf --- /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 diff --git a/examples/ldap/ldap-app/pom.xml b/examples/ldap/ldap-app/pom.xml index d080ba6a05..d7c79f46a8 100644 --- a/examples/ldap/ldap-app/pom.xml +++ b/examples/ldap/ldap-app/pom.xml @@ -33,16 +33,6 @@ keycloak-core provided - - org.keycloak - keycloak-adapter-core - provided - - - org.apache.httpcomponents - httpclient - provided - 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 0000000000..84e1129a88 --- /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 0000000000..e6ec7c8cba --- /dev/null +++ b/examples/ldap/ldap-app/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,37 @@ + + + + ldap-portal + + + + LDAPApp + /* + + + ldap-user + + + + + + + KEYCLOAK + does-not-matter + + + + ldap-user + + \ No newline at end of file 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 0000000000..f2bf4cb99e --- /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" %> + + + + + LDAP Example + + +

LDAP Example

+
+ +<% + 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(); +%> + Logout
+
+ + +

ID Token - basic claims

+

Username: <%=idToken.getPreferredUsername()%>

+

Email: <%=idToken.getEmail()%>

+

Full Name: <%=idToken.getName()%>

+

First: <%=idToken.getGivenName()%>

+

Last: <%=idToken.getFamilyName()%>

+
+ + +

ID Token - other claims

+<% + for (Map.Entry claim : idToken.getOtherClaims().entrySet()) { +%> +

<%= claim.getKey() %>: <%= claim.getValue().toString() %> +<% + } +%> +


+ + +

Access Token - roles

+

Realm roles: <%= accessToken.getRealmAccess().getRoles().toString() %>

+<% + for (Map.Entry acc : accessToken.getResourceAccess().entrySet()) { +%> +

Resource: <%= acc.getKey() %>, Roles: <%= acc.getValue().getRoles().toString() %>

+<% + } +%> +
+ + + \ No newline at end of file diff --git a/examples/ldap/ldap-app/users.ldif b/examples/ldap/ldap-app/users.ldif index e69de29bb2..520d477e1a 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 + diff --git a/misc/Testsuite.md b/misc/Testsuite.md index ebaee4bfce..41a578cd25 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 4d6d87ee0c..ac3ffcb099 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