|
15 | 15 | import javax.xml.xpath.XPathExpressionException; |
16 | 16 | import javax.xml.xpath.XPathFactory; |
17 | 17 |
|
| 18 | +import org.apache.commons.lang3.StringUtils; |
18 | 19 | import org.joda.time.DateTime; |
19 | 20 | import org.slf4j.Logger; |
20 | 21 | import org.slf4j.LoggerFactory; |
@@ -242,55 +243,7 @@ public boolean isValid(String requestId) { |
242 | 243 | } |
243 | 244 | } |
244 | 245 |
|
245 | | - // Check SubjectConfirmation, at least one SubjectConfirmation must be valid |
246 | | - boolean validSubjectConfirmation = false; |
247 | | - NodeList subjectConfirmationNodes = this.queryAssertion("/saml:Subject/saml:SubjectConfirmation"); |
248 | | - for (int i = 0; i < subjectConfirmationNodes.getLength(); i++) { |
249 | | - Node scn = subjectConfirmationNodes.item(i); |
250 | | - |
251 | | - Node method = scn.getAttributes().getNamedItem("Method"); |
252 | | - if (method != null && !method.getNodeValue().equals(Constants.CM_BEARER)) { |
253 | | - continue; |
254 | | - } |
255 | | - |
256 | | - NodeList subjectConfirmationDataNodes = scn.getChildNodes(); |
257 | | - for (int c = 0; c < subjectConfirmationDataNodes.getLength(); c++) { |
258 | | - if (subjectConfirmationDataNodes.item(c).getLocalName() != null && subjectConfirmationDataNodes.item(c).getLocalName().equals("SubjectConfirmationData")) { |
259 | | - |
260 | | - Node recipient = subjectConfirmationDataNodes.item(c).getAttributes().getNamedItem("Recipient"); |
261 | | - if (recipient != null && !recipient.getNodeValue().isEmpty() |
262 | | - && !recipient.getNodeValue().equals(currentUrl)) { |
263 | | - continue; |
264 | | - } |
265 | | - |
266 | | - Node inResponseTo = subjectConfirmationDataNodes.item(c).getAttributes().getNamedItem("InResponseTo"); |
267 | | - if (inResponseTo != null && !inResponseTo.getNodeValue().equals(responseInResponseTo)) { |
268 | | - continue; |
269 | | - } |
270 | | - |
271 | | - |
272 | | - Node notOnOrAfter = subjectConfirmationDataNodes.item(c).getAttributes().getNamedItem("NotOnOrAfter"); |
273 | | - if (notOnOrAfter != null) { |
274 | | - DateTime noa = Util.parseDateTime(notOnOrAfter.getNodeValue()); |
275 | | - if (noa.isEqualNow() || noa.isBeforeNow()) { |
276 | | - continue; |
277 | | - } |
278 | | - } |
279 | | - |
280 | | - Node notBefore = subjectConfirmationDataNodes.item(c).getAttributes().getNamedItem("NotBefore"); |
281 | | - if (notBefore != null) { |
282 | | - DateTime nb = Util.parseDateTime(notBefore.getNodeValue()); |
283 | | - if (nb.isAfterNow()) { |
284 | | - continue; |
285 | | - } |
286 | | - } |
287 | | - validSubjectConfirmation = true; |
288 | | - } |
289 | | - } |
290 | | - } |
291 | | - if (!validSubjectConfirmation) { |
292 | | - throw new Exception("A valid SubjectConfirmation was not found on this Response"); |
293 | | - } |
| 246 | + validateSubjectConfirmation(responseInResponseTo); |
294 | 247 |
|
295 | 248 | if (settings.getWantAssertionsSigned() && !signedElements.contains("Assertion")) { |
296 | 249 | throw new Exception("The Assertion of the Response is not signed and the SP requires it"); |
@@ -334,6 +287,72 @@ public boolean isValid(String requestId) { |
334 | 287 | } |
335 | 288 | } |
336 | 289 |
|
| 290 | + // Check SubjectConfirmation, at least one SubjectConfirmation must be valid |
| 291 | + private void validateSubjectConfirmation(String responseInResponseTo) throws Exception { |
| 292 | + final List<String> subjectConfirmationDataIssues = new ArrayList<>(); |
| 293 | + boolean validSubjectConfirmation = false; |
| 294 | + NodeList subjectConfirmationNodes = this.queryAssertion("/saml:Subject/saml:SubjectConfirmation"); |
| 295 | + for (int i = 0; i < subjectConfirmationNodes.getLength(); i++) { |
| 296 | + Node scn = subjectConfirmationNodes.item(i); |
| 297 | + |
| 298 | + Node method = scn.getAttributes().getNamedItem("Method"); |
| 299 | + if (method != null && !method.getNodeValue().equals(Constants.CM_BEARER)) { |
| 300 | + continue; |
| 301 | + } |
| 302 | + |
| 303 | + NodeList subjectConfirmationDataNodes = scn.getChildNodes(); |
| 304 | + for (int c = 0; c < subjectConfirmationDataNodes.getLength(); c++) { |
| 305 | + if (subjectConfirmationDataNodes.item(c).getLocalName() != null && subjectConfirmationDataNodes.item(c).getLocalName().equals("SubjectConfirmationData")) { |
| 306 | + |
| 307 | + Node recipient = subjectConfirmationDataNodes.item(c).getAttributes().getNamedItem("Recipient"); |
| 308 | + if (recipient == null) { |
| 309 | + subjectConfirmationDataIssues.add("SubjectConfirmationData doesn't contain a Recipient"); |
| 310 | + continue; |
| 311 | + } |
| 312 | + |
| 313 | + if (!recipient.getNodeValue().equals(currentUrl)) { |
| 314 | + subjectConfirmationDataIssues.add("SubjectConfirmationData doesn't match a valid Recipient"); |
| 315 | + continue; |
| 316 | + } |
| 317 | + |
| 318 | + Node inResponseTo = subjectConfirmationDataNodes.item(c).getAttributes().getNamedItem("InResponseTo"); |
| 319 | + if (inResponseTo != null && !inResponseTo.getNodeValue().equals(responseInResponseTo)) { |
| 320 | + subjectConfirmationDataIssues.add("SubjectConfirmationData has an invalid InResponseTo value"); |
| 321 | + continue; |
| 322 | + } |
| 323 | + |
| 324 | + |
| 325 | + Node notOnOrAfter = subjectConfirmationDataNodes.item(c).getAttributes().getNamedItem("NotOnOrAfter"); |
| 326 | + if (notOnOrAfter == null) { |
| 327 | + subjectConfirmationDataIssues.add("SubjectConfirmationData doesn't contain a NotOnOrAfter attribute"); |
| 328 | + continue; |
| 329 | + } |
| 330 | + |
| 331 | + DateTime noa = Util.parseDateTime(notOnOrAfter.getNodeValue()); |
| 332 | + if (noa.isEqualNow() || noa.isBeforeNow()) { |
| 333 | + subjectConfirmationDataIssues.add("SubjectConfirmationData is no longer valid"); |
| 334 | + continue; |
| 335 | + } |
| 336 | + |
| 337 | + Node notBefore = subjectConfirmationDataNodes.item(c).getAttributes().getNamedItem("NotBefore"); |
| 338 | + if (notBefore != null) { |
| 339 | + DateTime nb = Util.parseDateTime(notBefore.getNodeValue()); |
| 340 | + if (nb.isAfterNow()) { |
| 341 | + subjectConfirmationDataIssues.add("SubjectConfirmationData is not yet valid"); |
| 342 | + continue; |
| 343 | + } |
| 344 | + } |
| 345 | + validSubjectConfirmation = true; |
| 346 | + } |
| 347 | + } |
| 348 | + } |
| 349 | + if (!validSubjectConfirmation) { |
| 350 | + String subjectConfirmationDataIssuesMsg = subjectConfirmationDataIssues.isEmpty() ? "" : |
| 351 | + " - " + StringUtils.join(subjectConfirmationDataIssues, ", "); |
| 352 | + throw new Exception("A valid SubjectConfirmation was not found on this Response" + subjectConfirmationDataIssuesMsg); |
| 353 | + } |
| 354 | + } |
| 355 | + |
337 | 356 | /** |
338 | 357 | * Determines if the SAML Response is valid using the certificate. |
339 | 358 | * |
|
0 commit comments