Skip to content

Commit bb6967c

Browse files
committed
Fix #156. Add support for second-level status code. Refactor getStatus method (moved to Utils and used at SAMLResponse and LogoutResponse classes
1 parent 21b6b9e commit bb6967c

File tree

7 files changed

+117
-37
lines changed

7 files changed

+117
-37
lines changed

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

Lines changed: 3 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -577,42 +577,15 @@ public void checkStatus() throws ValidationError {
577577
* @param dom
578578
* The Response as XML
579579
*
580-
* @return array with the code and a message
580+
* @return SamlResponseStatus
581581
*
582582
* @throws IllegalArgumentException
583583
* if the response not contain status or if Unexpected XPath error
584584
* @throws ValidationError
585585
*/
586586
public static SamlResponseStatus getStatus(Document dom) throws ValidationError {
587-
try {
588-
String statusExpr = "/samlp:Response/samlp:Status";
589-
590-
NodeList statusEntry = Util.query(dom, statusExpr, null);
591-
if (statusEntry.getLength() != 1) {
592-
throw new ValidationError("Missing Status on response", ValidationError.MISSING_STATUS);
593-
}
594-
NodeList codeEntry;
595-
596-
codeEntry = Util.query(dom, statusExpr + "/samlp:StatusCode", (Element) statusEntry.item(0));
597-
598-
if (codeEntry.getLength() != 1) {
599-
throw new ValidationError("Missing Status Code on response", ValidationError.MISSING_STATUS_CODE);
600-
}
601-
602-
String stausCode = codeEntry.item(0).getAttributes().getNamedItem("Value").getNodeValue();
603-
SamlResponseStatus status = new SamlResponseStatus(stausCode);
604-
605-
NodeList messageEntry = Util.query(dom, statusExpr + "/samlp:StatusMessage",
606-
(Element) statusEntry.item(0));
607-
if (messageEntry.getLength() == 1) {
608-
status.setStatusMessage(messageEntry.item(0).getTextContent());
609-
}
610-
return status;
611-
} catch (XPathExpressionException e) {
612-
String error = "Unexpected error in getStatus." + e.getMessage();
613-
LOGGER.error(error);
614-
throw new IllegalArgumentException(error);
615-
}
587+
String statusXpath = "/samlp:Response/samlp:Status";
588+
return Util.getStatus(statusXpath, dom);
616589
}
617590

618591
/**

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

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import com.onelogin.saml2.exception.SettingsException;
2323
import com.onelogin.saml2.exception.ValidationError;
2424
import com.onelogin.saml2.http.HttpRequest;
25+
import com.onelogin.saml2.model.SamlResponseStatus;
2526
import com.onelogin.saml2.settings.Saml2Settings;
2627
import com.onelogin.saml2.util.Constants;
2728
import com.onelogin.saml2.util.SchemaFactory;
@@ -295,20 +296,33 @@ public String getIssuer() throws XPathExpressionException {
295296

296297
/**
297298
* Gets the Status of the Logout Response.
298-
*
299+
*
299300
* @return the Status
300301
*
301-
* @throws XPathExpressionException
302+
* @throws XPathExpressionException
302303
*/
303304
public String getStatus() throws XPathExpressionException
304305
{
305306
String statusCode = null;
306307
NodeList entries = this.query("/samlp:LogoutResponse/samlp:Status/samlp:StatusCode");
307308
if (entries.getLength() == 1) {
308309
statusCode = entries.item(0).getAttributes().getNamedItem("Value").getNodeValue();
309-
}
310+
}
310311
return statusCode;
311-
}
312+
}
313+
314+
/**
315+
* Gets the Status of the Logout Response.
316+
*
317+
* @return SamlResponseStatus
318+
*
319+
* @throws ValidationError
320+
*/
321+
public SamlResponseStatus getSamlResponseStatus() throws ValidationError
322+
{
323+
String statusXpath = "/samlp:Response/samlp:Status";
324+
return Util.getStatus(statusXpath, this.logoutResponseDocument);
325+
}
312326

313327
/**
314328
* Extracts nodes that match the query from the DOMDocument (Logout Response Menssage)

core/src/main/java/com/onelogin/saml2/model/SamlResponseStatus.java

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ public class SamlResponseStatus {
1212
*/
1313
private String statusCode;
1414

