LCOV - code coverage report
Current view: top level - httpd - CacheBasedWebSession.java (source / functions) Hit Total Coverage
Test: _coverage_report.dat Lines: 85 111 76.6 %
Date: 2022-11-19 15:00:39 Functions: 17 20 85.0 %

          Line data    Source code
       1             : // Copyright (C) 2009 The Android Open Source Project
       2             : //
       3             : // Licensed under the Apache License, Version 2.0 (the "License");
       4             : // you may not use this file except in compliance with the License.
       5             : // You may obtain a copy of the License at
       6             : //
       7             : // http://www.apache.org/licenses/LICENSE-2.0
       8             : //
       9             : // Unless required by applicable law or agreed to in writing, software
      10             : // distributed under the License is distributed on an "AS IS" BASIS,
      11             : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             : // See the License for the specific language governing permissions and
      13             : // limitations under the License.
      14             : 
      15             : package com.google.gerrit.httpd;
      16             : 
      17             : import static java.util.concurrent.TimeUnit.HOURS;
      18             : 
      19             : import com.google.common.annotations.VisibleForTesting;
      20             : import com.google.common.base.Strings;
      21             : import com.google.gerrit.common.Nullable;
      22             : import com.google.gerrit.common.UsedAt;
      23             : import com.google.gerrit.entities.Account;
      24             : import com.google.gerrit.extensions.restapi.BadRequestException;
      25             : import com.google.gerrit.httpd.restapi.ParameterParser;
      26             : import com.google.gerrit.server.AccessPath;
      27             : import com.google.gerrit.server.AnonymousUser;
      28             : import com.google.gerrit.server.CurrentUser;
      29             : import com.google.gerrit.server.IdentifiedUser;
      30             : import com.google.gerrit.server.PropertyMap;
      31             : import com.google.gerrit.server.account.AccountCache;
      32             : import com.google.gerrit.server.account.AuthResult;
      33             : import com.google.gerrit.server.account.externalids.ExternalId;
      34             : import com.google.gerrit.server.config.AuthConfig;
      35             : import com.google.inject.Provider;
      36             : import java.util.EnumSet;
      37             : import javax.servlet.http.Cookie;
      38             : import javax.servlet.http.HttpServletRequest;
      39             : import javax.servlet.http.HttpServletResponse;
      40             : import org.eclipse.jgit.http.server.GitSmartHttpTools;
      41             : 
      42             : public abstract class CacheBasedWebSession extends WebSession {
      43             :   @VisibleForTesting public static final String ACCOUNT_COOKIE = "GerritAccount";
      44             : 
      45             :   @UsedAt(UsedAt.Project.PLUGIN_WEBSESSION_FLATFILE)
      46         100 :   public static final long MAX_AGE_MINUTES = HOURS.toMinutes(12);
      47             : 
      48             :   private final HttpServletRequest request;
      49             :   private final HttpServletResponse response;
      50             :   private final WebSessionManager manager;
      51             :   private final AuthConfig authConfig;
      52             :   private final Provider<AnonymousUser> anonymousProvider;
      53             :   private final IdentifiedUser.RequestFactory identified;
      54          39 :   private final EnumSet<AccessPath> okPaths = EnumSet.of(AccessPath.UNKNOWN);
      55             :   private final AccountCache byIdCache;
      56             :   private Cookie outCookie;
      57             : 
      58             :   private WebSessionManager.Key key;
      59             :   private WebSessionManager.Val val;
      60             :   private CurrentUser user;
      61             : 
      62             :   protected CacheBasedWebSession(
      63             :       HttpServletRequest request,
      64             :       HttpServletResponse response,
      65             :       WebSessionManager manager,
      66             :       AuthConfig authConfig,
      67             :       Provider<AnonymousUser> anonymousProvider,
      68             :       IdentifiedUser.RequestFactory identified,
      69          39 :       AccountCache byIdCache) {
      70          39 :     this.request = request;
      71          39 :     this.response = response;
      72          39 :     this.manager = manager;
      73          39 :     this.authConfig = authConfig;
      74          39 :     this.anonymousProvider = anonymousProvider;
      75          39 :     this.identified = identified;
      76          39 :     this.byIdCache = byIdCache;
      77             : 
      78          39 :     String cookie = readCookie(request);
      79          39 :     if (cookie != null) {
      80           2 :       authFromCookie(cookie);
      81          39 :     } else if (request.getRequestURI() == null || !GitSmartHttpTools.isGitClient(request)) {
      82             :       String token;
      83             :       try {
      84          31 :         token = ParameterParser.getQueryParams(request).accessToken();
      85           0 :       } catch (BadRequestException e) {
      86           0 :         token = null;
      87          31 :       }
      88          31 :       if (token != null) {
      89           0 :         authFromQueryParameter(token);
      90             :       }
      91             :     }
      92          39 :     if (val != null && !checkAccountStatus(val.getAccountId())) {
      93           1 :       val = null;
      94           1 :       okPaths.clear();
      95             :     }
      96          39 :     if (val != null && val.needsCookieRefresh()) {
      97             :       // Session is more than half old; update cache entry with new expiration date.
      98           0 :       val = manager.createVal(key, val);
      99             :     }
     100          39 :   }
     101             : 
     102             :   private void authFromCookie(String cookie) {
     103           2 :     key = new WebSessionManager.Key(cookie);
     104           2 :     val = manager.get(key);
     105           2 :     String token = request.getHeader(XsrfConstants.XSRF_HEADER_NAME);
     106           2 :     if (val != null && token != null && token.equals(val.getAuth())) {
     107           0 :       okPaths.add(AccessPath.REST_API);
     108             :     }
     109           2 :   }
     110             : 
     111             :   private void authFromQueryParameter(String accessToken) {
     112           0 :     key = new WebSessionManager.Key(accessToken);
     113           0 :     val = manager.get(key);
     114           0 :     if (val != null) {
     115           0 :       okPaths.add(AccessPath.REST_API);
     116             :     }
     117           0 :   }
     118             : 
     119             :   @Nullable
     120             :   private static String readCookie(HttpServletRequest request) {
     121          39 :     Cookie[] all = request.getCookies();
     122          39 :     if (all != null) {
     123           2 :       for (Cookie c : all) {
     124           2 :         if (ACCOUNT_COOKIE.equals(c.getName())) {
     125           2 :           return Strings.emptyToNull(c.getValue());
     126             :         }
     127             :       }
     128             :     }
     129          39 :     return null;
     130             :   }
     131             : 
     132             :   @Override
     133             :   public boolean isSignedIn() {
     134          39 :     return val != null;
     135             :   }
     136             : 
     137             :   @Override
     138             :   @Nullable
     139             :   public String getXGerritAuth() {
     140           0 :     return isSignedIn() ? val.getAuth() : null;
     141             :   }
     142             : 
     143             :   @Override
     144             :   public boolean isValidXGerritAuth(String keyIn) {
     145           0 :     return keyIn.equals(getXGerritAuth());
     146             :   }
     147             : 
     148             :   @Override
     149             :   public boolean isAccessPathOk(AccessPath path) {
     150          19 :     return okPaths.contains(path);
     151             :   }
     152             : 
     153             :   @Override
     154             :   public void setAccessPathOk(AccessPath path, boolean ok) {
     155          38 :     if (ok) {
     156          38 :       okPaths.add(path);
     157             :     } else {
     158           0 :       okPaths.remove(path);
     159             :     }
     160          38 :   }
     161             : 
     162             :   @Override
     163             :   public CurrentUser getUser() {
     164          38 :     if (user == null) {
     165          34 :       if (isSignedIn()) {
     166             : 
     167           1 :         user = identified.create(val.getAccountId(), getUserProperties(val));
     168             :       } else {
     169          34 :         user = anonymousProvider.get();
     170             :       }
     171             :     }
     172          38 :     return user;
     173             :   }
     174             : 
     175             :   private static PropertyMap getUserProperties(@Nullable WebSessionManager.Val val) {
     176           2 :     if (val == null || val.getExternalId() == null) {
     177           2 :       return PropertyMap.EMPTY;
     178             :     }
     179           0 :     return PropertyMap.builder()
     180           0 :         .put(CurrentUser.LAST_LOGIN_EXTERNAL_ID_PROPERTY_KEY, val.getExternalId())
     181           0 :         .build();
     182             :   }
     183             : 
     184             :   @Override
     185             :   public void login(AuthResult res, boolean rememberMe) {
     186           2 :     Account.Id id = res.getAccountId();
     187           2 :     ExternalId.Key identity = res.getExternalId();
     188             : 
     189           2 :     if (val != null) {
     190           1 :       manager.destroy(key);
     191             :     }
     192             : 
     193           2 :     if (!checkAccountStatus(id)) {
     194           1 :       val = null;
     195           1 :       return;
     196             :     }
     197             : 
     198           2 :     key = manager.createKey(id);
     199           2 :     val = manager.createVal(key, id, rememberMe, identity, null, null);
     200           2 :     saveCookie();
     201           2 :     user = identified.create(val.getAccountId(), getUserProperties(val));
     202           2 :   }
     203             : 
     204             :   /** Set the user account for this current request only. */
     205             :   @Override
     206             :   public void setUserAccountId(Account.Id id) {
     207          38 :     key = new WebSessionManager.Key("id:" + id);
     208          38 :     val = new WebSessionManager.Val(id, 0, false, null, 0, null, null);
     209          38 :     user = identified.runAs(id, user, PropertyMap.EMPTY);
     210          38 :   }
     211             : 
     212             :   @Override
     213             :   public void logout() {
     214           1 :     if (val != null) {
     215           0 :       manager.destroy(key);
     216           0 :       key = null;
     217           0 :       val = null;
     218           0 :       saveCookie();
     219           0 :       user = anonymousProvider.get();
     220             :     }
     221           1 :   }
     222             : 
     223             :   @Nullable
     224             :   @Override
     225             :   public String getSessionId() {
     226          37 :     return val != null ? val.getSessionId() : null;
     227             :   }
     228             : 
     229             :   private boolean checkAccountStatus(Account.Id id) {
     230           2 :     return byIdCache.get(id).filter(as -> as.account().isActive()).isPresent();
     231             :   }
     232             : 
     233             :   private void saveCookie() {
     234           2 :     if (response == null) {
     235           0 :       return;
     236             :     }
     237             : 
     238             :     final String token;
     239             :     final int ageSeconds;
     240             : 
     241           2 :     if (key == null) {
     242           0 :       token = "";
     243           0 :       ageSeconds = 0 /* erase at client */;
     244             :     } else {
     245           2 :       token = key.getToken();
     246           2 :       ageSeconds = manager.getCookieAge(val);
     247             :     }
     248             : 
     249           2 :     String path = authConfig.getCookiePath();
     250           2 :     if (Strings.isNullOrEmpty(path)) {
     251           2 :       path = request.getContextPath();
     252           2 :       if (Strings.isNullOrEmpty(path)) {
     253           2 :         path = "/";
     254             :       }
     255             :     }
     256             : 
     257           2 :     if (outCookie != null) {
     258           0 :       throw new IllegalStateException("Cookie " + ACCOUNT_COOKIE + " was set");
     259             :     }
     260             : 
     261           2 :     outCookie = new Cookie(ACCOUNT_COOKIE, token);
     262             : 
     263           2 :     String domain = authConfig.getCookieDomain();
     264           2 :     if (!Strings.isNullOrEmpty(domain)) {
     265           0 :       outCookie.setDomain(domain);
     266             :     }
     267             : 
     268           2 :     outCookie.setSecure(isSecure(request));
     269           2 :     outCookie.setPath(path);
     270           2 :     outCookie.setMaxAge(ageSeconds);
     271           2 :     outCookie.setSecure(authConfig.getCookieSecure());
     272           2 :     response.addCookie(outCookie);
     273           2 :   }
     274             : 
     275             :   private static boolean isSecure(HttpServletRequest req) {
     276           2 :     return req.isSecure() || "https".equals(req.getScheme());
     277             :   }
     278             : }

Generated by: LCOV version 1.16+git.20220603.dfeb750