This is an old revision of the document!
Table of Contents
LDAP
LDAP ist ein Format zum Speichern von Daten in Verzeichnissen (!= Ordner. Verzeichnis wie z.B. Telefonverzeichnis, Katalog)
Hier eine tolle Einleitung:
- Partitions - unter Root hängt eine Partition. z.B. dc=otm,dc=intra
- AttributeType - beschreibt den Type eines Wertes
- ObjectClass - definiert einen Satz von attributen. z.B. Class person hat name, surname, .. als attribute
- Creating a Partition - http://directory.apache.org/apacheds/basic-ug/1.4.3-adding-partition.html
- Introduciton in schema definition - https://www.zytrax.com/books//ldap/ch3/
LDAP Server
Implementierung : http://directory.apache.org/apacheds/
LDAP Client
Nice implementation: http://directory.apache.org/studio/
Standard structure
Standard structure. May look as following.
Under Organisational Units “groups” and “users” put the Posix-Groups and Posix-Users
Achtung: The default POSIX group “users” must be created first.
Because at least one Group's GID (group id) must be referenced during user creation.
After that you can create
Example configuration with Jenkins
- Exported partitition otm.intra.
- The groups are managed in a separate ou.
- The passwords (userPassword attributeType) are not mandatory, but have to be added as a separate attribute. Their values may be stored as saulted hashes.
version: 1 dn: ou=JenkinsAdmins,ou=groups,dc=otm,dc=intra objectclass: groupOfNames objectclass: top cn: JenkinsAdmins member: cn=admin,ou=users,dc=otm,dc=intra member: cn=alexander.friesen,ou=users,dc=otm,dc=intra member: cn=boris.jelzin,ou=users,dc=otm,dc=intra ou: JenkinsAdmins dn: cn=alexander.friesen,ou=users,dc=otm,dc=intra objectClass: person objectClass: top cn: alexander.friesen sn: alexander.friesen userPassword:: e1NIQX13dVFVZXE0NjJuODJnbWJRYzZ6VXFSV01XZlU9 dn: ou=users,dc=otm,dc=intra objectclass: organizationalUnit objectclass: top ou: users dn: cn=stas.archontov,ou=users,dc=otm,dc=intra objectclass: person objectclass: top cn: stas.archotov cn: stas.archontov sn: stas.archontov userPassword:: e1NIQX13dVFVZXE0NjJuODJnbWJRYzZ6VXFSV01XZlU9 dn: cn=boris.jelzin,ou=users,dc=otm,dc=intra objectclass: person objectclass: top cn: boris.jelzin sn: boris.jelzin userPassword:: e1NIQX13dVFVZXE0NjJuODJnbWJRYzZ6VXFSV01XZlU9 dn: ou=JenkinsHotSyncer,ou=groups,dc=otm,dc=intra objectclass: groupOfNames objectclass: top cn: JenkinsHotSyncer member: cn=admin,ou=users,dc=otm,dc=intra member: cn=stas.archontov,ou=users,dc=otm,dc=intra ou: JenkinsHotSyncer dn: ou=JenkinsSyncer,ou=groups,dc=otm,dc=intra objectclass: groupOfNames objectclass: top cn: JenkinsSyncer member: cn=admin,ou=users,dc=otm,dc=intra member: cn=stas.archontov,ou=users,dc=otm,dc=intra ou: JenkinsSyncer dn: cn=admin,ou=users,dc=otm,dc=intra objectClass: person objectClass: top cn: admin sn: admin userPassword:: e1NIQX13dVFVZXE0NjJuODJnbWJRYzZ6VXFSV01XZlU9 dn: dc=otm,dc=intra objectclass: top objectclass: domain dc: otm dn: ou=groups,dc=otm,dc=intra objectclass: organizationalUnit objectclass: top ou: groups
Configure Jenkins to use your LDAP server
Privilidges via ACLs - Access Control Lists
Beispiel
Attributes
uid User id cn Common Name sn Surname l Location ou Organisational Unit o Organisation dc Domain Component st State c Country dn distinguished name, like cn=sadique5,ou=people,dc=ldap,dc=example,dc=com
Search Scope
3 types of scope:
base limits to just the base object onelevel limits to just the immediate children sub search the entire subtree from base down
Filling LDAP manually without file from script
ldapadd -H "ldap://localhost" -c -x -D "cn=admin,dc=ldap,dc=example,dc=com" -w "Jpk66g63ZifGYIcShSGM" << EOF dn: cn=sadique5,ou=people,dc=ldap,dc=example,dc=com cn: sadique5 sn: sadique uid: sadique displayName: Sadique Puthen Peedikayil givenName: Sadique mail: sadique@vanillanetworks.com mobile: 9895643639 homePhone: 0466-2254274 objectClass: inetOrgPerson userPassword: Jpk66g63ZifGYIcShSGM EOF
OpenLDAP and phpldapadmin
Starting both in docker:
docker network create ldapnetwork sudo docker run --restart=always -td --net ldapnetwork -h "opendj" --env ROOT_USER_DN="cn=Directory Manager" --env OPENDJ_USER="opendj" --env BASE_DN="dc=project,dc=intra" --env ROOT_PASSWORD="123abc" -p 1389:1389 -p 1636:1636 -p 3000:4444 --name opendj openidentityplatform/opendj sudo docker run --restart=always --env PHPLDAPADMIN_LDAP_HOSTS="#PYTHON2BASH:[{'opendj': [{'server': [{'tls': False}, {'port': 1389}]}, {'login': [{'bind_id': 'cn=Directory Manager'}, {'bind_pass': '123abc'}]}]}]" --net ldapnetwork -p 4200:80 --env PHPLDAPADMIN_HTTPS=false --detach --name php osixia/phpldapadmin:0.7.2 --loglevel debug
Navigate to http://localhost:4200
Login with
Login DN: cn=Directory Manager Pass: 123abc
display the configs
slapcat -b cn=config
Or within contianer
docker exec ldap slapcat -b cn=config
LDAP with Spring
Spring LDAP reference: https://docs.spring.io/autorepo/docs/spring-ldap/current/reference/#dns-as-attribute-values
Examples:
Schema extension
This is an example for an extended schema
stored as local.schema
# local.schema -- aaainetOrgPerson # $OpenLDAP$ ## This work is part of OpenLDAP Software <http://www.openldap.org/>. ## ## Copyright 1998-2014 The OpenLDAP Foundation. ## All rights reserved. ## ## Redistribution and use in source and binary forms, with or without ## modification, are permitted only as authorized by the OpenLDAP ## Public License. ## ## A copy of this license is available in the file LICENSE in the ## top-level directory of the distribution or, alternatively, at ## <http://www.OpenLDAP.org/license.html>. # # aaainetOrgPerson # # Defines additional attributes required by the SSP # TODO: request and add unique Private Enterprise Number from IANA Services # attributetype ( 5.12.345.1.123456.3.1.321 NAME 'x-company-auth0userId' DESC 'the id identifying ofthe auth0 user' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 ) attributetype ( 5.12.345.1.123456.3.1.322 NAME 'x-company-auth0clientId' DESC 'the clientId of the machine to machine user' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 ) attributetype ( 5.12.345.1.123456.3.1.323 NAME 'x-company-tags' DESC 'the tags field containing all the tags without empty spaces' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 ) attributetype ( 5.12.345.1.123456.3.1.324 NAME 'x-company-b360id' DESC 'the building 360 identifier of a customer' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 ) objectclass ( 5.12.345.1.123456.3.1.2 NAME 'x-company-auth0subject' DESC 'auth0 service registered person or machine' AUXILIARY MAY ( x-company-auth0userId $ x-company-auth0clientId ) ) objectclass ( 5.12.345.1.123456.3.1.3 NAME 'x-company-hastags' DESC 'an object which has a tag' AUXILIARY MAY ( x-company-tags ) ) objectclass ( 5.12.345.1.123456.3.1.4 NAME 'x-company-b360customer' DESC 'b360 customer' AUXILIARY MAY ( x-company-b360id ) )
Here is how to build an OpenLdap container with extended schema
FROM osixia/openldap:1.2.4 RUN mkdir -p /container/service/slapd/assets/config/bootstrap/ldif/custom COPY ./ldif/ /container/service/slapd/assets/config/bootstrap/ldif/custom RUN mkdir -p /container/service/slapd/assets/config/bootstrap/schema COPY ./schema/local.schema /container/service/slapd/assets/config/bootstrap/schema/ COPY ./containerscripts/start.sh /usr/bin/start.sh ENTRYPOINT start.sh && /container/tool/run
Pooling with Spring Boot
The following code can be used, to activate Pooling (https://docs.spring.io/spring-ldap/docs/1.3.2.RELEASE/reference/html/pooling.html) in a
- SpringBoot application - using Spring Data to talk to the Ldap server
The important part missing up there - was to pass the `PoolingContextSource` to the `LdapTemplate`
see `new LdapTemplate(poolingLdapContextSource());` in
@PropertySource("ldap-${spring.profiles.active}.properties") @Configuration public class LdapConfiguration { private static Logger LOG = LoggerFactory.getLogger(LdapConfiguration.class); @Autowired private Environment env; @Bean public LdapContextSource contextSource() { LdapContextSource contextSource = new LdapContextSource(); contextSource.setUrl(env.getRequiredProperty("ldap.url")); contextSource.setBase(env.getRequiredProperty("ldap.base")); contextSource.setUserDn(env.getRequiredProperty("ldap.user")); contextSource.setPassword(env.getRequiredProperty("ldap.password")); contextSource.setPooled(false); // Robert improved the performance by 100x for PARALLEL requests by enabling that Map<String, Object> environment = new HashMap<>(); // DEBUGGING environment.put("com.sun.jndi.ldap.connect.pool.debug", "fine"); // many debug infos contextSource.setBaseEnvironmentProperties(environment); return contextSource; } /** * Configure the LDAP connection pool to * validate connections https://docs.spring.io/spring-ldap/docs/1.3.2.RELEASE/reference/html/pooling.html * * so that the connections do not expire in pool * * @return */ @Bean public ContextSource poolingLdapContextSource() { PoolingContextSource poolingContextSource = new PoolingContextSource(); poolingContextSource.setDirContextValidator(new DefaultDirContextValidator()); poolingContextSource.setContextSource(contextSource()); poolingContextSource.setTestOnBorrow(true); poolingContextSource.setTestWhileIdle(true); poolingContextSource.setTimeBetweenEvictionRunsMillis(60000); poolingContextSource.setNumTestsPerEvictionRun(3); TransactionAwareContextSourceProxy proxy = new TransactionAwareContextSourceProxy(poolingContextSource); return proxy; } @Bean public LdapTemplate ldapTemplate() { LdapTemplate ldapTemplate = new LdapTemplate(poolingLdapContextSource()); ldapTemplate.setIgnoreNameNotFoundException(true); return ldapTemplate; } }