Anyframe IAM

1.1.3

본 문서의 저작권은 삼성SDS에 있으며 Anyframe 오픈소스 커뮤니티 활동의 목적하에서 자유로운 이용이 가능합니다. 본 문서를 복제, 배포할 경우에는 저작권자를 명시하여 주시기 바라며 본 문서를 변경하실 경우에는 원문과 변경된 내용을 표시하여 주시기 바랍니다. 원문과 변경된 문서에 대한 상업적 용도의 활용은 허용되지 않습니다. 본 문서에 오류가 있다고 판단될 경우 이슈로 등록해 주시면 적절한 조치를 취하도록 하겠습니다.


I. Anyframe IAM
1. Anyframe IAM Overview
1.1. What is Security ?
1.2. What is Spring Security ?
1.3. Anyframe IAM의 특징
1.4. Why Anyframe IAM ?
1.5. Anyframe IAM의 주요기능
1.6. 참조 오픈소스
2. Anyframe IAM Technical Specification
II. Anyframe IAM Install
3. Anyframe IAM Core Install
3.1. library 카피
3.2. Configuration
4. Anyframe IAM Admin Install
4.1. war 파일 배포
4.2. Configuration
III. Anyframe IAM Core
5. Anyframe IAM Core
5.1. 공유 컴포넌트(Shared Components)
5.2. 웹 어플리케이션의 인증 및 권한 처리 절차
5.3. Anyframe IAM Core 의 특징
6. IAM Core Configuration
6.1. Security Configuration
6.2. Database Configuration
6.3. IAM Core Extensions Configuration
7. Access Control
IV. Anyframe IAM Admin
8. Anyframe IAM Admin
8.1. Anyframe IAM Admin 특징
8.2. Anyframe IAM Admin 서비스
9. Admin 환경 설정 방법
9.1. remote-invoker-servlet.xml
10. IAM Admin 사용방법 Overview
10.1. User Management
10.2. Roles Management
10.3. Resource Management
10.4. Restriction Management
10.5. System Management
10.6. 시스템별 권한 관리
A. Authentication / Authorization
A.1. Intro
A.2. Filter Chain
A.3. 보안 객체(Secured Object)의 저장 구조
A.4. 주요 보안 객체 모델
A.5. Web Authorization
A.6. Method Authorization
B. IAM Database Schema
B.1. User Schema
B.2. Group Schema
B.3. Role Schema
B.4. Secured Resource Schema
B.5. View Resource Schema
B.6. Restricted Times Schema
B.7. IDS Schema
B.8. Excel Import/Export Schema

Anyframe IAM은 Java EE 기반의 엔터프라이즈 어플리케이션을 위한 보안 솔루션(사용자 인증 및 권한관리)을 제공하는 Identity & Access Management Framework 이다. Java EE 기반의 엔터프라이즈 어플리케이션은 사용자 인증 및 권한관리에 대한 다양한 요구사항을 가지고 있으며, 각각의 엔터프라이즈 어플리케이션에 대하여 이러한 기능들을 매번 새로이 개발하는 것은 많은 추가 비용과 리소스를 부담하게 한다. Anyframe IAM은 Spring Security 를 기반으로 하여 Anyframe 또는 Spring Framework 기반으로 작성된 엔터프라이즈 어플리케이션을 위한 인증 및 권한관리 기능을 제공함으로써, 개발 생산성을 향상시키고 사용자 인증 및 권한관리에 능동적이고 유연한 형태의 어플리케이션을 개발할 수 있도록 지원하는 프레임워크이다.

위 그림은 Anyframe IAM의 기본 구조도이다. Anyframe IAM은 Anyframe 또는 Spring Framework 기반의 엔터프라이즈 어플리케이션에 설치되어 사용자/그룹/역할/자원/시간별접근 등의 기능을 제공한다.
  • IT 영역에서의 보안이란 정보 자산(시스템 / 프로그램 / 데이터..) 에 대한 허가되지 않은 접근을 막는 것을 말한다.

  • 일반적으로 인증 (Authentication) , 권한 처리(Authorization) 라는 두 주요 기능을 포함한다.

  • 엔터프라이즈 어플리케이션을 위한 강력하고 유연한 보안 솔루션으로, 특히 Spring 기반의 어플리케이션에 강점을 가지고 있다. 기존 Servlet 스펙 Security 는 컨테이너 별 설정 및 이식성 문제와 웹 요청(request) 에 제한된 보안만 고려하는 한계가 있는데 비하여, Spring Security 는 서비스 레이어 및 도메인 객체 수준의 보안을 제공하며 설정에 기반한 유연한 보안 적용을 기반으로 보안 레이어 컴포넌트의 재사용성이 높은 오픈 소스 보안 프레임워크이다. 다양한 환경의 많은 사이트를 통해 검증되었으며 가장 활발한 커뮤니티와 빠른 기능 개선이 이루어지는 대표적인 Spring 의 서브프로젝트이기도 하다.

  • Spring Security 기반 IAM Core: 엔터프라이즈 어플리케이션에 설치되어 사용자 인증 및 권한관리를 제어하는 IAM Core 는 Spring Security 기반으로 작성되어 있으며, 일반적으로 DB 기반으로 구축된다. Anyframe 또는 Spring 기반의 어플리케이션에 적용시 기존 어플리케이션의 변경 영향을 최소할 수 있다.

  • 독립적인 형태의 IAM Admin Console: IAM Core 의 동작은 DB의 데이타를 기반으로 하여 구성되며, 이때 DB의 내용을 관리하기 위한 툴이 IAM Admin Console이다. 기존 엔터프라이즈 어플리케이션과 별도로 동작하므로 어플리케이션과의 독립적인 형태로 관리 기능을 구성할 수 있다.

  • Spring Security 의 강력한 기능을 그대로 계승: Spring Security 의 강력한 기능을 계승하고 확장하였으며, 유연하고 확장성 있는 형태의 사용자 인증 및 권한관리 기능을 제공하여 준다.

  • Spring Security 는 XML 기반의 설정만 지원하므로 (2.0.X 부터는 Namespace 를 통한 간소한 설정이 가능하지만 마찬가지로 XML 설정임)사용자, 역할, 보호자원, 권한맵핑 등에 대한 관리가 어려운 기능 취약점이 존재한다.

  • 우리나라 SI 실정에 맞는 best practice 인증/권한 처리와 관리 기능의 요구사항을 표준화 / 기능 확장 / 정제하여 Web UI 화면 기반으로 일반 사용자 조작을 통해 관리가 가능토록 Spring Security 강점과 SI 프로젝트 활용성을 두루 갖춘 유연하고 강력한 IAM 프레임워크 확보가 필요하였다.

Anyframe IAM의 Core 는 Spring Security 을 기반으로 하고 있으며, Anyframe 또는 Spring 기반의 비지니스 어플리케이션에 설치되어 기존 업무 코드의 변경을 최소화 화면서 사용자 인증 및 권한관리 기능을 추가할 수 있다. 특히 DB 기반으로 확장된 설정 정보를 바탕으로 동작한다는 점에서, 기존의 XML 방식으로 설정 정보를 저장하는 Spring Security 와 차이점을 지니고 있다.

  • Service Layer 및 사용자 정의 리소스 접근 제어(ACL)

    일반적으로 권한 체크는 웹 요청(request)에 대한 제어를 의미한다. Spring Security 에 기반한 IAM Core 는 웹 요청에 대한 제어 뿐만 아니라 서비스 레이어 및 도메인 객체 에 대한 권한 제어를 통해 보안을 처리할 수 있다. 또한 현장에서 요구가 많은 화면에 대한 permission 체크 기능을 제공하는 view resource 접근과 관련한 Tag 및 API 를 제공하고 있다.

  • 관심 영역의 분리

    Servlet Filter 와 Java AOP를 통한 가로채기(Interception)을 사용하여 보안을 부여하며, Spring 의 Ioc와 Lifecycle서비스 기반으로 동작하여 일반적인 업무 코드 영역과 분리되어 동작한다.

  • Database 기반의 설정

    IAM Core 의 기반이 되는 Spring Security 는 기본적으로 XML 기반의 설정을 통해 보안 설정을 통제한다. Anyframe의 IAM Core 는 일반적으로 널리 사용되는 DB 기반의 설정을 지원함으로써 XML 방식보다 보편적이며, 간단하고 유연한 방식으로 보안 관련 설정을 제어할 수 있다.

Anyframe 은 IAM Core 동작의 기반이 되는 Database 설정을 관리하기 위한 IAM Admin 웹 어플리케이션을 제공한다. IAM Admin은 jQuery, SpringMVC, HibernateJPA 등의 기술 요소를 기반으로 하여 구축되어 있으며, 관리자 권한을 가진 사용자는 IAM Admin 의 UI 에서 제공되는 기능들을 통하여 DB 기반의 보안 설정을 조작하고 제어할 수 있다.

  • Cross Browser를 지원하는 RIA 기반의 UI

    jQuery 를 사용하여 화면 Refresh가 최소화된 동적인 UI를 제공하며 , Internet Explorer 를 포함한 Cross Browser 환경을 지원한다.

  • 타겟 어플리케이션 권한 리로드

    명시적인 권한 리로드 기능을 통하여 변경된 권한정보를 타겟 어플리케이션에 반영할 수 있으며, 클러스터링 환경에서의 권한 리로드를 지원한다.

  • 타겟 어플리케이션 정보 수집

    관리 대상 어플리케이션의 자원 정보를 수집하는 기능을 제공하여 자원 등록을 손쉽게 할 수 있도록 지원한다.

  • 시간 제한 설정 기반의 권한 관리

    특정 리소스나 역할에 대한 시간 범위를 설정하여 접근을 제어할 수 있으며, 이에 대한 예외 규칙도 설정이 가능하다.

  • Auto Complete 지원을 통한 손쉬운 자원 등록

    타켓 어플리케이션의 수집된 자원 정보를 바탕으로 보호된 자원 등록시 사용자에게 동적인 UI 기반의 가이드를 제공한다.

  • 어플리케이션 통합관리

    하나의 Admin Console 을 통하여 다수의 어플리케이션을 통합관리할 수 있다.

  • Excel Data Import/Export

    Excel 파일의 Import/Export 기능을 이용하여 초기 데이타 구축 및 현 상태의 백업을 손쉽게 할 수 있다.

Anyframe IAM에서 사용하고 있는 주요 오픈소스는 다음과 같다.

Anyframe IAM을 적용하기 위한 기술적인 스펙은 다음과 같다.

  • Java Versions : JDK 1.5

  • Core Framework : Anyframe Java - Core Framework (또는 Spring Framework 기반 프레임워크)

  • Web Framework : Anyframe Java - Web Framework (또는 SpringMVC 기반 Web 프레임워크)

  • Presentation Layer : JSP

현재 1.1.3 버전은 Presentation Layer의 제어를 위한 태그 라이브러리 지원을 JSP에 한하여 제공하고 있으며, 각 UI 제품별 기능 추가는 시장 상황에 따라 제공 여부를 판단하여 지원할 예정이다. Anyframe IAM에서는 Struts Framework 기반의 권한제어는 지원하지 않는다.

이번 장에서는 사용자 어플리케이션에 설치되어 인증 및 권한 제어를 담당하는 Anyframe IAM Core를 설치 하는 절차에 대해서 알아본다.

IAM Core 설치 절차는 다음과 같다.

  • library 카피

  • Configuration

IAM Core 1.1.3 설치에는 jar 형식의 라이브러리 파일을 복사하는 과정이 필요하다.

아래의 jar 파일들은 Anyframe-iam-1.1.3-bin.zip 패키지에 포함된 anyframe-iam-sample-1.1.3.war 파일을 압축 해제하면 존재하는 WEB-INF/lib 디렉토리 이하에 위치한다. 입수된 jar 파일들을 해당 Web Application의 /WEB-INF/lib 폴더에 카피한다.

  • anyframe-iam-core-1.1.3.jar

  • anyframe-core-1.0.1.jar

  • spring-security-acl-3.0.2.RELEASE.jar

  • spring-security-cas-client-3.0.2.RELEASE.jar

  • spring-security-config-3.0.2.RELEASE.jar

  • spring-security-core-3.0.2.RELEASE.jar

  • spring-security-ldap-3.0.2.RELEASE.jar

  • spring-security-openid-3.0.2.RELEASE.jar

  • spring-security-taglibs-3.0.2.RELEASE.jar

  • spring-security-web-3.0.2.RELEASE.jar

일반적인 경우 샘플 어플리케이션에서 제공하는 설정을 그대로 사용하면된다. 본 문서에서는 주요 설정 및 사용자 정의가 가능한 부분을 위주로 설명을 한다.

어플리케이션의 messageSource Bean 설정(주로 context-common.xml)에 IAM 메시지 파일을 추가한다.

<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
    <property name="basenames">
        <list>
            ..
            <value>anyframe/iam/core/messages/security</value>
        </list>
    </property>
</bean>

모든 웹 요청이 Spring Security의 DelegatingFilterProxy로 전달되도록 web.xml에 설정을 추가한다.

<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>

<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

보호대상 자원 정보 수집 및 런타임 갱신을 IAM Admin에서 Remote로 처리 할 수 있는 설정을 spring-security-servlet.xml 파일에 추가한다.

특별한 경우가 아니라면 샘플에서 제공하는 설정을 그대로 사용해도 무방하다. 다만 Resource 정보 수집시 추가적으로 제외하고 싶은 자원이 있는 경우 아래와 같이 설정을 한다.

아래의 설정은 패키지 명이 org, net, java, anyframe(단 anyframe.iam.sample로 시작하는 자원은 제외)으로 시작하는 자원을 정보 수집 대상에서 제외하는 설정의 예이다.

<bean id="resourceGatherAssistService"
    class="org.anyframe.iam.core.assist.impl.ResourceGatherAssistServiceImpl" >
    <property name="filterPatterns">
        <list>
            <value>(?!anyframe\.iam\.sample\..*)anyframe\..*</value>
            <value>org\..*</value>
            <value>net\..*</value>
            <value>java\..*</value>
        </list>
    </property>
</bean>

이하 세팅은 context-spring-security.xml 파일에 적용한다.

http 하위 태그로 form-login을 지정하여 Form 기반 인증을 설정하고 login-page, login-processing-url, authentication-failure-url, default-target-url을 지정한다.

login-processing-url는 반드시 /j_spring_security_check 로 설정한다.

또한 logout 태그를 이용하여 logout 성공후에 이동할 페이지를 지정한다.

<http path-type="regex" lowercase-comparisons="false">
    <form-login login-page="/common/login.do" login-processing-url="/j_spring_security_check"
        authentication-failure-url="/common/login.do?login_error=1"
        default-target-url="/index.jsp?flag=L" />

        <anonymous />
        <logout logout-success-url="/index.jsp" />
</http>

jdbcUserService Bean의 property 설정으로 사용자 인증과 권한(Role) 정보에 대한 쿼리를 설정한다.

usersByUsernameQuery의 경우 USER_ID, PASSWORD, ENABLED 필드는 항상 1,2,3 번째 순서로 나타나야만 한다.

<b:bean id="jdbcUserService"
    class="org.anyframe.iam.core.userdetails.jdbc.ExtJdbcUserDetailsManager" >
    <!-- USER_ID, PASSWORD, ENABLED 는 항상 1,2,3 번째 순서로 나타나야 함!! -->
    <b:property name="usersByUsernameQuery" value="SELECT USER_ID, PASSWORD, CASE WHEN ENABLED = 'Y' THEN 1 ELSE 0 END ENABLED, USER_NAME, CREATE_DATE, MODIFY_DATE FROM USERS WHERE USER_ID = ?"/>
    <b:property name="authoritiesByUsernameQuery">
        <b:value>
            SELECT USER_ID,ROLE_ID,GROUP_ID,SUBJECT_ID,TYPE
            FROM AUTHORITIES C, (
                SELECT A.USER_ID,B.GROUP_ID
                FROM USERS A LEFT OUTER JOIN GROUPS_USERS B ON ( A.USER_ID = B.USER_ID )
                WHERE A.USER_ID = ? ) D
            WHERE ( C.SUBJECT_ID = D.USER_ID
                OR C.SUBJECT_ID = D.GROUP_ID )
        </b:value>
    </b:property>
    <b:property name="dataSource" ref="dataSource"/>
</b:bean>

이하 세팅은 context-spring-security.xml 파일에 적용한다.

IAM 에서는 Spring Security 의 보호자원, RoleHierarchy 정보, 확장한 Time 기반의 보호자원에 대한 데이터를 DB 기반으로 처리하고 있다.

SecuredObject에 대한 기본설정은 아래와 같다. IAM에서 제공하는 DB를 사용 할 경우 아래의 설정만으로 충분하다. (systemName 속성은 다수의 어플리케이션을 관리하여야 하는 경우에만 사용한다.)

<b:bean id="securedObjectService" class="org.anyframe.iam.core.securedobject.impl.SecuredObjectServiceImpl">
    <b:property name="securedObjectDAO" ref="securedObjectDAO" />
</b:bean>

<b:bean id="securedObjectDAO" class="org.anyframe.iam.core.securedobject.impl.SecuredObjectDAO">
    <b:property name="dataSource" ref="dataSource" />
    <!--b:property name="systemName" value="SAMPLE" /-->
</b:bean>

이하 세팅은 context-spring-security.xml 파일에 적용한다.

만약 IAM에서 제공하는 DB Schema를 동일하게 사용 할 수 없어 별도의 사용자화가 필요한 경우, SecuredObject에 대한 사용자 설정을 통해서 IAM Core의 적용이 가능하다.

사용자 설정은 아래와 같이 securedObjectDAO bean의 하위에 property 설정을 통해 가능하다. 단, 이 경우 IAM Admin Console 사용을 위해서는 customizing이 필요하다.

<b:bean id="securedObjectDAO" class="org.anyframe.iam.core.securedobject.impl.SecuredObjectDAO">
    <b:property name="dataSource" ref="dataSource" />
    <b:property name="sqlRolesAndUrl">
        <b:value>
            SELECT a.resource_pattern url, b.role_id authority
            FROM secured_resources a, secured_resources_roles b
            WHERE a.resource_id = b.resource_id
                AND a.resource_type = 'url'
            ORDER BY a.sort_order, a.resource_id
        </b:value>    	
    </b:property>
</b:bean>

