IBM®
메인 컨텐츠로 가기
    Korea [국가변경]    이용약관
 
 
   
        제품    서비스 & 솔루션    고객지원 & 다운로드    회원 서비스    
메인 컨텐츠로 가기

한국 developerWorks  >  자바 | 오픈 소스  >

Acegi로 자바 애플리케이션 보안화 하기, Part 2: LDAP 디렉토리 서버 사용하기 (한글)

ApacheDS와 Acegi를 이용한 액세스 컨트롤

developerWorks
문서 옵션

JavaScript가 필요한 문서 옵션은 디스플레이되지 않습니다.

샘플 코드

영어원문

영어원문


제안 및 의견
피드백

난이도 : 초급

Bilal Siddiqui , Freelance consultant, WaxSys

2008 년 1 월 15 일

Part 1을 기반으로, Acegi Security System의 고급 사용법을 배울 차례가 되었습니다. 이 글에서, Bilal Siddiqui는 유연한 고성능 ™ 자바 애플리케이션 보안을 위해 Acegi와 LDAP 디렉토리 서버를 결합하는 방법을 설명합니다. 액세스 컨트롤 정책을 작성하고, 이것을 ApacheDS에 저장하고 나서, 인증과 권한에 디렉토리 서버와 인터랙팅 하도록 Acegi를 설정하는 방법을 설명합니다.

본 시리즈의 첫번째 기술자료에서는 Acegi Security System을 사용하여 자바 엔터프라이즈 애플리케이션을 보안화 하는 방법을 설명하고 있다. 본 시리즈 첫 번째 기술자료에서는, Acegi를 소개했고, 보안 필터를 사용하여 간단한 URL 기반의 보안 시스템을 구현하는 방법을 설명했다. 두 번째 시간에는, Acegi의 고급 사용법을 설명하고자 한다. 액세스 컨트롤 정책을 작성하여 이것을 오픈 소스 LDAP 디렉토리 서버인 ApacheDS에 저장하는 방법을 설명한다. 또한, 디렉토리 서버와 인터랙팅 하도록 Acegi를 설정하여 액세스 컨트롤 정책을 실행한다. 후반부에는, ApacheDS와 Acegi를 사용하여 안전한 액세스 컨트롤 정책을 실행하는 예제 애플리케이션을 제공할 것이다.

소셜 북마크

mar.gar.in mar.gar.in
digg Digg
del.icio.us del.icio.us
Slashdot Slashdot

액세스 컨트롤 정책을 실행하는 것은 일반적으로 두 단계로 구성되어 있다:

  1. 디렉토리 서버에 사용자와 그 역할에 관한 데이터를 저장하기.
  2. 누가 액세스 하여, 데이터를 사용하는지를 정의하는 보안 코드 작성하기.

Acegi에서는 여러분이 코드를 작성하지 않아도 되므로, 이 글에서는, ApacheDS에 사용자와 역할 정보를 저장하고, 그 정보에 대해 액세스 컨트롤 정책을 실행하는 방법을 설명하겠다. 본 시리즈 마지막 기술자료에서는, 자바 클래스로의 액세스를 보안화 하도록 Acegi를 설정하는 방법을 설명하겠다.

샘플 애플리케이션을 다운로드 하라. 참고자료 섹션에서 Acegi, Tomcat, ApacheDS를 다운로드 하는데, 이것은 샘플 코드와 예제 애플리케이션을 실행하는데 필요한 것들이다.

LDAP 기초

Lightweight Directory Access Protocol (LDAP)은 디렉토리 서버에 저장된 정보를 읽기, 편집, 검색, 삭제하는 것 같은 일반적인 디렉토리 연산을 위한 데이터 포맷을 정의하는 가장 일반적인 프로토콜이다. 이 섹션에서는 디렉토리 서버가 보안 정보를 저장하는데 있어 프로퍼티 파일 보다 선호되는 이유와, LDAP 디렉토리에 정보를 구축하고 호스팅 하는 방법을 설명한다.

디렉토리 서버를 사용하는 이유?

본 시리즈 Part 1에서, 프로퍼티 파일의 형태로 사용자 정보를 저장하는 간단한 방법을 배웠다. (Part 1, Listing 6). 프로퍼티 파일은 사용자 이름, 패스워드, 사용자 역할을 텍스트 포맷에 저장했다. 실제 애플리케이션에서는, 프로퍼티 파일은 보안 정보에 적합한 스토리지가 아니다. 여러 가지 이유로, 디렉토리 서버가 더 나은 것으로 간주된다. 한 가지 이유는 실제 엔터프라이즈 애플리케이션은 많은 사용자들이 액세스 할 수 있다. 애플리케이션이 기능의 일부를 고객과 공급자에게 노출했을 경우 수천 명이 사용자가 될 수 있다. 텍스트 파일에 무작위로 저장된 정보를 자주 검색하는 것이 효율적이지 않지만, 디렉토리 서버는 이와 같은 검색을 위해 최적화 된다.

또 다른 이유는 사용자와 역할을 결합한 Part 1, Listing 6의 프로퍼티 파일에 드러났다. 실제 액세스 컨트롤 애플리케이션에서, 여러분은 사용자와 역할에 관한 정보를 따로 정의 및 관리해야 하는데, 이는 사용자 베이스를 더욱 쉽게 관리하기 위해서이다. 디렉토리 서버는 승진이나 새로운 고용을 반영하기 위해 사용자 정보를 수정 또는 업데이트 할 수 있는 거의 무한한 유연성을 제공한다. 참고자료 섹션에서 디렉토리 서버 사용법과 효과를 참조하라.

LDAP 디렉토리 설정

LDAP 디렉토리에 사용자 정보를 저장하고 싶다면, 디렉토리 설정에 대한 몇 가지를 이해해야 한다. LDAP에 대한 설명은 참고자료 섹션을 참조하라. 이 글에서는, LDAP 디렉토리와 Acegi를 사용하기 전에 알아야 할 기본 개념을 소개하겠다.

