Line data Source code
1 : // Copyright (C) 2017 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.account; 16 : 17 : import com.google.common.flogger.FluentLogger; 18 : import com.google.gerrit.extensions.events.LifecycleListener; 19 : import com.google.gerrit.extensions.restapi.ResourceConflictException; 20 : import com.google.gerrit.lifecycle.LifecycleModule; 21 : import com.google.gerrit.server.config.GerritServerConfig; 22 : import com.google.gerrit.server.config.ScheduleConfig; 23 : import com.google.gerrit.server.config.ScheduleConfig.Schedule; 24 : import com.google.gerrit.server.git.WorkQueue; 25 : import com.google.gerrit.server.query.account.AccountPredicates; 26 : import com.google.gerrit.server.query.account.InternalAccountQuery; 27 : import com.google.inject.Inject; 28 : import com.google.inject.Provider; 29 : import java.util.Optional; 30 : import org.eclipse.jgit.lib.Config; 31 : 32 : /** Runnable to enable scheduling account deactivations to run periodically */ 33 : public class AccountDeactivator implements Runnable { 34 138 : private static final FluentLogger logger = FluentLogger.forEnclosingClass(); 35 : 36 138 : public static class AccountDeactivatorModule extends LifecycleModule { 37 : @Override 38 : protected void configure() { 39 138 : listener().to(Lifecycle.class); 40 138 : } 41 : } 42 : 43 : static class Lifecycle implements LifecycleListener { 44 : private final WorkQueue queue; 45 : private final AccountDeactivator deactivator; 46 : private final boolean supportAutomaticAccountActivityUpdate; 47 : private final Optional<Schedule> schedule; 48 : 49 : @Inject 50 138 : Lifecycle(WorkQueue queue, AccountDeactivator deactivator, @GerritServerConfig Config cfg) { 51 138 : this.queue = queue; 52 138 : this.deactivator = deactivator; 53 138 : schedule = ScheduleConfig.createSchedule(cfg, "accountDeactivation"); 54 138 : supportAutomaticAccountActivityUpdate = 55 138 : cfg.getBoolean("auth", "autoUpdateAccountActiveStatus", false); 56 138 : } 57 : 58 : @Override 59 : public void start() { 60 138 : if (schedule.isPresent()) { 61 0 : if (supportAutomaticAccountActivityUpdate) { 62 0 : queue.scheduleAtFixedRate(deactivator, schedule.get()); 63 : } else { 64 0 : logger.atWarning().log( 65 : "Not scheduling AccountDeactivator because auth.autoUpdateAccountActiveStatus is false"); 66 : } 67 : } 68 138 : } 69 : 70 : @Override 71 : public void stop() { 72 : // handled by WorkQueue.stop() already 73 138 : } 74 : } 75 : 76 : private final Provider<InternalAccountQuery> accountQueryProvider; 77 : private final Realm realm; 78 : private final SetInactiveFlag sif; 79 : 80 : @Inject 81 : AccountDeactivator( 82 138 : Provider<InternalAccountQuery> accountQueryProvider, SetInactiveFlag sif, Realm realm) { 83 138 : this.accountQueryProvider = accountQueryProvider; 84 138 : this.sif = sif; 85 138 : this.realm = realm; 86 138 : } 87 : 88 : @Override 89 : public void run() { 90 0 : logger.atInfo().log("Running account deactivations"); 91 : try { 92 0 : int numberOfAccountsDeactivated = 0; 93 0 : for (AccountState acc : accountQueryProvider.get().query(AccountPredicates.isActive())) { 94 0 : if (processAccount(acc)) { 95 0 : numberOfAccountsDeactivated++; 96 : } 97 0 : } 98 0 : logger.atInfo().log( 99 : "Deactivations complete, %d account(s) were deactivated", numberOfAccountsDeactivated); 100 0 : } catch (Exception e) { 101 0 : logger.atSevere().withCause(e).log( 102 0 : "Failed to complete deactivation of accounts: %s", e.getMessage()); 103 0 : } 104 0 : } 105 : 106 : private boolean processAccount(AccountState accountState) { 107 0 : if (!accountState.userName().isPresent()) { 108 0 : return false; 109 : } 110 : 111 0 : String userName = accountState.userName().get(); 112 0 : logger.atFine().log("processing account %s", userName); 113 : try { 114 0 : if (realm.accountBelongsToRealm(accountState.externalIds()) && !realm.isActive(userName)) { 115 0 : sif.deactivate(accountState.account().id()); 116 0 : logger.atInfo().log("deactivated account %s", userName); 117 0 : return true; 118 : } 119 0 : } catch (ResourceConflictException e) { 120 0 : logger.atInfo().withCause(e).log("Account %s already deactivated, continuing...", userName); 121 0 : } catch (Exception e) { 122 0 : logger.atSevere().withCause(e).log( 123 : "Error deactivating account: %s (%s) %s", 124 0 : userName, accountState.account().id(), e.getMessage()); 125 0 : } 126 0 : return false; 127 : } 128 : 129 : @Override 130 : public String toString() { 131 0 : return "account deactivator"; 132 : } 133 : }