Developer: Java
  다운로드
Oracle TopLink
Oracle JDeveloper 10g
Oracle Database
샘플 코드
  태그
java, security, All

Java 애플리케이션에 로우 레벨 보안 구현하기


저자 – Oracle Fusion Middleware 리저널 디렉터 Lonneke Dikmans

데이터베이스에서 캐시에 이르는 전체 J2EE 애플리케이션 환경에 로우 레벨 보안을 구현하는 방법에 대해 알아 보십시오.

게시일: 2007년 7월

보안은 애플리케이션에서 매우 중요한 요소입니다. 사용자들은 인증 과정을 거쳐야 하며, 데이터는 불법적인 접근으로부터 보호되어야 합니다. 오라클은 별도의 개발 작업 없이도 데이터베이스의 로우 레벨 보안을 구현할 수 있는 솔루션인 Oracle Label Security를 제공합니다. 오픈 소스 Oracle TopLink를 ORM 솔루션으로 이용하여 로우 레벨 보안이 캐시 및 기타 애플리케이션 요소에서 적용, 관리됨을 보장할 수 있습니다. 본 문서는 아주 간단한 형태의 샘플 애플리케이션을 통해 로우 레벨 보안의 구현 원리를 설명하고 있습니다.

샘플 애플리케이션

샘플 애플리케이션은 HR 스키마를 사용하는 간단한 웹 애플리케이션으로 구현되었습니다. 사용자는 애플리케이션에 로그인하고 자신에게 허용된 지역의 데이터를 조회할 수 있습니다.

아래 그림은 애플리케이션 스키마의 네 가지 영역을 보여 주고 있습니다:

  • 데이터소스 계층. 데이터소스 계층은 Oracle RDBMS에 포함된 HR Schema입니다. 본 문서의 샘플 애플리케이션에서는 Countries, Locations, LOCATION_SEQ 오브젝트만이 사용됩니다. LOCATION 테이블을 위해 정의된 정책에 대해서는 다음 섹션에서 설명합니다.
  • 도메인 계층. 도메인 계층은 Java, Oracle TopLink, EJB 세션 파사드(session facade)를 사용하여 도메인 클래스에 대한 간단한 작업을 정의하고 있습니다. 이 기능은 로컬/원격 인터페이스를 통해 공개됩니다.
  • 프리젠테이션 계층. 프리젠테이션 계층은 사용자가 조회할 수 있는 모든 지역을 표시하는 하나의 JSF(JavaServer Faces) 페이지로 구성됩니다. 이 페이지는 (예제의 단순화를 위해) 기본 HTTP 인증을 사용하며 ADF 데이터 바인딩을 통해 도메인 계층에 연결됩니다.
  • 통합 테스트. 이 컴포넌트는 데이터소스 계층과 도메인 계층의 통합 테스트를 위한 코드를 포함하고 있습니다. 도메인 계층에 대해서는 원격 인터페이스가 사용됩니다.

Figure 1
그림 1 샘플 애플리케이션의 스키마 개요

Oracle Label Security 개요

오라클은 여러 가지 형태의 데이터베이스 액세스 컨트롤 기능을 제공합니다. 각각의 기능에 대해 잠시 살펴보도록 하겠습니다.

Discretionary Access Control (DAC). DAC는 데이터베이스 사용자들에게 오브젝트 레벨의 권한을 할당합니다. 접근은 오브젝트 단위로 허용 또는 거부됩니다. 한 예로, 아래와 같은 구문을 실행하여 SKING 사용자에게 LOCATIONS 테이블에 대한 SELECT 작업을 수행할 수 있도록 허용할 수 있습니다:

