Merge "Support creation of accounts via REST"
This commit is contained in:
commit
df5679f0a3
@ -35,6 +35,50 @@ Returns an account as an link:#account-info[AccountInfo] entity.
|
||||
}
|
||||
----
|
||||
|
||||
[[create-account]]
|
||||
Create Account
|
||||
~~~~~~~~~~~~~~
|
||||
[verse]
|
||||
'PUT /accounts/link:#username[\{username\}]'
|
||||
|
||||
Creates a new account.
|
||||
|
||||
In the request body additional data for the account can be provided as
|
||||
link:#account-input[AccountInput].
|
||||
|
||||
.Request
|
||||
----
|
||||
PUT /accounts/john HTTP/1.0
|
||||
Content-Type: application/json;charset=UTF-8
|
||||
|
||||
{
|
||||
"name": "John Doe",
|
||||
"email": "john.doe@example.com",
|
||||
"ssh_key": "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA0T...YImydZAw==",
|
||||
"http_password": "19D9aIn7zePb",
|
||||
"groups": [
|
||||
"MyProject-Owners"
|
||||
]
|
||||
}
|
||||
----
|
||||
|
||||
As response a detailed link:#account-info[AccountInfo] entity is
|
||||
returned that describes the created account.
|
||||
|
||||
.Response
|
||||
----
|
||||
HTTP/1.1 201 Created
|
||||
Content-Disposition: attachment
|
||||
Content-Type: application/json;charset=UTF-8
|
||||
|
||||
)]}'
|
||||
{
|
||||
"_account_id": 1000195,
|
||||
"name": "John Doe",
|
||||
"email": "john.doe@example.com"
|
||||
}
|
||||
----
|
||||
|
||||
[[list-account-capabilities]]
|
||||
List Account Capabilities
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@ -391,6 +435,11 @@ This can be:
|
||||
Identifier of a global capability. Valid values are all field names of
|
||||
the link:#capability-info[CapabilityInfo] entity.
|
||||
|
||||
[[username]]
|
||||
\{username\}
|
||||
~~~~~~~~~~~~
|
||||
The user name.
|
||||
|
||||
|
||||
[[json-entities]]
|
||||
JSON Entities
|
||||
@ -412,6 +461,26 @@ The email address the user prefers to be contacted through. +
|
||||
Only set if detailed account information is requested.
|
||||
|===========================
|
||||
|
||||
[[account-input]]
|
||||
AccountInput
|
||||
~~~~~~~~~~~~
|
||||
The `AccountInput` entity contains information for the creation of
|
||||
a new account.
|
||||
|
||||
[options="header",width="50%",cols="1,^2,4"]
|
||||
|============================
|
||||
|Field Name ||Description
|
||||
|`username` |optional|
|
||||
The user name. If provided, must match the user name from the URL.
|
||||
|`name` |optional|The full name of the user.
|
||||
|`email` |optional|The email address of the user.
|
||||
|`ssh_key` |optional|The public SSH key of the user.
|
||||
|`http_password`|optional|The HTTP password of the user.
|
||||
|`groups` |optional|
|
||||
A list of link:rest-api-groups.html#group-id[group IDs] that identify
|
||||
the groups to which the user should be added.
|
||||
|============================
|
||||
|
||||
[[capability-info]]
|
||||
CapabilityInfo
|
||||
~~~~~~~~~~~~~~
|
||||
|
@ -16,6 +16,7 @@ package com.google.gerrit.server.account;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.gerrit.extensions.registration.DynamicMap;
|
||||
import com.google.gerrit.extensions.restapi.AcceptsCreate;
|
||||
import com.google.gerrit.extensions.restapi.AuthException;
|
||||
import com.google.gerrit.extensions.restapi.IdString;
|
||||
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
|
||||
@ -34,24 +35,28 @@ import com.google.inject.Provider;
|
||||
import java.util.Set;
|
||||
|
||||
public class AccountsCollection implements
|
||||
RestCollection<TopLevelResource, AccountResource> {
|
||||
RestCollection<TopLevelResource, AccountResource>,
|
||||
AcceptsCreate<TopLevelResource>{
|
||||
private final Provider<CurrentUser> self;
|
||||
private final AccountResolver resolver;
|
||||
private final AccountControl.Factory accountControlFactory;
|
||||
private final IdentifiedUser.GenericFactory userFactory;
|
||||
private final DynamicMap<RestView<AccountResource>> views;
|
||||
private final CreateAccount.Factory createAccountFactory;
|
||||
|
||||
@Inject
|
||||
AccountsCollection(Provider<CurrentUser> self,
|
||||
AccountResolver resolver,
|
||||
AccountControl.Factory accountControlFactory,
|
||||
IdentifiedUser.GenericFactory userFactory,
|
||||
DynamicMap<RestView<AccountResource>> views) {
|
||||
DynamicMap<RestView<AccountResource>> views,
|
||||
CreateAccount.Factory createAccountFactory) {
|
||||
this.self = self;
|
||||
this.resolver = resolver;
|
||||
this.accountControlFactory = accountControlFactory;
|
||||
this.userFactory = userFactory;
|
||||
this.views = views;
|
||||
this.createAccountFactory = createAccountFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -116,4 +121,10 @@ public class AccountsCollection implements
|
||||
public DynamicMap<RestView<AccountResource>> views() {
|
||||
return views;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public CreateAccount create(TopLevelResource parent, IdString username) {
|
||||
return createAccountFactory.create(username.get());
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,200 @@
|
||||
// Copyright (C) 2013 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.server.account;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.gerrit.common.data.GlobalCapability;
|
||||
import com.google.gerrit.common.data.GroupDescriptions;
|
||||
import com.google.gerrit.common.errors.InvalidSshKeyException;
|
||||
import com.google.gerrit.extensions.annotations.RequiresCapability;
|
||||
import com.google.gerrit.extensions.restapi.BadRequestException;
|
||||
import com.google.gerrit.extensions.restapi.DefaultInput;
|
||||
import com.google.gerrit.extensions.restapi.ResourceConflictException;
|
||||
import com.google.gerrit.extensions.restapi.Response;
|
||||
import com.google.gerrit.extensions.restapi.RestModifyView;
|
||||
import com.google.gerrit.extensions.restapi.TopLevelResource;
|
||||
import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
|
||||
import com.google.gerrit.reviewdb.client.Account;
|
||||
import com.google.gerrit.reviewdb.client.AccountExternalId;
|
||||
import com.google.gerrit.reviewdb.client.AccountGroup;
|
||||
import com.google.gerrit.reviewdb.client.AccountGroupMember;
|
||||
import com.google.gerrit.reviewdb.client.AccountGroupMemberAudit;
|
||||
import com.google.gerrit.reviewdb.client.AccountSshKey;
|
||||
import com.google.gerrit.reviewdb.server.ReviewDb;
|
||||
import com.google.gerrit.server.IdentifiedUser;
|
||||
import com.google.gerrit.server.account.CreateAccount.Input;
|
||||
import com.google.gerrit.server.group.GroupsCollection;
|
||||
import com.google.gerrit.server.ssh.SshKeyCache;
|
||||
import com.google.gwtorm.server.OrmDuplicateKeyException;
|
||||
import com.google.gwtorm.server.OrmException;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.assistedinject.Assisted;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@RequiresCapability(GlobalCapability.CREATE_ACCOUNT)
|
||||
public class CreateAccount implements RestModifyView<TopLevelResource, Input> {
|
||||
public static class Input {
|
||||
@DefaultInput
|
||||
public String username;
|
||||
public String name;
|
||||
public String email;
|
||||
public String sshKey;
|
||||
public String httpPassword;
|
||||
public List<String> groups;
|
||||
}
|
||||
|
||||
public static interface Factory {
|
||||
CreateAccount create(String username);
|
||||
}
|
||||
|
||||
private final ReviewDb db;
|
||||
private final IdentifiedUser currentUser;
|
||||
private final GroupsCollection groupsCollection;
|
||||
private final SshKeyCache sshKeyCache;
|
||||
private final AccountCache accountCache;
|
||||
private final AccountByEmailCache byEmailCache;
|
||||
private final String username;
|
||||
|
||||
@Inject
|
||||
CreateAccount(ReviewDb db, IdentifiedUser currentUser,
|
||||
GroupsCollection groupsCollection, SshKeyCache sshKeyCache,
|
||||
AccountCache accountCache, AccountByEmailCache byEmailCache,
|
||||
@Assisted String username) {
|
||||
this.db = db;
|
||||
this.currentUser = currentUser;
|
||||
this.groupsCollection = groupsCollection;
|
||||
this.sshKeyCache = sshKeyCache;
|
||||
this.accountCache = accountCache;
|
||||
this.byEmailCache = byEmailCache;
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object apply(TopLevelResource rsrc, Input input)
|
||||
throws BadRequestException, ResourceConflictException,
|
||||
UnprocessableEntityException, OrmException {
|
||||
if (input == null) {
|
||||
input = new Input();
|
||||
}
|
||||
if (input.username != null && !username.equals(input.username)) {
|
||||
throw new BadRequestException("username must match URL");
|
||||
}
|
||||
|
||||
if (!username.matches(Account.USER_NAME_PATTERN)) {
|
||||
throw new BadRequestException("Username '" + username + "'"
|
||||
+ " must contain only letters, numbers, _, - or .");
|
||||
}
|
||||
|
||||
Set<AccountGroup.Id> groups = parseGroups(input.groups);
|
||||
|
||||
Account.Id id = new Account.Id(db.nextAccountId());
|
||||
AccountSshKey key = createSshKey(id, input.sshKey);
|
||||
|
||||
AccountExternalId extUser =
|
||||
new AccountExternalId(id, new AccountExternalId.Key(
|
||||
AccountExternalId.SCHEME_USERNAME, username));
|
||||
|
||||
if (input.httpPassword != null) {
|
||||
extUser.setPassword(input.httpPassword);
|
||||
}
|
||||
|
||||
if (db.accountExternalIds().get(extUser.getKey()) != null) {
|
||||
throw new ResourceConflictException(
|
||||
"username '" + username + "' already exists");
|
||||
}
|
||||
if (input.email != null
|
||||
&& db.accountExternalIds().get(getEmailKey(input.email)) != null) {
|
||||
throw new UnprocessableEntityException(
|
||||
"email '" + input.email + "' already exists");
|
||||
}
|
||||
|
||||
try {
|
||||
db.accountExternalIds().insert(Collections.singleton(extUser));
|
||||
} catch (OrmDuplicateKeyException duplicateKey) {
|
||||
throw new ResourceConflictException(
|
||||
"username '" + username + "' already exists");
|
||||
}
|
||||
|
||||
if (input.email != null) {
|
||||
AccountExternalId extMailto =
|
||||
new AccountExternalId(id, getEmailKey(input.email));
|
||||
extMailto.setEmailAddress(input.email);
|
||||
try {
|
||||
db.accountExternalIds().insert(Collections.singleton(extMailto));
|
||||
} catch (OrmDuplicateKeyException duplicateKey) {
|
||||
try {
|
||||
db.accountExternalIds().delete(Collections.singleton(extUser));
|
||||
} catch (OrmException cleanupError) {
|
||||
}
|
||||
throw new UnprocessableEntityException(
|
||||
"email '" + input.email + "' already exists");
|
||||
}
|
||||
}
|
||||
|
||||
Account a = new Account(id);
|
||||
a.setFullName(input.name);
|
||||
a.setPreferredEmail(input.email);
|
||||
db.accounts().insert(Collections.singleton(a));
|
||||
|
||||
if (key != null) {
|
||||
db.accountSshKeys().insert(Collections.singleton(key));
|
||||
}
|
||||
|
||||
for (AccountGroup.Id groupId : groups) {
|
||||
AccountGroupMember m =
|
||||
new AccountGroupMember(new AccountGroupMember.Key(id, groupId));
|
||||
db.accountGroupMembersAudit().insert(Collections.singleton(
|
||||
new AccountGroupMemberAudit(m, currentUser.getAccountId())));
|
||||
db.accountGroupMembers().insert(Collections.singleton(m));
|
||||
}
|
||||
|
||||
sshKeyCache.evict(username);
|
||||
accountCache.evictByUsername(username);
|
||||
byEmailCache.evict(input.email);
|
||||
|
||||
return Response.created(AccountInfo.parse(a, true));
|
||||
}
|
||||
|
||||
private Set<AccountGroup.Id> parseGroups(List<String> groups)
|
||||
throws UnprocessableEntityException {
|
||||
Set<AccountGroup.Id> groupIds = Sets.newHashSet();
|
||||
if (groups != null) {
|
||||
for (String g : groups) {
|
||||
groupIds.add(GroupDescriptions.toAccountGroup(
|
||||
groupsCollection.parseInternal(g)).getId());
|
||||
}
|
||||
}
|
||||
return groupIds;
|
||||
}
|
||||
|
||||
private AccountSshKey createSshKey(Account.Id id, String sshKey)
|
||||
throws BadRequestException {
|
||||
if (sshKey == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return sshKeyCache.create(new AccountSshKey.Id(id, 1), sshKey.trim());
|
||||
} catch (InvalidSshKeyException e) {
|
||||
throw new BadRequestException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private AccountExternalId.Key getEmailKey(String email) {
|
||||
return new AccountExternalId.Key(AccountExternalId.SCHEME_MAILTO, email);
|
||||
}
|
||||
}
|
@ -19,6 +19,7 @@ import static com.google.gerrit.server.account.AccountResource.CAPABILITY_KIND;
|
||||
|
||||
import com.google.gerrit.extensions.registration.DynamicMap;
|
||||
import com.google.gerrit.extensions.restapi.RestApiModule;
|
||||
import com.google.inject.assistedinject.FactoryModuleBuilder;
|
||||
|
||||
public class Module extends RestApiModule {
|
||||
@Override
|
||||
@ -29,6 +30,7 @@ public class Module extends RestApiModule {
|
||||
DynamicMap.mapOf(binder(), ACCOUNT_KIND);
|
||||
DynamicMap.mapOf(binder(), CAPABILITY_KIND);
|
||||
|
||||
put(ACCOUNT_KIND).to(PutAccount.class);
|
||||
get(ACCOUNT_KIND).to(GetAccount.class);
|
||||
get(ACCOUNT_KIND, "avatar").to(GetAvatar.class);
|
||||
get(ACCOUNT_KIND, "avatar.change.url").to(GetAvatarChangeUrl.class);
|
||||
@ -37,5 +39,7 @@ public class Module extends RestApiModule {
|
||||
get(ACCOUNT_KIND, "preferences.diff").to(GetDiffPreferences.class);
|
||||
put(ACCOUNT_KIND, "preferences.diff").to(SetDiffPreferences.class);
|
||||
get(CAPABILITY_KIND).to(GetCapabilities.CheckOne.class);
|
||||
|
||||
install(new FactoryModuleBuilder().build(CreateAccount.Factory.class));
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,28 @@
|
||||
// Copyright (C) 2013 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.server.account;
|
||||
|
||||
import com.google.gerrit.extensions.restapi.ResourceConflictException;
|
||||
import com.google.gerrit.extensions.restapi.RestModifyView;
|
||||
import com.google.gerrit.server.account.CreateAccount.Input;
|
||||
|
||||
public class PutAccount implements RestModifyView<AccountResource, Input> {
|
||||
@Override
|
||||
public Object apply(AccountResource resource, Input input)
|
||||
throws ResourceConflictException {
|
||||
throw new ResourceConflictException("Account \"" + resource.getUser().getNameEmail()
|
||||
+ "\" already exists");
|
||||
}
|
||||
}
|
@ -14,23 +14,16 @@
|
||||
|
||||
package com.google.gerrit.sshd.commands;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.gerrit.common.data.GlobalCapability;
|
||||
import com.google.gerrit.common.errors.InvalidSshKeyException;
|
||||
import com.google.gerrit.extensions.annotations.RequiresCapability;
|
||||
import com.google.gerrit.reviewdb.client.Account;
|
||||
import com.google.gerrit.reviewdb.client.AccountExternalId;
|
||||
import com.google.gerrit.extensions.restapi.RestApiException;
|
||||
import com.google.gerrit.extensions.restapi.TopLevelResource;
|
||||
import com.google.gerrit.reviewdb.client.AccountGroup;
|
||||
import com.google.gerrit.reviewdb.client.AccountGroupMember;
|
||||
import com.google.gerrit.reviewdb.client.AccountGroupMemberAudit;
|
||||
import com.google.gerrit.reviewdb.client.AccountSshKey;
|
||||
import com.google.gerrit.reviewdb.server.ReviewDb;
|
||||
import com.google.gerrit.server.IdentifiedUser;
|
||||
import com.google.gerrit.server.account.AccountByEmailCache;
|
||||
import com.google.gerrit.server.account.AccountCache;
|
||||
import com.google.gerrit.server.ssh.SshKeyCache;
|
||||
import com.google.gerrit.server.account.CreateAccount;
|
||||
import com.google.gerrit.sshd.CommandMetaData;
|
||||
import com.google.gerrit.sshd.SshCommand;
|
||||
import com.google.gwtorm.server.OrmDuplicateKeyException;
|
||||
import com.google.gwtorm.server.OrmException;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
@ -42,8 +35,6 @@ import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
/** Create a new user account. **/
|
||||
@ -69,94 +60,29 @@ final class CreateAccountCommand extends SshCommand {
|
||||
private String username;
|
||||
|
||||
@Inject
|
||||
private IdentifiedUser currentUser;
|
||||
|
||||
@Inject
|
||||
private ReviewDb db;
|
||||
|
||||
@Inject
|
||||
private SshKeyCache sshKeyCache;
|
||||
|
||||
@Inject
|
||||
private AccountCache accountCache;
|
||||
|
||||
@Inject
|
||||
private AccountByEmailCache byEmailCache;
|
||||
private CreateAccount.Factory createAccountFactory;
|
||||
|
||||
@Override
|
||||
protected void run() throws OrmException, IOException,
|
||||
InvalidSshKeyException, UnloggedFailure {
|
||||
if (!username.matches(Account.USER_NAME_PATTERN)) {
|
||||
throw die("Username '" + username + "'"
|
||||
+ " must contain only letters, numbers, _, - or .");
|
||||
}
|
||||
|
||||
final Account.Id id = new Account.Id(db.nextAccountId());
|
||||
final AccountSshKey key = readSshKey(id);
|
||||
|
||||
AccountExternalId extUser =
|
||||
new AccountExternalId(id, new AccountExternalId.Key(
|
||||
AccountExternalId.SCHEME_USERNAME, username));
|
||||
|
||||
if (httpPassword != null) {
|
||||
extUser.setPassword(httpPassword);
|
||||
}
|
||||
|
||||
if (db.accountExternalIds().get(extUser.getKey()) != null) {
|
||||
throw die("username '" + username + "' already exists");
|
||||
}
|
||||
if (email != null && db.accountExternalIds().get(getEmailKey()) != null) {
|
||||
throw die("email '" + email + "' already exists");
|
||||
}
|
||||
|
||||
protected void run() throws OrmException, IOException, UnloggedFailure {
|
||||
CreateAccount.Input input = new CreateAccount.Input();
|
||||
input.username = username;
|
||||
input.email = email;
|
||||
input.name = fullName;
|
||||
input.sshKey = readSshKey();
|
||||
input.httpPassword = httpPassword;
|
||||
input.groups = Lists.transform(groups, new Function<AccountGroup.Id, String>() {
|
||||
@Override
|
||||
public String apply(AccountGroup.Id id) {
|
||||
return id.toString();
|
||||
}});
|
||||
try {
|
||||
db.accountExternalIds().insert(Collections.singleton(extUser));
|
||||
} catch (OrmDuplicateKeyException duplicateKey) {
|
||||
throw die("username '" + username + "' already exists");
|
||||
createAccountFactory.create(username).apply(TopLevelResource.INSTANCE, input);
|
||||
} catch (RestApiException e) {
|
||||
throw die(e.getMessage());
|
||||
}
|
||||
|
||||
if (email != null) {
|
||||
AccountExternalId extMailto = new AccountExternalId(id, getEmailKey());
|
||||
extMailto.setEmailAddress(email);
|
||||
try {
|
||||
db.accountExternalIds().insert(Collections.singleton(extMailto));
|
||||
} catch (OrmDuplicateKeyException duplicateKey) {
|
||||
try {
|
||||
db.accountExternalIds().delete(Collections.singleton(extUser));
|
||||
} catch (OrmException cleanupError) {
|
||||
}
|
||||
throw die("email '" + email + "' already exists");
|
||||
}
|
||||
}
|
||||
|
||||
Account a = new Account(id);
|
||||
a.setFullName(fullName);
|
||||
a.setPreferredEmail(email);
|
||||
db.accounts().insert(Collections.singleton(a));
|
||||
|
||||
if (key != null) {
|
||||
db.accountSshKeys().insert(Collections.singleton(key));
|
||||
}
|
||||
|
||||
for (AccountGroup.Id groupId : new HashSet<AccountGroup.Id>(groups)) {
|
||||
AccountGroupMember m =
|
||||
new AccountGroupMember(new AccountGroupMember.Key(id, groupId));
|
||||
db.accountGroupMembersAudit().insert(Collections.singleton( //
|
||||
new AccountGroupMemberAudit(m, currentUser.getAccountId())));
|
||||
db.accountGroupMembers().insert(Collections.singleton(m));
|
||||
}
|
||||
|
||||
sshKeyCache.evict(username);
|
||||
accountCache.evictByUsername(username);
|
||||
byEmailCache.evict(email);
|
||||
}
|
||||
|
||||
private AccountExternalId.Key getEmailKey() {
|
||||
return new AccountExternalId.Key(AccountExternalId.SCHEME_MAILTO, email);
|
||||
}
|
||||
|
||||
private AccountSshKey readSshKey(final Account.Id id)
|
||||
throws UnsupportedEncodingException, IOException, InvalidSshKeyException {
|
||||
private String readSshKey() throws UnsupportedEncodingException, IOException {
|
||||
if (sshKey == null) {
|
||||
return null;
|
||||
}
|
||||
@ -169,6 +95,6 @@ final class CreateAccountCommand extends SshCommand {
|
||||
sshKey += line + "\n";
|
||||
}
|
||||
}
|
||||
return sshKeyCache.create(new AccountSshKey.Id(id, 1), sshKey.trim());
|
||||
return sshKey;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user