mirror of
https://github.com/apache/cloudstack.git
synced 2025-12-15 18:12:35 +01:00
API cmds for SSH-keys manipulation and VM passwds retrieval.
These include five new API cmds as well as changes to deployVirtualMachine to specify an optional name of an SSH key to pass to the VM when starting. When an SSH key is specified with a password-enabled template the newly created password is encrypted with the SSH public key and can be retrieved via the getVMPassword cmd. It is then the user's responsibility to decrypt retrieved passwords with the correct SSH private key.
This commit is contained in:
parent
49e2e6776e
commit
32c68e1583
52
api/src/com/cloud/api/commands/CreateSSHKeyPairCmd.java
Normal file
52
api/src/com/cloud/api/commands/CreateSSHKeyPairCmd.java
Normal file
@ -0,0 +1,52 @@
|
||||
package com.cloud.api.commands;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import com.cloud.api.ApiConstants;
|
||||
import com.cloud.api.BaseCmd;
|
||||
import com.cloud.api.Implementation;
|
||||
import com.cloud.api.Parameter;
|
||||
import com.cloud.api.response.SSHKeyPairResponse;
|
||||
import com.cloud.user.SSHKeyPair;
|
||||
|
||||
@Implementation(description="Create a new keypair and returns the private key", responseObject=SSHKeyPairResponse.class)
|
||||
public class CreateSSHKeyPairCmd extends BaseCmd {
|
||||
public static final Logger s_logger = Logger.getLogger(CreateSSHKeyPairCmd.class.getName());
|
||||
private static final String s_name = "createkeypairresponse";
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
//////////////// API parameters /////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
@Parameter(name=ApiConstants.NAME, type=CommandType.STRING, required=true, description="Name of the keypair")
|
||||
private String name;
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////////// Accessors ///////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////// API Implementation///////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
SSHKeyPair r = _mgr.createSSHKeyPair(this);
|
||||
SSHKeyPairResponse response = new SSHKeyPairResponse(r.getName(), r.getFingerprint(), r.getPrivateKey());
|
||||
response.setResponseName(getCommandName());
|
||||
response.setObjectName("keypair");
|
||||
this.setResponseObject(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCommandName() {
|
||||
return s_name;
|
||||
}
|
||||
}
|
||||
50
api/src/com/cloud/api/commands/DeleteSSHKeyPairCmd.java
Normal file
50
api/src/com/cloud/api/commands/DeleteSSHKeyPairCmd.java
Normal file
@ -0,0 +1,50 @@
|
||||
package com.cloud.api.commands;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import com.cloud.api.ApiConstants;
|
||||
import com.cloud.api.BaseCmd;
|
||||
import com.cloud.api.Implementation;
|
||||
import com.cloud.api.Parameter;
|
||||
import com.cloud.api.response.SuccessResponse;
|
||||
|
||||
@Implementation(description="Deletes a keypair by name", responseObject=SuccessResponse.class)
|
||||
public class DeleteSSHKeyPairCmd extends BaseCmd {
|
||||
public static final Logger s_logger = Logger.getLogger(CreateSSHKeyPairCmd.class.getName());
|
||||
private static final String s_name = "deletekeypairresponse";
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
//////////////// API parameters /////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
@Parameter(name=ApiConstants.NAME, type=CommandType.STRING, required=true, description="Name of the keypair")
|
||||
private String name;
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////////// Accessors ///////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////// API Implementation///////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
boolean result = _mgr.deleteSSHKeyPair(this);
|
||||
SuccessResponse response = new SuccessResponse(getCommandName());
|
||||
response.setSuccess(result);
|
||||
this.setResponseObject(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCommandName() {
|
||||
return s_name;
|
||||
}
|
||||
}
|
||||
@ -91,6 +91,9 @@ public class DeployVMCmd extends BaseAsyncCreateCmd {
|
||||
@Parameter(name=ApiConstants.NETWORK_IDS, type=CommandType.LIST, collectionType=CommandType.LONG, description="list of network ids used by virtual machine")
|
||||
private List<Long> networkIds;
|
||||
|
||||
@Parameter(name="keypair", type=CommandType.STRING, description="name of the ssh key pair used to login to the virtual machine")
|
||||
private String sshKeyPairName;
|
||||
|
||||
// unexposed parameter needed for serializing/deserializing the command
|
||||
@Parameter(name=ApiConstants.PASSWORD, type=CommandType.STRING, expose=false)
|
||||
private String password;
|
||||
@ -170,6 +173,10 @@ public class DeployVMCmd extends BaseAsyncCreateCmd {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getSSHKeyPairName() {
|
||||
return sshKeyPairName;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////// API Implementation///////////////////
|
||||
|
||||
54
api/src/com/cloud/api/commands/GetVMPasswordCmd.java
Normal file
54
api/src/com/cloud/api/commands/GetVMPasswordCmd.java
Normal file
@ -0,0 +1,54 @@
|
||||
package com.cloud.api.commands;
|
||||
|
||||
import java.security.InvalidParameterException;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import com.cloud.api.ApiConstants;
|
||||
import com.cloud.api.BaseCmd;
|
||||
import com.cloud.api.Implementation;
|
||||
import com.cloud.api.Parameter;
|
||||
import com.cloud.api.response.GetVMPasswordResponse;
|
||||
|
||||
@Implementation(responseObject=GetVMPasswordResponse.class, description="Returns an encrypted password for the VM")
|
||||
public class GetVMPasswordCmd extends BaseCmd {
|
||||
public static final Logger s_logger = Logger.getLogger(GetVMPasswordCmd.class.getName());
|
||||
private static final String s_name = "getvmpasswordresponse";
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
//////////////// API parameters /////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
@Parameter(name=ApiConstants.ID, type=CommandType.LONG, required=true, description="The ID of the virtual machine")
|
||||
private Long id;
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////////// Accessors ///////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////// API Implementation///////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
String passwd = _mgr.getVMPassword(this);
|
||||
if (passwd == null || passwd.equals(""))
|
||||
throw new InvalidParameterException("No password for VM with id '" + getId() + "' found.");
|
||||
|
||||
this.setResponseObject(new GetVMPasswordResponse(getCommandName(), passwd));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCommandName() {
|
||||
return s_name;
|
||||
}
|
||||
|
||||
}
|
||||
71
api/src/com/cloud/api/commands/ListSSHKeyPairsCmd.java
Normal file
71
api/src/com/cloud/api/commands/ListSSHKeyPairsCmd.java
Normal file
@ -0,0 +1,71 @@
|
||||
package com.cloud.api.commands;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import com.cloud.api.ApiConstants;
|
||||
import com.cloud.api.BaseListCmd;
|
||||
import com.cloud.api.Implementation;
|
||||
import com.cloud.api.Parameter;
|
||||
import com.cloud.api.response.ListResponse;
|
||||
import com.cloud.api.response.SSHKeyPairResponse;
|
||||
import com.cloud.user.SSHKeyPair;
|
||||
|
||||
@Implementation(description="List registered keypairs", responseObject=SSHKeyPairResponse.class)
|
||||
public class ListSSHKeyPairsCmd extends BaseListCmd {
|
||||
public static final Logger s_logger = Logger.getLogger(ListSSHKeyPairsCmd.class.getName());
|
||||
private static final String s_name = "listsshkeypairsresponse";
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
//////////////// API parameters /////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
@Parameter(name=ApiConstants.NAME, type=CommandType.STRING, required=false, description="A key pair name to look for")
|
||||
private String name;
|
||||
|
||||
@Parameter(name="fingerprint", type=CommandType.STRING, required=false, description="A public key fingerprint to look for")
|
||||
private String fingerprint;
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////////// Accessors ///////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getFingerprint() {
|
||||
return fingerprint;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////// API Implementation///////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
List<? extends SSHKeyPair> resultList = _mgr.listSSHKeyPairs(this);
|
||||
List<SSHKeyPairResponse> responses = new ArrayList<SSHKeyPairResponse>();
|
||||
for (SSHKeyPair result : resultList) {
|
||||
SSHKeyPairResponse r = new SSHKeyPairResponse(result.getName(), result.getFingerprint());
|
||||
r.setObjectName("keypair");
|
||||
responses.add(r);
|
||||
}
|
||||
|
||||
ListResponse<SSHKeyPairResponse> response = new ListResponse<SSHKeyPairResponse>();
|
||||
response.setResponses(responses);
|
||||
response.setResponseName(getCommandName());
|
||||
this.setResponseObject(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCommandName() {
|
||||
return s_name;
|
||||
}
|
||||
|
||||
}
|
||||
60
api/src/com/cloud/api/commands/RegisterSSHKeyPairCmd.java
Normal file
60
api/src/com/cloud/api/commands/RegisterSSHKeyPairCmd.java
Normal file
@ -0,0 +1,60 @@
|
||||
package com.cloud.api.commands;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import com.cloud.api.ApiConstants;
|
||||
import com.cloud.api.BaseCmd;
|
||||
import com.cloud.api.Implementation;
|
||||
import com.cloud.api.Parameter;
|
||||
import com.cloud.api.response.SSHKeyPairResponse;
|
||||
import com.cloud.user.SSHKeyPair;
|
||||
|
||||
@Implementation(description="Register a public key in a keypair under a certain name", responseObject=SSHKeyPairResponse.class)
|
||||
public class RegisterSSHKeyPairCmd extends BaseCmd {
|
||||
public static final Logger s_logger = Logger.getLogger(RegisterSSHKeyPairCmd.class.getName());
|
||||
private static final String s_name = "registerkeypairresponse";
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
//////////////// API parameters /////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
@Parameter(name=ApiConstants.NAME, type=CommandType.STRING, required=true, description="Name of the keypair")
|
||||
private String name;
|
||||
|
||||
@Parameter(name="publickey", type=CommandType.STRING, required=true, description="Public key material of the keypair")
|
||||
private String publicKey;
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////////// Accessors ///////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getPublicKey() {
|
||||
return publicKey;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////// API Implementation///////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
SSHKeyPair result = _mgr.registerSSHKeyPair(this);
|
||||
SSHKeyPairResponse response = new SSHKeyPairResponse(result.getName(), result.getFingerprint());
|
||||
response.setResponseName(getCommandName());
|
||||
response.setObjectName("keypair");
|
||||
this.setResponseObject(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCommandName() {
|
||||
return s_name;
|
||||
}
|
||||
|
||||
}
|
||||
27
api/src/com/cloud/api/response/GetVMPasswordResponse.java
Normal file
27
api/src/com/cloud/api/response/GetVMPasswordResponse.java
Normal file
@ -0,0 +1,27 @@
|
||||
package com.cloud.api.response;
|
||||
|
||||
import com.cloud.serializer.Param;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class GetVMPasswordResponse extends BaseResponse {
|
||||
|
||||
@SerializedName("encryptedpassword") @Param(description="The encrypted password of the VM")
|
||||
private String encryptedPassword;
|
||||
|
||||
public GetVMPasswordResponse() {}
|
||||
|
||||
public GetVMPasswordResponse(String responseName, String encryptedPassword) {
|
||||
setResponseName(responseName);
|
||||
setObjectName("password");
|
||||
setEncryptedPassword(encryptedPassword);
|
||||
}
|
||||
|
||||
public String getEncryptedPassword() {
|
||||
return encryptedPassword;
|
||||
}
|
||||
|
||||
public void setEncryptedPassword(String encryptedPassword) {
|
||||
this.encryptedPassword = encryptedPassword;
|
||||
}
|
||||
|
||||
}
|
||||
54
api/src/com/cloud/api/response/SSHKeyPairResponse.java
Normal file
54
api/src/com/cloud/api/response/SSHKeyPairResponse.java
Normal file
@ -0,0 +1,54 @@
|
||||
package com.cloud.api.response;
|
||||
|
||||
import com.cloud.api.ApiConstants;
|
||||
import com.cloud.serializer.Param;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class SSHKeyPairResponse extends BaseResponse {
|
||||
|
||||
@SerializedName(ApiConstants.NAME) @Param(description="Name of the keypair")
|
||||
private String name;
|
||||
|
||||
@SerializedName("fingerprint") @Param(description="Fingerprint of the public key")
|
||||
private String fingerprint;
|
||||
|
||||
@SerializedName("privatekey") @Param(description="Private key")
|
||||
private String privateKey;
|
||||
|
||||
public SSHKeyPairResponse() {}
|
||||
|
||||
public SSHKeyPairResponse(String name, String fingerprint) {
|
||||
this(name, fingerprint, null);
|
||||
}
|
||||
|
||||
public SSHKeyPairResponse(String name, String fingerprint, String privateKey) {
|
||||
this.name = name;
|
||||
this.fingerprint = fingerprint;
|
||||
this.privateKey = privateKey;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getFingerprint() {
|
||||
return fingerprint;
|
||||
}
|
||||
|
||||
public void setFingerprint(String fingerprint) {
|
||||
this.fingerprint = fingerprint;
|
||||
}
|
||||
|
||||
public String getPrivateKey() {
|
||||
return privateKey;
|
||||
}
|
||||
|
||||
public void setPrivateKey(String privateKey) {
|
||||
this.privateKey = privateKey;
|
||||
}
|
||||
|
||||
}
|
||||
@ -26,10 +26,13 @@ import java.util.Set;
|
||||
import com.cloud.alert.Alert;
|
||||
import com.cloud.api.ServerApiException;
|
||||
import com.cloud.api.commands.CreateDomainCmd;
|
||||
import com.cloud.api.commands.CreateSSHKeyPairCmd;
|
||||
import com.cloud.api.commands.DeleteDomainCmd;
|
||||
import com.cloud.api.commands.DeletePreallocatedLunCmd;
|
||||
import com.cloud.api.commands.DeleteSSHKeyPairCmd;
|
||||
import com.cloud.api.commands.ExtractVolumeCmd;
|
||||
import com.cloud.api.commands.GetCloudIdentifierCmd;
|
||||
import com.cloud.api.commands.GetVMPasswordCmd;
|
||||
import com.cloud.api.commands.ListAccountsCmd;
|
||||
import com.cloud.api.commands.ListAlertsCmd;
|
||||
import com.cloud.api.commands.ListAsyncJobsCmd;
|
||||
@ -50,6 +53,7 @@ import com.cloud.api.commands.ListPodsByCmd;
|
||||
import com.cloud.api.commands.ListPreallocatedLunsCmd;
|
||||
import com.cloud.api.commands.ListPublicIpAddressesCmd;
|
||||
import com.cloud.api.commands.ListRoutersCmd;
|
||||
import com.cloud.api.commands.ListSSHKeyPairsCmd;
|
||||
import com.cloud.api.commands.ListServiceOfferingsCmd;
|
||||
import com.cloud.api.commands.ListStoragePoolsCmd;
|
||||
import com.cloud.api.commands.ListSystemVMsCmd;
|
||||
@ -64,6 +68,7 @@ import com.cloud.api.commands.ListZonesByCmd;
|
||||
import com.cloud.api.commands.RebootSystemVmCmd;
|
||||
import com.cloud.api.commands.RegisterCmd;
|
||||
import com.cloud.api.commands.RegisterPreallocatedLunCmd;
|
||||
import com.cloud.api.commands.RegisterSSHKeyPairCmd;
|
||||
import com.cloud.api.commands.StartSystemVMCmd;
|
||||
import com.cloud.api.commands.StopSystemVmCmd;
|
||||
import com.cloud.api.commands.UpdateDomainCmd;
|
||||
@ -96,6 +101,7 @@ import com.cloud.storage.StoragePool;
|
||||
import com.cloud.storage.Volume;
|
||||
import com.cloud.template.VirtualMachineTemplate;
|
||||
import com.cloud.user.Account;
|
||||
import com.cloud.user.SSHKeyPair;
|
||||
import com.cloud.user.UserAccount;
|
||||
import com.cloud.uservm.UserVm;
|
||||
import com.cloud.utils.Pair;
|
||||
@ -406,4 +412,40 @@ public interface ManagementService {
|
||||
|
||||
public Long saveCompletedEvent(Long userId, Long accountId, String level, String type, String description, long startEventId);
|
||||
|
||||
/**
|
||||
* Search registered key pairs for the logged in user.
|
||||
* @param cmd The api command class.
|
||||
* @return The list of key pairs found.
|
||||
*/
|
||||
List<? extends SSHKeyPair> listSSHKeyPairs(ListSSHKeyPairsCmd cmd);
|
||||
|
||||
/**
|
||||
* Registers a key pair for a given public key.
|
||||
* @param cmd The api command class.
|
||||
* @return A VO with the key pair name and a finger print for the public key.
|
||||
*/
|
||||
SSHKeyPair registerSSHKeyPair(RegisterSSHKeyPairCmd cmd);
|
||||
|
||||
/**
|
||||
* Creates a new
|
||||
* @param cmd The api command class.
|
||||
* @return A VO containing the key pair name, finger print for the public key
|
||||
* and the private key material of the key pair.
|
||||
*/
|
||||
SSHKeyPair createSSHKeyPair(CreateSSHKeyPairCmd cmd);
|
||||
|
||||
/**
|
||||
* Deletes a key pair by name.
|
||||
* @param cmd The api command class.
|
||||
* @return True on success. False otherwise.
|
||||
*/
|
||||
boolean deleteSSHKeyPair(DeleteSSHKeyPairCmd cmd);
|
||||
|
||||
/**
|
||||
* Finds and returns an encrypted password for a VM.
|
||||
* @param cmd The api command class.
|
||||
* @return The encrypted password.
|
||||
*/
|
||||
String getVMPassword(GetVMPasswordCmd cmd);
|
||||
|
||||
}
|
||||
|
||||
32
api/src/com/cloud/user/SSHKeyPair.java
Normal file
32
api/src/com/cloud/user/SSHKeyPair.java
Normal file
@ -0,0 +1,32 @@
|
||||
package com.cloud.user;
|
||||
|
||||
import com.cloud.acl.ControlledEntity;
|
||||
|
||||
public interface SSHKeyPair extends ControlledEntity {
|
||||
|
||||
/**
|
||||
* @return The id of the key pair.
|
||||
*/
|
||||
public long getId();
|
||||
|
||||
/**
|
||||
* @return The given name of the key pair.
|
||||
*/
|
||||
public String getName();
|
||||
|
||||
/**
|
||||
* @return The finger print of the public key.
|
||||
*/
|
||||
public String getFingerprint();
|
||||
|
||||
/**
|
||||
* @return The public key of the key pair.
|
||||
*/
|
||||
public String getPublicKey();
|
||||
|
||||
/**
|
||||
* @return The private key of the key pair.
|
||||
*/
|
||||
public String getPrivateKey();
|
||||
|
||||
}
|
||||
@ -68,4 +68,10 @@ public interface UserVm extends VirtualMachine, ControlledEntity {
|
||||
Long getDomainRouterId();
|
||||
|
||||
void setUserData(String userData);
|
||||
|
||||
String getEncryptedPassword();
|
||||
|
||||
Long getSSHKeyPairId();
|
||||
|
||||
String getSSHPublicKey();
|
||||
}
|
||||
|
||||
@ -45,6 +45,7 @@ changeServiceForVirtualMachine=com.cloud.api.commands.UpgradeVMCmd;15
|
||||
updateVirtualMachine=com.cloud.api.commands.UpdateVMCmd;15
|
||||
recoverVirtualMachine=com.cloud.api.commands.RecoverVMCmd;3
|
||||
listVirtualMachines=com.cloud.api.commands.ListVMsCmd;15
|
||||
getVMPassword=com.cloud.api.commands.GetVMPasswordCmd;15
|
||||
|
||||
#### snapshot commands
|
||||
createSnapshot=com.cloud.api.commands.CreateSnapshotCmd;15
|
||||
@ -247,3 +248,10 @@ listNetworkOfferings=com.cloud.api.commands.ListNetworkOfferingsCmd;15
|
||||
createNetwork=com.cloud.api.commands.CreateNetworkCmd;15
|
||||
deleteNetwork=com.cloud.api.commands.DeleteNetworkCmd;15
|
||||
listNetworks=com.cloud.api.commands.ListNetworksCmd;15
|
||||
|
||||
#### SSH key pair commands
|
||||
registerSSHKeyPair=com.cloud.api.commands.RegisterSSHKeyPairCmd;15
|
||||
createSSHKeyPair=com.cloud.api.commands.CreateSSHKeyPairCmd;15
|
||||
deleteSSHKeyPair=com.cloud.api.commands.DeleteSSHKeyPairCmd;15
|
||||
listSSHKeyPairs=com.cloud.api.commands.ListSSHKeyPairsCmd;15
|
||||
|
||||
|
||||
@ -484,6 +484,9 @@ fi
|
||||
%{_javadir}/%{name}-commons-discovery.jar
|
||||
%{_javadir}/%{name}-iControl.jar
|
||||
%{_javadir}/%{name}-wsdl4j.jar
|
||||
%{_javadir}/%{name}-bcprov-jdk16-1.45.jar
|
||||
%{_javadir}/%{name}-jsch-0.1.42.jar
|
||||
|
||||
|
||||
%files core
|
||||
%defattr(0644,root,root,0755)
|
||||
|
||||
101
core/src/com/cloud/user/SSHKeyPairVO.java
Normal file
101
core/src/com/cloud/user/SSHKeyPairVO.java
Normal file
@ -0,0 +1,101 @@
|
||||
package com.cloud.user;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Transient;
|
||||
|
||||
@Entity
|
||||
@Table(name="ssh_keypairs")
|
||||
public class SSHKeyPairVO implements SSHKeyPair {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy=GenerationType.IDENTITY)
|
||||
@Column(name="id")
|
||||
private Long id = null;
|
||||
|
||||
@Column(name="account_id")
|
||||
private long accountId;
|
||||
|
||||
@Column(name="domain_id")
|
||||
private long domainId;
|
||||
|
||||
@Column(name="keypair_name")
|
||||
private String name;
|
||||
|
||||
@Column(name="fingerprint")
|
||||
private String fingerprint;
|
||||
|
||||
@Column(name="public_key")
|
||||
private String publicKey;
|
||||
|
||||
@Transient
|
||||
private String privateKey;
|
||||
|
||||
@Override
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getAccountId() {
|
||||
return accountId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getDomainId() {
|
||||
return domainId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFingerprint() {
|
||||
return fingerprint;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPublicKey() {
|
||||
return publicKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrivateKey() {
|
||||
return privateKey;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public void setAccountId(long accountId) {
|
||||
this.accountId = accountId;
|
||||
}
|
||||
|
||||
public void setDomainId(long domainId) {
|
||||
this.domainId = domainId;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void setFingerprint(String fingerprint) {
|
||||
this.fingerprint = fingerprint;
|
||||
}
|
||||
|
||||
public void setPublicKey(String publicKey) {
|
||||
this.publicKey = publicKey;
|
||||
}
|
||||
|
||||
public void setPrivateKey(String privateKey) {
|
||||
this.privateKey = privateKey;
|
||||
}
|
||||
|
||||
}
|
||||
@ -64,6 +64,15 @@ public class UserVmVO extends VMInstanceVO implements UserVm {
|
||||
@Column(name="display_name", updatable=true, nullable=true)
|
||||
private String displayName;
|
||||
|
||||
@Column(name="encrypted_password", updatable=true, nullable=true)
|
||||
private String encryptedPassword;
|
||||
|
||||
@Column(name="ssh_keypair_id", updatable=true, nullable=true)
|
||||
private Long sshKeyPairId;
|
||||
|
||||
@Column(name="ssh_public_key", updatable=true, nullable=true)
|
||||
private String sshPublicKey;
|
||||
|
||||
transient String password;
|
||||
|
||||
public String getPassword() {
|
||||
@ -74,6 +83,33 @@ public class UserVmVO extends VMInstanceVO implements UserVm {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSSHPublicKey() {
|
||||
return sshPublicKey;
|
||||
}
|
||||
|
||||
public void setSSHPublicKey(String publicKey) {
|
||||
this.sshPublicKey = publicKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEncryptedPassword() {
|
||||
return encryptedPassword;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getSSHKeyPairId() {
|
||||
return sshKeyPairId;
|
||||
}
|
||||
|
||||
public void setEncryptedPassword(String encryptedPassword) {
|
||||
this.encryptedPassword = encryptedPassword;
|
||||
}
|
||||
|
||||
public void setSSHKeyPairId(Long sshKeyPairId) {
|
||||
this.sshKeyPairId = sshKeyPairId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGuestIpAddress() {
|
||||
return guestIpAddress;
|
||||
@ -183,6 +219,24 @@ public class UserVmVO extends VMInstanceVO implements UserVm {
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
public UserVmVO(long id,
|
||||
String instanceName,
|
||||
String displayName,
|
||||
long templateId,
|
||||
long guestOsId,
|
||||
boolean haEnabled,
|
||||
long domainId,
|
||||
long accountId,
|
||||
long serviceOfferingId,
|
||||
String userData,
|
||||
String name,
|
||||
Long sshKeyPairId,
|
||||
String sshPublicKey) {
|
||||
this(id, instanceName, displayName, templateId, guestOsId, haEnabled, domainId, accountId, serviceOfferingId, userData, name);
|
||||
this.sshKeyPairId = sshKeyPairId;
|
||||
this.sshPublicKey = sshPublicKey;
|
||||
}
|
||||
|
||||
protected UserVmVO() {
|
||||
super();
|
||||
}
|
||||
|
||||
BIN
deps/cloud-bcprov-jdk16-1.45.jar
vendored
Normal file
BIN
deps/cloud-bcprov-jdk16-1.45.jar
vendored
Normal file
Binary file not shown.
BIN
deps/cloud-jsch-0.1.42.jar
vendored
Normal file
BIN
deps/cloud-jsch-0.1.42.jar
vendored
Normal file
Binary file not shown.
@ -110,6 +110,7 @@ import com.cloud.storage.upload.UploadMonitorImpl;
|
||||
import com.cloud.template.TemplateManagerImpl;
|
||||
import com.cloud.user.AccountManagerImpl;
|
||||
import com.cloud.user.dao.AccountDaoImpl;
|
||||
import com.cloud.user.dao.SSHKeyPairDaoImpl;
|
||||
import com.cloud.user.dao.UserAccountDaoImpl;
|
||||
import com.cloud.user.dao.UserDaoImpl;
|
||||
import com.cloud.user.dao.UserStatisticsDaoImpl;
|
||||
@ -234,6 +235,7 @@ public class DefaultComponentLibrary implements ComponentLibrary {
|
||||
addDao("ItWorkDao", ItWorkDaoImpl.class);
|
||||
addDao("FirewallRulesDao", FirewallRulesDaoImpl.class);
|
||||
addDao("PortForwardingRulesDao", PortForwardingRulesDaoImpl.class);
|
||||
addDao("SSHKeyPairDao", SSHKeyPairDaoImpl.class);
|
||||
addDao("UsageEventDao", UsageEventDaoImpl.class);
|
||||
addDao("ClusterDetailsDao", ClusterDetailsDaoImpl.class);
|
||||
}
|
||||
|
||||
@ -915,7 +915,7 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian
|
||||
}
|
||||
|
||||
private VmDataCommand generateVmDataCommand(VirtualRouter router, String vmPrivateIpAddress,
|
||||
String userData, String serviceOffering, String zoneName, String guestIpAddress, String vmName, String vmInstanceName, long vmId) {
|
||||
String userData, String serviceOffering, String zoneName, String guestIpAddress, String vmName, String vmInstanceName, long vmId, String publicKey) {
|
||||
VmDataCommand cmd = new VmDataCommand(vmPrivateIpAddress);
|
||||
|
||||
cmd.setAccessDetail(NetworkElementCommand.ROUTER_IP, router.getPrivateIpAddress());
|
||||
@ -930,6 +930,7 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian
|
||||
cmd.addVmData("metadata", "public-hostname", router.getPublicIpAddress());
|
||||
cmd.addVmData("metadata", "instance-id", vmInstanceName);
|
||||
cmd.addVmData("metadata", "vm-id", String.valueOf(vmId));
|
||||
cmd.addVmData("metadata", "public-keys", publicKey);
|
||||
|
||||
return cmd;
|
||||
}
|
||||
@ -1453,7 +1454,7 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian
|
||||
cmds.addCommand(
|
||||
"vmdata",
|
||||
generateVmDataCommand(router, nic.getIp4Address(), userData, serviceOffering, zoneName,
|
||||
nic.getIp4Address(), profile.getVirtualMachine().getName(), profile.getVirtualMachine().getInstanceName(), profile.getId()));
|
||||
nic.getIp4Address(), profile.getVirtualMachine().getName(), profile.getVirtualMachine().getInstanceName(), profile.getId(), profile.getVirtualMachine().getSSHPublicKey()));
|
||||
|
||||
try {
|
||||
_agentMgr.send(router.getHostId(), cmds);
|
||||
@ -1681,7 +1682,7 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian
|
||||
cmds.addCommand(
|
||||
"vmdata",
|
||||
generateVmDataCommand(router, nic.getIp4Address(), vm.getUserData(), serviceOffering, zoneName,
|
||||
nic.getIp4Address(), vm.getName(), vm.getInstanceName(), vm.getId()));
|
||||
nic.getIp4Address(), vm.getName(), vm.getInstanceName(), vm.getId(), null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -75,10 +75,13 @@ import com.cloud.api.ApiDBUtils;
|
||||
import com.cloud.api.BaseCmd;
|
||||
import com.cloud.api.ServerApiException;
|
||||
import com.cloud.api.commands.CreateDomainCmd;
|
||||
import com.cloud.api.commands.CreateSSHKeyPairCmd;
|
||||
import com.cloud.api.commands.DeleteDomainCmd;
|
||||
import com.cloud.api.commands.DeletePreallocatedLunCmd;
|
||||
import com.cloud.api.commands.DeleteSSHKeyPairCmd;
|
||||
import com.cloud.api.commands.ExtractVolumeCmd;
|
||||
import com.cloud.api.commands.GetCloudIdentifierCmd;
|
||||
import com.cloud.api.commands.GetVMPasswordCmd;
|
||||
import com.cloud.api.commands.ListAccountsCmd;
|
||||
import com.cloud.api.commands.ListAlertsCmd;
|
||||
import com.cloud.api.commands.ListAsyncJobsCmd;
|
||||
@ -99,6 +102,7 @@ import com.cloud.api.commands.ListPodsByCmd;
|
||||
import com.cloud.api.commands.ListPreallocatedLunsCmd;
|
||||
import com.cloud.api.commands.ListPublicIpAddressesCmd;
|
||||
import com.cloud.api.commands.ListRoutersCmd;
|
||||
import com.cloud.api.commands.ListSSHKeyPairsCmd;
|
||||
import com.cloud.api.commands.ListServiceOfferingsCmd;
|
||||
import com.cloud.api.commands.ListStoragePoolsCmd;
|
||||
import com.cloud.api.commands.ListSystemVMsCmd;
|
||||
@ -112,6 +116,7 @@ import com.cloud.api.commands.ListZonesByCmd;
|
||||
import com.cloud.api.commands.RebootSystemVmCmd;
|
||||
import com.cloud.api.commands.RegisterCmd;
|
||||
import com.cloud.api.commands.RegisterPreallocatedLunCmd;
|
||||
import com.cloud.api.commands.RegisterSSHKeyPairCmd;
|
||||
import com.cloud.api.commands.StartSystemVMCmd;
|
||||
import com.cloud.api.commands.StopSystemVmCmd;
|
||||
import com.cloud.api.commands.UpdateDomainCmd;
|
||||
@ -222,12 +227,15 @@ import com.cloud.template.VirtualMachineTemplate.TemplateFilter;
|
||||
import com.cloud.user.Account;
|
||||
import com.cloud.user.AccountManager;
|
||||
import com.cloud.user.AccountVO;
|
||||
import com.cloud.user.SSHKeyPair;
|
||||
import com.cloud.user.SSHKeyPairVO;
|
||||
import com.cloud.user.User;
|
||||
import com.cloud.user.UserAccount;
|
||||
import com.cloud.user.UserAccountVO;
|
||||
import com.cloud.user.UserContext;
|
||||
import com.cloud.user.UserVO;
|
||||
import com.cloud.user.dao.AccountDao;
|
||||
import com.cloud.user.dao.SSHKeyPairDao;
|
||||
import com.cloud.user.dao.UserAccountDao;
|
||||
import com.cloud.user.dao.UserDao;
|
||||
import com.cloud.utils.EnumUtils;
|
||||
@ -249,6 +257,7 @@ import com.cloud.utils.exception.CloudRuntimeException;
|
||||
import com.cloud.utils.exception.ExecutionException;
|
||||
import com.cloud.utils.net.MacAddress;
|
||||
import com.cloud.utils.net.NetUtils;
|
||||
import com.cloud.utils.ssh.SSHKeysHelper;
|
||||
import com.cloud.vm.ConsoleProxyVO;
|
||||
import com.cloud.vm.DomainRouterVO;
|
||||
import com.cloud.vm.InstanceGroupVO;
|
||||
@ -320,6 +329,8 @@ public class ManagementServerImpl implements ManagementServer {
|
||||
private final UploadMonitor _uploadMonitor;
|
||||
private final UploadDao _uploadDao;
|
||||
private final CertificateDao _certDao;
|
||||
private final SSHKeyPairDao _sshKeyPairDao;
|
||||
|
||||
|
||||
private final ScheduledExecutorService _eventExecutor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("EventChecker"));
|
||||
|
||||
@ -391,6 +402,7 @@ public class ManagementServerImpl implements ManagementServer {
|
||||
_asyncMgr = locator.getManager(AsyncJobManager.class);
|
||||
_tmpltMgr = locator.getManager(TemplateManager.class);
|
||||
_uploadMonitor = locator.getManager(UploadMonitor.class);
|
||||
_sshKeyPairDao = locator.getDao(SSHKeyPairDao.class);
|
||||
|
||||
_userAuthenticators = locator.getAdapters(UserAuthenticator.class);
|
||||
if (_userAuthenticators == null || !_userAuthenticators.isSet()) {
|
||||
@ -4663,4 +4675,88 @@ public class ManagementServerImpl implements ManagementServer {
|
||||
}
|
||||
return _hashKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSHKeyPair createSSHKeyPair(CreateSSHKeyPairCmd cmd) {
|
||||
Account account = UserContext.current().getCaller();
|
||||
SSHKeyPairVO s = _sshKeyPairDao.findByName(account.getAccountId(), account.getDomainId(), cmd.getName());
|
||||
if (s != null)
|
||||
throw new InvalidParameterValueException("A key pair with name '" + cmd.getName() + "' already exists.");
|
||||
|
||||
SSHKeysHelper keys = new SSHKeysHelper();
|
||||
|
||||
String name = cmd.getName();
|
||||
String publicKey = keys.getPublicKey();
|
||||
String fingerprint = keys.getPublicKeyFingerPrint();
|
||||
String privateKey = keys.getPrivateKey();
|
||||
|
||||
return createAndSaveSSHKeyPair(name, fingerprint, publicKey, privateKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteSSHKeyPair(DeleteSSHKeyPairCmd cmd) {
|
||||
Account account = UserContext.current().getCaller();
|
||||
SSHKeyPairVO s = _sshKeyPairDao.findByName(account.getAccountId(), account.getDomainId(), cmd.getName());
|
||||
if (s == null)
|
||||
throw new InvalidParameterValueException("A key pair with name '" + cmd.getName() + "' does not exist.");
|
||||
|
||||
return _sshKeyPairDao.deleteByName(account.getAccountId(), account.getDomainId(), cmd.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends SSHKeyPair> listSSHKeyPairs(ListSSHKeyPairsCmd cmd) {
|
||||
Account account = UserContext.current().getCaller();
|
||||
|
||||
if (cmd.getName() != null && cmd.getName().length() > 0)
|
||||
return _sshKeyPairDao.listKeyPairsByName(account.getAccountId(), account.getDomainId(), cmd.getName());
|
||||
|
||||
if (cmd.getFingerprint() != null && cmd.getFingerprint().length() > 0)
|
||||
return _sshKeyPairDao.listKeyPairsByFingerprint(account.getAccountId(), account.getDomainId(), cmd.getFingerprint());
|
||||
|
||||
return _sshKeyPairDao.listKeyPairs(account.getAccountId(), account.getDomainId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSHKeyPair registerSSHKeyPair(RegisterSSHKeyPairCmd cmd) {
|
||||
Account account = UserContext.current().getCaller();
|
||||
SSHKeyPairVO s = _sshKeyPairDao.findByName(account.getAccountId(), account.getDomainId(), cmd.getName());
|
||||
if (s != null)
|
||||
throw new InvalidParameterValueException("A key pair with name '" + cmd.getName() + "' already exists.");
|
||||
|
||||
String name = cmd.getName();
|
||||
String publicKey = SSHKeysHelper.getPublicKeyFromKeyMaterial(cmd.getPublicKey());
|
||||
String fingerprint = SSHKeysHelper.getPublicKeyFingerprint(publicKey);
|
||||
|
||||
if (publicKey == null)
|
||||
throw new InvalidParameterValueException("Public key is invalid");
|
||||
|
||||
return createAndSaveSSHKeyPair(name, fingerprint, publicKey, null);
|
||||
}
|
||||
|
||||
private SSHKeyPair createAndSaveSSHKeyPair(String name, String fingerprint, String publicKey, String privateKey) {
|
||||
Account account = UserContext.current().getCaller();
|
||||
SSHKeyPairVO newPair = new SSHKeyPairVO();
|
||||
|
||||
newPair.setAccountId(account.getAccountId());
|
||||
newPair.setDomainId(account.getDomainId());
|
||||
newPair.setName(name);
|
||||
newPair.setFingerprint(fingerprint);
|
||||
newPair.setPublicKey(publicKey);
|
||||
newPair.setPrivateKey(privateKey); // transient; not saved.
|
||||
|
||||
_sshKeyPairDao.persist(newPair);
|
||||
|
||||
return newPair;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVMPassword(GetVMPasswordCmd cmd) {
|
||||
Account account = UserContext.current().getCaller();
|
||||
UserVmVO vm = _userVmDao.findById(cmd.getId());
|
||||
if (vm == null || vm.getEncryptedPassword() == null || vm.getEncryptedPassword().equals("") || vm.getAccountId() != account.getAccountId())
|
||||
throw new InvalidParameterValueException("No password for VM with id '" + getId() + "' found.");
|
||||
|
||||
return vm.getEncryptedPassword();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
20
server/src/com/cloud/user/dao/SSHKeyPairDao.java
Normal file
20
server/src/com/cloud/user/dao/SSHKeyPairDao.java
Normal file
@ -0,0 +1,20 @@
|
||||
package com.cloud.user.dao;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.cloud.user.SSHKeyPairVO;
|
||||
import com.cloud.utils.db.GenericDao;
|
||||
|
||||
public interface SSHKeyPairDao extends GenericDao<SSHKeyPairVO, Long> {
|
||||
|
||||
public List<SSHKeyPairVO> listKeyPairs(long accountId, long domainId);
|
||||
|
||||
public List<SSHKeyPairVO> listKeyPairsByName(long accountId, long domainId, String name);
|
||||
|
||||
public List<SSHKeyPairVO> listKeyPairsByFingerprint(long accountId, long domainId, String fingerprint);
|
||||
|
||||
public SSHKeyPairVO findByName(long accountId, long domainId, String name);
|
||||
|
||||
public boolean deleteByName(long accountId, long domainId, String name);
|
||||
|
||||
}
|
||||
59
server/src/com/cloud/user/dao/SSHKeyPairDaoImpl.java
Normal file
59
server/src/com/cloud/user/dao/SSHKeyPairDaoImpl.java
Normal file
@ -0,0 +1,59 @@
|
||||
package com.cloud.user.dao;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.ejb.Local;
|
||||
|
||||
import com.cloud.user.SSHKeyPairVO;
|
||||
import com.cloud.utils.db.GenericDaoBase;
|
||||
import com.cloud.utils.db.SearchCriteria;
|
||||
|
||||
@Local(value={SSHKeyPairDao.class})
|
||||
public class SSHKeyPairDaoImpl extends GenericDaoBase<SSHKeyPairVO, Long> implements SSHKeyPairDao {
|
||||
|
||||
@Override
|
||||
public List<SSHKeyPairVO> listKeyPairs(long accountId, long domainId) {
|
||||
SearchCriteria<SSHKeyPairVO> sc = createSearchCriteria();
|
||||
sc.addAnd("accountId", SearchCriteria.Op.EQ, accountId);
|
||||
sc.addAnd("domainId", SearchCriteria.Op.EQ, domainId);
|
||||
return listBy(sc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SSHKeyPairVO> listKeyPairsByName(long accountId, long domainId, String name) {
|
||||
SearchCriteria<SSHKeyPairVO> sc = createSearchCriteria();
|
||||
sc.addAnd("accountId", SearchCriteria.Op.EQ, accountId);
|
||||
sc.addAnd("domainId", SearchCriteria.Op.EQ, domainId);
|
||||
sc.addAnd("name", SearchCriteria.Op.EQ, name);
|
||||
return listBy(sc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SSHKeyPairVO> listKeyPairsByFingerprint(long accountId, long domainId, String fingerprint) {
|
||||
SearchCriteria<SSHKeyPairVO> sc = createSearchCriteria();
|
||||
sc.addAnd("accountId", SearchCriteria.Op.EQ, accountId);
|
||||
sc.addAnd("domainId", SearchCriteria.Op.EQ, domainId);
|
||||
sc.addAnd("fingerprint", SearchCriteria.Op.EQ, fingerprint);
|
||||
return listBy(sc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSHKeyPairVO findByName(long accountId, long domainId, String name) {
|
||||
SearchCriteria<SSHKeyPairVO> sc = createSearchCriteria();
|
||||
sc.addAnd("accountId", SearchCriteria.Op.EQ, accountId);
|
||||
sc.addAnd("domainId", SearchCriteria.Op.EQ, domainId);
|
||||
sc.addAnd("name", SearchCriteria.Op.EQ, name);
|
||||
return findOneBy(sc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteByName(long accountId, long domainId, String name) {
|
||||
SSHKeyPairVO pair = findByName(accountId, domainId, name);
|
||||
if (pair == null)
|
||||
return false;
|
||||
|
||||
expunge(pair.getId());
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@ -171,10 +171,12 @@ import com.cloud.user.Account;
|
||||
import com.cloud.user.AccountManager;
|
||||
import com.cloud.user.AccountService;
|
||||
import com.cloud.user.AccountVO;
|
||||
import com.cloud.user.SSHKeyPair;
|
||||
import com.cloud.user.User;
|
||||
import com.cloud.user.UserContext;
|
||||
import com.cloud.user.UserVO;
|
||||
import com.cloud.user.dao.AccountDao;
|
||||
import com.cloud.user.dao.SSHKeyPairDao;
|
||||
import com.cloud.user.dao.UserDao;
|
||||
import com.cloud.user.dao.UserStatisticsDao;
|
||||
import com.cloud.uservm.UserVm;
|
||||
@ -186,6 +188,7 @@ import com.cloud.utils.component.ComponentLocator;
|
||||
import com.cloud.utils.component.Inject;
|
||||
import com.cloud.utils.component.Manager;
|
||||
import com.cloud.utils.concurrency.NamedThreadFactory;
|
||||
import com.cloud.utils.crypt.RSAHelper;
|
||||
import com.cloud.utils.db.DB;
|
||||
import com.cloud.utils.db.Filter;
|
||||
import com.cloud.utils.db.GlobalLock;
|
||||
@ -260,6 +263,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
|
||||
@Inject RulesManager _rulesMgr;
|
||||
@Inject LoadBalancingRulesManager _lbMgr;
|
||||
@Inject UsageEventDao _usageEventDao;
|
||||
@Inject SSHKeyPairDao _sshKeyPairDao;
|
||||
|
||||
private IpAddrAllocator _IpAllocator;
|
||||
ScheduledExecutorService _executor = null;
|
||||
@ -2232,6 +2236,19 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
|
||||
}
|
||||
}
|
||||
|
||||
// Find an SSH public key corresponding to the key pair name, if one is given
|
||||
Long sshKeyPairId = null;
|
||||
String sshPublicKey = null;
|
||||
if (cmd.getSSHKeyPairName() != null && !cmd.getSSHKeyPairName().equals("")) {
|
||||
Account account = UserContext.current().getCaller();
|
||||
SSHKeyPair pair = _sshKeyPairDao.findByName(account.getAccountId(), account.getDomainId(), cmd.getSSHKeyPairName());
|
||||
if (pair == null)
|
||||
throw new InvalidParameterValueException("A key pair with name '" + cmd.getSSHKeyPairName() + "' was not found.");
|
||||
|
||||
sshKeyPairId = pair.getId();
|
||||
sshPublicKey = pair.getPublicKey();
|
||||
}
|
||||
|
||||
_accountMgr.checkAccess(caller, template);
|
||||
|
||||
DataCenterDeployment plan = new DataCenterDeployment(dc.getId());
|
||||
@ -2288,7 +2305,8 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
|
||||
}
|
||||
|
||||
UserVmVO vm = new UserVmVO(id, instanceName, cmd.getDisplayName(),
|
||||
template.getId(), template.getGuestOSId(), offering.getOfferHA(), domainId, owner.getId(), offering.getId(), userData, hostName);
|
||||
template.getId(), template.getGuestOSId(), offering.getOfferHA(), domainId, owner.getId(), offering.getId(),
|
||||
userData, hostName, sshKeyPairId, sshPublicKey);
|
||||
|
||||
|
||||
if (_itMgr.allocate(vm, template, offering, rootDiskOffering, dataDiskOfferings, networks, null, plan, cmd.getHypervisor(), owner) == null) {
|
||||
@ -2336,6 +2354,16 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
|
||||
}
|
||||
vm.setPassword(password);
|
||||
|
||||
// Check if an SSH key pair was selected for the instance and if so use it to encrypt & save the vm password
|
||||
if (vm.getSSHKeyPairId() != null && vm.getSSHPublicKey() != null && password != null && !password.equals("saved_password") ) {
|
||||
String encryptedPasswd = RSAHelper.encryptWithSSHPublicKey(vm.getSSHPublicKey(), password);
|
||||
if (encryptedPasswd == null)
|
||||
throw new ServerApiException(BaseCmd.INTERNAL_ERROR, "Error encrypting password");
|
||||
|
||||
vm.setEncryptedPassword(encryptedPasswd);
|
||||
_vmDao.update(vm.getId(), vm);
|
||||
}
|
||||
|
||||
long userId = UserContext.current().getCallerUserId();
|
||||
UserVO caller = _userDao.findById(userId);
|
||||
|
||||
|
||||
@ -762,6 +762,7 @@ CREATE TABLE `cloud`.`user_vm` (
|
||||
`user_data` varchar(2048),
|
||||
`encrypted_password` varchar(1024) COMMENT 'vm password encrypted with the public key referenced in ssh_keypair',
|
||||
`ssh_keypair_id` bigint unsigned COMMENT 'id of the ssh keypair used to access the vm and/or encrypt the password',
|
||||
`ssh_public_key` varchar(5120) COMMENT 'ssh public key',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
|
||||
61
utils/src/com/cloud/utils/crypt/RSAHelper.java
Normal file
61
utils/src/com/cloud/utils/crypt/RSAHelper.java
Normal file
@ -0,0 +1,61 @@
|
||||
package com.cloud.utils.crypt;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.DataInput;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.Security;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.security.spec.KeySpec;
|
||||
import java.security.spec.RSAPublicKeySpec;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
|
||||
public class RSAHelper {
|
||||
|
||||
private static RSAPublicKey readKey(String key) throws Exception {
|
||||
byte[] encKey = Base64.decodeBase64(key.split(" ")[1]);
|
||||
DataInputStream dis = new DataInputStream(new ByteArrayInputStream(encKey));
|
||||
|
||||
byte[] header = readElement(dis);
|
||||
String pubKeyFormat = new String(header);
|
||||
if (!pubKeyFormat.equals("ssh-rsa"))
|
||||
throw new RuntimeException("Unsupported format");
|
||||
|
||||
byte[] publicExponent = readElement(dis);
|
||||
byte[] modulus = readElement(dis);
|
||||
|
||||
KeySpec spec = new RSAPublicKeySpec(new BigInteger(modulus), new BigInteger(publicExponent));
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("RSA", BouncyCastleProvider.PROVIDER_NAME);
|
||||
RSAPublicKey pubKey = (RSAPublicKey) keyFactory.generatePublic(spec);
|
||||
|
||||
return pubKey;
|
||||
}
|
||||
|
||||
private static byte[] readElement(DataInput dis) throws IOException {
|
||||
int len = dis.readInt();
|
||||
byte[] buf = new byte[len];
|
||||
dis.readFully(buf);
|
||||
return buf;
|
||||
}
|
||||
|
||||
public static String encryptWithSSHPublicKey(String sshPublicKey, String content) {
|
||||
String returnString = null;
|
||||
try {
|
||||
Security.addProvider(new BouncyCastleProvider());
|
||||
RSAPublicKey publicKey = readKey(sshPublicKey);
|
||||
Cipher cipher = Cipher.getInstance("RSA/None/PKCS1Padding", BouncyCastleProvider.PROVIDER_NAME);
|
||||
cipher.init(Cipher.ENCRYPT_MODE, publicKey , new SecureRandom());
|
||||
byte[] encrypted = cipher.doFinal(content.getBytes());
|
||||
returnString = Base64.encodeBase64String(encrypted);
|
||||
} catch (Exception e) {}
|
||||
|
||||
return returnString;
|
||||
}
|
||||
}
|
||||
90
utils/src/com/cloud/utils/ssh/SSHKeysHelper.java
Normal file
90
utils/src/com/cloud/utils/ssh/SSHKeysHelper.java
Normal file
@ -0,0 +1,90 @@
|
||||
package com.cloud.utils.ssh;
|
||||
|
||||
import com.jcraft.jsch.JSchException;
|
||||
import com.jcraft.jsch.KeyPair;
|
||||
import com.jcraft.jsch.JSch;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
|
||||
public class SSHKeysHelper {
|
||||
|
||||
private KeyPair keyPair;
|
||||
private static final char[] hexChars = { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' };
|
||||
|
||||
private static String toHexString(byte[] b) {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for (int i = 0; i < b.length; i++) {
|
||||
sb.append(hexChars[ (int)(((int)b[i] >> 4) & 0x0f)]);
|
||||
sb.append(hexChars[ (int)(((int)b[i]) & 0x0f)]);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public SSHKeysHelper() {
|
||||
try {
|
||||
keyPair = KeyPair.genKeyPair(new JSch(), KeyPair.RSA);
|
||||
} catch (JSchException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public String getPublicKeyFingerPrint() {
|
||||
return getPublicKeyFingerprint(getPublicKey());
|
||||
}
|
||||
|
||||
public static String getPublicKeyFingerprint(String publicKey) {
|
||||
String key[] = publicKey.split(" ");
|
||||
byte[] keyBytes = Base64.decodeBase64(key[1]);
|
||||
|
||||
MessageDigest md5 = null;
|
||||
try {
|
||||
md5 = MessageDigest.getInstance("MD5");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
String sumString = toHexString(md5.digest(keyBytes));
|
||||
String rString = "";
|
||||
|
||||
for (int i = 2; i <= sumString.length(); i += 2) {
|
||||
rString += sumString.substring(i-2, i);
|
||||
if (i != sumString.length())
|
||||
rString += ":";
|
||||
}
|
||||
|
||||
return rString;
|
||||
}
|
||||
|
||||
public static String getPublicKeyFromKeyMaterial(String keyMaterial) {
|
||||
if (!keyMaterial.contains(" "))
|
||||
keyMaterial = new String(Base64.decodeBase64(keyMaterial.getBytes()));
|
||||
|
||||
if (!keyMaterial.startsWith("ssh-rsa") || !keyMaterial.contains(" "))
|
||||
return null;
|
||||
|
||||
String[] key = keyMaterial.split(" ");
|
||||
if (key.length < 2)
|
||||
return null;
|
||||
|
||||
return key[0].concat(" ").concat(key[1]);
|
||||
}
|
||||
|
||||
public String getPublicKey() {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
keyPair.writePublicKey(baos, "");
|
||||
|
||||
return baos.toString();
|
||||
}
|
||||
|
||||
public String getPrivateKey() {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
keyPair.writePrivateKey(baos);
|
||||
|
||||
return baos.toString();
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user