사용자 설정이 가능한 Secured Object 항목과 기본 쿼리는 다음과 같다.

  • sqlRolesAndUrl : url 형식 보호자원-Role 매핑

    SELECT a.resource_pattern url, b.role_id authority
    FROM secured_resources a, secured_resources_roles b
    WHERE a.resource_id = b.resource_id
        AND a.resource_type = 'url'
    ORDER BY a.sort_order, a.resource_id

  • sqlRolesAndMethod : method 형식 보호자원-Role 매핑

    SELECT a.resource_pattern url, b.role_id authority
    FROM secured_resources a, secured_resources_roles b
    WHERE a.resource_id = b.resource_id
        AND a.resource_type = 'method'
    ORDER BY a.sort_order, a.resource_id

  • sqlRolesAndPointcut : pointcut 형식 보호자원-Role 매핑

    SELECT a.resource_pattern url, b.role_id authority
    FROM secured_resources a, secured_resources_roles b
    WHERE a.resource_id = b.resource_id
        AND a.resource_type = 'pointcut'
    ORDER BY a.sort_order, a.resource_id

  • sqlRegexMatchedRequestMapping : request best matching url 보호자원-Role 매핑

    SELECT a.resource_pattern uri, b.role_id authority
    FROM secured_resources a, secured_resources_roles b
    WHERE a.resource_id = b.resource_id
        AND a.resource_id =
            ( SELECT resource_id FROM
                ( SELECT resource_id, ROW_NUMBER() OVER (ORDER BY sort_order) resource_order FROM secured_resources c
                WHERE REGEXP_LIKE ( :url, c.resource_pattern )
                    AND c.resource_type = 'url'
                ORDER BY c.sort_order )
            WHERE resource_order = 1 )

  • sqlHierarchicalRoles : Role 계층구조

    SELECT a.child_role child, a.parent_role parent
    FROM roles_hierarchy a LEFT JOIN roles_hierarchy b on (a.child_role = b.parent_role)

  • sqlRestrictedTimesRoles : 실행시간 권한제어 restricted times roles 매핑

    SELECT time_type, a.time_id as time_id, start_date, start_time, end_date, end_time, role_id
    FROM restricted_times a, restricted_times_roles b
    WHERE a.time_id = b.time_id
    ORDER BY time_type, start_date, start_time, end_date, end_time

  • sqlRestrictedTimesResources : 실행시간 권한제어 restricted times resources 매핑

    SELECT time_type, a.time_id as time_id, start_date, start_time, end_date, end_time, b.resource_id as resource_id, resource_pattern, role_id as exclusion_role_id
    FROM restricted_times a,
        restricted_times_resources b left outer join times_resources_exclusion c
        on (b.time_id = c.time_id and b.resource_id = c.resource_id)
        , secured_resources d
    WHERE a.time_id = b.time_id
        AND b.resource_id = d.resource_id
        AND d.resource_type = 'url'
    ORDER BY d.sort_order, time_type, start_date, start_time, end_date, end_time

  • sqlViewResourceMapping : 조건(ROLE 리스트, 사용자 아이디)에 따른 view resource 매핑(sqlViewResourceMapping)

    SELECT view_resource_id, ref_type, ref_id, mask, permissions
    FROM view_resources_mapping
    WHERE view_resource_id = :viewResourceId
        AND (
            ( ref_id IN ( {{userRoleList}} ) AND ref_type = 'ROLE' )
            OR ( ref_id = :userId AND ref_type = 'USER' )
            OR ( ref_id = :groupId AND ref_type = 'GROUP' )
        )
    ORDER BY CASE ref_type WHEN 'USER' THEN 1 WHEN 'GROUP' THEN 2 WHEN 'ROLE' THEN 3 ELSE 10 END, ref_id

이하 세팅은 context-spring-security.xml 파일에 적용한다.

모든 요청에 대해서 Spring Security Filter Chain을 통해 처리 하지만 보호 예외 대상으로 등록 할 경우 Filter Chain을 거지치 않고 자원을 제공한다.(일반적으로 image, css, js 파일등에 대해서 설정한다.)

http 하위의 intercept-url 태그로 보호 예외 대상 자원에 대해 filters="none" 을 지정한다.

<http path-type="regex" lowercase-comparisons="false">
    <intercept-url pattern="\A/sample/images/.*\Z" filters="none" />
    <intercept-url pattern="\A/sample/css/.*\Z" filters="none" />
    <intercept-url pattern="\A/sample/javascript/.*\Z" filters="none" />
</http>

이하 세팅은 context-spring-security.xml 파일에 적용한다.

계층형 구조의 Role 정보를 사용할 경우 아래와 같이 설정한다. IAM은 기본적으로 계층형 Role 정보를 사용하도록 설정되어 있다. (Role 정보를 가져오는 방법은 Secured Object 설정을 참조한다.) 만약 계층형 Role 구조를 사용하지 않으려면 설정하지 않는다.

<b:bean id="roleHierarchy" class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl">
    <b:property name="hierarchy" ref="hierarchyStrings" />
</b:bean>

<b:bean id="hierarchyStrings" class="org.anyframe.iam.core.userdetails.hierarchicalroles.HierarchyStringsFactoryBean" init-method="init">
    <b:property name="securedObjectService" ref="securedObjectService" />
</b:bean>

이하 세팅은 context-spring-security.xml 파일에 적용한다.

사용자가 정의한 View Resource에 대해 매핑된 Permission 을 체크할 수 있는 기능을 제공한다. 대상 시스템에 필요한 권한을 선택적으로 적용 할 수 있다.

  • 기본 권한 : READ, WRITE, CREATE, DELETE, ADMINISTRATION

  • 추가 권한 : LIST, PRINT, REPORT, POPUP, DOWNLOAD, UPLOAD, HELP

  • 기타 예약 권한 : FNC0, FNC1, FNC2, FNC3, FNC4, FNC5, FNC6, FNC7, FNC8, FNC9

다음은 READ, WRITE, CREATE, DELETE, DOWNLOAD 권한만을 설정한 예제이다.

<b:bean id="viewResourceAccessService"
    class="org.anyframe.iam.core.acl.impl.ViewResourceAccessServiceImpl">
    <b:property name="securedObjectService" ref="securedObjectService" />
    <b:property name="registeredPermissions">
        <b:list>
            <b:ref local="org.anyframe.iam.core.acl.ExtBasePermission.READ" />
            <b:ref local="org.anyframe.iam.core.acl.ExtBasePermission.WRITE" />
            <b:ref local="org.anyframe.iam.core.acl.ExtBasePermission.CREATE" />
            <b:ref local="org.anyframe.iam.core.acl.ExtBasePermission.DELETE" />
            <b:ref local="org.anyframe.iam.core.acl.ExtBasePermission.DOWNLOAD" />
        </b:list>
    </b:property>
</b:bean>

<b:bean id="org.anyframe.iam.core.acl.ExtBasePermission.READ"
    class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
    <b:property name="staticField"
        value="org.anyframe.iam.core.acl.ExtBasePermission.READ" />
</b:bean>
<b:bean id="org.anyframe.iam.core.acl.ExtBasePermission.WRITE"
    class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
    <b:property name="staticField"
        value="org.anyframe.iam.core.acl.ExtBasePermission.WRITE" />
</b:bean>
<b:bean id="org.anyframe.iam.core.acl.ExtBasePermission.CREATE"
    class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
    <b:property name="staticField"
        value="org.anyframe.iam.core.acl.ExtBasePermission.CREATE" />
</b:bean>
<b:bean id="org.anyframe.iam.core.acl.ExtBasePermission.DELETE"
    class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
    <b:property name="staticField"
        value="org.anyframe.iam.core.acl.ExtBasePermission.DELETE" />
</b:bean>
<b:bean id="org.anyframe.iam.core.acl.ExtBasePermission.DOWNLOAD"
    class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
    <b:property name="staticField"
        value="org.anyframe.iam.core.acl.ExtBasePermission.DOWNLOAD" />
</b:bean>

이번 장에서는 IAM Core가 사용하는 DB 설정을 관리자가 손쉽게 조작 할 수 있도록 하는 Anyframe IAM Admin 설치 절차에 대해서 알아본다.

IAM Admin의 설치 절차는 다음과 같다.

  • WAS에 anyframe-iam-admin-web-1.1.3.war 배포

  • remote-invoker-servlet.xml 파일 설정

다운로드 받은 Anyframe-iam-1.1.3-bin.zip 파일의 압축을 해제 하면 나오는 anyframe-iam-admin-web-1.1.3.war 파일을 WAS에 배포한다.

WAS 별 배포 방법에 대한 설명은 본 문서 범위를 넘어가므로 생략하였다.

war 파일 배포 후 /WEB-INF/config/springmvc/remote-invoker-servlet.xml 파일을 열어서 gatherServiceClient, resourceReloadServiceClient Bean의 serverUrl Property 설정 값을 대상 시스템의 url로 설정한다.

serviceUrl property에서 굵은 글씨로 표시된 부분이 수정해야할 대상이다.

<bean id="gatherServiceClient"
    class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">				
    <property name="serviceUrl"
        value="
        http://localhost:8080/anyframe-iam-sample/assist/resourceGatherAssist.do" />
    <property name="serviceInterface"
        value="org.anyframe.iam.core.assist.IResourceGatherAssistService" />
    <property name="httpInvokerRequestExecutor">		
        <bean class="org.springframework.security.context.httpinvoker.
        					AuthenticationSimpleHttpInvokerRequestExecutor" />
    </property>
</bean>

<bean id="resourceReloadServiceClient"
    class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
    <property name="serviceUrl"
        value="
        http://localhost:8080/anyframe-iam-sample/reload/resourceReload.do" />
    <property name="serviceInterface"
        value="org.anyframe.iam.core.reload.IResourceReloadService" />
    <property name="httpInvokerRequestExecutor">
        <bean class="org.springframework.security.context.httpinvoker.
        					AuthenticationSimpleHttpInvokerRequestExecutor" />
    </property>
</bean>

WebLogic 배포시 유의 사항 1

Anyframe IAM 의 WAS별 배포시 WebLogic 에서는 Hibernate 와 연관하여 org.hibernate.hql.ast.HqlToken 클래스의 ClassNotFoundException 이 발생한다.

공식적으로 Hibernate 와 WebLogic 간의 antlr 라이브러리의 충돌 문제는 다음 링크과 같이 발표되어 있다.

https://www.hibernate.org/250.html

웹로직에서는 다음과 같이 세가지 방법으로 해당 문제점을 회피할 수 있다. Anyframe IAM에서는 이 중 세번째 방법을 사용하고 있으며, 아래 내용은 Hibernate 를 WebLogic 에 적용하는 경우 공통적인 조치사항이기도 하다.

첫번째 방법 : WAR 의 경우

WEB-INF/classes/weblogic.xml 을 다음과 같이 설정한다.