grant select to hr.locations to sking;
이제 SKING은 LOCATIONS 테이블의 모든 로우를 조회할 수 있습니다. 여기서 데이터베이스 사용자 대신 역할(role)에 대해 권한을 정의하는 것도 가능합니다. 이 경우, 개별 데이터베이스 사용자에게 권한을 허용하는 대신, 먼저 역할에 특정 권한을 허용하고 다시 이 역할을 데이터베이스 사용자에게 할당하는 방법이 사용됩니다.
create role emp_role;
grant connect to emp_role;
grant select to hr.locations to emp_role;
grant emp_role to SKING;
Fine-Grained Access Control (FGAC). FGAC는 "로우-레벨 보안"이라고도 불리며, 데이터의 컨텐트를 기준으로 접근을 통제하는 기능을 제공합니다. 이러한 형태의 요구 사항을 지원하는 오라클 데이터베이스 솔루션으로, Enterprise Edition에 포함된 기능인 Virtual Private Database(VPD)가 있습니다. VPD는 보안 정책과 세션 컨텍스트를 기준으로 다이내믹하게 쿼리를 수정합니다. VPD는 반환되는 로우를 제한하는 기능 이외에도, 컬럼 마스킹을 지원합니다.

보안 정책은 스토어드 프로시저를 이용하여 구현됩니다. 여기서 보안 정책은 오라클 데이터베이스에 저장된 애플리케이션 데이터 컨텐트 또는 컨텍스트 변수(사용자 이름, IP 주소 등)를 기준으로 접근을 통제하는데 사용됩니다.

Oracle Label Security (OLS)는 Enterprise Edition 옵션으로 제공되는 기능으로 VPD를 기반으로 구현됩니다. 관리자는 PL/SQL 코드를 작성하지 않고도 OLS를 이용하여 정책을 쉽게 생성할 수 있습니다. 데이터에 대한 접근 허용 여부는 4 가지 요소를 기준으로 결정됩니다.

  • 로우의 레이블
  • 사용자 세션의 레이블
  • 세션의 정책 권한
  • 테이블을 위한 정책 적용 옵션

로우 레이블

테이블의 각 로우에는 보안 요구 사항을 기준으로 레이블이 할당될 수 있습니다. 각 레이블은 3 가지 구성 요소를 갖습니다:

  1. 단일 레벨 (sensitivity) 랭킹
  2. 0개 또는 그 이상의 수평적 구분자(horizontal compartment) 또는 카테고리
  3. 0개 또는 그 이상의 계층적 그룹(hierarchical group)

샘플 애플리케이션에서는 "access_locations"라는 이름의 정책을 사용하여 누가 어떤 Location을 조회할 수 있는지 결정합니다. 샘플 애플리케이션에서는 구분자 또는 그룹이 사용되지 않습니다. 레벨은 'public' ('pub'), 'confidential' ('conf'), 'sensitive' ('sens')로 구분됩니다.

사용자 레이블

사용자에 대한 레이블 기반 인증을 통해, 레이블 처리된 로우에 대한 권한(읽기 또는 쓰기)이 결정됩니다. 로우에 레이블이 적용된 경우, 해당 레이블에 대한 접근 권한을 갖는 사용자만이 로우를 조회하거나 변경할 수 있습니다.

사용자가 데이터베이스에 연결될 때마다, 사용자 세션의 레이블은 해당 로우의 레이블과 매치됩니다.

권한

OLS는 특수 권한(special privilege)를 통해 권한을 가진 사용자가 특정 정책을 '우회(bypass)'할 수 있는 기능을 제공합니다. HR은 스키마의 소유자이므로 샘플 애플리케이션에 대한 FULL 권한을 가지고 있습니다. 따라서 정책에 의해 보호되는 모든 데이터를 읽고 쓸 수 있는 권한을 가집니다.

정책 실행

사용자는 데이터 쓰기 작업을 수행하면서 해당 로우의 레이블을 설정할 수 있습니다. 레이블의 레벨은 관리자가 미리 설정한 레벨 중 어떤 것이라도 선택이 가능합니다. 사용자가 레이블을 명시하지 않고 데이터 쓰기 작업을 완료한 경우, 사용자의 세션 레이블을 기준으로 자동으로 로우 레이블이 할당됩니다.

아래 표는 샘플 애플리케이션에 정의된 사용자 레이블을 정리하고 있습니다.

User

Max read

Max write

Min write

Default label

Default row

SKING 'sens' 'sens' 'conf' 'sens' 'sens'
KPARTNER 'conf' 'conf' 'pub' 'conf' 'conf'
LDORAN 'pub' 'pub' 'pub' 'pub' 'pub'