LDAP 디렉토리는 노드의 트리 형태로 정보를 저장한다. (그림 1):


그림 1. LDAP 디렉토리의 트리 구조
그림 1. LDAP 디렉토리의 트리 구조

그림 1에서, 루트 노드의 이름은 org이다. 이 루트 노드는 다른 엔터프라이즈와 관련된 데이터를 래핑할 수 있다. 예를 들어, 본 시리즈의 Part 1에서 개발했던 제조 회사는 루트 org 노드의 자식 노드로 보여진다. 이 제조 업체는 departmentspartners라는 두 개의 자식 노드를 갖고 있다.

partners 자식 노드는 다른 유형의 파트너들을 래핑한다. 그림 1에서는 customers, employees, suppliers가 보인다. 이 모든 세 가지 유형의 파트너들이 엔터프라이즈 시스템의 사용자로서 작동할 수 있다. 각 사용자 유형은 다른 비즈니스 역할을 갖고 있고, 시스템에 액세스 할 때 다른 권한을 갖는다.

마찬가지로, departments 노드에는 engineeringmarketing 자식 노드 같은 제조 업체의 다양한 부서들을 포함하고 있다. 각 부서 노드에는 한 개 이상의 사용자 그룹이 포함된다. 그림 1에서, engineers 그룹은 engineering 부서의 자식 노드이다.

각 부서의 자식들은 한 그룹의 사용자들을 나타낸다. 따라서, 부서 노드의 자식들은 멤버로서 다른 사용자들을 갖는다. 예를 들어, 엔지니어링 부서에서 근무하는 모든 엔지니어들은 engineering 부서 내 engineers 그룹의 멤버들이다.

마지막으로, departments 노드의 마지막 자식 노드를 주목하라. (그림 1) specialUser는 그룹이 아닌 사용자이다. 이러한 디렉토리 설정에서, alicebob 같은 사용자들은 partners 노드에 포함된다. 필자는 특별한 사용자를 departments 노드에 포함시켜서, 사용자들이 LDAP 디렉토리의 어느 곳에나 있을 수 있도록 함으로써, Acegi의 유연성을 드러내었다. 이 글 후반에는, specialUser를 수용하도록 Acegi를 설정하는 방법을 설명하겠다.

식별 이름 사용하기

LDAP는 식별 이름(distinguished name; DN) 개념을 사용하여 LDAP 트리의 특정 노드를 구분한다. 각 노드는 고유의 DN을 갖고 있는데, 여기에는 완전한 계층 정보가 포함되어 있다. 예를 들어, 그림 2에서는 그림 1에 사용된 일부 노드들의 DN을 보여주고 있다.


그림 2. LDAP 디렉토리에 있는 노드들의 식별 이름
그림 2. LDAP 디렉토리에 있는 노드들의 식별 이름

먼저, 그림 2의 루트 노드의 DN을 주목하라. 이것의 DN은 dc=org인데, 이것은 루트 org 노드와 연결된 애트리뷰트-값 쌍이다. 각 노드는 그 노드와 연결된 많은 애트리뷰트를 가질 수 있다. dc 애트리뷰트는 "domain component"를 의미하고, LDAP RFC 2256에 의해 정의된다. (참고자료-공식 RFC 문서). LDAP 디렉토리의 루트 노드는 도메인 컴포넌트로서 나타난다.

각 LDAP 애트리뷰트는 RFC에 의해 정의된다. LDAP는 많은 애트리뷰트를 사용하여 DN을 만들 수 있지만, 이 글의 예제에서는 다음의 네 가지만 사용한다:

  • dc (domain component)
  • o(organization)
  • ou (organizational unit)
  • uid (user ID)

dc는 도메인을 뜻하고, o는 조직명을, ou는 조직 내 단위를, 사용자에는 uid를 사용한다.

org가 루트 노드이기 때문에, DN은 고유의 이름 (dc=org)을 지정해야 한다. 반대로, manufacturingEnterprise의 DN은 o=manufacturingEnterprise,dc=org이다. 노드의 트리를 밑으로 가면서, 각 부모 노드들의 DN은 자식 노드들의 DN에 포함되어 있다.

애트리뷰트 그룹핑

LDAP는 객체 클래스의 형태로 관련된 애트리뷰트 유형들을 그룹핑 한다. 예를 들어, organizationalPerson이라는 객체 클래스에는 그 조직에서 일하는 사람을 정의하는 모든 애트리뷰트를 포함하고 있다. (예를 들어, 직위, 이름, 주소 등)

객체 클래스는 상속을 사용하는데, LDAP는 베이스 클래스를 정의하여 일반적으로 사용되는 애트리뷰트를 보유한다. 자식 클래스는 베이스 클래스를 확장하여 정의된 애트리뷰트를 사용한다. LDAP 디렉토리의 단일 노드는 많은 객체 클래스를 사용한다. 이 글의 예제는 다음과 같은 객체 클래스를 사용한다:

  • top 객체 클래스는 LDAP에 있는 모든 객체 클래스들의 베이스 클래스이다.

  • domain 객체 클래스는 다른 객체 클래스가 객체에 맞지 않을 때 사용된다. 이것은 애트리뷰트 세트를 정의하는데, 이는 객체를 지정하는데 사용될 있다. dc 애트리뷰트는 의무적이다.

  • organization 객체 클래스는 manufacturingEnterprise 같은 조직 노드를 나타낸다. (그림 2)

  • organizationalUnit 객체 클래스는 departments 노드와 이것의 자식 노드 같은(그림 1) 조직 내 단위들을 나타낸다.

  • groupOfNames 객체 클래스는 한 부서에서 근무하는 사람들의 이름 같이, 한 그룹의 이름을 나타낸다. member 애트리뷰트를 갖고 있는데, 여기에는 사용자 리스트가 포함된다. 그림 1이 모든 그룹 노드들(예, engineers 노드)은 member 애트리뷰트를 사용하여 그룹의 멤버를 지정한다. 더욱이, 이 예제는 groupOfNames 객체 클래스의 ou (organizational unit) 애트리뷰트를 사용하여 그룹의 비즈니스 역할을 지정한다.

  • organizationalPerson 객체 클래스는 한 조직에 있는 사람들을 나타낸다. (그림 1alice 노드).



