I should get a GET authentication request with a certain set of parameters:
"https://domain_name_of_idp_here/idp/profile/SAML2/Redirect/SSO?" +
"SAMLRequest=" + SAMLRequest + "&SigAlg=" + SigAlg + "&Signature=" + Signature
Thus, I'm interested in the parameters:
When I used OIOSAML, all these parts of the request formed automatically, but it was not possible to flexibly manage them and get full control.
So I decided to write my sP- based Web SSO by using OpenSAML 2.4.1
Consider how to create SAMLRequest. My idP requires that sP- AuthnRequest requests come in this format:
<?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>
Therefore SAMLRequest I form as follows:
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;
}
Then this message is compressed and encoded in 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();
}
Thus, this part - "SAMLRequest =" + SAMLRequest
- is formed.
"https://domain_name_of_idp_here/idp/profile/SAML2/Redirect/SSO?" +
"SAMLRequest=" + encodedRequestMessage
As for SigAlg. I use http%3A%2F%2Fwww.w3.org%2F2000%2F09%2Fxmldsig%23dsa-sha1
Therefore, this part also is formed.
"https://domain_name_of_idp_here/idp/profile/SAML2/Redirect/SSO?" +
"SAMLRequest=" + encodedRequestMessage + "&SigAlg=" + SigAlg
Question in forming of this part:
"&Signature=" + Signature
I get a signature so (but this method does not give the 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;
}
In the method buildAuthnRequestObject()
is added:
private AuthnRequest buildAuthnRequestObject() {
...
authRequest.setSignature(getSignature()); // <---- to sign the request
return authRequest;
}
This message also compressed and encoded in Base64 and takes the form:
<?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>
It is seen that the element SignatureValue
is empty.
How can I get the signature using OpenSaml and add it as a GET request parameter? To make it so: "&Signature =" + Signature.
There is a component called HTTPRedirectDeflateEncoder that will help with this, adding the sigalg, encoding and deflating and redirecting the user.
I have an example of usage on my blog, https://blog.samlsecurity.com/2011/01/redirect-with-authnrequest.html
I also have wider examples of its usage in my book, A Guide to OpenSAML