Skip to content

Commit 83b5f5c

Browse files
committed
Improve the Saml2AuthenticationRequest object
- introduce the AssertionConsumerServiceURL attribute - add javadoc - align property name with SAML XML for AuthNRequest
1 parent 9731386 commit 83b5f5c

File tree

4 files changed

+158
-21
lines changed

4 files changed

+158
-21
lines changed

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

+4-3
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,14 @@ public String createAuthenticationRequest(Saml2AuthenticationRequest request) {
4545
auth.setIsPassive(Boolean.FALSE);
4646
auth.setProtocolBinding("urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect");
4747
Issuer issuer = this.saml.buildSAMLObject(Issuer.class);
48-
issuer.setValue(request.getLocalSpEntityId());
48+
issuer.setValue(request.getIssuer());
4949
auth.setIssuer(issuer);
50-
auth.setDestination(request.getWebSsoUri());
50+
auth.setDestination(request.getDestination());
51+
auth.setAssertionConsumerServiceURL(request.getAssertionConsumerServiceUrl());
5152
return this.saml.toXml(
5253
auth,
5354
request.getCredentials(),
54-
request.getLocalSpEntityId()
55+
request.getIssuer()
5556
);
5657
}
5758

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

+133-13
Original file line numberDiff line numberDiff line change
@@ -19,27 +19,36 @@
1919
import org.springframework.security.saml2.credentials.Saml2X509Credential;
2020
import org.springframework.util.Assert;
2121

22+
import java.util.Collection;
2223
import java.util.LinkedList;
2324
import java.util.List;
25+
import java.util.function.Consumer;
2426

