在Linux上对Java中的远程活动目录进行身份验证

时间:2014-10-15 18:16:04

标签: java linux authentication active-directory

我的场景类似于此问题How to authenticate users with a customer's (remote) active directory server中描述的内容,除了我们的Web应用程序是基于Java的并且在CentOS Linux下运行。

我一直在搜索和阅读,但由于以下原因,似乎无法为我的方案找到有用的信息:

  1. 虽然基于Java的应用程序有不同的解决方案可以对AD进行身份验证(Kerberos,NTLM,来自Authenticating against Active Directory with Java on Linux的LDAP),但我认为它们不适用于远程 AD身份验证我读到了什么。
  2. 据说Kerberos是微软推荐的AD认证的“新”机制。但是,它似乎需要conf文件或系统属性才能工作。我们的Web应用程序是基于SaaS的,因此相同的代码库将为多个客户提供服务,而且我没有看到使Kerberos正常工作的好方法(即使它支持远程身份验证,我也看不到)。
  3. 产品Jespa使用基于NTLMv2的身份验证(同样,我没有看到它支持远程身份验证),这是“旧的”,不再被Microsoft推荐。此外,它需要创建一个“计算机帐户”。
  4. Okta有一个解决方案适用于我所面临的远程场景。但是,它需要在客户AD服务器上安装“AD代理”,以处理“AD代理”与坐在我们的Web应用程序中的Java库之间的所有SAML通信。对于我们的客户来说,在他们不是客户的基础设施中安装软件肯定是一个问题。
  5. 现在根据我最近的阅读,最好的安全措施是让组织隐藏防火墙后面的Active Directory服务器,不要将它暴露给Internet。我想知道这是否意味着无论工具和库是否存在远程Active Directory身份验证集成的“直接”路径,并且需要驻留在客户基础结构中的某种可信代理或代理来促进远程身份验证。

    欢迎任何意见和建议!

1 个答案:

答案 0 :(得分:1)

我们可以通过LDAP协议访问远程AD。在我的方案中,我在远程服务器上配置了LDAP。我已经安装了 Apache Active DS 来创建远程目录的实例。所以我可以在我的最后有一个配置细节。为此,我们需要域名&绑定凭据。您可以从此链接下载Apache Directory for Linux&创建新连接。见LDAP Connections to Active Directory Using Apache Directory Studio

Tomcat的LDAP配置:

Sample JNDIRealm configuration for Tomcat 7 - Apache.org

在位于Tomcat conf 目录的 server.xml 文件中的主机开放和主机结束标记之间添加所需的Realm配置。如,

<Host name="localhost"  appBase="webapps"
        unpackWARs="true" autoDeploy="true">
    <Realm   className="org.apache.catalina.realm.JNDIRealm"
        connectionName="cn=Manager,dc=mycompany,dc=com"
        connectionPassword="secret"
        connectionURL="ldap://localhost:389"
        userPassword="userPassword"
        userPattern="uid={0},ou=people,dc=mycompany,dc=com"
        roleBase="ou=groups,dc=mycompany,dc=com"
        roleName="cn"
        roleSearch="(uniqueMember={0})"
    />
    <!-- other stuffs -->
</Host>

请勿忘记发表评论以下条目 in server.xml

<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
           resourceName="UserDatabase"/>

完成此操作后,就可以配置您的Web应用程序了,它将通过Tomcat服务器调用LDAP服务器。

网络应用程序配置:

WebContent -> WEB-INF目录中的 web.xml 文件中添加以下条目。

