Skip to content

Commit e7ffe2f

Browse files
authored
Merge pull request #73 from miszobi/issue/72-allow-retrieving-assertion-details
Fixes #72: allow retrieving Assertion ID and NotOnOrAfter values
2 parents 40d1276 + 0b3fe35 commit e7ffe2f

5 files changed

Lines changed: 130 additions & 8 deletions

File tree

core/pom.xml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,18 @@
1212

1313
<dependencies>
1414
<!-- for test -->
15+
<dependency>
16+
<groupId>org.hamcrest</groupId>
17+
<artifactId>hamcrest-core</artifactId>
18+
<version>1.3</version>
19+
<scope>test</scope>
20+
</dependency>
21+
<dependency>
22+
<groupId>org.hamcrest</groupId>
23+
<artifactId>hamcrest-library</artifactId>
24+
<version>1.3</version>
25+
<scope>test</scope>
26+
</dependency>
1527
<dependency>
1628
<groupId>junit</groupId>
1729
<artifactId>junit</artifactId>

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

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import org.apache.commons.lang3.StringUtils;
1919
import org.joda.time.DateTime;
20+
import org.joda.time.Instant;
2021
import org.slf4j.Logger;
2122
import org.slf4j.LoggerFactory;
2223

@@ -64,7 +65,7 @@ public class Auth {
6465

6566
/**
6667
* NameID.
67-
*/
68+
*/
6869
private String nameid;
6970

7071
/**
@@ -77,6 +78,16 @@ public class Auth {
7778
*/
7879
private DateTime sessionExpiration;
7980

81+
/**
82+
* The ID of the last assertion processed
83+
*/
84+
private String lastAssertionId;
85+
86+
/**
87+
* The NotOnOrAfter values of the last assertion processed
88+
*/
89+
private List<Instant> lastAssertionNotOnOrAfter;
90+
8091
/**
8192
* User attributes data.
8293
*/
@@ -364,6 +375,8 @@ public void processResponse(String requestId) throws Exception {
364375
attributes = samlResponse.getAttributes();
365376
sessionIndex = samlResponse.getSessionIndex();
366377
sessionExpiration = samlResponse.getSessionNotOnOrAfter();
378+
lastAssertionId = samlResponse.getAssertionId();
379+
lastAssertionNotOnOrAfter = samlResponse.getAssertionNotOnOrAfter();
367380
LOGGER.debug("processResponse success --> " + samlResponseParameter);
368381
} else {
369382
errors.add("invalid_response");
@@ -534,9 +547,23 @@ public final DateTime getSessionExpiration()
534547
return sessionExpiration;
535548
}
536549

537-
/**
538-
* @return an array with the errors, the array is empty when the validation was successful
539-
*/
550+
/**
551+
* @return The ID of the last assertion processed
552+
*/
553+
public String getLastAssertionId() {
554+
return lastAssertionId;
555+
}
556+
557+
/**
558+
* @return The NotOnOrAfter values of the last assertion processed
559+
*/
560+
public List<Instant> getLastAssertionNotOnOrAfter() {
561+
return lastAssertionNotOnOrAfter;
562+
}
563+
564+
/**
565+
* @return an array with the errors, the array is empty when the validation was successful
566+
*/
540567
public List<String> getErrors()
541568
{
542569
return errors;

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

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import com.onelogin.saml2.model.SubjectConfirmationIssue;
1414
import org.apache.commons.lang3.ObjectUtils;
1515
import org.joda.time.DateTime;
16+
import org.joda.time.Instant;
1617
import org.slf4j.Logger;
1718
import org.slf4j.LoggerFactory;
1819
import org.w3c.dom.Document;
@@ -613,6 +614,29 @@ public String getSessionIndex() throws XPathExpressionException {
613614
return sessionIndex;
614615
}
615616

617+
/**
618+
* @return the ID of the assertion in the Response
619+
*/
620+
public String getAssertionId() throws XPathExpressionException {
621+
validateNumAssertions();
622+
final NodeList assertionNode = queryAssertion("");
623+
return assertionNode.item(0).getAttributes().getNamedItem("ID").getNodeValue();
624+
}
625+
626+
/**
627+
* @return a list of NotOnOrAfter values from SubjectConfirmationData nodes in this Response
628+
*/
629+
public List<Instant> getAssertionNotOnOrAfter() throws XPathExpressionException {
630+
final NodeList notOnOrAfterNodes = queryAssertion("/saml:Subject/saml:SubjectConfirmation/saml:SubjectConfirmationData");
631+
final ArrayList<Instant> notOnOrAfters = new ArrayList<>();
632+
for (int i = 0; i < notOnOrAfterNodes.getLength(); i++) {
633+
final Node notOnOrAfterAttribute = notOnOrAfterNodes.item(i).getAttributes().getNamedItem("NotOnOrAfter");
634+
if (notOnOrAfterAttribute != null) {
635+
notOnOrAfters.add(new Instant(notOnOrAfterAttribute.getNodeValue()));
636+
}}
637+
return notOnOrAfters;
638+
}
639+
616640
/**
617641
* Verifies that the document only contains a single Assertion (encrypted or not).
618642
*

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

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
package com.onelogin.saml2.test;
22

33

4-
import static com.onelogin.saml2.util.Util.UNIQUE_ID_PREFIX;
54
import static org.hamcrest.CoreMatchers.is;
65
import static org.hamcrest.CoreMatchers.containsString;
76
import static org.hamcrest.CoreMatchers.not;
87
import static org.hamcrest.CoreMatchers.startsWith;
8+
import static org.hamcrest.Matchers.contains;
99
import static org.junit.Assert.assertEquals;
1010
import static org.junit.Assert.assertFalse;
1111
import static org.junit.Assert.assertNotEquals;
@@ -21,16 +21,15 @@
2121

2222
import java.io.IOException;
2323
import java.net.URISyntaxException;
24-
import java.security.cert.CertificateEncodingException;
2524
import java.util.ArrayList;
26-
import java.util.Collection;
2725
import java.util.HashMap;
2826
import java.util.List;
2927

3028
import javax.servlet.http.HttpServletRequest;
3129
import javax.servlet.http.HttpServletResponse;
3230
import javax.servlet.http.HttpSession;
3331

32+
import org.joda.time.Instant;
3433
import org.junit.Test;
3534

3635
import com.onelogin.saml2.Auth;
@@ -232,8 +231,8 @@ public void testSetStrict() throws IOException, SettingsException, URISyntaxExce
232231
*/
233232
@Test
234233
public void testIsDebugActive() throws IOException, SettingsException, URISyntaxException {
235-
HttpServletRequest request = mock(HttpServletRequest.class);
236234
HttpServletResponse response = mock(HttpServletResponse.class);
235+
HttpServletRequest request = mock(HttpServletRequest.class);
237236
String samlResponseEncoded = Util.getFileAsString("data/responses/response1.xml.base64");
238237
when(request.getParameter("SAMLResponse")).thenReturn(samlResponseEncoded);
239238

@@ -811,6 +810,22 @@ public void testGetSessionIndex() throws Exception {
811810
assertEquals("_6273d77b8cde0c333ec79d22a9fa0003b9fe2d75cb", auth2.getSessionIndex());
812811
}
813812

813+
@Test
814+
public void testGetAssertionDetails() throws Exception {
815+
HttpServletResponse response = mock(HttpServletResponse.class);
816+
HttpServletRequest request = mock(HttpServletRequest.class);
817+
String samlResponseEncoded = Util.getFileAsString("data/responses/valid_response.xml.base64");
818+
when(request.getParameter("SAMLResponse")).thenReturn(samlResponseEncoded);
819+
when(request.getRequestURL()).thenReturn(new StringBuffer("http://localhost:8080/java-saml-jspsample/acs.jsp"));
820+
821+
Saml2Settings settings = new SettingsBuilder().fromFile("config/config.my.properties").build();
822+
Auth auth = new Auth(settings, request, response);
823+
auth.processResponse();
824+
825+
assertThat(auth.getLastAssertionId(), is("pfxeac87197-11cb-ec12-c181-ae739b54debe"));
826+
assertThat(auth.getLastAssertionNotOnOrAfter(), contains(new Instant("2023-08-23T06:57:01Z")));
827+
}
828+
814829
/**
815830
* Tests the getSessionExpiration method of Auth
816831
*

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

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import static org.hamcrest.CoreMatchers.containsString;
44
import static org.hamcrest.CoreMatchers.not;
5+
import static org.hamcrest.Matchers.*;
56
import static org.junit.Assert.assertEquals;
67
import static org.junit.Assert.assertThat;
78
import static org.junit.Assert.assertNull;
@@ -16,6 +17,7 @@
1617

1718
import javax.servlet.http.HttpServletRequest;
1819

20+
import org.joda.time.Instant;
1921
import org.junit.Test;
2022
import org.w3c.dom.Document;
2123
import org.w3c.dom.Node;
@@ -474,6 +476,48 @@ public void testGetSessionIndex() throws Exception {
474476
assertEquals("_7164a9a9f97828bfdb8d0ebc004a05d2e7d873f70c", samlResponse.getSessionIndex());
475477
}
476478

479+
@Test
480+
public void testGetAssertionDetails() throws Exception {
481+
final SamlResponse samlResponse = new SamlResponse(
482+
new SettingsBuilder().fromFile("config/config.my.properties").build(),
483+
mockRequestWithSamlResponse(Util.getFileAsString("data/responses/response1.xml.base64"))
484+
);
485+
final List<Instant> notOnOrAfters = samlResponse.getAssertionNotOnOrAfter();
486+
487+
assertEquals("pfxa46574df-b3b0-a06a-23c8-636413198772", samlResponse.getAssertionId());
488+
assertThat(notOnOrAfters, contains(new Instant("2010-11-18T22:02:37Z")));
489+
490+
}
491+
492+
@Test
493+
public void testGetAssertionDetails_encrypted() throws Exception {
494+
final SamlResponse samlResponse = new SamlResponse(
495+
new SettingsBuilder().fromFile("config/config.my.properties").build(),
496+
mockRequestWithSamlResponse(Util.getFileAsString("data/responses/valid_encrypted_assertion.xml.base64"))
497+
);
498+
final List<Instant> notOnOrAfters = samlResponse.getAssertionNotOnOrAfter();
499+
500+
assertEquals("_519c2712648ee09a06d1f9a08e9e835715fea60267", samlResponse.getAssertionId());
501+
assertThat(notOnOrAfters, contains(new Instant("2055-06-07T20:17:08Z")));
502+
503+
}
504+
505+
@Test
506+
public void testGetAssertionDetails_multiple() throws Exception {
507+
Saml2Settings settings = new SettingsBuilder().fromFile("config/config.my.properties").build();
508+
settings.setWantAssertionsSigned(false);
509+
settings.setWantMessagesSigned(true);
510+
511+
final SamlResponse samlResponse = new SamlResponse(
512+
settings,
513+
mockRequestWithSamlResponse(loadSignMessageAndEncode("data/responses/invalids/invalid_subjectconfirmation_multiple_issues.xml"))
514+
);
515+
final List<Instant> notOnOrAfters = samlResponse.getAssertionNotOnOrAfter();
516+
517+
assertEquals("pfx7841991c-c73f-4035-e2ee-c170c0e1d3e4", samlResponse.getAssertionId());
518+
assertThat(notOnOrAfters, contains(new Instant("2120-06-17T14:53:44Z"), new Instant("2010-06-17T14:53:44Z")));
519+
}
520+
477521
/**
478522
* Tests the getAttributes method of SamlResponse
479523
*

0 commit comments

Comments
 (0)