Skip to content

Commit 37b4047

Browse files
committed
Revert "Add Single Logout Support"
This reverts commit e807fae.
1 parent 404a6c5 commit 37b4047

File tree

41 files changed

+35
-4957
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+35
-4957
lines changed

docs/manual/src/docs/asciidoc/_includes/servlet/saml2/saml2-login.adoc

Lines changed: 8 additions & 267 deletions
Original file line numberDiff line numberDiff line change
@@ -1053,279 +1053,20 @@ filter.setRequestMatcher(new AntPathRequestMatcher("/saml2/metadata", "GET"));
10531053
[[servlet-saml2login-logout]]
10541054
=== Performing Single Logout
10551055

1056-
Spring Security ships with support for RP- and AP-initiated SAML 2.0 Single Logout.
1056+
Spring Security does not yet support single logout.
10571057

1058-
Briefly, there are two use cases Spring Security supports:
1059-
1060-
* **RP-Initiated** - Your application has an endpoint that, when POSTed to, will logout the user and send a `saml2:LogoutRequest` to the asserting party.
1061-
Thereafter, the asserting party will send back a `saml2:LogoutResponse` and allow your application to respond
1062-
* **AP-Initiated** - Your application has an endpoint that will receive a `saml2:LogoutRequest` from the asserting party.
1063-
Your application will complete its logout at that point and then send a `saml2:LogoutResponse` to the asserting party.
1064-
1065-
[NOTE]
1066-
In the **AP-Initiated** scenario, any local redirection that your application would do post-logout is rendered moot.
1067-
Once your application sends a `saml2:LogoutResponse`, it no longer has control of the browser.
1068-
1069-
=== Minimal Configuration for Single Logout
1070-
1071-
To use Spring Security's SAML 2.0 Single Logout feature, you will need the following things:
1072-
1073-
* First, the asserting party must support SAML 2.0 Single Logout
1074-
* Second, the asserting party should be configured to sign and POST `saml2:LogoutRequest` s and `saml2:LogoutResponse` s your application's `/logout/saml2/slo` endpoint
1075-
* Third, your application must have a PKCS#8 private key and X.509 certificate for signing `saml2:LogoutRequest` s and `saml2:LogoutResponse` s
1076-
1077-
==== RP-Initiated Single Logout
1078-
1079-
Given those, then for RP-initiated Single Logout, you can begin from the initial minimal example and add the following configuration:
1080-
1081-
[source,java]
1082-
----
1083-
@Value("${private.key}") RSAPrivateKey key;
1084-
@Value("${public.certificate}") X509Certificate certificate;
1085-
1086-
@Bean
1087-
RelyingPartyRegistrationRepository registrations() {
1088-
RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistrations
1089-
.fromMetadataLocation("https://ap.example.org/metadata")
1090-
.registrationId("id")
1091-
.singleLogoutServiceLocation("{baseUrl}/logout/saml2/slo")
1092-
.signingX509Credentials((signing) -> signing.add(Saml2X509Credential.signing(key, certificate))) <1>
1093-
.build();
1094-
return new InMemoryRelyingPartyRegistrationRepository(relyingPartyRegistration);
1095-
}
1096-
1097-
@Bean
1098-
SecurityFilterChain web(HttpSecurity http, RelyingPartyRegistrationRepository registrations) throws Exception {
1099-
RelyingPartyRegistrationResolver registrationResolver = new DefaultRelyingPartyRegistrationResolver(registrations);
1100-
LogoutHandler logoutResponseHandler = logoutResponseHandler(registrationResolver);
1101-
LogoutSuccessHandler logoutRequestSuccessHandler = logoutRequestSuccessHandler(registrationResolver);
1102-
1103-
http
1104-
.authorizeRequests((authorize) -> authorize
1105-
.anyRequest().authenticated()
1106-
)
1107-
.saml2Login(withDefaults())
1108-
.logout((logout) -> logout
1109-
.logoutUrl("/saml2/logout")
1110-
.logoutSuccessHandler(successHandler))
1111-
.addFilterBefore(new Saml2LogoutResponseFilter(logoutHandler), CsrfFilter.class);
1112-
1113-
return http.build();
1114-
}
1115-
1116-
private LogoutSuccessHandler logoutRequestSuccessHandler(RelyingPartyRegistrationResolver registrationResolver) { <2>
1117-
OpenSaml4LogoutRequestResolver logoutRequestResolver = new OpenSaml4LogoutRequestResolver(registrationResolver);
1118-
return new Saml2LogoutRequestSuccessHandler(logoutRequestResolver);
1119-
}
1120-
1121-
private LogoutHandler logoutHandler(RelyingPartyRegistrationResolver registrationResolver) { <3>
1122-
return new OpenSamlLogoutResponseHandler(relyingPartyRegistrationResolver);
1123-
}
1124-
----
1125-
<1> - First, add your signing key to the `RelyingPartyRegistration` instance or to <<servlet-saml2login-rpr-duplicated,multiple instances>>
1126-
<2> - Second, supply a `LogoutSuccessHandler` for initiating Single Logout, sending a `saml2:LogoutRequest` to the asserting party
1127-
<3> - Third, supply the `LogoutHandler` s needed to handle the `saml2:LogoutResponse` s sent from the asserting party.
1128-
1129-
==== Runtime Expectations for RP-Initiated
1130-
1131-
Given the above configuration any logged in user can send a `POST /logout` to your application to perform RP-initiated SLO.
1132-
Your application will then do the following:
1133-
1134-
1. Logout the user and invalidate the session
1135-
2. Use a `Saml2LogoutRequestResolver` to create, sign, and serialize a `<saml2:LogoutRequest>` based on the <<servlet-saml2login-relyingpartyregistration,`RelyingPartyRegistration`>> associated with the currently logged-in user.
1136-
3. Send a redirect or post to the asserting party based on the <<servlet-saml2login-relyingpartyregistration,`RelyingPartyRegistration`>>
1137-
4. Deserialize, verify, and process the `<saml2:LogoutResponse>` sent by the asserting party
1138-
5. Redirect to any configured successful logout endpoint
1139-
1140-
[TIP]
1141-
If your asserting party does not send `<saml2:LogoutResponse>` s when logout is complete, the asserting party can still send a `POST /saml2/logout` and then there is no need to configure the `Saml2LogoutResponseHandler`.
1142-
1143-
==== AP-Initiated Single Logout
1144-
1145-
Instead of RP-initiated Single Logout, you can again begin from the initial minimal example and add the following configuration to achieve AP-initiated Single Logout:
1146-
1147-
[source,java]
1148-
----
1149-
@Value("${private.key}") RSAPrivateKey key;
1150-
@Value("${public.certificate}") X509Certificate certificate;
1151-
1152-
@Bean
1153-
RelyingPartyRegistrationRepository registrations() {
1154-
RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistrations
1155-
.fromMetadataLocation("https://ap.example.org/metadata")
1156-
.registrationId("id")
1157-
.signingX509Credentials((signing) -> signing.add(Saml2X509Credential.signing(key, certificate))) <1>
1158-
.build();
1159-
return new InMemoryRelyingPartyRegistrationRepository(relyingPartyRegistration);
1160-
}
1161-
1162-
@Bean
1163-
SecurityFilterChain web(HttpSecurity http, RelyingPartyRegistrationRepository registrations) throws Exception {
1164-
RelyingPartyRegistrationResolver registrationResolver = new DefaultRelyingPartyRegistrationResolver(registrations);
1165-
LogoutHandler logoutRequestHandler = logoutRequestHandler(registrationResolver);
1166-
LogoutSuccessHandler logoutResponseSuccessHandler = logoutResponseSuccessHandler(registrationResolver);
1167-
1168-
http
1169-
.authorizeRequests((authorize) -> authorize
1170-
.anyRequest().authenticated()
1171-
)
1172-
.saml2Login(withDefaults())
1173-
.addFilterBefore(new Saml2LogoutRequestFilter(logoutResponseSuccessHandler, logoutRequestHandler), CsrfFilter.class);
1174-
1175-
return http.build();
1176-
}
1177-
1178-
private LogoutHandler logoutHandler(RelyingPartyRegistrationResolver registrationResolver) { <2>
1179-
return new CompositeLogoutHandler(
1180-
new OpenSamlLogoutRequestHandler(relyingPartyRegistrationResolver),
1181-
new SecurityContextLogoutHandler(),
1182-
new LogoutSuccessEventPublishingLogoutHandler());
1183-
}
1184-
1185-
private LogoutSuccessHandler logoutSuccessHandler(RelyingPartyRegistrationResolver registrationResolver) { <3>
1186-
OpenSaml4LogoutResponseResolver logoutResponseResolver = new OpenSaml4LogoutResponseResolver(registrationResolver);
1187-
return new Saml2LogoutResponseSuccessHandler(logoutResponseResolver);
1188-
}
1189-
----
1190-
<1> - First, add your signing key to the `RelyingPartyRegistration` instance or to <<servlet-saml2login-rpr-duplicated,multiple instances>>
1191-
<2> - Second, supply the `LogoutHandler` needed to handle the `saml2:LogoutRequest` s sent from the asserting party.
1192-
<3> - Third, supply a `LogoutSuccessHandler` for completing Single Logout, sending a `saml2:LogoutResponse` to the asserting party
1193-
1194-
==== Runtime Expectations for AP-Initiated
1195-
1196-
Given the above configuration, an asserting party can send a `POST /logout/saml2` to your application that includes a `<saml2:LogoutRequest>`
1197-
Also, your application can participate in an AP-initated logout when the asserting party sends a `<saml2:LogoutRequest>` to `/logout/saml2/slo`:
1198-
1199-
1. Use a `Saml2LogoutRequestHandler` to deserialize, verify, and process the `<saml2:LogoutRequest>` sent by the asserting party
1200-
2. Logout the user and invalidate the session
1201-
3. Create, sign, and serialize a `<saml2:LogoutResponse>` based on the <<servlet-saml2login-relyingpartyregistration,`RelyingPartyRegistration`>> associated with the just logged-out user
1202-
4. Send a redirect or post to the asserting party based on the <<servlet-saml2login-relyingpartyregistration,`RelyingPartyRegistration`>>
1203-
1204-
[TIP]
1205-
If your asserting party does not expect you do send a `<saml2:LogoutResponse>` s when logout is complete, you may not need to configure a `LogoutSuccessHandler`
1206-
1207-
[NOTE]
1208-
In the event that you need to support both logout flows, you can combine the above to configurations.
1209-
1210-
=== Configuring Logout Endpoints
1211-
1212-
There are three default endpoints that Spring Security's SAML 2.0 Single Logout support exposes:
1213-
* `/logout` - the endpoint for initiating single logout with an asserting party
1214-
* `/logout/saml2/slo` - the endpoint for receiving logout requests or responses from an asserting party
1215-
1216-
Because the user is already logged in, the `registrationId` is already known.
1217-
For this reason, `+{registrationId}+` is not part of these URLs by default.
1218-
1219-
These URLs are customizable in the DSL.
1220-
1221-
For example, if you are migrating your existing relying party over to Spring Security, your asserting party may already be pointing to `GET /SLOService.saml2`.
1222-
To reduce changes in configuration for the asserting party, you can configure the filter in the DSL like so:
1058+
Generally speaking, though, you can achieve this by creating and registering a custom `LogoutSuccessHandler` and `RequestMatcher`:
12231059