위로


LDAP 서버에서 작업하기

실제 애플리케이션에서는, LDAP 디렉토리에 시스템 사용자들에 대한 많은 정보를 저장한다. 예를 들어, 사용자 이름, 패스워드, 직위, 연락처 정보, 급여 정보를 저장한다. 단순함을 위해, 다음 예제들에서는 사용자 이름과 패스워드만 저장하는 방법을 보여준다.

이전에 언급했듯이, 이 예제는 오픈 소스 LDAP 디렉토리 서버인 ApacheDS를 사용하여 Acegi와 LDAP 디렉토리가 어떻게 작동하는지를 설명한다. 또한, JXplorer라고 하는 오픈 소스 LDAP 클라이언트를 사용하여 ApacheDS에 정보를 호스팅 하는 것 같은 간단한 디렉토리 연산을 실행한다. 참고자료 섹션에서 ApacheDS와 JXplorer를 다운로드 하여, 이것이 어떻게 작동하는지를 보라.

ApacheDS에 루트 노드 만들기

그림 1에 노드의 트리를 만들기 위해서는, ApacheDS에 루트 노드 org를 만들어야 한다. ApacheDS는 이를 위해 XML 설정 파일을 제공한다. XML 설정 파일은 애플리케이션 요구 사항에 맞춰 디렉토리 서버의 작동을 커스터마이징 할 수 있는 빈(bean)을 정의한다. 여기에서는 루트 노드를 생성하는데 필요한 설정만 설명하겠다.

ApacheDS의 conf 폴더에 server.xml이라고 하는 XML 설정 파일이 있다. 이 파일을 열면, Acegi의 필터 설정과 비슷한 많은 빈 설정을 볼 수 있다. examplePartitionsConfiguration이라고 하는 빈을 찾는다. 이 빈은 ApacheDS의 파티션을 관리한다. 새로운 루트 노드를 만들면, LDAP 디렉토리에 새로운 파티션을 만든 것이다.

examplePartitionConfiguration 빈을 편집하여 루트 org 노드를 만들라. (Listing 1):


Listing 1. examplePartitionConfiguration 빈 설정의 편집 폼
                
<bean id="examplePartitionConfiguration" class=
"org.apache.directory.server.core.partition.impl.btree.MutableBTreePartitionConfiguration"
>

<property name="suffix"><value>dc=org</value></property>

<property name="contextEntry">
<value>
objectClass: top
objectClass: domain
dc: org
</value>
</property>

<!-- Other properties of the examplePartitionConfiguration bean, which you don't  
need to edit. -->

</bean>

Listing 1은 examplePartitionConfiguration 빈의 두 개의 프로퍼티를 편집한다:

  • 루트 엔트리의 DN을 정의하는 suffix라는 프로퍼티.

  • 루트 org 노드가 사용할 객체 클래스를 정의하는 contextEntry 프로퍼티. 루트 org 노드는 두 개의 객체 클래스, topdomain을 사용한다.

소스 코드 다운로드 섹션에는 server.xml 편집 폼이 포함되어 있다. 이 예제를 사용하려면, server.xml을 소스 코드에서 ApacheDS의 정확한 위치(conf 폴더)로 복사한다.

그림 3은 JXplorer가 ApacheDS에 생성된 루트 노드를 디스플레이 하는 모습이다:


그림 3. JXplorer에 의해 디스플레이 된 루트 노드
그림 3. JXplorer에 의해 디스플레이 된 루트 노드

서버 채우기

LDAP 서버를 설정하는 다음 단계는 사용자와 그룹에 대한 정보를 채우는 단계이다. JXplorer를 사용하여 ApacheDS에 하나씩 노드를 만들 수 있지만, LDAP Data Interchange Format (LDIF)를 사용하여 서버를 채우는 것이 훨씬 쉽다. LDIF는 대부분의 LDAP에서 인식되는 포맷이다. LDIF 파일에 대해서는 developerWorks 기술자료에서 다루고 있다. (참고자료)

대신, 소스 코드 다운로드에서 그림 1의 사용자와 부서를 나타내는 LDIF 파일을 볼 수 있다. JXplorer를 사용하여 LDIF 파일을 ApacheDS로 가져올 수 있다. LDIF 파일을 가져오려면, JXplorer에 LDIF 메뉴를 사용한다. (그림 4):


그림 4. ApacheDS에 LDIF 파일 가져오기
그림 4. ApacheDS에 LDIF 파일 가져오기

LDIF 파일을 ApacheDS로 가져오면, JXplorer는 사용자 노드와 부서 노드의 트리를 디스플레이 한다. (그림 1) 이제 여러분은 LDAP 서버와 통신하도록 Acegi를 설정할 준비가 되었다.




위로


Acegi를 LDAP에 맞게 설정하기

Part 1을 기억해 보면, Acegi는 인증에 Authentication Processing Filter (APF)를 사용한다. APF는 클라이언트 요청에서 사용자 이름과 패스워드를 추출하고, 백엔드 사용자 베이스에서 사용자 매개변수를 읽고, 그 정보를 사용하여 사용자를 인증하는 등의 모든 백엔드 인증 프로세싱 태스크를 수행한다.

여러분은 Part 1에서 프로퍼티 파일을 위해 APF를 설정했다. 이제는 사용자 베이스를 LDAP 디렉토리에 저장했기 때문에, LDAP 디렉토리와 통신하기 위해서는 약간 다르게 필터를 설정해야 한다. Listing 2를 보면서, APF 필터가 Part 1의 "인증 프로세싱 필터"의 프로퍼티 파일 구현에 맞게 어떻게 설정되는지를 보자. :


