LCOV - code coverage report
Current view: top level - server/group - GroupResolver.java (source / functions) Hit Total Coverage
Test: _coverage_report.dat Lines: 39 42 92.9 %
Date: 2022-11-19 15:00:39 Functions: 5 5 100.0 %

          Line data    Source code
       1             : // Copyright (C) 2018 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.server.group;
      16             : 
      17             : import com.google.common.flogger.FluentLogger;
      18             : import com.google.gerrit.common.Nullable;
      19             : import com.google.gerrit.entities.AccountGroup;
      20             : import com.google.gerrit.entities.GroupDescription;
      21             : import com.google.gerrit.entities.GroupReference;
      22             : import com.google.gerrit.entities.InternalGroup;
      23             : import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
      24             : import com.google.gerrit.server.account.GroupBackend;
      25             : import com.google.gerrit.server.account.GroupBackends;
      26             : import com.google.gerrit.server.account.GroupCache;
      27             : import com.google.gerrit.server.account.GroupControl;
      28             : import com.google.inject.Inject;
      29             : import com.google.inject.Singleton;
      30             : import java.util.Optional;
      31             : 
      32             : @Singleton
      33             : public class GroupResolver {
      34         150 :   private static final FluentLogger logger = FluentLogger.forEnclosingClass();
      35             : 
      36             :   private final GroupBackend groupBackend;
      37             :   private final GroupCache groupCache;
      38             :   private final GroupControl.Factory groupControlFactory;
      39             : 
      40             :   @Inject
      41             :   GroupResolver(
      42         150 :       GroupBackend groupBackend, GroupCache groupCache, GroupControl.Factory groupControlFactory) {
      43         150 :     this.groupBackend = groupBackend;
      44         150 :     this.groupCache = groupCache;
      45         150 :     this.groupControlFactory = groupControlFactory;
      46         150 :   }
      47             : 
      48             :   /**
      49             :    * Parses a group ID from a request body and returns the group.
      50             :    *
      51             :    * @param id ID of the group, can be a group UUID, a group name or a legacy group ID
      52             :    * @return the group
      53             :    * @throws UnprocessableEntityException thrown if the group ID cannot be resolved or if the group
      54             :    *     is not visible to the calling user
      55             :    */
      56             :   public GroupDescription.Basic parse(String id) throws UnprocessableEntityException {
      57          33 :     GroupDescription.Basic group = parseId(id);
      58          33 :     if (group == null || !groupControlFactory.controlFor(group).isVisible()) {
      59          29 :       throw new UnprocessableEntityException(String.format("Group Not Found: %s", id));
      60             :     }
      61          17 :     return group;
      62             :   }
      63             : 
      64             :   /**
      65             :    * Parses a group ID from a request body and returns the group if it is a Gerrit internal group.
      66             :    *
      67             :    * @param id ID of the group, can be a group UUID, a group name or a legacy group ID
      68             :    * @return the group
      69             :    * @throws UnprocessableEntityException thrown if the group ID cannot be resolved, if the group is
      70             :    *     not visible to the calling user or if it's an external group
      71             :    */
      72             :   public GroupDescription.Internal parseInternal(String id) throws UnprocessableEntityException {
      73          14 :     GroupDescription.Basic group = parse(id);
      74          14 :     if (group instanceof GroupDescription.Internal) {
      75          14 :       return (GroupDescription.Internal) group;
      76             :     }
      77             : 
      78           0 :     throw new UnprocessableEntityException(String.format("External Group Not Allowed: %s", id));
      79             :   }
      80             : 
      81             :   /**
      82             :    * Parses a group ID and returns the group without making any permission check whether the current
      83             :    * user can see the group.
      84             :    *
      85             :    * @param id ID of the group, can be a group UUID, a group name or a legacy group ID
      86             :    * @return the group, null if no group is found for the given group ID
      87             :    */
      88             :   @Nullable
      89             :   public GroupDescription.Basic parseId(String id) {
      90          54 :     logger.atFine().log("Parsing group %s", id);
      91             : 
      92          54 :     AccountGroup.UUID uuid = AccountGroup.uuid(id);
      93          54 :     if (groupBackend.handles(uuid)) {
      94          40 :       logger.atFine().log("Group UUID %s is handled by a group backend", uuid.get());
      95          40 :       GroupDescription.Basic d = groupBackend.get(uuid);
      96          40 :       if (d != null) {
      97          40 :         logger.atFine().log("Found group %s", d.getName());
      98          40 :         return d;
      99             :       }
     100             :     }
     101             : 
     102             :     // Might be a numeric AccountGroup.Id. -> Internal group.
     103          41 :     if (id.matches("^[1-9][0-9]*$")) {
     104           7 :       logger.atFine().log("Group ID %s is a numeric ID", id);
     105             :       try {
     106           7 :         AccountGroup.Id groupId = AccountGroup.Id.parse(id);
     107           7 :         Optional<InternalGroup> group = groupCache.get(groupId);
     108           7 :         if (group.isPresent()) {
     109           2 :           logger.atFine().log(
     110             :               "Found internal group %s (UUID = %s)",
     111           2 :               group.get().getName(), group.get().getGroupUUID().get());
     112           2 :           return new InternalGroupDescription(group.get());
     113             :         }
     114           0 :       } catch (IllegalArgumentException e) {
     115             :         // Ignored
     116           0 :         logger.atFine().withCause(e).log("Parsing numeric group ID %s failed", id);
     117           5 :       }
     118             :     }
     119             : 
     120             :     // Might be a group name, be nice and accept unique names.
     121          41 :     logger.atFine().log("Try finding a group with name %s", id);
     122          41 :     GroupReference ref = GroupBackends.findExactSuggestion(groupBackend, id);
     123          41 :     if (ref != null) {
     124          17 :       GroupDescription.Basic d = groupBackend.get(ref.getUUID());
     125          17 :       if (d != null) {
     126          17 :         logger.atFine().log("Found group %s", d.getName());
     127          17 :         return d;
     128             :       }
     129             :     }
     130             : 
     131          38 :     logger.atFine().log("Group %s not found", id);
     132          38 :     return null;
     133             :   }
     134             : }

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