<security-constraint>
    <web-resource-collection>
          <web-resource-name>Logging Area</web-resource-name>
          <description>
              Authentication Required.
          </description>
          <url-pattern>/*</url-pattern>
          <http-method>GET</http-method>
          <http-method>POST</http-method>
    </web-resource-collection>
        <auth-constraint>
            <role-name>*</role-name>
        </auth-constraint>
    </security-constraint>
   <security-role>
      <role-name>*</role-name>
   </security-role>
    <login-config>
          <auth-method>BASIC</auth-method>
        <realm-name>Authentication Required.</realm-name>
</login-config>

这是基本配置。但是,您可以使用LDAP 映射特定用户或组。看看Mapping Roles to Users and Groups - J2EE Tutorial。您还可以通过在web-resource-collection标记下为其添加网址格式,将安全性添加到特定文件夹

<url-pattern>/Admin/*</url-pattern> // Restrict access to Admin folder
<url-pattern>/Employee/*</url-pattern>  // Restrict access to Employee folder

完成所有配置。现在,当您运行应用程序时,它将要求登录凭据。一旦你进入&amp;点击提交它将在LDAP服务器中搜索该用户。

Tomcat LDAP Authentication Window

在服务器上,要获取访问用户名,请使用以下代码段: -

Principal principal = request.getUserPrincipal();
String userName = principal.getName();

示例LDAP用户管理器(JBOSS):

public LdapContext getLdapContext() {
    // Set up environment for creating initial context
    Hashtable<String, Object> env = new Hashtable<String, Object>(11);

    env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
    // e.g., ldap://IP address of remote m/c:10389/dc=sevenseas,dc=com
    env.put(Context.PROVIDER_URL, LDAP_PROVIDER_URL + Constant.FORWARD_SLASH + LDAP_DOMAIN);

    // Authenticate as User and password
    env.put(Context.SECURITY_AUTHENTICATION, "simple");
    // e.g., "uid=admin,ou=system"
    env.put(Context.SECURITY_PRINCIPAL, LDAP_ADMIN);
    env.put(Context.SECURITY_CREDENTIALS, LDAP_DEFAULT_PASSWORD);

    try {
        // Create initial context
        ldapContext = new InitialLdapContext(env, null);
        if (ldapContext == null) {
            LogManager.fatal("Invalid LDAP system properties. Please contact your administrator.",
                    LDAPUserManager.class.getName());
        }
        System.out.println("Organization : " + ldapContext.getNameInNamespace());
    } catch (Exception e) {
        StringWriter stack = new StringWriter();
        e.printStackTrace(new PrintWriter(stack));
        LogManager.fatal(stack.toString(), LDAPUserManager.class.getName());
    }
    return ldapContext;
}

这将使用环境参数构造初始上下文以连接LDAP服务器。

现在,要从AD获取用户数据,请使用以下代码:

try {
        SearchControls constraints = new SearchControls();
        constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
        String[] attrIDs = { "cn", "sn", "givenName", "uid", "mail", "userPassword" };

        constraints.setReturningAttributes(attrIDs);

        // Search for user in LDAP server by emailId
        NamingEnumeration<SearchResult> answer = ldapContext.search(LDAP_GROUP, "mail=" + emailId, constraints);
        if (answer.hasMore()) {
            LogManager.info("User with email id '" + emailId + "' found.", LDAPUserManager.class.getName());

            Attributes attrs = answer.next().getAttributes();

            userDTO = new UserDTO();

            // Store user details temporarily
            Attribute firstNameAttr = attrs.get("givenName");
            String firstName = "";
            if (firstNameAttr == null) {
                userDTO.setFirstName(firstName);
            } else {
                firstName = firstNameAttr.get().toString();
                if (firstName == null) {
                    userDTO.setFirstName("");
                }
                userDTO.setFirstName(firstName);
            }

            Attribute lastNameAttr = attrs.get("sn");
            String lastName = "";
            if (lastNameAttr == null) {
                userDTO.setLastName(lastName);
            } else {
                lastName = lastNameAttr.get().toString();
                if (lastName == null) {
                    userDTO.setLastName("");
                }
                userDTO.setLastName(lastName);
            }

            return userDTO;
        } else {
            LogManager.fatal("Invalid User.", LDAPUserManager.class.getName());
            return userDTO;
        }
    } catch (Exception e) {
        StringWriter stack = new StringWriter();
        e.printStackTrace(new PrintWriter(stack));
        LogManager.fatal(stack.toString(), LDAPUserManager.class.getName());
    }

我希望这会对你有所帮助。