Skip to content

Commit c8cbf06

Browse files
committed
Add EncryptedAttribute support
Closes gh-9131
1 parent d0581c9 commit c8cbf06

File tree

3 files changed

+54
-0
lines changed

3 files changed

+54
-0
lines changed

saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/OpenSamlAuthenticationProvider.java

+12
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
import org.opensaml.saml.saml2.core.AttributeStatement;
7070
import org.opensaml.saml.saml2.core.Condition;
7171
import org.opensaml.saml.saml2.core.EncryptedAssertion;
72+
import org.opensaml.saml.saml2.core.EncryptedAttribute;
7273
import org.opensaml.saml.saml2.core.NameID;
7374
import org.opensaml.saml.saml2.core.OneTimeUse;
7475
import org.opensaml.saml.saml2.core.Response;
@@ -647,6 +648,17 @@ private Consumer<AssertionToken> createDefaultAssertionElementsDecrypter() {
647648
return (assertionToken) -> {
648649
Decrypter decrypter = this.decrypterConverter.convert(assertionToken.getToken());
649650
Assertion assertion = assertionToken.getAssertion();
651+
for (AttributeStatement statement : assertion.getAttributeStatements()) {
652+
for (EncryptedAttribute encryptedAttribute : statement.getEncryptedAttributes()) {
653+
try {
654+
Attribute attribute = decrypter.decrypt(encryptedAttribute);
655+
statement.getAttributes().add(attribute);
656+
}
657+
catch (Exception ex) {
658+
throw createAuthenticationException(Saml2ErrorCodes.DECRYPTION_ERROR, ex.getMessage(), ex);
659+
}
660+
}
661+
}
650662
if (assertion.getSubject() == null) {
651663
return;
652664
}

saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/authentication/OpenSamlAuthenticationProviderTests.java

+20
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import org.opensaml.saml.saml2.core.Assertion;
4444
import org.opensaml.saml.saml2.core.AttributeStatement;
4545
import org.opensaml.saml.saml2.core.EncryptedAssertion;
46+
import org.opensaml.saml.saml2.core.EncryptedAttribute;
4647
import org.opensaml.saml.saml2.core.EncryptedID;
4748
import org.opensaml.saml.saml2.core.NameID;
4849
import org.opensaml.saml.saml2.core.OneTimeUse;
@@ -298,6 +299,25 @@ public void authenticateWhenEncryptedNameIdWithSignatureThenItSucceeds() throws
298299
this.provider.authenticate(token);
299300
}
300301

302+
@Test
303+
public void authenticateWhenEncryptedAttributeThenDecrypts() {
304+
Response response = TestOpenSamlObjects.response();
305+
Assertion assertion = TestOpenSamlObjects.assertion();
306+
EncryptedAttribute attribute = TestOpenSamlObjects.encrypted("name", "value",
307+
TestSaml2X509Credentials.assertingPartyEncryptingCredential());
308+
AttributeStatement statement = build(AttributeStatement.DEFAULT_ELEMENT_NAME);
309+
statement.getEncryptedAttributes().add(attribute);
310+
assertion.getAttributeStatements().add(statement);
311+
response.getAssertions().add(assertion);
312+
TestOpenSamlObjects.signed(response, TestSaml2X509Credentials.assertingPartySigningCredential(),
313+
RELYING_PARTY_ENTITY_ID);
314+
Saml2AuthenticationToken token = token(response, TestSaml2X509Credentials.relyingPartyVerifyingCredential(),
315+
TestSaml2X509Credentials.relyingPartyDecryptingCredential());
316+
Saml2Authentication authentication = (Saml2Authentication) this.provider.authenticate(token);
317+
Saml2AuthenticatedPrincipal principal = (Saml2AuthenticatedPrincipal) authentication.getPrincipal();
318+
assertThat(principal.getAttribute("name")).containsExactly("value");
319+
}
320+
301321
@Test
302322
public void authenticateWhenDecryptionKeysAreMissingThenThrowAuthenticationException() throws Exception {
303323
Response response = TestOpenSamlObjects.response();

saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/authentication/TestOpenSamlObjects.java

+22
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
import org.opensaml.saml.saml2.core.AuthnRequest;
6060
import org.opensaml.saml.saml2.core.Conditions;
6161
import org.opensaml.saml.saml2.core.EncryptedAssertion;
62+
import org.opensaml.saml.saml2.core.EncryptedAttribute;
6263
import org.opensaml.saml.saml2.core.EncryptedID;
6364
import org.opensaml.saml.saml2.core.Issuer;
6465
import org.opensaml.saml.saml2.core.NameID;
@@ -301,6 +302,18 @@ static EncryptedID encrypted(NameID nameId,
301302
}
302303
}
303304

305+
static EncryptedAttribute encrypted(String name, String value, Saml2X509Credential credential) {
306+
Attribute attribute = attribute(name, value);
307+
X509Certificate certificate = credential.getCertificate();
308+
Encrypter encrypter = getEncrypter(certificate);
309+
try {
310+
return encrypter.encrypt(attribute);
311+
}
312+
catch (EncryptionException ex) {
313+
throw new Saml2Exception("Unable to encrypt nameID.", ex);
314+
}
315+
}
316+
304317
private static Encrypter getEncrypter(X509Certificate certificate) {
305318
String dataAlgorithm = XMLCipherParameters.AES_256;
306319
String keyAlgorithm = XMLCipherParameters.RSA_1_5;
@@ -318,6 +331,15 @@ private static Encrypter getEncrypter(X509Certificate certificate) {
318331
return encrypter;
319332
}
320333

334+
static Attribute attribute(String name, String value) {
335+
Attribute attribute = build(Attribute.DEFAULT_ELEMENT_NAME);
336+
attribute.setName(name);
337+
XSString xsValue = new XSStringBuilder().buildObject(AttributeValue.DEFAULT_ELEMENT_NAME, XSString.TYPE_NAME);
338+
xsValue.setValue(value);
339+
attribute.getAttributeValues().add(xsValue);
340+
return attribute;
341+
}
342+
321343
static List<AttributeStatement> attributeStatements() {
322344
List<AttributeStatement> attributeStatements = new ArrayList<>();
323345
AttributeStatementBuilder attributeStatementBuilder = new AttributeStatementBuilder();

0 commit comments

Comments
 (0)