java - 用于安全 LDAP 身份验证绕过的 BlindSSLFactory 在生产环境中不起作用

标签 java spring-boot ssl ldap ssl-certificate

我有一个奇怪的问题,几天来我都无法解决,所以我放弃了,决定向知识渊博的 stackoverflow 成员咨询。

我使用哪个 java 版本?

亚马逊 coretto 1.8.0_275

我想要实现什么?

在我的应用程序中,用户必须使用安全的 ldap 连接来验证自己。从 LDAP 目录进行身份验证后,用户将被重定向到他的主页。但是,我希望在通过安全端口连接到 ldap 服务器期间绕过认证检查。

到目前为止我做了什么,什么有效?

从其他帖子中,我发现我需要使用 BlindSSLFactory 类来绕过认证检查并在 ldap 查询期间将此类注入(inject)属性,我将其添加到我的项目中,如果我从 eclipse,一切正常,认证检查被绕过,用户登录。请注意:在我的 java truststore 中,我没有任何签名的认证。

什么不起作用?

如果我使用我创建的安装程序编译项目,并将其作为应用程序运行(不是从 eclipse,而是从它自己的安装程序),我会收到以下错误。 注意:我调试了以下行并打印了 true,因为我在项目运行之前设置了它: -Dcom.sun.jndi.ldap.object.disableEndpointIdentification:

javax.naming.CommunicationException: simple bind failed: 10.148.129.11:636
at com.sun.jndi.ldap.LdapClient.authenticate(LdapClient.java:219) ~[na:1.8.0_275]
at com.sun.jndi.ldap.LdapCtx.connect(LdapCtx.java:2897) ~[na:1.8.0_275]
at com.sun.jndi.ldap.LdapCtx.<init>(LdapCtx.java:347) ~[na:1.8.0_275]
at com.sun.jndi.ldap.LdapCtxFactory.getLdapCtxFromUrl(LdapCtxFactory.java:225) ~[na:1.8.0_275]
at com.sun.jndi.ldap.LdapCtxFactory.getUsingURL(LdapCtxFactory.java:189) ~[na:1.8.0_275]
at com.sun.jndi.ldap.LdapCtxFactory.getUsingURLs(LdapCtxFactory.java:243) ~[na:1.8.0_275]
at com.sun.jndi.ldap.LdapCtxFactory.getLdapCtxInstance(LdapCtxFactory.java:154) ~[na:1.8.0_275]
at com.sun.jndi.ldap.LdapCtxFactory.getInitialContext(LdapCtxFactory.java:84) ~[na:1.8.0_275]
at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:684) ~[na:1.8.0_275]
at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:313) ~[na:1.8.0_275]
at javax.naming.InitialContext.init(InitialContext.java:244) ~[na:1.8.0_275]
at javax.naming.InitialContext.<init>(InitialContext.java:216) ~[na:1.8.0_275]
at javax.naming.directory.InitialDirContext.<init>(InitialDirContext.java:101) ~[na:1.8.0_275]
at com.ricoh.sdced.festo.pab.web.login.LdapAuthentication.createLoginSession(LdapAuthentication.java:78) [classes!/:na]
at com.ricoh.sdced.festo.pab.web.login.LdapAuthentication.startLoginSession(LdapAuthentication.java:43) [classes!/:na]
at com.ricoh.sdced.festo.pab.web.views.LoginView.performLogin(LoginView.java:54) [classes!/:na]
at com.ricoh.sdced.festo.pab.web.views.LoginView.lambda$createLoginLayout$565279a2$1(LoginView.java:47) [classes!/:na]
at com.vaadin.flow.component.ComponentEventBus.fireEventForListener(ComponentEventBus.java:205) ~[flow-server-2.1.5.jar!/:2.1.5]
at com.vaadin.flow.component.ComponentEventBus.handleDomEvent(ComponentEventBus.java:373) ~[flow-server-2.1.5.jar!/:2.1.5]
at com.vaadin.flow.component.ComponentEventBus.lambda$addDomTrigger$dd1b7957$1(ComponentEventBus.java:264) ~[flow-server-2.1.5.jar!/:2.1.5]
at com.vaadin.flow.internal.nodefeature.ElementListenerMap.lambda$fireEvent$2(ElementListenerMap.java:441) ~[flow-server-2.1.5.jar!/:2.1.5]
at java.util.ArrayList.forEach(ArrayList.java:1259) ~[na:1.8.0_275]
at com.vaadin.flow.internal.nodefeature.ElementListenerMap.fireEvent(ElementListenerMap.java:441) ~[flow-server-2.1.5.jar!/:2.1.5]
at com.vaadin.flow.server.communication.rpc.EventRpcHandler.handleNode(EventRpcHandler.java:59) ~[flow-server-2.1.5.jar!/:2.1.5]
at com.vaadin.flow.server.communication.rpc.AbstractRpcInvocationHandler.handle(AbstractRpcInvocationHandler.java:64) ~[flow-server-2.1.5.jar!/:2.1.5]
at com.vaadin.flow.server.communication.ServerRpcHandler.handleInvocationData(ServerRpcHandler.java:402) ~[flow-server-2.1.5.jar!/:2.1.5]
at com.vaadin.flow.server.communication.ServerRpcHandler.lambda$handleInvocations$1(ServerRpcHandler.java:383) ~[flow-server-2.1.5.jar!/:2.1.5]
at java.util.ArrayList.forEach(ArrayList.java:1259) ~[na:1.8.0_275]
at com.vaadin.flow.server.communication.ServerRpcHandler.handleInvocations(ServerRpcHandler.java:383) ~[flow-server-2.1.5.jar!/:2.1.5]
at com.vaadin.flow.server.communication.ServerRpcHandler.handleRpc(ServerRpcHandler.java:318) ~[flow-server-2.1.5.jar!/:2.1.5]
at com.vaadin.flow.server.communication.UidlRequestHandler.synchronizedHandleRequest(UidlRequestHandler.java:89) ~[flow-server-2.1.5.jar!/:2.1.5]
at com.vaadin.flow.server.SynchronizedRequestHandler.handleRequest(SynchronizedRequestHandler.java:40) ~[flow-server-2.1.5.jar!/:2.1.5]
at com.vaadin.flow.server.VaadinService.handleRequest(VaadinService.java:1540) ~[flow-server-2.1.5.jar!/:2.1.5]
at com.vaadin.flow.server.VaadinServlet.service(VaadinServlet.java:247) ~[flow-server-2.1.5.jar!/:2.1.5]
at com.vaadin.flow.spring.SpringServlet.service(SpringServlet.java:95) ~[vaadin-spring-12.1.2.jar!/:na]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:733) ~[tomcat-embed-core-9.0.37.jar!/:4.0.FR]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-9.0.37.jar!/:9.0.37]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.37.jar!/:9.0.37]
at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:712) ~[tomcat-embed-core-9.0.37.jar!/:9.0.37]
at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:459) ~[tomcat-embed-core-9.0.37.jar!/:9.0.37]
at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:352) ~[tomcat-embed-core-9.0.37.jar!/:9.0.37]
at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:312) ~[tomcat-embed-core-9.0.37.jar!/:9.0.37]
at org.springframework.web.servlet.mvc.ServletForwardingController.handleRequestInternal(ServletForwardingController.java:141) ~[spring-webmvc-5.2.8.RELEASE.jar!/:5.2.8.RELEASE]
at org.springframework.web.servlet.mvc.AbstractController.handleRequest(AbstractController.java:177) ~[spring-webmvc-5.2.8.RELEASE.jar!/:5.2.8.RELEASE]
at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:52) ~[spring-webmvc-5.2.8.RELEASE.jar!/:5.2.8.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040) ~[spring-webmvc-5.2.8.RELEASE.jar!/:5.2.8.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943) ~[spring-webmvc-5.2.8.RELEASE.jar!/:5.2.8.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.2.8.RELEASE.jar!/:5.2.8.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) ~[spring-webmvc-5.2.8.RELEASE.jar!/:5.2.8.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:652) ~[tomcat-embed-core-9.0.37.jar!/:4.0.FR]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.2.8.RELEASE.jar!/:5.2.8.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:733) ~[tomcat-embed-core-9.0.37.jar!/:4.0.FR]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-9.0.37.jar!/:9.0.37]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.37.jar!/:9.0.37]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.37.jar!/:9.0.37]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.37.jar!/:9.0.37]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.37.jar!/:9.0.37]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.2.8.RELEASE.jar!/:5.2.8.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.8.RELEASE.jar!/:5.2.8.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.37.jar!/:9.0.37]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.37.jar!/:9.0.37]
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.2.8.RELEASE.jar!/:5.2.8.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.8.RELEASE.jar!/:5.2.8.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.37.jar!/:9.0.37]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.37.jar!/:9.0.37]
at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:93) ~[spring-boot-actuator-2.3.3.RELEASE.jar!/:2.3.3.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.8.RELEASE.jar!/:5.2.8.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.37.jar!/:9.0.37]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.37.jar!/:9.0.37]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.2.8.RELEASE.jar!/:5.2.8.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.8.RELEASE.jar!/:5.2.8.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.37.jar!/:9.0.37]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.37.jar!/:9.0.37]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202) ~[tomcat-embed-core-9.0.37.jar!/:9.0.37]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) ~[tomcat-embed-core-9.0.37.jar!/:9.0.37]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541) ~[tomcat-embed-core-9.0.37.jar!/:9.0.37]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) ~[tomcat-embed-core-9.0.37.jar!/:9.0.37]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) ~[tomcat-embed-core-9.0.37.jar!/:9.0.37]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) ~[tomcat-embed-core-9.0.37.jar!/:9.0.37]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) ~[tomcat-embed-core-9.0.37.jar!/:9.0.37]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:373) ~[tomcat-embed-core-9.0.37.jar!/:9.0.37]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) ~[tomcat-embed-core-9.0.37.jar!/:9.0.37]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868) ~[tomcat-embed-core-9.0.37.jar!/:9.0.37]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1589) ~[tomcat-embed-core-9.0.37.jar!/:9.0.37]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) ~[tomcat-embed-core-9.0.37.jar!/:9.0.37]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) ~[na:1.8.0_275]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) ~[na:1.8.0_275]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.37.jar!/:9.0.37]
at java.lang.Thread.run(Thread.java:748) ~[na:1.8.0_275]
Caused by: java.net.SocketException: Connection or outbound has closed
at sun.security.ssl.SSLSocketImpl$AppOutputStream.write(SSLSocketImpl.java:967) ~[na:1.8.0_275]
at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82) ~[na:1.8.0_275]
at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140) ~[na:1.8.0_275]
at com.sun.jndi.ldap.Connection.writeRequest(Connection.java:448) ~[na:1.8.0_275]
at com.sun.jndi.ldap.Connection.writeRequest(Connection.java:421) ~[na:1.8.0_275]
at com.sun.jndi.ldap.LdapClient.ldapBind(LdapClient.java:359) ~[na:1.8.0_275]
at com.sun.jndi.ldap.LdapClient.authenticate(LdapClient.java:214) ~[na:1.8.0_275]
... 88 common frames omitted

