如何使用Spring Security对Active Directory服务器进行身份验证?

如何使用Spring Security对Active Directory服务器进行身份验证?,第1张

如何使用Spring Security对Active Directory服务器进行身份验证?

我曾遇到过与我相同的经历,最后写了一个自定义身份验证提供程序,该程序对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组的用户?)和分配角色这种方式,或者甚至在授予用户访问之前的一些条件,甚至测试
所有



欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5565342.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-14
下一篇 2022-12-14

发表评论

登录后才能评论

评论列表(0条)

保存