Listing 2. 프로퍼티 파일에 맞춰 APF 설정하기
                
<bean id="authenticationProcessingFilter"
class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter">

<property name="authenticationManager" ref="authenticationManager" />

<property name="authenticationFailureUrl"
value="/login.jsp?login_error=1" />

<property name="defaultTargetUrl"
value="/index.jsp" />

<property name="filterProcessesUrl"
value="/j_acegi_security_check" />

</bean>

Listing 2를 보면, 네 개의 매개변수를 APF에 제공했다. LDAP 서버에 저장할 수 있도록 첫 번째 매개변수(authenticationManager)를 재설정 하면 된다. 다른 세 개의 매개변수들은 변함이 없다.

인증 매니저 설정하기

Listing 3은 Acegi의 인증 매니저를 설정하여 LDAP 서버와 통신하는 방법을 보여주고 있다:


Listing 3. LDAP용으로 Acegi 인증 매니저 설정하기
                
<bean id="authenticationManager"
class="org.acegisecurity.providers.ProviderManager">

<property name="providers">
<list>
<ref local="ldapAuthenticationProvider" />
</list>
</property>

</bean>

Listing 3에서, org.acegisecurity.providers.ProviderManager는 Acegi의 인증 프로세스를 관리하는 매니저 클래스이다. 이 작업을 수행하기 위해, 인증 매니저는 한 개 이상의 인증 공급자를 필요로 한다. 매니저 빈의 공급자 프로퍼티를 사용하여 한 개 이상의 공급자를 설정할 수 있다. Listing 3에는 단 한 개의 공급자인, LDAP 인증 공급자만 포함되어 있다.

LDAP 인증 공급자는 백엔드 LDAP 디렉토리와 모든 통신을 핸들한다. 이것 역시도 설정할 수 있다.

LDAP 인증 공급자 설정하기

Listing 4는 LDAP 인증 공급자의 설정을 보여주고 있다:


Listing 4. LDAP Authentication Provider 설정하기
                
<bean id="ldapAuthenticationProvider"
class="org.acegisecurity.providers.ldap.LdapAuthenticationProvider">

<constructor-arg><ref local="authenticator"/></constructor-arg>

<constructor-arg><ref local="populator"/></constructor-arg>

</bean>

LDAP 인증 공급자의 이름이 org.acegisecurity.providers.ldap.LdapAuthenticationProvider 이다. 이것의 구조체는 두 개의 <constructor-arg> 태그의 형태로 두 개의 매개변수를 취한다. (Listing 4)

LdapAuthenticationProvider 구조체에 대한 첫 번째 매개변수는 authenticator인데, 사용자 이름과 패스워드를 확인함으로써 LDAP 디렉토리에서 사용자를 인증한다. 사용자가 인증되면, 두 번째 매개변수인 populator는 LDAP 디렉토리에서 사용자의 액세스 권한(또는 비즈니스 역할)에 관한 정보를 가져온다.

다음 섹션에서는 authenticator와 populator 빈을 설정하는 방법을 설명한다.




위로


authenticator 설정하기

authenticator 빈은 사용자 이름과 패스워드로 LDAP 디렉토리에 사용자가 있는지 여부를 검사한다. Acegi는 org.acegisecurity.providers.ldap.authenticator.BindAuthenticator라고 하는 authenticator를 제공하는데, 이것은 사용자 이름과 패스워드를 검사하는 기능을 수행한다.

authenticator 빈을 설정해 보자. (Listing 5):


Listing 5. authenticator 빈 설정하기
                
<bean id="authenticator"
class="org.acegisecurity.providers.ldap.authenticator.BindAuthenticator">

<constructor-arg><ref local="initialDirContextFactory"/></constructor-arg>

<property name="userDnPatterns">
<list>
<value>uid={0},ou=employees,ou=partners</value>
<value>uid={0},ou=customers,ou=partners</value>
<value>uid={0},ou=suppliers,ou=partners</value>
</list>
</property>

<property name="userSearch"><ref local="userSearch"/></property>

</bean>

Listing 5에서, BindAuthenticator 구조체는 <constructor-arg> 태그의 형태로 한 개의 매개변수를 취한다. Listing 5에 있는 매개변수의 이름은 initialDirContextFactory이다. 이 매개변수는 실제로 또 다른 빈인데, 잠시 후에 설정 방법을 설명하겠다.

지금으로서는, initialDirContextFactory 빈의 목적이 나중에 검색 연산을 위한 초기 정황을 지정하는 것이라는 것을 알 뿐이다. 초기 정황은 LDAP 디렉토리에 특정 노드를 지정하는 DN이다. 일단, 초기 정황을 지정하면, 나중의 모든 검색 연산(예를 들어, 특정 사용자 배치하기)은 이 노드의 자식 노드에서 발생한다.

예를 들어, 그림 2partners 노드를 보면, DN이 ou=partners,o=manufacturingEnterprise,dc=org이다. partners 노드를 초기 정황으로 지정하면, Acegi는 partners 노드의 자식 노드 중에서만 사용자를 찾는다.

DN 패턴 설정하기

BindAuthenticator 구조체를 설정하는 것 외에도, authenticator 빈의 두 개의 프로퍼티를 설정해야 한다. (Listing 5의 두 개의 <property> 태그).

첫 번째 <property> 태그는 userDnPatterns 프로퍼티를 정의하는데, 이것은 한 개 이상의 DN 패턴들의 리스트를 래핑힌다. DN 패턴은 공통적인 것을 갖고 있는 많은 LDAP 노드들을 설정한다. (그림 2employees 노드의 모든 자식 노드들).