2527
/**
2628
* Data holder for information required to send an {@code AuthNRequest}
2729
* from the service provider to the identity provider
30+
* https://www.oasis-open.org/committees/download.php/35711/sstc-saml-core-errata-2.0-wd-06-diff.pdf (line 2031)
2831
*
2932
* @see {@link Saml2AuthenticationRequestFactory}
30-
* @see https://www.oasis-open.org/committees/download.php/35711/sstc-saml-core-errata-2.0-wd-06-diff.pdf (line 2031)
3133
* @since 5.2
3234
*/
33-
public class Saml2AuthenticationRequest {
34-
private final String localSpEntityId;
35+
public final class Saml2AuthenticationRequest {
36+
private final String issuer;
3537
private final List<Saml2X509Credential> credentials;
36-
private String webSsoUri;
38+
private final String destination;
39+
private final String assertionConsumerServiceUrl;
3740

38-
public Saml2AuthenticationRequest(String localSpEntityId, String webSsoUri, List<Saml2X509Credential> credentials) {
39-
Assert.hasText(localSpEntityId, "localSpEntityId cannot be null");
40-
Assert.hasText(localSpEntityId, "webSsoUri cannot be null");
41-
this.localSpEntityId = localSpEntityId;
42-
this.webSsoUri = webSsoUri;
41+
private Saml2AuthenticationRequest(
42+
String issuer,
43+
String destination,
44+
String assertionConsumerServiceUrl,
45+
List<Saml2X509Credential> credentials) {
46+
Assert.hasText(issuer, "issuer cannot be null");
47+
Assert.hasText(destination, "destination cannot be null");
48+
Assert.hasText(assertionConsumerServiceUrl, "spAssertionConsumerServiceUrl cannot be null");
49+
this.issuer = issuer;
50+
this.destination = destination;
51+
this.assertionConsumerServiceUrl = assertionConsumerServiceUrl;
4352
this.credentials = new LinkedList<>();
4453
for (Saml2X509Credential c : credentials) {
4554
if (c.isSigningCredential()) {
@@ -50,15 +59,126 @@ public Saml2AuthenticationRequest(String localSpEntityId, String webSsoUri, List
5059
}
5160

5261

53-
public String getLocalSpEntityId() {
54-
return this.localSpEntityId;
62+
/**
63+
* returns the issuer, the local SP entity ID, for this authentication request.
64+
* This property should be used to populate the {@code AuthNRequest.Issuer} XML element.
65+
* This value typically is a URI, but can be an arbitrary string.
66+
* @return issuer
67+
*/
68+
public String getIssuer() {
69+
return this.issuer;
5570
}
5671

57-
public String getWebSsoUri() {
58-
return this.webSsoUri;
72+
/**
73+
* returns the destination, the WEB Single Sign On URI, for this authentication request.
74+
* This property populates the {@code AuthNRequest#Destination} XML attribute.
75+
* @return destination
76+
*/
77+
public String getDestination() {
78+
return this.destination;
5979
}
6080

81+
/**
82+
* Returns the desired {@code AssertionConsumerServiceUrl} that this SP wishes to receive the
83+
* assertion on. The IDP may or may not honor this request.
84+
* This property populates the {@code AuthNRequest#AssertionConsumerServiceURL} XML attribute.
85+
* @return the AssertionConsumerServiceURL value
86+
*/
87+
public String getAssertionConsumerServiceUrl() {
88+
return assertionConsumerServiceUrl;
89+
}
90+
91+
/**
92+
* Returns a list of credentials that can be used to sign the {@code AuthNRequest} object
93+
* @return signing credentials
94+
*/
6195
public List<Saml2X509Credential> getCredentials() {
6296
return this.credentials;
6397
}
98+
99+
/**
100+
* A builder for {@link Saml2AuthenticationRequest}.
101+
* returns a builder object
102+
*/
103+
public static Builder builder() {
104+
return new Builder();
105+
}
106+
107+
/**
108+
* A builder for {@link Saml2AuthenticationRequest}.
109+
*/
110+
public static class Builder {
111+
private String issuer;
112+
private List<Saml2X509Credential> credentials = new LinkedList<>();
113+
private String destination;
114+
private String assertionConsumerServiceUrl;
115+
116+
private Builder() {
117+
}
118+
119+
/**
120+
* Sets the issuer for the authentication request.
121+
* @param issuer - a required value
122+
* @return this {@code Builder}
123+
*/
124+
public Builder issuer(String issuer) {
125+
this.issuer = issuer;
126+
return this;
127+
}
128+
129+
/**
130+
* Modifies the collection of {@link Saml2X509Credential} credentials
131+
* used in communication between IDP and SP, specifically signing the
132+
* authentication request.
133+
* For example:
134+
* <code>
135+
* Saml2X509Credential credential = ...;
136+
* return Saml2AuthenticationRequest.withLocalSpEntityId("id")
137+
* .credentials(c -> c.add(credential))
138+
* ...
139+
* .build();
140+
* </code>
141+
* @param credentials - a consumer that can modify the collection of credentials
142+
* @return this object
143+
*/
144+
public Builder credentials(Consumer<Collection<Saml2X509Credential>> credentials) {
145+
credentials.accept(this.credentials);
146+
return this;
147+
}
148+
149+
/**
150+
* Sets the Destination for the authentication request. Typically the {@code Service Provider EntityID}
151+
* @param destination - a required value
152+
* @return this {@code Builder}
153+
*/
154+
public Builder destination(String destination) {
155+
this.destination = destination;
156+
return this;
157+
}
158+
159+
/**
160+
* Sets the {@code assertionConsumerServiceURL} for the authentication request.
161+
* Typically the {@code Service Provider EntityID}
162+
* @param assertionConsumerServiceUrl - a required value
163+
* @return this {@code Builder}
164+
*/
165+
public Builder assertionConsumerServiceUrl(String assertionConsumerServiceUrl) {
166+
this.assertionConsumerServiceUrl = assertionConsumerServiceUrl;
167+
return this;
168+
}
169+
170+
/**
171+
* Creates a {@link Saml2AuthenticationRequest} object.
172+
* @return the Saml2AuthenticationRequest object
173+
* @throws {@link IllegalArgumentException} if a required property is not set
174+
*/
175+
public Saml2AuthenticationRequest build() {
176+
return new Saml2AuthenticationRequest(
177+
this.issuer,
178+
this.destination,
179+
this.assertionConsumerServiceUrl,
180+
this.credentials
181+
);
182+
}
183+
}
64184
}

saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/servlet/filter/Saml2WebSsoAuthenticationRequestFilter.java

+14-5
Original file line numberDiff line numberDiff line change
@@ -105,11 +105,20 @@ private String createSamlRequestRedirectUrl(HttpServletRequest request, RelyingP
105105

106106
private Saml2AuthenticationRequest createAuthenticationRequest(RelyingPartyRegistration relyingParty, HttpServletRequest request) {
107107
String localSpEntityId = Saml2Utils.getServiceProviderEntityId(relyingParty, request);
108-
return new Saml2AuthenticationRequest(
109-
localSpEntityId,
110-
relyingParty.getIdpWebSsoUrl(),
111-
relyingParty.getSigningCredentials()
112-
);
108+
return Saml2AuthenticationRequest
109+
.builder()
110+
.issuer(localSpEntityId)
111+
.destination(relyingParty.getIdpWebSsoUrl())
112+
.credentials(c -> c.addAll(relyingParty.getCredentials()))
113+
.assertionConsumerServiceUrl(
114+
Saml2Utils.resolveUrlTemplate(
115+
relyingParty.getAssertionConsumerServiceUrlTemplate(),
116+
Saml2Utils.getApplicationUri(request),
117+
relyingParty.getRemoteIdpEntityId(),
118+
relyingParty.getRegistrationId()
119+
)
120+
)
121+
.build();
113122
}
114123

115124
}

samples/boot/saml2login/src/integration-test/java/org/springframework/security/samples/Saml2LoginIntegrationTests.java

+7
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,13 @@ public void authenticateRequestWhenWorkingThenDestinationAttributeIsSet() throws
160160
"https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/SSOService.php",
161161
destination
162162
);
163+
String acsURL = authnRequest.getAssertionConsumerServiceURL();
164+
assertEquals(
165+
"AssertionConsumerServiceURL must match",
166+
"http://localhost:8080/login/saml2/sso/simplesamlphp",
167+
acsURL
168+
);
169+
163170
}
164171

165172

0 commit comments

Comments
 (0)