parent
7056c2d9de
commit
8904361a37
|
@ -117,5 +117,4 @@ public class Saml2WebSsoAuthenticationFilter extends AbstractAuthenticationProce
|
|||
return new String(b, UTF_8);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,17 +19,16 @@ package org.springframework.security.saml2.provider.service.authentication;
|
|||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.hamcrest.BaseMatcher;
|
||||
import org.hamcrest.Description;
|
||||
import org.hamcrest.Matcher;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Duration;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.opensaml.core.xml.XMLObject;
|
||||
import org.opensaml.saml.saml2.core.Assertion;
|
||||
import org.opensaml.saml.saml2.core.EncryptedAssertion;
|
||||
import org.opensaml.saml.saml2.core.EncryptedID;
|
||||
|
@ -37,15 +36,17 @@ import org.opensaml.saml.saml2.core.NameID;
|
|||
import org.opensaml.saml.saml2.core.Response;
|
||||
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.saml2.credentials.Saml2X509Credential;
|
||||
|
||||
import static java.util.Collections.emptyList;
|
||||
import static org.springframework.security.saml2.provider.service.authentication.Saml2CryptoTestSupport.encryptAssertion;
|
||||
import static org.springframework.security.saml2.provider.service.authentication.Saml2CryptoTestSupport.encryptNameId;
|
||||
import static org.springframework.security.saml2.provider.service.authentication.Saml2CryptoTestSupport.signXmlObject;
|
||||
import static org.springframework.security.saml2.provider.service.authentication.TestSaml2AuthenticationObjects.assertion;
|
||||
import static org.springframework.security.saml2.provider.service.authentication.TestSaml2AuthenticationObjects.response;
|
||||
import static org.springframework.security.saml2.provider.service.authentication.TestSaml2X509Credentials.assertingPartyCredentials;
|
||||
import static org.springframework.security.saml2.provider.service.authentication.TestSaml2X509Credentials.relyingPartyCredentials;
|
||||
import static org.springframework.security.saml2.provider.service.authentication.TestOpenSamlObjects.assertion;
|
||||
import static org.springframework.security.saml2.provider.service.authentication.TestOpenSamlObjects.encrypted;
|
||||
import static org.springframework.security.saml2.provider.service.authentication.TestOpenSamlObjects.response;
|
||||
import static org.springframework.security.saml2.provider.service.authentication.TestOpenSamlObjects.signed;
|
||||
import static org.springframework.security.saml2.provider.service.authentication.TestSaml2X509Credentials.assertingPartyEncryptingCredential;
|
||||
import static org.springframework.security.saml2.provider.service.authentication.TestSaml2X509Credentials.assertingPartyPrivateCredential;
|
||||
import static org.springframework.security.saml2.provider.service.authentication.TestSaml2X509Credentials.assertingPartySigningCredential;
|
||||
import static org.springframework.security.saml2.provider.service.authentication.TestSaml2X509Credentials.relyingPartyDecryptingCredential;
|
||||
import static org.springframework.security.saml2.provider.service.authentication.TestSaml2X509Credentials.relyingPartyVerifyingCredential;
|
||||
import static org.springframework.test.util.AssertionErrors.assertTrue;
|
||||
import static org.springframework.util.StringUtils.hasText;
|
||||
|
||||
|
@ -57,37 +58,23 @@ import static org.springframework.util.StringUtils.hasText;
|
|||
*/
|
||||
public class OpenSamlAuthenticationProviderTests {
|
||||
|
||||
private static String username = "test@saml.user";
|
||||
private static String recipientUri = "https://localhost/login/saml2/sso/idp-alias";
|
||||
private static String recipientEntityId = "https://localhost/saml2/service-provider-metadata/idp-alias";
|
||||
private static String idpEntityId = "https://some.idp.test/saml2/idp";
|
||||
private static String DESTINATION = "https://localhost/login/saml2/sso/idp-alias";
|
||||
private static String RELYING_PARTY_ENTITY_ID = "https://localhost/saml2/service-provider-metadata/idp-alias";
|
||||
private static String ASSERTING_PARTY_ENTITY_ID = "https://some.idp.test/saml2/idp";
|
||||
|
||||
private OpenSamlAuthenticationProvider provider = new OpenSamlAuthenticationProvider();
|
||||
private OpenSamlImplementation saml = OpenSamlImplementation.getInstance();
|
||||
|
||||
private OpenSamlAuthenticationProvider provider;
|
||||
private OpenSamlImplementation saml;
|
||||
private Saml2AuthenticationToken token;
|
||||
|
||||
@Rule
|
||||
public ExpectedException exception = ExpectedException.none();
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.saml = OpenSamlImplementation.getInstance();
|
||||
this.provider = new OpenSamlAuthenticationProvider();
|
||||
this.token = new Saml2AuthenticationToken(
|
||||
"responseXml",
|
||||
recipientUri,
|
||||
idpEntityId,
|
||||
recipientEntityId,
|
||||
relyingPartyCredentials()
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void supportsWhenSaml2AuthenticationTokenThenReturnTrue() {
|
||||
|
||||
assertTrue(
|
||||
OpenSamlAuthenticationProvider.class + "should support " + this.token.getClass(),
|
||||
this.provider.supports(this.token.getClass())
|
||||
OpenSamlAuthenticationProvider.class + "should support " + Saml2AuthenticationToken.class,
|
||||
this.provider.supports(Saml2AuthenticationToken.class)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -101,247 +88,191 @@ public class OpenSamlAuthenticationProviderTests {
|
|||
|
||||
@Test
|
||||
public void authenticateWhenUnknownDataClassThenThrowAuthenticationException() {
|
||||
Assertion assertion = defaultAssertion();
|
||||
this.token = responseXml(assertion);
|
||||
this.exception.expect(authenticationMatcher(Saml2ErrorCodes.UNKNOWN_RESPONSE_CLASS));
|
||||
this.provider.authenticate(this.token);
|
||||
|
||||
Assertion assertion = this.saml.buildSamlObject(Assertion.DEFAULT_ELEMENT_NAME);
|
||||
this.provider.authenticate(token(this.saml.serialize(assertion)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateWhenXmlErrorThenThrowAuthenticationException() {
|
||||
this.token = new Saml2AuthenticationToken(
|
||||
"invalid xml string",
|
||||
recipientUri,
|
||||
idpEntityId,
|
||||
recipientEntityId,
|
||||
relyingPartyCredentials()
|
||||
);
|
||||
this.exception.expect(authenticationMatcher(Saml2ErrorCodes.MALFORMED_RESPONSE_DATA));
|
||||
this.provider.authenticate(this.token);
|
||||
|
||||
Saml2AuthenticationToken token = token("invalid xml");
|
||||
this.provider.authenticate(token);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateWhenInvalidDestinationThenThrowAuthenticationException() {
|
||||
Response response = response(recipientUri + "invalid", idpEntityId);
|
||||
this.token = responseXml(response);
|
||||
this.exception.expect(authenticationMatcher(Saml2ErrorCodes.INVALID_DESTINATION));
|
||||
this.provider.authenticate(this.token);
|
||||
|
||||
Response response = response(DESTINATION + "invalid", ASSERTING_PARTY_ENTITY_ID);
|
||||
response.getAssertions().add(assertion());
|
||||
signed(response, assertingPartySigningCredential(), RELYING_PARTY_ENTITY_ID);
|
||||
Saml2AuthenticationToken token = token(response, relyingPartyVerifyingCredential());
|
||||
this.provider.authenticate(token);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateWhenNoAssertionsPresentThenThrowAuthenticationException() {
|
||||
Response response = response(recipientUri, idpEntityId);
|
||||
this.token = responseXml(response);
|
||||
this.exception.expect(
|
||||
authenticationMatcher(Saml2ErrorCodes.MALFORMED_RESPONSE_DATA, "No assertions found in response.")
|
||||
);
|
||||
this.provider.authenticate(this.token);
|
||||
|
||||
Saml2AuthenticationToken token = token(response(), assertingPartySigningCredential());
|
||||
this.provider.authenticate(token);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateWhenInvalidSignatureOnAssertionThenThrowAuthenticationException() {
|
||||
Response response = response(recipientUri, idpEntityId);
|
||||
Assertion assertion = defaultAssertion();
|
||||
response.getAssertions().add(assertion);
|
||||
this.token = responseXml(response);
|
||||
this.exception.expect(authenticationMatcher(Saml2ErrorCodes.INVALID_SIGNATURE));
|
||||
this.provider.authenticate(this.token);
|
||||
|
||||
Response response = response();
|
||||
response.getAssertions().add(assertion());
|
||||
Saml2AuthenticationToken token = token(response);
|
||||
this.provider.authenticate(token);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateWhenOpenSAMLValidationErrorThenThrowAuthenticationException() throws Exception {
|
||||
Response response = response(recipientUri, idpEntityId);
|
||||
Assertion assertion = defaultAssertion();
|
||||
this.exception.expect(authenticationMatcher(Saml2ErrorCodes.INVALID_ASSERTION));
|
||||
|
||||
Response response = response();
|
||||
Assertion assertion = assertion();
|
||||
assertion
|
||||
.getSubject()
|
||||
.getSubjectConfirmations()
|
||||
.get(0)
|
||||
.getSubjectConfirmationData()
|
||||
.setNotOnOrAfter(DateTime.now().minus(Duration.standardDays(3)));
|
||||
signXmlObject(
|
||||
assertion,
|
||||
assertingPartyCredentials(),
|
||||
recipientEntityId
|
||||
);
|
||||
signed(assertion, assertingPartySigningCredential(), RELYING_PARTY_ENTITY_ID);
|
||||
response.getAssertions().add(assertion);
|
||||
this.token = responseXml(response);
|
||||
|
||||
this.exception.expect(authenticationMatcher(Saml2ErrorCodes.INVALID_ASSERTION));
|
||||
this.provider.authenticate(this.token);
|
||||
Saml2AuthenticationToken token = token(response, relyingPartyVerifyingCredential());
|
||||
this.provider.authenticate(token);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateWhenMissingSubjectThenThrowAuthenticationException() {
|
||||
Response response = response(recipientUri, idpEntityId);
|
||||
Assertion assertion = defaultAssertion();
|
||||
assertion.setSubject(null);
|
||||
signXmlObject(
|
||||
assertion,
|
||||
assertingPartyCredentials(),
|
||||
recipientEntityId
|
||||
);
|
||||
response.getAssertions().add(assertion);
|
||||
this.token = responseXml(response);
|
||||
|
||||
this.exception.expect(authenticationMatcher(Saml2ErrorCodes.SUBJECT_NOT_FOUND));
|
||||
|
||||
Response response = response();
|
||||
Assertion assertion = assertion();
|
||||
assertion.setSubject(null);
|
||||
signed(assertion, assertingPartySigningCredential(), RELYING_PARTY_ENTITY_ID);
|
||||
response.getAssertions().add(assertion);
|
||||
Saml2AuthenticationToken token = token(response, relyingPartyVerifyingCredential());
|
||||
this.provider.authenticate(token);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateWhenUsernameMissingThenThrowAuthenticationException() throws Exception {
|
||||
Response response = response(recipientUri, idpEntityId);
|
||||
Assertion assertion = defaultAssertion();
|
||||
this.exception.expect(authenticationMatcher(Saml2ErrorCodes.USERNAME_NOT_FOUND));
|
||||
|
||||
Response response = response();
|
||||
Assertion assertion = assertion();
|
||||
assertion
|
||||
.getSubject()
|
||||
.getNameID()
|
||||
.setValue(null);
|
||||
signXmlObject(
|
||||
assertion,
|
||||
assertingPartyCredentials(),
|
||||
recipientEntityId
|
||||
);
|
||||
signed(assertion, assertingPartySigningCredential(), RELYING_PARTY_ENTITY_ID);
|
||||
response.getAssertions().add(assertion);
|
||||
this.token = responseXml(response);
|
||||
|
||||
this.exception.expect(authenticationMatcher(Saml2ErrorCodes.USERNAME_NOT_FOUND));
|
||||
this.provider.authenticate(this.token);
|
||||
Saml2AuthenticationToken token = token(response, relyingPartyVerifyingCredential());
|
||||
this.provider.authenticate(token);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateWhenAssertionContainsValidationAddressThenItSucceeds() throws Exception {
|
||||
Response response = response(recipientUri, idpEntityId);
|
||||
Assertion assertion = defaultAssertion();
|
||||
Response response = response();
|
||||
Assertion assertion = assertion();
|
||||
assertion.getSubject().getSubjectConfirmations().forEach(
|
||||
sc -> sc.getSubjectConfirmationData().setAddress("10.10.10.10")
|
||||
);
|
||||
signXmlObject(
|
||||
assertion,
|
||||
assertingPartyCredentials(),
|
||||
recipientEntityId
|
||||
);
|
||||
signed(assertion, assertingPartySigningCredential(), RELYING_PARTY_ENTITY_ID);
|
||||
response.getAssertions().add(assertion);
|
||||
this.token = responseXml(response);
|
||||
this.provider.authenticate(this.token);
|
||||
Saml2AuthenticationToken token = token(response, relyingPartyVerifyingCredential());
|
||||
this.provider.authenticate(token);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateWhenEncryptedAssertionWithoutSignatureThenItFails() throws Exception {
|
||||
Response response = response(recipientUri, idpEntityId);
|
||||
Assertion assertion = defaultAssertion();
|
||||
EncryptedAssertion encryptedAssertion = encryptAssertion(assertion, assertingPartyCredentials());
|
||||
response.getEncryptedAssertions().add(encryptedAssertion);
|
||||
this.token = responseXml(response);
|
||||
this.exception.expect(authenticationMatcher(Saml2ErrorCodes.INVALID_SIGNATURE));
|
||||
this.provider.authenticate(this.token);
|
||||
|
||||
Response response = response();
|
||||
EncryptedAssertion encryptedAssertion = encrypted(assertion(), assertingPartyEncryptingCredential());
|
||||
response.getEncryptedAssertions().add(encryptedAssertion);
|
||||
Saml2AuthenticationToken token = token(response, relyingPartyDecryptingCredential());
|
||||
this.provider.authenticate(token);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateWhenEncryptedAssertionWithSignatureThenItSucceeds() throws Exception {
|
||||
Response response = response(recipientUri, idpEntityId);
|
||||
Assertion assertion = defaultAssertion();
|
||||
signXmlObject(
|
||||
assertion,
|
||||
assertingPartyCredentials(),
|
||||
recipientEntityId
|
||||
);
|
||||
EncryptedAssertion encryptedAssertion = encryptAssertion(assertion, assertingPartyCredentials());
|
||||
Response response = response();
|
||||
Assertion assertion = signed(assertion(), assertingPartySigningCredential(), RELYING_PARTY_ENTITY_ID);
|
||||
EncryptedAssertion encryptedAssertion = encrypted(assertion, assertingPartyEncryptingCredential());
|
||||
response.getEncryptedAssertions().add(encryptedAssertion);
|
||||
this.token = responseXml(response);
|
||||
this.provider.authenticate(this.token);
|
||||
Saml2AuthenticationToken token = token(response, relyingPartyVerifyingCredential(), relyingPartyDecryptingCredential());
|
||||
this.provider.authenticate(token);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateWhenEncryptedAssertionWithResponseSignatureThenItSucceeds() throws Exception {
|
||||
Response response = response(recipientUri, idpEntityId);
|
||||
Assertion assertion = defaultAssertion();
|
||||
EncryptedAssertion encryptedAssertion = encryptAssertion(assertion, assertingPartyCredentials());
|
||||
Response response = response();
|
||||
EncryptedAssertion encryptedAssertion = encrypted(assertion(), assertingPartyEncryptingCredential());
|
||||
response.getEncryptedAssertions().add(encryptedAssertion);
|
||||
signXmlObject(
|
||||
response,
|
||||
assertingPartyCredentials(),
|
||||
recipientEntityId
|
||||
);
|
||||
this.token = responseXml(response);
|
||||
provider.authenticate(this.token);
|
||||
signed(response, assertingPartySigningCredential(), RELYING_PARTY_ENTITY_ID);
|
||||
Saml2AuthenticationToken token = token(response, relyingPartyVerifyingCredential(), relyingPartyDecryptingCredential());
|
||||
this.provider.authenticate(token);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateWhenEncryptedNameIdWithSignatureThenItSucceeds() throws Exception {
|
||||
Response response = response(recipientUri, idpEntityId);
|
||||
Assertion assertion = defaultAssertion();
|
||||
Response response = response();
|
||||
Assertion assertion = assertion();
|
||||
NameID nameId = assertion.getSubject().getNameID();
|
||||
EncryptedID encryptedID = encryptNameId(nameId, assertingPartyCredentials());
|
||||
EncryptedID encryptedID = encrypted(nameId, assertingPartyEncryptingCredential());
|
||||
assertion.getSubject().setNameID(null);
|
||||
assertion.getSubject().setEncryptedID(encryptedID);
|
||||
signXmlObject(
|
||||
assertion,
|
||||
assertingPartyCredentials(),
|
||||
recipientEntityId
|
||||
);
|
||||
response.getAssertions().add(assertion);
|
||||
this.token = responseXml(response);
|
||||
this.provider.authenticate(this.token);
|
||||
signed(assertion, assertingPartySigningCredential(), RELYING_PARTY_ENTITY_ID);
|
||||
Saml2AuthenticationToken token = token(response, relyingPartyVerifyingCredential(), relyingPartyDecryptingCredential());
|
||||
this.provider.authenticate(token);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void authenticateWhenDecryptionKeysAreMissingThenThrowAuthenticationException() throws Exception {
|
||||
Response response = response(recipientUri, idpEntityId);
|
||||
Assertion assertion = defaultAssertion();
|
||||
EncryptedAssertion encryptedAssertion = encryptAssertion(assertion, assertingPartyCredentials());
|
||||
response.getEncryptedAssertions().add(encryptedAssertion);
|
||||
this.token = responseXml(response);
|
||||
|
||||
this.token = new Saml2AuthenticationToken(
|
||||
this.token.getSaml2Response(),
|
||||
recipientUri,
|
||||
idpEntityId,
|
||||
recipientEntityId,
|
||||
emptyList()
|
||||
);
|
||||
|
||||
this.exception.expect(
|
||||
authenticationMatcher(Saml2ErrorCodes.DECRYPTION_ERROR, "No valid decryption credentials found.")
|
||||
);
|
||||
this.provider.authenticate(this.token);
|
||||
|
||||
Response response = response();
|
||||
EncryptedAssertion encryptedAssertion = encrypted(assertion(), assertingPartyEncryptingCredential());
|
||||
response.getEncryptedAssertions().add(encryptedAssertion);
|
||||
Saml2AuthenticationToken token = token(this.saml.serialize(response));
|
||||
this.provider.authenticate(token);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateWhenDecryptionKeysAreWrongThenThrowAuthenticationException() throws Exception {
|
||||
Response response = response(recipientUri, idpEntityId);
|
||||
Assertion assertion = defaultAssertion();
|
||||
EncryptedAssertion encryptedAssertion = encryptAssertion(assertion, assertingPartyCredentials());
|
||||
response.getEncryptedAssertions().add(encryptedAssertion);
|
||||
this.token = responseXml(response);
|
||||
|
||||
this.token = new Saml2AuthenticationToken(
|
||||
this.token.getSaml2Response(),
|
||||
recipientUri,
|
||||
idpEntityId,
|
||||
recipientEntityId,
|
||||
assertingPartyCredentials()
|
||||
);
|
||||
|
||||
this.exception.expect(
|
||||
authenticationMatcher(Saml2ErrorCodes.DECRYPTION_ERROR, "Failed to decrypt EncryptedData")
|
||||
);
|
||||
this.provider.authenticate(this.token);
|
||||
|
||||
Response response = response();
|
||||
EncryptedAssertion encryptedAssertion = encrypted(assertion(), assertingPartyEncryptingCredential());
|
||||
response.getEncryptedAssertions().add(encryptedAssertion);
|
||||
Saml2AuthenticationToken token = token(this.saml.serialize(response), assertingPartyPrivateCredential());
|
||||
this.provider.authenticate(token);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void writeObjectWhenTypeIsSaml2AuthenticationThenNoException() throws IOException {
|
||||
Response response = response(recipientUri, idpEntityId);
|
||||
Assertion assertion = defaultAssertion();
|
||||
signXmlObject(
|
||||
assertion,
|
||||
assertingPartyCredentials(),
|
||||
recipientEntityId
|
||||
);
|
||||
EncryptedAssertion encryptedAssertion = encryptAssertion(assertion, assertingPartyCredentials());
|
||||
Response response = response();
|
||||
Assertion assertion = signed(assertion(), assertingPartySigningCredential(), RELYING_PARTY_ENTITY_ID);
|
||||
EncryptedAssertion encryptedAssertion = encrypted(assertion, assertingPartyEncryptingCredential());
|
||||
response.getEncryptedAssertions().add(encryptedAssertion);
|
||||
this.token = responseXml(response);
|
||||
|
||||
Saml2Authentication authentication = (Saml2Authentication) this.provider.authenticate(this.token);
|
||||
Saml2AuthenticationToken token = token(response, relyingPartyVerifyingCredential(), relyingPartyDecryptingCredential());
|
||||
Saml2Authentication authentication = (Saml2Authentication) this.provider.authenticate(token);
|
||||
|
||||
// the following code will throw an exception if authentication isn't serializable
|
||||
ByteArrayOutputStream byteStream = new ByteArrayOutputStream(1024);
|
||||
|
@ -350,27 +281,6 @@ public class OpenSamlAuthenticationProviderTests {
|
|||
objectOutputStream.flush();
|
||||
}
|
||||
|
||||
private Assertion defaultAssertion() {
|
||||
return assertion(
|
||||
username,
|
||||
idpEntityId,
|
||||
recipientEntityId,
|
||||
recipientUri
|
||||
);
|
||||
}
|
||||
|
||||
private Saml2AuthenticationToken responseXml(XMLObject assertion) {
|
||||
String xml = this.saml.serialize(assertion);
|
||||
return new Saml2AuthenticationToken(
|
||||
xml,
|
||||
recipientUri,
|
||||
idpEntityId,
|
||||
recipientEntityId,
|
||||
relyingPartyCredentials()
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
private Matcher<Saml2AuthenticationException> authenticationMatcher(String code) {
|
||||
return authenticationMatcher(code, null);
|
||||
}
|
||||
|
@ -402,4 +312,14 @@ public class OpenSamlAuthenticationProviderTests {
|
|||
}
|
||||
};
|
||||
}
|
||||
|
||||
private Saml2AuthenticationToken token(Response response, Saml2X509Credential... credentials) {
|
||||
String payload = this.saml.serialize(response);
|
||||
return token(payload, credentials);
|
||||
}
|
||||
|
||||
private Saml2AuthenticationToken token(String payload, Saml2X509Credential... credentials) {
|
||||
return new Saml2AuthenticationToken(payload,
|
||||
DESTINATION, ASSERTING_PARTY_ENTITY_ID, RELYING_PARTY_ENTITY_ID, Arrays.asList(credentials));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import org.junit.Test;
|
|||
import org.junit.rules.ExpectedException;
|
||||
import org.opensaml.saml.common.xml.SAMLConstants;
|
||||
import org.opensaml.saml.saml2.core.AuthnRequest;
|
||||
|
||||
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
|
||||
import org.springframework.security.saml2.provider.service.registration.Saml2MessageBinding;
|
||||
|
||||
|
@ -30,7 +31,7 @@ import static java.nio.charset.StandardCharsets.UTF_8;
|
|||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.springframework.security.saml2.provider.service.authentication.Saml2Utils.samlDecode;
|
||||
import static org.springframework.security.saml2.provider.service.authentication.TestSaml2X509Credentials.relyingPartyCredentials;
|
||||
import static org.springframework.security.saml2.provider.service.authentication.TestSaml2X509Credentials.relyingPartySigningCredential;
|
||||
import static org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration.withRelyingPartyRegistration;
|
||||
import static org.springframework.security.saml2.provider.service.registration.Saml2MessageBinding.POST;
|
||||
import static org.springframework.security.saml2.provider.service.registration.Saml2MessageBinding.REDIRECT;
|
||||
|
@ -55,7 +56,7 @@ public class OpenSamlAuthenticationRequestFactoryTests {
|
|||
.providerDetails(c -> c.webSsoUrl("https://destination/sso"))
|
||||
.providerDetails(c -> c.entityId("remote-entity-id"))
|
||||
.localEntityIdTemplate("local-entity-id")
|
||||
.credentials(c -> c.addAll(relyingPartyCredentials()))
|
||||
.credentials(c -> c.add(relyingPartySigningCredential()))
|
||||
.build();
|
||||
contextBuilder = Saml2AuthenticationRequestContext.builder()
|
||||
.issuer("https://issuer")
|
||||
|
|
|
@ -16,24 +16,22 @@
|
|||
|
||||
package org.springframework.security.saml2.provider.service.authentication;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.opensaml.security.credential.BasicCredential;
|
||||
import org.opensaml.security.credential.Credential;
|
||||
import org.opensaml.security.credential.CredentialSupport;
|
||||
import org.opensaml.security.credential.UsageType;
|
||||
import org.opensaml.xmlsec.crypto.XMLSigningUtil;
|
||||
|
||||
import org.springframework.security.saml2.credentials.Saml2X509Credential;
|
||||
import org.springframework.web.util.UriUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.ISO_8859_1;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.opensaml.xmlsec.signature.support.SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256;
|
||||
import static org.springframework.security.saml2.provider.service.authentication.TestSaml2X509Credentials.assertingPartyCredentials;
|
||||
import static org.springframework.security.saml2.provider.service.authentication.TestSaml2X509Credentials.relyingPartyCredentials;
|
||||
import static org.springframework.security.saml2.provider.service.authentication.TestOpenSamlObjects.getSigningCredential;
|
||||
import static org.springframework.security.saml2.provider.service.authentication.TestSaml2X509Credentials.assertingPartySigningCredential;
|
||||
import static org.springframework.security.saml2.provider.service.authentication.TestSaml2X509Credentials.relyingPartyVerifyingCredential;
|
||||
|
||||
public class OpenSamlImplementationTests {
|
||||
|
||||
|
@ -45,12 +43,12 @@ public class OpenSamlImplementationTests {
|
|||
@Test
|
||||
public void signQueryParametersWhenDataSuppliedReturnsValidSignature() throws Exception {
|
||||
OpenSamlImplementation impl = OpenSamlImplementation.getInstance();
|
||||
List<Saml2X509Credential> signCredentials = relyingPartyCredentials();
|
||||
List<Saml2X509Credential> verifyCredentials = assertingPartyCredentials();
|
||||
Saml2X509Credential signingCredential = assertingPartySigningCredential();
|
||||
Saml2X509Credential verifyingCredential = relyingPartyVerifyingCredential();
|
||||
String samlRequest = "saml-request-example";
|
||||
String encoded = Saml2Utils.samlEncode(samlRequest.getBytes(UTF_8));
|
||||
String relayState = "test relay state";
|
||||
Map<String, String> parameters = impl.signQueryParameters(signCredentials, encoded, relayState);
|
||||
Map<String, String> parameters = impl.signQueryParameters(Arrays.asList(signingCredential), encoded, relayState);
|
||||
|
||||
String queryString = "SAMLRequest=" +
|
||||
UriUtils.encode(encoded, ISO_8859_1) +
|
||||
|
@ -62,21 +60,11 @@ public class OpenSamlImplementationTests {
|
|||
|
||||
byte[] signature = Saml2Utils.samlDecode(parameters.get("Signature"));
|
||||
boolean result = XMLSigningUtil.verifyWithURI(
|
||||
getOpenSamlCredential(verifyCredentials.get(1), "local-sp-entity-id", UsageType.SIGNING),
|
||||
getSigningCredential(verifyingCredential, "local-sp-entity-id"),
|
||||
ALGO_ID_SIGNATURE_RSA_SHA256,
|
||||
signature,
|
||||
queryString.getBytes(UTF_8)
|
||||
);
|
||||
assertThat(result).isTrue();
|
||||
}
|
||||
|
||||
private Credential getOpenSamlCredential(Saml2X509Credential credential, String localSpEntityId, UsageType usageType) {
|
||||
BasicCredential cred = CredentialSupport.getSimpleCredential(
|
||||
credential.getCertificate(),
|
||||
credential.getPrivateKey()
|
||||
);
|
||||
cred.setEntityId(localSpEntityId);
|
||||
cred.setUsageType(usageType);
|
||||
return cred;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,15 +16,16 @@
|
|||
|
||||
package org.springframework.security.saml2.provider.service.authentication;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.security.saml2.provider.service.authentication.Saml2Utils.samlDecode;
|
||||
import static org.springframework.security.saml2.provider.service.authentication.Saml2Utils.samlInflate;
|
||||
import static org.springframework.security.saml2.provider.service.authentication.TestSaml2X509Credentials.relyingPartyCredentials;
|
||||
import static org.springframework.security.saml2.provider.service.authentication.TestSaml2X509Credentials.relyingPartySigningCredential;
|
||||
|
||||
/**
|
||||
* Tests for {@link Saml2AuthenticationRequestFactory} default interface methods
|
||||
|
@ -36,7 +37,7 @@ public class Saml2AuthenticationRequestFactoryTests {
|
|||
.providerDetails(c -> c.webSsoUrl("https://example.com/destination"))
|
||||
.providerDetails(c -> c.entityId("remote-entity-id"))
|
||||
.localEntityIdTemplate("local-entity-id")
|
||||
.credentials(c -> c.addAll(relyingPartyCredentials()))
|
||||
.credentials(c -> c.add(relyingPartySigningCredential()))
|
||||
.build();
|
||||
|
||||
@Test
|
||||
|
|
|
@ -1,169 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.saml2.provider.service.authentication;
|
||||
|
||||
import org.springframework.security.saml2.Saml2Exception;
|
||||
import org.springframework.security.saml2.credentials.Saml2X509Credential;
|
||||
|
||||
import org.apache.xml.security.algorithms.JCEMapper;
|
||||
import org.apache.xml.security.encryption.XMLCipherParameters;
|
||||
import org.opensaml.core.xml.io.MarshallingException;
|
||||
import org.opensaml.saml.common.SignableSAMLObject;
|
||||
import org.opensaml.saml.saml2.core.Assertion;
|
||||
import org.opensaml.saml.saml2.core.EncryptedAssertion;
|
||||
import org.opensaml.saml.saml2.core.EncryptedID;
|
||||
import org.opensaml.saml.saml2.core.NameID;
|
||||
import org.opensaml.saml.saml2.encryption.Encrypter;
|
||||
import org.opensaml.security.SecurityException;
|
||||
import org.opensaml.security.credential.BasicCredential;
|
||||
import org.opensaml.security.credential.Credential;
|
||||
import org.opensaml.security.credential.CredentialSupport;
|
||||
import org.opensaml.security.credential.UsageType;
|
||||
import org.opensaml.security.x509.BasicX509Credential;
|
||||
import org.opensaml.xmlsec.SignatureSigningParameters;
|
||||
import org.opensaml.xmlsec.encryption.support.DataEncryptionParameters;
|
||||
import org.opensaml.xmlsec.encryption.support.EncryptionException;
|
||||
import org.opensaml.xmlsec.encryption.support.KeyEncryptionParameters;
|
||||
import org.opensaml.xmlsec.signature.support.SignatureConstants;
|
||||
import org.opensaml.xmlsec.signature.support.SignatureException;
|
||||
import org.opensaml.xmlsec.signature.support.SignatureSupport;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.List;
|
||||
import javax.crypto.SecretKey;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.opensaml.security.crypto.KeySupport.generateKey;
|
||||
|
||||
final class Saml2CryptoTestSupport {
|
||||
static void signXmlObject(SignableSAMLObject object, List<Saml2X509Credential> signingCredentials, String entityId) {
|
||||
SignatureSigningParameters parameters = new SignatureSigningParameters();
|
||||
Credential credential = getSigningCredential(signingCredentials, entityId);
|
||||
parameters.setSigningCredential(credential);
|
||||
parameters.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256);
|
||||
parameters.setSignatureReferenceDigestMethod(SignatureConstants.ALGO_ID_DIGEST_SHA256);
|
||||
parameters.setSignatureCanonicalizationAlgorithm(SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);
|
||||
try {
|
||||
SignatureSupport.signObject(object, parameters);
|
||||
} catch (MarshallingException | SignatureException | SecurityException e) {
|
||||
throw new Saml2Exception(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static EncryptedAssertion encryptAssertion(Assertion assertion, List<Saml2X509Credential> encryptionCredentials) {
|
||||
X509Certificate certificate = getEncryptionCertificate(encryptionCredentials);
|
||||
Encrypter encrypter = getEncrypter(certificate);
|
||||
try {
|
||||
Encrypter.KeyPlacement keyPlacement = Encrypter.KeyPlacement.valueOf("PEER");
|
||||
encrypter.setKeyPlacement(keyPlacement);
|
||||
return encrypter.encrypt(assertion);
|
||||
}
|
||||
catch (EncryptionException e) {
|
||||
throw new Saml2Exception("Unable to encrypt assertion.", e);
|
||||
}
|
||||
}
|
||||
|
||||
static EncryptedID encryptNameId(NameID nameID, List<Saml2X509Credential> encryptionCredentials) {
|
||||
X509Certificate certificate = getEncryptionCertificate(encryptionCredentials);
|
||||
Encrypter encrypter = getEncrypter(certificate);
|
||||
try {
|
||||
Encrypter.KeyPlacement keyPlacement = Encrypter.KeyPlacement.valueOf("PEER");
|
||||
encrypter.setKeyPlacement(keyPlacement);
|
||||
return encrypter.encrypt(nameID);
|
||||
}
|
||||
catch (EncryptionException e) {
|
||||
throw new Saml2Exception("Unable to encrypt nameID.", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static Encrypter getEncrypter(X509Certificate certificate) {
|
||||
Credential credential = CredentialSupport.getSimpleCredential(certificate, null);
|
||||
final String dataAlgorithm = XMLCipherParameters.AES_256;
|
||||
final String keyAlgorithm = XMLCipherParameters.RSA_1_5;
|
||||
SecretKey secretKey = generateKeyFromURI(dataAlgorithm);
|
||||
BasicCredential dataCredential = new BasicCredential(secretKey);
|
||||
DataEncryptionParameters dataEncryptionParameters = new DataEncryptionParameters();
|
||||
dataEncryptionParameters.setEncryptionCredential(dataCredential);
|
||||
dataEncryptionParameters.setAlgorithm(dataAlgorithm);
|
||||
|
||||
KeyEncryptionParameters keyEncryptionParameters = new KeyEncryptionParameters();
|
||||
keyEncryptionParameters.setEncryptionCredential(credential);
|
||||
keyEncryptionParameters.setAlgorithm(keyAlgorithm);
|
||||
|
||||
Encrypter encrypter = new Encrypter(dataEncryptionParameters, asList(keyEncryptionParameters));
|
||||
|
||||
return encrypter;
|
||||
}
|
||||
|
||||
private static SecretKey generateKeyFromURI(String algoURI) {
|
||||
try {
|
||||
String jceAlgorithmName = JCEMapper.getJCEKeyAlgorithmFromURI(algoURI);
|
||||
int keyLength = JCEMapper.getKeyLengthFromURI(algoURI);
|
||||
return generateKey(jceAlgorithmName, keyLength, null);
|
||||
}
|
||||
catch (NoSuchAlgorithmException | NoSuchProviderException e) {
|
||||
throw new Saml2Exception(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static X509Certificate getEncryptionCertificate(List<Saml2X509Credential> encryptionCredentials) {
|
||||
X509Certificate certificate = null;
|
||||
for (Saml2X509Credential credential : encryptionCredentials) {
|
||||
if (credential.isEncryptionCredential()) {
|
||||
certificate = credential.getCertificate();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (certificate == null) {
|
||||
throw new Saml2Exception("No valid encryption certificate found");
|
||||
}
|
||||
return certificate;
|
||||
}
|
||||
|
||||
private static Saml2X509Credential hasSigningCredential(List<Saml2X509Credential> credentials) {
|
||||
for (Saml2X509Credential c : credentials) {
|
||||
if (c.isSigningCredential()) {
|
||||
return c;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Credential getSigningCredential(List<Saml2X509Credential> signingCredential,
|
||||
String localSpEntityId
|
||||
) {
|
||||
Saml2X509Credential credential = hasSigningCredential(signingCredential);
|
||||
if (credential == null) {
|
||||
throw new Saml2Exception("no signing credential configured");
|
||||
}
|
||||
BasicCredential cred = getBasicCredential(credential);
|
||||
cred.setEntityId(localSpEntityId);
|
||||
cred.setUsageType(UsageType.SIGNING);
|
||||
return cred;
|
||||
}
|
||||
|
||||
private static BasicX509Credential getBasicCredential(Saml2X509Credential credential) {
|
||||
return CredentialSupport.getSimpleCredential(
|
||||
credential.getCertificate(),
|
||||
credential.getPrivateKey()
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,225 @@
|
|||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.saml2.provider.service.authentication;
|
||||
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Base64;
|
||||
import java.util.UUID;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
import org.apache.xml.security.encryption.XMLCipherParameters;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Duration;
|
||||
import org.opensaml.core.xml.io.MarshallingException;
|
||||
import org.opensaml.saml.common.SAMLVersion;
|
||||
import org.opensaml.saml.common.SignableSAMLObject;
|
||||
import org.opensaml.saml.saml2.core.Assertion;
|
||||
import org.opensaml.saml.saml2.core.Conditions;
|
||||
import org.opensaml.saml.saml2.core.EncryptedAssertion;
|
||||
import org.opensaml.saml.saml2.core.EncryptedID;
|
||||
import org.opensaml.saml.saml2.core.Issuer;
|
||||
import org.opensaml.saml.saml2.core.NameID;
|
||||
import org.opensaml.saml.saml2.core.Response;
|
||||
import org.opensaml.saml.saml2.core.Subject;
|
||||
import org.opensaml.saml.saml2.core.SubjectConfirmation;
|
||||
import org.opensaml.saml.saml2.core.SubjectConfirmationData;
|
||||
import org.opensaml.saml.saml2.encryption.Encrypter;
|
||||
import org.opensaml.security.SecurityException;
|
||||
import org.opensaml.security.credential.BasicCredential;
|
||||
import org.opensaml.security.credential.Credential;
|
||||
import org.opensaml.security.credential.CredentialSupport;
|
||||
import org.opensaml.security.credential.UsageType;
|
||||
import org.opensaml.xmlsec.SignatureSigningParameters;
|
||||
import org.opensaml.xmlsec.encryption.support.DataEncryptionParameters;
|
||||
import org.opensaml.xmlsec.encryption.support.EncryptionException;
|
||||
import org.opensaml.xmlsec.encryption.support.KeyEncryptionParameters;
|
||||
import org.opensaml.xmlsec.signature.support.SignatureConstants;
|
||||
import org.opensaml.xmlsec.signature.support.SignatureException;
|
||||
import org.opensaml.xmlsec.signature.support.SignatureSupport;
|
||||
|
||||
import org.springframework.security.saml2.Saml2Exception;
|
||||
import org.springframework.security.saml2.credentials.Saml2X509Credential;
|
||||
|
||||
final class TestOpenSamlObjects {
|
||||
private static OpenSamlImplementation saml = OpenSamlImplementation.getInstance();
|
||||
|
||||
private static String USERNAME = "test@saml.user";
|
||||
private static String DESTINATION = "https://localhost/login/saml2/sso/idp-alias";
|
||||
private static String RELYING_PARTY_ENTITY_ID = "https://localhost/saml2/service-provider-metadata/idp-alias";
|
||||
private static String ASSERTING_PARTY_ENTITY_ID = "https://some.idp.test/saml2/idp";
|
||||
private static SecretKey SECRET_KEY =
|
||||
new SecretKeySpec(Base64.getDecoder().decode("shOnwNMoCv88HKMEa91+FlYoD5RNvzMTAL5LGxZKIFk="), "AES");
|
||||
|
||||
static Response response() {
|
||||
return response(DESTINATION, ASSERTING_PARTY_ENTITY_ID);
|
||||
}
|
||||
|
||||
static Response response(String destination, String issuerEntityId) {
|
||||
Response response = saml.buildSamlObject(Response.DEFAULT_ELEMENT_NAME);
|
||||
response.setID("R"+UUID.randomUUID().toString());
|
||||
response.setIssueInstant(DateTime.now());
|
||||
response.setVersion(SAMLVersion.VERSION_20);
|
||||
response.setID("_" + UUID.randomUUID().toString());
|
||||
response.setDestination(destination);
|
||||
response.setIssuer(issuer(issuerEntityId));
|
||||
return response;
|
||||
}
|
||||
|
||||
static Assertion assertion() {
|
||||
return assertion(USERNAME, ASSERTING_PARTY_ENTITY_ID, RELYING_PARTY_ENTITY_ID, DESTINATION);
|
||||
}
|
||||
|
||||
static Assertion assertion(
|
||||
String username,
|
||||
String issuerEntityId,
|
||||
String recipientEntityId,
|
||||
String recipientUri
|
||||
) {
|
||||
Assertion assertion = saml.buildSamlObject(Assertion.DEFAULT_ELEMENT_NAME);
|
||||
assertion.setID("A"+ UUID.randomUUID().toString());
|
||||
assertion.setIssueInstant(DateTime.now());
|
||||
assertion.setVersion(SAMLVersion.VERSION_20);
|
||||
assertion.setIssueInstant(DateTime.now());
|
||||
assertion.setIssuer(issuer(issuerEntityId));
|
||||
assertion.setSubject(subject(username));
|
||||
assertion.setConditions(conditions());
|
||||
|
||||
SubjectConfirmation subjectConfirmation = subjectConfirmation();
|
||||
subjectConfirmation.setMethod(SubjectConfirmation.METHOD_BEARER);
|
||||
SubjectConfirmationData confirmationData = subjectConfirmationData(recipientEntityId);
|
||||
confirmationData.setRecipient(recipientUri);
|
||||
subjectConfirmation.setSubjectConfirmationData(confirmationData);
|
||||
assertion.getSubject().getSubjectConfirmations().add(subjectConfirmation);
|
||||
return assertion;
|
||||
}
|
||||
|
||||
|
||||
static Issuer issuer(String entityId) {
|
||||
Issuer issuer = saml.buildSamlObject(Issuer.DEFAULT_ELEMENT_NAME);
|
||||
issuer.setValue(entityId);
|
||||
return issuer;
|
||||
}
|
||||
|
||||
static Subject subject(String principalName) {
|
||||
Subject subject = saml.buildSamlObject(Subject.DEFAULT_ELEMENT_NAME);
|
||||
|
||||
if (principalName != null) {
|
||||
subject.setNameID(nameId(principalName));
|
||||
}
|
||||
|
||||
return subject;
|
||||
}
|
||||
|
||||
static NameID nameId(String principalName) {
|
||||
NameID nameId = saml.buildSamlObject(NameID.DEFAULT_ELEMENT_NAME);
|
||||
nameId.setValue(principalName);
|
||||
return nameId;
|
||||
}
|
||||
|
||||
static SubjectConfirmation subjectConfirmation() {
|
||||
return saml.buildSamlObject(SubjectConfirmation.DEFAULT_ELEMENT_NAME);
|
||||
}
|
||||
|
||||
static SubjectConfirmationData subjectConfirmationData(String recipient) {
|
||||
SubjectConfirmationData subject = saml.buildSamlObject(SubjectConfirmationData.DEFAULT_ELEMENT_NAME);
|
||||
subject.setRecipient(recipient);
|
||||
subject.setNotBefore(DateTime.now().minus(Duration.millis(5 * 60 * 1000)));
|
||||
subject.setNotOnOrAfter(DateTime.now().plus(Duration.millis(5 * 60 * 1000)));
|
||||
return subject;
|
||||
}
|
||||
|
||||
static Conditions conditions() {
|
||||
Conditions conditions = saml.buildSamlObject(Conditions.DEFAULT_ELEMENT_NAME);
|
||||
conditions.setNotBefore(DateTime.now().minus(Duration.millis(5 * 60 * 1000)));
|
||||
conditions.setNotOnOrAfter(DateTime.now().plus(Duration.millis(5 * 60 * 1000)));
|
||||
return conditions;
|
||||
}
|
||||
|
||||
static Credential getSigningCredential(Saml2X509Credential credential, String entityId) {
|
||||
BasicCredential cred = getBasicCredential(credential);
|
||||
cred.setEntityId(entityId);
|
||||
cred.setUsageType(UsageType.SIGNING);
|
||||
return cred;
|
||||
}
|
||||
|
||||
static BasicCredential getBasicCredential(Saml2X509Credential credential) {
|
||||
return CredentialSupport.getSimpleCredential(
|
||||
credential.getCertificate(),
|
||||
credential.getPrivateKey()
|
||||
);
|
||||
}
|
||||
|
||||
static <T extends SignableSAMLObject> T signed(T signable, Saml2X509Credential credential, String entityId) {
|
||||
SignatureSigningParameters parameters = new SignatureSigningParameters();
|
||||
Credential signingCredential = getSigningCredential(credential, entityId);
|
||||
parameters.setSigningCredential(signingCredential);
|
||||
parameters.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256);
|
||||
parameters.setSignatureReferenceDigestMethod(SignatureConstants.ALGO_ID_DIGEST_SHA256);
|
||||
parameters.setSignatureCanonicalizationAlgorithm(SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);
|
||||
try {
|
||||
SignatureSupport.signObject(signable, parameters);
|
||||
} catch (MarshallingException | SignatureException | SecurityException e) {
|
||||
throw new Saml2Exception(e);
|
||||
}
|
||||
|
||||
return signable;
|
||||
}
|
||||
|
||||
static EncryptedAssertion encrypted(Assertion assertion, Saml2X509Credential credential) {
|
||||
X509Certificate certificate = credential.getCertificate();
|
||||
Encrypter encrypter = getEncrypter(certificate);
|
||||
try {
|
||||
return encrypter.encrypt(assertion);
|
||||
}
|
||||
catch (EncryptionException e) {
|
||||
throw new Saml2Exception("Unable to encrypt assertion.", e);
|
||||
}
|
||||
}
|
||||
|
||||
static EncryptedID encrypted(NameID nameId, Saml2X509Credential credential) {
|
||||
X509Certificate certificate = credential.getCertificate();
|
||||
Encrypter encrypter = getEncrypter(certificate);
|
||||
try {
|
||||
return encrypter.encrypt(nameId);
|
||||
}
|
||||
catch (EncryptionException e) {
|
||||
throw new Saml2Exception("Unable to encrypt nameID.", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static Encrypter getEncrypter(X509Certificate certificate) {
|
||||
String dataAlgorithm = XMLCipherParameters.AES_256;
|
||||
String keyAlgorithm = XMLCipherParameters.RSA_1_5;
|
||||
|
||||
BasicCredential dataCredential = new BasicCredential(SECRET_KEY);
|
||||
DataEncryptionParameters dataEncryptionParameters = new DataEncryptionParameters();
|
||||
dataEncryptionParameters.setEncryptionCredential(dataCredential);
|
||||
dataEncryptionParameters.setAlgorithm(dataAlgorithm);
|
||||
|
||||
Credential credential = CredentialSupport.getSimpleCredential(certificate, null);
|
||||
KeyEncryptionParameters keyEncryptionParameters = new KeyEncryptionParameters();
|
||||
keyEncryptionParameters.setEncryptionCredential(credential);
|
||||
keyEncryptionParameters.setAlgorithm(keyAlgorithm);
|
||||
|
||||
Encrypter encrypter = new Encrypter(dataEncryptionParameters, keyEncryptionParameters);
|
||||
Encrypter.KeyPlacement keyPlacement = Encrypter.KeyPlacement.valueOf("PEER");
|
||||
encrypter.setKeyPlacement(keyPlacement);
|
||||
|
||||
return encrypter;
|
||||
}
|
||||
}
|
|
@ -1,112 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.saml2.provider.service.authentication;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Duration;
|
||||
import org.opensaml.saml.common.SAMLVersion;
|
||||
import org.opensaml.saml.saml2.core.Assertion;
|
||||
import org.opensaml.saml.saml2.core.Conditions;
|
||||
import org.opensaml.saml.saml2.core.Issuer;
|
||||
import org.opensaml.saml.saml2.core.NameID;
|
||||
import org.opensaml.saml.saml2.core.Response;
|
||||
import org.opensaml.saml.saml2.core.Subject;
|
||||
import org.opensaml.saml.saml2.core.SubjectConfirmation;
|
||||
import org.opensaml.saml.saml2.core.SubjectConfirmationData;
|
||||
|
||||
final class TestSaml2AuthenticationObjects {
|
||||
private static OpenSamlImplementation saml = OpenSamlImplementation.getInstance();
|
||||
|
||||
static Response response(String destination, String issuerEntityId) {
|
||||
Response response = saml.buildSamlObject(Response.DEFAULT_ELEMENT_NAME);
|
||||
response.setID("R"+UUID.randomUUID().toString());
|
||||
response.setIssueInstant(DateTime.now());
|
||||
response.setVersion(SAMLVersion.VERSION_20);
|
||||
response.setID("_" + UUID.randomUUID().toString());
|
||||
response.setDestination(destination);
|
||||
response.setIssuer(issuer(issuerEntityId));
|
||||
return response;
|
||||
}
|
||||
static Assertion assertion(
|
||||
String username,
|
||||
String issuerEntityId,
|
||||
String recipientEntityId,
|
||||
String recipientUri
|
||||
) {
|
||||
Assertion assertion = saml.buildSamlObject(Assertion.DEFAULT_ELEMENT_NAME);
|
||||
assertion.setID("A"+ UUID.randomUUID().toString());
|
||||
assertion.setIssueInstant(DateTime.now());
|
||||
assertion.setVersion(SAMLVersion.VERSION_20);
|
||||
assertion.setIssueInstant(DateTime.now());
|
||||
assertion.setIssuer(issuer(issuerEntityId));
|
||||
assertion.setSubject(subject(username));
|
||||
assertion.setConditions(conditions());
|
||||
|
||||
SubjectConfirmation subjectConfirmation = subjectConfirmation();
|
||||
subjectConfirmation.setMethod(SubjectConfirmation.METHOD_BEARER);
|
||||
SubjectConfirmationData confirmationData = subjectConfirmationData(recipientEntityId);
|
||||
confirmationData.setRecipient(recipientUri);
|
||||
subjectConfirmation.setSubjectConfirmationData(confirmationData);
|
||||
assertion.getSubject().getSubjectConfirmations().add(subjectConfirmation);
|
||||
return assertion;
|
||||
}
|
||||
|
||||
|
||||
static Issuer issuer(String entityId) {
|
||||
Issuer issuer = saml.buildSamlObject(Issuer.DEFAULT_ELEMENT_NAME);
|
||||
issuer.setValue(entityId);
|
||||
return issuer;
|
||||
}
|
||||
|
||||
static Subject subject(String principalName) {
|
||||
Subject subject = saml.buildSamlObject(Subject.DEFAULT_ELEMENT_NAME);
|
||||
|
||||
if (principalName != null) {
|
||||
subject.setNameID(nameId(principalName));
|
||||
}
|
||||
|
||||
return subject;
|
||||
}
|
||||
|
||||
static NameID nameId(String principalName) {
|
||||
NameID nameId = saml.buildSamlObject(NameID.DEFAULT_ELEMENT_NAME);
|
||||
nameId.setValue(principalName);
|
||||
return nameId;
|
||||
}
|
||||
|
||||
static SubjectConfirmation subjectConfirmation() {
|
||||
return saml.buildSamlObject(SubjectConfirmation.DEFAULT_ELEMENT_NAME);
|
||||
}
|
||||
|
||||
static SubjectConfirmationData subjectConfirmationData(String recipient) {
|
||||
SubjectConfirmationData subject = saml.buildSamlObject(SubjectConfirmationData.DEFAULT_ELEMENT_NAME);
|
||||
subject.setRecipient(recipient);
|
||||
subject.setNotBefore(DateTime.now().minus(Duration.millis(5 * 60 * 1000)));
|
||||
subject.setNotOnOrAfter(DateTime.now().plus(Duration.millis(5 * 60 * 1000)));
|
||||
return subject;
|
||||
}
|
||||
|
||||
static Conditions conditions() {
|
||||
Conditions conditions = saml.buildSamlObject(Conditions.DEFAULT_ELEMENT_NAME);
|
||||
conditions.setNotBefore(DateTime.now().minus(Duration.millis(5 * 60 * 1000)));
|
||||
conditions.setNotOnOrAfter(DateTime.now().plus(Duration.millis(5 * 60 * 1000)));
|
||||
return conditions;
|
||||
}
|
||||
|
||||
}
|
|
@ -16,19 +16,17 @@
|
|||
|
||||
package org.springframework.security.saml2.provider.service.authentication;
|
||||
|
||||
import org.springframework.security.saml2.Saml2Exception;
|
||||
import org.springframework.security.saml2.credentials.Saml2X509Credential;
|
||||
|
||||
import org.opensaml.security.crypto.KeySupport;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.security.KeyException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.opensaml.security.crypto.KeySupport;
|
||||
|
||||
import org.springframework.security.saml2.Saml2Exception;
|
||||
import org.springframework.security.saml2.credentials.Saml2X509Credential;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static org.springframework.security.saml2.credentials.Saml2X509Credential.Saml2X509CredentialType.DECRYPTION;
|
||||
|
@ -37,36 +35,28 @@ import static org.springframework.security.saml2.credentials.Saml2X509Credential
|
|||
import static org.springframework.security.saml2.credentials.Saml2X509Credential.Saml2X509CredentialType.VERIFICATION;
|
||||
|
||||
final class TestSaml2X509Credentials {
|
||||
static List<Saml2X509Credential> assertingPartyCredentials() {
|
||||
return Arrays.asList(
|
||||
new Saml2X509Credential(
|
||||
idpPrivateKey(),
|
||||
idpCertificate(),
|
||||
SIGNING,
|
||||
DECRYPTION
|
||||
),
|
||||
new Saml2X509Credential(
|
||||
spCertificate(),
|
||||
ENCRYPTION,
|
||||
VERIFICATION
|
||||
)
|
||||
);
|
||||
static Saml2X509Credential assertingPartySigningCredential() {
|
||||
return new Saml2X509Credential(idpPrivateKey(), idpCertificate(), SIGNING);
|
||||
}
|
||||
|
||||
static List<Saml2X509Credential> relyingPartyCredentials() {
|
||||
return Arrays.asList(
|
||||
new Saml2X509Credential(
|
||||
spPrivateKey(),
|
||||
spCertificate(),
|
||||
SIGNING,
|
||||
DECRYPTION
|
||||
),
|
||||
new Saml2X509Credential(
|
||||
idpCertificate(),
|
||||
ENCRYPTION,
|
||||
VERIFICATION
|
||||
)
|
||||
);
|
||||
static Saml2X509Credential assertingPartyEncryptingCredential() {
|
||||
return new Saml2X509Credential(spCertificate(), ENCRYPTION);
|
||||
}
|
||||
|
||||
static Saml2X509Credential assertingPartyPrivateCredential() {
|
||||
return new Saml2X509Credential(idpPrivateKey(), idpCertificate(), SIGNING, DECRYPTION);
|
||||
}
|
||||
|
||||
static Saml2X509Credential relyingPartyVerifyingCredential() {
|
||||
return new Saml2X509Credential(idpCertificate(), VERIFICATION);
|
||||
}
|
||||
|
||||
static Saml2X509Credential relyingPartySigningCredential() {
|
||||
return new Saml2X509Credential(spPrivateKey(), spCertificate(), SIGNING);
|
||||
}
|
||||
|
||||
static Saml2X509Credential relyingPartyDecryptingCredential() {
|
||||
return new Saml2X509Credential(spPrivateKey(), spCertificate(), DECRYPTION);
|
||||
}
|
||||
|
||||
private static X509Certificate certificate(String cert) {
|
||||
|
|
Loading…
Reference in New Issue