iPOJO를 이용한 선언적 권한 관리 학술

오늘은 웹 서버에서 JSON 메소드까지 이어지는 폼 인증과 권한 관리를 구현했는데 방법을 간단히 정리해둡니다. 그런데 아마 OSGi 환경에서 Jetty 등을 붙여서 굴려보는 경우는 아직 없을테니 크라켄을 쓰지 않는 이상 아래 사항을 실제 구현해보긴 어려울 것 같군요.. (게다가 OSGi Compendium에 정의된 HTTP Service 스펙은 백만년전 서블릿 스펙 기준이라 매우 썩..)

아무튼 iPOJO 환경에서 어노테이션을 실제로 어떻게 만들어 활용하는지 파악하는데 도움이 될 듯. JPA로 트랜잭션 어노테이션 붙일 때도 같은 방법을 썼습니다. 그러나 설명을 불친절하게 해놔서.. iPOJO 기반 지식이 없으면 이해하시는데 어려움이 많을 듯.. 역시 나중에 시간 나면..

1. 퍼미션 어노테이션 구현

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AppPermission {
    String value();
}

2. 퍼미션 점검 인터페이스 추가

public interface AppPermissionChecker {
    boolean isAllowed(String permission);
}

3. 서블릿 필터
  • javax.servlet.Filter / AppPermissionChecker 인터페이스를 구현한 접근 권한 제어기..
  • HttpServletRequest에서 getSession(true)를 호출하여 세션을 얻어냅니다.
  • 세션에 사용자 식별자가 없으면 로그인 페이지로 리다이렉트합니다.
  • 세션에 사용자 식별자가 있으면 ThreadLocal에 식별자를 저장하고, filterChain.doFilter()를 호출하여 계속 진행합니다.
  • 퍼미션 점검 인터페이스 (AppPermissionChecker) 구현하면서 ThreadLocal에 넣었던 사용자 식별자를 뽑아냅니다.
  • 사용자 식별자를 이용하여 허용된 권한 목록을 찾아내고, 지정된 퍼미션이 있는지 확인합니다.
4. iPOJO 핸들러 구현

iPOJO 1.2.0에서 지원하는 메타데이터에 아직 어노테이션이 없으므로 좀 난잡하게 어노테이션 정보를 뽑아내고, InstanceManager.register()를 호출해서 콜백이 걸리도록 합니다.

AppPermissionChecker가 iPOJO에 의해 인젝트 된다는 점을 주목..
(뒷부분의 메타데이터 설정 참조)

import org.apache.felix.ipojo.ConfigurationException;
import org.apache.felix.ipojo.PrimitiveHandler;
import org.apache.felix.ipojo.metadata.Element;
import org.apache.felix.ipojo.parser.MethodMetadata;

public class AppPermissionHandler extends PrimitiveHandler {
    private Map<String, String> methodPermissionMap = new ConcurrentHashMap<String, String>();
    private AppPermissionChecker checker;
   
    @Override
    public void configure(Element metadata, Dictionary configuration)
            throws ConfigurationException {
        Object o = getInstanceManager().getPojoObject();
        for (Method m : o.getClass().getDeclaredMethods()) {
            AppPermission perm = m.getAnnotation(AppPermission.class);
            if (perm != null) {
                MethodMetadata mm = getPojoMetadata().getMethod(m.getName());
                if (mm != null) {
                    methodPermissionMap.put(m.getName(), perm.value());
                    getInstanceManager().register(mm, this);
                }
            }
        }
    }

    @Override
    public void start() {
    }

    @Override
    public void stop() {
    }

    @Override
    public void onEntry(Object pojo, Method method, Object[] args) {
        String permissionName = methodPermissionMap.get(method.getName());
        if (checker.isAllowed(permissionName) == false) {
            throw new SecurityException(method + " " + permissionName);
        }
    }

5. iPOJO 핸들러 메타데이터 기입

<ipojo xmlns:perm="com.example.handler">
...핸들러 메타데이터 부분...
    <handler className="com.example.handler.AppPermissionHandler"
        name="apppermission" namespace="com.example.handler">
        <requires field="checker" />
    </handler>
...서블릿 필터 컴포넌트 정의..
    <component className="com.example.handler.AccessControlFilter">
        <provides />
    </component>
...AppPermission을 사용하는 컴포넌트의 정의...
    <component classname="com.example.ExampleComponent"
        immediate="true" architecture="true">
        <provides />
        <perm:AppPermission />
    </component>
</ipojo>

iPOJO를 이용하여 커스텀 핸들러 어노테이션을 구현할 때에는 아래 사항에 특히 주의해야 합니다.
  • 어노테이션이 속한 패키지는 메타데이터에 정의한 핸들러의 네임스페이스 속성과 일치해야 함.
  • 어노테이션 이름은 메타데이터에 정의한 핸들러의 이름 속성과 일치해야 함.
  • 패키지 이름은 반드시 ipojo나 handler를 포함해야 함.
6. 서블릿 필터 등록

이전 글을 참조하여 동적으로 서블릿 필터 컴포넌트 인스턴스를 생성한 다음 서블릿 컨테이너에 필터를 등록.

7. 어노테이션 사용

@AppPermission("HelloWorldPermission")
public void helloworld() {
...
}

이렇게 어노테이션을 메소드 위에 박아주기만 하면, 권한 검사는 끝나게 되는거죠. 즐거운 개발~

트랙백

이 글과 관련된 글 쓰기 (트랙백 보내기)
TrackbackURL : http://www.xeraph.com/tb/4916570 [도움말]

덧글

댓글 입력 영역