DAC와 FGAC의 조함. 아래 그림은 사용자가 LOCATIONS 테이블을 조회했을 때 어떤 작업이 발생하는지 보여 주고 있습니다.

Figure 2
그림 2. DAC, FGAC를 조합한 플로우

먼저, 데이터베이스는 DAC를 기준으로 사용자가 충분한 권한을 갖고 있는지 확인합니다. 사용자가 hr.locations 테이블을 조회할 수 있는 권한을 가지고 있다면, 데이터베이스는 다음으로 사용자가 정책을 우회할 수 있는 특수 권한을 가지고 있는지 점검합니다. 사용자가 특수 권한을 가지고 있지 않다면, 정책을 기준으로 접근이 통제됩니다. 사용자가 특수 권한을 가지고 있다면, 정책은 무시되며 전적으로 사용자의 권한을 기준으로 쿼리가 수행됩니다.

샘플 애플리케이션에 포함된 테스트 스크립트는 서로 다른 사용자가 로그인하여 동일한 쿼리를 실행할 때 어떤 상황이 발생하는지 보여 주고 있습니다.

SQL*Plus를 열고 아래와 같이 실행하여 서로 다른 사용자가 전체 location 정보를 조회하도록 합니다.

@[path-to_file]\ols_test_security_policy.sql	  
데이터베이스에 접근한 사용자가 누구인지에 따라, 동일한 쿼리가 서로 다른 결과를 반환함을 확인할 수 있을 것입니다.

Oracle TopLink 세션

Oracle TopLink 세션은 Oracle TopLink 런타임에서 사용되는 커뮤니케이션 메커니즘입니다. 세션에는 여러 가지 형태가 있습니다. 하나의 세션은 아래와 같은 컴포넌트로 구성됩니다:

  • Java 오브젝트 빌더. Oracle TopLink는 데이터소스로부터 읽어 들인 결과를 오브젝트로 변환하고, 쓰기 작업에 대해 오브젝트를 쿼리로 변환합니다.
  • 쿼리 메커니즘. 세션은 오브젝트에 대한 모든 퍼시스턴스 작업을 실행합니다.
  • 커넥션 풀. 커넥션 풀은 하나의 데이터소스 내에서 사용 가능한 모든 재활용 가능한 연결을 포함하고 있습니다. 커넥션 풀은 연결 생성에 수반되는 오버헤드를 제거함으로써 애플리케이션의 성능을 극적으로 개선할 수 있게 합니다. Oracle TopLink는 내부적으로 구현된 커넥션 풀 또는 Java Platform, J2EE 서버 또는 JDBC 드라이버가 제공하는 외부 커넥션 풀을 사용할 수 있습니다.
  • 공유 캐시. 캐시는 데이터베이스에서 읽기/쓰기 처리되는 모든 오브젝트를 저장합니다. 서버 세션으로부터 생성되는 모든 클라이언트 세션은 이 캐시를 공유합니다. 캐시 역시 성능 관점에서 매우 중요한 역할을 담당합니다.
아래에서는 VPD나 OLS를 사용하지 않은 "일반적인" Java EE 애플리케이션 환경에서의 Oracle TopLink 세션에 대해 설명하고 있습니다.

데이터의 읽기. 데이터소스로부터 데이터를 읽어 오는 과정에서 Oracle TopLink에 발생하는 작업 내역이 아래와 같습니다:

  • 서버 세션으로부터 클라이언트 세션을 가져옴
  • 쿼리 빌더를 이용하여 쿼리를 작성
  • 캐시를 확인하여 데이터를 읽어오거나, 오브젝트가 캐시에 저장되지 않은 경우 데이터베이스로부터 읽어 옴
  • 결과를 오브젝트로 변환
전체 국가 정보를 읽어 오기 위한 코드가 아래와 같습니다:
	 
/**
* finds all countries
* @return List<Country> or an empty list if none are found
*/
public List<Country> findAllCountries() {
	Session session = getSessionFactory().acquireSession(); 
	List<Country> results = 
         (List<Country>)session.executeQuery("findAllCountries", Country.class);
	session.release();
	results = (List<Country>)getSessionFactory().detach(results);

	return results;
}	
The query is defined in the class descriptor, as can be seen below:
	 
