Enable specific AccessPaths based on authentication

If the authentication method permits an AccessPath, add it to the
WebSession as a permitted path. Downstream from authentication a
CurrentUser can change its access path based on the entry point of
the request, allowing RefControl to make decisions around this as
expected, without running into the race condition of making user
before the real access method can be determined.

This allows authentication systems to decide on their own if the
REST_API was sufficiently protected from a potentially evil script.

Change-Id: Iefbe6745421f5f438bc06e2e4578a7207718b9a5
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/CacheBasedWebSession.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/CacheBasedWebSession.java
index 2dd14c5..2286615 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/CacheBasedWebSession.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/CacheBasedWebSession.java
@@ -35,6 +35,8 @@
 
 import org.eclipse.jgit.http.server.GitSmartHttpTools;
 
+import java.util.EnumSet;
+
 import javax.servlet.http.Cookie;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
@@ -66,7 +68,7 @@
   private final AuthConfig authConfig;
   private final Provider<AnonymousUser> anonymousProvider;
   private final IdentifiedUser.RequestFactory identified;
-  private AccessPath accessPath;
+  private final EnumSet<AccessPath> okPaths = EnumSet.of(AccessPath.UNKNOWN);
   private Cookie outCookie;
 
   private Key key;
@@ -85,34 +87,29 @@
     this.anonymousProvider = anonymousProvider;
     this.identified = identified;
 
-    String cookie = request.getHeader("Authorization");
-    if (cookie != null && cookie.startsWith("Bearer ")) {
-      cookie = cookie.substring("Bearer ".length());
-      accessPath = AccessPath.REST_API;
-    } else if (cookie != null && GitSmartHttpTools.isGitClient(request)) {
-      accessPath = AccessPath.GIT;
-    } else {
-      cookie = readCookie();
-      accessPath = AccessPath.WEB_BROWSER;
-    }
+    if (!GitSmartHttpTools.isGitClient(request)) {
+      String cookie = readCookie();
+      String token = request.getHeader("Authorization");
+      if (token != null && token.startsWith("Bearer ")) {
+        token = token.substring("Bearer ".length());
+        okPaths.add(AccessPath.REST_API);
+      } else {
+        token = cookie;
+      }
 
-    if (cookie != null) {
-      key = new Key(cookie);
-      val = manager.get(key);
-    } else {
-      key = null;
-      val = null;
-    }
+      if (token != null) {
+        key = new Key(token);
+        val = manager.get(key);
 
-    if (isSignedIn() && val.needsCookieRefresh()) {
-      // Cookie is more than half old. Send the cookie again to the
-      // client with an updated expiration date. We don't dare to
-      // change the key token here because there may be other RPCs
-      // queued up in the browser whose xsrfKey would not get updated
-      // with the new token, causing them to fail.
-      //
-      val = manager.createVal(key, val);
-      saveCookie();
+        if (isSignedIn() && val.needsCookieRefresh()) {
+          // Cookie is more than half old. Send the cookie again to the
+          // client with an updated expiration date.
+          val = manager.createVal(key, val);
+          if (cookie != null) {
+            saveCookie();
+          }
+        }
+      }
     }
   }
 
@@ -129,10 +126,12 @@
     return null;
   }
 
+  @Override
   public boolean isSignedIn() {
     return val != null;
   }
 
+  @Override
   public String getAuthorization() {
     return isSignedIn() ? "Bearer " + key.getToken() : null;
   }
@@ -142,17 +141,34 @@
     return keyIn.equals(getAuthorization());
   }
 
+  @Override
+  public boolean isAccessPathOk(AccessPath path) {
+    return okPaths.contains(path);
+  }
+
+  @Override
+  public void setAccessPathOk(AccessPath path, boolean ok) {
+    if (ok) {
+      okPaths.add(path);
+    } else {
+      okPaths.remove(path);
+    }
+  }
+
+  @Override
   public AccountExternalId.Key getLastLoginExternalId() {
     return val != null ? val.getExternalId() : null;
   }
 
