주석에서 조언을 얻었고 두 번째 옵션을 구현했습니다. 이는 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 문서 (예 : "사용자 이름 또는 계정 이름으로 식별 된 사용자 본인")과 더 가깝습니다. JAASRealm
및 HttpServletRequest
위의 제한으로는 명확하게 중요 의한 계좌 식별자 (현재 세션 요청 및 응답에 대한 액세스를 갖는다)는 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가 테이블에서 벗어나거나 단일 사용자 교장을 사용하여 문제가 있음을 나타냅니다. 해당 중간 계층에 인터페이스가 없으므로 Subject
Principals
의 순서가 명확하게 설정됩니다. 사용자 교장이 JAASRealm
에 의해 잘못된 형식으로 해석 될 수있는 잠재적 보안 취약성을 예상 할 수 있습니다. 이는 예상 된 순서대로 반환 되었기 때문입니다. 이 문제로부터 보호하려면 commit
동안 Subject
에 선언 된 사용자 유형 중 하나만 Principal
을 추가해야하며 여러 사용자 클래스 이름을 피해야합니다.
따라서 위의 모든 문서에 따르면 JAAS를 충실하게 따르지 않기 때문에 옵션 2의 경우 JAASRealm
을 사용하지 않을 것입니다. 이로 인해 순수한 ServletFilter
접근 방식으로 되돌아갑니다.
이제 javax.security.auth.Subject에는 권한 부여에 필요한 모든 항목 (여러 사용자 주체, 역할 및 ACL 그룹)이 포함되어 있습니다. 불행히도이 클래스는 부분적으로 만 직렬화 가능하므로 클래스를 Principal
으로 감싸서 반환 할 수는 없습니다.
스프링의 DefaultJaasAuthenticationProvider을 만족 시키려면 을 역할 이름에 매핑하려면 AuthorityGranter을 구현해야했기 때문에 매핑 수행 방법을 완전히 제어 할 수있었습니다.
AuthorityGranter
은 내 ServletFilter
에서 사용할 수 없지만 (해당 webapp는 Spring 프레임 워크에 의존하지 않습니다.) 스프링 이외의 웹 응용 프로그램에 대한 매핑 역할은 비슷합니다. 일시적으로 HttpServletRequestWrapper를 사용하여 세션 속성 (인증 중에 세션에 저장 됨)에서 Principal 및 Roles를 읽고 getUserPrincipal 및 isUserInRole을 무시합니다. 궁극적으로 JAASRealm을 테스트하여이 부분을 처리 할 수 있는지 확인 하겠지만 아직 그다지 빠르지는 않습니다.
'SubjectIdentifier'를 동일한 'Subject'와 연결된 별도의 'Principal'으로 구현하는 것은 JAAS API에 의해 암시 된 메커니즘으로 표준 JAA API 자체가 표준 정보 보안 개념과 용어로 직접 모델링됩니다. 사용자를 성공적으로 인증하면 사용할 수있는 모든 'Principal'과 관련된 'Subject'를 채워야합니다. –