<class-descriptor-query-manager>
   <query-manager>
      <descriptor-alias>Countries</descriptor-alias>
         <query-list>
            <query>
               <name>findAllCountries</name>
               <query-type>
                  oracle.toplink.queryframework.ReadAllQuery
               </query-type>
               <cache-usage>Check Cache by Primary Key</cache-usage>
               <lock-mode>Do Not Acquire Locks</lock-mode>
               <distinct-state>Uncomputed Distinct</distinct-state>
               <in-memory-query-indirection-policy>
			Throw Indirection Exception
		   ..etc..
            </query>
         </query-list>
      </query-manager>
session.executeQuery(...)는 가장 먼저 공유 캐시로부터 국가 정보를 가져 오려고 시도합니다. 오브젝트가 캐시에 저장되어 있지 않은 경우에는 session.xml에 저장된 연결을 사용하여 데이터베이스로부터 읽어 옵니다.

데이터의 쓰기. 데이터소스에 데이터를 쓰는 과정에서도 위와 유사한 작업이 실행됩니다.

  1. 데이터소스에 데이터를 쓰는 과정에서도 위와 유사한 작업이 실행됩니다.
  2. UnitofWork 내에 오브젝트를 생성
  3. 쿼리 빌더와 커넥션 풀에서 가져온 연결을 이용하여 데이터베이스에 데이터를 커밋
오브젝트를 데이터베이스에 쓰기 위한 코드의 예가 아래와 같습니다:
	 
/**
* saves an entity
* @param entity that needs to persisted
* @return Object that is persisted.
*/
public Object persistEntity(Object entity) {
	UnitOfWork uow = getSessionFactory().acquireUnitOfWork();
	Object existingObject = uow.readObject(entity);
       if (existingObject != null)
		throw new RuntimeException("Entity already exists");
        Object newInstance = uow.deepMergeClone(entity);
        uow.commit();

        return newInstance;
    }	 
	 
UnitOfWork는 트랜잭션의 단위로서 기능하며, 데이터베이스에 기록된 내용이 서버 캐시에도 기록됨을 보장합니다. 이와 같은 방법으로 캐시로부터 변경된 국가 정보를 읽어 오는 경우에도, 업데이트된 정확한 결과를 보장할 수 있습니다.

커넥션 풀. JEE 애플리케이션을 개발할 때에는 Oracle TopLink와 함께 외부 커넥션 풀을 사용하는 것이 일반적입니다. 이 경우, 데이터 읽기 작업과 쓰기 작업에 각각 별도의 커넥션 풀이 사용됩니다.

기본적으로 TopLink는 내부 커넥션 풀을 사용합니다. 따라서 이 경우에는 쓰기 작업을 위해, 그리고 읽기 작업을 위해 각각 서로 다른 커넥션 풀이 사용됩니다.

Figure 3
그림 3 Toplink 커넥션 풀 옵션

Oracle TopLink와 VPD

앞 섹션에서, 일반적인 Java EE 애플리케이션 구성과 공유 캐시, 커넥션 풀링 등에 대해 설명했습니다. 하지만 샘플 애플리케이션에서는 좀 더 복잡한 형태의 솔루션이 요구되고 있습니다. 먼저, 모든 사용자가 공유 캐시를 사용하도록 할 수는 없습니다. 모든 사용자가 모든 데이터를 조회할 수 있도록 허용되지 않기 때문입니다. 두 번째로, 접근 권한을 통제하기 위해서 데이터베이스는 연결되는 사용자에 대한 정보를 관리하고 있어야 합니다. 마지막으로, 데이터베이스에 삽입되는 새로운 데이터의 보안 레벨을 컨트롤할 수 있어야 합니다.

이를 위해 Oracle TopLink와 VPD를 함께 활용하여 상호 격리된 클라이언트 세션을 설정하고 프록시 인증을 적용합니다.