Acegi의 authenticator는 authenticator 빈의 userDnPatterns 프로퍼티에 설정된 각 DN 패턴에서 한 개의 DN을 구축한다. 예를 들어, Listing 5에 설정된 첫 번째 DN 패턴, uid={0},ou=employees,ou=partners를 보자. authenticator 빈은 {0}을 인증 하는 동안 사용자(alice)가 제공한 사용자 이름으로 대체한다. {0}을 사용자 이름으로 대체한 후에, DN 패턴은 DN (RDN), uid=alice,ou=employees,ou=partners가 되는데, 이것은 초기 정황이 DN이 되어야 한다.

예를 들어, 그림 2alice의 엔트리를 보자. 이 엔트리는 employees 노드의 첫 번째 자식이다. 이것의 DN은 uid=alice,ou=employees,ou=partners,o=manufacturingEnterprise, dc=org이다. 초기 정황으로서 o=manufacturingEnterprise,dc=org를 사용하고, 이것을 RDN uid=alice,ou=employees,ou=partners 뒤에 붙인다면, alice의 DN을 얻는다.

이러한 방식으로 DN 패턴에서 사용자의 DN을 구축한 후에, authenticator는 DN과 사용자 패스워드를 LDAP 디렉토리로 보낸다. 이 디렉토리는 DN이 정확한 패스워드를 갖고 있는지를 확인한다. 그렇다면, 사용자는 인증을 받는다. 이 프로세스를 LDAP 용어로 바인드 인증(bind authentication)이라고 한다. LDAP는 다른 인증 메커니즘을 제공하지만, 이 글의 예제에서는 바인드 인증만 사용한다.

첫 번째 DN 패턴에 의해 생성된 DN이 디렉토리에 존재하지 않으면, authenticator 빈은 이 리스트에 설정된 다음 DN 패턴을 시도한다. 이러한 방식으로, authenticator 빈은 모든 DN 패턴들이 인증을 요청한 사용자의 정확한 DN을 구축하도록 한다.

검색 필터

LDAP 디렉토리에 사용자 정보를 저장하는데 있어서의 유연성을 설명했던 "LDAP 디렉토리 설정" 섹션을 잠시 떠올려 보자. 필자는 특별한 사용자(specialUser)를 그림 1departments 노드 내에 생성했다.

Listing 5에 설정된 DN 패턴들을 사용하여 특별한 사용자의 DN을 생성한다면, 어떤 패턴도 특별한 사용자의 DN을 생성하기에 적합하지 않다는 것을 발견하게 된다. 결국, 사용자가 로그인을 시도하면, Acegi의 authenticator 빈은 정확한 DN을 구축할 수 없고, 결국 사용자 인증을 실패한다.

Acegi는 검색 필터를 지정함으로써 이와 같은 특별한 케이스를 핸들한다. authenticator 빈은 검색 필터를 사용하여 DN 패턴에서 DN을 구축함으로써 인증할 수 없는 사용자를 찾는다.

Listing 5의 두 번째 <property> 태그는 <ref> 자식 태그를 갖고 있는데, 이것은 userSearch라고 하는 빈을 의미한다. userSearch 빈은 검색 쿼리를 지정한다. Listing 6은 userSearch 빈을 설정하여 특별한 사용자를 핸들하는 방법을 보여주고 있다.


Listing 6. 특별한 사용자를 검색하는 검색 쿼리 설정하기
                
<bean id="userSearch"
class="org.acegisecurity.ldap.search.FilterBasedLdapUserSearch">

<constructor-arg>
<value>ou=departments</value>
</constructor-arg>

<constructor-arg>
<value>(uid={0})</value>
</constructor-arg>

<constructor-arg>
<ref local="initialDirContextFactory" />
</constructor-arg>

<property name="searchSubtree">
<value>true</value>
</property>

</bean>

검색 쿼리의 매개변수

Listing 6은 userSearch 빈이 org.acegisecurity.ldap.search.FilterBasedLdapUserSearch라는 클래스의 인스턴스이고, 이것의 구조체는 세 개의 매개변수를 취하고 있음을 보여주고 있다. 첫 번째 매개변수는 authenticator가 사용자를 검색하는 노드를 설정한다. 첫 번째 매개변수의 값은 ou=departments인데, 이것은 그림 2departments 노드를 설정하는 RDN이다.

두 번째 매개변수인, (uid={0})은 검색 필터를 설정한다. 여러분은 uid 애트리뷰트를 사용하여 사용자를 지정하기 때문에, uid 애트리뷰트가 특정 값을 갖고 있는 노드를 찾음으로써 사용자를 찾을 수 있다. 여러분도 알다시피, 중괄호 속에 있는 0은 Acegi에게 {0}을 인증을 받을 사용자 이름으로 대체할 것을 명령한다. (이 경우, specialUser).

세 번째 매개변수는 Listing 5BindAuthenticator 구조체를 설명하면서 소개했던 것과 같은 초기 정황에 대한 레퍼런스이다. 일단 초기 정황이 설정되면, 나중의 모든 검색 연산들은 초기 정황 노드의 자식 노드 내에서 발생한다. Listing 5의 첫 번째 매개변수의 값으로서 설정된 RDN(ou=departments)이 초기 정황 앞에 붙는다.

세 개의 구조체 매개변수 외에도, Listing 6의 userSearch 빈은 searchSubtree라고 하는 프로퍼티를 취한다. 여러분이 값을 true로 설정하면, 검색 연산에는 여러분이 첫 번째 구조체 매개변수의 값으로서 설정한 노드의 하위 트리(모든 자식, 손자, 증손자)를 포함하게 된다.

authenticator 빈의 설정은 이제 끝났다. 다음 섹션에서는 populator 빈의 설정에 대해 설명한다. (Listing 4)




위로


populator 설정하기

populator 빈은 authenticator 빈에 의해 이미 인증된 사용자의 비즈니스 역할을 읽는다. Listing 7은 populator 빈의 XML 설정 모습이다:


Listing 7. populator 빈의 XML 설정
                
<bean id="populator"
class="org.acegisecurity.providers.ldap.populator.DefaultLdapAuthoritiesPopulator">

<constructor-arg>
<ref local="initialDirContextFactory"/>
</constructor-arg>

