我曾遇到过与我相同的经历,最后写了一个自定义身份验证提供程序,该程序对Active Directory服务器执行LDAP查询。
因此,与安全性相关的bean是:
<beans:bean id="contextSource" > <beans:constructor-arg value="ldap://hostname.queso.com:389/" /></beans:bean><beans:bean id="ldapAuthenticationProvider" > <beans:property name="authenticator" ref="ldapAuthenticator" /> <custom-authentication-provider /></beans:bean><beans:bean id="ldapAuthenticator" > <beans:property name="contextFactory" ref="contextSource" /> <beans:property name="principalPrefix" value="QUESO" /></beans:bean>
然后是LdapAuthenticationProvider类:
public class LdapAuthenticationProvider implements AuthenticationProvider { private LdapAuthenticator authenticator; public Authentication authenticate(Authentication auth) throws AuthenticationException { // Authenticate, using the passed-in credentials. DirContextOperations authAdapter = authenticator.authenticate(auth); // Creating an LdapAuthenticationToken (rather than using the existing Authentication // object) allows us to add the already-created LDAP context for our app to use later. LdapAuthenticationToken ldapAuth = new LdapAuthenticationToken(auth, "ROLE_USER"); InitialLdapContext ldapContext = (InitialLdapContext) authAdapter .getObjectAttribute("ldapContext"); if (ldapContext != null) { ldapAuth.setContext(ldapContext); } return ldapAuth; } public boolean supports(Class clazz) { return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(clazz)); } public LdapAuthenticator getAuthenticator() { return authenticator; } public void setAuthenticator(LdapAuthenticator authenticator) { this.authenticator = authenticator; }}
然后是LdapAuthenticatorImpl类:
public class LdapAuthenticatorImpl implements LdapAuthenticator { private DefaultSpringSecurityContextSource contextFactory; private String principalPrefix = ""; public DirContextOperations authenticate(Authentication authentication) { // Grab the username and password out of the authentication object. String principal = principalPrefix + authentication.getName(); String password = ""; if (authentication.getCredentials() != null) { password = authentication.getCredentials().toString(); } // If we have a valid username and password, try to authenticate. if (!("".equals(principal.trim())) && !("".equals(password.trim()))) { InitialLdapContext ldapContext = (InitialLdapContext) contextFactory .getReadWriteContext(principal, password); // We need to pass the context back out, so that the auth provider can add it to the // Authentication object. DirContextOperations authAdapter = new DirContextAdapter(); authAdapter.addAttributevalue("ldapContext", ldapContext); return authAdapter; } else { throw new BadCredentialsException("Blank username and/or password!"); } } static public InitialLdapContext recreateLdapContext(LdapAuthenticator authenticator, LdapAuthenticationToken auth) { DirContextOperations authAdapter = authenticator.authenticate(auth); InitialLdapContext context = (InitialLdapContext) authAdapter .getObjectAttribute("ldapContext"); auth.setContext(context); return context; } public DefaultSpringSecurityContextSource getContextFactory() { return contextFactory; } public void setContextFactory(DefaultSpringSecurityContextSource contextFactory) { this.contextFactory = contextFactory; } public String getPrincipalPrefix() { return principalPrefix; } public void setPrincipalPrefix(String principalPrefix) { if (principalPrefix != null) { this.principalPrefix = principalPrefix; } else { this.principalPrefix = ""; } }}
最后,LdapAuthenticationToken类:
public class LdapAuthenticationToken extends AbstractAuthenticationToken { private static final long serialVersionUID = -5040340622950665401L; private Authentication auth; transient private InitialLdapContext context; private List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>(); public LdapAuthenticationToken(Authentication auth, GrantedAuthority defaultAuthority) { this.auth = auth; if (auth.getAuthorities() != null) { this.authorities.addAll(Arrays.asList(auth.getAuthorities())); } if (defaultAuthority != null) { this.authorities.add(defaultAuthority); } super.setAuthenticated(true); } public LdapAuthenticationToken(Authentication auth, String defaultAuthority) { this(auth, new GrantedAuthorityImpl(defaultAuthority)); } public GrantedAuthority[] getAuthorities() { GrantedAuthority[] authoritiesArray = this.authorities.toArray(new GrantedAuthority[0]); return authoritiesArray; } public void addAuthority(GrantedAuthority authority) { this.authorities.add(authority); } public Object getCredentials() { return auth.getCredentials(); } public Object getPrincipal() { return auth.getPrincipal(); } public InitialLdapContext getContext() { return context; } public void setContext(InitialLdapContext context) { this.context = context; }}
您会注意到其中可能有一些不需要的地方。
例如,我的应用程序需要保留成功登录的LDAP上下文,以供用户登录后进一步使用-
该应用程序的目的是让用户通过其AD凭据登录,然后执行更多与AD相关的功能。因此,因此,我有一个自定义的身份验证令牌LdapAuthenticationToken可以传递(而不是Spring的默认身份验证令牌),它允许我附加LDAP上下文。在LdapAuthenticationProvider.authenticate()中,我创建该令牌并将其传递回去。在LdapAuthenticatorImpl.authenticate()中,我将登录的上下文附加到返回对象,以便可以将其添加到用户的Spring认证对象中。
另外,在LdapAuthenticationProvider.authenticate()中,我为所有登录的用户分配了ROLE_USER角色,这就是让我在我的URL元素中测试该角色的原因。您将要使其与要测试的角色匹配,甚至根据Active
Directory组或其他角色分配角色。
最后,这是必然的结果,我实现LdapAuthenticationProvider.authenticate()的方式为具有有效AD帐户的所有用户提供了相同的ROLE_USER角色。显然,在这种方法中,可以对用户进行进一步的测试(即是在一个特定的AD组的用户?)和分配角色这种方式,或者甚至在授予用户访问之前的一些条件,甚至测试
所有 。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)