LCOV - code coverage report
Current view: top level - pgm/init - InitAdminUser.java (source / functions) Hit Total Coverage
Test: _coverage_report.dat Lines: 22 82 26.8 %
Date: 2022-11-19 15:00:39 Functions: 6 11 54.5 %

          Line data    Source code
       1             : // Copyright (C) 2014 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.pgm.init;
      16             : 
      17             : import static java.nio.charset.StandardCharsets.UTF_8;
      18             : 
      19             : import com.google.common.base.Strings;
      20             : import com.google.gerrit.common.Nullable;
      21             : import com.google.gerrit.entities.Account;
      22             : import com.google.gerrit.entities.GroupReference;
      23             : import com.google.gerrit.entities.InternalGroup;
      24             : import com.google.gerrit.exceptions.NoSuchGroupException;
      25             : import com.google.gerrit.extensions.client.AuthType;
      26             : import com.google.gerrit.pgm.init.api.ConsoleUI;
      27             : import com.google.gerrit.pgm.init.api.InitFlags;
      28             : import com.google.gerrit.pgm.init.api.InitStep;
      29             : import com.google.gerrit.pgm.init.api.SequencesOnInit;
      30             : import com.google.gerrit.server.account.AccountSshKey;
      31             : import com.google.gerrit.server.account.AccountState;
      32             : import com.google.gerrit.server.account.externalids.ExternalId;
      33             : import com.google.gerrit.server.account.externalids.ExternalIdFactory;
      34             : import com.google.gerrit.server.index.account.AccountIndex;
      35             : import com.google.gerrit.server.index.account.AccountIndexCollection;
      36             : import com.google.gerrit.server.index.group.GroupIndex;
      37             : import com.google.gerrit.server.index.group.GroupIndexCollection;
      38             : import com.google.gerrit.server.util.time.TimeUtil;
      39             : import com.google.inject.Inject;
      40             : import java.io.IOException;
      41             : import java.nio.file.Files;
      42             : import java.nio.file.Path;
      43             : import java.nio.file.Paths;
      44             : import java.util.ArrayList;
      45             : import java.util.List;
      46             : import java.util.Optional;
      47             : import org.apache.commons.validator.routines.EmailValidator;
      48             : 
      49             : public class InitAdminUser implements InitStep {
      50             :   private final InitFlags flags;
      51             :   private final ConsoleUI ui;
      52             :   private final AccountsOnInit accounts;
      53             :   private final VersionedAuthorizedKeysOnInit.Factory authorizedKeysFactory;
      54             :   private final ExternalIdsOnInit externalIds;
      55             :   private final SequencesOnInit sequencesOnInit;
      56             :   private final GroupsOnInit groupsOnInit;
      57             :   private final ExternalIdFactory externalIdFactory;
      58             :   private AccountIndexCollection accountIndexCollection;
      59             :   private GroupIndexCollection groupIndexCollection;
      60             : 
      61             :   @Inject
      62             :   InitAdminUser(
      63             :       InitFlags flags,
      64             :       ConsoleUI ui,
      65             :       AccountsOnInit accounts,
      66             :       VersionedAuthorizedKeysOnInit.Factory authorizedKeysFactory,
      67             :       ExternalIdsOnInit externalIds,
      68             :       SequencesOnInit sequencesOnInit,
      69             :       GroupsOnInit groupsOnInit,
      70          15 :       ExternalIdFactory externalIdFactory) {
      71          15 :     this.flags = flags;
      72          15 :     this.ui = ui;
      73          15 :     this.accounts = accounts;
      74          15 :     this.authorizedKeysFactory = authorizedKeysFactory;
      75          15 :     this.externalIds = externalIds;
      76          15 :     this.sequencesOnInit = sequencesOnInit;
      77          15 :     this.groupsOnInit = groupsOnInit;
      78          15 :     this.externalIdFactory = externalIdFactory;
      79          15 :   }
      80             : 
      81             :   @Override
      82          15 :   public void run() {}
      83             : 
      84             :   @Inject
      85             :   void set(AccountIndexCollection accountIndexCollection) {
      86          15 :     this.accountIndexCollection = accountIndexCollection;
      87          15 :   }
      88             : 
      89             :   @Inject
      90             :   void set(GroupIndexCollection groupIndexCollection) {
      91          15 :     this.groupIndexCollection = groupIndexCollection;
      92          15 :   }
      93             : 
      94             :   @Override
      95             :   public void postRun() throws Exception {
      96          15 :     if (!accounts.hasAnyAccount()) {
      97          15 :       welcome();
      98             :     }
      99          15 :     AuthType authType = flags.cfg.getEnum(AuthType.values(), "auth", null, "type", null);
     100          15 :     if (authType != AuthType.DEVELOPMENT_BECOME_ANY_ACCOUNT) {
     101          15 :       return;
     102             :     }
     103             : 
     104           0 :     if (!accounts.hasAnyAccount()) {
     105           0 :       ui.header("Gerrit Administrator");
     106           0 :       if (ui.yesno(true, "Create administrator user")) {
     107           0 :         Account.Id id = Account.id(sequencesOnInit.nextAccountId());
     108           0 :         String username = ui.readString("admin", "username");
     109           0 :         String name = ui.readString("Administrator", "name");
     110           0 :         String httpPassword = ui.readString("secret", "HTTP password");
     111           0 :         AccountSshKey sshKey = readSshKey(id);
     112           0 :         String email = readEmail(sshKey);
     113             : 
     114           0 :         List<ExternalId> extIds = new ArrayList<>(2);
     115           0 :         extIds.add(externalIdFactory.createUsername(username, id, httpPassword));
     116             : 
     117           0 :         if (email != null) {
     118           0 :           extIds.add(externalIdFactory.createEmail(id, email));
     119             :         }
     120           0 :         externalIds.insert("Add external IDs for initial admin user", extIds);
     121             : 
     122           0 :         Account persistedAccount =
     123           0 :             accounts.insert(
     124           0 :                 Account.builder(id, TimeUtil.now()).setFullName(name).setPreferredEmail(email));
     125             :         // Only two groups should exist at this point in time and hence iterating over all of them
     126             :         // is cheap.
     127           0 :         Optional<GroupReference> adminGroupReference =
     128             :             groupsOnInit
     129           0 :                 .getAllGroupReferences()
     130           0 :                 .filter(group -> group.getName().equals("Administrators"))
     131           0 :                 .findAny();
     132           0 :         if (!adminGroupReference.isPresent()) {
     133           0 :           throw new NoSuchGroupException("Administrators");
     134             :         }
     135           0 :         GroupReference adminGroup = adminGroupReference.get();
     136           0 :         groupsOnInit.addGroupMember(adminGroup.getUUID(), persistedAccount);
     137             : 
     138           0 :         if (sshKey != null) {
     139           0 :           VersionedAuthorizedKeysOnInit authorizedKeys = authorizedKeysFactory.create(id).load();
     140           0 :           authorizedKeys.addKey(sshKey.sshPublicKey());
     141           0 :           authorizedKeys.save("Add SSH key for initial admin user\n");
     142             :         }
     143             : 
     144           0 :         AccountState as = AccountState.forAccount(persistedAccount, extIds);
     145           0 :         for (AccountIndex accountIndex : accountIndexCollection.getWriteIndexes()) {
     146           0 :           accountIndex.replace(as);
     147           0 :         }
     148             : 
     149           0 :         InternalGroup adminInternalGroup = groupsOnInit.getExistingGroup(adminGroup);
     150           0 :         for (GroupIndex groupIndex : groupIndexCollection.getWriteIndexes()) {
     151           0 :           groupIndex.replace(adminInternalGroup);
     152           0 :         }
     153             :       }
     154             :     }
     155           0 :   }
     156             : 
     157             :   private void welcome() {
     158          15 :     ui.message(
     159             :         "============================================================================\n"
     160             :             + "Welcome to the Gerrit community\n\n"
     161             :             + "Find more information on the homepage: https://www.gerritcodereview.com\n"
     162             :             + "Discuss Gerrit on the mailing list: https://groups.google.com/g/repo-discuss\n"
     163             :             + "============================================================================\n");
     164          15 :   }
     165             : 
     166             :   private String readEmail(AccountSshKey sshKey) {
     167           0 :     String defaultEmail = "admin@example.com";
     168           0 :     if (sshKey != null && sshKey.comment() != null) {
     169           0 :       String c = sshKey.comment().trim();
     170           0 :       if (EmailValidator.getInstance().isValid(c)) {
     171           0 :         defaultEmail = c;
     172             :       }
     173             :     }
     174           0 :     return readEmail(defaultEmail);
     175             :   }
     176             : 
     177             :   private String readEmail(String defaultEmail) {
     178           0 :     String email = ui.readString(defaultEmail, "email");
     179           0 :     if (email != null && !EmailValidator.getInstance().isValid(email)) {
     180           0 :       ui.message("error: invalid email address\n");
     181           0 :       return readEmail(defaultEmail);
     182             :     }
     183           0 :     return email;
     184             :   }
     185             : 
     186             :   @Nullable
     187             :   private AccountSshKey readSshKey(Account.Id id) throws IOException {
     188           0 :     String defaultPublicSshKeyFile = "";
     189           0 :     Path defaultPublicSshKeyPath = Paths.get(System.getProperty("user.home"), ".ssh", "id_rsa.pub");
     190           0 :     if (Files.exists(defaultPublicSshKeyPath)) {
     191           0 :       defaultPublicSshKeyFile = defaultPublicSshKeyPath.toString();
     192             :     }
     193           0 :     String publicSshKeyFile = ui.readString(defaultPublicSshKeyFile, "public SSH key file");
     194           0 :     return !Strings.isNullOrEmpty(publicSshKeyFile) ? createSshKey(id, publicSshKeyFile) : null;
     195             :   }
     196             : 
     197             :   private AccountSshKey createSshKey(Account.Id id, String keyFile) throws IOException {
     198           0 :     Path p = Paths.get(keyFile);
     199           0 :     if (!Files.exists(p)) {
     200           0 :       throw new IOException(String.format("Cannot add public SSH key: %s is not a file", keyFile));
     201             :     }
     202           0 :     String content = new String(Files.readAllBytes(p), UTF_8);
     203           0 :     return AccountSshKey.create(id, 1, content);
     204             :   }
     205             : }

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