blob: 5088424102258da70c71f5bc85fdf8d595858b10 [file] [log] [blame]
// 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.errors.EmailException;
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 com.google.inject.Provider;
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")
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 currentUser;
@Inject
private IdentifiedUser.GenericFactory genericUserFactory;
@Inject
private CreateEmail.Factory createEmailFactory;
@Inject
private Provider<GetEmails> getEmailsProvider;
@Inject
private Provider<DeleteEmail> deleteEmailProvider;
@Inject
private Provider<PutName> putNameProvider;
@Inject
private Provider<PutHttpPassword> putHttpPasswordProvider;
@Inject
private Provider<PutActive> putActiveProvider;
@Inject
private Provider<DeleteActive> deleteActiveProvider;
@Inject
private Provider<AddSshKey> addSshKeyProvider;
@Inject
private Provider<GetSshKeys> getSshKeysProvider;
@Inject
private Provider<DeleteSshKey> deleteSshKeyProvider;
private IdentifiedUser user;
private AccountResource rsrc;
@Override
public void start(final Environment env) {
startThread(new CommandRunnable() {
@Override
public void run() throws Exception {
if (!currentUser.getCapabilities().canAdministrateServer()) {
String msg =
String.format(
"fatal: %s does not have \"Administrator\" capability.",
currentUser.getUserName());
throw new UnloggedFailure(1, msg);
}
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;
putNameProvider.get().apply(rsrc, in);
}
if (httpPassword != null) {
PutHttpPassword.Input in = new PutHttpPassword.Input();
in.httpPassword = httpPassword;
putHttpPasswordProvider.get().apply(rsrc, in);
}
if (active) {
putActiveProvider.get().apply(rsrc, null);
} else if (inactive) {
try {
deleteActiveProvider.get().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();
}
};
addSshKeyProvider.get().apply(rsrc, in);
}
}
private void deleteSshKeys(List<String> sshKeys) throws RestApiException,
OrmException {
List<SshKeyInfo> infos = getSshKeysProvider.get().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);
deleteSshKeyProvider.get().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 = getEmailsProvider.get().apply(rsrc);
DeleteEmail deleteEmail = deleteEmailProvider.get();
for (EmailInfo e : emails) {
deleteEmail.apply(new AccountResource.Email(user, e.email),
new DeleteEmail.Input());
}
} else {
deleteEmailProvider.get().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;
}
}