Spring LDAP の基本的な使い方 (Spring Boot)
[最終更新] (2019/06/03 00:35:36)
プログラミング/IoT の関連商品 (Amazonのアソシエイトとして、当メディアは適格販売により収入を得ています。)
最近の投稿
注目の記事

概要

こちらのページでは、Java のソースコードにハードコーディングしたユーザーとパスワードの情報をもとに、Spring Security でログインフォーム認証を行いました。本ページではユーザー認証を LDAP サーバーからの情報をもとに行います。

Spring LDAP が提供する LDAP クライアントを Spring Boot から利用します。LDAP サーバーは、Spring Boot のドキュメントに記載のある UnboundID を利用します。メモリ上で動作し、アプリケーション起動時にリソースファイルをもとに初期化される、開発時に便利な簡易サーバーです。

公式ドキュメント

LDAP について

解説動画 Spring LDAP 2.0.0

サンプルプロジェクト

基本的な Gradle プロジェクトです。

.
|-- build.gradle
|-- gradle
|   `-- wrapper
|       |-- gradle-wrapper.jar
|       `-- gradle-wrapper.properties
|-- gradlew
|-- gradlew.bat
`-- src
    `-- main
        |-- java
        |   `-- hello
        |       |-- Application.java
        |       |-- HelloController.java
        |       `-- WebSecurityConfig.java
        `-- resources
            |-- application.yml
            `-- test-server.ldif

build.gradle

buildscript {
    ext {
        springBootVersion = '1.5.3.RELEASE'
    }
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
    }
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'org.springframework.boot'

jar {
    baseName = 'gs-spring-boot'
    version =  '0.1.0'
}

repositories {
    mavenCentral()
}

sourceCompatibility = 1.8
targetCompatibility = 1.8

dependencies {
    compile('org.springframework.boot:spring-boot-starter-web')
    compile('org.springframework.boot:spring-boot-starter-security')
    compile('org.springframework.boot:spring-boot-starter-data-ldap')
    compile('org.springframework.security:spring-security-ldap')
    compile('com.unboundid:unboundid-ldapsdk') // UnboundId, an open source LDAP server.
}

src/main/resources/application.yml

アプリケーション設定ファイルにアプリ内蔵の簡易 LDAP サーバ UnboundID の設定を追加します。

spring:
  ldap:
    embedded:
      base-dn: dc=springframework,dc=org
      ldif: classpath:test-server.ldif
      port: 8389

src/main/java/hello/Application.java

アノテーションの意味についてはこちらをご参照ください。

package hello;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

src/main/java/hello/HelloController.java

HTTP レスポンスのボディで返す文字列を直接コントローラで指定する @RestController アノテーションを利用しています。

package hello;

import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;

@RestController
public class HelloController {

    @RequestMapping("/")
    public String index() {
        return "Greetings from Spring Boot!";
    }
}

src/main/java/hello/WebSecurityConfig.java

Spring Security の利用時と同様に、@EnableWebSecurity アノテーションが設定されて WebSecurityConfigurerAdapter を継承したクラスで Spring Security の既定の挙動をカスタマイズできます。

  • .authorizeRequests() すべてのエンドポイントで認証が必要になるように設定しています。
  • .formLogin() ログイン認証用のエンドポイントが自動生成されるように設定しています。既定値のパス /login に対する HTML ログインフォームページが生成されます。
  • .ldapAuthentication() ログイン認証で LDAP サーバからの情報を利用するように設定しています。入力されたユーザー名は uid={0} で LDAP 検索時に利用されます。入力されたパスワードは LdapShaPasswordEncoder()ハッシュ値を計算して、属性名 userPassword の値と比較されます。

WebSecurityConfig.java

package hello;

