| // Copyright (C) 2012 The Android Open Source Project |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| package com.google.gerrit.sshd.commands; |
| |
| import com.google.gerrit.common.data.GlobalCapability; |
| import com.google.gerrit.common.errors.EmailException; |
| import com.google.gerrit.extensions.annotations.RequiresCapability; |
| import com.google.gerrit.extensions.restapi.RawInput; |
| import com.google.gerrit.extensions.restapi.ResourceNotFoundException; |
| import com.google.gerrit.extensions.restapi.RestApiException; |
| import com.google.gerrit.reviewdb.client.Account; |
| import com.google.gerrit.reviewdb.client.AccountSshKey; |
| import com.google.gerrit.server.IdentifiedUser; |
| import com.google.gerrit.server.account.AccountResource; |
| import com.google.gerrit.server.account.AddSshKey; |
| import com.google.gerrit.server.account.CreateEmail; |
| import com.google.gerrit.server.account.DeleteActive; |
| import com.google.gerrit.server.account.DeleteEmail; |
| import com.google.gerrit.server.account.DeleteSshKey; |
| import com.google.gerrit.server.account.GetEmails; |
| import com.google.gerrit.server.account.GetEmails.EmailInfo; |
| import com.google.gerrit.server.account.GetSshKeys; |
| import com.google.gerrit.server.account.GetSshKeys.SshKeyInfo; |
| import com.google.gerrit.server.account.PutActive; |
| import com.google.gerrit.server.account.PutHttpPassword; |
| import com.google.gerrit.server.account.PutName; |
| import com.google.gerrit.sshd.BaseCommand; |
| import com.google.gerrit.sshd.CommandMetaData; |
| import com.google.gwtorm.server.OrmException; |
| import com.google.inject.Inject; |
| |
| import org.apache.sshd.server.Environment; |
| import org.kohsuke.args4j.Argument; |
| import org.kohsuke.args4j.Option; |
| |
| import java.io.BufferedReader; |
| import java.io.ByteArrayInputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.InputStreamReader; |
| import java.io.UnsupportedEncodingException; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.List; |
| |
| /** Set a user's account settings. **/ |
| @CommandMetaData(name = "set-account", description = "Change an account's settings") |
| @RequiresCapability(GlobalCapability.MODIFY_ACCOUNT) |
| final class SetAccountCommand extends BaseCommand { |
| |
| @Argument(index = 0, required = true, metaVar = "USER", usage = "full name, email-address, ssh username or account id") |
| private Account.Id id; |
| |
| @Option(name = "--full-name", metaVar = "NAME", usage = "display name of the account") |
| private String fullName; |
| |
| @Option(name = "--active", usage = "set account's state to active") |
| private boolean active; |
| |
| @Option(name = "--inactive", usage = "set account's state to inactive") |
| private boolean inactive; |
| |
| @Option(name = "--add-email", metaVar = "EMAIL", usage = "email addresses to add to the account") |
| private List<String> addEmails = new ArrayList<>(); |
| |
| @Option(name = "--delete-email", metaVar = "EMAIL", usage = "email addresses to delete from the account") |
| private List<String> deleteEmails = new ArrayList<>(); |
| |
| @Option(name = "--add-ssh-key", metaVar = "-|KEY", usage = "public keys to add to the account") |
| private List<String> addSshKeys = new ArrayList<>(); |
| |
| @Option(name = "--delete-ssh-key", metaVar = "-|KEY", usage = "public keys to delete from the account") |
| private List<String> deleteSshKeys = new ArrayList<>(); |
| |
| @Option(name = "--http-password", metaVar = "PASSWORD", usage = "password for HTTP authentication for the account") |
| private String httpPassword; |
| |
| @Inject |
| private IdentifiedUser.GenericFactory genericUserFactory; |
| |
| @Inject |
| private CreateEmail.Factory createEmailFactory; |
| |
| @Inject |
| private GetEmails getEmails; |
| |
| @Inject |
| private DeleteEmail deleteEmail; |
| |
| @Inject |
| private PutName putName; |
| |
| @Inject |
| private PutHttpPassword putHttpPassword; |
| |
| @Inject |
| private PutActive putActive; |
| |
| @Inject |
| private DeleteActive deleteActive; |
| |
| @Inject |
| private AddSshKey addSshKey; |
| |
| @Inject |
| private GetSshKeys getSshKeys; |
| |
| @Inject |
| private DeleteSshKey deleteSshKey; |
| |
| private IdentifiedUser user; |
| private AccountResource rsrc; |
| |
| @Override |
| public void start(final Environment env) { |
| startThread(new CommandRunnable() { |
| @Override |
| public void run() throws Exception { |
| parseCommandLine(); |
| validate(); |
| setAccount(); |
| } |
| }); |
| } |
| |
| private void validate() throws UnloggedFailure { |
| if (active && inactive) { |
| throw new UnloggedFailure(1, |
| "--active and --inactive options are mutually exclusive."); |
| } |
| if (addSshKeys.contains("-") && deleteSshKeys.contains("-")) { |
| throw new UnloggedFailure(1, "Only one option may use the stdin"); |
| } |
| if (deleteSshKeys.contains("ALL")) { |
| deleteSshKeys = Collections.singletonList("ALL"); |
| } |
| if (deleteEmails.contains("ALL")) { |
| deleteEmails = Collections.singletonList("ALL"); |
| } |
| } |
| |
| private void setAccount() throws OrmException, IOException, UnloggedFailure { |
| user = genericUserFactory.create(id); |
| rsrc = new AccountResource(user); |
| try { |
| for (String email : addEmails) { |
| addEmail(email); |
| } |
| |
| for (String email : deleteEmails) { |
| deleteEmail(email); |
| } |
| |
| if (fullName != null) { |
| PutName.Input in = new PutName.Input(); |
| in.name = fullName; |
| putName.apply(rsrc, in); |
| } |
| |
| if (httpPassword != null) { |
| PutHttpPassword.Input in = new PutHttpPassword.Input(); |
| in.httpPassword = httpPassword; |
| putHttpPassword.apply(rsrc, in); |
| } |
| |
| if (active) { |
| putActive.apply(rsrc, null); |
| } else if (inactive) { |
| try { |
| deleteActive.apply(rsrc, null); |
| } catch (ResourceNotFoundException e) { |
| // user is already inactive |
| } |
| } |
| |
| addSshKeys = readSshKey(addSshKeys); |
| if (!addSshKeys.isEmpty()) { |
| addSshKeys(addSshKeys); |
| } |
| |
| deleteSshKeys = readSshKey(deleteSshKeys); |
| if (!deleteSshKeys.isEmpty()) { |
| deleteSshKeys(deleteSshKeys); |
| } |
| } catch (RestApiException e) { |
| throw die(e.getMessage()); |
| } |
| } |
| |
| private void addSshKeys(List<String> sshKeys) throws RestApiException, |
| UnloggedFailure, OrmException, IOException { |
| for (final String sshKey : sshKeys) { |
| AddSshKey.Input in = new AddSshKey.Input(); |
| in.raw = new RawInput() { |
| @Override |
| public InputStream getInputStream() throws IOException { |
| return new ByteArrayInputStream(sshKey.getBytes("UTF-8")); |
| } |
| |
| @Override |
| public String getContentType() { |
| return "plain/text"; |
| } |
| |
| @Override |
| public long getContentLength() { |
| return sshKey.length(); |
| } |
| }; |
| addSshKey.apply(rsrc, in); |
| } |
| } |
| |
| private void deleteSshKeys(List<String> sshKeys) throws RestApiException, |
| OrmException { |
| List<SshKeyInfo> infos = getSshKeys.apply(rsrc); |
| if (sshKeys.contains("ALL")) { |
| for (SshKeyInfo i : infos) { |
| deleteSshKey(i); |
| } |
| } else { |
| for (String sshKey : sshKeys) { |
| for (SshKeyInfo i : infos) { |
| if (sshKey.trim().equals(i.sshPublicKey) |
| || sshKey.trim().equals(i.comment)) { |
| deleteSshKey(i); |
| } |
| } |
| } |
| } |
| } |
| |
| private void deleteSshKey(SshKeyInfo i) throws OrmException { |
| AccountSshKey sshKey = new AccountSshKey( |
| new AccountSshKey.Id(user.getAccountId(), i.seq), i.sshPublicKey); |
| deleteSshKey.apply( |
| new AccountResource.SshKey(user, sshKey), null); |
| } |
| |
| private void addEmail(String email) throws UnloggedFailure, RestApiException, |
| OrmException { |
| CreateEmail.Input in = new CreateEmail.Input(); |
| in.email = email; |
| in.noConfirmation = true; |
| try { |
| createEmailFactory.create(email).apply(rsrc, in); |
| } catch (EmailException e) { |
| throw die(e.getMessage()); |
| } |
| } |
| |
| private void deleteEmail(String email) throws UnloggedFailure, |
| RestApiException, OrmException { |
| if (email.equals("ALL")) { |
| List<EmailInfo> emails = getEmails.apply(rsrc);; |
| for (EmailInfo e : emails) { |
| deleteEmail.apply(new AccountResource.Email(user, e.email), |
| new DeleteEmail.Input()); |
| } |
| } else { |
| deleteEmail.apply(new AccountResource.Email(user, email), |
| new DeleteEmail.Input()); |
| } |
| } |
| |
| private List<String> readSshKey(final List<String> sshKeys) |
| throws UnsupportedEncodingException, IOException { |
| if (!sshKeys.isEmpty()) { |
| String sshKey; |
| int idx = sshKeys.indexOf("-"); |
| if (idx >= 0) { |
| sshKey = ""; |
| BufferedReader br = |
| new BufferedReader(new InputStreamReader(in, "UTF-8")); |
| String line; |
| while ((line = br.readLine()) != null) { |
| sshKey += line + "\n"; |
| } |
| sshKeys.set(idx, sshKey); |
| } |
| } |
| return sshKeys; |
| } |
| } |