2017-10-25 12 views
1

스프링 4와 Struts 2.3에서 잘 작동하는 JAAS LoginModule을 구현했습니다. 이 LoginModule은 Tomcat 8.0/8.5의 ServletFilter을 통해 호출되어 Spring 프레임 워크 외부의 서블릿에 대한 요청을 인증하고 권한을 부여합니다.JAAS 로그인 모듈의 사용자 주체 - 별도의 주체 또는 Bean 속성으로 추가 속성?

LoginModulejava.security.acl.Group의 간단한 구현을 사용하며 간단한 구현 인 java.security.Principal으로 사용자와 역할을 구분합니다. "간단하다"는 말은 인터페이스를 만족시키는 최소한의 구현을 의미합니다.

"사용자"구현은 name 속성을 고유 한 사용자 이름 (실제로 전자 메일 주소)으로 매핑합니다. 전자 메일 주소는 고유하지만 변경할 수 있으므로 계정 데이터베이스에는 그룹, 역할 할당 및 서비스 요청 기록 (사용자 익명화)에 사용되는 고유 한 계정 식별자 (GUID)가 포함되어 있습니다. 내 모델에는 AccountIdentifier에 자체 클래스가 있습니다. 본질적으로 두 개의 고유 한 계정 식별자가 있지만 인증을 위해 전자 메일 주소를 LoginModule에 제공해야하므로 User Principal의 기반이되었습니다.

계정 식별자는 현재 LoginModuleSubject으로 전달되고 있지 않지만 지금은 서비스 요청을 기록하기 위해 필요합니다.

은 내가 Subject를 통해 사용할 수있는 계정 ID를 만드는 두 가지 방법으로 앞으로 볼 수 있지만 나는 최고의 JAAS를위한 연습이다 불확실입니다 :에 "accountIdentifier을 포함 Principal 구현 나의 현재의"사용자 "를 확장

  1. "속성은 LoginModule.commit() 동안 설정됩니다.
  2. LoginModule.commit() 중에 Subject에 추가되는 Principal으로 AccountIdentifier을 구현하십시오.

첫 번째 옵션은 가장 쉽지만 계정에서 개인 식별 정보를 분리하는 목적을 상쇄하는 것처럼 보입니다.

"사용자"(전자 메일 주소가 포함 된) 주체를 제목에 추가해야합니까?

+1

'SubjectIdentifier'를 동일한 'Subject'와 연결된 별도의 'Principal'으로 구현하는 것은 JAAS API에 의해 암시 된 메커니즘으로 표준 JAA API 자체가 표준 정보 보안 개념과 용어로 직접 모델링됩니다. 사용자를 성공적으로 인증하면 사용할 수있는 모든 'Principal'과 관련된 'Subject'를 채워야합니다. –

답변

1

주석에서 조언을 얻었고 두 번째 옵션을 구현했습니다. 이는 JAAS를 구현하는 방법에 동의합니다.

그러나 일단 변경을 수행하면 Spring, Tomcat 및 Servlet API에 내재 된 몇 가지 제한 사항과 비 호환성을 발견했습니다. 전통과 마찬가지로 썬은 문제에 대한 80 %의 해결책을 만들어 나머지를 독자에게 연습으로 남겨 둡니다.

본인의 대답을 원래 질문에 대한 포괄적 인 답변으로 문서화하기 위해 사용하고 있습니다.

Tomcat 8.5 JAAS Realm 문서 상태 :

JAASRealm를 사용하여 개발자에게 Tomcat의 CMA와 실질적으로 생각할 수있는 모든 보안 영역을 결합 할 수있는 기능을 제공합니다.다음

상태로 진행 ​​: Tomcat이 알 수 있도록 javax.security.Principal을 확장, JAAS에 지정되지 않지만 사용자 및 역할 구분에

, 당신은 별도의 클래스를 생성해야하는 주체 로그인 모듈에서 반환 된 사용자와 역할은 무엇입니까 ( org.apache.catalina.realm.JAASRealm 참조). 관계없이 반환 된 첫 번째 사용자는 이며 사용자는 Principal으로 처리되는 항상입니다. 이 문서는 문구 "주 사용자"를 사용하는

참고. 따라서 사용자와 역할을 javax.security.Principal (위에서 권장 한대로) 확장하는 고유 한 클래스로 구현했지만 즉시 반환 할 단일 사용자 만 허용하는 HttpServletRequest.getUserPrincipal()에 의해 시행되는 내장 제한이 발생했습니다. :

현재 인증 된 사용자의 이름을 포함하는 javax.security.Principal 개체를 반환합니다. 사용자가 인증되지 않은 경우 메서드는 null을 반환합니다.

위 문서의 엄격한 읽기

는 "... 현재 인증 된 사용자의 이름"을 을 포함해야하지만, 내 원래의 목표를 충족시키기 위해, 나는 "으로 이것을 해석하고 있다고 주장한다. .. 인증 된 주체의 이름 또는 식별자 ". 이는 com.sun.security.auth.UserPrincipal 문서 (예 : "사용자 이름 또는 계정 이름으로 식별 된 사용자 본인")과 더 가깝습니다.