<constructor-arg>
<value>ou=departments</value>
</constructor-arg>

<property name="groupRoleAttribute">
<value>ou</value>
</property>

<property name="searchSubtree">
<value>true</value>
</property>

</bean>

Listing 7에서, populator 빈은 구조체에 두 개의 인자와 groupRoleAttribute라고 하는 프로퍼티를 취한다. 첫 번째 구조체 매개변수는 populator 빈이 인증을 받은 사용자의 비즈니스 역할을 읽기 위해 사용하는 초기 정황을 설정한다. authenticatorpopulator 빈에 같은 초기 정황을 사용하는 것은 의무적인 것은 아니다. 각각 다른 초기 정황을 설정할 수 있다.

두 번째 구조체 인자는 초기 정황 앞에 populator가 붙이는 RDN을 설정한다. 이러한 방식으로, RDN은 departments 노드 같은 사용자 그룹들을 포함하고 있는 노드의 DN을 형성한다.

populator 빈의 groupRoleAttribute 프로퍼티는 이 그룹의 멤버들의 비즈니스 역할에 대한 데이터를 보유하고 있는 애트리뷰트를 지정한다. ou라고 하는 애트리뷰트에 각 그룹의 비즈니스 역할에 대한 정보를 저장했던 LDAP 디렉토리 설정하기 섹션을 생각해 보자. 여러분은 groupRoleAttribute 프로퍼티의 값으로서 ou를 설정했다. (Listing 7)

여러분도 알다시피, populator 빈은 LDAP 디렉토리를 검색하여 인증을 받은 사용자가 속해 있는 그룹들의 노드를 찾는다. 그리고 나서, 그 그룹 노드의 ou 애트리뷰트에 붙은 값을 읽어서 사용자의 정식 비즈니스 역할을 파악한다.

이것으로, populator 빈의 설정을 마쳤다. 지금까지, 여러분은 Listing 5, Listing 6, Listing 7에서 초기 정황을 사용했다. 다음에는, 초기 정황을 설정하는 방법을 설명하겠다.

초기 정황 설정하기

Listing 8은 Acegi에 초기 정황을 설정하는 방법을 보여주고 있다:


Listing 8. 초기 정황의 XML 설정
                
<bean id="initialDirContextFactory"
class="org.acegisecurity.ldap.DefaultInitialDirContextFactory">

<constructor-arg value="ldap://localhost:389/o=manufacturingEnterprise,dc=org"/>

<property name="managerDn">
<value>cn=manager,o=manufacturingEnterprise,dc=org</value>
</property>

<property name="managerPassword">
<value>secret</value>
</property>

</bean>

org.acegisecurity.ldap.DefaultInitialDirContextFactory이고, 이것은 Acegi에 포함된 팩토리 클래스이다. Acegi는 내부적으로 이 클래스를 사용하여 디렉토리를 통해 검색하는 것 같은 디렉토리 연산을 핸들하는 다른 클래스들의 객체들을 구축한다. 초기 정황 팩토리를 설정할 때 다음을 설정해야 한다:

  • LDAP 디렉토리의 네트워크 주소와 구조체 매개변수로서의 루트 디렉토리 노드. 초기 정황에서 여러분이 설정하는 노드는 루트 노드로서 취해진다. 모든 후기 연산들(search)은 루트 노드에 의해 정의된 하위 트리에서 수행된다는 의미이다.

  • 각각 managerDnmanagerPassword로서 정의된 DN과 패스워드. Acegi는 검색 연산을 수행하기 전에 디렉토리 서버에서 스스로를 인증할 수 있는 DN과 패스워드가 있어야 한다.

LDAP 디렉토리에 사용자 베이스를 호스팅 하는 방법과, Acegi를 설정하여 LDAP 디렉토리에서 정보를 사용하여 사용자를 인증하는 방법을 배웠다. 다음 섹션에서는 Acegi의 Authentication Processing Filter를 자세히 보도록 하겠다. 이것이 어떻게 인증 프로세스를 관리하는지를 설명하겠다.




위로


인증과 권한

APF가 설정되면, LDAP 디렉토리와 통신하여 사용자를 인증할 준비가 된다. 디렉토리와의 통신에 있어서 APF가 따르는 일부 단계들은 여러분이 Part 1을 읽어 보았다면 익숙할 것이다. Part 1에서는 사용자 인증을 위해 이 필터가 다른 서비스와 어떻게 작동하는지를 설명했다. 그림 5의 시퀀스 다이어그램은 Part 1, 그림 3에서 보여주었던 것과 비슷하다:


그림 5. APF가 LDAP 사용자를 인증한다.
그림 5. APF가 LDAP 사용자를 인증한다.

