Skip to content

daggerok/spring-data-ldap-example

Repository files navigation

Spring + LDAP CI

Play with LDAP in Docker using Spring java APIs...

LDAP basics (docker)

defaults

# run LDAP server (dy default: Example Inc. with example.org domain):
docker run -p 389:389 -p 636:636 --rm -it --name ldap osixia/openldap:1.3.0

# exec LDAP query:
docker exec ldap ldapsearch -x -H ldap://localhost:389 -b dc=example,dc=org -D "cn=admin,dc=example,dc=org" -w admin

customize

docker run -p 389:389 -p 636:636 --rm -it --name ldap \
  --env LDAP_ORGANISATION="My Test Company Inc." \
  --env LDAP_DOMAIN="my-test-company-domain.com" \
  osixia/openldap:1.3.0

# exec query
docker exec ldap ldapsearch -x -H ldap://localhost:389 -b dc=my-test-company-domain,dc=com -D "cn=admin,dc=my-test-company-domain,dc=com" -w admin

step: 0

let's prepare LDAP in Docker by using osixia solution.

create step-0-hello-ldap/ldap/Dockerfile file:

FROM osixia/openldap-backup:1.3.0
LABEL MAINTAINER="Maksim Kostromin <daggerok@gmail.com> https://githuib.com/daggerok/spring-data-ldap-example"
ENTRYPOINT ["/bin/bash"]
CMD ["-c", "/container/tool/run --copy-service -l debug"]
COPY --chown=openldap:openldap ./test-data.ldif /container/service/slapd/assets/config/bootstrap/ldif/50-test-data.ldif

create step-0-hello-ldap/ldap/test-data.ldif file:

version: 1

# Entry: uid=user,dc=my-test-company-domain,dc=com
# user: uid=user,dc=my-test-company-domain,dc=com
# password: password
dn: uid=user,dc=my-test-company-domain,dc=com
uid: user
cn: user
sn: 3
description: My Test Company LDAP user organization account
objectclass: top
objectClass: inetOrgPerson
mail: user@my-test-company-domain.com
userPassword: password

# Entries already exists / provided by docker container:
# Entry 1: dc=my-test-company-domain,dc=com
# Entry 2: cn=admin,dc=my-test-company-domain,dc=com
# Admin user: cn=admin,dc=my-test-company-domain,dc=com
# Admin password: adm1nZupperUberP@assw0rd!!1111oneoneone

create step-0-hello-ldap/docker-compose.yaml file:

version: '2.1'
networks:
  my-test-company-domain.com:
services:
  ldap:
    hostname: ldap.my-test-company-domain.com
    build: ./ldap
    environment:
      LDAP_ORGANISATION: My Test Company Inc.
      LDAP_DOMAIN: my-test-company-domain.com
      LDAP_ADMIN_PASSWORD: adm1nZupperUberP@assw0rd!!1111oneoneone
      LDAP_BACKUP_CONFIG_CRON_EXP: '* * * * *'
      LDAP_BACKUP_DATA_CRON_EXP: '*/15 * * * *'
      LDAP_BACKUP_TTL: 7
    ports:
    - '389:389'
    - '636:636'
    networks:
      my-test-company-domain.com:
        aliases:
          - ldap
          - ldap.my-test-company-domain.com
    healthcheck:
      test: ( ( test 1 -eq `ss -tulwn | grep '0.0.0.0:389' | wc -l` ) && ( test 1 -eq `ss -tulwn | grep '0.0.0.0:636' | wc -l` ) ) || exit 1
      interval: 5s
      timeout: 5s
      retries: 55
  # omit ldap-admin-uiand step-0-hello-ldap definitions...

add dependencies in step-0-hello-ldap/pom.xml file:

<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-ldap</artifactId>
  </dependency>
</dependencies>

add configurations in step-0-hello-ldap/src/main/resources/application.properties file:

spring.ldap.urls=ldap://${LDAP_HOST:127.0.0.1}:${LDAP_PORT:389}
spring.ldap.username=${LDAP_USER:cn=admin,dc=my-test-company-domain,dc=com}
spring.ldap.password=${LDAP_PASSWORD:adm1nZupperUberP@assw0rd!!1111oneoneone}
spring.ldap.base=dc=my-test-company-domain,dc=com

implement java app:

@Log4j2
@RestController
@RequiredArgsConstructor
class LdapResource {

  final LdapTemplate ldapTemplate;

  @RequestMapping("/")
  ResponseEntity<?> index(@RequestBody(required = false) Optional<LinkedHashMap<String, String>> request) {
    var query = request.map(map -> map.get("query"))
                       .orElse("objectClass=inetOrgPerson");

    if (!query.contains("=")) return ResponseEntity
        .badRequest().body(Collections.singletonMap("error", "Invalid query. Use key=value format!"));

    String[] kv = query.split("=");
    var searchResults = ldapTemplate.search(
        LdapQueryBuilder.query().where(kv[0]).is(kv[1]),
        (AttributesMapper<Collection<String>>) attributes -> {
          Iterator<? extends Attribute> iterator = attributes.getAll().asIterator();
          return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED), false)
                              .map(String::valueOf)
                              .collect(Collectors.toList());
        }
    );

    return ResponseEntity.ok()
                         .body(searchResults.stream()
                                            .flatMap(Collection::stream)
                                            .collect(Collectors.toList()));
  }
}

simplify testing for all boiler-plates with docker-compose:

./mvnw -f step-0-hello-ldap clean package spring-boot:build-image docker-compose:up
http :8080
http :8080 query=objectClass=top
./mvnw -f step-0-hello-ldap docker-compose:down

resources