【问题标题】:What is the easiest way to get an LDAPContext from a FacesContext?从 FacesContext 获取 LDAPContext 的最简单方法是什么?
【发布时间】:2015-04-06 19:48:21
【问题描述】:

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

我的安全性已在容器中配置并且可以正常工作,因此

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;这将要求代码知道 Web 服务器(JBoss EAP 6.2)已经知道的所有 LDAP server / bind-DN / bind-password configuration(来自 standalone.xml 中定义的 <login-module>)。例如,getUserPrincipal()isUserInRole() 之类的方法需要访问我想要访问的同一个目录配置文件。

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

【问题讨论】:

    标签: jsf ldap httpsession jboss-eap-6 facescontext


    【解决方案1】:

    从 FacesConext 获取 LdapConext 的最简单方法是什么?

    根本没有办法,更不用说简单的办法了。 JSF 不假定存在 LDAP 服务器,也不提供任何与 LDAP 相关的 API。

    由于容器建立了明显的 LDAP 连接

    当您登录时。不是永久的。如果有一个 LDAP 服务器。而且 JSF 不知道容器是如何让你登录的。

    我觉得一定有办法……

    没有。

    【讨论】:

    • @EJB - 也许我应该澄清......在我调用 req.login() 时,有一个与目录的连接。那时我想查询更多属性。
    • 不会改变我的答案。如果您需要有关登录用户的更多信息,您必须自己查找,或者编写一个特定于容器的登录模块,将您需要的额外信息存储在用户主体中。
    【解决方案2】:

    我认为这个问题的一个有用答案是没有办法直接从FacesContext 获得LDAPContext,但是通过编写特定于容器的登录模块和Principal 类,您可以传递其他数据通过HttpServletRequest 得到FacesContext

    我将把我的解决方案的细节放在这里,因为即使它与FacesContext 没有直接关系,它也给了我在问题正文中所要求的内容,这是一种从LDAP 配置文件,同时避免创建一个完全独立的LDAPContext

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

    我想我正在使用这个解决方案让我的应用程序依赖于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() 方法中使用新的登录模块和主体

    sn-p:

        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. standalone.xml 中配置JBoss EAP 6.2 以使用新类

    sn-p:

    <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>
    

    【讨论】:

      猜你喜欢
      • 2020-10-16
      • 1970-01-01
      • 2015-02-13
      • 1970-01-01
      • 1970-01-01
      • 2021-03-21
      • 2019-04-21
      • 2023-03-13
      • 1970-01-01
      相关资源
      最近更新 更多