1단계부터 9 단계는 내부 인증을 위해 APF가 프로퍼티 파일을 사용하든, LDAP 서버와 통신하든 상관 없이 같다. 초기 9 단계는 그대로이며, 10 단계부터 LDAP 고유의 단계이다:

  1. 필터 체인에 있는 이전 필터가 요청, 응답, 필터 체인 객체를 APF로 전달한다.

  2. APF는 요청 객체에서 보내온 사용자 이름, 패스워드, 기타 정보를 사용하여 인증 토큰을 만든다.

  3. APF는 인증 토큰을 인증 매니저에게 전달한다.

  4. 인증 매니저는 한 개 이상의 인증 공급자를 포함하고 있다. 각 공급자는 한 가지 유형의 인증을 지원한다. 매니저는 공급자 중에서 어떤 것이 APF에서 받은 인증 토큰을 지원하는지를 검사한다.

  5. 인증 매니저는 인증 토큰을 인증에 적합한 공급자에게 전달한다.

  6. 인증 공급자는 인증 토큰에서 사용자 이름을 추출하여, 이것을 캐시 서비스라고 하는 서비스로 전달한다. Acegi는 인증을 받았던 사용자 캐시를 관리한다. 다음에 사용자가 로그인 하면, 백엔드 데이터 스토리지에서 읽어오는 대신, Acegi는 사용자의 상세(사용자 이름, 패스워드, 권한)를 캐시로부터 로딩한다. 따라서 성능이 향상된다.

  7. 사용자 캐시 서비스는 사용자 상세가 캐시에 존재하는지 여부를 검사한다.

  8. 사용자 캐시 서비스는 사용자의 상세를 인증 공급자에 리턴한다. 캐시가 사용자 상세를 포함하고 있지 않으면, 무효를 리턴한다.

  9. 인증 공급자는 캐시 서비스가 사용자 상세를 리턴 했는지, 무효를 리턴 했는지를 확인한다.

  10. 여기서부터 인증 프로세스는 LDAP 고유의 절차이다. 캐시가 무효를 리턴 했다면, LDAP 인증 공급자는 사용자 이름(6 단계)과 패스워드를 Listing 5에서 설정된 authenticator 빈으로 전달한다.

  11. authenticatorListing 5userDnPatterns 프로퍼티에서 설정된 DN 패턴을 사용하여 사용자 DN을 만든다. 사용 가능한 모든 DN 패턴을 하나씩 시도하면서, DN 패턴에서 DN을 만들고, 이것을 사용자 패스워드와 함께 LDAP 디렉토리로 보낸다. LDAP 디렉토리는 DN이 존재하는지 여부와 패스워드가 정확한지를 검사한다. DN 패턴이 적용되면, 사용자는 LDAP 디렉토리로 연결되고, authenticator는 15 단계로 이동한다.

  12. 어떤 DN 패턴도 작동하지 않으면(DN 패턴에 의해 지정된 위치에서 주어진 패스워드를 가진 사용자가 존재하지 않으면), authenticatorListing 6에 설정된 검색 쿼리에 따라 LDAP 디렉토리에 있는 사용자를 검색한다. LDAP 디렉토리가 사용자를 찾을 수 없으면, 인증이 실패한다.

  13. LDAP 디렉토리가 사용자를 찾으면, 사용자의 DN을 authenticator로 리턴한다.

  14. authenticator는 사용자의 DN과 패스워드를 LDAP 디렉토리로 보내서 사용자의 패스워드가 정확한지를 검사한다. LDAP 디렉토리가 패스워드가 정확하다는 것을 알아내면, 사용자는 LDAP 디렉토리로 연결된다.

  15. authenticator는 사용자 정보를 LDAP 인증 공급자로 보낸다.

  16. LDAP 인증 공급자는 컨트롤을 populator 빈으로 보낸다.

  17. populator는 사용자가 속해 있는 그룹을 검색한다.

  18. LDAP 디렉토리는 사용자 역할 정보를 populator로 리턴한다.

  19. populator는 역할 정보를 LDAP 인증 공급자로 리턴한다.

  20. LDAP 인증 공급자는 사용자 상세를 (사용자의 비즈니스 역할에 관한 정보와 함께) APF로 리턴한다. 사용자는 이제 인증에 성공한 것이다.

마지막 세 단계(21, 22, 23)는 인증 방식에 관계 없이 같다.

인터셉터(Interceptor) 설정하기

APF가 사용자를 인증하는 과정을 살펴보았다. 다음 단계는 인증에 성공한 사용자가 요청된 리소스에 액세스 할 권한을 받는지를 검사하는 단계이다. 이것은 Acegi의 Interceptor Filter (IF)의 역할이다. 이 섹션에서는 IF를 설정하여 액세스 컨트롤 정책을 실행하는 방법을 설명한다.

Part 1, Listing 7에서 IF를 설정했다. Interceptor Filter는 역할을 가진 리소스들을 매핑하는데, 필요한 역할을 가진 사용자만이 주어진 리소스에 액세스 할 수 있다. 제조 업체의 다른 부서들의 비즈니스 역할을 나타내기 위해서, Listing 9는 또 다른 역할을 기존 IF 설정에 추가한다:


Listing 9. Interceptor Filter 설정하기
                
<bean id="filterInvocationInterceptor"
class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">

<property name="authenticationManager" ref="authenticationManager" />

<property name="accessDecisionManager" ref="accessDecisionManager" />

