좋아요, 그러니 하루 반 정도 작업 한 후에 알아 냈습니다.
내 원래 접근 방식은 ActiveDirectoryLdapAuthenticationProvider
클래스를 확장하고 그 loadUserAuthorities()
메서드를 재정 의하여 인증 된 사용자의 사용 권한을 사용자 정의하는 것이 었습니다. 당연한 이유로, ActiveDirectoryLdapAuthenticationProvider
클래스는 final
으로 지정되어 있으므로 확장 할 수 없습니다.
는 다행히, 오픈 소스 해킹을 제공한다 (그 클래스의 슈퍼 클래스는 하지final
있습니다) 그래서 간단하게 따라 패키지와 클래스 참조를, 그것의 전체 내용을 복사 한 final
지정을 제거하고 조정. 나는이 클래스의 코드를 편집하지 않았다. 편집 할 필요가 없다는 눈에 잘 띄는 주석을 추가했다. 그 다음이 클래스를 OverrideActiveDirectoryLdapAuthenticationProvider
으로 확장했습니다.이 파일은 ldap.xml
파일에서도 참조되었으며 loadUserAuthorities
에 대한 재정의 메서드가 추가되었습니다. 이러한 모든 기능은 격리 된 가상 서버의 암호화되지 않은 세션에서 단순한 LDAP 바인딩을 사용하여 효과적이었습니다.
실제 네트워크 환경에서는 모든 LDAP 쿼리가 TLS 핸드 셰이크로 시작해야하지만 쿼리되는 서버는 PDC가 아니며 이름은 'sub.domain.tld'이지만 사용자는 적절하게 인증됩니다 'domain.tld' 또한 바인딩하려면 사용자 이름 앞에 'NT_DOMAIN \'이 와야합니다. 이 모든 작업은 커스터마이징 작업을 필요로했으며 불행히도 어디서나 거의 도움이되지 않았습니다.
그래서 여기가 OverrideActiveDirectoryLdapAuthenticationProvider
에 더 재 지정을 포함 모두의 preposterously 간단한 변경입니다 :
입니다
@Override
protected DirContext bindAsUser(String username, String password) {
final String bindUrl = url; //super reference
Hashtable<String,String> env = new Hashtable<String,String>();
env.put(Context.SECURITY_AUTHENTICATION, "simple");
//String bindPrincipal = createBindPrincipal(username);
String bindPrincipal = "NT_DOMAIN\\" + username; //the bindPrincipal() method builds the principal name incorrectly
env.put(Context.SECURITY_PRINCIPAL, bindPrincipal);
env.put(Context.PROVIDER_URL, bindUrl);
env.put(Context.SECURITY_CREDENTIALS, password);
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxtFactory");
//and finally, this simple addition
env.put(Context.SECURITY_PROTOCOL, "tls");
//. . . try/catch portion left alone
}
, 나는이 방법에게 한 모두가 bindPrincipal
문자열이 포맷 된 방식을 변경했다, 나는 추가 해시 테이블의 키/값
내 ldap.xml
에 전달 되었기 때문에 domain
매개 변수에서 내 클래스로 전달 된 하위 도메인을 제거 할 필요가 없었습니다.
@Override
protected DirContextOperations searchForUser(DirContext ctx, String username) throws NamingException {
SearchControls searchCtls = new SearchControls();
searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
//this doesn't work, and I'm not sure exactly what the value of the parameter {0} is
//String searchFilter = "(&(objectClass=user)(userPrincipalName={0}))";
String searchFilter = "(&(objectClass=user)(userPrincipalName=" + username + "@domain.tld))";
final String bindPrincipal = createBindPrincipal(username);
String searchRoot = rootDn != null ? rootDn : searchRootFromPrincipal(bindPrincipal);
return SpringSecurityLdapTemplate.searchForSingleEntryInternal(ctx, searchCtls, searchRoot, searchFilter, new Object[]{bindPrincipal});
마지막 변화가 제대로 (내 목적을 위해) 문자열을 구축하려면 createBindPrincipal()
방법이었다 : 나는 단순히 내가 OverrideActiveDirectoryLdapAuthenticationProvider
에 searchForUser()
방법을 변경 <constructor-arg value="domain.tld"/>
다음
거기 매개 변수 을 변경 : 여전히 내 테스트 및 headdesking 모두에서 정리 필요 - -
@Override String createBindPrincipal(String username) { if (domain == null || username.toLowerCase().endsWith(domain)) { return username; } return "NT_DOMAIN\\" + username; }
그리고 위의 변경과
가 나는 결합 할 수 있었다 네트워크에서 Active Directory에 대해 본인임을 인증하고, 원하는 모든 사용자 개체 필드를 캡처하고, 그룹 구성원을 식별합니다.오, 분명히 TLS에는 'ldaps : //'가 필요하지 않으므로 내 ldap.xml
ldap://192.168.0.3:389
입니다.
TL; DR :
은 TLS를 활성화하려면,의 final
지정을 제거 할 사용자 정의 클래스에 확장, 환경의 해시 테이블에 env.put(Context.SECURITY_PROTOCOL, "tls");
을 추가하여 bindAsUser()
를 오버라이드 (override), 봄의 ActiveDirectoryLdapAuthenticationProvider
클래스를 복사합니다. 그게 전부 야. 바인드 사용자 이름, 도메인 및 LDAP 쿼리 문자열을보다 자세히 제어하려면 적용 가능한 방법을 적절하게 재정의하십시오. 내 경우에는 {0}
의 값을 식별 할 수 없으므로 완전히 제거하고 전달 된 username
문자열을 대신 삽입했습니다.
바라기를, 누군가가 도움이 될 것으로 기대합니다.