상호 격리된 클라이언트 세션. 상호 격리된(isolated) 클라이언트 세션이란 각각 별도의 세션 캐시를 갖도록 설정된 클라이언트 세션을 의미합니다.

Figure 4
그림 4 상호 격리된 클라이언트 세션

VPD 또는 OLS를 사용하는 경우, 모든 테이블은 상호 격리되어야 합니다. 전체 프로젝트에 대해 또는 클래스에 대해서만 격리 설정을 할 수 있습니다. 상호 격리된 클래스에서 공유 클래스를 참조하는 것은 허용되지만, 그 반대는 허용되지 않습니다. 샘플 애플리케이션에서는 location으로부터 country를 참조할 수 있으나, 그 반대 방향의 참조는 불가합니다. 이와 같은 방법으로 클래스 레벨의 격리를 설정하는 것이 가능합니다. 클래스를 격리하는 방법에는 두 가지가 있습니다. 그 하나는 워크벤치를 사용하는 것이고, 또 하나는 Java 코드를 이용하는 것입니다.

워크벤치에서 클래스를 격리하는 방법이 아래와 같습니다:
  1. 네비게이터에서 Location을 선택합니다.
  2. Cache 탭을 클릭합니다.
  3. isolated를 선택합니다.
  4. 변경 사항을 저장합니다.
변경된 session.xml이 아래와 같습니다:
	 
<transactional-policy type="relational">
      <descriptor-alias>Location</descriptor-alias>
      <refresh-cache-policy/>
      <caching-policy>
         <cache-coordination>None</cache-coordination>
         <cache-isolation>Isolated</cache-isolation>
      </caching-policy>
      <query-manager type="relational"/>
      <locking-policy type="relational"/>
      <primary-key-policy>
         <primary-key-handles>
            <column-handle>
               <column-table-name>LOCATIONS</column-table-name>
               <column-name>LOCATION_ID</column-name>
            </column-handle>
         </primary-key-handles>
      </primary-key-policy>
 </transactional-policy>	 
	 
Oracle JDeveloper에서는 매핑 에디터를 이용하여 캐싱의 격리 설정을 수행할 수 있습니다. 세션을 커스터마이즈 하는 방법에는 두 가지가 있습니다. 그 하나는 SessionEventListener 세션의 preLogin 메소드를 사용하는 것이고 또 하나는 SessionManager에서 getSession() 메소드를 사용하는 것입니다.

Oracle JDeveloper에서는 매핑 에디터를 이용하여 캐싱의 격리 설정을 수행할 수 있습니다. 세션을 커스터마이즈 하는 방법에는 두 가지가 있습니다. 그 하나는 SessionEventListener 세션의 preLogin 메소드를 사용하는 것이고 또 하나는 SessionManager에서 getSession() 메소드를 사용하는 것입니다.

	 
public class LocationEventListener extends SessionEventAdapter {

   //other methods you want to override 

 /**
 * We isolate the Location class here.
 * @param event that is raised before the session is logged in.
 */
 public void preLogin(SessionEvent event) {
   logger.info("in prelogin event");
   ClassDescriptor descriptor = event.getSession().getClassDescriptor(Location.class);
   descriptor.setIsIsolated(true);
  }
}
아래와 같이 매핑 에디터에서 세션에 클래스를 추가합니다.

Figure 5
그림 5 이벤트 리스너를 이용한 세션 설정

SessionManager.getSession(...) 메소드를 사용하려면, 로그인하지 않은 상태에서 가져온 세션에 클래스 디스크립터(class descriptor)를 설정한 후 로그인합니다.

	 
private Server getSession(){
	Server server = (Server)sessionManager.getSession(xmlSessionConfigLoader, "hr", false);
	ClassDescriptor descriptor = server.getClassDescriptor(Location.class);
   	descriptor.setIsIsolated(true);
   	server.login();
	//.... rest of code....
}	 
 

연결

