0

我有一个doLogin()从 JSF 页面调用的 Java 方法,该页面从用户那里获取一个 id ( String netId) 和密码 ( String password)。使用Active Directory 登录中的主体doLogin()启动身份验证。netId之后,我想从保护我的应用程序的目录中获取除主体名称之外的其他属性。

我的安全性在容器中配置并且它可以工作,这样

HttpSession ses = FacesContext.getCurrentInstance().getExternalContext().getSession (false);
HttpServletRequest req = FacesContext.getCurrentInstance().getExternalContext().getRequest();

req.login(netID, password);

成功并且

req.getUserPrincipal().getName();

返回用户的netID. 但是,我的应用程序netId仅用于身份验证。访问另一个数据库的应用程序的其他部分需要其他属性(commonName例如)。我想做类似的事情

usefulLDAPobj = *getLDAPSession from "somewhere" in the HTTP Session, the FacesContext or some other available object*

String cn = usefulLDAPobj.getAttributeFromProfile ("cn");

ses.setAttribute("username", cn);

从那时起,在我的 Hibernate ORM 中使用存储在会话中的用户名。

我知道头脑简单的usefulLDAPobj.getAttributeFromProfile ("cn")人会更复杂,但如果我能找到一个让我访问 LDAP 目录的起点,我可以填写它。

由于容器设置了明显的 LDAP 连接,我觉得必须有一种方法可以让我使用它,而不必以编程方式手动构建 LdapContext;这将要求代码知道server / bind-DN / bind-password configurationWeb 服务器(JBoss EAP 6.2)已经知道的所有 LDAP(来自<login-module>定义在 中standalone.xml)。例如,方法喜欢getUserPrincipal()并且isUserInRole()需要访问我想要访问的同一个目录配置文件。

所以我的问题是:有没有办法从 FacesContext 或 HTTPServletRequest 或任何可从 HTTPServlet 访问的对象获取 LDAP 连接或上下文?

4

2 回答 2

0

What is the easiest way to get an LdapConext from a FacesConext?

There isn't a way at all, let alone an easy way. JSF doesn't assume the presence of an LDAP server, and doesn't provide any LDAP-related APIs.

Since there is an obvious LDAP connection being set up by the container

When you logged in. Not permanently. If there was an LDAP server at all. And JSF doesn't know how the container logged you in.

I feel there must be a way ...

There isn't.

于 2015-04-06T21:52:20.567 回答
0

我认为这个问题的一个有用答案是没有办法LDAPContext直接从FacesContextPrincipalHttpServletRequestFacesContext.

我将把我的解决方案的详细信息放在这里,因为即使它与它没有直接关系,FacesContext它也给了我在问题正文中所要求的内容,这是一种从 LDAP 配置文件中获取额外用户数据同时避免需要的方法创造一个整体分开LDAPContext

我特别想要的是CN,我能够在DN不进行额外搜索的情况下将其解析出来。如果我需要任何其他数据,我假设我可以ctxfindUserDN()下面使用它。

我想我正在使我的应用程序依赖于JBoss这个解决方案,如果这是不可取的,我会搜索一个JBoss独立的登录模块类来扩展(不知道这是否容易、困难或不可能)。

这是我的解决方案:

  1. 在 AdvancedADLoginModule 中覆盖 findUserDN (LdapContext ctx)

    package ca.mycompany.myapp.jboss;
    
    import java.security.Principal;
    
    import javax.naming.ldap.LdapContext;
    import javax.security.auth.login.LoginException;
    
    import org.jboss.security.negotiation.AdvancedADLoginModule;
    
    public class NameFetchingADLoginModule extends AdvancedADLoginModule
    
        @Override
        protected String findUserDN(LdapContext ctx) throws LoginException
        {
            String lclUserDN = super.findUserDN(ctx);
    
            Principal principal = getIdentity();
    
            if (principal instanceof PrincipalWithDisplayName)
            {
                String displayName = lclUserDN.substring(3, lclUserDN.indexOf(','));
                ((PrincipalWithDisplayName) principal).setDisplayName (displayName);
            }
    
            return lclUserDN;
        }
    }
    
  2. 扩展 Principal 以提供 displayName 属性

    package ca.mycompany.myapp.jboss;
    
    import java.io.Serializable;
    import java.security.Principal;
    
    public class PrincipalWithDisplayName implements Serializable, Principal
    {
        private static final long serialVersionUID = 1L;
        private final String name;
    
        // additional attribute provided by this subclass
        private String displayName;
    
        public PrincipalWithDisplayName(final String name) {
            this.name = name;
        }
    
        // new and overriding getters and setters, equals() and hashCode() removed for brevity
    }
    
  3. 在 doLogin() 方法中使用新的登录模块和 Principal

片段:

    String displayName = "";
    HttpSession ses = FacesContext.getCurrentInstance().getExternalContext().getSession (false);
    HttpServletRequest req = FacesContext.getCurrentInstance().getExternalContext().getRequest();

    try {           
        req.login(userName, password); // this throws an exception if authentication fails

        Principal lclUser = req.getUserPrincipal();
        if (lclUser instanceof PrincipalWithDisplayName)
        {
            displayName = ((PrincipalWithDisplayName) lclUser).getDisplayName ();
        }

        // get Http Session and store username
        //
        HttpSession session = HttpUtil.getSession();
        sess.setAttribute("username", displayName);
        ...
  1. 配置JBoss EAP 6.2, in standalone.xml, 以使用新的类

片段:

<subsystem xmlns="urn:jboss:domain:security:1.2">
    <security-domains>
        <security-domain name="company_ad" cache-type="default">
            <authentication>
                <login-module code="ca.mycompany.myapp.jboss.NameFetchingADLoginModule" flag="required">
                    <module-option name="java.naming.factory.initial" value="com.sun.jndi.ldap.LdapCtxFactory"/>
                    <module-option name="java.naming.provider.url" value="ldap://servernm.mycompany.tst:389"/>
                    <module-option name="java.naming.security.authentication" value="simple"/>
                    <module-option name="bindDN" value="CN=AuthGuy,OU=Accounts,OU=Company User Accounts,DC=company,DC=tst"/>
                    <module-option name="bindCredential" value="Snowden1"/>
                    <module-option name="baseCtxDN" value="OU=Company User Accounts,DC=company,DC=tst"/>
                    <module-option name="baseFilter" value="(sAMnetID={0})"/>
                    <module-option name="searchScope" value="SUBTREE_SCOPE"/>
                    <module-option name="allowEmptyPassword" value="false"/>
                    <module-option name="rolesCtxDN" value="OU=Company User Accounts,DC=company,DC=tst"/>
                    <module-option name="roleFilter" value="(sAMAccountName={0})"/>
                    <module-option name="roleAttributeID" value="memberOf"/>
                    <module-option name="roleAttributeIsDN" value="true"/>
                    <module-option name="roleNameAttributeID" value="cn"/>
                    <module-option name="recurseRoles" value="1"/>
                    <module-option name="principalClass" value="ca.mycompany.myapp.jboss.PrincipalWithDisplayName"/>
                </login-module>
            </authentication>
        </security-domain>
    </security-domains>
</subsystem>
于 2015-04-07T19:32:58.003 回答