| 저자 Shing Wai Chan |
Java EE 5 이전에는 배포 설명자에서만 웹 계층 구성요소 및 Enterprise JavaBeans 기술 구성요소(일명 enterprise bean)에 대한 인증 및 권한 부여 정보를 지정할 수 있었다. 하지만 Java EE 5는 보안 주석을 통합하여 작업을 단순화했다. 이러한 주석은 JSR 250: 자바 플랫폼에 대한 일반 주석에 지정되어 있다.
이 주석은 enterprise bean 및 웹 구성요소에 대한 권한 부여를 단순화한다. 이 단순화는 enterprise bean에서 특히 중요하다.
이 테크팁에서는 보안 주석을 사용하여 보호되는 enterprise bean의 구성 방법을 살펴보겠다. 또한 애플리케이션 클라이언트에서 enterprise bean에 액세스하는 방법도 살펴보겠다.
샘플 웹 애플리케이션 패키지가 이 팁에 제공된다. 이 팁의 코드 예제는 해당 패키지에 포함된 샘플의 소스 코드에서 따온 것이다.
간단한 예제
간단한 enterprise bean(이 경우, PingEjb라는 무상태 세션 빈)을 먼저 작성해 보고 권한 부여 검사를 포함해 보자.
@Remote({Ping.class}) @Stateless public class PingEjb implements Ping { @PermitAll public String pingPermitAll() { return "PingEjb: pingPermitAll"; } @DenyAll public String pingPermitAll() { return "PingEjb: pingDenyAll"; } @RolesAllowed({"staff"}) public String ping() { return "PingEjb: ping"; } }
PingEjb에서 @PermitAll, @DenyAll 및 @RolesAllowed의 3가지 보안 주석을 주목하기 바란다. 사실 Java EE 5에서는 5개의 보안 주석이 도입되었다. 방금 언급한 3가지 주석 외에 @DeclareRoles 및 @RunAs가 있다. 5개의 모든 보안 주석은 javax.annotation.security 패키지에 있다.
@PermitAll을 사용하면 모든 보안 역할에서 연관된 메소드를 호출할 수 있다. @DenyAll을 사용하면 모든 보안 역할에서 연관된 메소드를 호출할 수 없다. PingEjb의 @RolesAllowed 주석은 ping 메소드에 적용된다. 여기서는 "staff" 역할을 가진 사용자만 이 메소드에 액세스할 수 있다.
보다 복잡한 예제
앞의 예제에서는 @RolesAllowed를 사용하여 enterprise bean에서 메소드를 보호하기가 얼마나 쉬운지 살펴보았다. 다음은 보다 복잡한 예제이다.
@RunAs(value="staff") @DeclareRoles({"staff", "temporary"}) @RolesAllowed({"ttrole"}) @Stateless public class HelloEjb implements Hello { @Resource private SessionContext sc; @EJB private Ping ping; public String hello() { if (!sc.isCallerInRole("staff") && !sc.isCallerInRole("temporary")) { return "HelloEjb: hello"; } else { throw new RuntimeException( "of role staff or temporary"); } } @RolesAllowed({"myrole"}) public String ping() { return ping.ping(); } }
HelloEjb 예제에는 두 개의 @RolesAllowed 주석이 있는데, 하나는 클래스 레벨이고 다른 하나는 메소드 레벨이다. 클래스 레벨의 @RolesAllowed 주석은 bean의 모든 비즈니스 메소드에 적용된다. 하지만 이 주석은 보다 구체적인 메소드 레벨의 보안 주석이 있는 경우 재정의될 수 있다. hello 메소드에는 보안 주석이 없으므로 이 메소드는 클래스 레벨의 주석 @RolesAllowed({"ttrole"})에 종속된다. 하지만 ping 메소드는 메소드 레벨의 주석 @RolesAllowed({"myrole"})에 종속된다.
@RunAs 주석은 메소드 호출 내의 후속 호출에 대한 역할을 지정하지만 메소드의 직접 호출에 대한 역할은 지정하지 않는다. 예제에서 HelloEjb.ping()은 로그인 사용자 역할을 가진 사용자라기보다 "staff" 역할을 가진 사용자로서 Ping.ping() 메소드를 호출한다.
@DeclareRoles 주석은 구성요소가 사용하는 역할을 정의하기 위해 사용된다. HelloEjb에서 "staff" 및 "temporary" 역할은 hello 메소드 내에서 isCallerInRole()의 호출에 의해 사용될 수 있다. isCallerInRole() 메소드는 @RolesAllowed보다 복잡한 보안 검사를 제공한다. HelloEjb에서는 "ttrole" 역할을 가진 사용자만 hello() 메소드에 액세스할 수 있다. "staff" 또는 "temporary" 역할을 가진 사용자는 이 메소드에 액세스할 수 없다.
다음 두 예제는 보안 관점에서 기능적으로 동일하다는 사실에 주목하기 바란다.
@RolesAllowed("staff") public String dummy() { ... }and: @DeclareRoles({"staff"}) ... public String dummy() { if (!sc.isCallerInRole("staff")) { throw RuntimeException("Not authorized"); } ... }
클라이언트 작성하기
이제 앞의 예제에서 살펴본 enterprise bean을 사용하는 클라이언트 자바 기술 프로그램을 작성해 보자. 다음은 클라이언트 코드의 단편이다. 샘플 패키지에서 전체 코드를 찾을 수 있다.
public class Client { private static @EJB Ping ping; private static @EJB Hello hello; public static void main(String arg[]) { System.out.println( "Calling Ping.pingPermitAll(): ... " + ping.pingPermitAll()); try { System.out.println( "Calling Ping.pingDenyAll(): ... " + ping.pingDenyAll()); ... try { System.out.println( "Calling Ping.ping(): ... " + ping.ping()); ... System.out.println("Calling Hello.hello(): ... " + hello.hello()); System.out.println("Calling Hello.ping(): .... " + hello.ping()); ...
클라이언트 프로그램은 보안이 지정되지 않은 것처럼 동일한 방식으로 enterprise bean에 액세스한다는 사실에 주목하기 바란다. 이 프로그램은 @EJB 주석을 사용하여 bean을 찾는다.
private static @EJB Ping ping; private static @EJB Hello hello;
그리고 일반적인 방식으로 enterprise bean 메소드를 호출한다.
hello.hello(); hello.ping()
배포 설명자에서 보안 정보 지정하기
보안 주석이 인증 및 권한 부여를 단순화하기는 하지만 배포 설명자에서 일부 보안 관련 정보를 지정해야 한다. 다행히도 주석을 사용하고 기본 설정에 의존하면 배포 설명자에 지정해야 하는 보안 관련 정보의 양은 크게 줄어든다. 권한 부여를 사용하는 애플리케이션의 경우 여전히 배포 설명자에 security-role-mapping을 설정해야 한다.
Java EE 환경은 권한 부여를 위한 역할을 사용한다. 하지만 많은 운영 체제 환경에서 사용자들은 그룹과 연관되어 있다. security-role-mapping은 사용자 역할 개념과 principal 또는 그룹 사이의 링크를 제공한다. 이 매핑을 통해 principal-name 또는 group-name을 role-name과 연관시킬 수 있다. Java EE 5 SDK의 썬 자바 시스템 애플리케이션 서버와 같은 Java EE 5 애플리케이션 서버 구현에서는 security-role-mapping을 sun-application.xml 파일에 정의한다. 다음은 그 예제이다.
<sun-application> <security-role-mapping> <role-name>ttrole</role-name> <group-name>ttgroup</group-name> </security-role-mapping> <security-role-mapping> <role-name>myrole</role-name> <principal-name>ttuser</principal-name> </security-role-mapping> <security-role-mapping> <role-name>staff</role-name> <principal-name>aprincipal</principal-name> </security-role-mapping> <security-role-mapping> <role-name>temporary</role-name> <principal-name>noone</principal-name> </security-role-mapping> </sun-application>
사용자는 애플리케이션에 사용된 각 역할에 대한 매핑을 정의해야 한다. @RunAs의 역할에서 sun-ejb-jar.xml에 principal이 정의되어 있지 않으면 애플리케이션 서버는 security-role-mapping의 principal을 사용한다. 다음은 HelloEjb enterprise bean에 대한 run-as principal을 sun-ejb-jar.xml 파일에 정의하는 예제이다.
<sun-ejb-jar> <enterprise-beans> <ejb> <ejb-name>HelloEjb</ejb-name> <principal> <name>aprincipal</name> </principal> </ejb> </enterprise-beans> </sun-ejb-jar>
@RolesAllowed 주석을 사용하는 경우에는 애플리케이션 서버가 배포 설명자에서 <ior-security-config> 요소에 대한 기본값을 제공한다. 기본 <ior-security-config> 요소에는 username_password의 <auth-method> 요소 값과 인증을 위한 기본 영역이 제공된다. sun-application.xml 파일에서 다음과 같이 <security-role-mapping> 요소 다음에 <realm> 요소를 추가하여 이를 사용자 정의할 수 있다.
<realm>file</realm>
샘플 코드 실행하기
- Java EE 5 SDK가 없으면 Java EE Downloads 페이지에서 Java EE 5 SDK를 다운로드하여 설치한다.
- 다음 환경 변수를 설정한다.
JAVEE_HOME.이 변수는 썬 자바 시스템 애플리케이션 서버의 설치 위치를 가리켜야 한다.
ANT_HOME.이 변수는 ant의 설치 위치를 가리켜야 한다. Ant는 Java EE 5 SDK에 포함된 썬 자바 시스템 애플리케이션 서버에 포함되어 있다. (Windows에서는lib\ant하위 디렉토리에 있음)
JAVA_HOME.이 변수는 사용자 시스템의 JDK 5.0 위치를 가리켜야 한다.
$JAVA_HOME/bin,$ANT_HOME/bin및$JAVAEE_HOME/bin을 사용자의PATH환경 변수에 추가한다.
- 팁에 대한 샘플 패키지를 다운로드하고 해당 컨텐츠의 압축을 푼다. 이제 압축이 풀린 디렉토리가
<sample_install_dir>/ejb-secann과 같이 나타난다. 여기서<sample_install_dir>는 샘플 패키지를 설치한 디렉토리이다. 예를 들어, Windows 시스템의C:\경로에 해당 컨텐츠의 압축을 풀었다면 새로 생성된 디렉토리는C:\ejb-secann이 되어야 한다.
ejb-secann디렉토리로 변경하고build.properties파일을 적절하게 편집한다. 예를 들어, admin 호스트가 원격인 경우admin.host의 값을 기본값(localhost)에서 적절한 원격 호스트로 변경한다. 또한 다음 등록 정보가 올바르게 지정되었는지 확인한다.
admin.user. 도메인을 시작 및 중지하는 관리자의 ID이다.
admin.port. 관리 서버의 http 포트 번호이다.
passwd파일에서AS_ADMIN_PASSWORD값을 관리자 비밀번호로 업데이트한다.AS_ADMIN_USERPASSWORD는 테스트를 위해 생성된 사용자의 비밀번호이다. 이 값을 변경하는 경우 실행 대상의 해당 값도 업데이트한다.
- 다음 명령을 입력하여 애플리케이션 서버를 시작한다.
<appserv_install>/bin/asadmin start-domain domain1
여기서<appsrv_install>은 애플리케이션 서버를 설치한 위치이다.
- 다음 명령을 입력하여 사용자(ttuser)를 애플리케이션 서버의 기본 영역에 생성한다.
ant create-user
- 샘플을 빌드하고 배포한다. 먼저 다음 명령을 입력한다.
ant build
그러면 enterprise bean 및 서블릿 웹 서비스 클래스가 컴파일되고 ear 파일이 생성된다.
그리고 다음 명령을 입력한다.ant deploy
그러면 ear 파일이 애플리케이션 서버에 배포된다.
- 클라이언트 애플리케이션을 실행하여 EJB에 액세스한다. 다음 명령을 입력한다.
ant run
다음과 같은 결과가 나타나야 한다.[exec] Calling Ping.pingPermitAll(): ...PingEjb: pingPermitAll[exec] Expected failure for any call of Ping.pingDenyAll()[exec] Expected failure for direct call of Ping.ping()[exec] Calling Hello.hello(): ... HelloEjb: hello[exec] Calling Hello.ping(): .... PingEjb: pingPing.ping()의 직접 호출은 실패할 것이다. 사용자ttuser는ttgroup그룹에 있으며 이 그룹은myrole및ttrole역할을 가지고 있고Ping.ping()메소드는 권한 부여를 위해staff역할을 필요로 하기 때문이다.
- 다음 명령을 입력하여 EJB ear 파일을 배포 해제할 수 있다.
ant undeploy
- 애플리케이션을 배포 해제한 후 다음 명령을 입력하여 테스트용 사용자를 제거한다.
ant delete-user
저자 정보
Shing Wai Chan은 썬 자바 시스템 애플리케이션 서버 및 Java EE SDK 개발 팀의 멤버입니다. 그는 지난 몇 년 동안 Java EE 보안에 관여해 왔습니다.
"Java EE" 카테고리의 다른 글
- Attach API (댓글 18개 / 트랙백 1개) 2007/09/03
- JSP 2.0 EXPRESSION LANGUAGE (댓글 1개 / 트랙백 0개) 2004/02/05
- 환경 엔트리를 이용해서 배포의 사용자 정의하기 (댓글 2개 / 트랙백 0개) 2003/12/24
- JAX-WS를 이용한 웹 서비스 개발 (댓글 1개 / 트랙백 0개) 2006/01/18
- EJB 2.1로 메시지 구동 빈 이용하기 (댓글 1개 / 트랙백 0개) 2005/05/18
- EclipseLink를 사용하여 JPA에서 반복 불가능한 읽기 방지 (댓글 0개 / 트랙백 1개) 2008/07/09
- 컴포넌트 시스템과 클래스 로더 경계 (댓글 1개 / 트랙백 0개) 2004/10/05
- JAX-WS Dispatch 및 Provider API를 이용한 문서 처리 (댓글 4개 / 트랙백 0개) 2006/09/15
- POJO를 Persistent Entity로 변환하기 (댓글 1개 / 트랙백 0개) 2005/12/27
- SAAJ 소개 (댓글 1개 / 트랙백 0개) 2005/06/08
댓글을 달아 주세요
자바는 알면 알수록 재미가 있어지네요. 좋은 자료 잘 활용하겠습니다.
2007/09/13 22:41좋은 정보 감사해요~
2007/09/19 03:28좋은 글,감사합니다
2007/09/19 13:24좋은 정보 감사합니다.
2007/09/19 23:11많이 배우고 가요~