首页 > 解决方案 > 在tomcat自定义JNDIRealm中访问会话信息

问题描述

我正在尝试编写自定义 JNDIRealm 但如何访问 Request 对象?

我这样做的原因是我有 2 个 LDAP 服务器,其中一个执行 2-Factor 检查。我需要访问 Request 对象以查看请求的来源。对于 Intranet 用户,我使用普通 LDAP 服务器,但对于 Internet 用户,我使用 2-Factor LDAP 服务器

标签: authenticationtomcat9realm-base-adapter

解决方案


似乎不可能......我必须更新我的 login.jsp 并在那里访问 Request 对象并在 j_username 中传递我需要的信息

var isWebProxyRequest = "<%= request.getHeader("PROXY_HEADER") != null ? "Y" : "N" %>";                                                  
getElement("j_username").value = (isWebProxyRequest == "Y" ? "WEB::" : "INTERNAL::") + getElement("username").value;

在我的情况下,我有一个 apache 代理,它执行我的 DDOS 和 WEB 和设置标题属性的 TOMCAT 之间的其他保护。这是通过在 apache ssl.conf 中进行以下设置来完成的

RequestHeader set PROXY_HEADER xxxx

如上所示,我检测并将一个名为 TYPE 的变量设置为 WEB 或 INTRANET

我将 TYPE 传递给 j_username 所以当 j_username 传递给 Realm 时会看到 ::

然后我编写了自己的自定义领域,称为 SelectorRealm,如下所示

package xxxx;

public class SelectionRealm extends CombinedRealm {
   private static final Log log = LogFactory.getLog(SelectionRealm.class);

   public boolean checkSelector(Realm realm, String selector) {
      return ((SelectorRealm) realm).getSelector().equals(selector);
   }

   public String getUserName(String username) {
      return username.replaceAll("^.*::", "");
   }

   public String getSelector(String username) {
      return username.replaceAll("::.*$", "");
   }

   public Principal authenticate(String _username, String clientDigest, String nonce, String nc, String cnonce, String qop, String realmName, String md5a2) {
      Principal authenticatedUser = null;

      String username = getUserName(_username);
      String selector = getSelector(_username);
      log.info("username=" + username + " selector=" + selector);
      for (Realm realm : realms) {
         if (!checkSelector(realm, selector)) continue;

         authenticatedUser = realm.authenticate(username, clientDigest, nonce, nc, cnonce, qop, realmName, md5a2);
         break;
      }

      return authenticatedUser;
   }

   public Principal authenticate(String _username) {
      Principal authenticatedUser = null;

      String username = getUserName(_username);
      String selector = getSelector(_username);
      log.info("SelectionRealm: username=" + username + " selector=" + selector);
      for (Realm realm : realms) {
         if (!checkSelector(realm, selector)) continue;

         authenticatedUser = realm.authenticate(username);
         break;
      }
      return authenticatedUser;
   }

   public Principal authenticate(String _username, String credentials) {
      Principal authenticatedUser = null;

      String username = getUserName(_username);
      String selector = getSelector(_username);
      log.info("SelectionRealm: username=" + username + " selector=" + selector);
      for (Realm realm : realms) {
         if (!checkSelector(realm, selector)) continue;

         authenticatedUser = realm.authenticate(username, credentials);
         break;
      }

      return authenticatedUser;
   }

   public Principal authenticate(GSSContext gssContext, boolean storeCred) {
      UnsupportedOperationException uoe = new UnsupportedOperationException("SelectionRealm.authenticate.GSSContext");
      log.error("SelectionRealm.unexpectedMethod", uoe);
      throw uoe;
   }

   public Principal authenticate(GSSName gssName, GSSCredential gssCredential) {
      UnsupportedOperationException uoe = new UnsupportedOperationException("SelectionRealm.authenticate.GSSName");
      log.error("SelectionRealm.unexpectedMethod", uoe);
      throw uoe;
   }
}

和 SelectorRealm 为

package xxxx;

public interface SelectorRealm {
   public void setSelector(String selector);
   public String getSelector();
}

和实现 SelectorRealm 的自定义 JNDIRealm

package xxxx;

public class JNDIRealm extends org.apache.catalina.realm.JNDIRealm implements SelectorRealm {
   protected String selector = null;

   public void setSelector(String selector) {
      this.selector = selector;
   }

   public String getSelector() {
      return this.selector;
   }
}

所以现在我的 tomcat context.xml 设置为

   <Realm className="xxxx.SelectionRealm" >
      <Realm className="xxxx.JNDIRealm" debug="99"
                       connectionURL="ldaps://${LDAP_INTERNAL_SERVER}:${LDAP_INTERNAL_PORT}"
             selector="INTERNAL"
             ... />

      <Realm className="xxxx.JNDIRealm" debug="99"
             connectionURL="ldaps://${LDAP_WEB_SERVER}:${LDAP_WEB_PORT}"
             selector="WEB"
             ... />
   </Realm>

推荐阅读