我应该得到一个带有特定参数集的 GET 身份验证请求:
"https://domain_name_of_idp_here/idp/profile/SAML2/Redirect/SSO?" +
"SAMLRequest=" + SAMLRequest + "&SigAlg=" + SigAlg + "&Signature=" + Signature
因此,我对参数感兴趣:
- SAML请求
- 信号算法
- 签名
当我使用 OIOSAML 时, 请求的所有这些部分都是自动形成的,但不可能灵活地管理它们并获得完全控制。
所以我决定使用 OpenSAML 2.4.1 编写基于 sp 的 Web SSO
考虑如何创建 SAMLRequest。我的 idP 要求 sP-AuthnRequest 请求采用以下格式:
<?xml version="1.0" encoding="UTF-8"?>
<saml2p:AuthnRequest xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol"
AssertionConsumerServiceURL=
"https://ip_of_my_sp_here/oiosaml/saml/SAMLAssertionConsumer"
Destination="https://domain_name_of_idp_here/idp/profile/SAML2/Redirect/SSO"
ForceAuthn="false"
ID="_054240e4-...-e0b5e84d3a35"
IsPassive="false"
IssueInstant="2012-02-28T06:43:35.704Z"
ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
Version="2.0">
<saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
test_issuer
</saml2:Issuer>
因此我形成的SAMLRequest如下:
private AuthnRequest buildAuthnRequestObject() {
DateTime issueInstant = new DateTime();
IssuerBuilder issuerBuilder = new IssuerBuilder();
Issuer issuer = issuerBuilder.buildObject(
"urn:oasis:names:tc:SAML:2.0:assertion",
"Issuer", "samlp");
issuer.setValue(issuerId);
AuthnRequestBuilder authRequestBuilder = new AuthnRequestBuilder();
AuthnRequest authRequest =
authRequestBuilder.buildObject("urn:oasis:names:tc:SAML:2.0:protocol",
"AuthnRequest", "samlp");
authRequest.setForceAuthn(new Boolean(false));
authRequest.setIsPassive(new Boolean(false));
authRequest.setIssueInstant(issueInstant.plusHours(4));
authRequest.setProtocolBinding(
"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST");
authRequest.setAssertionConsumerServiceURL(consumerUrl);
authRequest.setDestination(idPDestinationUrlSSO);
authRequest.setIssuer(issuer);
authRequest.setID(authReqRandomId);
authRequest.setVersion(SAMLVersion.VERSION_20);
return authRequest;
}
然后这条消息被压缩并用Base64编码:
private String encodeRequestMessage(RequestAbstractType requestMessage)
throws MarshallingException, IOException {
Marshaller marshaller =
Configuration.getMarshallerFactory().getMarshaller(requestMessage);
Element authDOM = marshaller.marshall(requestMessage);
Deflater deflater = new Deflater(Deflater.DEFLATED, true);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
DeflaterOutputStream deflaterOutputStream =
new DeflaterOutputStream(byteArrayOutputStream,
deflater);
StringWriter rspWrt = new StringWriter();
XMLHelper.writeNode(authDOM, rspWrt);
deflaterOutputStream.write(rspWrt.toString().getBytes());
deflaterOutputStream.close();
String encodedRequestMessage =
Base64.encodeBytes(byteArrayOutputStream.toByteArray(),
Base64.DONT_BREAK_LINES);
return URLEncoder.encode(encodedRequestMessage, "UTF-8").trim();
}
因此,这部分 - "SAMLRequest ="+ SAMLRequest
- 形成了。
"https://domain_name_of_idp_here/idp/profile/SAML2/Redirect/SSO?" +
"SAMLRequest=" + encodedRequestMessage
至于 SigAlg。我使用 http%3A%2F%2Fwww.w3.org%2F2000%2F09%2Fxmldsig%23dsa-sha1
因此,这部分也就形成了。
"https://domain_name_of_idp_here/idp/profile/SAML2/Redirect/SSO?" +
"SAMLRequest=" + encodedRequestMessage + "&SigAlg=" + SigAlg
这部分的形成问题:
"&Signature=" + Signature
我得到了一个签名(但是这个方法没有给出签名):
public Signature getSignature() {
KeyStore keyStore =
KeyStore.getInstance(KeyStore.getDefaultType());
FileInputStream fileInputStream =
new FileInputStream(new File(jksFileName));
keyStore.load(fileInputStream, jksPassword);
fileInputStream.close();
KeyStore.PrivateKeyEntry privateKeyEntry =
(KeyStore.PrivateKeyEntry) keyStore.getEntry(alias,
new KeyStore.PasswordProtection(jksPassword));
PrivateKey privateKey = privateKeyEntry.getPrivateKey();
X509Certificate certificate =
(X509Certificate) privateKeyEntry.getCertificate();
BasicX509Credential credential = new BasicX509Credential();
credential.setEntityCertificate(certificate);
credential.setPrivateKey(privateKey);
Signature signature =
(Signature) org.opensaml.xml.Configuration.getBuilderFactory()
.getBuilder(org.opensaml.xml.signature.Signature.DEFAULT_ELEMENT_NAME)
.buildObject(org.opensaml.xml.signature.Signature.DEFAULT_ELEMENT_NAME);
signature.setSigningCredential(credential);
SecurityConfiguration securityConfiguration =
Configuration.getGlobalSecurityConfiguration();
String keyInfoGeneratorProfile = null;
SecurityHelper.prepareSignatureParams(signature,
credential, securityConfiguration, keyInfoGeneratorProfile);
return signature;
}
在方法 buildAuthnRequestObject()
中添加:
private AuthnRequest buildAuthnRequestObject() {
...
authRequest.setSignature(getSignature()); // <---- to sign the request
return authRequest;
}
此消息也使用 Base64 进行压缩和编码,并采用以下形式:
<?xml version="1.0" encoding="UTF-8"?>
<samlp:AuthnRequest AssertionConsumerServiceURL=
"https://ip_of_my_sp_here/EsiaChecker_war/resp/"
Destination=
"https://domain_name_of_idp_here/idp/profile/SAML2/Redirect/SSO"
ForceAuthn="false"
ID="0"
IsPassive="false"
IssueInstant="2014-09-1T19:07:42.718Z"
ProtocolBinding=
"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Version="2.0"
xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol">
<samlp:Issuer xmlns:samlp=
"urn:oasis:names:tc:SAML:2.0:assertion">my_issuer_here
</samlp:Issuer>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm=
"http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:SignatureMethod Algorithm=
"http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<ds:Reference URI="#0">
<ds:Transforms>
<ds:Transform Algorithm=
"http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
<ds:Transform Algorithm=
"http://www.w3.org/2001/10/xml-exc-c14n#"/>
</ds:Transforms>
<ds:DigestMethod Algorithm=
"http://www.w3.org/2000/09/xmldsig#sha1"/>
<ds:DigestValue/>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue/>
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>MIIEXD...0CFtd6whg==
</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</ds:Signature>
</samlp:AuthnRequest>
可以看出元素 SignatureValue
是空的。
如何使用 OpenSaml 获取签名并将其添加为 GET 请求参数?为此:"&Signature ="+ Signature.
最佳答案
有一个名为 HTTPRedirectDeflateEncoder 的组件可以帮助解决这个问题,添加信号、编码和压缩以及重定向用户。
我的博客上有一个使用示例,https://blog.samlsecurity.com/2011/01/redirect-with-authnrequest.html
我的书 A Guide to OpenSAML 中也有更广泛的用法示例
关于java - 签名作为身份验证请求中的参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25598788/