12241060
[source,java]
12251061
----
1226-
Saml2LogoutResponseFilter filter = new Saml2LogoutResponseFilter(logoutHandler);
1227-
filter.setLogoutRequestMatcher(new AntPathRequestMatcher("/SLOService.saml2", "GET"));
12281062
http
12291063
// ...
1230-
.addFilterBefore(filter, CsrfFilter.class);
1231-
----
1232-
1233-
=== Customizing `<saml2:LogoutRequest>` Resolution
1234-
1235-
It's common to need to set other values in the `<saml2:LogoutRequest>` than the defaults that Spring Security provides.
1236-
1237-
By default, Spring Security will issue a `<saml2:LogoutRequest>` and supply:
1238-
1239-
* The `Destination` attribute - from `RelyingPartyRegistration#getAssertingPartyDetails#getSingleLogoutServiceLocation`
1240-
* The `ID` attribute - a GUID
1241-
* The `<Issuer>` element - from `RelyingPartyRegistration#getEntityId`
1242-
* The `<NameID>` element - from `Authentication#getName`
1243-
1244-
To add other values, you can use delegation, like so:
1245-
1246-
[source,java]
1247-
----
1248-
OpenSamlLogoutRequestResolver delegate = new OpenSamlLogoutRequestResolver(registrationResolver);
1249-
return (request, response, authentication) -> {
1250-
OpenSamlLogoutRequestBuilder builder = delegate.resolveLogoutRequest(request, response, authentication); <1>
1251-
builder.name(((Saml2AuthenticatedPrincipal) authentication.getPrincipal()).getFirstAttribute("CustomAttribute")); <2>
1252-
builder.logoutRequest((logoutRequest) -> logoutRequest.setIssueInstant(DateTime.now()));
1253-
return builder.logoutRequest(); <3>
1254-
};
1255-
----
1256-
<1> - Spring Security applies default values to a `<saml2:LogoutRequest>`
1257-
<2> - Your application specifies customizations
1258-
<3> - You complete the invocation by calling `request()`
1259-
1260-
[NOTE]
1261-
Support for OpenSAML 4 is coming.
1262-
In anticipation of that, `OpenSamlLogoutRequestResolver` does not add an `IssueInstant`.
1263-
Once OpenSAML 4 support is added, the default will be able to appropriate negotiate that datatype change, meaning you will no longer have to set it.
1264-
1265-
=== Customizing `<saml2:LogoutResponse>` Resolution
1266-
1267-
It's common to need to set other values in the `<saml2:LogoutResponse>` than the defaults that Spring Security provides.
1268-
1269-
By default, Spring Security will issue a `<saml2:LogoutResponse>` and supply:
1270-
1271-
* The `Destination` attribute - from `RelyingPartyRegistration#getAssertingPartyDetails#getSingleLogoutServiceResponseLocation`
1272-
* The `ID` attribute - a GUID
1273-
* The `<Issuer>` element - from `RelyingPartyRegistration#getEntityId`
1274-
* The `<Status>` element - `SUCCESS`
1275-
1276-
To add other values, you can use delegation, like so:
1277-
1278-
[source,java]
1279-
----
1280-
OpenSamlLogoutResponseResolver delegate = new OpenSamlLogoutResponseResolver(registrationResolver);
1281-
return (request, response, authentication) -> {
1282-
OpenSamlLogoutResponseBuilder builder = delegate.resolveLogoutResponse(request, response, authentication); <1>
1283-
if (checkOtherPrevailingConditions()) {
1284-
builder.status(StatusCode.PARTIAL_LOGOUT); <2>
1285-
}
1286-
builder.logoutResponse((logoutResponse) -> logoutResponse.setIssueInstant(DateTime.now()));
1287-
return builder.logoutResponse(); <3>
1288-
};
1289-
----
1290-
<1> - Spring Security applies default values to a `<saml2:LogoutResponse>`
1291-
<2> - Your application specifies customizations
1292-
<3> - You complete the invocation by calling `response()`
1293-
1294-
[NOTE]
1295-
Support for OpenSAML 4 is coming.
1296-
In anticipation of that, `OpenSamlLogoutResponseResolver` does not add an `IssueInstant`.
1297-
Once OpenSAML 4 support is added, the default will be able to appropriate negotiate that datatype change, meaning you will no longer have to set it.
1298-
1299-
=== Customizing `<saml2:LogoutRequest>` Validation
1300-
1301-
To customize validation, you can implement your own `LogoutHandler`.
1302-
At this point, the validation is minimal, so you may be able to first delegate to the default `LogoutHandler` like so:
1303-
1304-
[source,java]
1305-
----
1306-
LogoutHandler logoutHandler(RelyingPartyRegistrationResolver registrationResolver) {
1307-
OpenSamlLogoutRequestHandler delegate = new OpenSamlLogoutRequestHandler(registrationResolver);
1308-
return (request, response, authentication) -> {
1309-
delegate.logout(request, response, authentication); // verify signature, issuer, destination, and principal name
1310-
LogoutRequest logoutRequest = // ... parse using OpenSAML
1311-
// perform custom validation
1312-
}
1313-
}
1064+
.logout(logout -> logout
1065+
.logoutSuccessHandler(myCustomSuccessHandler())
1066+
.logoutRequestMatcher(myRequestMatcher())
1067+
)
13141068
----
13151069

