当前位置: 首页 > 知识库问答 >
问题:

Spring Security SAML-如何配置客户端身份验证?

班安平
2023-03-14

我正在尝试调整Spring Security SAML示例应用程序,以使用测试IDP(由其他人提供给我)而不是SSOCELL。单击“SAML登录”可以正确地将我重定向到IDP的SSO登录页面,但在登录并重定向回示例应用程序后,我会得到一个异常(显然是在工件解析期间),其根源是:

org.opensaml.ws.message.decoder.MessageDecodingException: Error when sending request to artifact resolution service.
    at org.springframework.security.saml.websso.ArtifactResolutionProfileImpl.getArtifactResponse(ArtifactResolutionProfileImpl.java:110)
    at org.springframework.security.saml.websso.ArtifactResolutionProfileBase.resolveArtifact(ArtifactResolutionProfileBase.java:101)
    ... 34 more
Caused by: javax.net.ssl.SSLPeerUnverifiedException: SSL peer failed hostname validation for name: null
    at org.opensaml.ws.soap.client.http.TLSProtocolSocketFactory.verifyHostname(TLSProtocolSocketFactory.java:233)
    at org.opensaml.ws.soap.client.http.TLSProtocolSocketFactory.createSocket(TLSProtocolSocketFactory.java:186)
    at org.apache.commons.httpclient.HttpConnection.open(HttpConnection.java:707)
    at org.apache.commons.httpclient.MultiThreadedHttpConnectionManager$HttpConnectionAdapter.open(MultiThreadedHttpConnectionManager.java:1361)
    at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java:387)
    at org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java:171)
    at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:397)
    at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:346)
    at org.springframework.security.saml.websso.ArtifactResolutionProfileImpl.getArtifactResponse(ArtifactResolutionProfileImpl.java:99)

挖了一会儿后,我意识到服务器需要相关端口的客户端身份验证。如果我这样连接到它,我会得到一个有效的响应:

curl -k --cert spcert.pem --key spkey.pem https://testidp:8110/idp/profile/SAML2/SOAP/ArtifactResolution

此外,如果我通过编辑服务器在IDP上禁用clientAuth,异常就会消失。IDP tomcat的xml,并在相关<代码>

如果我像这样使用apache httpclient,那么连接到IDP的8110端口就可以了

package at.awst.perkele.httpstest;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;

import javax.net.ssl.SSLContext;

import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;

public class HTTPSTest {
    private static final String CA_KEYSTORE_TYPE = KeyStore.getDefaultType(); // "JKS";
    private static final String CA_KEYSTORE_PATH = "myKeystore.jks";
    private static final String CA_KEYSTORE_PASS = "secret";

    private static final String CLIENT_KEYSTORE_TYPE = KeyStore.getDefaultType(); // "JKS";
    private static final String CLIENT_KEYSTORE_PATH = "myKeystore.jks";
    private static final String CLIENT_KEYSTORE_PASS = "secret";

    private static final String HTTPS_URL = "https://testidp:8110/idp/profile/SAML2/SOAP/ArtifactResolution";

    public static void main(String[] args) throws Exception {
        SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(createSslCustomContext(), new String[] { "TLSv1" }, 
                null, SSLConnectionSocketFactory.getDefaultHostnameVerifier());

        try (CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(csf).build()) {
            HttpGet req = new HttpGet(HTTPS_URL);
            try (CloseableHttpResponse response = httpclient.execute(req)) {
                HttpEntity entity = response.getEntity();

                System.out.println(String.format("Reponse status: %s", response.getStatusLine()));
                System.out.println(String.format("Response entity: %s", entity.toString()));

                BufferedReader in = new BufferedReader(new InputStreamReader(entity.getContent()));
                String line = null;
                while ((line = in.readLine()) != null) {
                    System.out.println(line);
                }
                EntityUtils.consume(entity);
            }
        }
    }

    private static SSLContext createSslCustomContext() throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException, KeyManagementException, UnrecoverableKeyException {
        // Trusted CA keystore
        KeyStore tks = KeyStore.getInstance(CA_KEYSTORE_TYPE);
        tks.load(new FileInputStream(CA_KEYSTORE_PATH), CA_KEYSTORE_PASS.toCharArray());

        // Client keystore
        KeyStore cks = KeyStore.getInstance(CLIENT_KEYSTORE_TYPE);
        cks.load(new FileInputStream(CLIENT_KEYSTORE_PATH), CLIENT_KEYSTORE_PASS.toCharArray());

        SSLContext sslcontext = SSLContexts.custom().loadTrustMaterial(tks, new TrustSelfSignedStrategy()) 
                .loadKeyMaterial(cks, CLIENT_KEYSTORE_PASS.toCharArray())
                .build();
        return sslcontext;
    }

}

但是,我不知道如何正确配置Spring SAML的TLSPROCOLOGLOGINGINGREREER(或使用客户端密钥所需的任何内容)。