import java.util.Arrays;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.encoding.LdapShaPasswordEncoder;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .anyRequest().fullyAuthenticated()
                .and()
            .formLogin();
    }

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
            .ldapAuthentication()
                .userDnPatterns("uid={0},ou=people")
                .groupSearchBase("ou=groups")
                .contextSource(contextSource())
                .passwordCompare()
                    .passwordEncoder(new LdapShaPasswordEncoder())
                    .passwordAttribute("userPassword");
    }

    @Bean
    public DefaultSpringSecurityContextSource contextSource() {
        return new DefaultSpringSecurityContextSource(Arrays.asList("ldap://localhost:8389/"), "dc=springframework,dc=org");
    }
}

src/main/resources/test-server.ldif

Spring LDAP チュートリアルに記載の LDIF (LDAP Data Interchange Format) 情報をそのまま利用します。ログインユーザー名は ben、パスワードは benspassword です。

dn: dc=springframework,dc=org
objectclass: top
objectclass: domain
objectclass: extensibleObject
dc: springframework

...

dn: uid=ben,ou=people,dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: Ben Alex
sn: Alex
uid: ben
userPassword: {SHA}nFCebWjxfaLbHHG1Qk5UU4trbvQ=

...
  • dn Distinguished Name → ディレクトリ内で一意に識別するための値
  • dc Domain Component → ドメインを構成するための要素 (例えば www.google.comdc=www,dc=google,dc=com となります)
  • ou Organizational Unit → あるドメイン内の組織
  • cn Common Name → ある組織内の人やもの

LDAP クライアントの使い方

上記サンプルプロジェクトでは、LDAP クライアントを Spring Security の認証で、あまり意識することなく内部的に利用しました。以下では、Spring LDAP が提供する LDAP クライアントを直接利用するサンプルコードをまとめます。簡単のため、HelloController.java 内で LDAP クライアントを利用しますが、実際のアプリケーションでは @Repository Bean や @Service Bean で利用する設計が好ましいとされます。

CN 一覧を検索

src/main/resources/application.yml

LDAP サーバーへの接続に必要な情報を設定します。LdapContextSource に値が設定されて @Autowired した LdapTemplate で利用されます。

spring:
  ldap:
    embedded:
      base-dn: dc=springframework,dc=org
      ldif: classpath:test-server.ldif
      port: 8389
    context-source:
      url: ldap://localhost:8389
      base: dc=springframework,dc=org
      username:
      password:

src/main/java/hello/HelloController.java

今回のサンプルでは扱いませんが、context-source の値を動的にリクエスト毎に設定したい場合は、LdapContextSource を new で新規に生成して、それを引数に LdapTemplate を new で新規に生成して利用します。LdapTemplate@Autowired は行いません。

package hello;

import static org.springframework.ldap.query.LdapQueryBuilder.query;

import java.util.List;

import javax.naming.NamingException;
import javax.naming.directory.Attributes;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ldap.core.AttributesMapper;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @Autowired
    private LdapTemplate ldapTemplate;

    public List<String> getAllPersonNames() {
        return ldapTemplate.search(
            query().where("objectclass").is("person"),
            new AttributesMapper<String>() {
                public String mapFromAttributes(Attributes attrs) throws NamingException {
                    return (String) attrs.get("cn").get();
                }
            });
    }

    @RequestMapping("/")
    public String index() {
        return getAllPersonNames().toString();
    }
}

レスポンス例

[quote\"guy, Joe Smeth, Mouse, Jerry, slash/guy, Ben Alex, Bob Hamilton, Space Cadet]

1000 件を越えるデータを取得する

この続きが気になる方は

Spring LDAP の基本的な使い方 (Spring Boot)

残り文字数は全体の約 20 %
tybot
100 円
関連ページ
    概要 Spring フレームワークによる Web アプリケーション開発で、ログイン処理を実装する際は Spring Security が便利です。ここでは特に、こちらのページに記載の Spring Boot で Web アプリケーションを開発する場合を対象とし、フォームによる ID/Password ログインを行うためのサンプルコードをまとめます。