【问题标题】:"CLIENT-CERT" based X509 certificate authentication in Grails 3.3Grails 3.3 中基于“CLIENT-CERT”的 X509 证书身份验证
【发布时间】:2018-05-22 19:40:09
【问题描述】:

当我尝试升级到 Grails 3 时,我一直在尝试镜像我在 Grails 2 中的实现已有一段时间了。

我需要使用“client-cert”身份验证方法支持基于 X509 证书的身份验证,也就是说,我只想在请求受保护的资源后提示输入证书。 请参阅下面 Application.groovy 中的当前实现。

@Bean
EmbeddedServletContainerCustomizer containerCustomizer() throws Exception {

    return new EmbeddedServletContainerCustomizer() {
        @Override
        public void customize(ConfigurableEmbeddedServletContainer container) {
            TomcatEmbeddedServletContainerFactory tomcat = (TomcatEmbeddedServletContainerFactory) container
            tomcat.addConnectorCustomizers(
                    new TomcatConnectorCustomizer() {
                        @Override
                        public void customize(Connector connector) {
                            connector.setPort(8443)
                            connector.setSecure(true)
                            connector.setScheme("https")

                            Http11NioProtocol proto = (Http11NioProtocol) connector.getProtocolHandler()
                            proto.setMinSpareThreads(5)
                            proto.setSSLEnabled(true)
                            proto.setClientAuth("false")

                            proto.setKeystoreFile("/tmp/keys/app.jks")
                            proto.setKeystorePass("changeit")
                            proto.setKeystoreType("JKS")
                            proto.setKeyAlias("ssl_server")
                            proto.setTruststoreFile("/tmp/keys/app.jts")
                            proto.setTruststoreType("JKS")
                            proto.setTruststorePass("changeit")
                        }
                    })
            tomcat.addContextCustomizers(new TomcatContextCustomizer() {
                @Override
                public void customize(Context context) {
                    context.setPath("/myapp")
                    SecurityConstraint sc = new SecurityConstraint()
                    SecurityCollection securityCollection = new SecurityCollection()
                    securityCollection.setName("Protected")
                    securityCollection.addPattern("/*")

                    sc.addCollection(securityCollection)

                    sc.addAuthRole("mySecureConnection")
                    sc.setUserConstraint("CONFIDENTIAL")
                    context.addConstraint(sc)
                    context.addSecurityRole("mySecureConnection")
                    context.setRealm(new MySecurityRealm())

                    LoginConfig loginConfig = new LoginConfig()
                    loginConfig.setAuthMethod("CLIENT-CERT")
                    loginConfig.setRealmName("MySecurityRealm")
                    context.setLoginConfig(loginConfig)
                    sc.setAuthConstraint(true)

                }
            });
        }
    }

但是,无论我尝试使用多少种不同的方式来削减它,应用程序都不会在访问时请求证书(它应该基于我上面的全部捕获模式)。 请注意,当 clientAuth 设置为 true 时,此机制会按预期工作;

proto.setClientAuth("true")

但这意味着总是要求一个证书,这最终不是我想要的(我打算更新上面的模式)。 任何帮助将不胜感激。

【问题讨论】:

    标签: ssl spring-boot grails x509certificate grails-3.3


    【解决方案1】:

    在返回 Grails 3.3.x 以应用有效的方法之前,我自己在原版 tomcat 和 Spring Boot 级别进行了概念验证之后,我自己就完成了这项工作。 我认为拼图中最重要的部分可能是添加了一个 tomcat 阀门组件(显然使用 SSLAuthenticator 实现),这是我能够设法让浏览器提示输入证书的唯一方法。然后,这要求我使用自定义领域从证书中检索主体(我目前不知道其他方法)。 代码如下;

    @Bean
    public EmbeddedServletContainerFactory servletContainer() {
        final TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory();
        tomcat.addContextValves(new SSLAuthenticator());
    
        tomcat.addContextCustomizers(new TomcatContextCustomizer() {
            @Override
            public void customize(Context ctx) {
    
                String AUTH_ROLE = "mySecureRole";
                ctx.addSecurityRole(AUTH_ROLE);
                ctx.setRealm(new MySecurityRealm())
    
                LoginConfig config = new LoginConfig();
                config.setAuthMethod("CLIENT-CERT");
                config.setRealmName("MySecurityRealm");
                ctx.setLoginConfig(config);
    
                SecurityConstraint constraint = new SecurityConstraint();
                constraint.addAuthRole(AUTH_ROLE);
                SecurityCollection collection = new SecurityCollection();
                collection.addPattern("/secure");
                constraint.addCollection(collection);
                ctx.addConstraint(constraint);
            }
        })
    
        tomcat.addAdditionalTomcatConnectors(createConnector());
        return tomcat;
    }
    
    
    private Connector createConnector() {
        Connector connector = new Connector(TomcatEmbeddedServletContainerFactory.DEFAULT_PROTOCOL);
    
        connector.setPort(8443);
        connector.setSecure(true);
        connector.setScheme("https");
    
        Http11NioProtocol proto = (Http11NioProtocol) connector.getProtocolHandler();
        proto.setMinSpareThreads(5);
        proto.setSSLEnabled(true);
        proto.setClientAuth("false");
        proto.setSSLProtocol("all");
    
        proto.setKeystoreFile("/path/store.jks");
        proto.setKeystorePass("changeit");
        proto.setKeystoreType("JKS");
        proto.setKeyAlias("ssl_server");
        proto.setTruststoreFile("/path/store.jts");
        proto.setTruststoreType("JKS");
        proto.setTruststorePass("changeit");
    
        proto.setSSLVerifyDepth(2);
        return connector;
    }
    

    为了完整起见,我将保留连接器详细信息,但当然,所有重要的事情都发生在上下文定制器中。 现在,当我访问此 Web 应用程序时,不会提示我输入证书。这只发生在我访问正是我需要的 /secure 路径时。

    【讨论】:

      猜你喜欢
      • 2023-03-15
      • 1970-01-01
      • 2019-01-03
      • 2016-10-02
      • 2018-02-24
      • 2017-01-23
      • 1970-01-01
      • 2011-11-11
      • 2018-07-25
      相关资源
      最近更新 更多