那么,我如何告诉Spring Security SAML在TLS/SSL连接中使用客户端密钥进行客户端身份验证呢?

共有1个答案

徐星阑
2023-03-14

好的,弄清楚如何在Spring SAML的TLS连接中启用clientAuth。这是我来自securityContext.xml的服务提供商配置:

<bean class="org.springframework.security.saml.metadata.ExtendedMetadataDelegate">
    <constructor-arg>
        <bean class="org.opensaml.saml2.metadata.provider.FilesystemMetadataProvider">
            <constructor-arg>
                <value type="java.io.File">classpath:metadata/sp.xml</value>
            </constructor-arg>
            <property name="parserPool" ref="parserPool" />
        </bean>
    </constructor-arg>
    <constructor-arg>
        <bean class="org.springframework.security.saml.metadata.ExtendedMetadata">
            <property name="local" value="true" />
            <property name="signMetadata" value="true" />
            <property name="signingKey" value="mykey" />
            <property name="encryptionKey" value="mykey" />
            <property name="tlsKey" value="mykey" />
        </bean>
    </constructor-arg>
</bean>  

通过

密钥必须像往常一样在JKSKeyManager中声明:

<bean id="keyManager" class="org.springframework.security.saml.key.JKSKeyManager">
    <constructor-arg value="classpath:security/keystore.jks" />
    <constructor-arg type="java.lang.String" value="secret" />
    <constructor-arg>
        <map>
            <entry key="mykey" value="secret" />
        </map>
    </constructor-arg>
    <constructor-arg type="java.lang.String" value="mykey" />
</bean>

这在这里的文档中被称为“填充用于SSL/TLS客户端身份验证的凭据。如果ExtendedMetadata指定了属性tlsKey,它将用作从keyManager bean中查找密钥的别名。否则,不会为客户端身份验证提供凭据。”我花了一段时间才找到;-)

 类似资料:
  • 授权服务器为进行客户端身份验证的目的,为Web应用客户端创建客户端凭据。授权服务器被鼓励考虑比客户端密码更强的客户端身份验证手段。Web应用程序客户端必须确保客户端密码和其他客户端凭据的机密性。 授权不得向本地应用程序或基于用户代理的应用客户端颁发客户端密码或其他客户端凭据用于客户端验证目的。授权服务器可以颁发客户端密码或其他凭据给专门的设备上特定安装的本地应用程序客户端。 当客户端身份验证不可用

  • 在向令牌端点发起请求时,机密客户端或其他被颁发客户端凭据的客户端必须如2.3节所述与授权服务器进行身份验证。客户端身份验证用于: 实施刷新令牌和授权码到它们被颁发给的客户端的绑定。当授权码在不安全通道上向重定向端点传输时,或者 当重定向URI没有被完全注册时,客户端身份验证是关键的。 通过禁用客户端或者改变其凭据从被入侵的客户端恢复,从而防止攻击者滥用被盗的刷新令牌。改变单套客户端凭据显然快于撤销

  • 如果客户端类型是机密的,客户端和授权服务器建立适合于授权服务器的安全性要求的客户端身份验证方法。授权服务器可以接受符合其安全要求的任何形式的客户端身份验证。 机密客户端通常颁发(或建立)一组客户端凭据用于与授权服务器进行身份验证(例如,密码、公/私钥对)。授权服务器可以与公共客户端建立客户端身份验证方法。然而,授权服务器不能依靠公共客户端身份验证达到识别客户端的目的。 客户端在每次请求中不能使用一

  • 有时需要对某些网络资源(如Servlet、JSP等)进行访问权限验证,也就是说,有访问权限的用户才能访问该网络资源。进行访问权限验证的方法很多,但通过HTTP响应消息头的WWW-Authenticate字段进行访问权限的验证应该是众多权限验证方法中比较简单的一个。 通过HTTP响应消息头的WWW-Authenticate字段可以使浏览器出现一个验证对话框,访问者需要在这个对话框中输入用户名和密码,

  • 我正在尝试使用 Spring 启动管理员(服务器客户端)设置示例应用程序,并遇到了身份验证问题。 当在客户端的管理/执行器endpoint上启用 spring 安全性时,spring-boot-admin 服务器似乎无法与客户端通信 - 通过 Web 浏览器登录到管理界面会导致弹出连续的身份验证窗口循环并提示输入用户名/密码。点击取消将在页面上显示 HTTP 401 错误。 下面是一个适用于客户端

  • 我不熟悉SSL和证书。我一直在做关于客户端证书认证的研究。我看过这个和wiki。 因此,如果我必须为我的B2B REST服务实现客户端证书身份验证解决方案,我应该执行以下操作 要求客户端生成自己的私钥,并为其公钥生成证书(CA 颁发?)。通过电子邮件或 USB 闪存盘发送该证书。 在服务器端将客户端的公共证书导入信任存储区并启用客户端身份验证 在握手期间,客户端会出示其证书并进行身份验证,因为服务