Merge branch 'stable-2.15'

* stable-2.15:
  Update bazlets to the latest stable-2.15 to use 2.15.2 API
  Upgrade JGit to 4.9.2.201712150930-r.15-g5fe8e31d4
  Update bazlets to latest revision on stable-2.15
  Update bazlets to latest revision on stable-2.14
  Format Java files with google-java-format 1.5
  Update bazlets to use 2.15 release API
  Add support for "expires_in" field in authentication response
  Update bazlets to the latest on stable-2.14 to use 2.14.7 release API
  Replace joda-time with Java 8 API
  Format BUILD file with buildifier
  Replace Guava's Optional with Java 8 Optional
  LfsSshAuth: Check number of arguments to git-lfs-authenticate command

Change-Id: I99b4fc74e0970ff7ac217c3b58961fcd34c4f679
diff --git a/src/main/java/com/googlesource/gerrit/plugins/lfs/AuthInfo.java b/src/main/java/com/googlesource/gerrit/plugins/lfs/AuthInfo.java
index 187ce6f..4336ed5 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/lfs/AuthInfo.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/lfs/AuthInfo.java
@@ -14,12 +14,48 @@
 
 package com.googlesource.gerrit.plugins.lfs;
 
-public class AuthInfo {
-  public final String authToken;
-  public final String expiresAt;
+import java.time.Instant;
 
-  public AuthInfo(String authToken, String expiresAt) {
+public class AuthInfo {
+  private final String authToken;
+  private final Instant issued;
+  private final Long expiresIn;
+
+  /**
+   * @param authToken token
+   * @param issued time at which the token was issued
+   * @param expiresIn expiry duration in seconds
+   */
+  public AuthInfo(String authToken, Instant issued, Long expiresIn) {
     this.authToken = authToken;
-    this.expiresAt = expiresAt;
+    this.issued = issued;
+    this.expiresIn = expiresIn;
+  }
+
+  /**
+   * Get the auth token
+   *
+   * @return the auth token
+   */
+  public String authToken() {
+    return authToken;
+  }
+
+  /**
+   * Get a formatted timestamp of the time at which this authentication expires
+   *
+   * @return timestamp
+   */
+  public String expiresAt() {
+    return LfsDateTime.format(issued.plusSeconds(expiresIn));
+  }
+
+  /**
+   * Get the time duration after which this authentication expires
+   *
+   * @return the time duration in seconds
+   */
+  public Long expiresIn() {
+    return expiresIn;
   }
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/lfs/ExpiringAction.java b/src/main/java/com/googlesource/gerrit/plugins/lfs/ExpiringAction.java
index 7d43d04..d3255a1 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/lfs/ExpiringAction.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/lfs/ExpiringAction.java
@@ -21,10 +21,12 @@
 
 public class ExpiringAction extends Response.Action {
   public final String expiresAt;
+  public final Long expiresIn;
 
   public ExpiringAction(String href, AuthInfo info) {
     this.href = href;
-    this.header = Collections.singletonMap(HDR_AUTHORIZATION, info.authToken);
-    this.expiresAt = info.expiresAt;
+    this.header = Collections.singletonMap(HDR_AUTHORIZATION, info.authToken());
+    this.expiresAt = info.expiresAt();
+    this.expiresIn = info.expiresIn();
   }
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsAuthToken.java b/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsAuthToken.java
index 0cadf7b..a603705 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsAuthToken.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsAuthToken.java
@@ -1,30 +1,28 @@
-//Copyright (C) 2017 The Android Open Source Project
+// Copyright (C) 2017 The Android Open Source Project
 //
-//Licensed under the Apache License, Version 2.0 (the "License");
-//you may not use this file except in compliance with the License.
-//You may obtain a copy of the License at
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
 //
-//http://www.apache.org/licenses/LICENSE-2.0
+// http://www.apache.org/licenses/LICENSE-2.0
 //
-//Unless required by applicable law or agreed to in writing, software
-//distributed under the License is distributed on an "AS IS" BASIS,
-//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-//See the License for the specific language governing permissions and
-//limitations under the License.
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
 
 package com.googlesource.gerrit.plugins.lfs;
 
 import com.google.common.base.Joiner;
 import com.google.common.base.Splitter;
+import java.time.Instant;
 import java.util.List;
 import java.util.Optional;
 
 public abstract class LfsAuthToken {
-  private static final LfsDateTime FORMAT = LfsDateTime.instance();
-
   public abstract static class Processor<T extends LfsAuthToken> {
     private static final char DELIMETER = '~';
-
     protected final LfsCipher cipher;
 
     protected Processor(LfsCipher cipher) {
@@ -40,7 +38,6 @@
       if (!decrypted.isPresent()) {
         return Optional.empty();
       }
-
       return createToken(Splitter.on(DELIMETER).splitToList(decrypted.get()));
     }
 
@@ -57,27 +54,26 @@
     }
 
     public boolean verify() {
-      return onTime(token.expiresAt) && verifyTokenValues();
+      return onTime(Instant.now()) && verifyTokenValues();
     }
 
     protected abstract boolean verifyTokenValues();
 
-    static boolean onTime(String dateTime) {
-      return FORMAT.now().compareTo(dateTime) <= 0;
+    public boolean onTime(Instant when) {
+      return when.isBefore(token.issued.plusSeconds(token.expiresIn));
     }
   }
 
-  public final String expiresAt;
+  public final Instant issued;
+  public final Long expiresIn;
 
-  protected LfsAuthToken(int expirationSeconds) {
-    this(timeout(expirationSeconds));
+  protected LfsAuthToken(Instant issued, Long expiresIn) {
+    this.issued = issued;
+    this.expiresIn = expiresIn;
   }
 
-  protected LfsAuthToken(String expiresAt) {
-    this.expiresAt = expiresAt;
-  }
-
-  static String timeout(int expirationSeconds) {
-    return FORMAT.now(expirationSeconds);
+  protected LfsAuthToken(String issued, Long expiresIn) {
+    this.issued = Instant.parse(issued);
+    this.expiresIn = expiresIn;
   }
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsDateTime.java b/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsDateTime.java
index b47eb98..4a1936c 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsDateTime.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsDateTime.java
@@ -15,40 +15,21 @@
 package com.googlesource.gerrit.plugins.lfs;
 
 import java.time.Instant;
-import java.time.ZoneId;
 import java.time.ZoneOffset;
 import java.time.format.DateTimeFormatter;
 import java.util.Locale;
 
 public class LfsDateTime {
-  private final DateTimeFormatter format;
+  private static final DateTimeFormatter FORMAT =
+      DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ")
+          .withZone(ZoneOffset.UTC)
+          .withLocale(Locale.getDefault());
 
-  private LfsDateTime(ZoneId zone) {
-    format =
-        DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ")
-            .withZone(zone)
-            .withLocale(Locale.getDefault());
+  public static String now() {
+    return FORMAT.format(Instant.now());
   }
 
-  /* Create an instance with the system default time zone. */
-  public static LfsDateTime instance() {
-    return new LfsDateTime(ZoneOffset.systemDefault());
-  }
-
-  /* Create an instance with the specified time zone. */
-  public static LfsDateTime instance(ZoneId zone) {
-    return new LfsDateTime(zone);
-  }
-
-  public String now() {
-    return format.format(Instant.now());
-  }
-
-  public String now(int secondsToAdd) {
-    return format.format(Instant.now().plusSeconds(secondsToAdd));
-  }
-
-  public String format(Instant instant) {
-    return format.format(instant);
+  public static String format(Instant instant) {
+    return FORMAT.format(instant);
   }
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsRepositoryResolver.java b/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsRepositoryResolver.java
index cbb5e95..914e638 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsRepositoryResolver.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsRepositoryResolver.java
@@ -62,7 +62,7 @@
       return repository;
     }
 
-    //this is unlikely situation as cache is pre-populated from config but...
+    // this is unlikely situation as cache is pre-populated from config but...
     log.error(
         String.format(
             "Project %s is configured with not existing" + " backend %s of type %s",
diff --git a/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsSshAuth.java b/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsSshAuth.java
index 61a6032..08d7ca7 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsSshAuth.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsSshAuth.java
@@ -48,6 +48,9 @@
 
   @Override
   public String authenticate(CurrentUser user, List<String> args) throws UnloggedFailure, Failure {
+    if (args.size() != 2) {
+      throw new UnloggedFailure(1, "Unexpected number of arguments");
+    }
     try {
       URL url = new URL(canonicalWebUrl);
       String path = url.getPath();
diff --git a/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsSshRequestAuthorizer.java b/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsSshRequestAuthorizer.java
index 22e6b8e..6397e7a 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsSshRequestAuthorizer.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsSshRequestAuthorizer.java
@@ -17,6 +17,7 @@
 import com.google.gerrit.server.CurrentUser;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
+import java.time.Instant;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Optional;
@@ -26,22 +27,21 @@
 @Singleton
 class LfsSshRequestAuthorizer {
   static class SshAuthInfo extends AuthInfo {
-    SshAuthInfo(String authToken, String expiresAt) {
-      super(SSH_AUTH_PREFIX + authToken, expiresAt);
+    SshAuthInfo(String authToken, Instant issued, Long expiresIn) {
+      super(SSH_AUTH_PREFIX + authToken, issued, expiresIn);
     }
   }
 
   private static final Logger log = LoggerFactory.getLogger(LfsSshRequestAuthorizer.class);
   private static final int DEFAULT_SSH_TIMEOUT = 10;
   static final String SSH_AUTH_PREFIX = "Ssh: ";
-
   private final Processor processor;
-  private final int expirationSeconds;
+  private final Long expiresIn;
 
   @Inject
   LfsSshRequestAuthorizer(Processor processor, LfsConfigurationFactory configFactory) {
     this.processor = processor;
-    int timeout = DEFAULT_SSH_TIMEOUT;
+    long timeout = DEFAULT_SSH_TIMEOUT;
     try {
       timeout =
           configFactory
@@ -53,13 +53,13 @@
           DEFAULT_SSH_TIMEOUT,
           e);
     }
-    this.expirationSeconds = timeout;
+    this.expiresIn = timeout;
   }
 
   SshAuthInfo generateAuthInfo(CurrentUser user, String project, String operation) {
     LfsSshAuthToken token =
-        new LfsSshAuthToken(user.getUserName().get(), project, operation, expirationSeconds);
-    return new SshAuthInfo(processor.serialize(token), token.expiresAt);
+        new LfsSshAuthToken(user.getUserName().get(), project, operation, Instant.now(), expiresIn);
+    return new SshAuthInfo(processor.serialize(token), token.issued, token.expiresIn);
   }
 
   Optional<String> getUserFromValidToken(String authToken, String project, String operation) {
@@ -67,13 +67,11 @@
     if (!token.isPresent()) {
       return Optional.empty();
     }
-
     Verifier verifier = new Verifier(token.get(), project, operation);
     if (!verifier.verify()) {
       log.error("Invalid data was provided with auth token {}.", authToken);
       return Optional.empty();
     }
-
     return Optional.of(token.get().user);
   }
 
@@ -89,18 +87,23 @@
       values.add(token.user);
       values.add(token.project);
       values.add(token.operation);
-      values.add(token.expiresAt);
+      values.add(LfsDateTime.format(token.issued));
+      values.add(String.valueOf(token.expiresIn));
       return values;
     }
 
     @Override
     protected Optional<LfsSshAuthToken> createToken(List<String> values) {
-      if (values.size() != 4) {
+      if (values.size() != 5) {
         return Optional.empty();
       }
-
       return Optional.of(
-          new LfsSshAuthToken(values.get(0), values.get(1), values.get(2), values.get(3)));
+          new LfsSshAuthToken(
+              values.get(0),
+              values.get(1),
+              values.get(2),
+              values.get(3),
+              Long.valueOf(values.get(4))));
     }
   }
 
@@ -125,15 +128,15 @@
     private final String project;
     private final String operation;
 
-    LfsSshAuthToken(String user, String project, String operation, int expirationSeconds) {
-      super(expirationSeconds);
+    LfsSshAuthToken(String user, String project, String operation, Instant issued, Long expiresIn) {
+      super(issued, expiresIn);
       this.user = user;
       this.project = project;
       this.operation = operation;
     }
 
-    LfsSshAuthToken(String user, String project, String operation, String expiresAt) {
-      super(expiresAt);
+    LfsSshAuthToken(String user, String project, String operation, String issued, Long expiresIn) {
+      super(issued, expiresIn);
       this.user = user;
       this.project = project;
       this.operation = operation;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/lfs/fs/LfsFsRequestAuthorizer.java b/src/main/java/com/googlesource/gerrit/plugins/lfs/fs/LfsFsRequestAuthorizer.java
index f27eb62..1336884 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/lfs/fs/LfsFsRequestAuthorizer.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/lfs/fs/LfsFsRequestAuthorizer.java
@@ -19,6 +19,8 @@
 import com.googlesource.gerrit.plugins.lfs.AuthInfo;
 import com.googlesource.gerrit.plugins.lfs.LfsAuthToken;
 import com.googlesource.gerrit.plugins.lfs.LfsCipher;
+import com.googlesource.gerrit.plugins.lfs.LfsDateTime;
+import java.time.Instant;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Optional;
@@ -34,9 +36,10 @@
     this.processor = processor;
   }
 
-  public AuthInfo generateAuthInfo(String operation, AnyLongObjectId id, int expirationSeconds) {
-    LfsFsAuthToken token = new LfsFsAuthToken(operation, id, expirationSeconds);
-    return new AuthInfo(processor.serialize(token), token.expiresAt);
+  public AuthInfo generateAuthInfo(
+      String operation, AnyLongObjectId id, Instant now, Long expiresIn) {
+    LfsFsAuthToken token = new LfsFsAuthToken(operation, id, now, expiresIn);
+    return new AuthInfo(processor.serialize(token), token.issued, token.expiresIn);
   }
 
   public boolean verifyAuthInfo(String authToken, String operation, AnyLongObjectId id) {
@@ -44,7 +47,6 @@
     if (!token.isPresent()) {
       return false;
     }
-
     return new Verifier(token.get(), operation, id).verify();
   }
 
@@ -59,18 +61,22 @@
       List<String> values = new ArrayList<>(3);
       values.add(token.operation);
       values.add(token.id.getName());
-      values.add(token.expiresAt);
+      values.add(LfsDateTime.format(token.issued));
+      values.add(String.valueOf(token.expiresIn));
       return values;
     }
 
     @Override
     protected Optional<LfsFsAuthToken> createToken(List<String> values) {
-      if (values.size() != 3) {
+      if (values.size() != 4) {
         return Optional.empty();
       }
-
       return Optional.of(
-          new LfsFsAuthToken(values.get(0), LongObjectId.fromString(values.get(1)), values.get(2)));
+          new LfsFsAuthToken(
+              values.get(0),
+              LongObjectId.fromString(values.get(1)),
+              values.get(2),
+              Long.valueOf(values.get(3))));
     }
   }
 
@@ -94,14 +100,14 @@
     private final String operation;
     private final AnyLongObjectId id;
 
-    LfsFsAuthToken(String operation, AnyLongObjectId id, int expirationSeconds) {
-      super(expirationSeconds);
+    LfsFsAuthToken(String operation, AnyLongObjectId id, Instant issued, Long expiresIn) {
+      super(issued, expiresIn);
       this.operation = operation;
       this.id = id;
     }
 
-    LfsFsAuthToken(String operation, AnyLongObjectId id, String expiresAt) {
-      super(expiresAt);
+    LfsFsAuthToken(String operation, AnyLongObjectId id, String issued, Long expiresIn) {
+      super(issued, expiresIn);
       this.operation = operation;
       this.id = id;
     }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/lfs/fs/LocalLargeFileRepository.java b/src/main/java/com/googlesource/gerrit/plugins/lfs/fs/LocalLargeFileRepository.java
index 4d897d4..172861b 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/lfs/fs/LocalLargeFileRepository.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/lfs/fs/LocalLargeFileRepository.java
@@ -32,6 +32,7 @@
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.time.Instant;
 import org.eclipse.jgit.lfs.lib.AnyLongObjectId;
 import org.eclipse.jgit.lfs.server.Response;
 import org.eclipse.jgit.lfs.server.fs.FileLfsRepository;
@@ -42,11 +43,11 @@
   }
 
   public static final String CONTENT_PATH = "content";
-  private static final int DEFAULT_TIMEOUT = 10; //in seconds
+  private static final int DEFAULT_TIMEOUT = 10; // in seconds
 
   private final String servletUrlPattern;
   private final LfsFsRequestAuthorizer authorizer;
-  private final int expirationSeconds;
+  private final Long expiresIn;
 
   @Inject
   LocalLargeFileRepository(
@@ -61,10 +62,11 @@
         getOrCreateDataDir(configFactory.getGlobalConfig(), backend, defaultDataDir));
     this.authorizer = authorizer;
     this.servletUrlPattern = "/" + getContentPath(backend) + "*";
-    this.expirationSeconds =
-        configFactory
-            .getGlobalConfig()
-            .getInt(backend.type.name(), backend.name, "expirationSeconds", DEFAULT_TIMEOUT);
+    this.expiresIn =
+        (long)
+            configFactory
+                .getGlobalConfig()
+                .getInt(backend.type.name(), backend.name, "expirationSeconds", DEFAULT_TIMEOUT);
   }
 
   public String getServletUrlPattern() {
@@ -74,14 +76,14 @@
   @Override
   public Response.Action getDownloadAction(AnyLongObjectId id) {
     Response.Action action = super.getDownloadAction(id);
-    AuthInfo authInfo = authorizer.generateAuthInfo(DOWNLOAD, id, expirationSeconds);
+    AuthInfo authInfo = authorizer.generateAuthInfo(DOWNLOAD, id, Instant.now(), expiresIn);
     return new ExpiringAction(action.href, authInfo);
   }
 
   @Override
   public Response.Action getUploadAction(AnyLongObjectId id, long size) {
     Response.Action action = super.getUploadAction(id, size);
-    AuthInfo authInfo = authorizer.generateAuthInfo(UPLOAD, id, expirationSeconds);
+    AuthInfo authInfo = authorizer.generateAuthInfo(UPLOAD, id, Instant.now(), expiresIn);
     return new ExpiringAction(action.href, authInfo);
   }
 
diff --git a/src/main/java/com/googlesource/gerrit/plugins/lfs/locks/LfsProjectLocks.java b/src/main/java/com/googlesource/gerrit/plugins/lfs/locks/LfsProjectLocks.java
index 7dfa103..4f612ee 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/lfs/locks/LfsProjectLocks.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/lfs/locks/LfsProjectLocks.java
@@ -50,8 +50,6 @@
           .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
           .disableHtmlEscaping()
           .create();
-  private static final LfsDateTime FORMAT = LfsDateTime.instance();
-
   private final PathToLockId toLockId;
   private final String project;
   private final Path locksPath;
@@ -105,7 +103,8 @@
     }
 
     lock =
-        new LfsLock(lockId, input.path, FORMAT.now(), new LfsLockOwner(user.getUserName().get()));
+        new LfsLock(
+            lockId, input.path, LfsDateTime.now(), new LfsLockOwner(user.getUserName().get()));
     LockFile fileLock = new LockFile(locksPath.resolve(lockId).toFile());
     try {
       if (!fileLock.lock()) {
diff --git a/src/test/java/com/googlesource/gerrit/plugins/lfs/LfsAuthTokenTest.java b/src/test/java/com/googlesource/gerrit/plugins/lfs/LfsAuthTokenTest.java
index c074151..5a72637 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/lfs/LfsAuthTokenTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/lfs/LfsAuthTokenTest.java
@@ -15,7 +15,6 @@
 package com.googlesource.gerrit.plugins.lfs;
 
 import static com.google.common.truth.Truth.assertThat;
-import static com.googlesource.gerrit.plugins.lfs.LfsAuthToken.Verifier.onTime;
 
 import java.time.Instant;
 import java.util.ArrayList;
@@ -25,58 +24,41 @@
 
 public class LfsAuthTokenTest {
   private final LfsCipher cipher = new LfsCipher();
-  private final LfsDateTime formatter = LfsDateTime.instance();
-
-  @Test
-  public void testExpiredTime() throws Exception {
-    // test that even 1ms expiration is enough
-    assertThat(onTime(formatter.format(now().minusMillis(1)))).isFalse();
-  }
-
-  @Test
-  public void testOnTime() throws Exception {
-    // if there is at least 1ms before there is no timeout
-    assertThat(onTime(formatter.format(now().plusMillis(1)))).isTrue();
-  }
 
   @Test
   public void testTokenSerializationDeserialization() throws Exception {
     TestTokenProessor processor = new TestTokenProessor(cipher);
-    TestToken token = new TestToken(0);
+    TestToken token = new TestToken(Instant.now(), 0L);
     String serialized = processor.serialize(token);
-
     assertThat(serialized).isNotEmpty();
-
     Optional<TestToken> deserialized = processor.deserialize(serialized);
     assertThat(deserialized.isPresent()).isTrue();
-    assertThat(token.expiresAt).isEqualTo(deserialized.get().expiresAt);
+    assertThat(token.issued).isEqualTo(deserialized.get().issued);
   }
 
   @Test
   public void testTokenOnTime() throws Exception {
-    TestToken token = new TestToken(1);
+    Instant when = Instant.now();
+    TestToken token = new TestToken(when, 1L);
     TestTokenVerifier verifier = new TestTokenVerifier(token);
-    assertThat(verifier.verify()).isTrue();
+    assertThat(verifier.onTime(when.plusMillis(999))).isTrue();
   }
 
   @Test
   public void testTokenExpired() throws Exception {
-    TestToken token = new TestToken(-1);
+    Instant when = Instant.now();
+    TestToken token = new TestToken(when, 1L);
     TestTokenVerifier verifier = new TestTokenVerifier(token);
-    assertThat(verifier.verify()).isFalse();
-  }
-
-  private Instant now() {
-    return Instant.now();
+    assertThat(verifier.onTime(when.plusMillis(1001))).isFalse();
   }
 
   private class TestToken extends LfsAuthToken {
-    TestToken(int expirationSeconds) {
-      super(expirationSeconds);
+    TestToken(Instant now, Long expiresIn) {
+      super(now, expiresIn);
     }
 
-    TestToken(String expiresAt) {
-      super(expiresAt);
+    TestToken(String expiresAt, Long expiresIn) {
+      super(expiresAt, expiresIn);
     }
   }
 
@@ -88,13 +70,14 @@
     @Override
     protected List<String> getValues(TestToken token) {
       List<String> values = new ArrayList<>(2);
-      values.add(token.expiresAt);
+      values.add(LfsDateTime.format(token.issued));
+      values.add(String.valueOf(token.expiresIn));
       return values;
     }
 
     @Override
     protected Optional<TestToken> createToken(List<String> values) {
-      return Optional.of(new TestToken(values.get(0)));
+      return Optional.of(new TestToken(values.get(0), Long.valueOf(values.get(1))));
     }
   }
 
diff --git a/src/test/java/com/googlesource/gerrit/plugins/lfs/LfsDateTimeTest.java b/src/test/java/com/googlesource/gerrit/plugins/lfs/LfsDateTimeTest.java
index 99dcfe2..e2852c5 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/lfs/LfsDateTimeTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/lfs/LfsDateTimeTest.java
@@ -17,35 +17,16 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import java.time.Instant;
-import java.util.TimeZone;
 import org.joda.time.DateTime;
-import org.joda.time.DateTimeZone;
 import org.joda.time.format.ISODateTimeFormat;
 import org.junit.Test;
-import org.junit.experimental.theories.DataPoints;
-import org.junit.experimental.theories.Theories;
-import org.junit.experimental.theories.Theory;
-import org.junit.runner.RunWith;
 
-@RunWith(Theories.class)
 public class LfsDateTimeTest {
-  @DataPoints public static String[] timeZones = {"US/Eastern", "Asia/Tokyo", "UTC"};
-
   @Test
-  public void formatWithDefaultTimezone() throws Exception {
+  public void format() throws Exception {
     DateTime now = DateTime.now();
-    String jodaFormat = ISODateTimeFormat.dateTime().print(now);
-    LfsDateTime formatter = LfsDateTime.instance();
-    String javaFormat = formatter.format(Instant.ofEpochMilli(now.getMillis()));
-    assertThat(javaFormat).isEqualTo(jodaFormat);
-  }
-
-  @Theory
-  public void formatWithSpecifiedTimezone(String zone) throws Exception {
-    DateTime now = DateTime.now().withZone(DateTimeZone.forID(zone));
-    String jodaFormat = ISODateTimeFormat.dateTime().withZone(DateTimeZone.forID(zone)).print(now);
-    LfsDateTime formatter = LfsDateTime.instance(TimeZone.getTimeZone(zone).toZoneId());
-    String javaFormat = formatter.format(Instant.ofEpochMilli(now.getMillis()));
+    String jodaFormat = ISODateTimeFormat.dateTime().withZoneUTC().print(now);
+    String javaFormat = LfsDateTime.format(Instant.ofEpochMilli(now.getMillis()));
     assertThat(javaFormat).isEqualTo(jodaFormat);
   }
 }
diff --git a/src/test/java/com/googlesource/gerrit/plugins/lfs/fs/LfsFsRequestAuthorizerTest.java b/src/test/java/com/googlesource/gerrit/plugins/lfs/fs/LfsFsRequestAuthorizerTest.java
index 38c310f..8cd7225 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/lfs/fs/LfsFsRequestAuthorizerTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/lfs/fs/LfsFsRequestAuthorizerTest.java
@@ -20,6 +20,7 @@
 import com.googlesource.gerrit.plugins.lfs.AuthInfo;
 import com.googlesource.gerrit.plugins.lfs.LfsCipher;
 import com.googlesource.gerrit.plugins.lfs.fs.LfsFsRequestAuthorizer.Processor;
+import java.time.Instant;
 import org.eclipse.jgit.lfs.lib.LongObjectId;
 import org.junit.Test;
 
@@ -29,22 +30,22 @@
 
   @Test
   public void testVerifyAuthInfo() throws Exception {
-    AuthInfo info = auth.generateAuthInfo("o", zeroId(), 1);
-    assertThat(auth.verifyAuthInfo(info.authToken, "o", zeroId())).isTrue();
+    AuthInfo info = auth.generateAuthInfo("o", zeroId(), Instant.now(), 1L);
+    assertThat(auth.verifyAuthInfo(info.authToken(), "o", zeroId())).isTrue();
   }
 
   @Test
   public void testVerifyAgainstDifferentOperation() throws Exception {
-    AuthInfo info = auth.generateAuthInfo("o", zeroId(), 1);
-    assertThat(auth.verifyAuthInfo(info.authToken, "p", zeroId())).isFalse();
+    AuthInfo info = auth.generateAuthInfo("o", zeroId(), Instant.now(), 1L);
+    assertThat(auth.verifyAuthInfo(info.authToken(), "p", zeroId())).isFalse();
   }
 
   @Test
   public void testVerifyAgainstDifferentObjectId() throws Exception {
-    AuthInfo info = auth.generateAuthInfo("o", zeroId(), 1);
+    AuthInfo info = auth.generateAuthInfo("o", zeroId(), Instant.now(), 1L);
     assertThat(
             auth.verifyAuthInfo(
-                info.authToken,
+                info.authToken(),
                 "o",
                 LongObjectId.fromString(
                     "123456789012345678901234567890" + "123456789012345678901234567890" + "1234")))