15+
/**
16+
* Status code second level
17+
*/
18+
private String subStatusCode;
19+
1520
/**
1621
* Status Message
1722
*/
@@ -50,11 +55,28 @@ public String getStatusCode() {
5055
/**
5156
* Set the status code
5257
*
53-
* @param stausCode
58+
* @param statusCode
5459
* String. Status code
5560
*/
56-
public void setStatusCode(String stausCode) {
57-
this.statusCode = stausCode;
61+
public void setStatusCode(String statusCode) {
62+
this.statusCode = statusCode;
63+
}
64+
65+
/**
66+
* @return string the second-level status code
67+
*/
68+
public String getSubStatusCode() {
69+
return subStatusCode;
70+
}
71+
72+
/**
73+
* Set the second-level status code
74+
*
75+
* @param subStatusCode
76+
* String. second-level status code
77+
*/
78+
public void setSubStatusCode(String subStatusCode) {
79+
this.subStatusCode = subStatusCode;
5880
}
5981

6082
/**

core/src/main/java/com/onelogin/saml2/util/Constants.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,27 @@ public final class Constants {
6161
public static String STATUS_REQUESTER = "urn:oasis:names:tc:SAML:2.0:status:Requester";
6262
public static String STATUS_RESPONDER = "urn:oasis:names:tc:SAML:2.0:status:Responder";
6363
public static String STATUS_VERSION_MISMATCH = "urn:oasis:names:tc:SAML:2.0:status:VersionMismatch";
64+
65+
// Status Second-level Codes
66+
public static String STATUS_AUTHNFAILED = "urn:oasis:names:tc:SAML:2.0:status:AuthnFailed";
67+
public static String STATUS_INVALID_ATTRNAME_OR_VALUE = "urn:oasis:names:tc:SAML:2.0:status:InvalidAttrNameOrValue";
68+
public static String STATUS_INVALID_NAMEIDPOLICY = "urn:oasis:names:tc:SAML:2.0:status:InvalidNameIDPolicy";
69+
public static String STATUS_NO_AUTHNCONTEXT = "urn:oasis:names:tc:SAML:2.0:status:NoAuthnContext";
70+
public static String STATUS_NO_AVAILABLE_IDP = "urn:oasis:names:tc:SAML:2.0:status:NoAvailableIDP";
6471
public static String STATUS_NO_PASSIVE = "urn:oasis:names:tc:SAML:2.0:status:NoPassive";
72+
public static String STATUS_NO_SUPPORTED_IDP = "urn:oasis:names:tc:SAML:2.0:status:NoSupportedIDP";
6573
public static String STATUS_PARTIAL_LOGOUT = "urn:oasis:names:tc:SAML:2.0:status:PartialLogout";
6674
public static String STATUS_PROXY_COUNT_EXCEEDED = "urn:oasis:names:tc:SAML:2.0:status:ProxyCountExceeded";
75+
public static String STATUS_REQUEST_DENIED = "urn:oasis:names:tc:SAML:2.0:status:RequestDenied";
76+
public static String STATUS_REQUEST_UNSUPPORTED = "urn:oasis:names:tc:SAML:2.0:status:RequestUnsupported";
77+
public static String STATUS_REQUEST_VERSION_DEPRECATED = "urn:oasis:names:tc:SAML:2.0:status:RequestVersionDeprecated";
78+
public static String STATUS_REQUEST_VERSION_TOO_HIGH = "urn:oasis:names:tc:SAML:2.0:status:RequestVersionTooHigh";
79+
public static String STATUS_REQUEST_VERSION_TOO_LOW = "urn:oasis:names:tc:SAML:2.0:status:RequestVersionTooLow";
80+
public static String STATUS_RESOURCE_NOT_RECOGNIZED = "urn:oasis:names:tc:SAML:2.0:status:ResourceNotRecognized";
81+
public static String STATUS_TOO_MANY_RESPONSES = "urn:oasis:names:tc:SAML:2.0:status:TooManyResponses";
82+
public static String STATUS_UNKNOWN_ATTR_PROFILE = "urn:oasis:names:tc:SAML:2.0:status:UnknownAttrProfile";
83+
public static String STATUS_UNKNOWN_PRINCIPAL = "urn:oasis:names:tc:SAML:2.0:status:UnknownPrincipal";
84+
public static String STATUS_UNSUPPORTED_BINDING = "urn:oasis:names:tc:SAML:2.0:status:UnsupportedBinding";
6785

6886
// Canonization
6987
public static String C14N = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315";

core/src/main/java/com/onelogin/saml2/util/Util.java

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@
8888

8989
import com.onelogin.saml2.exception.ValidationError;
9090
import com.onelogin.saml2.exception.XMLEntityException;
91+
import com.onelogin.saml2.model.SamlResponseStatus;
9192

9293

9394
/**
@@ -1351,6 +1352,50 @@ public static Boolean validateBinarySignature(String signedQuery, byte[] signatu
13511352
return valid;
13521353
}
13531354

1355+
/**
1356+
* Get Status from a Response
1357+
*
1358+
* @param dom
1359+
* The Response as XML
1360+
*
1361+
* @return SamlResponseStatus
1362+
*
1363+
* @throws IllegalArgumentException
1364+
* @throws ValidationError
1365+
*/
1366+
public static SamlResponseStatus getStatus(String statusXpath, Document dom) throws ValidationError {
1367+
try {
1368+
NodeList statusEntry = Util.query(dom, statusXpath, null);
1369+
if (statusEntry.getLength() != 1) {
1370+
throw new ValidationError("Missing Status on response", ValidationError.MISSING_STATUS);
1371+
}
1372+
NodeList codeEntry = Util.query(dom, statusXpath + "/samlp:StatusCode", (Element) statusEntry.item(0));
1373+
1374+
if (codeEntry.getLength() == 0) {
1375+
throw new ValidationError("Missing Status Code on response", ValidationError.MISSING_STATUS_CODE);
1376+
}
1377+
String stausCode = codeEntry.item(0).getAttributes().getNamedItem("Value").getNodeValue();
1378+
SamlResponseStatus status = new SamlResponseStatus(stausCode);
1379+
1380+
NodeList subStatusCodeEntry = Util.query(dom, statusXpath + "/samlp:StatusCode/samlp:StatusCode", (Element) statusEntry.item(0));
1381+
if (subStatusCodeEntry.getLength() > 0) {
1382+
String subStatusCode = subStatusCodeEntry.item(0).getAttributes().getNamedItem("Value").getNodeValue();
1383+
status.setSubStatusCode(subStatusCode);
1384+
}
1385+
1386+
NodeList messageEntry = Util.query(dom, statusXpath + "/samlp:StatusMessage", (Element) statusEntry.item(0));
1387+
if (messageEntry.getLength() == 1) {
1388+
status.setStatusMessage(messageEntry.item(0).getTextContent());
1389+
}
1390+
1391+
return status;
1392+
} catch (XPathExpressionException e) {
1393+
String error = "Unexpected error in getStatus." + e.getMessage();
1394+
LOGGER.error(error);
1395+
throw new IllegalArgumentException(error);
1396+
}
1397+
}
1398+
13541399
/**
13551400
* Generates a nameID.
13561401
*

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -693,6 +693,13 @@ public void testGetStatus() throws IOException, Error, XPathExpressionException,
693693
status = SamlResponse.getStatus(samlResponseDoc);
694694
assertEquals(Constants.STATUS_RESPONDER, status.getStatusCode());
695695
assertEquals("something_is_wrong", status.getStatusMessage());
696+
697+
samlResponseEncoded = Util.getFileAsString("data/responses/invalids/status_code_and_sub_status_code_responder_and_msg.xml.base64");
698+
samlResponseDoc = Util.loadXML(new String(Util.base64decoder(samlResponseEncoded)));
699+
status = SamlResponse.getStatus(samlResponseDoc);
700+
assertEquals(Constants.STATUS_RESPONDER, status.getStatusCode());
701+
assertEquals(Constants.STATUS_AUTHNFAILED, status.getSubStatusCode());
702+
assertEquals("something_is_wrong", status.getStatusMessage());
696703
}
697704

698705
/**
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
PHNhbWxwOlJlc3BvbnNlDQp4bWxuczpzYW1scD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOnByb3RvY29sIg0KQ29uc2VudD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmNvbnNlbnQ6dW5zcGVjaWZpZWQiIERlc3RpbmF0aW9uPSINCmh0dHBzOi8vZXhhbXBsZS5jb20vb3BlbnNzby9Db25zdW1lci9tZXRhQWxpYXMvc3AiDQpJRD0iX2E3MWJiZjIyLTkwYTktNGE5Ni1iOWNlLWVhNWJhMzBhZWU2NSINCkluUmVzcG9uc2VUbz0iczIxMjAzYjI3ZDM4ZDBhMDdlYTJjNzEzZTdhMDA0NWNmOGQxZTMyODExIg0KSXNzdWVJbnN0YW50PSIyMDExLTA4LTI0VDE2OjM2OjMwLjM2NVoiIFZlcnNpb249IjIuMCI+PElzc3Vlcg0KeG1sbnM9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphc3NlcnRpb24iPg0KaHR0cDovL2lkcC5leGFtcGxlLmNvbS9hZGZzL3NlcnZpY2VzL3RydXN0PC9Jc3N1ZXI+PHNhbWxwOlN0YXR1cz48c2FtbHA6U3RhdHVzQ29kZSBWYWx1ZT0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOnN0YXR1czpSZXNwb25kZXIiPjxzYW1scDpTdGF0dXNDb2RlIFZhbHVlPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6c3RhdHVzOkF1dGhuRmFpbGVkIi8+PC9zYW1scDpTdGF0dXNDb2RlPjxzYW1scDpTdGF0dXNNZXNzYWdlPnNvbWV0aGluZ19pc193cm9uZzwvc2FtbHA6U3RhdHVzTWVzc2FnZT48L3NhbWxwOlN0YXR1cz48L3NhbWxwOlJlc3BvbnNlPg==

0 commit comments

Comments
 (0)