<?xml version="1.0" encoding="UTF-8"?>
<wls:weblogic-web-app xmlns:wls="http://www.bea.com/ns/weblogic/90"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
        http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd 
        http://www.bea.com/ns/weblogic/90 
        http://www.bea.com/ns/weblogic/90/weblogic-web-app.xsd">
    <wls:weblogic-version>10.0</wls:weblogic-version>
    <wls:jsp-descriptor>
        <wls:page-check-seconds>3</wls:page-check-seconds>
        <wls:precompile>false</wls:precompile>
    </wls:jsp-descriptor>
    <wls:container-descriptor>
        <wls:servlet-reload-check-secs>3</wls:servlet-reload-check-secs>
        <wls:resource-reload-check-secs>-1</wls:resource-reload-check-secs>
        <wls:prefer-web-inf-classes>true</wls:prefer-web-inf-classes>
    </wls:container-descriptor>
    <wls:context-root>anyframe-iam-admin-web</wls:context-root>
    <wls:charset-params>
        <wls:input-charset>
            <wls:resource-path>/*</wls:resource-path>
            <wls:java-charset-name>utf-8</wls:java-charset-name>
        </wls:input-charset>
    </wls:charset-params>
</wls:weblogic-web-app>

두번째 방법 : EAR 의 경우

EAR 패키지의 META-INF/weblogic-application.xml 을 다음과 같이 설정한다.

<?xml version="1.0" encoding="UTF-8"?>
<wls:weblogic-application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:wls="http://www.bea.com/ns/weblogic/90"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
        http://java.sun.com/xml/ns/j2ee/j2ee_1_4.xsd
        http://www.bea.com/ns/weblogic/90
        http://www.bea.com/ns/weblogic/90/weblogic-application.xsd">
    <wls:prefer-application-packages>
        <wls:package-name>antlr.*</wls:package-name>
    </wls:prefer-application-packages>
</wls:weblogic-application>

세번째 방법 : 클래스패스에 antlr 을 추가

%WL_HOME%\common\lib 디렉토리에 antlr-2.7.6.jar 을 복사한 후setDomainEnv.cmd 파일(또는 .sh 파일)에

set PRE_CLASSPATH=%WL_HOME%\common\lib\antlr-2.7.6.jar(UNIX sh : set PRE_CLASSPATH="${WL_HOME}/common/lib/antlr-2.7.6.jar"와 같이 추가해준다.

WebLogic 배포시 유의 사항 2

또한 WebLogic 에서는 Hibernate 3.5.3, jpa 2.0 과 관련하여 javax.persistence.OneToMany.orphanRemoval()의 NoSuchMethodException 이 발생한다

이는 weblogic.xml 에서 prefer-web-inf-classes을 true 로 조정하여도 별다른 효과가 없는데,

JEUS 6.0 에서는 다음과 같은 방법으로 해당 문제점을 회피할 수 있다.

앞서와 같은 방법으로 해당 문제점을 회피할 수 있다.

 

클래스패스에 hibernate-jpa-2.0-api-1.0.0.Final 을 추가(이전 설정 내용-antlr-에 추가됨)

%WL_HOME%\common\lib 디렉토리에 hibernate-jpa-2.0-api-1.0.0.Final.jar 을 복사한 후setDomainEnv.cmd 파일(또는 .sh 파일)에

set PRE_CLASSPATH=%WL_HOME%\common\lib\antlr-2.7.6.jar;%WL_HOME%\common\lib\hibernate-jpa-2.0-api-1.0.0.Final.jar

(UNIX sh : set PRE_CLASSPATH="${WL_HOME}/common/lib/antlr-2.7.6.jar:${WL_HOME}/common/lib/hibernate-jpa-2.0-api-1.0.0.Final.jar") 와 같이 추가해준다.

JEUS 6.0 배포시 유의 사항

Anyframe IAM 의 WAS별 배포시 JEUS 6.0 에서는 JPA 라이브러리와 연관하여 기동시 오류가 발생한다.

JEUS 6.0 은 라이브러리 내에 JPA 1.0 대의 라이브러리를 임의적으로 포함하고 있으나, JPA 2.0대 기반의 어플리케이션을 구동하는 경우 라이브러리 간의 충돌로 인하여 정상적으로 기동이 되지 않는다.

JEUS 6.0 에서는 다음과 같은 방법으로 해당 문제점을 회피할 수 있다.

 

1. %JEUS_HOME%/lib/system/javaee.jar 에서는 압축을 해제한 후 javax.persistence 패키지 삭제하여 다시 패키지 (jar cf javaee.jar javaee)

2. %JEUS_HOME%/lib/system/ 의 toplink-essentials.jar 와 toplink-essentials-agent.jar 는 삭제 또는 확장자를 org 로 변경

3. hibernate-jpa-2.0-api-1.0.0.Final.jar 을 %JEUS_HOME%/lib/system/에 배포

Anyframe IAM(Identity & Access Management) Core는 Spring Security Framework을 기반으로 인증 및 권한관리 기능을 제공한다. 현재 Anyframe IAM 에 적용된 Spring Security Framework의 버전은 3.0.2 이다.

IAM Core 는 Java EE 기반의 엔터프라이즈 어플리케이션을 위한 통합 보안 서비스(인증 및 권한관리)를 제공한다. 또한 Java EE 기반의 엔터프라이즈 어플리케이션 개발을 위하여 가장 널리 사용되는 Spring Framework 이나 Anyframe 기반의 프로젝트를 지원한다. 일반적으로 어플리케이션에 보안 기능을 추가하여야 하는 경우 어플리케이션 환경을 재구성하기 위한 일련의 제반 작업들이 수반되는데, 이는 개발 생산성 측면에서의 부담을 야기한다. 그러나 IAM Core 를 사용하면 이러한 최소화된 형태의 설정 작업을 통해 유연하고 강력한 보안 기능들을 사용할 수 있다.

IAM Core 에서 핵심적인 컴포넌트들을 공유 컴포넌트(Shared Components) 라고 하며, IAM Core 의 핵심 기능들은 이러한 공유 컴포넌트들을 기반으로 동작한다. 공유 컴포넌트들은 기타 다른 컴포넌트들과의 결합을 통해 전체 구조를 표현할 수 있다. 그중에서도 가장 중요한 객체는 SecurityContextHolder 이다. 기본적으로 SecurityContextHolder 는 ThreadLocal 을 이용하여 어플리케이션의 보안 컨텍스트의 세부사항 및 인증 주체에 대한 세부 사항을 보관한다.

Spring Security 의 주요 공유 컴포넌트들은 다음과 같으며, 해당 컴포넌트에 대한 추가 정보는 본 문서의 Appendix A. Authentication / Authorization 및 Spring Security 의 공식 매뉴얼 (http://static.springsource.org/spring-security/site/docs/3.0.x/reference/springsecurity.pdf)을 참고하기 바란다.

  • SecurityContextHolder : SecurityContext 에 대한 모든 유형의 access 를 제공한다.

  • SecurityContext : Authentication 객체를 담고 있으며, 또한 request 에 특정한 보안정보를 유지 할 수도 있다.

  • HttpSessionContextIntegrationFilter : 웹 요청 간의 SecurityContext 를 HttpSession 에 저장한다.

  • Authentication : Spring Security 에 특정한 방법으로 인증주체를 표현한다.

  • GrantedAuthority : 인증주체에 대한 어플리케이션 범위의 권한을 나타낸다.

  • UserDetails : 어플리케이션의 DAO 를 사용하여 Authentication 객체를 작성할 수 있도록 필요한 정보를 제공한다.

  • UserDetailsService : String 기반의 username(또는 인증 ID, 일반적으로 userId 로 사용함)이 전달되었을 때 UserDetails 를 생성한다.

일반적인 웹 어플리케이션의 인증 및 권한 처리 절차는 다음과 같다.

위 그림은 웹 어플리케이션의 인증 및 권한 처리 절차를 나타내는 순서도이다. 자원에 대한 요청이 발생하면 해당 자원이 보호된 자원인지를 판별한 후, 다음으로 인증 된 사용자인지를 판단한다. 인증 되지 않은 사용자는 로그인 프로세스를 거친 후 해당 자원에 대한 접근 권한이 있는지를 판단하게 되고 최종적으로 보호된 자원을 제공하게 된다.
  • 1. 자원(img/html 등의 static 웹 리소스 또는 .do/jsp 등의 dynamic 웹 리소스) 요청

  • 2. 보호된 자원(secured resources)인지 판단

  • 3. 인증된 사용자인지 판단 -> 인증된 경우 다음 단계 진행 / 인증 정보가 없는 경우 인증을 위한 처리로 분기

  • 4. 아직 인증이 되지 않은 경우 로그인 페이지로 이동 (기존 요청 url 은 인증 성공 후 진행할 수 있도록 보관)

  • 5. 인증 메커니즘에 따라 사용자 로그인 (일반적으로 id/password 를 HTML Form 을 통해 post 방식으로 submit)

  • 6. 신원 정보(credential)가 유효한지 판단 -> 유효 시 다음 단계 진행 / 유효치 않을 시 에러 페이지 이동 또는 신원 정보 재요청(로그인 실패 정보 설정하여 로그인 페이지로 되돌아감)

  • 7. 해당 보호 자원에 대한 접근 권한이 있는지 판단 -> 있으면 보호 자원 제공 / 접근 권한 없을 시 Access Denied 에러 페이지로 이동

인증 및 권한 처리 절차에 대한 상세한 내용을 원할 경우 다음의 링크를 참조하면 된다.

  • 타겟 어플리케이션에 설치되어 인증 및 권한 처리 제어

  • DB 기반의 보호자원, 권한 맵핑 처리 제공

  • 런타임 보호자원-권한 맵핑 (Web Url, Restricted Times Roles/Resources) reload 기능 제공

  • 사용자 정의 viewResource 에 대한 Permission 체크 기능 제공

  • Anyframe IAM 의 DB Schema 를 사용할 수 없거나 JDK 1.4 환경인 경우 1.1.3 이전 버전의 IAM Core 단독으로 적용 가능 cf.) 데이터 관리는 업무 프로젝트에서 대응해야 함

Anyframe IAM Core 의 기반이 되는 Spring Security 는 기본적으로 XML 설정만을 지원한다. 하지만 XML 설정 방식만을 지원하는 경우 방대하고 복잡한 속성 파일들로 인해 시스템 유지보수시 비용 발생 및 지연을 초래할 가능성이 높아지며 일반적인 엔터프라이즈 어플리케이션에서 선호되는 형태의 설정 방식이 아니다.

이러한 문제점을 해결하기 위해 Ayframe IAM Core 는 Spring Security 를 확장하여 Database 기반의 설정 정보를 기반으로 동작하도록 개발되었다. 본 문서에서는 IAM Core 의 설정방법에 대해 상세히 살펴보도록 한다.

일반적으로 Spring Security 기본 기능 적용을 위한 필수 라이브러리는 다음과 같다.

  • spring-security-core-3.0.2.RELEASE.jar

  • spring-security-taglibs-3.0.2.RELEASE.jar

  • spring-security-web-3.0.2.RELEASE.jar

IAM Core 에서는 spring-security-core, spring-security-acl, spring-security-taglibs, spring-web 의 기능을 확장하여 제공하고 있다. 이 외에도 Spring, AspectJ 등 AOP 관련 라이브러리, Apache Commons 일부 라이브러리 등을 함께 사용하고 있다.

web.xml 등록

  • org.springframework.web.filter.DelegatingFilterProxy 등록 : Application Context에 Spring 빈으로 등록된 필터 구현체를 대표하는 Spring Framework 클래스이다.

  • 모든 웹요청이 Spring Security의 DelegatingFilterProxy로 전달되도록 한다.

  • DelegatingFilterProxy는 웹요청이 서로 다른 URL 패턴에 근거하여 서로 다른 필터로 전달될 수 있도록 해주는 일반 목적용으로 사용할 수 있는 클래스이다.

  • 이런 위임된 필터들은 어플리케이션 컨텍스트 내에서 관리되며, 따라서 Dependency Injection 의 이점을 누릴 수 있다.

<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>

<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

..
<!-- if you wish to use Concurrent Session Control
<listener>
	<listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
</listener>
 -->
		

Security Namespace

  • since Spring Security 2.0.x

  • 이전의 복잡한 Security bean 설정에 비해 매우 간소한 설정

  • 하부 구현의 이해없이 가장 일반적으로 사용되는 케이스에 대해 미리 만들어 제공

  • 모든 Security 기능을 포함하지는 않으며 변경/확장하기 어려운 부분이 존재함

Namespace 기반의 Spring Security 설정 파일의 주요 Tag

  • <http>

  • <intercept-url … />

  • <global-method-security />

  • <jdbc-user-service />

Namespace 기반의 Spring Security 설정 예

<b:beans xmlns="http://www.springframework.org/schema/security"
    xmlns:b="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd">
                        
    <http path-type="regex" lowercase-comparisons="false">
        <intercept-url pattern="\A/sample/images/.*\Z" filters="none" />
        <intercept-url pattern="\A/sample/css/.*\Z" filters="none" />
        <intercept-url pattern="\A/sample/javascript/.*\Z" filters="none" />

        <intercept-url pattern="\A/login\.do.*\Z" access="IS_AUTHENTICATED_ANONYMOUSLY" />
        <intercept-url pattern="\A/security/users/list\.do.*\Z" access="ROLE_USER" />
        <intercept-url pattern="\A/.*\.do.*\Z" access="ROLE_RESTRICTED" />
        <intercept-url pattern="\A/.*\Z" access="IS_AUTHENTICATED_ANONYMOUSLY" />
        
        <custom-filter after="FILTER_SECURITY_INTERCEPTOR" ref="filterSecurityInterceptor"/>
        <custom-filter after="EXCEPTION_TRANSLATION_FILTER"
                        ref="restrictedTimesFilterSecurityInterceptor"/>

        <form-login login-page="/login.do" login-processing-url="/j_spring_security_check"
            authentication-failure-url="/login.do?login_error=1"
            default-target-url="/plugins.do" />

        <anonymous />
        <logout logout-success-url="/plugins.do" />

        <!--
            if you wish to use Concurrent Session Control - see also listener
            configuration of web.xml - HttpSessionEventPublisher
        -->
        <session-management>
            <concurrency-control max-sessions="1" error-if-maximum-exceeded="true"/>
        </session-management>
    </http>
    
	<authentication-manager alias="authenticationManager"> 
	    <authentication-provider>
	        <password-encoder hash="md5"/>
	        <jdbc-user-service data-source-ref="dataSource"
	            users-by-username-query="SELECT USER_ID, PASSWORD, ENABLED FROM USERS WHERE USER_ID = ?"
	            authorities-by-username-query="SELECT SUBJECT_ID AS USER_ID, ROLE_ID FROM AUTHORITIES WHERE SUBJECT_ID = ?"
	        />
	    </authentication-provider>
	</authentication-manager>

    <global-method-security secured-annotations="enabled" jsr250-annotations="enabled">
        <protect-pointcut expression="execution(* security..UsersService.remove(..))" access="ROLE_ADMIN" />
    </global-method-security>
    
</b:beans>
		

위는 Spring Security 의 Namespace 태그 기반의 인증/권한 처리 설정 예이다.

  • http 태그를 통해 Spring Security 의 주요 보안 기능이 자동으로 설정된다. 위에서는 path-type 속성을 통해 정규식 url 패턴 매처를 사용하고 있으며, lowercase-comparisons 는 false 로 url 패턴의 대소문자는 원본 그대로 유지한채 비교토록 하고 있는 예이다.

  • http 하위의 intercept-url 태그로 먼저 상단에 images, css, javascript 에 해당하는 정적 웹 리소스에 대해 filters="none" 을 지정하여 Spring Security 의 Filter Chain 을 태우지 않고 무조건 제공토록 설정하였다.

  • intercept-url 태그에 access 속성을 통해 권한을 지정할 수 있으며 위에서 로그인 페이지 이동을 위한 login.do 패턴에 대해서는 아무에게나 접근 가능토록 열려 있다. 또한 /security/users/list.do 에 대해서는 ROLE_USER 권한을 지정하고 있으며 기타 모든 .do 패턴에 대해서는 ROLE_RESTRICTED, 그 외의 모든 패턴에 대해서는 아무나 접근 가능토록 설정한 예이다.

  • form-login 을 지정하여 HTML Form 기반 인증으로 설정하였으며 login-page 나 인증에 실패했을때 되돌아갈 페이지, 인증에 성공했을 때 기본으로 이동할 페이지 등을 지정하고 있다.

  • anonymous 태그를 설정하면 AnonymousProcessingFilter 가 자동으로 추가되며 인증되지 않은 임의의 사용자 접근 시 ROLE_ANONYMOUS 라는 기본 Role 로 처리될 것이다.

  • logout 태그를 통해 logout 성공 시 되돌아갈 페이지를 지정하고 있다.

  • session-management 태그를 통해 한 사용자가 동시 접근할 수 있는 갯수를 지정할 수 있다. 이 태그와 쌍으로 반드시 web.xml 에 HttpSessionEventPublisher 에 대한 Listener 지정이 필요하다.

  • authenication-provider 태그를 기본 설정으로 썼을때 DaoAuthenticationProvider 로 설정되며, JDBC 기반의 UserDetailsService 가 id, password 에 따른 사용자 정보 조회를 위해 사용된다. 위에서는 사용자 패스워드의 암호화를 위해 password-encoder 를 지정하여 복호화가 불가능하도록 One-way hash algorithim 으로 md5 를 지정한 예이다. 사용자 인증 시 암호화된 password 를 비교하여 처리하게 된다. (위에서 나타나지는 않았으나 사용자 password 데이터 변경을 위한 서비스를 개발할 때는 동일하게 password encoder bean 을 통해 암호화해야할 필요성이 있다. 관련 사용예는 Anyframe 의 Security 샘플을 참조하라.)

  • global-method-security 태그를 통해 Method 실행에 대한 보안 제어를 설정하고 있으며 위 예에서는 jsr250 의 @RolesAllowed annotation 및 Spring Security 의 자체 @Secured annotation 을 사용 가능토록 설정하였으며, AspectJ 의 Pointcut 표현식으로 사용자 서비스의 remove 에 대해서는 ROLE_ADMIN 권한을 지정하고 있음을 알 수 있다. Spring AOP 가 적용되기 위해서는 interface - implementation 형태로 서비스를 작성하는 것을 권고하는 바이며, interface 가 없는 경우에 AOP 적용을 위해서는 CGLib 적용이 필요하므로 유의한다.

사용자 인증과 관련된 테이블은 사용자테이블과 사용자권한테이블이며 사용자권한관련 테이블은 역할, 자원, 역할계층 등의 테이블이 있다.

[표제목-IAM Table]
 테이블 명칭설명
사용자정보USERS어플리케이션 사용자 정보
그룹정보GROUPS사용자 그룹 정보
GROUPS_HIERARCHY사용자 그룹간의 계층 정보
GROUPS_USERS사용자 그룹과 사용자 간의 매핑 정보
Role(권한)정보ROLESROLE(권한) 정보
ROLES_HIERARCHYROLE(권한)간의 계층 정보
AUTHORITIESROLE(권한)과 그룹/사용자 매핑 정보
보호자원정보SECURED_RESOURCES보호대상이 되는 자원 정보
SECURED_RESOURCES_ROLES보호대상 자원과 ROLE(권한)과의 매핑 정보
CANDIDATE_SECURED_RESOURCES보호자원으로 등록 될 수 있는 자원 정보
View 정보VIEW_RESOURCES어플리케이션 화면 정보
VIEW_RESOURCES_MAPPING어플리케이션 화면 정보과 ROLE(권한) 정보간의 매핑
VIEW_HIERARCHY화면 정보간의 계층 정보
시간에 의한 제한 관련 정보RESTRICTED_TIMES시스템 사용 제한 시간에 대한 정보
RESTRICTED_TIMES_RESOURCES시스템 사용 제한 시간과 자원 간의 매핑 정보
RESTRICTED_TIMES_ROLES시스템 사용 제한 시간과 ROLE(권한)간의 매핑정보
TIME_RESOURCES_EXCLUSION시스템 사용 제한 예외 정보
기타IDSID 자동생성 관련 정보
DATA_UPLOAD엑셀 Import/Export 를 위한 정보

해당 테이블의 ERD는 다음과 같으며 각 테이블의 DDL 문장은 Appendix B. IAM Database Schema를 참조한다.

위 그림은 IAM Database Schema ERD이다.

Anyframe IAM Core 에서 사용하는 확장 기능 위주의 설정에 대해서 알아본다. 일반적인 경우 IAM 과 함께 제공되는 샘플 어플리케이션의 설정을 그대로 사용하면 되므로 각 설정의 의미를 이해하는데 주안점을 두었다.

타겟 어플리케이션의 messageSource 빈 설정(주로 context-common.xml 에 존재)에 아래와 같이 IAM 메시지 파일을 추가한다.

    <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
        <property name="basenames">
            <list>
                ..
                <value>anyframe/iam/core/messages/security</value>
            </list>
        </property>
    </bean>
    

Spring Security 의<jdbc-user-service /> 대신 IAM 의 ExtJdbcUserDetailsManager 를 적용한다.

    <b:bean id="jdbcUserService"
            class="org.anyframe.iam.core.userdetails.jdbc.ExtJdbcUserDetailsManager" >
        <!-- usersByUsernameQuery 에서 사용자에 대한 group 을 함께 조회할 때 해당 property 명을 설정 -->
        <b:property name="userGroupPropertyName" value="GROUP_ID"/>
        <!-- USER_ID, PASSWORD, ENABLED 는 항상 1,2,3 번째 순서로 나타나야 함! -->
        <b:property name="usersByUsernameQuery">
            <b:value>
              SELECT A.USER_ID AS USER_ID, PASSWORD, CASE WHEN ENABLED = 'Y' THEN 1 ELSE 0 END ENABLED, 
                     B.GROUP_ID AS GROUP_ID, USER_NAME, USER_NAME, CREATE_DATE, MODIFY_DATE
              FROM USERS A LEFT OUTER JOIN GROUPS_USERS B 
                   ON ( A.USER_ID = B.USER_ID ) 
              WHERE A.USER_ID = ?
            </b:value>
        </b:property>
        <b:property name="authoritiesByUsernameQuery">
            <b:value>
            SELECT USER_ID,ROLE_ID,GROUP_ID,SUBJECT_ID,TYPE
              FROM AUTHORITIES C, (
                      SELECT A.USER_ID,B.GROUP_ID
                        FROM USERS A LEFT OUTER JOIN GROUPS_USERS B ON ( A.USER_ID = B.USER_ID )
                       WHERE A.USER_ID = ? ) D
             WHERE ( C.SUBJECT_ID = D.USER_ID
                          OR C.SUBJECT_ID = D.GROUP_ID )
            </b:value>
        </b:property>
        <b:property name="dataSource" ref="dataSource"/>
        <!-- 사용자 정의 CustomUserVO 를 쓰고자 하는 경우 ExtUsersByUsernameMapping 를 확장하여 makeCustomUser() 에 관련 로직을 작성한 MappingSqlQuery 등록 -->
        <!-- <b:property name="mapClass" value="org.anyframe.iam.core.userdetails.jdbc.CustomUsersByUsernameMapping"/> -->
    </b:bean>
    
    ..
    <authentication-manager alias="authenticationManager"> 
        <authentication-provider user-service-ref="jdbcUserService" />
    </authentication-manager>
    

커스텀 사용자 정보를 Spring Security 의 UserDetails 확장 객체로 저장할 수 있게 하였고 그룹에 대한 권한을 사용자 로그인 시 함께 사용자의 권한으로 로딩하게 한 예이다. mapClass 를 지정하지 않으면 IAM 의 ExtUsersByUsernameMapping 으로 내부적으로 커스텀 사용자 정보는 Map 형태로 처리되나 사용자가 이를 확장한 맵핑 객체를 작성하여 제공하면 사용자가 지정한 JavaBeans 객체로도 처리가 가능하다.(관련 예는 ExtUsersByUsernameMapping 의 javadoc 참조) 또 위에서 사용자 그룹에 대한 property 명을 설정 가능토록 하였으므로 이를 잘 맞추어 주도록 한다. 설정치 않은 경우 default 값은 userGroup 이다.

아래는 CustomUserDetailsHelper 를 사용하여 커스텀 사용자 객체를 얻어낼 수 있는 사용법의 예이다. 아래 사용자 정보 객체는 웹 영역에서 뿐만 아니라 Application 전체 레이어에 걸쳐 동일한 방법으로 접근이 가능하다.

    ExtUser extUser = CustomUserDetailsHelper.getAuthenticatedUser();
    Map customUserMap = (Map) extUser.getCustomUser();
    // CustomUser 라는 JavaBeans 로 맵핑을 처리하는 mapClass 를 작성하여 적용한 경우
    // CustomUser customUser = (CustomUser) extUser.getCustomUser();
    

IAM 에서는 Spring Security 의 보호자원 및 RoleHierarchy, 자체 확장한 Time 기반의 보호자원에 대한 데이터를 DB 기반으로 처리하고 있다. 이는 Container 기동 시에 한번(또는 reload 요청시) 조회하여 처리되는 구조이다.

    <b:bean id="securedObjectService" class="org.anyframe.iam.core.securedobject.impl.SecuredObjectServiceImpl">
        <b:property name="securedObjectDAO" ref="securedObjectDAO" />
    </b:bean>

    <b:bean id="securedObjectDAO" class="org.anyframe.iam.core.securedobject.impl.SecuredObjectDAO">
        <b:property name="dataSource" ref="dataSource" />
        <!--b:property name="systemName" ref="SAMPLE" /-->
    </b:bean>
    

systemName 속성은 업무 어플리케이션이 여러 개인 경우 해당 어플리케이션을 지정한다.

IAM 의 DB Schema 를 사용하지 않고 IAM Core 만을 단독으로 적용하거나 일부 DB 테이블이 다른 경우 등 쿼리 변경이 필요한 경우를 고려하여 securedObjectDAO 에는 sqlRolesAndUrl, sqlRolesAndMethod, sqlRolesAndPointcut, sqlRegexMatchedRequestMapping, sqlHierarchicalRoles, sqlRestrictedTimesRoles, sqlRestrictedTimesResources, sqlViewResourceMapping 에 대해 사용자 설정이 가능하도록 되어 있다. 상세 내용은 SecuredObject 사용자화 설정 이나 SecuredObjectDAO 소스를 참고하도록 한다.

Spring Security 의 RoleHierarchy 처리를 그대로 사용하고 있으며, Role 의 Hierachy 데이터를 DB 기반으로 로딩하는 부분이 추가되어 있다.

    <b:bean id="roleHierarchy" class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl">
        <b:property name="hierarchy" ref="hierarchyStrings" />
    </b:bean>

    <b:bean id="hierarchyStrings" class="org.anyframe.iam.core.userdetails.hierarchicalroles.HierarchyStringsFactoryBean"
            init-method="init">
        <b:property name="securedObjectService" ref="securedObjectService" />
    </b:bean>

    <b:bean id="userDetailsServiceWrapper" class="org.springframework.security.access.hierarchicalroles.UserDetailsServiceWrapper">
        <b:property name="roleHierarchy" ref="roleHierarchy" />
        <b:property name="userDetailsService" ref="jdbcUserService" />
    </b:bean>
    ..
    <authentication-manager alias="authenticationManager"> 
        <authentication-provider user-service-ref="userDetailsServiceWrapper" />
    </authentication-manager>
    <b:bean id="roleHierarchy" class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl">
        <b:property name="hierarchy" ref="hierarchyStrings" />
    </b:bean>

    <b:bean id="hierarchyStrings" class="org.anyframe.iam.core.userdetails.hierarchicalroles.HierarchyStringsFactoryBean"
            init-method="init">
        <b:property name="securedObjectService" ref="securedObjectService" />
    </b:bean>

    <b:bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
        <b:property name="allowIfAllAbstainDecisions" value="false" />
        <b:property name="decisionVoters">
            <b:list>
                <!-- RoleHierarchyVoter -->
                <b:bean class="org.springframework.security.access.vote.RoleHierarchyVoter">
                    <b:constructor-arg ref="roleHierarchy" />
                </b:bean>
                <b:bean class="org.springframework.security.access.vote.AuthenticatedVoter" />
            </b:list>
        </b:property>
    </b:bean>
    

Spring Security 에서는 RoleHierarchy 처리를 위한 2가지 방법을 제공하고 있다. UserDetailsServiceWrapper 를 사용하여 원본 jdbcUserService 를 랩핑하는 방법과 랩핑하지 않고 AccessDecisionVoter 처리 시 RoleVoter 가 아닌 RoleHierarchyVoter (roleHierarchy 를 내부적으로 활용) 를 설정하는 방법이다. (UserDetailsServiceWrapper는 3.0 버전에서도 정상적으로 동작하나 현재 deprecated 되었으므로 향후 사용시 유의하여야 한다.)

Namespace 에서 기본 포함되는 FilterSecurityInterceptor 및 DefaultFilterInvocationDefinitionSource 외에 DB 기반의 보호자원(Url)-권한맵핑을 적용하기 위해 아래 설정을 추가한다.

    <b:bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
        <b:property name="allowIfAllAbstainDecisions" value="false" />
        <b:property name="decisionVoters">
            <b:list>
                <b:bean class="org.springframework.security.access.vote.RoleVoter">
                    <b:property name="rolePrefix" value="" />
                </b:bean>
                <b:bean class="org.springframework.security.access.vote.AuthenticatedVoter" />
            </b:list>
        </b:property>
    </b:bean>

    <b:bean id="filterSecurityInterceptor" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
        <!-- Namespace 에서 기본으로 FilterSecurityInterceptor 는 들어가는데  observeOncePerRequest 를 설정하지 않으면 기본으로 같은 Filter 타입인 경우에는 수행을 하지 않음에 유의함.-->
        <b:property name="observeOncePerRequest" value="false" />
        <b:property name="authenticationManager" ref="authenticationManager" />
        <b:property name="accessDecisionManager" ref="accessDecisionManager" />
        <b:property name="securityMetadataSource" ref="databaseSecurityMetadataSource" />
    </b:bean>

    <b:bean id="databaseSecurityMetadataSource"
        class="org.springframework.security.web.access.intercept.AnyframeReloadableDefaultFilterInvocationDefinitionSource">
        <b:constructor-arg ref="regexUrlPathMatcher" />
        <b:constructor-arg ref="requestMap" />
        <b:property name="securedObjectService" ref="securedObjectService" />
    </b:bean>

    <b:bean id="regexUrlPathMatcher" class="org.springframework.security.web.util.RegexUrlPathMatcher" />

    <b:bean id="requestMap" class="org.anyframe.iam.core.intercept.ResourcesMapFactoryBean" init-method="init">
        <b:property name="securedObjectService" ref="securedObjectService" />
        <b:property name="resourceType" value="url" />
    </b:bean>

Spring Security 의 Namespace 에서 URL 보호 자원에 대한 Authorization 처리 기능을 제공하기 위해 자동으로 추가되는 FilterSecurityInterceptor 에 더하여 위와 같이 동일한 FilterSecurityInterceptor 를 추가로 custom-filter 로 추가하여 DB 기반의 보호자원-권한맵핑 데이터 기반 처리를 추가하기 위한 설정 예이다. 기본 FILTER_SECURITY_INTERCEPTOR 바로 다음 위치에 배치하는 것을 권고하는 바이고 주의할 점은 Spring Security 에서는 동일한 Filter 타입에 대해서는 기본적으로 하나의 request 처리 시 한번만 동작하도록 구동하기 때문에 이를 해제해 주기 위해 observeOncePerRequest 를 false 로 지정해 주어야 한다. databaseSecurityMetadataSource 으로 등록하는 bean 은 Spring Security 의 DefaultFilterInvocationDefinitionSource 를 확장하여 DB 기반 초기 데이터 로딩 및 runtime reload 기능을 추가하였고, requestMap 으로 정의한 FactoryBean 확장 클래스를 통해 securedObjectService 를 사용한 DB 데이터를 databaseSecurityMetadataSource 의 초기 데이터로 제공하게 된다. Url 패턴 매칭을 검사하는 PatternMatcher 는 위에서 정규식 기반의 RegexUrlPathMatcher 로 지정한 예이다. 정규식을 사용하면 매우 강력한 패턴 매칭 검사가 가능하고 기본으로 URL parameter 를 포함한 전체 url 에 대해 검사할 수 있다. 이외에 AntUrlPathMatcher 를 설정할 수 있으며 표현식이 정규식 작성에 비해 간결하다. 기본으로는 URL parameter 는 제거하고 패턴 매칭 비교를 수행하게 된다.

DB 기반의 Method/Pointcut 보호자원 데이터를 활용한 Method Authorization 을 적용하기 위한 설정의 예이다.

    <!-- customizing method security start -->
    <b:bean id="methodMap" class="org.anyframe.iam.core.intercept.ResourcesMapFactoryBean" init-method="init">
        <b:property name="securedObjectService" ref="securedObjectService" />
        <b:property name="resourceType" value="method" />
    </b:bean>

    <b:bean id="methodSecurityMetadataSources" class="org.springframework.security.access.method.MapBasedMethodSecurityMetadataSource">
        <b:constructor-arg ref="methodMap" />
    </b:bean>

    <b:bean id="_delegatingMethodSecurityMetadataSource" class="org.springframework.security.access.method.DelegatingMethodSecurityMetadataSource">
        <b:property name="methodSecurityMetadataSources">
            <b:list>
                <b:ref bean="methodSecurityMetadataSources" />
                <b:bean class="org.springframework.security.access.annotation.SecuredAnnotationSecurityMetadataSource" />
                <b:bean class="org.springframework.security.access.annotation.Jsr250MethodSecurityMetadataSource" />
            </b:list>
        </b:property>
    </b:bean>

    <b:bean id="_methodSecurityMetadataSourceAdvisor" class="org.springframework.security.access.intercept.aopalliance.MethodSecurityMetadataSourceAdvisor">
        <b:constructor-arg value="_methodSecurityInterceptor" />
        <b:constructor-arg ref="_delegatingMethodSecurityMetadataSource" />
        <b:constructor-arg value="_delegatingMethodSecurityMetadataSource" />
    </b:bean>

    <b:bean id="_methodSecurityInterceptor" class="org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor">
        <b:property name="validateConfigAttributes" value="false" />
        <b:property name="authenticationManager" ref="authenticationManager" />
        <b:property name="accessDecisionManager" ref="accessDecisionManager" />
        <!--
        <b:property name="afterInvocationManager" ref="afterInvocationManager" />
        -->
        <b:property name="securityMetadataSource" ref="_delegatingMethodSecurityMetadataSource" />
    </b:bean>

    <b:bean id="pointcutMap" class="org.anyframe.iam.core.intercept.ResourcesMapFactoryBean" init-method="init">
        <b:property name="securedObjectService" ref="securedObjectService" />
        <b:property name="resourceType" value="pointcut" />
    </b:bean>

    <b:bean id="_protectPointcutPostProcessor" class="org.springframework.security.config.method.ProtectPointcutPostProcessor">
        <b:constructor-arg ref="methodSecurityMetadataSources" />
        <b:property name="pointcutMap" ref="pointcutMap" />
    </b:bean>

    <!-- customizing method security end -->

Namespace 의 <global-method-security> 를 대체하여 전통적인 Bean 설정 형식으로 정의하여야 하며 특히 jsr-250 / secured annotation 기반의 메서드 보안을 동일하게 지원하기 위한 다단계의 methodSecurityMetadataSource (SecurityMetadataSource) 참조 설정에 유의한다. methodSecurityMetadataSources 으로 등록하는 bean 은 Spring Security 의 MapBasedMethodSecurityMetadataSource 를 그대로 사용하며 생성자 인자로 methodMap 로 정의한 FactoryBean 확장 클래스를 통해 securedObjectService 를 사용한 보호자원(method)-권한 맵핑 DB 데이터를 초기 데이터로 제공하게 된다. 마찬가지로 pointcutMap 으로 정의한 FactoryBean 확장 클래스를 통해 securedObjectService 를 사용한 보호자원(pointcut)-권한맵핑 DB 데이터를 기반으로 AspectJ 의 Pointcut 표현식을 읽어 각각의 Bean 생성 시 동적으로 포인트컷을 추가하는 BeanPostProcessor 인 ProtectPointcutPostProcessor 에 dependency 로 제공하여 표현식이 매치되는 bean 의 대상 메서드에 메서드 보안처리를 위한 Advisor 를 적용하게 된다.

실행 시간에 따른 제한 자원(Url) 및 제한 Role 에 대한 접근 제어 기능을 적용하기 위한 예이다.

    <b:bean id="restrictedTimesAccessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
        <b:property name="allowIfAllAbstainDecisions" value="false" />
        <b:property name="decisionVoters">
            <b:list>
                <b:bean
                    class="org.springframework.security.access.vote.AnyframeRoleHierarchyRestrictedVoter">
                    <b:property name="rolePrefix" value="" />
                    <b:property name="roleHierarchy" ref="roleHierarchy" />
                </b:bean>
                <b:bean class="org.springframework.security.access.vote.AuthenticatedVoter" />
            </b:list>
        </b:property>
    </b:bean>

    <b:bean id="restrictedTimesFilterSecurityInterceptor"
        class="org.anyframe.iam.core.intercept.web.RestrictedTimesFilterSecurityInterceptor">
        <b:property name="authenticationManager" ref="authenticationManager" />
        <b:property name="accessDecisionManager" ref="restrictedTimesAccessDecisionManager" />
        <b:property name="securityMetadataSource" ref="restrictedTimesSecurityMetadataSource" />
    </b:bean>

    <b:bean id="restrictedTimesSecurityMetadataSource"
        class="org.anyframe.iam.core.intercept.web.ReloadableRestrictedTimesFilterInvocationSecurityMetadataSource">
        <b:property name="urlMatcher" ref="regexUrlPathMatcher" />
        <b:property name="securedObjectService" ref="securedObjectService" />
    </b:bean>

Spring Security 의 FilterSecurityInterceptor 를 확장하여 실행 시간에 따른 접근 제어 기능을 제공하는 RestrictedTimesFilterSecurityInterceptor 와 DB 기반의 실행시간-Resource/Role 제한 데이터로 부터 현재 시각에 해당하는 제한 데이터에 대해 매칭을 판단하여 적절한 제한/허용 Role 을 얻기 위한 ReloadableRestrictedTimesFilterInvocationSecurityMetadataSource, 또 시간제한 Resource/Role 에 따른 최종적인 ACCESS/DENY 접근 제어를 판단하기 위한 AccessDecisionVoter 확장 구현인 AnyframeRoleHierarchyRestrictedVoter 를 설정하여 실행시간에 따른 접근 제어를 유연하게 적용할 수 있다. 위의 시간 제한 설정을 위한 세가지 Bean 은 반드시 쌍으로 사용되며, RestrictedTimesFilterSecurityInterceptor 는 custom-filter 로 Spring Security의 Namespace 에서 자동으로 추가되는 FILTER_SECURITY_INTERCEPTOR 바로 앞에 배치하여 사용하기를 권고한다. (http 태그를 참고한다.) 실행 시간 제한 유형은 매일 적용되는 제한 유형인 crash, daily 와 사용자가 시작 ~ 종료 일시를 지정하는 weekend, holiday, improve 유형을 지정할 수 있도록 IAM Admin 에서 데이터 관리 영역이 제공되고 있으니 참고토록 한다.

IAM Admin 에서 보호자원을 등록할 때 실제 타겟 어플리케이션에서 구동되는 UrlMapping 이나 서비스 메서드 정보를 기반으로 Assist(자동완성) 를 지원하기 위한 설정의 예이다.

resourceGatherAssistService 와 resourceCreationAssistService 를 통해 해당 어플리케이션의 자원 정보를 수집하고 DB 의 임시 테이블에 저장할 수 있다. 이 서비스들은 IAM Admin 에 remote 로 노출되어 Admin 에서 호출 시 해당 기능을 그 시점에 수행하게 될 것이다.

    <bean id="resourceGatherAssistService"
        class="org.anyframe.iam.core.assist.impl.ResourceGatherAssistServiceImpl" />

resourceGatherAssistService 는 url, method, pointcut 유형의 보호자원 등록의 Assist 를 위해 Service 로 끝나는(candidateBeanPostfix 를 지정하는 경우 다른 postfix 를 지정할 수 있음) 업무서비스 Bean의 package/class/method 등의 정보를 수집하고 이를 기반으로 간략한 pointcut 표현식 Assist 정보도 계산한다. Url 정보를 수집하기 위해서는 SpringMVC 의 AbstractUrlHandlerMapping 유형의 HandlerMapping 빈들에 등록되어 있는 url 을 활용하므로 위 resourceGatherAssistService 빈 설정은 DispatcherServlet 을 통해 로딩하는 WebApplicationContext 에 해당하는 xx-servlet.xml 설정 파일(아래 IAM Admin Remote 연동 설정 파일과 동일)에 등록 하여야 함에 유의한다.

보호자원 정보를 런타임에 갱신할 수 있는 기능을 대표로 수행하는 reloadService 설정 예이다.

    <b:bean id="resourceReloadService"
        class="org.anyframe.iam.core.reload.impl.ResourceReloadServiceImpl">
        <b:property name="databaseSecurityMetadataSource" ref="databaseSecurityMetadataSource" />
        <b:property name="restrictedTimesSecurityMetadataSource" ref="restrictedTimesSecurityMetadataSource" />
        <b:property name="restrictedTimesAccessDecisionManager" ref="restrictedTimesAccessDecisionManager" />
    </b:bean>

reloadService 를 통해 DB 기반의 보호자원(Url)-권한 맵핑 정보(requestMap) 및 시간제한에 따른 보호자원 정보를 런타임에 갱신할 수 있으며, 이 서비스는 IAM Admin 에 remote 로 노출되어 Admin 에서 호출 시 해당 기능을 그 시점에 수행하게 될 것이다.

보호자원 정보 Assist 및 런타임 갱신을 IAM Admin 에서 Remote 로 처리할 수 있도록 설정한 예이다.

    <!-- Remote HttpInvoker Call -->
    <bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter" />
    
    <bean id="resourceGatherAssistService"
        class="org.anyframe.iam.core.assist.impl.ResourceGatherAssistServiceImpl" />
    
    <bean id="gatherService" 
        class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">
        <property name="service" ref="resourceGatherAssistService" />
        <property name="serviceInterface"
            value="org.anyframe.iam.core.assist.IResourceGatherAssistService" />
    </bean>
    
    <bean id="reloadService" 
        class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">
        <property name="service" ref="resourceReloadService" />
        <property name="serviceInterface"
            value="org.anyframe.iam.core.reload.IResourceReloadService" />
    </bean>

    <bean id="urlMappingResourceAssist" 
        class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <props>
                <prop key="/assist/resourceGatherAssist.do">gatherService</prop>
                <prop key="/reload/resourceReload.do">reloadService</prop>
            </props>
        </property>
    </bean>

IAM Admin 도 동일하게 Spring 기반 어플리케이션 이므로 Spring Bean 에 대해 remote 서비스로 노출할 수 있는 방법 중 하나인 HttpInvoker 기술을 사용하여 위와 같이 SpringMVC 의 DispatcherServlet 을 통해 Http 기반으로 매우 간단하게 remote 연동이 가능하다. 위 설정 내용은 spring-security-servlet.xml 으로 분리하여 DispatcherServlet 에 의한 WebApplicationContext 에 등록토록 한다.

    <intercept-url pattern="\A/assist/resourceGatherAssist\.do.*\Z" access="ROLE_ADMIN" />
    <intercept-url pattern="\A/reload/resourceReload\.do.*\Z" access="ROLE_ADMIN" />

관리자 만이 위 runtime reload 및 assit 정보 수집/등록을 할 수 있도록 하기 위해서는 http 태그의 intercept-url 설정으로 해당 remote 공개 url 에 대해 ROLE_ADMIN 을 지정하는 것이 필요하다. IAM Admin 에서는 이를 고려하여 로그인한 사용자(관리자)의 인증정보를 자동으로 HttpInvoker remote 호출 시 넘길 수 있도록 HttpInvoker client 에 대한 HttpInvokerProxyFactoryBean 설정 시 httpInvokerRequestExecutor 로 AuthenticationSimpleHttpInvokerRequestExecutor 를 설정한다. 관련 예는 Admin 환경 설정 방법의 remote-invoker-servlet.xml 설정 예를 참고한다.

HttpInvoker 방식의 remote 호출 시 암호화한 형태로 데이터를 전송하는 것이 아니라 단순히 Base64 인코딩한 형태로만 전송하므로 보안에 취약한 문제가 있다. 이를 개선하기 위해서는 https 채널 보안을 적용하는 것이 필요하며 설정은 다음과 같다.

    <intercept-url pattern="\A/reload/resourceReload\.do.*\Z" access="ROLE_ADMIN" requires-channel="https" />
    ..

https 프로토콜 기반의 채널 보안을 적용하기 위한 SSL, X.509 인증서(또는 사설인증서) 처리를 위한 적용 절차는 본 문서 범위를 넘어가므로 생략하였다.

사용자가 정의 View Resource(ex. 화면, 프로그램)에 대해 매핑된 Permission 을 체크할 수 있는 기능을 제공한다.

    <b:bean id="viewResourceAccessService"
        class="org.anyframe.iam.core.acl.impl.ViewResourceAccessServiceImpl">
        <b:property name="securedObjectService" ref="securedObjectService" />
        <b:property name="registeredPermissions">
            <b:list>
                <b:ref local="org.anyframe.iam.core.acl.ExtBasePermission.READ" />
                <b:ref local="org.anyframe.iam.core.acl.ExtBasePermission.WRITE" />
                <b:ref local="org.anyframe.iam.core.acl.ExtBasePermission.CREATE" />
                <b:ref local="org.anyframe.iam.core.acl.ExtBasePermission.DELETE" />
                <b:ref local="org.anyframe.iam.core.acl.ExtBasePermission.ADMINISTRATION" />                
                <b:ref local="org.anyframe.iam.core.acl.ExtBasePermission.LIST" />                
                <b:ref local="org.anyframe.iam.core.acl.ExtBasePermission.PRINT" />
                <!--
                <b:ref local="org.anyframe.iam.core.acl.ExtBasePermission.REPORT" />
                <b:ref local="org.anyframe.iam.core.acl.ExtBasePermission.POPUP" />
                <b:ref local="org.anyframe.iam.core.acl.ExtBasePermission.DOWNLOAD" />
                <b:ref local="org.anyframe.iam.core.acl.ExtBasePermission.UPLOAD" />
                <b:ref local="org.anyframe.iam.core.acl.ExtBasePermission.HELP" />
                -->
            </b:list>
        </b:property>
    </b:bean>
    
    <!-- 현재 Application 에서 사용하는 Permission 정의 -->
    <b:bean id="org.anyframe.iam.core.acl.ExtBasePermission.READ"
        class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
        <b:property name="staticField"
            value="org.anyframe.iam.core.acl.ExtBasePermission.READ" />
    </b:bean>
    <b:bean id="org.anyframe.iam.core.acl.ExtBasePermission.WRITE"
        class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
        <b:property name="staticField"
            value="org.anyframe.iam.core.acl.ExtBasePermission.WRITE" />
    </b:bean>
    <b:bean id="org.anyframe.iam.core.acl.ExtBasePermission.CREATE"
        class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
        <b:property name="staticField"
            value="org.anyframe.iam.core.acl.ExtBasePermission.CREATE" />
    </b:bean>
    <b:bean id="org.anyframe.iam.core.acl.ExtBasePermission.DELETE"
        class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
        <b:property name="staticField"
            value="org.anyframe.iam.core.acl.ExtBasePermission.DELETE" />
    </b:bean>
    <b:bean id="org.anyframe.iam.core.acl.ExtBasePermission.ADMINISTRATION"
        class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
        <b:property name="staticField"
            value="org.anyframe.iam.core.acl.ExtBasePermission.ADMINISTRATION" />
    </b:bean>
    
    <b:bean id="org.anyframe.iam.core.acl.ExtBasePermission.LIST"
        class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
        <b:property name="staticField"
            value="org.anyframe.iam.core.acl.ExtBasePermission.LIST" />
    </b:bean>
    
    <b:bean id="org.anyframe.iam.core.acl.ExtBasePermission.PRINT"
        class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
        <b:property name="staticField"
            value="org.anyframe.iam.core.acl.ExtBasePermission.PRINT" />
    </b:bean>
    <!--
    <b:bean id="org.anyframe.iam.core.acl.ExtBasePermission.REPORT"
        class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
        <b:property name="staticField"
            value="org.anyframe.iam.core.acl.ExtBasePermission.REPORT" />
    </b:bean>
    <b:bean id="org.anyframe.iam.core.acl.ExtBasePermission.POPUP"
        class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
        <b:property name="staticField"
            value="org.anyframe.iam.core.acl.ExtBasePermission.POPUP" />
    </b:bean>
    <b:bean id="org.anyframe.iam.core.acl.ExtBasePermission.DOWNLOAD"
        class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
        <b:property name="staticField"
            value="org.anyframe.iam.core.acl.ExtBasePermission.DOWNLOAD" />
    </b:bean>
    <b:bean id="org.anyframe.iam.core.acl.ExtBasePermission.UPLOAD"
        class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
        <b:property name="staticField"
            value="org.anyframe.iam.core.acl.ExtBasePermission.UPLOAD" />
    </b:bean>
    <b:bean id="org.anyframe.iam.core.acl.ExtBasePermission.HELP"
        class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
        <b:property name="staticField"
            value="org.anyframe.iam.core.acl.ExtBasePermission.HELP" />
    </b:bean>
    -->

Anyframe IAM 에서는 Spring Security 의 BasePermission 을 확장하여 많이 쓰이는 몇가지 Permission 속성을 추가한 ExtBasePermission 을 통하여 Spring Security 와 마찬가지로 Bit Mask 표현 및 처리를 제공하고 있다. READ, WRITE, CREATE, DELETE, ADMINISTRATION 는 Spring Security 에서 기본으로 제공하는 Permission 이며 위 설정 상에서는 해당 어플리케이션에서는 LIST, PRINT 만 더 추가하여 사용한 예이다. 위에서 확인할 수 있듯이 현재 Application 에서 사용하는 Permission 정의 영역에 필요한 Permission 정의 부분만 필터링 하여 적용할 수 있다. 위 예에서는 나타나 있지 않지만 ExtBasePermission 은 FNC0 ~ FNC9 까지의 추가 예약 Permission 속성을 가지고 있으므로 Application 에서 더많은 Permission 항목이 필요한 경우 적절히 의미를 부여하여 사용할 수 있을 것이다. 현재의 IAM Admin 에서도 타겟 어플리케이션마다 각각 달라질 수 있는 Permission 항목을 동적으로 처리하려면 위의 viewResourceAccessService 관련 설정을 IAM Admin 의 context-security.xml 에 동일하게 맞춰 주어야 함에 유의한다.

viewResourceAccessService 를 통해 로그인한 사용자(사용자 > 그룹 > ROLE 의 우선순위로 고려함)가 특정 View Name 에 대해 특정 Permissions 를 가지고 있는지 체크할 수 있는 기능을 제공하며, JSP 커스텀 태그인 ViewResourceTag 는 이를 활용하여 Permission 에 따라 화면내에 제어할 영역의 처리를 쉽게 할 수 있게 된다. 관련 사용 예는 Access Control 챕터를 참고토록 한다. 또한 IAM Admin 에서는 Resource Management - View List / View Mapping 항목으로 사용자 정의 ViewResource 및 Permission 맵핑 데이터 관리 영역이 제공되고 있으니 참고토록 한다.

사용자 정의 리소스 (view resource) 에 대해 DB 기반의 permission 을 지정할 수 있으며(Data 관리는 IAM Admin 에서 제공) 이에 대한 허가된 Permission 의 확인을 위해 IAM Core 에서는 로그인한 사용자가 해당 view resource 에 대해 나열한 permission 을 가지고 있는지 체크하기 위한 API(서비스) 및 이를 활용하는 Tag Library 를 제공한다.

Spring Security 의 ACL 에서 사용하는 것과 마찬가지로 Bit Masking 에 의한 permission 을 처리할 수 있도록 하였다.

SI 프로젝트에서 일반적으로 요구하는 화면에 대한 READ, WRITE, CREATE, DELETE, ADMINISTRATION .. 에 대한 permission 확인을 위한 기능으로 활용한다.

permission 을 체크하기 원하는 자바 코드에서 아래의 viewResourceAccessService 를 통하여 권한이 있는지 체크한다. (AOP 를 적용하여 permission 체크 로직을 공통화하는 것이 좋음. - 추후 가이드 예정)

boolean result = viewResourceAccessService.isGranted("updateCategory", Arrays.asList(new Integer[] { 3 }))

위에서 3 은 bit mask 표시로 0..00011 이며 이는 READ,WRITE 권한을 나타낸다. 위에서 3 에 해당하는 bit mask 를 얻기 위해 ExtBasePermission.getPermissionMask("READ,WRITE") 와 같이 사용할 수도 있다.

jsp 화면에서 아래와 같이 서비스 호출 function 영역이나 버튼 영역을 Tag 로 감싸 권한이 있는 경우에만 HTML 이 그려지도록 적용한다.

<%@ taglib uri="/WEB-INF/anyframe-iam.tld" prefix="iam" %>
..
<iam:access hasPermission="${iam:getPermissionMask(\"CREATE\")}" viewName="listCategory">
 function fncAddCategoryView() {
  ..
 }
</iam:access>
..
<iam:access hasPermission="${iam:getPermissionMask(\"CREATE\")}" viewName="listCategory">
  Add 버튼 영역
</iam:access>

위와 같이 화면표시를 제한한다 하더라도 실제로 권한 처리가 된것은 아님에 유의한다. 보안상 서버단에서 반드시 실제적인 방어(Web request authorization, method authorization, view resource ACL, domain 객체 ACL ..)가 필요하다.

IAM Admin은 콘솔 기능을 제공하는 별도의 웹 어플리케이션 형태로 제공이 되며, IAM Core 가 설치 및 세팅된 상태에서 Web Application Server 에 WAR 형태로 배포된다. IAM Admin 의 View 영역은 jQuery 와 JSP 기술로 구현되어 있으며, Controller 영역은 Anyframe Web, Model 영역은 HibernateJPA와 Anyframe Core 로 구성되어 있다.

IAM Core 가 DB의 설정 내용을 기반으로 실제 대상 어플리케이션의 권한을 제어하는 기능을 주로 제공한다면, IAM Admin 은 Core 가 의존하는 DB 설정을 관리자가 손쉽게 조작할 수 있도록 하며, 변경된 내용을 Core 가 인식할 수 있도록 제어 신호를 전달하는 역할을 제공한다.

Anyframe IAM Architecture

IAM Admin 에서는 UI 제어를 위하여 JavaScript Framework 인 jQuery 를 사용하고 있다. jQuery 를 활용하여 화면 리프레쉬를 최소화하면서 서버와의 요청과 응답을 수행할 수 있도록 구성되어 있다. 현재 수많은 플러그인들이 jQuery에 제공되고 있으며, 그 중 Anyframe IAM에서 사용하고 있는 jQuery 관련 플러그인들은 다음과 같다. (jQuery 자체에 대한 설명은 본 매뉴얼의 범위를 벗어나는 영역이므로 아래 목록의 링크를 참조하기 바란다.)

IAM Admin 은 Spring Security 기반의 IAM Core 가 제공하는 기능에 추가하여 사용자 편의 및 기능 향상을 위해 다음과 같은 특징을 제공한다. (권한 리로드 및 어플리케이션 정보 수집 기능은 HttpInvoker 기반으로 작성되어 방화벽 제한없이 동작할 수 있다.)

  • Cross Browser 지원

    IAM Admin 은 Cross Browser 지원하여 Internet Explorer 뿐만 아니라 Firefox, Chrome, Safari 등과 같은 브라우저에서도 동일하게 동작하도록 구현되어 있다.

    IAM Admin은 Cross Browser를 지원하여 Internet Explorer, Firefox, Chrome, Safari 등과 같은 브라우저에서 동일하게 동작하도록 구현되어 있다.
  • 타겟 어플리케이션 권한 리로드

    IAM Admin 상에서 변경된 권한 정보는 명시적으로 권한 리로드를 요청하기 전까지는 반영되지 않으며, 관리자가 권한 변경 작업을 종료한 이후 권한 리로드 기능을 수행하면 타켓 어플리케이션(일반적으로 업무 어플리케이션) 의 권한 정보가 갱신된다. 이때 클러스터링 된 서버 환경하에서도 권한 리로드가 가능하다.

    위 그림은 IAM Admin에 의해서 권한 리로드 기능을 수행하는 동작에 대한 예시화면이다.
  • 타겟 어플리케이션 정보 수집

    타겟 어플리케이션은 유지보수를 반복하면서 새로운 기능들이 추가되거나 변경이 될 것이다. IAM Admin 에서는 보호된 자원 등록을 손쉽게 할 수 있도록 타겟 어플리케이션의 정보를 수집하는 기능을 제공한다.

    위 그림은 타겟 어플리케이션에 대한 권한 정보 등록을 쉽게 도와주기 위한 IAM의 정보 수집 기능에 대한 설명이다.
  • 시간 제한에 의한 권한 관리

    IAM Admin 에서는 특정 리소스나 역할에 대한 허용 시간 범위를 설정한 다음, 해당 시간동안 자원에 대한 접근, 역할에 대한 접근을 제어할 수 있으며, 이러한 규칙에 예외되는(접근이 허용된 관리자 등) 역할도 정의할 수 있다.

  • Auto Complete 지원

    권한 관리를 위하여 타겟 어플리케이션의 보호된 자원을 등록하는 것은 복잡하고 어려운 작업이다. IAM Admin 은 자동 완성 기능을 이용해 이미 추출되어 있는 타겟 어플리케이션의 정보를 기반으로 힌트를 제공하여 사용자가 좀 더 손쉽게 보호된 자원을 등록할 수 있도록 지원한다.

  • 어플리케이션 통합관리

    하나의 Admin Console 을 통하여 다수의 어플리케이션을 통합관리할 수 있다.

  • Excel Data Import/Export

    Excel 파일의 Import/Export 기능을 이용하여 초기 데이타 구축 및 현 상태의 백업을 손쉽게 할 수 있다.

IAM Admin은 Anyframe 기반의 Service 들을 통하여 DB 기반의 정보를 관리할 수 있다. 다음의 도해와 설명은 IAM Admin 의 서비스들을 나타낸 것이다. 아래 도해에서 DAO는 공히 Hibernate-JPA 로 기반으로 구성되어 있다. 해당 서비스들을 이용하여 권한을 구성하는 방법에 대한 내용은 사용법을 참고하도록 한다.

핵심 서비스 #1

IAM Admin 에서 주로 사용되는 Service 들의 첫번째 목록이다. 사용자그룹-사용자 관계(groupsUsers), 사용자 (users), 권한(authorites), 역할(roles) 역할-리소스 관계(securedResourceRoles)과 같이 IAM Core 에서 핵심적으로 바라보는 정보들을 관리한다.

핵심 서비스 #2

IAM Admin 에서 주로 사용되는 Service 들의 두번째 목록이다. 사용자그룹(groups), 보호된 자원(securedResources), 자원후보군(candidateSecuredResources)과 같은 정보들을 관리한다.

시간 설정 기반의 권한 제어 서비스

IAM Admin 에서는 시간 범위를 설정한 다음, 해당하는 시간동안 자원에 대한 접근, 역할에 대한 접근을 제어할 수 있으며, 이러한 규칙에 예외되는(예를 들어 접근이 허용된 관리자) 역할도 정의할 수 있다.

화면 제어를 위한 서비스

업무 어플리케이션을 개발하는 경우, 사용 권한에 따라 화면의 버튼 디스플레이 여부를 제어하거나, 메뉴 디스플레이 여부를 제어해야 하는 경우가 있다. 이 때 권한을 체크하기 위힌 서비스를 제공한다.

IAM Admin 은 관리 대상 어플리케이션과의 연동을 위하여 일부 환경 설정을 필요로 한다. 이번 장에서는 IAM Admin 환경 설정 내용에 대하여 설명한다.

대상 시스템의 Resource 정보 수집, 권한 Reload 를 위한 설정을 추가한다.

gatherServiceClient, resourceReloadServiceClient bean의 serverUrl Property 설정 값을 대상 시스템의 url로 설정한다. (설정 내용의 http://localhost:8080/anyframe-iam-sample 부분)

<bean id="gatherServiceClient"
    class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">				
    <property name="serviceUrl"
        value="http://localhost:8080/anyframe-iam-sample/assist/resourceGatherAssist.do" />
    <property name="serviceInterface"
        value="anyframe.iam.core.assist.IResourceGatherAssistService" />
    <property name="httpInvokerRequestExecutor">		
        <bean
            class="org.springframework.security.context.httpinvoker.
            					AuthenticationSimpleHttpInvokerRequestExecutor" />
    </property>
</bean>

<bean id="resourceReloadServiceClient"
    class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
    <property name="serviceUrl"
        value="https://localhost:8080/anyframe-iam-sample/reload/resourceReload.do" />
    <property name="serviceInterface"
        value="org.anyframe.iam.core.reload.IResourceReloadService" />
    <property name="httpInvokerRequestExecutor">
        <bean class="org.springframework.security.context.httpinvoker.
        					AuthenticationSimpleHttpInvokerRequestExecutor" />
    </property>
</bean>

IAM Admin은 크게 아래의 5개의 메뉴로 구성되어 있다.

  • User Management : 사용자와 사용자 그룹을 관리하는 메뉴

  • Roles Management : ROLE(역할)을 관리하는 메뉴. 역할에 자원이나 사용자, 사용자그룹을 등록할 수 있다.

  • Resource Management : 자원을 관리하는 메뉴. 새로운 자원을 등록, 삭제하거나 화면제어 기능을 설정할 수 있다.

  • Restriction Management : 시간에 따른 제한을 관리하는 메뉴. 사용자, 역할, 자원에 시간 제한 설정을 관리할 수 있다.

  • System Management : 엔터프라이즈 어플리케이션을 관리하는 메뉴. IAM Admin을 통해 변경된 내용을 적용시키기 위한 Reload 기능과 자원 정보를 수집하는 기능을 제공한다. 그 외에도 다량의 Data를 Excel File로 관리할 수 있는 메뉴를 제공한다.

User Management 메뉴에서는 사용자와 그룹에 대한 전반적인 관리 메뉴를 제공한다. 최초 User List 항목을 클릭하면 다음 그림과 유사한 화면을 볼 수 있다.

위 그림은 사용자 관리 화면 중 그룹 계층 목록 화면에서의 Context menu 사용 예제 화면이다. 트리 화면에서 우클릭을 이용해서 그룹을 추가/수정/삭제 할 수 있고, 그룹을 클릭하여 우측 탭화면에 그룹 상세 정보를 확인할 수 있다.

화면 좌측의 메뉴는 사용자 그룹의 계층 구조를 나타내고, 우측의 입력창은 선택된 그룹에 대한 상세 정보를 나타낸다. 상단의 버튼을 이용해서 전체 펼치기, 접기 기능을 사용할 수 있고, 그룹의 생성, 수정, 삭제 기능은 메뉴에서 우클릭을 함으로써 사용할 수 있다. 또한 화면 상단의 입력창을 이용해서 그룹 이름 검색 기능을 사용할 수 있는데, 사용자의 편의를 위해서 입력 자동 완성 기능 또한 제공되어진다. 트리 검색 기능은 IAM Admin이 제공하는 모든 Tree UI 화면에서 사용 가능한 메뉴이다. 그룹 검색 기능을 사용하면 아래의 그림과 같은 화면을 볼 수 있다.

위 그림은 그룹명 검색시 IAM Admin에서 제공하는 자동완성 기능에 예시 화면이다.

Users 탭에서는 사용자 목록을 확인할 수 있다. 좌측 그룹 메뉴에서 특정 그룹을 선택했을 경우, 해당 그룹에 속한 사용자들이 표시된다.

위 그림은 특정 그룹을 클릭했을 때 User 탭에서 해당 그룹에 속하는 사용자 목록이 출력되는 예시 화면이다.

사용자 목록에서 특정 사용자를 더블클릭하면 사용자 상세 화면으로 이동한다.

위 그림은 사용자 상세 화면이다. 상세 화면에서 특정 사용자의 정보를 수정하고 역할을 등록/삭제 할 수 있다.

상세 화면에서는 사용자의 정보를 수정할 수 있다. 하단의 ROLE LIST 화면에서는 사용자에게 특정한 역할을 등록하거나 삭제할 수 있다. 역할의 등록, 삭제는 Roles Management 에서 사용할 수 있다.

Roles Management 메뉴에서는 사용자 혹은 자원을 등록할 역할들을 관리한다. 최초 Role List 메뉴를 클릭하면 사용자 그룹 메뉴와 동일하게 계층 구조를 나타내는 트리 구조의 메뉴가 보여진다.

위 그림은 역할의 계층구조를 나타내는 트리 화면이다. 그룹 관리 화면과 마찬가지로 마우스 우클릭을 이용해서 역할을 등록/수정/삭제 할 수 있고, 역할을 클릭하여 우측 화면에 역할 상세 정보를 확인할 수 있다.

Roles Management 메뉴에는 Role, Resource List, User Group, Users, 총 4개의 탭 메뉴가 존재한다. 각각의 메뉴는 좌측의 역할 트리에서 특정 역할을 선택 했을 때, 해당 역할에 등록 된 자원, 그룹 혹은 사용자를 나타내는 화면이다.

Resource List 화면에서는 좌측에 선택된 역할에 할당 되어 있는 자원들의 목록을 보여준다. 역할에 자원을 할당 시킬때 한가지 유의 해야 할 사항은 역할의 계층구조이다. 하위의 역할에 자원을 할당 시켰을 경우, 상위 역할은 하위 역할이 가지는 자원을 잠재적으로 내재한다. 따라서 상위 역할에 따로 자원을 등록하지 않더라도 하위 역할의 자원에 대한 접근 권한을 가진다고 보면 된다.

아래의 그림은 좌측의 특정 Role을 선택한 경우 해당 Role에 할당된 자원들의 목록을 보여주는 화면이다. 그림의 상단에 "Nested"라고 적혀진 Select Box는 Oracle DB를 사용하는 사용자에게만 보여지는 메뉴이다. (Oracle이 아닌 다른 DB를 사용하는 사용자는 Select box가 화면에 나타나지 않는다.) Select box 값을 "Nested"로 선택하면 현재 선택된 역할의 자원 뿐 아니라 해당 역할의 하위 역할이 가지는 자원들의 목록을 모두 볼 수 있게 된다. "Self"를 선택하게 되면 해당 역할에 할당된 자원만이 출력된다.

위 그림은 역할에 등록된 자원 목록 예시 화면이다. 좌측의 역할 계층 구조 영역에서 특정 역할을 선택하면 우측의 목록 영역에서 해당 역할에 등록된 자원의 목록을 확인할 수 있다.

다음으로 확인할 메뉴는 User Group 탭메뉴 이다. User Group 탭 메뉴를 선택하면 다음과 같은 화면을 볼 수 있다. 이 화면에서는 사용자에게 일일이 역할을 등록하는 번거로운 작업을 개선하기 위해 해당 그룹에 속하는 모든 사용자에게 특정 역할을 할당하는 일을 기능을 수행한다. 우측의 Multi-Select Box 내의 그룹들은 좌측 역할 메뉴에서 선택 된 역할을 할당받은 그룹들의 목록이다.

위 그림은 특정 역할에 그룹을 등록/삭제 하는 예시 화면이다. 좌측의 트리에서 그룹을 선택한 후 우측 화살표 버튼을 클릭하여 해당 그룹을 역할에 등록 할 수 있다.

유의사항

역할과 사용자 그룹 둘 다 계층 관계를 가지기 때문에 혼동 될 수 있기 때문에 주의해야 한다. 역할 메뉴에서 설명 한 것처럼 하위 역할에 등록된 자원에 대한 접근은 상위 역할의 사용자에게 허용된다. 하지만 사용자 그룹은 동일하게 동작하지않음을 명심해야 한다. 사용자 그룹 메뉴에서 하위 그룹이 가지는 접근 권한을 상위 그룹이 반드시 가지는 것은 아니다. 상위 그룹이 접근 권한을 가지기 위해서는 그 자원에 대한 역할을 할당 해야 한다. 역할 메뉴의 계층 구조와 혼동되어 사용하는 일이 없도록 해야 한다.

Users 탭 메뉴를 클릭하면 아래와 같이 두 개의 목록이 나타난다. 좌측의 메뉴는 어떠한 역할에도 할당되어 있지 않은 사용자의 목록이고, 우측의 메뉴는 선택된 역할에 이미 할당 된 사용자의 목록이다.

위 그림은 특정 역할에 사용자를 등록/삭제 하는 예시 화면이다. 좌측의 목록에서 사용자를 선택한 후 오른쪽 방향 화살표 버튼을 클릭하는 것으로 특정 역할에 사용자를 등록할 수 있다.

이 메뉴는 사용자 개개인에 역할을 등록하는 것으로, 앞서 설명한 역할-그룹 할당과는 별개로 동작한다. 예를 들어 특정한 사용자 A가 속한 그룹 GROUP_A 에 ROLE_A를 할당 한 후, A 사용자에게 또 다른 역할 ROLE_B를 할당 했을 경우, 사용자 A는 ROLE_A와 ROLE_B에 해당하는 자원의 접근 권한을 모두 가지게 된다. 따라서 사용자 개인에게 역할을 할당할 경우나 사용자 그룹에 역할을 할당할 경우에는 중복적인 자원 할당을 반드시 유념해야한다.

Resource Management 메뉴에서는 접근 권한을 통제 할 자원에 대한 메뉴를 제공한다. Resource Management 메뉴에는 Resource List, View List, View Mapping의 3가지 상세 메뉴가 존재한다.

먼저 Resource List 메뉴를 살펴보자. Resource List 메뉴에서는 현재 등록 된 자원들의 목록을 확인 할 수 있다. 자원의 종류에는 URL, Method, PointCut의 3가지가 있고 각각 특별한 패턴의 형태로 등록된다. URL 자원은 정규식의 형태로 등록 가능하고, POINT CUT 자원은 AspectJ 에서 지원하는 형태의 패턴을 사용하여 등록 할 수 있다. Method 형태의 자원은 현재 특정 패턴을 지원하지는 않고 있다. 추후 새로운 버전에서 정규식 이외의 패턴 사용, Method 자원의 패턴 적용 등을 검토 할 예정이다.

아래의 화면은 Resource List를 선택했을 때 보여지는 자원 목록이다.

위 그림은 보호 대상 자원으로 등록한 자원 목록 예시 화면이다.

원하는 자원을 더블클릭 하면 자원에 대한 상세화면을 확인할 수 있다. 상세 화면은 아래의 자원명, 자원의 종류, 패턴, 세부설명, 우선권 등을 입력하도록 되어있다. 여기서 우선권이란, 중복적으로 등록된 자원 패턴들 사이에서의 우선적인 매칭 비교 순위를 의미한다. 즉, 우선권이 높은 자원에 대한 매칭 후 권한 부여가 먼저 이루어지는 것이다.

예를 들어, URL 형태의 자원 product/*.do 자원에 5라는 우선권을 부여 한 후, product/add.do 자원에는 11, product/getProduct.do 에는 12, product/updateProduct.do 자원에는 13의 우선권을 부여하였다. 사용자는 관리자에게는 제품에 대한 CRUD, 즉 생성, 조회, 수정, 삭제에 대한 권한을 모두 부여할 예정이고, 일반 이용 고객에게는 생성, 조회, 수정 권한만 허용하고 삭제 권한은 허용하지 않을 예정이다. 따라서 사용자는 ROLE_ADMIN 에게 product/*.do 자원을 할당하고, ROLE_USER 에게 product/add.do, product/getProduct.do, product/updateProduct.do 자원을 할당 하였다. 하지만 이런 방법으로 자원을 할당 하였을 때는 다음과 같은 문제가 발생한다. 먼저 관리자 역할에 할당 되어있는 사용자는 CRUD 모든 기능에 대해 제한 없이 사용할 수 있을 것이다. 하지만 일반 사용자가 product/getProduct.do URL 자원을 호출 했을 경우, product/getProduct.do 자원이 DB상의 어떤 자원 패턴과 매칭 되는지 우선권을 바탕으로 비교 작업을 하게 된다. 따라서 우선권이 높게 설정되어 있는 product/*.do 패턴에 우선적으로 매칭 되어져서 product/*.do 자원이 할당되어 있는 ROLE_ADMIN 권한과 현재 사용자의 권한을 비교하게 된다. 결과적으로 일반 사용자는 ROLE_ADMIN 권한을 가지고 있지 않기 때문에 product/getProduct.do 요청은 접근 거부 당하게 된다.

위와 같은 오류를 범하지 않기 위해서는 다음의 사항을 준수해야한다.

유의사항

  • 일반화 된 자원(예를 들면 *.do와 같은)의 우선 순위는 되도록 낮게 준다(즉, 큰 숫자로 등록한다).

  • 빈번하게 참조되어지는 자원의 경우 우선권을 높게 설정하는 것이 성능 향상에 도움이 된다.

  • 보호되는 자원으로 등록 할 필요성이 없는 자원에 대해서는 Spring Security의 기본 설정 파일의 http namespace 태그 내 intercept-url 에 해당 패턴에 대해 filters="none" 으로 등록하도록 한다.

아래의 그림은 특정 자원을 더블 클릭해서 상세 정보 화면으로 이동한 모습이다. 자원 패턴을 등록 할 때 자동 완성 기능을 사용하고 있는 것을 확인할 수 있다.

위 그림은 자원 상세 정보 예시 화면이다. 자원을 등록할 때 패턴에 대한 자동완성 기능을 제공한다.

사용자는 기본적으로 자원 패턴 란을 작성하면 된다. 작성의 편의를 돕고 실수를 막기 위해서 자원 패턴 입력할 때 자동 완성 기능을 지원한다. 자동 완성 기능을 이용하여 패턴을 등록했을 때에는 정규식 등을 이용하여 유사한 이름의 자원을 묶음으로 등록 할 수 없다. 그런 경우에는 상세 자원 패턴 란의 직접입력 체크박스를 클릭한 후, 사용자가 직접 자원을 등록할 수 있다. 이 경우에는 사용자의 실수에 의한 어플리케이션 오동작의 소지가 있기 때문에, 패턴 정규식 사용에 능통한 사용자가 아니면 이 방법을 쓰지 않을 것을 추천한다.

아래의 그림은 URL 형태의 자원 패턴을 입력할 때 볼 수 있는 화면이다. URL 패턴은 왼쪽의 URL Request 주소와 오른쪽의 파라메터로 이루어진다. 파라메터는 필수 입력 사항이 아니므로 선택적으로 사용하면 된다.

위 그림은 URL 형태의 자원을 입력하는 예시 화면이다. 자동 완성 기능을 이용하여 패턴 입력시 실수를 방지할 수 있다.

아래에 있는 세 개의그림은 Method 형태의 자원 패턴을 입력할 때의 화면이다. Method 패턴은 총 3개의 입력창을 가지며 이들은 좌측에서부터 차례로 패키지, 클래스, 메소드를 입력하는 곳이다. System Management 메뉴의 Resource Gathering 을 이용하면 엔터프라이즈 어플리케이션의 자원을 수집해서 보관해 두기 때문에 패턴을 입력할 때 자동 완성 기능을 사용하여 수월하게 패턴을 입력 할 수 있다. 좌측의 패키지 정보부터 클래스, 메소드 순으로 작성하면 아래의 세부 자원 패턴 항목에서 세 개의 입력 내용을 결합시킨 형태로 표현해준다. 결합된 이 정보가 최종적으로 저장될 패턴의 형태이다.

먼저 패키지를 입력한다.

위 그림은 Method 형태의 자원 패턴 입력 화면 중 패키지 정보를 입력할 때 자동 완성을 이용하는 예시 화면이다.

다음으로 클래스를 입력한다.

위 그림은 Method 형태의 자원 패턴 입력 화면 중 클래스 정보를 입력하는 예시이다.

마지막으로 메소드를 입력한다.

위 그림은 Methdo 형태의 자원 패턴 입력 화면 중 메소드 정보를 입력하는 예시이다.

혹시 자원명이 기억나지 않으면 입력창에 스페이스바를 입력하면 모든 자원 목록이 나타난다. 이 결과를 바탕으로 자원 패턴을 입력하면 더욱 간단하게 입력할 수 있을 것이다.

마지막으로 POINTCUT 형태이 자원 패턴 입력에 대해서 알아보자. POINTCUT 패턴은 단 하나의 입력창을 가지며 사용자가 자동완성 기능을 이용해 입력창을 작성하면, 아래의 상세 자원 패턴 란에서 포인트컷 패턴에서 사용되는 AspectJ 지원 패턴 형태로 완성시켜준다. 만약 AspectJ에서 지원하는 PointCut 형태의 패턴에 능숙하다면 Self Input 체크 박스를 클릭한 다음 상세 자원 패턴 란을 직접 수정하여서 여러개의 패턴을 묶음으로 등록 할 수도 있다.

위 그림은 포인트컷 형태의 자원 패턴 입력시 자동 완성 기능을 이용하여 패턴을 입력하는 예시 화면이다.

위 그림은 AspectJ에서 지원하는 Pointcut 형태의 패턴을 직접 입력한 예시 화면이다.

View List 메뉴 에서는 권한에 따른 화면 제어를 위해 View Resource를 등록하고 수정/삭제 하는 기능을 제공한다.권한에 따라서 화면을 제어 하기 위해서는 해당 페이지에 다음과 같이 iam:access 태그를 이용해서 제어하고자 하는 내용을 감싸주면 된다.

<iam:access hasPermission="${iam:getPermissionMask(\"CREATE\")}" viewName="listCategory">
	<td><input type="button" name="addCategory" onClick="javascript:fncAddCategoryView();"></td>
</iam:access>
태그 내에 있는 viewName에 해당하는 자원을 등록, 수정, 삭제 하는 화면이 바로 View List 메뉴이다.

아래의 화면은 View List 화면의 예시이다. 화면의 좌측에 계층구조를 가지는 View Resource 목록이 있고, 오른쪽에 탭메뉴로 구성된 상세화면, 리스트, 매핑 화면을 볼 수 있다.

위 그림은 화면 제어를 위한 계층 구조를 가지는 View Resource 관리 예시 화면이다.

좌측의 Tree 화면에서 마우스 우클릭으로 View Resource 등록, 삭제, 수정 등의 동작을 할 수 있다.

위 그림은 화면 제어 계층 구조에서 마우스 오른쪽 버튼을 클릭하여 View Resource를 등록/수정/삭제 하는 예시 화면이다.

다음은 View 자원의 상세 정보 페이지 이다. View Name은 모든 View Resource 가운데 유일한 값을 가져야 한다. 우측의 Check Name 버튼을 이용해서 중복 확인을 통과 해야 View Resource를 등록/수정 할 수 있다. 또한 System Name 필드는 화면 우측 상단의 System Name select Box의 내용이 자동으로 설정되므로 이를 유념하자.

위 그림은 View Resource의 상세 정보 페이지이다.

다음으로 확인할 메뉴는 View List 탭 메뉴 이다. 좌측의 Tree 메뉴에서 선택한 View Resource의 계층 구조상 한 단계 하위에 속해있는 View Resource들의 List를 나타낸다. Tree 메뉴에서 아무런 View Resource도 선택하지 않았다면 전체 View Resource List를 확인할 수 있다.

위 그림은 좌측의 트리에서 특정 View Resource를 클릭 했을때 오른쪽 View List 탭에서 나타나는 화면 제어 목록 예시 화면이다.

마지막으로 View Mapping 탭 메뉴를 알아보자. View Mapping 메뉴에서는 사용자가 입력한 View 자원과 사용자, 그룹, 역할 간의 할당을 관리한다. 기본적으로 관리자가 iam:access내에 지정한 Permission을 가지는 사용자만이 태그 내의 내용에 대한 권한을 가지기 때문에, 해당 Permission을 View Mapping 화면에서 쉽게 관리하도록 편리한 UI를 제공한다.

최초 View Mapping 메뉴를 선택하면 View 자원에 Permission을 가지고 있는 사용자들에 대한 리스트가 보여진다. Reference Type 항목은 해당 Permission이 할당 된 곳이 사용자 개인인지, 그룹인지 혹은 역할인지를 나타내는 항목이다. 여기서 주의할 점은 역할 보다는 사용자 그룹이, 그룹 보다는 사용자에게 할당된 Permission이 우선권을 가진다는 점이다. 예를 들어 Update Category 라는 카테고리 수정에 대한 View 자원에 대한 권한을 'ROLE_ADMIN' 역할과 'STAFF' 그룹에게 부여했다고 가정해보자. STAFF 그룹은 'ROLE_ADMIN'보다 하위 계층인 'ROLE_STAFF' 역할에 할당 되어있다. 따라서 STAFF 그룹을 제외한 나머지 'ROLE_STAFF'에 할당 된 사용자들은 Update Category라는 ID를 가지는 View 자원에 대해서 권한이 없지만, STAFF 그룹만은 해당 자원에 대한 권한을 가지게 되는 것이다. 마찬가지로 그룹에게는 자원이 할당되지 않았다 하더라도 개인 사용자에게 View 자원에 대한 권한을 줄 수 있다. 이는 그룹 내의 모든 사용자 가운데 예외 케이스를 설정하기 위해 해당 룰을 이렇게 정의한 것이므로, 혹시 그룹 내의 다수의 사용자에게 이와 같이 권한을 줘야 되는 상황이라면 새로운 역할을 만들어서 해당 역할에 권한을 할당하는 방법을 추천한다.

아래의 그림은 View Mapping 메뉴를 선택했을 때 보여지는 할당 목록에 대한 예시 화면이다.

위 그림은 View Mapping 탭에서 매핑 정보 목록을 나타내는 예시 화면이다.

다음에 보여지는 그림은 View 자원에 역할과 그룹, 사용자를 할당하는 예시 화면이다. 최초 관리 하고자 하는 View 자원의 ID를 화면 상단에 입력한 후, 아래의 Add Role, Add Group, Add User 버튼을 이용하여 할당하고자 하는 대상에게 권한을 부여하면 된다. Permission 목록은 아래의 그림처럼 READ, WRITE, CREATE, DELETE, ADMINISTRATION, LIST, PRINT 등으로 초기 설정 되어 있고, 설정 파일을 통해서 사용자가 원하는 대로 변경할 수 있다. 사용자 설정 변경은 다음의 링크를 참고한다. IAM Core Configuration

위 그림은 View Resource에 역할과 그룹, 사용자를 할당하는 예시 화면이다.

Restriction Management 메뉴에서는 자원을 시간에 따라 관리할 수 있도록 다양한 메뉴를 제공한다. 세부 메뉴으로는 Restricted Times List와 Times Mapping 메뉴가 있다.

먼저 Restricted Times List 화면을 살펴보자. 아래의 그림은 Restricted Times List 메뉴을 클릭 했을 때 나타나는 화면의 예시이다. 이 화면은 자원을 제한하고자 하는 날짜와 시간들을 등록/수정/삭제 하는 화면이다. 세부 항목으로는 Time Type과 시작/종료 시간, 시작/종료 날짜, 상세 설명 등이 있다. Time Type에는 improve, daily, weekend, holiday, crash의 다섯가지 종류가 존재한다. 이는 각각 시스템 개선, 매일, 주말, 휴일, 장애발생을 나타낸다. 여기서 주의할 점은 Time Type의 weekend를 선택했을 경우이다. weekly로 설정 했을 경우 사용자들은 시작 시간과 종료 시간 사이의 매 주말에 대한 시간 제어 설정이 가능하다고 생각할 수 있는데, 실제로는 그렇게 동작하지 않는다. Time Type 항목은 시간 자원을 쉽게 구분하기 위해 text 형태로 저장하는 필드일 뿐이고, 사용자가 입력할 시작 날짜와 종료 날짜에 대한 제한을 직접 설정해야한다. 따라서 사용자가 10월 매 주말에 대한 권한 제어를 하기 위해서 시작 날짜를 091001(09년 10월 1일), 종료 날짜를 091031(09년 10월 31일)로 설정 하였다면, 실제 동작은 사용자의 기대와는 다르게 10월 한달 내내 권한이 통제될 것이다.

위 그림은 시간별 접근 제한 기능을 사용하기 위해 등록한 시간 목록 예시 화면이다.

Time List 화면에서 특정 시간을 더블 클릭하면 상세 화면으로 이동한다. 상세 화면에서는 해당 시간 자원에 대해 수정을 가할 수 있다.

위 그림은 등록된 특정 시간에 대한 상세 정보 예시 화면이다.

다음으로 살펴볼 화면은 Times Mapping 메뉴이다. Times Mapping 화면은 Time-Role, Time-Resource, Time-Exclusion 총 3개의 탭 메뉴로 구성되어 있다.

먼저 Time-Role 메뉴에 대해 살펴보자. Time-Role 메뉴는 앞서 Restricted Times List 화면에서 생성한 시간 자원에 역할을 할당 시켜서, 특정 역할을 가지는 사용자들을 특정 시간동안 제한하는 메뉴이다. Time-Role 메뉴를 클릭하면 아래와 같은 화면을 볼 수 있다. 아래의 리스트 화면은 사용자가 정한 시간과 그에 할당된 역할이 한 줄씩 나열되어 있다. 특정 할당 내용을 더블 클릭 하면 상세 화면으로 이동 한다.

위 그림은 시간에 대한 접근 제한 기능 중에서 현재 등록된 시간별 역할 제한 목록 예시 화면이다.

아래의 화면은 time-00004 과 ROLE_MANAGER 간의 할당 정보를 보여주는 상세 정보 페이지 이다. 우선 상단의 Time ID 란에서 사용자가 원하는 시간 제한 ID를 찾아서 입력한 후, 아래의 ROLES LIST 에서 제한되기를 원하는 역할을 찾아서 더블 클릭 하면 오른쪽에 해당 역할의 리스트가 나타나는 것을 볼 수 있을 것이다. 여기서 한 가지 알아둘 것은 사용자가 특정 역할에 대해 시간 제한을 설정 했다면, 해당 역할의 하위에 속해있는 역할들 또한 시간 제한이 설정된다는 것이다. 예를 들어 아래의 그림과 같이 ROLE_MANAGER 역할에 장애 처리의 목적으로 시간 000000 부터 235959 까지 제한 했다고 가정하면, ROLE_MANAGER역할의 하위에 있는 ROLE_USER, ISAUTHENTICATED_ANONYMOUSLY 두 개의 역할에 속하는 사용자들 또한 000000 시간부터 235959 시간까지 사용이 제한는 것이다.

위 그림은 특정 시간에 특정 역할 사용자들의 접근을 제한하기 위한 등록 예시 화면이다.

다음으로 Time-Resource 메뉴에 대해 살펴보자. Time-Resource 메뉴에서는 특정 시간동안 특정 자원에 대한 접근 권한을 제어하기 위한 메뉴이다. Time-Resource 메뉴를 클릭하면 아래 그림과 같은 특정 시간에 대해 할당 되어있는 자원의 목록을 볼 수 있다. Time ID를 더블클릭 하면 해당 시간에 할당되어 있는 자원 목록과 상세 내용을 확인할 수 있는 상세 화면 페이지가 보여진다.

위 그림은 특정 시간동안 특정 자원에 대한 접근을 제한하기 위해 등록된 시간-자원 매핑 목록 예시화면이다.

아래의 그림은 시간-자원 목록의 상세 내용 페이지이다. 시간에 따른 자원 제한을 설정 하기 위해서는 우선 상단의 Time ID 란에서 원하는 시간의 Time ID를 선택한 후, 하단의 Add Resource 버튼을 클릭해서 팝업이 나타나는 것을 확인한다. 팝업창에서 원하는 자원을 클릭 한 이후 Add 버튼을 클릭하면 상세 화면 페이지에 자원이 할당 되는 것을 볼 수 있다.

위 그림은 특정 시간에 특정 자원에 대한 접근을 제한하기 위한 등록 예시 화면이다.

마지막으로 살펴볼 메뉴는 Time-Exclusion이다. 이 메뉴에서는 Time-Resource 메뉴에서 설정한 시간에 따른 접근 제한에 대해 예외 케이스를 설정할 수 있다. 쉽게 말해 장애 복구를 위해서 전체 시스템에 대한 접근을 막은 후, 관리자 권한을 가진 사용자에게만 예외적으로 시스템을 개방해서 시스템 복구를 하도록 예외 상황을 적용 시키는 것이다. Time-Exclusion 메뉴를 클릭 하면 아래의 그림과 같은 목록을 볼 수 있다. 특정 항목을 더블 클릭 해서 상세 목록 페이지로 이동할 수 있다.

위 그림은 특정 시간에 대한 접근 제한 기능 중 등록된 예외 케이스의 목록 화면이다.

아래의 그림은 Time-Exclusion의 상세 화면 페이지이다. 시간 제한에 대해 예외 조건을 주기 위해서는 우선 상단의 Resource ID 란 우측에 있는 검색 버튼을 이용해서 시간-자원 간의 할당 내역이 존재 하는지를 확인 해야한다. 검색 버튼을 클릭하면 존재하는 시간-자원 할당 목록이 나타나는데 이 중에서 예외 조건을 설정하기 위한 자원을 더블 클릭한다. 그러면 아래의 상세 항목들이 자동으로 완성 되고, 그 이후에 하단의 Role Tree를 열어서 예외로 설정되기를 원하는 역할을 더블 클릭 하면 해당 역할이 우측의 목록으로 나타나게 된다. 여기서 유의할 점은 사용자가 예외로 설정한 역할의 상위에 존재하는 역할들 또한 접근 제한이 해제된다는 것이다. 예를 들어 아래의 그림과 같이 web-000009 자원의 제한 설정에 ROLE_MANAGER 역할의 사용자를 예외로 설정하게 되면, ROLE_MANAGER의 상위에 존재하는 ROLE_ADMIN 에 속하는 사용자들 또한 web-000009 자원에 대한 제한 설정이 해제 된다. 따라서 역할에 대한 예외를 설정할 때 해당 역할의 상위 역할의 사용자들 또한 제한이 해제 된다는 것을 유념하고 예외 설정 해야 될 것이다.

위 그림은 특정 시간에 특정 자원에 대해 등록된 접근 제한 설정에 예외 케이스를 입력하는 예시 화면이다.

System Management 메뉴에서는 비지니스 어플리케이션에 대한 간단한 제어 기능을 제공한다. System Management 메뉴에는 Resource Reload와 Resource Gathering, Data Upload 총 세 개의 서브메뉴가 존재한다.

Resource Reload 메뉴에서는 앞서 설명한 4 개의 메뉴들에서 설정한 내용들을 적용하기 위한 기능을 제공한다. 기본적으로 변경된 내용들을 적용시키기 위해서는 비지니스 어플리케이션의 서버를 재시작 해야 하지만 본 기능을 이용하면 서버의 재시작 없이 설정을 변경 시킬 수 있다. Resource Reload 메뉴를 클릭하면 아래의 그림과 같은 화면이 나타난다.

위 그림은 Resource Reload 기능을 사용할 수 있는 화면 예시이다.

타겟 어플리케이션 서버를 선택한 후, 사용자/역할/자원에 대한 정보를 Reload 할지, 시간 관리 메뉴에 대한 정보를 Reload 할 지를 Select Box에서 선택 한 후, 하단의 Reload 버튼을 클릭하면 잠시 로딩 시간을 가진 후 완료 메세지가 나타난다.

이 동작은 반드시 타겟 어플리케이션 서버가 동작하고 있을 때 수행 해야 한다. 그렇지 않은 경우에는 아래와 같은 오류 메세지가 나타날 것이다.

위 그림은 Target Application 서버가 동작하지 않고 있는 상황에서 Reload 기능을 수행 했을 때 발생하는 오류 화면이다.

Resource Gathering 메뉴는 타겟 어플리케이션의 정보를 수집하는 기능을 제공한다. 이 기능을 사용하면 타겟 어플리케이션의 bean 설정과 Request URL 주소 등을 수집해서 임시로 저장하게 된다. 저장된 정보는 Resource Management 메뉴에서 자원을 등록할 때 자동 완성 기능을 통해 더 쉽게 자원을 등록 하도록 사용자에게 편의를 제공한다. Resource Gathering 메뉴를 클릭하게 되면 아래의 그림과 같은 화면을 볼 수 있다. 화면에서 자원 수집을 원하는 어플리케이션 서버를 선택한 후 Reload 버튼을 클릭하면 잠시 로딩 시간을 가진 후, 완료 메세지가 나타나게 된다.

위 그림은 Resource Gathering 기능을 사용할 수 있는 예시 화면이다.

Data Upload 메뉴는 다량의 초기 Data를 직접 입력하는 번거로움을 덜기 위하여 다량의 데이터를 Excel 파일로 등록 / 관리 하는 기능을 제공한다.

사용에 앞서 Excel File을 저장할 저장 공간의 위치를 /anyframe-iam-admin-web/src/main/resources/systemname.properties 에 적절하게 등록한다. (디렉토리의 경로는 절대 경로로 인식된다.)

DESTINATION_DIR=D:\\anyframe-iam-admmin-web\\src\\main\\webapp\\excel

Data Upload 메뉴의 최초 화면은 아래와 같이 검색창과 3 개의 버튼, 화면 중앙의 File 목록으로 구성 되어있다.

위 그림은 엑셀 파일 업로드 기능을 이용할 수 있는 목록 화면 예시이다.

  • Upload : 원하는 Excel File을 Upload 하는 화면으로 이동한다.

  • SnapShot : 현재 DB에 저장된 데이터를 바탕으로 엑셀 파일을 생성하여 저장한다. SNAPSHOT-xxxx-workDate-yyyymmdd.xls 의 파일명으로 생성된다.

  • Apply : 선택한 엑셀 파일의 내용을 DB에 반영한다. 이 때 기존에 DB에 존재하던 데이터는 SNAPSHOT 파일로 저장 후 삭제되어 새로운 엑셀 파일로 대체된다. FILE-xxxxxx-OriginalFileName.xls 의 파일명으로 생성된다.

  • File 목록 : File 목록의 Bold체로 표시된 File name을 클릭하면 해당 파일을 다운 받을 수 있다.

유의사항

새로운 데이터를 추가 하기 위해서 파일을 업로드 할 경우 기존의 데이터가 모두 삭제 되므로 주의 해야 한다. 예를 들어 기존의 USERS 테이블에 200명의 사용자가 이미 입력 되어 있었고, 추가로 50명에 해당하는 데이터를 삽입 하기 위해서 엑셀 파일을 업로드 하여 Apply 버튼을 누르게 되면, 기존의 200명에 해당하는 데이터는 SNAPSHOT 파일에 저장 후 삭제 되고 실제로 DB에는 50명의 데이터만 남게 된다. 그러므로 신규 데이터를 추가 하기 위해서는 기존의 DATA의 SNAPSHOT 파일을 먼저 생성한 후, 생성된 Excel 파일에 원하는 데이터를 추가 하는 형태로 작업을 진행 해야 한다.

Upload 버튼을 클릭하면 아래와 같은 화면으로 이동하게 된다. 화면은 Data Upload용 File Input box와 Submit, Cancel 버튼이 상단에 있고 화면 중앙에는 File Upload 후 Validation 결과를 목록으로 보여주는 Grid 화면이 존재한다.

위 그림은 특정 엑셀 파일을 업로드 했을 때 유효값 검증 결과 목록 예시 화면이다.

화면의 File Upload input box를 통해 Excel File을 업로드 할 수 있다. 현재 IAM은 2003년 이하 버전으로 작성된 xls 파일만을 지원한다. 파일 업로드 후 Submit 버튼을 누르면 입력값 검증을 거친 후 성공적으로 저장된 경우 이전 화면으로 돌아가게 된다. 하지만 입력값에 문제가 있을 경우, 위 그림처럼 Error Message 란에 오류 메세지가 나타나고, 파일은 저장되지 않는다. 파일의 입력값을 오류 메세지에 따라 정상적으로 고친 이후에 다시 파일을 업로드 시켜야지 정상적으로 파일이 저장된다.

하나의 IAM Admin 관리 화면은 여러 개의 시스템을 통합 관리할 수 있도록 구성되어 있다. IAM에서 관리되어야 하는 시스템의 이름은 /anyframe-iam-admin-web/src/main/resources/systemname.properties 에 다음과 같이 등록된다. (구분값은 콤마로 구분한다.)

SYSTEM_NAMES=IAM_SAMPLE

만약 관리할 시스템이 여러 개 라면, 아래와 같이 콤마로 구분하여 등록 하면 된다.

SYSTEM_NAMES=IAM_SAMPLE1,IAM_SAMPLE2

또한 앞서 설정한 remote-invoker-servlet.xml 파일 내에 관리 하고자 하는 모든 시스템의 수집 경로를 지정해 주어야 한다. 이 때 bean id값은 반드시 unique해야 한다. 아래의 설정 예시 중 bold체로 강조된 부분을 참고하도록 한다.

<!-- Remote HttpInvoker Call -->
	<bean id="gatherServiceClient1"
		class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">				
		<property name="serviceUrl"
			value="http://localhost:8080/anyframe-iam-sample/assist/resourceGatherAssist.do" />
		<property name="serviceInterface"
			value="org.anyframe.iam.core.assist.IResourceGatherAssistService" />
		<property name="httpInvokerRequestExecutor">		
			<bean
				class="org.springframework.security.context.httpinvoker.
									AuthenticationSimpleHttpInvokerRequestExecutor" />
		</property>
	</bean>
	<bean id="gatherServiceClient2"
		class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">				
		<property name="serviceUrl"
			value="http://localhost:8080/anyframe-iam-sample2/assist/resourceGatherAssist.do" />
		<property name="serviceInterface"
			value="org.anyframe.iam.core.assist.IResourceGatherAssistService" />
		<property name="httpInvokerRequestExecutor">		
			<bean
				class="org.springframework.security.context.httpinvoker.
									AuthenticationSimpleHttpInvokerRequestExecutor" />
		</property>
	</bean>
	
	<bean id="resourceReloadServiceClient1"
		class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
		<property name="serviceUrl"
			value="http://localhost:8080/anyframe-iam-sample/reload/resourceReload.do" />			
		<property name="serviceInterface"
			value="org.anyframe.iam.core.reload.IResourceReloadService" />
		<property name="httpInvokerRequestExecutor">
			<bean
				class="org.springframework.security.context.httpinvoker.
									AuthenticationSimpleHttpInvokerRequestExecutor" />
		</property>
	</bean>
	<bean id="resourceReloadServiceClient2"
		class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
		<property name="serviceUrl"
			value="http://localhost:8080/anyframe-iam-sample2/reload/resourceReload.do" />			
		<property name="serviceInterface"
			value="org.anyframe.iam.core.reload.IResourceReloadService" />
		<property name="httpInvokerRequestExecutor">
			<bean
				class="org.springframework.security.context.httpinvoker.
									AuthenticationSimpleHttpInvokerRequestExecutor" />
		</property>
	</bean>

			

Admin 의 설정이 완료되었다면, 대상 어플리케이션에도 어플리케이션 이름을 지정해 주어야 한다. 앞서 설정한 spring-security-servlet.xml 파일을 열어서 아래의 bold체로 강조된 강조된 부분을 적절한 시스템명으로 변경한다.

<!-- Remote HttpInvoker Call -->
	<bean id="resourceGatherAssistService"
		class="org.anyframe.iam.core.assist.impl.ResourceGatherAssistServiceImpl" >
		<property name="filterPatterns">
			<list>
				<value>(?!anyframe\.iam\.sample\..*)anyframe\..*</value>
				<value>org\..*</value>
				<value>net\..*</value>
				<value>java\..*</value>
			</list>
		</property>
		<property name="systemName" value="IAM_SAMPLE1" />
	</bean>

마찬가지로 context-spring-security.xml 파일을 열어 아래의 bold체 부분을 적절한 시스템명으로 변경한다.

<b:bean id="securedObjectDAO" class="org.anyframe.iam.core.securedobject.impl.SecuredObjectDAO">
	<b:property name="dataSource" ref="dataSource" />
	<b:property name="systemName" value="IAM_SAMPLE" />
</b:bean>

DB 의 SECURED_RESOURCES 에는 최소한 RESOURCE_TYPE이 pointcut 인 데이터가 하나는 존재하여야 한다. 다음과 같이 pointcut 타입의 데이터를 하나 Insert 하여 준다. (select * from secured_resources where RESOURCE_ID like 'PNC%')

위 그림은 RESOURCE_TYPE이 pointcut인 데이터 예시이다. IAM 기동을 위해서 pointcut 형태의 resource가 최소 하나 이상 등록되어 있어야 한다.

IAM에서 시스템을 통합관리하는 방법은 간단하다. 화면의 우측 상단에 존재하는 시스템 콤보박스를 클릭하여 원하는 시스템으로 맞춘 후 작업을 진행하면 된다. (이 때 콤보박스에 보이는 시스템 목록은 systemname.properties 에 등록된 목록이다.)

위 그림은 다중 시스템을 IAM을 이용하여 관리할 때 콤보박스를 이용하여 시스템을 선택하는 예시 화면이다.

작업 도중 시스템명을 변경하면(콤보 박스를 변경시키면) 초기 화면으로 이동하므로 유의 해야 한다.

본 Appendix 의 내용은 매뉴얼에서 본문으로 다루기 어려운 Spring Security에 대한 심도 있는 부분에 대한 개략적인 내용으로 구성되어 있다. 하기 내용에 대한 더욱 심도있는 내용은 Spring Security 의 공식 매뉴얼 (http://static.springsource.org/spring-security/site/docs/2.0.x/reference/springsecurity.pdf)에 다루어져 있으므로 해당 매뉴얼을 참고하기 바란다.

Spring Security 는 Servlet Filter 기술을 사용하여 웹 리소스에 대한 보안 제어를 제공하며 여러 Filter 를 Filter Chain 으로 엮어 필요에 따른 각 보안 기능을 적용하게 된다. Spring Security 에서 사용하는 Filter 들은 Spring 컨테이너가 관리하는 Bean 이기도 하며 사용자 인증, 보호자원 권한 제어 등 주요 보안 기능에 필요한 세부 보안 기능을 매우 유연하게 추상화하여 Spring 에서 관리하는 별도의 Dependency Bean 형태로 사용하게 된다. 아래에 나타난 Filter (AuthenticationProcessingFilter, HttpSessionContextIntegrationFilter, ExceptionTranslationFilter, FilterSecurityInterceptor) 들은 Spring Security 에서 필수적으로 사용되고 있으며 필요에 따라 Spring Security 에서 기본으로 구현하여 제공하는 다양한 Filter 들을 추가/변경 할 수 있다. Anyframe IAM 의 경우 FilterSecurityInterceptor 를 확장한 시간 제한에 따른 권한 제어용 Filter 등을 추가로 삽입하여 처리 가능하다.

위 그림은 Spring Security에서 제공하는 Filter chain에 대한 설명이다. Spring Security에서 기본적으로 제공하는 Filter chain 외에 추가적으로 다양한 Filter들을 추가/변경 할 수 있다.

Spring Security 에서는 사용자 인증에 따른 보안 정보를 제공하는 보안 객체를 기본으로 현재 실행중인 Thread 에 유지할 수 있도록 제공하고 있다. Spring Security 의 기본 구현에 따르면 SecurityContext 를 SecurityContextHolder 내부에 생성된 ThreadLocal 객체를 이용하여 저장하게 되며 HttpSessionContextIntegrationFilter 를 사용하여 request 간 SecurityContext 정보를 Http Session 에 동기화하여 유지하게 된다.

위 그림은 Spring Security에서 사용자 인증에 따른 보안 정보를 제공하기 위한 보안 객체를 저장하는 방법에 대한 설명이다. 보안 정보(SecurityContext)를 ThreadLocal 객체를 이용하여 저장하게 되며 HttpSessionContextIntegrationFilter를 사용하여 Request간 SecurityContext 정보를 Session에 동기화 하여 유지하게 된다.
  • Spring Security에서 생성한 정보 - SecurityContextHoler 이용하여 SecurityContext 얻음

  • 응용프로그램이 분산되어 있는 경우 등 다양한 환경에서 사용 가능토록 SecurityContext를 SecurityContextHolder 내부에 생성한 ThreadLocal 객체를 이용하여 저장하고 있음.

  • ThreadLocal 객체는 현 쓰레드에서만 필요한 상태 정보를 담을 수 있음.

  • 웹 환경에서 사용자 요청시 마다 동일한 역할을 하는 SecurityContext를 다시 생성하는 것은 맞지 않음 → HttpSessionContextIntegrationFilter 를 사용하여 SecurityContext 정보를 ThreadLocal에 기록하고 가져오는 작업을 수행함. (Session 에 저장)

아래는 Spring Security 에서 보호된 자원에 대한 권한 맵핑을 검사하여 접근을 허용할지 결정하는 권한 처리에 관계된 주요 모듈의 관계를 나타낸다.

위 그림은 Spring Security에서 보호된 자원에 대한 권한 매핑을 검사하여 접근을 허용할지 여부를 결정하는 권한 저리 관련 모듈에 대한 설명이다.
  • Web Url 에 대한 보호자원 보안 제어를 처리하는 FilterSecurityInterceptor 는 AbstractSecurityInterceptor 를 상속받고 있으며 ObjectDefinitionSource 를 통하여 보호자원-권한맵핑 데이터를 검사하여 매칭된 패턴에 해당하는 권한이 실제로 로그인한 사용자가 가지고 있는지를 AccessDecisionManager 에 등록된 AccessDecisionVoter 들의 ACCESS/DENIED 조합의 결과로 처리하게 된다. parent 인 AbstractSecurityInterceptor 에서는 필요에 따라 AuthenticationManager 를 통한 인증 및 RunAsManager 에 의한 사용자 대리 처리 Spring 의 ApplicationEvent 를 상속받은 여러 보안 관련 이벤트 처리를 수행하게 된다.

  • 위의 구조를 통해 보호자원 및 권한 맵핑, 권한 검사 등의 보안 모듈은 매우 유연하게 추상화되어 있음을 알 수 있으며, 메서드에 대한 AOP 형식의 보안 제어를 사용하는 MethodSecurityInterceptor 등도 마찬가지로 AbstractSecurityInterceptor 를 상속받고 있으며 동일하게 여러 Interface 에 대한 메서드 유형 보안 처리를 위한 구현 모듈을 사용하게 된다.

위의 Filter Chain 과 보안 객체 모델에서 확인할 수 있는 FilterSecurityInterceptor 가 Web URL 권한 처리를 담당하며 Spring Security 2.0 이후의 Namespace 태그를 사용하여 설정하는 경우 http 태그 하위에 <intercept-url pattern="antpath/regex 표현식 url 패턴" access="접근 가능한 Role" /> 형태로 보호하고자 하는 웹 Url 자원에 대해 맵핑 권한을 지정하게 된다.

intercept-url 로 지정하는 url 패턴의 순서는 매우 중요하며 Spring Security 에서는 나타나는 순서에 따라(Top to Bottom) 제일 먼저 match 된 패턴에 맵핑된 권한만 검사하게 된다. 그러므로 일반적으로 상세 패턴을 상위로, 와일드카드를 사용한 그룹 패턴은 하위로 작성하여야 하며 자주 억세스 하는 페이지에 대한 맵핑은 상위로 지정하는 것이 성능상 유리하다.

Anyframe IAM 에서는 위 보호자원(Url)-Role 권한 맵핑 부분을 DB화 하여 동일하게 DB 기반의 권한 처리를 하는 FilterSecurityInterceptor 를 하나 더 추가하여 custom-filter 로 배치하여 함께 사용하게 된다.

메서드 보안 제어는 HttpServletRequest 기반의 Web 환경이 아닌 경우에도 적용이 가능하며 더욱 견고하고 재사용성이 뛰어나며 강력한 권한 처리를 제공한다.

Spring 프레임워크에서와 마찬가지로 Spring AOP, AspectJ 와 같은 다양한 AOP 기술을 지원하며 Spring Security 의 메서드 권한 처리는 Around Advice 로 동작하게 된다. 따라서 메서드 실행 전/후에 보안 로직을 적용할 수 있으며 결과값을 가공(ex. Domain 객체에 대한 ACL 을 고려한 결과 데이터 Filtering)할 수도 있다.

Method metadata 지원

  • @JSR250 – ex.) @RolesAllowed("ROLE_USER")

  • @Secured – ex.) @Secured("ROLE_USER")

  • Instance-based XML

    <bean id="categoryService" class="com.sds.emp.sale.services.impl.CategoryServiceImpl">
        <security:intercept-methods>
            <security:protect method="com.sds.emp.sale.services.CategoryService.add*" access="ROLE_ADMIN"/>
        </security:intercept-methods>
        ..

  • AspectJ pointcut – ex.) <protect-pointcut expression="execution(* *.get*(..))" access="ROLE_USER" />

Anyframe IAM 에서는 위 보호자원(Method)-Role, 보호자원(Pointcut)-Role 권한 맵핑 부분을 DB화 하여 처리 가능하다.

또한 Spring Security 3.0 이상에서는 EL(Expression Language)- @PreAuthorize, @PostAuthorize, @PreFilter, @PostFilter 을 사용한 보다 강력한 보안 기능을 제공한다.

IAM에서 사용되는 DB Schema 정보이다. 아래의 DDL 문장들은 HSQL DB를 기준으로 작성이 되어있다. 해당 내용을 참고해 실제 프로젝트에서 사용되는 DB에 맞는 DDL 문장으로 수정 해 사용 가능하다.

사용자 정보를 가지는 테이블 이다.

CREATE TABLE USERS (
    USER_ID      VARCHAR(20) NOT NULL,
    USER_NAME    VARCHAR(50) NOT NULL,
    PASSWORD     VARCHAR(50) NOT NULL,
    ENABLED      CHAR(1),
    CREATE_DATE  VARCHAR(8),
    MODIFY_DATE  VARCHAR(8),
    CONSTRAINT PK_USERS
    PRIMARY KEY ( USER_ID )
);

사용자 그룹에 관련된 정보를 가지는 테이블이다.

CREATE TABLE GROUPS (
    GROUP_ID     VARCHAR(20) NOT NULL,
    GROUP_NAME   VARCHAR(50) NOT NULL,
    CREATE_DATE  VARCHAR(8),
    MODIFY_DATE  VARCHAR(8),
    CONSTRAINT PK_GROUPS
    PRIMARY KEY ( GROUP_ID )
); 

CREATE TABLE GROUPS_HIERARCHY ( 
    PARENT_GROUP  VARCHAR(50) NOT NULL,
    CHILD_GROUP   VARCHAR(50) NOT NULL,
    CREATE_DATE   VARCHAR(8),
    MODIFY_DATE   VARCHAR(8),
    CONSTRAINT PK_GROUPS_HIERARCHY PRIMARY KEY ( PARENT_GROUP, CHILD_GROUP ),
    CONSTRAINT FK_GROUPS1 FOREIGN KEY (PARENT_GROUP) REFERENCES GROUPS (GROUP_ID),
    CONSTRAINT FK_GROUPS2 FOREIGN KEY (CHILD_GROUP) REFERENCES GROUPS (GROUP_ID)
);

CREATE TABLE GROUPS_USERS (
    GROUP_ID     VARCHAR(20) NOT NULL,
    USER_ID      VARCHAR(20) NOT NULL,
    CREATE_DATE  VARCHAR(8),
    MODIFY_DATE  VARCHAR(8),
    CONSTRAINT PK_GROUPS_USERS PRIMARY KEY ( GROUP_ID, USER_ID ),
    CONSTRAINT FK_GROUPS_USERS_GROUP_ID FOREIGN KEY (GROUP_ID) REFERENCES GROUPS (GROUP_ID),
    CONSTRAINT FK_GROUPS_USERS_USER_ID FOREIGN KEY (USER_ID) REFERENCES USERS (USER_ID)
);

Role에 관련된 정보를 가지는 테이블이다.

CREATE TABLE ROLES (
    ROLE_ID      VARCHAR(50)  NOT NULL,
    ROLE_NAME    VARCHAR(50),
    DESCRIPTION  VARCHAR(100),
    CREATE_DATE  VARCHAR(8),
    MODIFY_DATE  VARCHAR(8),
    CONSTRAINT PK_ROLES PRIMARY KEY ( ROLE_ID )
);

CREATE TABLE ROLES_HIERARCHY (
    PARENT_ROLE  VARCHAR(50) NOT NULL,
    CHILD_ROLE   VARCHAR(50) NOT NULL,
    CREATE_DATE  VARCHAR(8),
    MODIFY_DATE  VARCHAR(8),
    CONSTRAINT PK_ROLES_HIERARCHY PRIMARY KEY ( PARENT_ROLE, CHILD_ROLE ),
    CONSTRAINT FK_ROLES1 FOREIGN KEY(PARENT_ROLE) REFERENCES ROLES(ROLE_ID),
    CONSTRAINT FK_ROLES2 FOREIGN KEY(CHILD_ROLE) REFERENCES ROLES (ROLE_ID)
);

보호대상자원에 관련된 정보를 가지는 테이블이다.

CREATE TABLE SECURED_RESOURCES ( 
    RESOURCE_ID       VARCHAR(10) NOT NULL,
    SYSTEM_NAME       VARCHAR(15),
    RESOURCE_NAME     VARCHAR(50), 
    RESOURCE_PATTERN  VARCHAR(300) NOT NULL,
    DESCRIPTION       VARCHAR(100),
    RESOURCE_TYPE     VARCHAR(10) NOT NULL,
    SORT_ORDER        NUMERIC,
    CREATE_DATE       VARCHAR(8),
    MODIFY_DATE       VARCHAR(8),
    CONSTRAINT PK_RECURED_RESOURCES
    PRIMARY KEY ( RESOURCE_ID )
); 

CREATE TABLE SECURED_RESOURCES_ROLES ( 
    RESOURCE_ID  VARCHAR(10) NOT NULL, 
    ROLE_ID      VARCHAR(50) NOT NULL, 
    CREATE_DATE  VARCHAR(8), 
    MODIFY_DATE  VARCHAR(8), 
    CONSTRAINT PK_SECURED_RESOURCES_ROLES PRIMARY KEY ( RESOURCE_ID, ROLE_ID ),
    CONSTRAINT FK_SECURED_RESOURCES FOREIGN KEY(RESOURCE_ID) REFERENCES SECURED_RESOURCES(RESOURCE_ID),
    CONSTRAINT FK_ROLES4 FOREIGN KEY (ROLE_ID) REFERENCES ROLES(ROLE_ID)
);

CREATE TABLE CANDIDATE_SECURED_RESOURCES (
    CANDIDATE_RESOURCE_ID    NUMERIC(10) NOT NULL,
    SYSTEM_NAME				 VARCHAR(15),
    BEANID                   VARCHAR(128),
    PACKAGES                 VARCHAR(128) NOT NULL,
    CLASSES                  VARCHAR(128),
    METHOD                   VARCHAR(128),
    PARAMETER                VARCHAR(128),
    REQUESTMAPPING           VARCHAR(128),
    POINTCUT                 VARCHAR(128),
    CANDIDATE_RESOURCE_TYPE  VARCHAR(10) NOT NULL,
    CONSTRAINT	CANDIDATE_SECURED_RESOURCES_PK	PRIMARY KEY(CANDIDATE_RESOURCE_ID)
);

화면제어에 관련된 정보를 가지는 테이블이다.

CREATE TABLE VIEW_RESOURCES (
    VIEW_RESOURCE_ID  VARCHAR(50) NOT NULL,   -- ex.) LOGI_001
    SYSTEM_NAME VARCHAR(15),
    CATEGORY          VARCHAR(255),           -- ex.) 물류 > 입고관리
    VIEW_NAME         VARCHAR(50) NOT NULL,   -- ex.) 미입고현황
    DESCRIPTION       VARCHAR(255) NOT NULL,  -- ex.) 입고되지 않은 주문 리스트
    VIEW_INFO         VARCHAR(255),           -- ex.) 화면에 대한 추가 정보
    CONSTRAINT PK_VIEW_RESOURCES  PRIMARY KEY(VIEW_RESOURCE_ID)
);

CREATE TABLE VIEW_RESOURCES_MAPPING  (
    VIEW_RESOURCE_ID  VARCHAR(50) NOT NULL,
    REF_ID            VARCHAR(50) NOT NULL,   -- ex.) ROLE_ID or USER_ID
    MASK              INTEGER NOT NULL,       -- ex.) 1(R), 2(W), 4(C), 8(D), 16(A)
    PERMISSIONS       VARCHAR(255) NOT NULL,  -- ex.) READ, WRITE, CREATE, DELETE, ADMINISTRATION
    REF_TYPE          VARCHAR(10) NOT NULL,   -- ex.) ROLE or USER [todo:// or GROUP]
    CONSTRAINT PK_VIEW_RESOURCES_MAPPING  PRIMARY KEY(VIEW_RESOURCE_ID, REF_ID),
    CONSTRAINT FK_MAPPING_VIEW_RESOURCE_ID  FOREIGN KEY (VIEW_RESOURCE_ID) REFERENCES VIEW_RESOURCES (VIEW_RESOURCE_ID)
);

CREATE TABLE VIEW_HIERARCHY (
	PARENT_VIEW VARCHAR2(50) NOT NULL,
	CHILD_VIEW VARCHAR2(50) NOT NULL,
	CREATE_DATE VARCHAR2(8),
	MODIFY_DATE VARCHAR2(8),
	CONSTRAINT PK_VIEW_HIERARCHY PRIMARY KEY(PARENT_VIEW,CHILD_VIEW),
	CONSTRAINT FK_VIEW1 FOREIGN KEY(PARENT_VIEW) REFERENCES VIEW_RESOURCES(VIEW_RESOURCE_ID),
	CONSTRAINT FK_VIEW2 FOREIGN KEY(CHILD_VIEW) REFERENCES VIEW_RESOURCES(VIEW_RESOURCE_ID)
);

시간에 의한 제어와 관련된 정보를 가지는 테이블이다.

CREATE TABLE RESTRICTED_TIMES (
    TIME_ID     VARCHAR(10) NOT NULL,
    TIME_TYPE   VARCHAR(10) NOT NULL,  -- crash, holiday, weekend, improve, daily
    START_DATE  VARCHAR(8),
    START_TIME  VARCHAR(6) NOT NULL,
    END_DATE    VARCHAR(8),
    END_TIME    VARCHAR(6) NOT NULL,
    DESCRIPTION	VARCHAR(100),
    CONSTRAINT PK_RESTRICTED_TIMES PRIMARY KEY(TIME_ID)
);

CREATE TABLE RESTRICTED_TIMES_RESOURCES (
    TIME_ID      VARCHAR(10) NOT NULL,
    RESOURCE_ID  VARCHAR(10) NOT NULL,
    CONSTRAINT PK_RESTRICTED_TIMES_RESOURCES  PRIMARY KEY(TIME_ID, RESOURCE_ID),
    CONSTRAINT FK_TIMES_RESOURCES_TIME_ID FOREIGN KEY (TIME_ID) REFERENCES RESTRICTED_TIMES(TIME_ID),
    CONSTRAINT FK_TIMES_RESOURCES_RESOURCE_ID FOREIGN KEY(RESOURCE_ID) REFERENCES SECURED_RESOURCES(RESOURCE_ID)
);

CREATE TABLE TIMES_RESOURCES_EXCLUSION (
    TIME_ID      VARCHAR(10) NOT NULL,
    RESOURCE_ID  VARCHAR(10) NOT NULL,
    ROLE_ID      VARCHAR(50) NOT NULL,
    CONSTRAINT PK_EXCLUSION  PRIMARY KEY(TIME_ID, RESOURCE_ID, ROLE_ID),
    CONSTRAINT FK_EXCLUSION_TIME_ID FOREIGN KEY (TIME_ID) REFERENCES RESTRICTED_TIMES(TIME_ID),
    CONSTRAINT FK_EXCLUSION_RESOURCE_ID FOREIGN KEY(RESOURCE_ID) REFERENCES SECURED_RESOURCES(RESOURCE_ID),
    CONSTRAINT FK_EXCLUSION_ROLE_ID FOREIGN KEY(ROLE_ID) REFERENCES ROLES(ROLE_ID)
);

CREATE TABLE RESTRICTED_TIMES_ROLES (
    TIME_ID  VARCHAR(10) NOT NULL,
    ROLE_ID  VARCHAR(50) NOT NULL,
    CONSTRAINT PK_RESTRICTED_TIMES_ROLES  PRIMARY KEY(TIME_ID, ROLE_ID),
    CONSTRAINT FK_TIMES_ROLES_TIME_ID FOREIGN KEY (TIME_ID) REFERENCES RESTRICTED_TIMES(TIME_ID),
    CONSTRAINT FK_TIMES_ROLES_ROLE_ID FOREIGN KEY(ROLE_ID) REFERENCES ROLES(ROLE_ID)
);

ID 자동 생성과 관련된 테이블이다.

CREATE TABLE IDS ( 
    TABLE_NAME  VARCHAR(16) NOT NULL, 
    NEXT_ID     NUMERIC(30) NOT NULL, 
    PRIMARY KEY ( TABLE_NAME )
);

엑셀 파일 Import/Export와 관련된 테이블이다.

CREATE TABLE DATA_UPLOAD (
	FILE_ID VARCHAR2(14) NOT NULL,
	PATH VARCHAR2(255) NOT NULL,
	FILE_NAME VARCHAR2(255) NOT NULL,
	CREATE_DATE VARCHAR2(8) NOT NULL,
	WORK_DATE VARCHAR2(8),
	CONSTRAINT PK_DATA_UPLOAD PRIMARY KEY(FILE_ID)
);