# HG changeset patch # User Tom Gottfried # 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(); @@ -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 @@ + + saml-time-tolerance + 1000 + + + features-file /WEB-INF/features.xml