+  @Override
   public CurrentUser getCurrentUser() {
     if (isSignedIn()) {
-      return identified.create(accessPath, val.getAccountId());
+      return identified.create(val.getAccountId());
     }
     return anonymousProvider.get();
   }
 
+  @Override
   public void login(final AuthResult res, final boolean rememberMe) {
     final Account.Id id = res.getAccountId();
     final AccountExternalId.Key identity = res.getExternalId();
@@ -167,11 +183,13 @@
   }
 
   /** Set the user account for this current request only. */
+  @Override
   public void setUserAccountId(Account.Id id) {
     key = new Key("id:" + id);
     val = new Val(id, 0, false, null, 0, null);
   }
 
+  @Override
   public void logout() {
     if (val != null) {
       manager.destroy(key);
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/ContainerAuthFilter.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/ContainerAuthFilter.java
index 29b5d95..433b4f5 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/ContainerAuthFilter.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/ContainerAuthFilter.java
@@ -17,6 +17,7 @@
 import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;
 import static javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED;
 
+import com.google.gerrit.server.AccessPath;
 import com.google.gerrit.server.account.AccountCache;
 import com.google.gerrit.server.account.AccountState;
 import com.google.gerrit.server.config.GerritServerConfig;
@@ -99,7 +100,10 @@
       rsp.sendError(SC_UNAUTHORIZED);
       return false;
     }
-    session.get().setUserAccountId(who.getAccount().getId());
+    WebSession ws = session.get();
+    ws.setUserAccountId(who.getAccount().getId());
+    ws.setAccessPathOk(AccessPath.GIT, true);
+    ws.setAccessPathOk(AccessPath.REST_API, true);
     return true;
   }
 }
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GitOverHttpServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GitOverHttpServlet.java
index cb5eb68..546ac71 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GitOverHttpServlet.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GitOverHttpServlet.java
@@ -18,7 +18,9 @@
 import com.google.gerrit.common.data.Capable;
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.AccessPath;
 import com.google.gerrit.server.AnonymousUser;
+import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.cache.CacheModule;
 import com.google.gerrit.server.git.AsyncReceiveCommits;
@@ -157,8 +159,12 @@
       } catch (NoSuchProjectException err) {
         throw new RepositoryNotFoundException(projectName);
       }