JAASRealmHttpServletRequest 위의 제한으로는 명확하게 중요 의한 계좌 식별자 (현재 세션 요청 및 응답에 대한 액세스를 갖는다)는 ServletFilter 통해 요청에 전달 될 경우, 그것은 반드시 그 첫 번째 Principal에 포함되어야합니다 (원래 질문의 옵션 1은이 요구 사항을 충족 시키거나 옵션 2가 먼저 나타나고 원래 사용자 이름은 필요하지 않은 경우에만 옵션 2를 충족시킵니다). 나는 내가 정말로 필요로하는 것은 계정 식별자이므로 지금 내가 두 번째 옵션 인 "EmailAddressPrincipal"을 MyLoginModule에 건네고 Subject을 통해 다시 "AccountIdentifierPrincipal"을 받는다. (즉, MyLogin.commit()은 " AccountIdentifierPrincipal "을 첫 번째 주체로 사용하면 백킹 컬렉션은 주인의 순서를 유지해야합니다.) Subject.getPrincipals에 의해 반환 된 교장을 통해이 영역의 반복으로

(:

JAASRealm 문서는 어떤 섹션에 당신이 읽고, 실제로 교장의 정확한 순서에 관한 약간 모순 달려있다 이 "사용자 클래스"목록과이 사용자의 사용자로 일치하는 첫 번째 사용자를 식별합니다.

반환되는 첫 번째 사용자는 항상 사용자 사용자로 처리됩니다.

기본적으로 내가 만들려고하면 무엇을하고 있는지 JAASRealm 모방, 인증이 같이 것이라는 ServletFilter :

final LoginContext loginContext = new LoginContext(MyLoginModule.JAAS_REALM, new DefaultCallbackHandler(username, password)); 
loginContext.login(); 
final Subject subject = loginContext.getSubject(); 
request.getSession().setAttribute("AUTH_USER_PRINCIPAL", subject.getPrincipals(AccountIdentifierPrincipal.class).iterator().next()); 
request.getSession().setAttribute("AUTH_ROLE_PRINCIPALS", subject.getPrincipals(MyRolePrincipal.class)); 

불행하게도,이 javax.security.auth.Subject의 생성자와 직접 충돌하는 이는 java.util.Set이 주체의 백업 컬렉션으로 사용되도록 요구합니다. 또한, Set.iterator() 문서 상태 :

요소는 특별한 순서없이 반환됩니다 (세트가 보증을 제공하는 클래스의 인스턴스가 아닌 경우).

우리가 Subject에있는 최초의 액세스는 불행하게도 LoginContext의 내부 어딘가에 호출 뭔가를있는 LoginModule.initialize() 방법이다 (나는 생각한다). 즉 Principals에 대한 후원 컬렉션으로 사용되는 Set의 정확한 하위 클래스를 제어 할 수 없으므로 해당 주문을 제어 할 수 없습니다. 이 시간이 ServletFilter에 도착할 때까지는 SynchronizedSet이므로 원래 클래스가 무엇인지, 또는 순서 재 지정이 발생했는지 여부는 분명하지 않습니다.

이 모두가 JAASRealm이 예상대로 작동하기 위해 옵션 2가 테이블에서 벗어나거나 단일 사용자 교장을 사용하여 문제가 있음을 나타냅니다. 해당 중간 계층에 인터페이스가 없으므로 SubjectPrincipals의 순서가 명확하게 설정됩니다. 사용자 교장이 JAASRealm에 의해 잘못된 형식으로 해석 될 수있는 잠재적 보안 취약성을 예상 할 수 있습니다. 이는 예상 된 순서대로 반환 되었기 때문입니다. 이 문제로부터 보호하려면 commit 동안 Subject에 선언 된 사용자 유형 중 하나만 Principal을 추가해야하며 여러 사용자 클래스 이름을 피해야합니다.

따라서 위의 모든 문서에 따르면 JAAS를 충실하게 따르지 않기 때문에 옵션 2의 경우 JAASRealm을 사용하지 않을 것입니다. 이로 인해 순수한 ServletFilter 접근 방식으로 되돌아갑니다.

이제 javax.security.auth.Subject에는 권한 부여에 필요한 모든 항목 (여러 사용자 주체, 역할 및 ACL 그룹)이 포함되어 있습니다. 불행히도이 클래스는 부분적으로 만 직렬화 가능하므로 클래스를 Principal으로 감싸서 반환 할 수는 없습니다.

스프링의 DefaultJaasAuthenticationProvider을 만족 시키려면 을 역할 이름에 매핑하려면 AuthorityGranter을 구현해야했기 때문에 매핑 수행 방법을 완전히 제어 할 수있었습니다.

AuthorityGranter은 내 ServletFilter에서 사용할 수 없지만 (해당 webapp는 Spring 프레임 워크에 의존하지 않습니다.) 스프링 이외의 웹 응용 프로그램에 대한 매핑 역할은 비슷합니다. 일시적으로 HttpServletRequestWrapper를 사용하여 세션 속성 (인증 중에 세션에 저장 됨)에서 Principal 및 Roles를 읽고 getUserPrincipalisUserInRole을 무시합니다. 궁극적으로 JAASRealm을 테스트하여이 부분을 처리 할 수 ​​있는지 확인 하겠지만 아직 그다지 빠르지는 않습니다.