Guide_Authenticating a User with LDAP

Dev.Hammy·2023년 12월 12일
0

Spring Guides

목록 보기
6/46

https://docs.spring.io/spring-ldap/docs/current/reference/

이 가이드는 애플리케이션을 생성하고 Spring Security LDAP 모듈로 보안을 유지하는 프로세스를 안내합니다.

LDAP

LDAP란?

  • 네트워크 프로토콜로, 디렉터리 서비스에 접근하는 데 사용
  • 디렉터리 서비스: 사용자, 컴퓨터, 리소스와 같은 데이터를 저장하고 관리
  • 표준화된 방식으로 데이터 읽기, 변경

LDAP의 주요 용도

  • 사용자 인증
  • 디렉터리 검색
  • 이메일 클라이언트 설정
  • 인터넷 서비스

LDAP의 특징

  • 계층적인 구조로 정보 저장
  • 간단하고 확장 가능
  • 기업 환경에서 인프라로 사용
  • 유연, 보안 강화, 중앙 집중식 디렉터리 서비스 제공

LDAP의 장점

  • 표준화된 방식으로 디렉터리 서비스에 접근 가능
  • 다양한 용도로 사용 가능
  • 계층적인 구조로 정보 관리 효율적
  • 보안 강화
  • 중앙 집중식 디렉터리 서비스 제공

LDAP의 단점

  • 데이터 저장에 비용이 많이 들 수 있음
  • 성능이 저하될 수 있음

LDAP의 활용 사례

  • Active Directory
  • OpenLDAP
  • Red Hat Directory Server
  • 389 Directory Server

What You Will Build

Spring Security에 내장된 Java 기반 LDAP 서버로 보호되는 간단한 웹 애플리케이션을 구축합니다. 사용자 집합이 포함된 데이터 파일을 사용하여 LDAP 서버를 로드합니다.

First, Build an Unsecured Web Application

build.gradle

plugins {
    id 'java'
    id 'org.springframework.boot' version '3.2.0'
    id 'io.spring.dependency-management' version '1.1.4'
}

group = 'guides'
version = '0.0.1-SNAPSHOT'

