Skip to content

Commit b1a905b

Browse files
committed
Add Session Index Support
Closes gh-10613
1 parent e280061 commit b1a905b

File tree

7 files changed

+63
-10
lines changed

7 files changed

+63
-10
lines changed

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

+16-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@
1717
package org.springframework.security.saml2.provider.service.authentication;
1818

1919
import java.io.Serializable;
20+
import java.util.Collections;
2021
import java.util.List;
2122
import java.util.Map;
2223

@@ -34,14 +35,22 @@ public class DefaultSaml2AuthenticatedPrincipal implements Saml2AuthenticatedPri
3435

3536
private final Map<String, List<Object>> attributes;
3637

38+
private final List<String> sessionIndexes;
39+
3740
private String registrationId;
3841

3942
public DefaultSaml2AuthenticatedPrincipal(String name, Map<String, List<Object>> attributes) {
43+
this(name, attributes, Collections.emptyList());
44+
}
45+
46+
public DefaultSaml2AuthenticatedPrincipal(String name, Map<String, List<Object>> attributes,
47+
List<String> sessionIndexes) {
4048
Assert.notNull(name, "name cannot be null");
4149
Assert.notNull(attributes, "attributes cannot be null");
50+
Assert.notNull(sessionIndexes, "sessionIndexes cannot be null");
4251
this.name = name;
4352
this.attributes = attributes;
44-
this.registrationId = null;
53+
this.sessionIndexes = sessionIndexes;
4554
}
4655

4756
@Override
@@ -54,6 +63,11 @@ public Map<String, List<Object>> getAttributes() {
5463
return this.attributes;
5564
}
5665

66+
@Override
67+
public List<String> getSessionIndexes() {
68+
return this.sessionIndexes;
69+
}
70+
5771
@Override
5872
public String getRelyingPartyRegistrationId() {
5973
return this.registrationId;

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

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -76,4 +76,8 @@ default String getRelyingPartyRegistrationId() {
7676
return null;
7777
}
7878

79+
default List<String> getSessionIndexes() {
80+
return Collections.emptyList();
81+
}
82+
7983
}

saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSamlLogoutRequestResolver.java

+16-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2021 the original author or authors.
2+
* Copyright 2002-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -31,10 +31,12 @@
3131
import org.opensaml.saml.saml2.core.Issuer;
3232
import org.opensaml.saml.saml2.core.LogoutRequest;
3333
import org.opensaml.saml.saml2.core.NameID;
34+
import org.opensaml.saml.saml2.core.SessionIndex;
3435
import org.opensaml.saml.saml2.core.impl.IssuerBuilder;
3536
import org.opensaml.saml.saml2.core.impl.LogoutRequestBuilder;
3637
import org.opensaml.saml.saml2.core.impl.LogoutRequestMarshaller;
3738
import org.opensaml.saml.saml2.core.impl.NameIDBuilder;
39+
import org.opensaml.saml.saml2.core.impl.SessionIndexBuilder;
3840
import org.w3c.dom.Element;
3941