+
+      CurrentUser user = pc.getCurrentUser();
+      user.setAccessPath(AccessPath.GIT);
+
       if (!pc.isVisible()) {
-        if (pc.getCurrentUser() instanceof AnonymousUser) {
+        if (user instanceof AnonymousUser) {
           throw new ServiceNotAuthorizedException();
         } else {
           throw new ServiceNotEnabledException();
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/ProjectBasicAuthFilter.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/ProjectBasicAuthFilter.java
index 0d63682..3d9f4c8 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/ProjectBasicAuthFilter.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/ProjectBasicAuthFilter.java
@@ -18,6 +18,7 @@
 
 import com.google.common.base.Objects;
 import com.google.common.base.Strings;
+import com.google.gerrit.server.AccessPath;
 import com.google.gerrit.server.account.AccountCache;
 import com.google.gerrit.server.account.AccountException;
 import com.google.gerrit.server.account.AccountManager;
@@ -103,10 +104,9 @@
   private boolean verify(HttpServletRequest req, Response rsp)
       throws IOException {
     final String hdr = req.getHeader(AUTHORIZATION);
-    if (hdr == null) {
+    if (hdr == null || !hdr.startsWith(LIT_BASIC)) {
       // Allow an anonymous connection through, or it might be using a
       // session cookie instead of basic authentication.
-      //
       return true;
     }
 
@@ -142,7 +142,10 @@
 
     try {
       AuthResult whoAuthResult = accountManager.authenticate(whoAuth);
-      session.get().setUserAccountId(whoAuthResult.getAccountId());
+      WebSession ws = session.get();
+      ws.setUserAccountId(whoAuthResult.getAccountId());
+      ws.setAccessPathOk(AccessPath.GIT, true);
+      ws.setAccessPathOk(AccessPath.REST_API, true);
       return true;
     } catch (AccountException e) {
       log.warn("Authentication failed for " + username, e);
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/ProjectDigestFilter.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/ProjectDigestFilter.java
index 9e12e8c..c38425d 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/ProjectDigestFilter.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/ProjectDigestFilter.java
@@ -20,6 +20,7 @@
 import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
 import static javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED;
 
+import com.google.gerrit.server.AccessPath;
 import com.google.gerrit.server.account.AccountCache;
 import com.google.gerrit.server.account.AccountState;
 import com.google.gerrit.server.config.CanonicalWebUrl;
@@ -109,10 +110,9 @@
   private boolean verify(HttpServletRequest req, Response rsp)
       throws IOException {
     final String hdr = req.getHeader(AUTHORIZATION);
-    if (hdr == null) {
+    if (hdr == null || !hdr.startsWith("Digest ")) {
       // Allow an anonymous connection through, or it might be using a
       // session cookie instead of digest authentication.
-      //
       return true;
     }
 
@@ -164,7 +164,10 @@
     if (expect.equals(response)) {
       try {
         if (tokens.checkToken(nonce, "") != null) {
-          session.get().setUserAccountId(who.getAccount().getId());
+          WebSession ws = session.get();
+          ws.setUserAccountId(who.getAccount().getId());
+          ws.setAccessPathOk(AccessPath.GIT, true);
+          ws.setAccessPathOk(AccessPath.REST_API, true);
           return true;
 
         } else {
@@ -229,12 +232,6 @@
   }
 
   private Map<String, String> parseAuthorization(String auth) {
-    if (!auth.startsWith("Digest ")) {
-      // We only support Digest authentication scheme, deny the rest.
-      //
-      return Collections.emptyMap();
-    }
-
     Map<String, String> p = new HashMap<String, String>();
     int next = "Digest ".length();
     while (next < auth.length()) {
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebSession.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebSession.java
index 34a235a..598b860 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebSession.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebSession.java
@@ -16,26 +16,23 @@
 
 import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.reviewdb.client.AccountExternalId;
+import com.google.gerrit.server.AccessPath;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.account.AuthResult;
 
 public interface WebSession {
   public boolean isSignedIn();
-
   public String getAuthorization();
-
   public boolean isValidAuthorization(String keyIn);
-
   public AccountExternalId.Key getLastLoginExternalId();
-
   public CurrentUser getCurrentUser();
-
   public void login(AuthResult res, boolean rememberMe);
 
   /** Set the user account for this current request only. */
   public void setUserAccountId(Account.Id id);
+  public boolean isAccessPathOk(AccessPath path);
+  public void setAccessPathOk(AccessPath path, boolean ok);
 
   public void logout();
-
   public String getSessionId();
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/AnonymousUser.java b/gerrit-server/src/main/java/com/google/gerrit/server/AnonymousUser.java
index 5d36b33..f1fe72d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/AnonymousUser.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/AnonymousUser.java
@@ -30,7 +30,7 @@
 public class AnonymousUser extends CurrentUser {
   @Inject
   AnonymousUser(CapabilityControl.Factory capabilityControlFactory) {
-    super(capabilityControlFactory, AccessPath.UNKNOWN);
+    super(capabilityControlFactory);
   }
 
   @Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/CurrentUser.java b/gerrit-server/src/main/java/com/google/gerrit/server/CurrentUser.java
index f057c3a..86a6ef8 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/CurrentUser.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/CurrentUser.java
@@ -33,15 +33,12 @@
  */
 public abstract class CurrentUser {
   private final CapabilityControl.Factory capabilityControlFactory;
-  private final AccessPath accessPath;
+  private AccessPath accessPath = AccessPath.UNKNOWN;
 
   private CapabilityControl capabilities;
 
-  protected CurrentUser(
-      CapabilityControl.Factory capabilityControlFactory,
-      AccessPath accessPath) {
+  protected CurrentUser(CapabilityControl.Factory capabilityControlFactory) {
     this.capabilityControlFactory = capabilityControlFactory;
-    this.accessPath = accessPath;
   }
 
   /** How this user is accessing the Gerrit Code Review application. */
@@ -49,6 +46,10 @@
     return accessPath;
   }
 
+  public void setAccessPath(AccessPath path) {
+    accessPath = path;
+  }
+
   /**
    * Get the set of groups the user is currently a member of.
    * <p>
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/IdentifiedUser.java b/gerrit-server/src/main/java/com/google/gerrit/server/IdentifiedUser.java
index 89cbac1..3826293 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/IdentifiedUser.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/IdentifiedUser.java
@@ -38,6 +38,7 @@
 import com.google.inject.OutOfScopeException;
 import com.google.inject.Provider;
 import com.google.inject.Singleton;
+import com.google.inject.util.Providers;
 
 import org.eclipse.jgit.lib.PersonIdent;
 import org.eclipse.jgit.util.SystemReader;
@@ -90,20 +91,19 @@
     }
 
     public IdentifiedUser create(final Account.Id id) {
-      return create(AccessPath.UNKNOWN, null, id);
+      return create((SocketAddress) null, id);
     }
 
     public IdentifiedUser create(Provider<ReviewDb> db, Account.Id id) {
-      return new IdentifiedUser(capabilityControlFactory, AccessPath.UNKNOWN,
+      return new IdentifiedUser(capabilityControlFactory,
           authConfig, anonymousCowardName, canonicalUrl, realm, accountCache,
           groupBackend, null, db, id);
     }
 
-    public IdentifiedUser create(AccessPath accessPath,
-        Provider<SocketAddress> remotePeerProvider, Account.Id id) {
-      return new IdentifiedUser(capabilityControlFactory, accessPath,
+    public IdentifiedUser create(SocketAddress remotePeer, Account.Id id) {
+      return new IdentifiedUser(capabilityControlFactory,
           authConfig, anonymousCowardName, canonicalUrl, realm, accountCache,
-          groupBackend, remotePeerProvider, null, id);
+          groupBackend, Providers.of(remotePeer), null, id);
     }
   }
 
@@ -149,9 +149,8 @@
       this.dbProvider = dbProvider;
     }
 
-    public IdentifiedUser create(final AccessPath accessPath,
-        final Account.Id id) {
-      return new IdentifiedUser(capabilityControlFactory, accessPath,
+    public IdentifiedUser create(Account.Id id) {
+      return new IdentifiedUser(capabilityControlFactory,
           authConfig, anonymousCowardName, canonicalUrl, realm, accountCache,
           groupBackend, remotePeerProvider, dbProvider, id);
     }
@@ -187,7 +186,6 @@
 
   private IdentifiedUser(
       CapabilityControl.Factory capabilityControlFactory,
-      final AccessPath accessPath,
       final AuthConfig authConfig,
       final String anonymousCowardName,
       final Provider<String> canonicalUrl,
@@ -195,7 +193,7 @@
       final GroupBackend groupBackend,
       @Nullable final Provider<SocketAddress> remotePeerProvider,
       @Nullable final Provider<ReviewDb> dbProvider, final Account.Id id) {
-    super(capabilityControlFactory, accessPath);
+    super(capabilityControlFactory);
     this.canonicalUrl = canonicalUrl;
     this.accountCache = accountCache;
     this.groupBackend = groupBackend;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/InternalUser.java b/gerrit-server/src/main/java/com/google/gerrit/server/InternalUser.java
index eba59c8..f13eee9 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/InternalUser.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/InternalUser.java
@@ -39,7 +39,7 @@
 
   @Inject
   protected InternalUser(CapabilityControl.Factory capabilityControlFactory) {
-    super(capabilityControlFactory, AccessPath.UNKNOWN);
+    super(capabilityControlFactory);
   }
 
   @Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/PeerDaemonUser.java b/gerrit-server/src/main/java/com/google/gerrit/server/PeerDaemonUser.java
index 75ba0d7..4d26f02 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/PeerDaemonUser.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/PeerDaemonUser.java
@@ -40,7 +40,7 @@
   @Inject
   protected PeerDaemonUser(CapabilityControl.Factory capabilityControlFactory,
       @Assisted SocketAddress peer) {
-    super(capabilityControlFactory, AccessPath.SSH_COMMAND);
+    super(capabilityControlFactory);
     this.peer = peer;
   }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/SingleGroupUser.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/SingleGroupUser.java
index 270b2e7..4b71719 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/SingleGroupUser.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/SingleGroupUser.java
@@ -17,7 +17,6 @@
 import com.google.gerrit.reviewdb.client.AccountGroup;
 import com.google.gerrit.reviewdb.client.AccountProjectWatch;
 import com.google.gerrit.reviewdb.client.Change;
-import com.google.gerrit.server.AccessPath;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.account.CapabilityControl;
 import com.google.gerrit.server.account.GroupMembership;
@@ -37,7 +36,7 @@
 
   public SingleGroupUser(CapabilityControl.Factory capabilityControlFactory,
       Set<AccountGroup.UUID> groups) {
-    super(capabilityControlFactory, AccessPath.UNKNOWN);
+    super(capabilityControlFactory);
     this.groups = new ListGroupMembership(groups);
   }
 
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/project/RefControlTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/project/RefControlTest.java
index d4b07ae..0deeebd 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/project/RefControlTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/project/RefControlTest.java
@@ -33,7 +33,6 @@
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.rules.PrologEnvironment;
 import com.google.gerrit.rules.RulesCache;
-import com.google.gerrit.server.AccessPath;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.account.CapabilityControl;
 import com.google.gerrit.server.account.GroupMembership;
@@ -415,7 +414,7 @@
     private final GroupMembership groups;
 
     MockUser(String name, AccountGroup.UUID[] groupId) {
-      super(RefControlTest.this.capabilityControlFactory, AccessPath.UNKNOWN);
+      super(RefControlTest.this.capabilityControlFactory);
       username = name;
       ArrayList<AccountGroup.UUID> groupIds = Lists.newArrayList(groupId);
       groupIds.add(registered);
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/AbstractGitCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/AbstractGitCommand.java
index af5df25..90ffebd 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/AbstractGitCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/AbstractGitCommand.java
@@ -21,7 +21,6 @@
 import com.google.gerrit.server.project.ProjectControl;
 import com.google.gerrit.sshd.SshScope.Context;
 import com.google.inject.Inject;
-import com.google.inject.Provider;
 
 import org.apache.sshd.server.Environment;
 import org.eclipse.jgit.errors.RepositoryNotFoundException;
@@ -29,7 +28,6 @@
 import org.kohsuke.args4j.Argument;
 
 import java.io.IOException;
-import java.net.SocketAddress;
 
 public abstract class AbstractGitCommand extends BaseCommand {
   @Argument(index = 0, metaVar = "PROJECT.git", required = true, usage = "project name")
@@ -84,13 +82,10 @@
   }
 
   private SshSession newSession() {
-    return new SshSession(session, session.getRemoteAddress(), userFactory
-        .create(AccessPath.GIT, new Provider<SocketAddress>() {
-          @Override
-          public SocketAddress get() {
-            return session.getRemoteAddress();
-          }
-        }, user.getAccountId()));
+    SshSession n = new SshSession(session, session.getRemoteAddress(),
+        userFactory.create(session.getRemoteAddress(), user.getAccountId()));
+    n.setAccessPath(AccessPath.GIT);
+    return n;
   }
 
   private void service() throws IOException, Failure {
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/DatabasePubKeyAuth.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/DatabasePubKeyAuth.java
index a69a2f1..74ec562 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/DatabasePubKeyAuth.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/DatabasePubKeyAuth.java
@@ -15,7 +15,6 @@
 package com.google.gerrit.sshd;
 
 import com.google.gerrit.reviewdb.client.AccountSshKey;
-import com.google.gerrit.server.AccessPath;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.PeerDaemonUser;
@@ -23,7 +22,6 @@
 import com.google.gerrit.server.config.SitePaths;
 import com.google.gerrit.sshd.SshScope.Context;
 import com.google.inject.Inject;
-import com.google.inject.Provider;
 import com.google.inject.Singleton;
 
 import org.apache.commons.codec.binary.Base64;
@@ -43,7 +41,6 @@
 import java.io.FileNotFoundException;
 import java.io.FileReader;
 import java.io.IOException;
-import java.net.SocketAddress;
 import java.security.KeyPair;
 import java.security.PublicKey;
 import java.util.Collection;
@@ -201,13 +198,7 @@
 
   private IdentifiedUser createUser(final SshSession sd,
       final SshKeyCacheEntry key) {
-    return userFactory.create(AccessPath.SSH_COMMAND,
-        new Provider<SocketAddress>() {
-          @Override
-          public SocketAddress get() {
-            return sd.getRemoteAddress();
-          }
-        }, key.getAccount());
+    return userFactory.create(sd.getRemoteAddress(), key.getAccount());
   }
 
   private SshKeyCacheEntry find(final Iterable<SshKeyCacheEntry> keyList,
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshScope.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshScope.java
index d6f66ca..180b4d6 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshScope.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshScope.java
@@ -73,8 +73,7 @@
     public CurrentUser getCurrentUser() {
       final CurrentUser user = session.getCurrentUser();
       if (user instanceof IdentifiedUser) {
-        return userFactory.create(user.getAccessPath(), //
-            ((IdentifiedUser) user).getAccountId());
+        return userFactory.create(((IdentifiedUser) user).getAccountId());
       }
       return user;
     }
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshSession.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshSession.java
index 3c4d4f8..2cc16b5 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshSession.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshSession.java
@@ -14,6 +14,7 @@
 
 package com.google.gerrit.sshd;
 
+import com.google.gerrit.server.AccessPath;
 import com.google.gerrit.server.CurrentUser;
 
 import org.apache.sshd.common.Session.AttributeKey;
@@ -43,6 +44,7 @@
   }
 
   SshSession(SshSession parent, SocketAddress peer, CurrentUser user) {
+    user.setAccessPath(AccessPath.SSH_COMMAND);
     this.sessionId = parent.sessionId;
     this.remoteAddress = peer;
     if (parent.remoteAddress == peer) {
@@ -83,6 +85,10 @@
     authError = error;
   }
 
+  void setAccessPath(AccessPath path) {
+    identity.setAccessPath(path);
+  }
+
   /** @return {@code true} if the authentication did not succeed. */
   boolean isAuthenticationError() {
     return authError != null;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SuExec.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SuExec.java
index 33459c2..ccf23e1 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SuExec.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SuExec.java
@@ -16,7 +16,6 @@
 
 import com.google.common.util.concurrent.Atomics;
 import com.google.gerrit.reviewdb.client.Account;
-import com.google.gerrit.server.AccessPath;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.PeerDaemonUser;
@@ -116,14 +115,8 @@
     } else {
       peer = peerAddress;
     }
-
-    return new SshSession(session.get(), peer, userFactory.create(
-        AccessPath.SSH_COMMAND, new Provider<SocketAddress>() {
-          @Override
-          public SocketAddress get() {
-            return peer;
-          }
-        }, accountId));
+    return new SshSession(session.get(), peer,
+        userFactory.create(peer, accountId));
   }
 
   private static String join(List<String> args) {