[PATCH] Add configurable time tolerance to SAML ticket validation

Wald Commits scm-commit at wald.intevation.org
Wed Jun 28 20:11:03 CEST 2017


# HG changeset patch
# User Tom Gottfried <tom at intevation.de>
# Date 1498673393 -7200
# Node ID 2c8259176c461dcf251d1143de64ccb1fd447524
# Parent  1fa03f3c9d3d9c320f6bd37078ad7f47b367b706
Add configurable time tolerance to SAML ticket validation.

This allows e.g. to account for time skew between the ISP and
the server this servlet is run on.

diff -r 1fa03f3c9d3d -r 2c8259176c46 gwt-client/src/main/java/org/dive4elements/river/client/server/auth/saml/Assertion.java
--- a/gwt-client/src/main/java/org/dive4elements/river/client/server/auth/saml/Assertion.java	Tue May 30 12:51:42 2017 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/server/auth/saml/Assertion.java	Wed Jun 28 20:09:53 2017 +0200
@@ -48,7 +48,6 @@
     private static final String ATTR_CONT_ROLE =
         "urn:conterra:names:sdi-suite:policy:attribute:role";
 
-
     public Assertion(Element assertion) {
         this.assertion = assertion;
         this.roles = new LinkedList<String>();
@@ -174,14 +173,15 @@
      * Returns whether the ticket to which the assertion belongs is
      * valid at the time the method is called. The method returns true,
      * if both dates (notbefore and notonorafter) have been determined
-     * successfully and the current date/time is between both.
+     * successfully and the current date/time is between both (with given
+     * tolerance).
      * @return Whether the ticket is valid now.
      */
-    public boolean isValidNow() {
+    public boolean isValidNow(int timeEps) {
         Date now = new Date();
         return (this.notbefore != null && this.notonorafter != null
-                && now.after(this.notbefore)
-                && !this.notonorafter.before(now));
+            && now.after(new Date(this.notbefore.getTime() - timeEps))
+            && now.before(new Date(this.notonorafter.getTime() + timeEps)));
     }
 }
 // vim: set fileencoding=utf-8 ts=4 sw=4 et si tw=80:
diff -r 1fa03f3c9d3d -r 2c8259176c46 gwt-client/src/main/java/org/dive4elements/river/client/server/auth/saml/TicketValidator.java
--- a/gwt-client/src/main/java/org/dive4elements/river/client/server/auth/saml/TicketValidator.java	Tue May 30 12:51:42 2017 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/server/auth/saml/TicketValidator.java	Wed Jun 28 20:09:53 2017 +0200
@@ -48,11 +48,18 @@
     private Key trustedKey;
 
     /**
+     * Tolerance in milliseconds for validation based on NotBefore and
+     * NotOnOrAfter of the SAML ticket
+     */
+    private int timeEps;
+
+    /**
      * Creates a new TicketValidator from a trusted key.
      * @param trustedKey  The trusted key for the signature checks.
      */
-    public TicketValidator(Key trustedKey) {
+    public TicketValidator(Key trustedKey, int timeEps) {
         this.trustedKey = trustedKey;
+        this.timeEps = timeEps;
     }
 
     /**
@@ -61,9 +68,10 @@
      * @param filename The filename of the X509 certificate containing
      * the trusted public key.
      */
-    public TicketValidator(String filename) throws IOException,
-                                                   CertificateException {
+    public TicketValidator(String filename, int timeEps)
+        throws IOException, CertificateException {
         this.trustedKey = loadKey(filename);
+        this.timeEps = timeEps;
     }
 
     /**
@@ -107,10 +115,11 @@
         }
 
         Assertion assertion = new Assertion(assertionElement);
-        if (!assertion.isValidNow()) {
+        if (!assertion.isValidNow(this.timeEps)) {
             log.error("Ticket is not valid now"
                          + " (NotBefore: " + assertion.getFrom()
-                         + ", NotOnOrAfter: " + assertion.getUntil());
+                         + ", NotOnOrAfter: " + assertion.getUntil()
+                         + ", Tolerance (milliseconds): " + this.timeEps);
             return null;
         }
 
diff -r 1fa03f3c9d3d -r 2c8259176c46 gwt-client/src/main/java/org/dive4elements/river/client/server/auth/was/Authenticator.java
--- a/gwt-client/src/main/java/org/dive4elements/river/client/server/auth/was/Authenticator.java	Tue May 30 12:51:42 2017 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/server/auth/was/Authenticator.java	Wed Jun 28 20:09:53 2017 +0200
@@ -64,8 +64,10 @@
                 else {
                     String trustedKey =
                     (String)context.getInitParameter("saml-trusted-public-key");
+                    String timeEpsilon = context.getInitParameter(
+                        "saml-time-tolerance");
                     return new Response(entity, username, password, features,
-                                        context.getRealPath(trustedKey));
+                        context.getRealPath(trustedKey), timeEpsilon);
                 }
             }
             catch(GeneralSecurityException e) {
diff -r 1fa03f3c9d3d -r 2c8259176c46 gwt-client/src/main/java/org/dive4elements/river/client/server/auth/was/Response.java
--- a/gwt-client/src/main/java/org/dive4elements/river/client/server/auth/was/Response.java	Tue May 30 12:51:42 2017 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/server/auth/was/Response.java	Wed Jun 28 20:09:53 2017 +0200
@@ -45,10 +45,11 @@
     private String password;
     private Features features;
     private String trustedKeyFile;
+    private String timeEpsilon;
 
 
     public Response(HttpEntity entity, String username, String password,
-                    Features features, String trustedKeyFile)
+            Features features, String trustedKeyFile, String timeEpsilon)
         throws AuthenticationException, IOException {
 
         if (entity == null) {
@@ -80,6 +81,7 @@
         this.password = password;
         this.features = features;
         this.trustedKeyFile = trustedKeyFile;
+        this.timeEpsilon = timeEpsilon;
     }
 
     @Override
@@ -97,8 +99,9 @@
     public Assertion getAssertion() {
         if (this.assertion == null && this.root != null) {
             try {
+                int timeEps = Integer.parseInt(this.timeEpsilon);
                 TicketValidator validator =
-                    new TicketValidator(this.trustedKeyFile);
+                    new TicketValidator(this.trustedKeyFile, timeEps);
                 this.assertion = validator.checkTicket(this.root);
             }
             catch (Exception e) {
diff -r 1fa03f3c9d3d -r 2c8259176c46 gwt-client/src/main/webapp/WEB-INF/web.xml
--- a/gwt-client/src/main/webapp/WEB-INF/web.xml	Tue May 30 12:51:42 2017 +0200
+++ b/gwt-client/src/main/webapp/WEB-INF/web.xml	Wed Jun 28 20:09:53 2017 +0200
@@ -51,6 +51,13 @@
     </context-param>
 
     <context-param>
+        <!-- Tolerance in milliseconds for validation based on NotBefore and
+             NotOnOrAfter of the SAML ticket -->
+        <param-name>saml-time-tolerance</param-name>
+        <param-value>1000</param-value>
+    </context-param>
+
+    <context-param>
         <param-name>features-file</param-name>
         <param-value>/WEB-INF/features.xml</param-value>
     </context-param>


More information about the Dive4Elements-commits mailing list