java {
    sourceCompatibility = '17'
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

tasks.named('test') {
    useJUnitPlatform()
}

Create a Simple Web Controller

Spring에서 REST 엔드포인트는 Spring MVC 컨트롤러입니다. 다음 Spring MVC 컨트롤러(src/main/java/guides/authenticatingldap/HomeController.java)는 간단한 메시지를 반환하여 GET / 요청을 처리합니다.

package guides.authenticatingldap;

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

@RestController
public class HomeController {

    @GetMapping("/")
    public String index() {
        return "Welcome to the home page!";
    }

}

전체 클래스는 @RestController로 표시되어 Spring MVC가 컨트롤러를 자동 감지하고(내장된 검색 기능을 사용하여) 필요한 웹 경로를 자동으로 구성할 수 있습니다.

@RestController는 또한 뷰가 없기 때문에 Spring MVC에게 텍스트를 HTTP 응답 본문에 직접 쓰라고 지시합니다. 대신 페이지를 방문하면 브라우저에 간단한 메시지가 표시됩니다(이 가이드의 초점은 LDAP로 페이지를 보호하는 것이기 때문입니다).

Build the Unsecured Web Application

보안되지 않은 웹 애플리케이션 구축
웹 애플리케이션을 보호하기 전에 웹 애플리케이션이 작동하는지 확인해야 합니다. 그렇게 하려면 몇 가지 핵심 Bean을 정의해야 하며, 이는 Application 클래스를 생성하여 수행할 수 있습니다. 다음 목록(src/main/java/guides/authenticatingldap/AuthenticatingLdapApplication.java)은 해당 클래스를 보여줍니다.

package guides.authenticatingldap;

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

@SpringBootApplication
public class AuthenticatingLdapApplication {

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

}

브라우저를 열고 http://localhost:8080을 방문하면 다음 일반 텍스트가 표시됩니다.

Set up Spring Security

Spring Security를 구성하려면 먼저 빌드에 몇 가지 추가 종속성을 추가해야 합니다.

implementation("org.springframework.boot:spring-boot-starter-security")
implementation("org.springframework.ldap:spring-ldap-core")
implementation("org.springframework.security:spring-security-ldap")
implementation("com.unboundid:unboundid-ldapsdk")

Gradle의 아티팩트 해결 문제로 인해 spring-tx를 가져와야 합니다. 그렇지 않으면 Gradle이 작동하지 않는 이전 버전을 가져옵니다.

implementation 'org.springframework:spring-tx:6.1.0'

이러한 종속성은 Spring Security와 오픈 소스 LDAP 서버인 UnboundId를 추가합니다. 이러한 종속성이 적용되면 다음 예제(src/main/java/guides/authenticatingldap/WebSecurityConfig.java)에 표시된 대로 순수 Java를 사용하여 보안 정책을 구성할 수 있습니다.

WebSecurityConfig

또한 LDAP 서버가 필요합니다. Spring Boot은 순수 Java로 작성된 내장 서버에 대한 자동 구성을 제공하며, 이 가이드에서 사용됩니다. ldapAuthentication() 메서드는 로그인 폼의 사용자 이름을 {0}에 삽입하여 uid={0},ou=people,dc=springframework,dc=org 형태로 LDAP 서버에서 검색하도록 설정합니다. 또한 passwordCompare() 메서드는 인코더와 암호 속성의 이름을 구성합니다.

package guides.authenticatingldap;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
public class WebSecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .anyRequest().fullyAuthenticated()
                .and()
                .formLogin();

        return http.build();
    }

    @Autowired
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
                .ldapAuthentication()
                .userDnPatterns("uid={0},ou=people")
                .groupSearchBase("ou=groups")
                .contextSource()
                .url("ldap://localhost:8389/dc=springframework,dc=org")
                .and()
                .passwordCompare()
                .passwordEncoder(new BCryptPasswordEncoder())
                .passwordAttribute("userPassword");
    }

}

//@Configuration
//public class WebSecurityConfig {

//  @Bean
//  public SecurityFilterChain configure(HttpSecurity http) throws Exception {
//    return http
//      .authorizeRequests()
//      .anyRequest().authenticated()
//      .and()
//      .formLogin(Customizer.withDefaults())
//      .build();
//  }
//}

주석 처리된 코드는 Spring Security 5.7 이전 버전에서 사용되던 코드입니다. Spring Security 5.7부터는 SecurityFilterChain 인터페이스를 사용하여 컨피규레이션해야 하므로 기존 코드는 더 이상 사용되지 않습니다.

주석 처리된 코드와 현재 코드의 차이점은 다음과 같습니다:

  1. 인증 방식:

    • 주석 처리된 코드: anyRequest().authenticated()
    • 현재 코드: anyRequest().fullyAuthenticated()
  2. formLogin 사용:

    • 주석 처리된 코드: formLogin(Customizer.withDefaults())
    • 현재 코드: 명시적으로 설정하지 않음
  3. LDAP 인증 설정:

    • 주석 처리된 코드: ldapAuthentication()에 설정 포함
    • 현재 코드: configure(AuthenticationManagerBuilder) 메서드에 설정 분리

현재 코드는 SecurityFilterChain 인터페이스를 사용하여 컨피규레이션을 구성하고, anyRequest().fullyAuthenticated() 메서드를 사용하여 모든 요청에 대해 완전한 인증(인증 및 권한 부여)을 요구합니다. 또한, formLogin 설정을 명시적으로 설정하지 않아 Spring Security의 기본 폼 로그인 기능을 사용합니다.

주석 처리된 코드는 anyRequest().authenticated() 메서드를 사용하여 모든 요청에 대해 단순히 인증만 요구합니다. 또한, formLogin(Customizer.withDefaults()) 메서드를 사용하여 Spring Security의 기본 폼 로그인 기능을 사용합니다.