我的代码逻辑如何?

public class BlindSSLSocketFactory extends SocketFactory {

private static SocketFactory blindFactory = null;
/**
 * Builds an ALL trusting "blind" ssl socket factory.
 */
static {
// create a trust manager that will purposefully fall down on the
// job
    TrustManager[] blindTrustMan = new TrustManager[] { new X509TrustManager() {
        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }

        public void checkClientTrusted(X509Certificate[] c, String a) {
        }

        public void checkServerTrusted(X509Certificate[] c, String a) {
        }
    } };

    // create our "blind" ssl socket factory with our lazy trust manager
    try {
        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, blindTrustMan, new java.security.SecureRandom());
        blindFactory = sc.getSocketFactory();
    } catch (GeneralSecurityException e) {
        e.printStackTrace();
    }
}

/**
 * @see javax.net.SocketFactory#getDefault()
 */
public static SocketFactory getDefault() {
    return new BlindSSLSocketFactory();
}

/**
 * @see javax.net.SocketFactory#createSocket(java.lang.String, int)
 */
public Socket createSocket(String arg0, int arg1) throws IOException, UnknownHostException {
    return blindFactory.createSocket(arg0, arg1);
}

/**
 * @see javax.net.SocketFactory#createSocket(java.net.InetAddress, int)
 */
public Socket createSocket(InetAddress arg0, int arg1) throws IOException {
    return blindFactory.createSocket(arg0, arg1);
}

/**
 * @see javax.net.SocketFactory#createSocket(java.lang.String, int,
 *      java.net.InetAddress, int)
 */
public Socket createSocket(String arg0, int arg1, InetAddress arg2, int arg3)
        throws IOException, UnknownHostException {
    return blindFactory.createSocket(arg0, arg1, arg2, arg3);
}

/**
 * @see javax.net.SocketFactory#createSocket(java.net.InetAddress, int,
 *      java.net.InetAddress, int)
 */
public Socket createSocket(InetAddress arg0, int arg1, InetAddress arg2, int arg3) throws IOException {
    return blindFactory.createSocket(arg0, arg1, arg2, arg3);
}