4042
import org.springframework.security.core.Authentication;
@@ -67,6 +69,8 @@ final class OpenSamlLogoutRequestResolver {
6769

6870
private final NameIDBuilder nameIdBuilder;
6971

72+
private final SessionIndexBuilder sessionIndexBuilder;
73+
7074
private final LogoutRequestBuilder logoutRequestBuilder;
7175

7276
private final RelyingPartyRegistrationResolver relyingPartyRegistrationResolver;
@@ -87,6 +91,9 @@ final class OpenSamlLogoutRequestResolver {
8791
Assert.notNull(this.issuerBuilder, "issuerBuilder must be configured in OpenSAML");
8892
this.nameIdBuilder = (NameIDBuilder) registry.getBuilderFactory().getBuilder(NameID.DEFAULT_ELEMENT_NAME);
8993
Assert.notNull(this.nameIdBuilder, "nameIdBuilder must be configured in OpenSAML");
94+
this.sessionIndexBuilder = (SessionIndexBuilder) registry.getBuilderFactory()
95+
.getBuilder(SessionIndex.DEFAULT_ELEMENT_NAME);
96+
Assert.notNull(this.sessionIndexBuilder, "sessionIndexBuilder must be configured in OpenSAML");
9097
}
9198

9299
/**
@@ -122,6 +129,14 @@ Saml2LogoutRequest resolve(HttpServletRequest request, Authentication authentica
122129
NameID nameId = this.nameIdBuilder.buildObject();
123130
nameId.setValue(authentication.getName());
124131
logoutRequest.setNameID(nameId);
132+
if (authentication.getPrincipal() instanceof Saml2AuthenticatedPrincipal) {
133+
Saml2AuthenticatedPrincipal principal = (Saml2AuthenticatedPrincipal) authentication.getPrincipal();
134+
for (String index : principal.getSessionIndexes()) {
135+
SessionIndex sessionIndex = this.sessionIndexBuilder.buildObject();
136+
sessionIndex.setSessionIndex(index);
137+
logoutRequest.getSessionIndexes().add(sessionIndex);
138+
}
139+
}
125140
logoutRequestConsumer.accept(registration, logoutRequest);
126141
if (logoutRequest.getID() == null) {
127142
logoutRequest.setID("LR" + UUID.randomUUID());

saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProvider.java

+13-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2021 the original author or authors.
2+
* Copyright 2002-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -57,6 +57,7 @@
5757
import org.opensaml.saml.saml2.core.Assertion;
5858
import org.opensaml.saml.saml2.core.Attribute;
5959
import org.opensaml.saml.saml2.core.AttributeStatement;
60+
import org.opensaml.saml.saml2.core.AuthnStatement;
6061
import org.opensaml.saml.saml2.core.Condition;
6162
import org.opensaml.saml.saml2.core.EncryptedAssertion;
6263
import org.opensaml.saml.saml2.core.OneTimeUse;
@@ -425,7 +426,9 @@ public static Converter<ResponseToken, Saml2Authentication> createDefaultRespons
425426
Assertion assertion = CollectionUtils.firstElement(response.getAssertions());
426427
String username = assertion.getSubject().getNameID().getValue();
427428
Map<String, List<Object>> attributes = getAssertionAttributes(assertion);
428-
DefaultSaml2AuthenticatedPrincipal principal = new DefaultSaml2AuthenticatedPrincipal(username, attributes);
429+
List<String> sessionIndexes = getSessionIndexes(assertion);
430+
DefaultSaml2AuthenticatedPrincipal principal = new DefaultSaml2AuthenticatedPrincipal(username, attributes,
431+
sessionIndexes);
429432
String registrationId = responseToken.token.getRelyingPartyRegistration().getRegistrationId();
430433
principal.setRelyingPartyRegistrationId(registrationId);
431434
return new Saml2Authentication(principal, token.getSaml2Response(),
@@ -617,6 +620,14 @@ private static Map<String, List<Object>> getAssertionAttributes(Assertion assert
617620
return attributeMap;
618621
}
619622

623+
private static List<String> getSessionIndexes(Assertion assertion) {
624+
List<String> sessionIndexes = new ArrayList<>();
625+
for (AuthnStatement statement : assertion.getAuthnStatements()) {
626+
sessionIndexes.add(statement.getSessionIndex());
627+
}
628+
return sessionIndexes;
629+
}
630+
620631
private static Object getXmlObjectValue(XMLObject xmlObject) {
621632
if (xmlObject instanceof XSAny) {
622633
return ((XSAny) xmlObject).getTextContent();

saml2/saml2-service-provider/src/opensaml4Test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProviderTests.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2021 the original author or authors.
2+
* Copyright 2002-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -247,6 +247,7 @@ public void authenticateWhenAssertionContainsAttributesThenItSucceeds() {
247247
expected.put("registeredDate", Collections.singletonList(registeredDate));
248248
assertThat((String) principal.getFirstAttribute("name")).isEqualTo("John Doe");
249249
assertThat(principal.getAttributes()).isEqualTo(expected);
250+
assertThat(principal.getSessionIndexes()).contains("session-index");
250251
}
251252

252253
@Test

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

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2021 the original author or authors.
2+
* Copyright 2002-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -49,6 +49,7 @@
4949
import org.opensaml.saml.saml2.core.AttributeStatement;
5050
import org.opensaml.saml.saml2.core.AttributeValue;
5151
import org.opensaml.saml.saml2.core.AuthnRequest;
52+
import org.opensaml.saml.saml2.core.AuthnStatement;
5253
import org.opensaml.saml.saml2.core.Conditions;
5354
import org.opensaml.saml.saml2.core.EncryptedAssertion;
5455
import org.opensaml.saml.saml2.core.EncryptedAttribute;
@@ -153,6 +154,9 @@ static Assertion assertion(String username, String issuerEntityId, String recipi
153154
confirmationData.setRecipient(recipientUri);
154155
subjectConfirmation.setSubjectConfirmationData(confirmationData);
155156
assertion.getSubject().getSubjectConfirmations().add(subjectConfirmation);
157+
AuthnStatement statement = build(AuthnStatement.DEFAULT_ELEMENT_NAME);
158+
statement.setSessionIndex("session-index");
159+
assertion.getAuthnStatements().add(statement);
156160
return assertion;
157161
}
158162

saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSamlLogoutRequestResolverTests.java

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2021 the original author or authors.
2+
* Copyright 2002-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@
1919
import java.io.ByteArrayInputStream;
2020
import java.nio.charset.StandardCharsets;
2121
import java.util.ArrayList;
22+
import java.util.Arrays;
2223
import java.util.HashMap;
2324

2425
import javax.servlet.http.HttpServletRequest;
@@ -86,10 +87,13 @@ public void resolvePostWhenAuthenticatedThenIncludesName() {
8687
Saml2MessageBinding binding = registration.getAssertingPartyDetails().getSingleLogoutServiceBinding();
8788
LogoutRequest logoutRequest = getLogoutRequest(saml2LogoutRequest.getSamlRequest(), binding);
8889
assertThat(logoutRequest.getNameID().getValue()).isEqualTo(authentication.getName());
90+
assertThat(logoutRequest.getSessionIndexes()).hasSize(1);
91+
assertThat(logoutRequest.getSessionIndexes().get(0).getSessionIndex()).isEqualTo("session-index");
8992
}
9093

9194
private Saml2Authentication authentication(RelyingPartyRegistration registration) {
92-
DefaultSaml2AuthenticatedPrincipal principal = new DefaultSaml2AuthenticatedPrincipal("user", new HashMap<>());
95+
DefaultSaml2AuthenticatedPrincipal principal = new DefaultSaml2AuthenticatedPrincipal("user", new HashMap<>(),
96+
Arrays.asList("session-index"));
9397
principal.setRelyingPartyRegistrationId(registration.getRegistrationId());
9498
return new Saml2Authentication(principal, "response", new ArrayList<>());
9599
}

0 commit comments

Comments
 (0)