따라서, Spring Security 5.7 이후 버전에서는 주석 처리된 코드 대신 현재 코드를 사용하는 것이 좋습니다.

Add Application Properties

Spring LDAP에서는 application.properties 파일에 세 가지 애플리케이션 속성을 설정해야 합니다.

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

Set up User Data

LDAP 서버는 LDIF(LDAP Data Interchange Format) 파일을 사용하여 사용자 데이터를 교환할 수 있습니다. application.properties 내의 spring.ldap.embedded.ldif 속성을 사용하면 Spring Boot가 LDIF 데이터 파일을 가져올 수 있습니다. 이를 통해 데모 데이터를 쉽게 사전 로드할 수 있습니다. 다음 목록(src/main/resources/test-server.ldif에 있음)은 이 예에서 작동하는 LDIF 파일을 보여줍니다.

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

dn: ou=groups,dc=springframework,dc=org
objectclass: top
objectclass: organizationalUnit
ou: groups

dn: ou=subgroups,ou=groups,dc=springframework,dc=org
objectclass: top
objectclass: organizationalUnit
ou: subgroups

dn: ou=people,dc=springframework,dc=org
objectclass: top
objectclass: organizationalUnit
ou: people

dn: ou=space cadets,dc=springframework,dc=org
objectclass: top
objectclass: organizationalUnit
ou: space cadets

dn: ou=\"quoted people\",dc=springframework,dc=org
objectclass: top
objectclass: organizationalUnit
ou: "quoted people"

dn: ou=otherpeople,dc=springframework,dc=org
objectclass: top
objectclass: organizationalUnit
ou: otherpeople

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: $2a$10$c6bSeWPhg06xB1lvmaWNNe4NROmZiSpYhlocU/98HNr2MhIOiSt36

dn: uid=bob,ou=people,dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: Bob Hamilton
sn: Hamilton
uid: bob
userPassword: bobspassword

dn: uid=joe,ou=otherpeople,dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: Joe Smeth
sn: Smeth
uid: joe
userPassword: joespassword

dn: cn=mouse\, jerry,ou=people,dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: Mouse, Jerry
sn: Mouse
uid: jerry
userPassword: jerryspassword

dn: cn=slash/guy,ou=people,dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: slash/guy
sn: Slash
uid: slashguy
userPassword: slashguyspassword

dn: cn=quote\"guy,ou=\"quoted people\",dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: quote\"guy
sn: Quote
uid: quoteguy
userPassword: quoteguyspassword

dn: uid=space cadet,ou=space cadets,dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: Space Cadet
sn: Cadet
uid: space cadet
userPassword: spacecadetspassword



dn: cn=developers,ou=groups,dc=springframework,dc=org
objectclass: top
objectclass: groupOfUniqueNames
cn: developers
ou: developer
uniqueMember: uid=ben,ou=people,dc=springframework,dc=org
uniqueMember: uid=bob,ou=people,dc=springframework,dc=org

dn: cn=managers,ou=groups,dc=springframework,dc=org
objectclass: top
objectclass: groupOfUniqueNames
cn: managers
ou: manager
uniqueMember: uid=ben,ou=people,dc=springframework,dc=org
uniqueMember: cn=mouse\, jerry,ou=people,dc=springframework,dc=org

dn: cn=submanagers,ou=subgroups,ou=groups,dc=springframework,dc=org
objectclass: top
objectclass: groupOfUniqueNames
cn: submanagers
ou: submanager
uniqueMember: uid=ben,ou=people,dc=springframework,dc=org

LDIF 파일 사용은 프로덕션 시스템의 표준 구성이 아닙니다. 그러나 테스트 목적이나 가이드에는 유용합니다.

실행해보기

http://localhost:8080 사이트에 접속하면 Spring Security에서 제공하는 로그인 페이지로 이동하게 된다.

사용자 이름 ben과 비밀번호 benspassword를 입력합니다. 브라우저에 다음 메시지가 표시되어야 합니다.

0개의 댓글