1316-
=== Customizing `<saml2:LogoutResponse>` Validation
1070+
The success handler will send logout requests to the asserting party.
13171071

1318-
To customize validation, you can implement your own `LogoutHandler`.
1319-
At this point, the validation is minimal, so you may be able to first delegate to the default `LogoutHandler` like so:
1320-
1321-
[source,java]
1322-
----
1323-
LogoutHandler logoutHandler(RelyingPartyRegistrationResolver registrationResolver) {
1324-
OpenSamlLogoutResponseHandler delegate = new OpenSamlLogoutResponseHandler(registrationResolver);
1325-
return (request, response, authentication) -> {
1326-
delegate.logout(request, response, authentication); // verify signature, issuer, destination, and status
1327-
LogoutResponse logoutResponse = // ... parse using OpenSAML
1328-
// perform custom validation
1329-
}
1330-
}
1331-
----
1072+
The request matcher will detect logout requests from the asserting party.

saml2/saml2-service-provider/core/src/main/java/org/springframework/security/saml2/core/Saml2ErrorCodes.java

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,6 @@ public interface Saml2ErrorCodes {
3737
*/
3838
String MALFORMED_RESPONSE_DATA = "malformed_response_data";
3939

40-
/**
41-
* Request is invalid in a general way.
42-
*
43-
* @since 5.5
44-
*/
45-
String INVALID_REQUEST = "invalid_request";
46-
4740
/**
4841
* Response is invalid in a general way.
4942
*

0 commit comments

Comments
 (0)