Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Bill Burke 2015-07-10 20:39:15 -04:00
commit 474ebed0ee
16 changed files with 638 additions and 34 deletions

View file

@ -107,6 +107,12 @@
<exclude name="**/*.iml"/> <exclude name="**/*.iml"/>
</fileset> </fileset>
</copy> </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"> <copy todir="target/examples/kerberos" overwrite="true">
<fileset dir="../../examples/kerberos"> <fileset dir="../../examples/kerberos">
<exclude name="**/target/**"/> <exclude name="**/target/**"/>

View file

@ -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 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. 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. It also needs to enable forwardable ticket support in Kerberos configuration and your browser.
Detailed steps: 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) . **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, 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). 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: 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. 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. 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 **6)** Run ApacheDS based Kerberos server . The [LDAP Example](../ldap) contains the embedded server, which you can run for example
as shown here: with these commands (assuming you're in `kerberos` directory with this example)
``` ```
git clone https://github.com/keycloak/keycloak.git cd ..
mvn clean install -DskipTests=true java -jar ldap/embedded-ldap/target/embedded-ldap.jar kerberos
cd testsuite/integration
mvn exec:java -Pkerberos
``` ```
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` . **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` . 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
More info in [testsuite README](https://github.com/keycloak/keycloak/blob/master/misc/Testsuite.md#kerberos-server). 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): **8)** Test the example. Obtain kerberos ticket by running command from CMD (on linux):

View file

@ -81,7 +81,6 @@
"usernameLDAPAttribute" : "uid", "usernameLDAPAttribute" : "uid",
"userObjectClasses" : "inetOrgPerson, organizationalPerson", "userObjectClasses" : "inetOrgPerson, organizationalPerson",
"connectionUrl" : "ldap://localhost:10389", "connectionUrl" : "ldap://localhost:10389",
"baseDn" : "dc=keycloak,dc=org",
"userDnSuffix" : "ou=People,dc=keycloak,dc=org", "userDnSuffix" : "ou=People,dc=keycloak,dc=org",
"bindDn" : "uid=admin,ou=system", "bindDn" : "uid=admin,ou=system",
"bindCredential" : "secret", "bindCredential" : "secret",

View file

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

38
examples/ldap/README.md Normal file
View file

@ -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.

View file

@ -14,8 +14,10 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern; 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 * Allows to run embedded ApacheDS LDAP or Kerberos server
* the proper class (LDAPEmbeddedServer, KerberosEmbeddedServer or KerberosKeytabCreator) *
* 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> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */

View file

@ -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"
}
}
]
}

View file

@ -33,16 +33,6 @@
<artifactId>keycloak-core</artifactId> <artifactId>keycloak-core</artifactId>
<scope>provided</scope> <scope>provided</scope>
</dependency> </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> </dependencies>
<build> <build>

View file

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

View file

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

View file

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

View file

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

View file

@ -806,7 +806,7 @@ module.controller('UserFederationMapperListCtrl', function($scope, $location, No
$scope.hasAnyMapperTypes = false; $scope.hasAnyMapperTypes = false;
for (var property in mapperTypes) { for (var property in mapperTypes) {
if (!(property.startsWith('$'))) { if (!(property.indexOf('$') === 0)) {
$scope.hasAnyMapperTypes = true; $scope.hasAnyMapperTypes = true;
break; break;
} }

View file

@ -94,11 +94,10 @@ To start a ApacheDS based LDAP server for testing LDAP sending run:
mvn exec:java -Pldap 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: in Keycloak admin console with the settings like:
* Vendor: Other * Vendor: Other
* Connection URL: ldap://localhost:10389 * Connection URL: ldap://localhost:10389
* Base DN: dc=keycloak,dc=org
* User DN Suffix: ou=People,dc=keycloak,dc=org * User DN Suffix: ou=People,dc=keycloak,dc=org
* Bind DN: uid=admin,ou=system * Bind DN: uid=admin,ou=system
* Bind credential: secret * Bind credential: secret
@ -110,18 +109,18 @@ To start a ApacheDS based Kerberos server for testing Kerberos + LDAP sending ru
mvn exec:java -Pkerberos 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. 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 . LDAP will import initial data from [src/main/resources/kerberos/users-kerberos.ldif](src/main/resources/kerberos/users-kerberos.ldif) . 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. 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: But additionally you can enable Kerberos authentication in LDAP provider with the settings like:
* Kerberos realm: KEYCLOAK.ORG * Kerberos realm: KEYCLOAK.ORG
* Server Principal: HTTP/localhost@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. 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` ) 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` . Then you need to configure your browser to allow SPNEGO/Kerberos login from `localhost` .

View file

@ -155,7 +155,7 @@ public class SyncProvidersTest {
} }
@Test @Test
public void test02duplicateUsernameSync() { public void test02duplicateUsernameAndEmailSync() {
LDAPObject duplicatedLdapUser; LDAPObject duplicatedLdapUser;
KeycloakSession session = keycloakRule.startSession(); KeycloakSession session = keycloakRule.startSession();
@ -168,8 +168,6 @@ public class SyncProvidersTest {
// Add user to LDAP with duplicated username "user7" // Add user to LDAP with duplicated username "user7"
duplicatedLdapUser = FederationTestUtils.addLDAPUser(ldapFedProvider, testRealm, "user7", "User7FN", "User7LN", "user7-something@email.org", null, "126"); duplicatedLdapUser = FederationTestUtils.addLDAPUser(ldapFedProvider, testRealm, "user7", "User7FN", "User7LN", "user7-something@email.org", null, "126");
// Add user to LDAP with duplicated email "user7@email.org"
//FederationTestUtils.addLDAPUser(ldapFedProvider, testRealm, "user7-something", "User7FNN", "User7LNL", "user7@email.org", null, "126");
} finally { } finally {
keycloakRule.stopSession(session, true); keycloakRule.stopSession(session, true);
} }

View file

@ -45,3 +45,22 @@ postalCode: 88441
postalCode: 77332 postalCode: 77332
street: Elm 5 street: Elm 5
userPassword: password 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