Skip to content

Commit 421341a

Browse files
authored
Merge pull request #82 from ThePetrov/allow-authn-request-without-relaystate
Allow authn request without relayState if relayState is empty
2 parents cca5d21 + e0eeb43 commit 421341a

2 files changed

Lines changed: 92 additions & 12 deletions

File tree

toolkit/src/main/java/com/onelogin/saml2/Auth.java

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,8 @@ public void setStrict(Boolean value)
213213
* Initiates the SSO process.
214214
*
215215
* @param returnTo
216-
* The target URL the user should be returned to after login.
216+
* The target URL the user should be returned to after login (relayState).
217+
* Will be a self-routed URL when null, or not be appended at all when an empty string is provided
217218
* @param forceAuthn
218219
* When true the AuthNRequest will set the ForceAuthn='true'
219220
* @param isPassive
@@ -237,7 +238,10 @@ public void login(String returnTo, Boolean forceAuthn, Boolean isPassive, Boolea
237238
} else {
238239
relayState = returnTo;
239240
}
240-
parameters.put("RelayState", relayState);
241+
242+
if (!relayState.isEmpty()) {
243+
parameters.put("RelayState", relayState);
244+
}
241245

242246
if (settings.getAuthnRequestsSigned()) {
243247
String sigAlg = settings.getSignatureAlgorithm();
@@ -267,7 +271,8 @@ public void login() throws IOException {
267271
* Initiates the SSO process.
268272
*
269273
* @param returnTo
270-
* The target URL the user should be returned to after login.
274+
* The target URL the user should be returned to after login (relayState).
275+
* Will be a self-routed URL when null, or not be appended at all when an empty string is provided.
271276
*
272277
* @throws IOException
273278
*/
@@ -279,7 +284,8 @@ public void login(String returnTo) throws IOException {
279284
* Initiates the SLO process.
280285
*
281286
* @param returnTo
282-
* The target URL the user should be returned to after logout.
287+
* The target URL the user should be returned to after logout (relayState).
288+
* Will be a self-routed URL when null, or not be appended at all when an empty string is provided
283289
* @param nameId
284290
* The NameID that will be set in the LogoutRequest.
285291
* @param sessionIndex
@@ -296,13 +302,15 @@ public void logout(String returnTo, String nameId, String sessionIndex) throws I
296302
parameters.put("SAMLRequest", samlLogoutRequest);
297303

298304
String relayState;
299-
if (returnTo == null || returnTo.isEmpty()) {
305+
if (returnTo == null) {
300306
relayState = ServletUtils.getSelfRoutedURLNoQuery(request);
301307
} else {
302308
relayState = returnTo;
303309
}
304310

305-
parameters.put("RelayState", relayState);
311+
if (!relayState.isEmpty()) {
312+
parameters.put("RelayState", relayState);
313+
}
306314

307315
if (settings.getLogoutRequestSigned()) {
308316
String sigAlg = settings.getSignatureAlgorithm();
@@ -331,8 +339,9 @@ public void logout() throws IOException, XMLEntityException {
331339
/**
332340
* Initiates the SLO process.
333341
*
334-
* @param returnTo
335-
* The target URL the user should be returned to after logout.
342+
* @param returnTo
343+
* The target URL the user should be returned to after logout (relayState).
344+
* Will be a self-routed URL when null, or not be appended at all when an empty string is provided
336345
*
337346
* @throws IOException
338347
* @throws XMLEntityException
@@ -659,11 +668,11 @@ private String buildSignature(String samlMessage, String relayState, String sign
659668
PrivateKey key = settings.getSPkey();
660669

661670
String msg = type + "=" + Util.urlEncoder(samlMessage);
662-
if (relayState != null) {
671+
if (StringUtils.isNotEmpty(relayState)) {
663672
msg += "&RelayState=" + Util.urlEncoder(relayState);
664673
}
665674

666-
if (signAlgorithm == null || signAlgorithm.isEmpty()) {
675+
if (StringUtils.isEmpty(signAlgorithm)) {
667676
signAlgorithm = Constants.RSA_SHA1;
668677
}
669678

toolkit/src/test/java/com/onelogin/saml2/test/AuthTest.java

Lines changed: 73 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import static java.util.Collections.singletonMap;
55
import static org.hamcrest.CoreMatchers.containsString;
66
import static org.hamcrest.CoreMatchers.is;
7+
import static org.hamcrest.CoreMatchers.not;
78
import static org.hamcrest.CoreMatchers.startsWith;
89
import static org.hamcrest.Matchers.contains;
910
import static org.junit.Assert.assertEquals;
@@ -38,6 +39,7 @@
3839
import com.onelogin.saml2.settings.SettingsBuilder;
3940
import com.onelogin.saml2.util.Constants;
4041
import com.onelogin.saml2.util.Util;
42+
import org.mockito.ArgumentCaptor;
4143

4244
public class AuthTest {
4345

@@ -104,7 +106,7 @@ public void testConstructorWithReqRes() throws IOException, SettingsException, U
104106
assertEquals(settings.getIdpEntityId(), auth.getSettings().getIdpEntityId());
105107
assertEquals(settings.getSpEntityId(), auth.getSettings().getSpEntityId());
106108
}
107-
109+
108110
/**
109111
* Tests the constructor of Auth
110112
* Case: filename, HttpServletRequest and HttpServletResponse provided
@@ -730,7 +732,7 @@ public void testIsAuthenticated() throws Exception {
730732
expectedErrors = new ArrayList<String>();
731733
expectedErrors.add("invalid_response");
732734
assertEquals(expectedErrors, auth2.getErrors());
733-
assertThat(auth2.getLastErrorReason(), containsString("Invalid issuer in the Assertion/Response"));
735+
assertThat(auth2.getLastErrorReason(), containsString("Invalid issuer in the Assertion/Response"));
734736

735737
samlResponseEncoded = Util.getFileAsString("data/responses/valid_response.xml.base64");
736738
when(request.getParameterMap()).thenReturn(singletonMap("SAMLResponse", new String[]{samlResponseEncoded}));
@@ -963,6 +965,36 @@ public void testLoginWithRelayState() throws IOException, SettingsException, URI
963965
verify(response).sendRedirect(matches("https:\\/\\/pitbulk.no-ip.org\\/simplesaml\\/saml2\\/idp\\/SSOService.php\\?SAMLRequest=(.)*&RelayState=http%3A%2F%2Flocalhost%3A8080%2Fexpected.jsp"));
964966
}
965967

968+
/**
969+
* Tests the login method of Auth
970+
* Case: Login with empty relayState - no relayState appended
971+
*
972+
* @throws SettingsException
973+
* @throws IOException
974+
* @throws URISyntaxException
975+
*
976+
* @see com.onelogin.saml2.Auth#login
977+
*/
978+
@Test
979+
public void testLoginWithoutRelayState() throws IOException, SettingsException, URISyntaxException {
980+
HttpServletRequest request = mock(HttpServletRequest.class);
981+
HttpServletResponse response = mock(HttpServletResponse.class);
982+
when(request.getScheme()).thenReturn("http");
983+
when(request.getServerPort()).thenReturn(8080);
984+
when(request.getServerName()).thenReturn("localhost");
985+
when(request.getRequestURI()).thenReturn("/initial.jsp");
986+
987+
Saml2Settings settings = new SettingsBuilder().fromFile("config/config.my.properties").build();
988+
settings.setAuthnRequestsSigned(false);
989+
990+
Auth auth = new Auth(settings, request, response);
991+
auth.login("");
992+
final ArgumentCaptor<String> urlCaptor = ArgumentCaptor.forClass(String.class);
993+
verify(response).sendRedirect(urlCaptor.capture());
994+
assertThat(urlCaptor.getValue(), startsWith("https://pitbulk.no-ip.org/simplesaml/saml2/idp/SSOService.php?SAMLRequest="));
995+
assertThat(urlCaptor.getValue(), not(containsString("&RelayState=")));
996+
}
997+
966998
/**
967999
* Tests the login method of Auth
9681000
* Case: Signed Login but no sp key
@@ -1080,6 +1112,37 @@ public void testLogoutWithRelayState() throws IOException, SettingsException, XM
10801112
verify(response).sendRedirect(matches("https:\\/\\/pitbulk.no-ip.org\\/simplesaml\\/saml2\\/idp\\/SingleLogoutService.php\\?SAMLRequest=(.)*&RelayState=http%3A%2F%2Flocalhost%3A8080%2Fexpected.jsp"));
10811113
}
10821114

1115+
/**
1116+
* Tests the logout method of Auth
1117+
* Case: Logout with empty RelayState - no RelayState appended
1118+
*
1119+
* @throws IOException
1120+
* @throws SettingsException
1121+
* @throws XMLEntityException
1122+
*
1123+
* @see com.onelogin.saml2.Auth#logout
1124+
*/
1125+
@Test
1126+
public void testLogoutWithoutRelayState() throws IOException, SettingsException, XMLEntityException {
1127+
HttpServletRequest request = mock(HttpServletRequest.class);
1128+
HttpServletResponse response = mock(HttpServletResponse.class);
1129+
when(request.getScheme()).thenReturn("http");
1130+
when(request.getServerPort()).thenReturn(8080);
1131+
when(request.getServerName()).thenReturn("localhost");
1132+
when(request.getRequestURI()).thenReturn("/initial.jsp");
1133+
1134+
Saml2Settings settings = new SettingsBuilder().fromFile("config/config.my.properties").build();
1135+
settings.setLogoutRequestSigned(false);
1136+
1137+
Auth auth = new Auth(settings, request, response);
1138+
auth.logout("");
1139+
1140+
final ArgumentCaptor<String> urlCaptor = ArgumentCaptor.forClass(String.class);
1141+
verify(response).sendRedirect(urlCaptor.capture());
1142+
assertThat(urlCaptor.getValue(), startsWith("https://pitbulk.no-ip.org/simplesaml/saml2/idp/SingleLogoutService.php?SAMLRequest="));
1143+
assertThat(urlCaptor.getValue(), not(containsString("&RelayState=")));
1144+
}
1145+
10831146
/**
10841147
* Tests the logout method of Auth
10851148
* Case: Signed Logout but no sp key
@@ -1434,6 +1497,14 @@ public void testBuildSignature() throws URISyntaxException, IOException, Setting
14341497

14351498
signature = auth.buildResponseSignature(deflatedEncodedLogoutResponse, null, "");
14361499
assertEquals(expectedSignature, signature);
1500+
1501+
signature = auth.buildRequestSignature(deflatedEncodedAuthNRequest, "", signAlgorithm);
1502+
expectedSignature = "NS/yZ0WkHHtPU6LBWioxTzFsATJC6k7D8PcmBuM4NcC1klHSX5gmgDJdGs+7ee433RxhsTRLDNXJnXInAFG5iqZQK/Jps1aqx9iCAwfC4GCJs605e/hw3UXWKKo1lKxwE4Zu6eJ0TsMQ2gj/5qLezQL98CgqmFHLhvNgGJZcG6U=";
1503+
assertEquals(expectedSignature, signature);
1504+
1505+
signature = auth.buildRequestSignature(deflatedEncodedLogoutResponse, "", signAlgorithm);
1506+
expectedSignature = "GiO58DZMcRb8QR+dxUvn9bp5tIp2Eal8+tvOAEbYoAX6+7TMO8tTkpPjRD60pG+SMYjTC+lXQHygX2AXcO5ZQj8snfqx94C3dCOP7gLKOowFcaD0TunmnFCBx6qLv2cOleS9PSx49BSZJiGuffNcfgvTvsyqGwC2EatPP2+AxDM=";
1507+
assertEquals(expectedSignature, signature);
14371508
}
14381509

14391510
}

0 commit comments

Comments
 (0)