OC4J 10.1.3 이후 버전에서는 매니지드(managed)와 네이티브(native)의 두 가지 데이터 소스가 지원되고 있습니다. 매니지드 데이터 소스는 JDBC 드라이버 또는 데이터소스에 대해 래퍼(wrapper)로서 동작하는 java.sql.DataSource 인터페이스를 이용하여 구현되며 OC4J에 의해 제공됩니다. 매니지드 데이터 소스는 글로벌 트랜잭션에 참여할 수 있으며 커넥션 풀을 사용합니다. 네이티브 데이터소스는 java.sql.DataSource 인터페이스를 통해 구현되며 JDBC 드라이버 벤더에 의해 제공됩니다.

하나의 Oracle TopLink 프로젝트 내에서 서로 다른 유형의 서버 세션을 정의할 수 있습니다. 아래에서는 매니지드 데이터소스(jdbc/hrDS)와 네이티브 데이터 소스의 구현 예를 보여 주고 있습니다. sessions.xml에 정의된 내용이 아래와 같습니다:

	 
<?xml version = '1.0' encoding = 'UTF-8'?>
<!DOCTYPE toplink-configuration PUBLIC "-//Oracle Corp.//DTD TopLink Sessions 9.0.4//EN" "sessions_9_0_4.dtd">
<toplink-configuration>
   <session>
	<!-- managed datasource -->
      <name>hr</name>
      <project-xml>META-INF/locationMap.xml</project-xml>
      <session-type>
         <server-session/>
      </session-type>
      <login>
         <datasource>jdbc/hrDS</datasource>
         <uses-native-sequencing>true</uses-native-sequencing>
      </login>
     <!-- etc -->
   </session>
   <session>
	<!-- native datasource -->
      <name>sking</name>
      <project-xml>META-INF/locationMap.xml</project-xml>
      <session-type>
         <server-session/>
      </session-type>
      <login>
         <driver-class>oracle.jdbc.OracleDriver</driver-class>
         <connection-url>jdbc:oracle:thin:@localhost:1521:ORCL</connection-url>
         <platform-class>oracle.toplink.platform.database.oracle.Oracle10Platform</platform-class>
         <user-name>sking</user-name>
         <encryption-class-name>oracle.toplink.internal.security.JCEEncryptor</encryption-class-name>
         <encrypted-password>F21B2AE50E304BA0D81243DD794296A5</encrypted-password>
      </login>
   </session>
</toplink-configuration>
이름을 기준으로 올바른 세션을 가져오기 위해 세션 팩토리(session factory)를 사용할 수 있습니다. 사용할 세션을 정의하는 방법이 아래와 같습니다.
	 
this.sessionFactory =  new SessionFactory("META-INF/sessions.xml", "hr");
     Session session = getSessionFactory().acquireSession();	 
매니지드 데이터소스를 사용할 때에는, VPD 관련 SQL 구문을 쿼리에 추가하기 위한 로직을 개발자가 직접 구현해야 합니다. 하지만 좀 더 간단한 방법으로 프록시 인증을 사용할 수 있습니다. 본 문서의 샘플 애플리케이션에서, 모든 사용자는 데이터베이스에 의해 확인이 가능하므로 프록시 인증의 활용이 가능합니다. OC4J 10g (10.1.3.x)는 Oracle JDBC 네이티브 데이터소스를 위한 프록시 인증을 지원합니다. 이 작업은 워크벤치 또는 Oracle JDeveloper에서는 지원되지 않으며, 별도의 Java 코딩이 필요합니다.

본 문서의 예제에서는 유저네임만을 기준으로 프록시 인증을 수행하기로 합니다. (보다 상세한 설명은 How-To 문서: OC4J 10g (10.1.3) 데이터 소스를 이용한 프록시 인증의 설정 및 사용을 참고하시기 바랍니다.)