还有我的 LDAP 登录类,我在其中注入(inject)了这个 blindSSLFactory 类

@Component
public class LdapAuthentication {

private final Logger logger = LoggerFactory.getLogger(getClass());

private String username;

private String password;

private boolean isLoggedIn;

public LdapAuthentication() {
}

public void startLoginSession(String username, String password)
        throws NamingException {
    
    logger.info("preparing user login details...");
    
    this.username = username;
    this.password = password;
    
    logger.info("user login will be attempted for user: " + this.username);

    this.isLoggedIn = createLoginSession(this.username, this.password);
    
    logger.info("login attempt success result: " + this.isLoggedIn); 
}

private boolean createLoginSession(String username, String password)
        throws NamingException {

    logger.info("creating a LDAP Authentication session...");
    logger.info("System property value for            -Dcom.sun.jndi.ldap.object.disableEndpointIdentification:"
            + System.getProperty("com.sun.jndi.ldap.object.disableEndpointIdentification"));

    String ldapServerUrl = buildLdapPrefix()
            + SettingsResolver.getInstance().getSetting(
                    "ldap.server.address")
            + ":"
            + SettingsResolver.getInstance().getSetting(
                    "ldap.server.port.number");

    logger.info("LDAP authentication URL: " + ldapServerUrl);

    Properties props = new Properties();
    
    //use this line if you wanna discard ssl certificate validation
    props.put("java.naming.ldap.factory.socket",
            BlindSSLSocketFactory.class.getName());
    
    props.put(Context.INITIAL_CONTEXT_FACTORY,
            "com.sun.jndi.ldap.LdapCtxFactory");
    props.put(Context.PROVIDER_URL, ldapServerUrl);
    props.put(Context.SECURITY_PRINCIPAL, username);
    props.put(Context.SECURITY_CREDENTIALS, password);

    InitialDirContext context = null;
    try {
        context = new InitialDirContext(props);
        SearchControls controls = new SearchControls();
        controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
        NamingEnumeration<SearchResult> results = context.search(
                toDC(SettingsResolver.getInstance().getSetting(
                        "ldap.server.domain.name")), String.format(
                        "(& (userPrincipalName=%s)(objectClass=user))",
                        this.username), controls);
        
        return results.hasMore();
    } catch (NamingException namingException) {
        logger.error(
                "Exception occurred while authenticating to LDAP Server: ",
                namingException);

        throw namingException;
    } finally {
        try {
            if (context != null)
                context.close();
        } catch (Exception ex) {
        }
    }
}

private static String toDC(String username) {
    String result = "";
    String[] parts = username.split("\\.");
    for (int index = 0; index < parts.length - 1; index++)
        result = result.concat("DC=").concat(parts[index]).concat(",");
    return result.concat("DC=").concat(parts[parts.length - 1]);
}

public boolean isUserLoggedIn() {
    return this.isLoggedIn;
}

private String buildLdapPrefix() {
    String securePortEnabled = SettingsResolver.getInstance().getSetting(
            "ldap.server.secure.port.enabled");

    if (securePortEnabled.contains("true")) {
        return "ldaps://";
    } else {
        return "ldap://";
    }
}

最佳答案

也许您的 BlindSSLFactory 实际上并未在生产环境中使用。我的钱在 java.naming.ldap.factory.socket 在代码的其他地方被覆盖,因为它似乎是让你的应用程序知道它应该通过类似 SPI 的接口(interface)利用这个工厂的方式

一个好的起点是远程调试 JVM 并查看运行时属性值的设置。

关于java - 用于安全 LDAP 身份验证绕过的 BlindSSLFactory 在生产环境中不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65368359/

相关文章:

java - 如何在 Spring MVC REST 中为 JSON 设置内容长度?

java - Java中有没有办法将多个参数对传递给一个方法?

java - 如何在 Eclipse 中打开 Java、Scala 和 JRuby 的单个项目?

java - 通过命令行运行spring boot应用的非主类

spring-boot - 带有Spring-data-elastic的Spring Boot连接到AWS服务器上的Elastic Search 7.4.0

java - 在 Hibernate/JPA 中,我应该在哪里以及在哪个用例中使用 SessionFactory 和 Session

java - 在 Android 应用程序中使用 zxing 扫描条形码阅读器数据

java - 是否可以将自定义信任库与 SOAPConnection 一起使用?

Codeigniter URL 重写 SSL HTTPS

java - 无法识别 SSL 聊天错误客户端证书和 TLSv1.2