Skip to content

Commit b8a7c92

Browse files
committed
Fix #98 Be able to provide a NameIDFormat to LogoutRequest.Fix getNameIdData method.
1 parent 64b5d7f commit b8a7c92

6 files changed

Lines changed: 202 additions & 15 deletions

File tree

core/src/main/java/com/onelogin/saml2/authn/SamlResponse.java

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -410,17 +410,20 @@ public boolean isValid() {
410410
public HashMap<String,String> getNameIdData() throws Exception {
411411
HashMap<String,String> nameIdData = new HashMap<String, String>();
412412

413-
NodeList encryptedIDNodes = this.queryAssertion("/saml:Subject/saml:EncryptedID/xenc:EncryptedData");
413+
NodeList encryptedIDNodes = this.queryAssertion("/saml:Subject/saml:EncryptedID");
414414
NodeList nameIdNodes;
415415
Element nameIdElem;
416416
if (encryptedIDNodes.getLength() == 1) {
417-
Element encryptedData = (Element) encryptedIDNodes.item(0);
418-
PrivateKey key = settings.getSPkey();
419-
if (key == null) {
420-
throw new SettingsException("Key is required in order to decrypt the NameID", SettingsException.PRIVATE_KEY_NOT_FOUND);
421-
}
417+
NodeList encryptedDataNodes = this.queryAssertion("/saml:Subject/saml:EncryptedID/xenc:EncryptedData");
418+
if (encryptedDataNodes.getLength() == 1) {
419+
Element encryptedData = (Element) encryptedDataNodes.item(0);
420+
PrivateKey key = settings.getSPkey();
421+
if (key == null) {
422+
throw new SettingsException("Key is required in order to decrypt the NameID", SettingsException.PRIVATE_KEY_NOT_FOUND);
423+
}
422424

423-
Util.decryptElement(encryptedData, key);
425+
Util.decryptElement(encryptedData, key);
426+
}
424427
nameIdNodes = this.queryAssertion("/saml:Subject/saml:EncryptedID/saml:NameID|/saml:Subject/saml:NameID");
425428

426429
if (nameIdNodes == null || nameIdNodes.getLength() == 0) {
@@ -481,6 +484,23 @@ public String getNameId() throws Exception {
481484
return nameID;
482485
}
483486

487+
/**
488+
* Gets the NameID Format provided from the SAML Response String.
489+
*
490+
* @return string NameID Format
491+
*
492+
* @throws Exception
493+
*/
494+
public String getNameIdFormat() throws Exception {
495+
HashMap<String,String> nameIdData = getNameIdData();
496+
String nameidFormat = null;
497+
if (!nameIdData.isEmpty() && nameIdData.containsKey("Format")) {
498+
LOGGER.debug("SAMLResponse has NameID Format --> " + nameIdData.get("Format"));
499+
nameidFormat = nameIdData.get("Format");
500+
}
501+
return nameidFormat;
502+
}
503+
484504
/**
485505
* Gets the Attributes from the AttributeStatement element.
486506
*

core/src/main/java/com/onelogin/saml2/logout/LogoutRequest.java

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,12 @@ public class LogoutRequest {
6464
* NameID.
6565
*/
6666
private String nameId;
67-
67+
68+
/**
69+
* NameID Format.
70+
*/
71+
private String nameIdFormat;
72+
6873
/**
6974
* SessionIndex. When the user is logged, this stored it from the AuthnStatement of the SAML Response
7075
*/
@@ -96,10 +101,12 @@ public class LogoutRequest {
96101
* The NameID that will be set in the LogoutRequest.
97102
* @param sessionIndex
98103
* The SessionIndex (taken from the SAML Response in the SSO process).
104+
* @param nameIdFormat
105+
* The nameIdFormat that will be set in the LogoutRequest.
99106
* @throws XMLEntityException
100107
*
101108
*/
102-
public LogoutRequest(Saml2Settings settings, HttpRequest request, String nameId, String sessionIndex) throws XMLEntityException {
109+
public LogoutRequest(Saml2Settings settings, HttpRequest request, String nameId, String sessionIndex, String nameIdFormat) throws XMLEntityException {
103110
this.settings = settings;
104111
this.request = request;
105112

@@ -114,6 +121,7 @@ public LogoutRequest(Saml2Settings settings, HttpRequest request, String nameId,
114121
id = Util.generateUniqueID();
115122
issueInstant = Calendar.getInstance();
116123
this.nameId = nameId;
124+
this.nameIdFormat = nameIdFormat;
117125
this.sessionIndex = sessionIndex;
118126

119127
StrSubstitutor substitutor = generateSubstitutor(settings);
@@ -124,6 +132,24 @@ public LogoutRequest(Saml2Settings settings, HttpRequest request, String nameId,
124132
}
125133
}
126134

135+
/**
136+
* Constructs the LogoutRequest object.
137+
*
138+
* @param settings
139+
* OneLogin_Saml2_Settings
140+
* @param request
141+
* the HttpRequest object to be processed (Contains GET and POST parameters, request URL, ...).
142+
* @param nameId
143+
* The NameID that will be set in the LogoutRequest.
144+
* @param sessionIndex
145+
* The SessionIndex (taken from the SAML Response in the SSO process).
146+
*
147+
* @throws XMLEntityException
148+
*/
149+
public LogoutRequest(Saml2Settings settings, HttpRequest request, String nameId, String sessionIndex) throws XMLEntityException {
150+
this(settings, request, nameId, sessionIndex, null);
151+
}
152+
127153
/**
128154
* Constructs the LogoutRequest object.
129155
*
@@ -215,7 +241,11 @@ private StrSubstitutor generateSubstitutor(Saml2Settings settings) {
215241
String nameIdFormat = null;
216242
String spNameQualifier = null;
217243
if (nameId != null) {
218-
nameIdFormat = settings.getSpNameIDFormat();
244+
if (this.nameIdFormat == null) {
245+
nameIdFormat = settings.getSpNameIDFormat();
246+
} else {
247+
nameIdFormat = this.nameIdFormat;
248+
}
219249
} else {
220250
nameId = settings.getIdpEntityId();
221251
nameIdFormat = Constants.NAMEID_ENTITY;

core/src/test/java/com/onelogin/saml2/test/authn/AuthnResponseTest.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,34 @@ public void testGetNameId() throws Exception {
197197
assertNull(samlResponse.getNameId());
198198
}
199199

200+
/**
201+
* Tests the getNameIdFormat method of SamlResponse
202+
*
203+
* @throws Exception
204+
*
205+
* @see com.onelogin.saml2.authn.SamlResponse#getNameIdFormat
206+
*/
207+
@Test
208+
public void testGetNameIdFormat() throws Exception {
209+
Saml2Settings settings = new SettingsBuilder().fromFile("config/config.my.properties").build();
210+
String samlResponseEncoded = Util.getFileAsString("data/responses/response1.xml.base64");
211+
SamlResponse samlResponse = new SamlResponse(settings, newHttpRequest(samlResponseEncoded));
212+
assertEquals("urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", samlResponse.getNameIdFormat());
213+
214+
samlResponseEncoded = Util.getFileAsString("data/responses/response_encrypted_nameid.xml.base64");
215+
samlResponse = new SamlResponse(settings, newHttpRequest(samlResponseEncoded));
216+
assertEquals("urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified", samlResponse.getNameIdFormat());
217+
218+
samlResponseEncoded = Util.getFileAsString("data/responses/valid_encrypted_assertion.xml.base64");
219+
samlResponse = new SamlResponse(settings, newHttpRequest(samlResponseEncoded));
220+
assertEquals("urn:oasis:names:tc:SAML:2.0:nameid-format:transient", samlResponse.getNameIdFormat());
221+
222+
settings.setWantNameId(false);
223+
samlResponseEncoded = Util.getFileAsString("data/responses/invalids/no_nameid.xml.base64");
224+
samlResponse = new SamlResponse(settings, newHttpRequest(samlResponseEncoded));
225+
assertNull(samlResponse.getNameIdFormat());
226+
}
227+
200228
/**
201229
* Tests the getNameId method of SamlResponse
202230
* Case: No NameId

core/src/test/java/com/onelogin/saml2/test/logout/LogoutRequestTest.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,14 @@ public void testGetNameIdData() throws Exception {
253253
assertThat(nameIdDataStr, containsString("Value=ONELOGIN_1e442c129e1f822c8096086a1103c5ee2c7cae1c"));
254254
assertThat(nameIdDataStr, not(containsString("SPNameQualifier")));
255255

256+
logoutRequest = new LogoutRequest(settings, null, "ONELOGIN_1e442c129e1f822c8096086a1103c5ee2c7cae1c", null, "urn:oasis:names:tc:SAML:2.0:nameid-format:emailAddress");
257+
logoutRequestStringBase64 = logoutRequest.getEncodedLogoutRequest();
258+
logoutRequestStr = Util.base64decodedInflated(logoutRequestStringBase64);
259+
nameIdDataStr = LogoutRequest.getNameIdData(logoutRequestStr, key).toString();
260+
assertThat(nameIdDataStr, containsString("urn:oasis:names:tc:SAML:2.0:nameid-format:emailAddress"));
261+
assertThat(nameIdDataStr, containsString("Value=ONELOGIN_1e442c129e1f822c8096086a1103c5ee2c7cae1c"));
262+
assertThat(nameIdDataStr, not(containsString("SPNameQualifier")));
263+
256264
String keyString = Util.getFileAsString("data/customPath/certs/sp.pem");
257265
key = Util.loadPrivateKey(keyString);
258266
logoutRequestStr = Util.getFileAsString("data/logout_requests/logout_request_encrypted_nameid.xml");

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

Lines changed: 64 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,11 @@ public class Auth {
7171
*/
7272
private String nameid;
7373

74+
/**
75+
* NameIDFormat.
76+
*/
77+
private String nameidFormat;
78+
7479
/**
7580
* SessionIndex. When the user is logged, this stored it from the AuthnStatement of the SAML Response
7681
*/
@@ -345,18 +350,20 @@ public void login(String returnTo) throws IOException, SettingsException {
345350
* @param sessionIndex
346351
* The SessionIndex (taken from the SAML Response in the SSO process).
347352
* @param stay
348-
* True if we want to stay (returns the url string) False to execute redirection
353+
* True if we want to stay (returns the url string) False to execute redirection
354+
* @param nameidFormat
355+
* The NameID Format will be set in the LogoutRequest.
349356
*
350357
* @return the SLO URL with the LogoutRequest if stay = True
351358
*
352359
* @throws IOException
353360
* @throws XMLEntityException
354361
* @throws SettingsException
355362
*/
356-
public String logout(String returnTo, String nameId, String sessionIndex, Boolean stay) throws IOException, XMLEntityException, SettingsException {
363+
public String logout(String returnTo, String nameId, String sessionIndex, Boolean stay, String nameidFormat) throws IOException, XMLEntityException, SettingsException {
357364
Map<String, String> parameters = new HashMap<String, String>();
358365

359-
LogoutRequest logoutRequest = new LogoutRequest(settings, null, nameId, sessionIndex);
366+
LogoutRequest logoutRequest = new LogoutRequest(settings, null, nameId, sessionIndex, nameidFormat);
360367
String samlLogoutRequest = logoutRequest.getEncodedLogoutRequest();
361368
parameters.put("SAMLRequest", samlLogoutRequest);
362369

@@ -399,13 +406,56 @@ public String logout(String returnTo, String nameId, String sessionIndex, Boolea
399406
* The NameID that will be set in the LogoutRequest.
400407
* @param sessionIndex
401408
* The SessionIndex (taken from the SAML Response in the SSO process).
409+
* @param stay
410+
* True if we want to stay (returns the url string) False to execute redirection
411+
*
412+
* @return the SLO URL with the LogoutRequest if stay = True
402413
*
403414
* @throws IOException
404415
* @throws XMLEntityException
405416
* @throws SettingsException
406417
*/
418+
public String logout(String returnTo, String nameId, String sessionIndex, Boolean stay) throws IOException, XMLEntityException, SettingsException {
419+
return logout(returnTo, nameId, sessionIndex, stay, null);
420+
}
421+
422+
/**
423+
* Initiates the SLO process.
424+
*
425+
* @param returnTo
426+
* The target URL the user should be returned to after logout (relayState).
427+
* Will be a self-routed URL when null, or not be appended at all when an empty string is provided
428+
* @param nameId
429+
* The NameID that will be set in the LogoutRequest.
430+
* @param sessionIndex
431+
* The SessionIndex (taken from the SAML Response in the SSO process).
432+
* @param nameidFormat
433+
* The NameID Format will be set in the LogoutRequest.
434+
* @throws IOException
435+
* @throws XMLEntityException
436+
* @throws SettingsException
437+
*/
438+
public void logout(String returnTo, String nameId, String sessionIndex, String nameidFormat) throws IOException, XMLEntityException, SettingsException {
439+
logout(returnTo, nameId, sessionIndex, false, nameidFormat);
440+
}
441+
442+
/**
443+
* Initiates the SLO process.
444+
*
445+
* @param returnTo
446+
* The target URL the user should be returned to after logout (relayState).
447+
* Will be a self-routed URL when null, or not be appended at all when an empty string is provided
448+
* @param nameId
449+
* The NameID that will be set in the LogoutRequest.
450+
* @param sessionIndex
451+
* The SessionIndex (taken from the SAML Response in the SSO process).
452+
*
453+
* @throws IOException
454+
* @throws XMLEntityException
455+
* @throws SettingsException
456+
*/
407457
public void logout(String returnTo, String nameId, String sessionIndex) throws IOException, XMLEntityException, SettingsException {
408-
logout(returnTo, nameId, sessionIndex, false);
458+
logout(returnTo, nameId, sessionIndex, false, null);
409459
}
410460

411461
/**
@@ -416,7 +466,7 @@ public void logout(String returnTo, String nameId, String sessionIndex) throws I
416466
* @throws SettingsException
417467
*/
418468
public void logout() throws IOException, XMLEntityException, SettingsException {
419-
logout(null, null, null);
469+
logout(null, null, null, false);
420470
}
421471

422472
/**
@@ -475,6 +525,7 @@ public void processResponse(String requestId) throws Exception {
475525

476526
if (samlResponse.isValid(requestId)) {
477527
nameid = samlResponse.getNameId();
528+
nameidFormat = samlResponse.getNameIdFormat();
478529
authenticated = true;
479530
attributes = samlResponse.getAttributes();
480531
sessionIndex = samlResponse.getSessionIndex();
@@ -643,6 +694,14 @@ public final String getNameId()
643694
return nameid;
644695
}
645696

697+
/**
698+
* @return the nameID Format of the assertion
699+
*/
700+
public final String getNameIdFormat()
701+
{
702+
return nameidFormat;
703+
}
704+
646705
/**
647706
* @return the SessionIndex of the assertion
648707
*/

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

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -810,6 +810,48 @@ public void testGetNameID() throws Exception {
810810
assertEquals("2de11defd199f8d5bb63f9b7deb265ba5c675c10", auth3.getNameId());
811811
}
812812

813+
/**
814+
* Tests the getNameIdFormat method of Auth
815+
* Case: get nameid format from a SAMLResponse
816+
*
817+
* @throws Exception
818+
*
819+
* @see com.onelogin.saml2.Auth#getNameIdFormat
820+
*/
821+
@Test
822+
public void testGetNameIdFormat() throws Exception {
823+
HttpServletRequest request = mock(HttpServletRequest.class);
824+
HttpServletResponse response = mock(HttpServletResponse.class);
825+
String samlResponseEncoded = Util.getFileAsString("data/responses/response1.xml.base64");
826+
when(request.getParameterMap()).thenReturn(singletonMap("SAMLResponse", new String[]{samlResponseEncoded}));
827+
when(request.getRequestURL()).thenReturn(new StringBuffer("http://localhost:8080/java-saml-jspsample/acs.jsp"));
828+
829+
Saml2Settings settings = new SettingsBuilder().fromFile("config/config.my.properties").build();
830+
Auth auth = new Auth(settings, request, response);
831+
assertNull(auth.getNameIdFormat());
832+
auth.processResponse();
833+
assertFalse(auth.isAuthenticated());
834+
assertNull(auth.getNameIdFormat());
835+
836+
samlResponseEncoded = Util.getFileAsString("data/responses/valid_response.xml.base64");
837+
when(request.getParameterMap()).thenReturn(singletonMap("SAMLResponse", new String[]{samlResponseEncoded}));
838+
Auth auth2 = new Auth(settings, request, response);
839+
assertNull(auth2.getNameIdFormat());
840+
auth2.processResponse();
841+
assertTrue(auth2.isAuthenticated());
842+
assertEquals("urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", auth2.getNameIdFormat());
843+
844+
samlResponseEncoded = Util.getFileAsString("data/responses/response_encrypted_nameid.xml.base64");
845+
when(request.getParameterMap()).thenReturn(singletonMap("SAMLResponse", new String[]{samlResponseEncoded}));
846+
when(request.getRequestURL()).thenReturn(new StringBuffer("https://pitbulk.no-ip.org/newonelogin/demo1/index.php?acs"));
847+
settings.setStrict(false);
848+
Auth auth3 = new Auth(settings, request, response);
849+
assertNull(auth3.getNameIdFormat());
850+
auth3.processResponse();
851+
assertTrue(auth3.isAuthenticated());
852+
assertEquals("urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified", auth3.getNameIdFormat());
853+
}
854+
813855
/**
814856
* Tests the getNameId method of SamlResponse
815857
*

0 commit comments

Comments
 (0)