오늘은 웹 서버에서 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. 서블릿 필터
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를 이용하여 커스텀 핸들러 어노테이션을 구현할 때에는 아래 사항에 특히 주의해야 합니다.
이전 글을 참조하여 동적으로 서블릿 필터 컴포넌트 인스턴스를 생성한 다음 서블릿 컨테이너에 필터를 등록.
7. 어노테이션 사용
@AppPermission("HelloWorldPermission")
public void helloworld() {
...
}
이렇게 어노테이션을 메소드 위에 박아주기만 하면, 권한 검사는 끝나게 되는거죠. 즐거운 개발~
아무튼 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에 넣었던 사용자 식별자를 뽑아냅니다.
- 사용자 식별자를 이용하여 허용된 권한 목록을 찾아내고, 지정된 퍼미션이 있는지 확인합니다.
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를 포함해야 함.
이전 글을 참조하여 동적으로 서블릿 필터 컴포넌트 인스턴스를 생성한 다음 서블릿 컨테이너에 필터를 등록.
7. 어노테이션 사용
@AppPermission("HelloWorldPermission")
public void helloworld() {
...
}
이렇게 어노테이션을 메소드 위에 박아주기만 하면, 권한 검사는 끝나게 되는거죠. 즐거운 개발~




덧글