티스토리 뷰
웹 사이트 및 웹 애플리케이션 사용권한을 특정 클라이언트에게만 권한을 부여하고 싶을 때가 있습니다. 주로 많이 사용하는 방법 중 하나는 로그인을 도입하는 것이죠. 로그인을 할 때, 아이디와 패스워드만 있으면, 어떠한 클라이언트라도 웹 사이트 접근을 허용할 수 있습니다. 권한이 부여된 유저에게만 접근을 인가하는 방식을 보안(Security)라고 합니다. Spring에는 다양한 Security 모듈을 지원하는데, 그중 LDAP를 이용한 보안인증방법에 대하여 포스팅을 진행해보도록 하겠습니다.
Springboot LDAP용 프로젝트 다운로드
https://start.spring.io/ 에서 Spring Web 디펜던시만 추가하여, 프로젝트를 다운로드합니다.
다음으로, 보안을 적용하기 전에 앞서 간단한 문자열을 출력하는 웹 애플리케이션을 작성해보겠습니다.
웹 애플리케이션 작성하기
SpringBoot에서 Endpoint를 처리한 MVC Controller를 작성해보겠습니다. 아래 클래스에 작성된 컨트롤러는 사이트 URL에 접속하면 "Welcome to the home page!"를 출력하는 내용입니다. HomeController클래스 상단에 작성된 @RestController 어노테이션은 HTTP 응답 시, ResponseBody에 컨텍스트를 담아 반환하는 클래스임을 명시하는 것입니다. 여기서는 "/"경로에 접근할 경우, ResponseBody에 "Welcome to the home page!" 텍스트가 포함되어 응답합니다.
package com.example.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!";
}
}
HomeController를 실행할 Main클래스를 아래와 같이 작성합니다.
package com.example.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);
}
}
SpringBoot 애플리케이션을 실행하면 아래와 같이 실행 로그가 기록되고, localhost에 접근하면 앞서 작성한 문자열이 반환되는 것을 확인할 수 있습니다.
localhost:8080에 접근 시, 접근이 인가된 유저에게만 문자열을 볼 수 있도록 LDAP를 이용하여 보안을 적용해보겠습니다.
LDAP를 이용한 보안 적용
LDAP란 Lightweight Directory Access Protocol의 약자이고, 경량 디렉터리 접근 프로토콜입니다. LDAP는 X.500이라는 Directory Access Protocol의 경량화된 버전이라고 불리며, TCP/IP Layer위에서 동작합니다. 그러므로, HTTP 프로토콜과 유사하게 Request, Reponse를 가지며, 프로토콜 Schema도 ldap://xxxx.xxxx.xx:port와 같은 형태로 URL이 정의되므로, HTTP와 유사한 점이 많습니다. HTTP는 익명의 누군가라도 Request를 전송하고, Response를 받아 정보를 받을 수 있는 반면, LDAP는 인증된 유저에 대해서만 Request에 대한 Response을 받을 수 있습니다. 그리고, HTTP은 평문(Plain Text)으로 전송하여, 패킷을 가로채면 누구나 해당 내용을 확인이 가능하지만, LDAP는 전송 데이터에 대한 Base64와 같은 인코딩이 적용되어 Binary 포맷으로 데이터를 전송합니다. 그러므로, HTTP보단 LDAP가 보안성이 더 좋겠죠? LDAP는 LDIF(LDAP Data Interchange Format) 데이터 포맷으로 데이터를 데이터베이스에 저장합니다. 데이터 저장 구성요소는 아래와 같습니다.
- LDAP는 Tree 구조로 데이터를 저장함
- Entry > Attribute > Type, Value > dn, cn, ou, dc, rdn (A > B는 A는 B의 부분집합)
- Entry : Tree를 식별하는 단위
- Attribute : Entry를 구성하는 노드 단위, Type과 Value로 구성됨
- Type : dn, cn, ou, dc, rdn과 같은 Type이 존재함.
- Value : Type에 대한 값을 나타냄
이러한 LDIF를 LDAP로 요청을 받고 처리하는 Directory Server가 있는데, 해당 서버에서는 데이터를 Tree 구조로 저장하므로 NoSQL의 일종으로도 볼 수 있습니다. LDAP도 HTTP Method와 같이 조회, 추가, 삭제, 수정과 같은 연산을 지원합니다. LDAP에 대해 자세히 알아보고 싶으신 분은 아래 링크 참조 바랍니다.
LDAP에 대한 개략적인 설명은 이것으로 마치고, 다시 본론으로 돌아와 SpringBoot에서 LDAP를 적용하는 방법에 대해 알아보겠습니다.
Build.gradle 파일에 LDAP사용을 위한 디펜던시를 추가해줍니다.
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")
다음으로, LDAP 설정을 위한 속성 설정 클래스 파일을 작성해줍니다.
package com.example.authenticatingldap;
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.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@Configuration
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()
.url("ldap://localhost:8389/dc=springframework,dc=org")
.and()
.passwordCompare()
.passwordEncoder(new BCryptPasswordEncoder())
.passwordAttribute("userPassword");
}
}
WebSecurityConfigurerAdapter 클래스를 상속받아 LDAP를 설정합니다. SpringBoot에는 LDAP Server가 내장되어 있어, 별도로 LDAP 서버를 구축하고 생성하지 않아도 됩니다. 다음으로 웹 사이트에 접근 가능한 유저 데이터를 등록해보겠습니다. 우선 application.properties에 ldif 환경설정 내용을 작성합니다.
spring.ldap.embedded.ldif=classpath:test-server.ldif
spring.ldap.embedded.base-dn=dc=springframework,dc=org
spring.ldap.embedded.port=8389
유저 정보는 src/main/resources/test-server.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
http://localhost:8080에 접속하면, LDAP 인증 사이트로 리다이렉션 되어, 로그인을 수행해야 합니다.
WebSecurityConfig에서 passwordEncryt를 BCrypt방식을 사용하도록 되어 있어, test-server.ldif 파일 중 uid가 ben이고 userPassword 항목이 인코딩 된 항목이 있는데, 이는 디코딩하면 benspassword이고, LDAP 인증 사이트에서 ID는 ben, Password를 benspassword를 입력하면 최초에 보았던 welcom to the home page! 문구가 정상적으로 출력됩니다. 이로서, 웹 애플리케이션에 LDAP 보안을 적용하였습니다.
이상으로 SpringBoot에서 LDAP 보안 적용하는 법에 대해 알아보았습니다.
'IT 기술' 카테고리의 다른 글
구글 서치콘솔 현재 색인이 생성되지 않음 제외됨 해결방법 (0) | 2022.08.25 |
---|---|
SpringBoot 웹 페이지 보안 로그인 적용하기 (0) | 2022.08.16 |
티스토리 블로그를 구글 검색에 등록하는 방법 (0) | 2022.08.16 |
Springboot에서 ActiveMQ로 메세시 송수신하기 (0) | 2022.08.09 |
Springboot에서 Form Input 값 어노테이션으로 검증하기 (0) | 2022.08.08 |
- Total
- Today
- Yesterday
- springboot 실행
- 스프링부트빌드
- C++
- AWS
- MPA
- OSI 7계층
- 스프링부트 restapi
- token
- codesmell 유형
- SPA
- springboot restapi
- notion 업무일정관리
- selenium
- notion
- iframe 태그 찾기
- oracle 메모리
- springboot rest api 서버
- TCP/UDP
- 클린코드작성원칙
- springboot build
- 클린코드작성법
- API Gateway 캐싱
- oracle pga sga
- 디자인패턴
- 테스팅 자동화
- 디자인패턴 구조패턴
- python
- 멀티코어 멀티프로세서
- 스프링부트실행
- 코드스멜 유형
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |