Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
474ebed0ee
16 changed files with 638 additions and 34 deletions
|
@ -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/**"/>
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
38
examples/ldap/README.md
Normal 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.
|
|
@ -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>
|
||||
*/
|
||||
|
|
278
examples/ldap/ldap-app/ldaprealm.json
Normal file
278
examples/ldap/ldap-app/ldaprealm.json
Normal 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"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -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>
|
||||
|
|
10
examples/ldap/ldap-app/src/main/webapp/WEB-INF/keycloak.json
Normal file
10
examples/ldap/ldap-app/src/main/webapp/WEB-INF/keycloak.json
Normal 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"
|
||||
}
|
||||
}
|
37
examples/ldap/ldap-app/src/main/webapp/WEB-INF/web.xml
Normal file
37
examples/ldap/ldap-app/src/main/webapp/WEB-INF/web.xml
Normal 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>
|
66
examples/ldap/ldap-app/src/main/webapp/index.jsp
Normal file
66
examples/ldap/ldap-app/src/main/webapp/index.jsp
Normal 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>
|
|
@ -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
|
||||
|
|
@ -806,7 +806,7 @@ module.controller('UserFederationMapperListCtrl', function($scope, $location, No
|
|||
|
||||
$scope.hasAnyMapperTypes = false;
|
||||
for (var property in mapperTypes) {
|
||||
if (!(property.startsWith('$'))) {
|
||||
if (!(property.indexOf('$') === 0)) {
|
||||
$scope.hasAnyMapperTypes = true;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -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` .
|
||||
|
|
|
@ -155,7 +155,7 @@ public class SyncProvidersTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void test02duplicateUsernameSync() {
|
||||
public void test02duplicateUsernameAndEmailSync() {
|
||||
LDAPObject duplicatedLdapUser;
|
||||
|
||||
KeycloakSession session = keycloakRule.startSession();
|
||||
|
@ -168,8 +168,6 @@ public class SyncProvidersTest {
|
|||
// Add user to LDAP with duplicated username "user7"
|
||||
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 {
|
||||
keycloakRule.stopSession(session, true);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue