제5장 Custom 보안 서비스 개발

내용 목차

5.1. 개요
5.2. 서비스 클래스
5.3. Custom 보안 서비스 구현 패턴
5.4. SPI 클래스
5.4.1. SubjectValidationService SPI
5.4.2. SubjectFactoryService SPI
5.4.3. AuthenticationService SPI
5.4.4. AuthenticationRepositoryService SPI
5.4.5. IdentityAssertionService SPI
5.4.6. CredentialMappingService SPI
5.4.7. CredentialVerificationService SPI
5.4.8. AuthorizationService SPI
5.4.9. AuthorizationRepositoryService SPI
5.4.10. EventHandlingService SPI
5.4.11. Dependencies between SPI Implementations
5.5. 보안 서비스 설정

본 장에서는 JEUS 보안 시스템의 주요 특징인 Custom 보안 서비스를 개발하는 방법에 대해 설명한다.

Custom 보안 서비스를 이용하면 JEUS 보안 시스템과 다양한 외부 보안 시스템, 보안 데이터 저장소를 쉽게 통합할 수 있다.

다음은 Custom 보안 서비스를 개발과 관련된 몇 가지 중요한 개념으로 각 절에서 상세히 설명한다.

pluggable 보안 아키텍처에서 가장 기본이 되는 클래스는 jeus.security.base.Service 클래스이다. 서비스 클래스는 보안 서비스를 구현하려는 클래스들이 반드시 확장해야 하는 추상 클래스로 현재 jeus.security.spi 패키지에 있는 모든 SPI 클래스도 이 클래스를 확장한 것이다.

다음은 서비스 클래스의 클래스 다이어그램이다.


서비스 클래스는 모든 보안 서비스에 공통적으로 적용되는 다음의 항목들을 포함하고 있다.

본 절에서는 Custom 보안 서비스의 구현 방법에 대해서 간략하게 설명한다.

일반적인 Custom 보안 서비스를 구현하는 과정은 다음과 같다.

  1. 사전에 보안 시스템과 보안 시스템 아키텍처를 충분히 이해하고 있어야 한다.

  2. Custom 보안 서비스가 어떤 보안 기능을 제공해야 하는지 파악한다.

  3. 해당 특성을 가지고 있는 SPI 클래스를 선택한다. 주요 SPI 클래스에 대한 자세한 내용은 “5.4. SPI 클래스”를 참고한다.

  4. 해당 SPI 클래스에 대한 문서를 주의 깊게 살펴본다(Javadoc, 참고 자료, “5.4. SPI 클래스”에 대한 설명을 참고한다).

  5. 해당 SPI 클래스의 서브 클래스를 작성하고, 서브 클래스에서 다음 메소드들을 구현한다. 그리고 반드시 파라미터가 없는 public 생성자를 제공해야 한다.

    1. 선택적으로 서비스 초기화에 사용되는 속성들을 정의한다. 각 속성은 public static final String 타입으로 각각이 무엇을 나타내는지는 문서화되어야 한다.

    2. doCreate() 메소드를 구현한다. 이 메소드는 보안 서비스가 시작할 때 단 한 번 불리며, 자원 할당과 같은 일반적인 초기화 작업을 수행한다. 이 메소드는 getProperty() 메소드를 통해 설정값을 읽어 들인다. getProperty() 메소드의 파라미터는 이전 단계에서 설정된 속성명이다.

    3. doDestroy() 메소드를 구현한다. 이 메소드는 서비스가 종료하기 전에 단 한 번 호출된다. 이 메소드는 doCreate() 메소드에서 할당된 자원을 해제하거나, 특정 파일에 로그를 남기는 등의 일반적인 clean-up 작업을 수행한다.

    4. 선택한 SPI 클래스의 모든 추상 메소드를 Javadoc에서 설명하고 있는 방식대로 구현한다.

    5. 선택적으로 JMX를 통해 서비스를 관리하는 데 사용되는 메소드들을 구현할 수 있다. getMBean() 또는 getMBeanInfo() 메소드를 구현한다.

  6. SPI를 구현한 클래스를 컴파일한다.

  7. “제2장 보안 시스템 설정”에서 설명한 대로 새로운 보안 서비스를 JEUS에 등록한다.

본 절에서는 jeus.security.spi 패키지에 포함되어 있는 다양한 SPI 클래스에 대해 설명한다.

다음은 jeus.security.spi 패키지 내에 정의된 SPI 클래스 목록이다. Cardinality는 각 도메인에 해당 SPI 클래스가 몇 개나 있을 수 있는지에 대한 설명이다.

class namePurposeCardinality
SecurityInstaller

보안 시스템을 설치하고 제거한다.

전체 JVM에 대해 오직 하나만 존재해야 한다.

1
SubjectValidationService로그인 전에 해당 Subject의 Credential이 유효한지 아닌지 체크한다.0개 이상
SubjectFactoryService로그인 전에 Custom Subject를 생성한다.1
AuthenticationService로그인 전에 Subject를 인증한다.1
AuthenticationRepositoryServiceSubject를 Subject 저장소로부터 추가, 삭제, 조회한다.1
IdentityAssertionService cert-user-map.xml 파일 정보를 이용하여 Credential을 Subject에 매핑한다.0개 이상
CredentialMappingService Truststore 정보를 이용하여 Credential을 Subject에 매핑한다.0개 이상
CredentialVerificationServiceSubject가 가지고 있는 Credential 중 최소한 하나라도 유효한지 검증한다.0개 이상
AuthorizationServiceSubject가 특정 Role 또는 리소스에 접근할 권한이 있는지 체크한다.1
AuthorizationRepositoryServicePolicy를 저장소로부터 추가, 삭제, 조회한다.1
EventHandlingService보안 이벤트에 대한 Custom 이벤트 핸들러, 다양한 보안 감사를 구현한다.0개 이상

jeus.security.spi.SubjectValidationService SPI는 Subject가 가지고 있는 Credential이 유효한지 아닌지를 체크하는 데 사용된다. 이것은 때때로 Credential이 유효하지 않는 경우도 있음을 나타낸다. 유효하지 않는 Credential은 곧 Subject가 유효하지 않다는 의미이고, 결과적으로 해당 Subject로는 로그인할 수 없다는 것을 나타낸다.

SubjectValidationService의 전형적인 예는 Subject가 "lock" Credential을 가지고 있는지 여부를 체크하는 것이다. 만약 "lock" Credential을 가지고 있다면, Subject는 Lock에 걸린 것으로 취급되어 더 이상의 로그인 프로세스가 진행되지 않는다.

SubjectValidationService.checkValidity(Subject) 메소드는 보통 로그인 과정에서 호출된다. 만약 이 메소드에서 SecurityException이 발생되면, 모든 로그인 과정은 실패로 돌아간다. Subject에 "lock" Credential을 자동으로 설정하기 위해서 EventHandlingService가 사용된다. 이에 관한 자세한 설명은 “5.4.10. EventHandlingService SPI”를 참고한다.

인증(파라미터로 넘어온 Subject가 실제 해당 Subject인지 검증하는 것)과 Subject 유효성 검사는 서로 별개의 것이나 로그인 과정에는 2가지 서비스가 모두 사용된다.

도메인당 0개 이상의 SubjectValidationService 인스턴스가 설정될 수 있다. 전체 SubjectValidationService에서 SecurityException이 하나도 발생하지 않으면, Subject는 유효하다고 판단되고, 로그인 과정이 계속 진행된다. 그러나 만약 SecurityException이 한 곳이라도 발생하면 전체 유효성 검사는 실패로 돌아가고 로그인 과정은 더 이상 진행되지 않는다.

참고

SubjectValidationService SPI는 CredentialVerificationService와 많은 점에서 비슷해 보이지만 기능명에서 다르다.

SubjectValidationService는 Credential을 체크해서 Subject가 유효한지 아닌지를 판단하고, CredentialVerificationService는 해당 Subject가 실제 Subject인지 증명하는 Credential을 최소한 하나라도 가지고 있는지를 체크한다. 따라서, SubjectValidationService는 Subject가 성공적으로 인증된 후 사용되고, 반면에 CredentialVerificationService는 AuthenticationService에서 인증 과정 중에 사용된다.

jeus.security.spi.AuthenticationService는 Subject를 인증하기 위한 클래스이다. 즉, 파라미터로 넘겨받은 Subject가 Subject 저장소에 등록되어 있는 실제 Subject와 일치하는지 검증하는 것이다.

인증 과정은 다음과 같다.

  1. jeus.security.spi.CredentialMappingService.getSubjectName(Object) 메소드를 호출하여 Subject의 Credential이 어떤 사용자에 매핑되는지 확인한다.

  2. jeus.security.spi.AuthenticationRepository.getSubject(String username) 메소드를 호출하여 Subject 저장소로부터 실제 등록되어 있는 Subject를 로컬로 복사해온다. 이를 로컬 Subject라고 한다.

  3. 만약 로컬 Subject가 null이 아니라면 로컬 Subject의 Credential과 인증할 Subject의 Credential이 일치하는지 비교한다. 이 비교는 jeus.security.spi.CredentialVerificationService.verifyCredentials(Subject, Subject) 메소드를 호출하여 수행된다.

    몇몇 경우에는 equals(Objet)를 사용하여 Credential을 비교하기도 하는데, 이는 유연한 방법이 아니다.

  4. 위의 과정이 모두 성공적으로 완료되면 로컬 Subject가 authenticate(Subject) 메소드로부터 리턴되고, 결국 이 Subject를 사용하여 SecurityCommonService로 로그인한다.

도메인당 1개 이상의 AuthenticationService를 설정할 수 있다. 만약 설정된 AuthenticationService 중 최소한 하나라도 Subject를 성공적으로 인증했다면 모든 AuthenticationService가 인증한 것으로 간주한다. 즉, 단 하나의 AuthenticationService라도 성공적으로 Subject를 인증했다면, 추가적으로 다른 AuthenticationService에 Query를 던지지 않는다.

jeus.security.spi.CredentialVerificationService SPI는 새로운 타입의 Proof Credential을 지원하기 위해 사용된다.

Proof Credential는 파라미터로 넘어온 Subject가 실제 존재하는 Subject인지 검증하기 위해 사용되는 Credential이다. Proof Credential의 전형적인 예가 바로 패스워드로 jeus.security.resource.Password 클래스로 구현된다.

CredentialVerificationService SPI는 서브 클래스가 반드시 구현해야 하는 단 하나의 메소드인 doVerifyCredentials(Subject, Subject)를 선언하고 있다. 이 메소드 Signature에서 첫 번째로 나오는 Subject는 "reference Subject"라고 하고, Subject 저장소에 등록되어 있는 실제 Subject의 Credential들을 가지고 있다. 두 번째로 나오는 Subject는 "proof Subject"라고 하고, "proof Credential"들을 가지고 있다. doVerifyCredentials(Subject, Subject) 메소드는 2개의 Subject의 Credential들을 서로 비교해서 하나라도 일치하는 것이 있는지 확인한다.

Credential들 간의 매칭은 다양한 방법으로 이루어진다(보통 equals(Object) 메소드만으로는 충분하지 않다). 만약 두 Subject 간에 하나라도 일치하는 Credential이 있다면 메소드는 리턴되고, 그렇지 않다면 jeus.security.base.SecurityException이 발생한다.

참고

몇몇 경우에는 Reference Subject에 대한 정보가 필요없을 때가 있다. 즉, 특정 Proof Credential의 경우 Proof Subjet에 대한 정보만 가지고 Credential을 검증할 수 있다. 예를 들어 특정 Certificate Credential의 경우가 그렇다.

jeus.security.resource.Password를 매치하는 CredentialVerificationService는 jeus.security.impl.verification.PasswordVerificationService 클래스이다.

도메인당 0개 이상의 CredentialVerificationService를 설정할 수 있다. 만약 최소한 하나의 CredentialVerificationService에서라도 매칭이 확인되면 전체 CredentialVerificationService가 모두 성공한 것으로 간주된다. 그렇지 않으면 SecurityException이 발생하고, 전체 검증은 모두 실패한 것으로 간주되어 결과적으로 인증 과정이 실패하게 된다.

EventHandlingService SPI는 각종 보안 이벤트를 캡쳐해서 처리하는 인터페이스이다.

EventHandlingService SPI를 사용하면 보안 이벤트가 발생할 때 로그를 남기고 관리자에 자동으로 메일을 보내고, Subject에 Lock을 설정하는 등의 작업을 쉽게 구현할 수 있다.

기본 개념은 매우 간단한데 보안 서비스에서 발생한 jeus.security.base.Event 타입의 이벤트는 같은 보안 도메인에 설정되어 있는 모든 EventHandlingService들에 통보된다. 그러면 EventHandlingService는 이벤트의 내용에 따라 각각 다르게 처리한다.

EventHandlingService의 예로 Subject에 Lock을 거는 경우를 생각해 볼 수 있다. AuthenticationService(인증 서비스)가 실패할 때마다 “security.authentication.failed” 타입의 이벤트가 발생한다. 그러면 lockout EventHandlingService가 이벤트를 캐치하여, handleEvent(Event) 메소드를 실행시킨다. 이 메소드 내부에서는 로그인 횟수를 카운트하고 있다가 특정 값(예를 들면 3회) 이상에 도달하면 해당 Subject에 "lock" Credential을 설정한다.

이후 SubjectValidationService는 해당 Subject에 Lock이 걸렸음을 확인하고, 결과적으로 이 Subject로의 로그인 시도는 모두 실패하게 만든다. SubjectValidationService와 EventHandlingService를 결합하면, 한번에 3회 이상 로그인에 실패한 Subject에 Lock을 걸어 더 이상 시스템에 로그인 시도를 할 수 없게 만드는 기능을 추가할 수 있다.

그러나 EventHandlingService SPI가 가장 빈번하게 사용되는 곳은 이벤트를 기록하는 Logger를 구현할 때 이다. 이벤트는 일반 텍스트나 XML 파일에 기록되기도 하지만, 때때로 부인방지를 위해 암호화된 파일이 사용되기도 한다.

도메인당 0개 이상의 EventHandlingService를 설정할 수 있다.

새로운 SPI 구현 클래스를 컴파일한 다음, 이 클래스를 JEUS 보안 시스템에 등록해야 한다. 등록하는 방법은 “2.3. 보안 도메인 구성요소 설정”을 참고한다.