Я пытаюсь адаптировать Spring Security SAML sample application, чтобы использовать тестовый IDP (предоставленный мне кем-то другим) вместо ssocircle. Нажатие на «Логин SAML» правильно перенаправляет меня на страницу входа в систему единого входа IDP, но после входа в систему и перенаправления обратно к образцу приложения я получаю исключение (видимо, во время разрешения артефакта), корень которого:Spring Security SAML - как настроить клиентскую аутентификацию?
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
Кроме того, исключение уходит, если отключить clientAuth на IDP пути редактирования server.x МВОЙ кота и изменений clientAuth к «ложной» в соответствующем теге <Connector>
.
Подключение к порту ВПЛ 8110 отлично работает, если я использую Apache HttpClient как так
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;
}
}
Однако, я не знаю, как правильно настроить TLSProtocolConfigurer Spring SAML (или все, что необходимо использовать клиент ключ).
Итак, как я могу сообщить SAML Spring Security использовать мой клиентский ключ для аутентификации клиента в соединениях TLS/SSL?
Предоставьте свой securityContext.xml. Также вы импортировали сертификат своего тестового IDP? –
Я добавил его к вопросу. Да, я импортировал сертификат IDP в мое хранилище ключей (настроено в securityContext.xml). BTW: Если я переключу clientAuth с true на false в IDP (путем редактирования server.xml и изменения ''), пример приложения начинает работать. –
Ginkobonsai