수행해야 할 작업이 아래와 같습니다:

  1. 사용자를 변경합니다: alter user ldoran grant connect through hr;
  2. 아래 코드를 추가하여 프록시 인증을 통해 상호 격리된 클라이언트 세션을 가져옵니다:
    /**
    * Returns an isolated client session from the server session
    * @return isolated client session.
    */
    private Session getSession() {
    	Server server = 
                (Server)sessionManager.getSession(new XMLSessionConfigLoader(),  
                                                  HR_SESSION_CONFIG, 
                                                  Thread.currentThread().getContextClassLoader());
           DatabaseLogin login = (DatabaseLogin)server.getLogin().clone();
           login.dontUseExternalConnectionPooling();
            // this also sets isLazy flag to false
           ConnectionPolicy policy = new ConnectionPolicy(login);
           policy.setShouldUseExclusiveConnection(server.getDefaultConnectionPolicy(). 
                                                   shouldUseExclusiveConnection());
           // Set proxy properties into connection policy's login
           JNDIConnector connector = (JNDIConnector)login.getConnector();
           login.setConnector(new OracleJDBC10_1_0_2ProxyConnector(connector.getName())); 
            String user = getUser();
            login.setProperty(PROXYTYPE, 
                              Integer.toString(OracleConnection.PROXYTYPE_USER_NAME));
            login.setProperty(OracleConnection.PROXY_USER_NAME, user);
            return server.acquireClientSession(policy);
        }
    
    컨텍스트로부터 웹 애플리케이션에 로그인한 사용자 정보를 가져올 수 있습니다:
    /**
    * Gets the Principal that logged in from the context
    * @return the name of the caller principal. 
    * 
    */
    private String getUser(){
       String user = ctx.getCallerPrincipal().getName();
       logger.info("user that logged in: " + user);
       return user;
    }
    

독점적 연결(Exclusive Connection) VPD, OLS가 적용된 경우에는 애플리케이션에서 독점적 연결(exclusive connection)을 사용하는 것이 일반적입니다. Oracle TopLink는 세션의 라이프사이클 기간 동안 격리된 데이터의 읽기/쓰기 작업을 수행하기 위해 클라이언트 세션에 독점적 연결을 할당합니다. 독점적 연결은 서버 세션의 쓰기 커넥션 풀로부터 가져옵니다. Oracle TopLink는 격리되지 않은 데이터의 읽기를 위해 읽기 커넥션 풀로부터 공유 커넥션을 별도로 가져 옵니다.

독점적 연결을 사용하려면 아래 코드를 추가합니다:

//......
ConnectionPolicy policy = new ConnectionPolicy(login);
policy.setShouldUseExclusiveConnection(server.getDefaultConnectionPolicy(). 
                                        shouldUseExclusiveConnection());
//... rest of the code

결론

본 문서를 통해 TopLink 환경에서 Java EE 웹 애플리케이션에 Oracle Label Security를 구현하는 방법을 배워 보았습니다. 또 샘플 애플리케이션을 이용하여 웹 애플리케이션과 데이터베이스 보안을 설정하고 보안 정책을 적용하는 방법이 설명되었습니다. 오라클 데이터베이스의 보안 기능, 그리고 Java EE의 보안 기능 매우 강력한 효과를 발휘합니다.

실제 애플리케이션 환경에서는 Oracle Internet Directory에 보안 설정을 저장함으로써 사용자, 역할, 권한을 보다 쉽게 관리할 수 있도록 하는 것이 바람직할 것입니다. 샘플 애플리케이션에서는 데이터베이스에 대한 읽기 작업만을 수행하며, 쓰기 작업은 발생하지 않습니다. 데이터가 데이터베이스에 기록되고 옵티미스틱 락킹이 사용되는 경우, 'no-rows modified' 이벤트를 위한 핸들러를 추가해 주어야 합니다. 이 이벤트는 보안 위반 또는 락킹 오류로 인해 발생할 수 있습니다. 락킹이 문제가 되는 경우, 애플리케이션은 오브젝트를 다시 데이터베이스 쓰려 시도합니다. 보안이 문제가 된 경우에는 익셉션이 발생합니다.

Happy coding!


Lonneke Dikmans은 Oracle Fusion Middleware 리저널 디렉터 겸 Oracle ACE이며, 네덜란드의 Approach Alliance에서 매니징 파트너로 일하고 있습니다. 그녀는 SOA 및 민첩성 있는 개발을 전문 분야로 하는 아키텍트로서, 2000년부터 JDeveloper를 사용해 왔으며 Java 애플리케이션의 설계, 개발, 구축에 관련한 풍부한 경험을 보유하고 있습니다.
E-mail this page
Printer View Printer View