<property name="objectDefinitionSource">
<value>
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/protected/engineering/**=ROLE_HEAD_OF_ENGINEERING
/protected/marketing/**=ROLE_HEAD_OF_MARKETING
/**=IS_AUTHENTICATED_ANONYMOUSLY
</value>
</property>

</bean>

Listing 9에서, IF는 세 개의 매개변수를 취한다. 첫 번째와 세 번째 매개변수는 Part 1에서 설정된 것과 같은 것이다. 두 번째 매개변수(accessDecisionManager)가 추가되었다.

accessDecisionManager 빈은 권한 결정을 내리는 책임이 있다. Listing 9의 세 번째 매개변수에서 제공한 액세스 컨트롤 정의를 사용하여 권한(또는 액세스 컨트롤) 결정을 내린다. 세 번째 매개변수는 objectDefinitionSource이다.

액세스 결정 매니저 설정하기

accessDecisionManager는 사용자가 리소스에 액세스 할 수 있는지 여부를 결정한다. Acegi는 많은 액세스 결정 매니저를 제공하는데, 액세스 컨트롤 결정을 내리는 방식은 다양하다. 이 글에서는 하나의 액세스 결정 매니저의 작동에 대해서만 설명하겠다. (Listing 10):


Listing 10. Configuring the access decision manger
                
<bean id="accessDecisionManager" class="org.acegisecurity.vote.AffirmativeBased">

<property name="decisionVoters">
<list>
<bean class="org.acegisecurity.vote.RoleVoter"/>
<bean class="org.acegisecurity.vote.AuthenticatedVoter" />
</list>
</property>

</bean>

Listing 10에서, accessDecisionManager 빈은 org.acegisecurity.vote.AffirmativeBased 클래스의 인스턴스이다. accessDecisionManager 빈은 단 한 개의 매개변수를 취하는데, 이것은 voters의 리스트이다.

Acegi에서, Voter는 사용자가 특정 리소스에 액세스 할 수 있는지 여부를 결정한다. accessDecisionManager에 의해 쿼리를 받으면, Voter는 세 가지 옵션을 갖는다. 액세스 허용(access-granted), 액세스 거부(access-denied), 확실하지 않을 때 기권(abstain from voting)이다.

다른 유형의 액세스 결정 매니저는 Voter 결정을 인터프리팅 하는 방식이 다르다. AffirmativeBased 액세스 결정 매니저(Listing 10)는 간단한 결정 로직을 실행한다. Voter가 확정적인 표를 던지면, 사용자가 요청을 받은 리소스에 액세스 할 수 있다.

Voter 로직

Acegi는 여러 유형의 Voter 구현을 제공한다. accessDecisionManager는 인증을 받은 사용자에 대한 정보(사용자의 비즈니스 역할 포함)와 objectDefinitionSource 객체를 Voter에 전달한다. 다음 예제는 두 가지 유형의 Voter, RoleVoterAuthenticatedVoter를 사용한다. (Listing 10):

  • RoleVoterobjectDefinitionSource 객체 안에 있는 라인에서 접두사 ROLE_ 로 시작하는 역할을 찾을 수 있을 때에만 투표한다. RoleVoter가 이와 같은 라인을 찾을 수 없으면, 기권한다. 사용자의 비즈니스 역할 중에서 매칭되는 역할을 찾으면, 액세스 허용에 투표한다. 매칭되는 역할을 찾지 못하면, 액세스 거부를 투표한다. Listing 9에는, ROLE_: ROLE_HEAD_OF_ENGINEERINGROLE_HEAD_OF_MARKETING 접두사를 가진 두 개의 역할이 있다.

  • AuthenticatedVoterobjectDefinitionSource 객체에서 사전 정의된 역할을 가진 라인들을 찾을 경우에만 표를 던진다. Listing 9에는, 한 개의 라인이 있다. (IS_AUTHENTICATED_ANONYMOUSLY) 익명 인증은 사용자가 인증을 받을 수 없다는 것을 의미한다. 이 라인을 찾으면, AuthenticatedVoter는 보호를 받지 못하는 일부 리소스(ROLE_ 접두사를 가진 라인에 포함되지 않은 리소스)는 익명으로 인증을 받은 사용자에 의해 액세스 될 수 있다. AuthenticatedVoter는 요청을 받은 리소스가 보호를 받지 못하고, objectDefinitionSource 객체가 보호를 받지 못하는 리소스가 익명 인증을 받은 사용자에 의해 액세스 될 수 있도록 한다면, 액세스 허용을 투표하고, 그렇지 않을 경우 액세스 거부를 표시한다.



위로


예제 애플리케이션

이 글에서는 지금까지 여러분이 배웠던 LDAP와 Acegi 개념을 설명하는 예제 애플리케이션을 제공한다. LDAP-Acegi 애플리케이션은 엔지니어링과 마케팅 문서를 올바르게 인증을 받은 사용자에게 제공하는 인덱스 페이지를 디스플레이 한다. 여러분도 알게 되겠지만, LDAP-Acegi 애플리케이션에서는 사용자 alice가 엔지니어링 문서를 볼 수 있고, 사용자 bob이 마케팅 문서를 볼 수 있다. 또한, 특별한 사용자가 엔지니어링과 마케팅 문서 모두를 볼 수 있다. 이 모든 것은 LDAP 디렉토리 서버를 설정할 때 설정되었던 것이다. 예제 애플리케이션을 다운로드하여 지금 확인해보기 바란다.




위로


결론

이 글에서, LDAP 디렉토리에서 사용자와 비즈니스 역할 정보를 호스팅 하는 방법을 배웠다. 또한, Acegi를 설정하여 LDAP 디렉토리와 인터랙팅 하고, 액세스 컨트롤 정책을 실행하는 방법을 배웠다. 마지막 시리즈에서는, 자바 클래스로의 액세스를 보안화 하도록 Acegi를 설정하는 방법을 설명하겠다.





위로


다운로드 하십시오

설명이름크기다운로드 방식
본 기술자료의 소스 코드j-acegi2.zip10KBHTTP
다운로드 방식에 대한 정보


참고자료

교육

제품 및 기술 얻기
  • ApacheDS: Apache.org에서 다운로드.

  • JXplorer: 자바 기반, 오픈 소스 LDAP 클라이언트.


토론


필자소개

Bilal Siddiqui는 전기 엔지니어이자, XML 컨설턴트이며, WaxSys의 공동 창립자이다. 1995년 University of Engineering and Technology, Lahore에서 전자 엔지니어링 학위를 받은 후, 제어 시스템을 위한 소프트웨어 솔루션을 설계하기 시작했다. 그 후, XML로 전향했으며 C++을 프로그래밍 한 경험을 살려 웹 과 Wap 기반 XML 프로세싱 툴, 서버 측 파싱 솔루션, 서비스 애플리케이션을 구현하고 있다.




기사에 대한 평가


보다 나은 서비스를 제공하기 위함이오니 잠시 짬을 내어 이 양식을 제출하여 주십시오.



아니오잘 모르겠음
 


 


12345
 



위로


Java and all Java-based trademarks are trademarks of Sun Microsystems, Inc. in the United States, other countries, or both. 기타 회사, 제품, 및 서비스명은 다른 상표나 서비스 마크일 수 있습니다.

developerWorks 콘텐트를 다른 사이트에 전재하기:
developerWorks 콘텐트에 대한 저작권은 IBM에 있습니다. IBM의 서면 허가나 원본 저자의 허락이 없이는 전재를 금합니다. 저희 콘텐트를 전재하시려면 IBM developerWorks 담당자 에게 문의하십시오.
    IBM 소개 개인정보 보호정책 문의