Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

Expand All @@ -16,6 +16,11 @@

<dependencies>

<dependency>
<groupId>com.hierynomus</groupId>
<artifactId>sshj</artifactId>
<version>0.13.0</version>
</dependency>

<dependency>
<groupId>org.hibernate</groupId>
Expand Down Expand Up @@ -95,7 +100,7 @@
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.5.6</version>
<version>1.6.2</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
Expand Down
32 changes: 20 additions & 12 deletions src/main/java/com/sergeev/controlpanel/model/Node.java
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
package com.sergeev.controlpanel.model;

import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.sergeev.controlpanel.model.user.User;
import com.sun.istack.internal.NotNull;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;

import javax.persistence.*;
import java.net.InetAddress;
import java.util.*;
import java.util.HashSet;
import java.util.Set;

/**
* Created by dmitry-sergeev on 22.09.15.
Expand All @@ -35,6 +31,9 @@ public class Node extends AbstractModel{
@Column(name = "osVersion")
private String osVersion;

@Column(name = "publicKey", unique = true, nullable = false)
private String publicKey; // Looks like "a6:90:99:9c:c5:15:d8:07:b5:fa:c5:79:77:93:9b:b6"

@ElementCollection(targetClass = Component.class)
private Set<Component> components = null;

Expand All @@ -44,12 +43,21 @@ public class Node extends AbstractModel{
public Node() {
}

public Node(String name, InetAddress inetAddress, String osName, String osVersion) {
public Node(String name, InetAddress inetAddress, String osName, String osVersion, String publicKey) {
this.name = name;
this.inetAddress = inetAddress;
this.osName = osName;
this.osVersion = osVersion;
users = new HashSet<>();
this.publicKey = publicKey;
}

public String getPublicKey() {
return publicKey;
}

public void setPublicKey(String publicKey) {
this.publicKey = publicKey;
}

public long getId() {
Expand Down Expand Up @@ -92,15 +100,15 @@ public void setOsVersion(String osVersion) {
this.osVersion = osVersion;
}

public void setComponents(Set<Component> components) {
this.components = components;
}

@OneToMany(mappedBy = "node", cascade = CascadeType.ALL)
public Set<Component> getComponents(){
public Set<Component> getComponents() {
return components;
}

public void setComponents(Set<Component> components) {
this.components = components;
}

public Set<Component> addComponent(Component component){
components.add(component);
component.setNode(this);
Expand Down
144 changes: 144 additions & 0 deletions src/main/java/com/sergeev/controlpanel/ssh/SshService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
package com.sergeev.controlpanel.ssh;

import com.sergeev.controlpanel.model.Node;
import net.schmizz.sshj.SSHClient;
import net.schmizz.sshj.common.IOUtils;
import net.schmizz.sshj.connection.ConnectionException;
import net.schmizz.sshj.connection.channel.direct.Session;
import net.schmizz.sshj.connection.channel.direct.Session.Command;
import net.schmizz.sshj.transport.TransportException;
import net.schmizz.sshj.userauth.UserAuthException;

import java.io.File;
import java.io.IOException;
import java.util.concurrent.TimeUnit;


public class SshService {
private static final String KEY_PATH;

static {
KEY_PATH = (new File("src/main/resources/cp.pem")).getAbsolutePath();
}

private final SSHClient ssh;
private Node node;
private Session session;

public SshService(Node node) {
ssh = new SSHClient();
this.node = node;
}

public void updatePublicKey() {
ssh.addHostKeyVerifier(node.getPublicKey());
}

private void connect() throws IOException {
ssh.connect(node.getInetAddress());
}

private void disconnect() throws IOException {
ssh.disconnect();
}

private void logIn() throws UserAuthException, TransportException {
ssh.authPublickey("root", KEY_PATH);
}

private void logIn(String password) throws UserAuthException, TransportException {
ssh.authPassword("root", password);
}

private void startSession() throws ConnectionException, TransportException {
session = ssh.startSession();
}

private void stopSession() throws ConnectionException, TransportException {
session.close();
}

/*
String["Result", "Exit status"]
*/
private String[] executeCommand(String stringCommand) throws IOException {
String[] response = new String[2];
final Command cmd = session.exec(stringCommand);
response[0] = IOUtils.readFully(cmd.getInputStream()).toString();
cmd.join(5, TimeUnit.SECONDS);
response[1] = cmd.getExitStatus().toString();

return response;
}

public String[] sendCommand(String cmd, String password) throws IOException {
this.connect();
try {
if (password.isEmpty()) {
this.logIn();
} else {
this.logIn(password);
}
this.startSession();
try {
return this.executeCommand(cmd);
} finally {
this.stopSession();
}
} finally {
this.disconnect();
}
}

public void initializeNode(String password) throws IOException {
// TODO: Read from resources/cp.id_rsa.pub
this.sendCommand(
"echo \"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDYCj4uihLqTI2c+A++p0tXwWCnIh3F8m2OD7h4OtJdoF8Q4Lz3/Ziq0X+BuZ2QRmVXeJkBQMT/z8E1iOktSRGYgZrVqGDdOsAiu8g6PTbnE3BSsqa5pUJ4mdZ6xc5l0xRrGb05TN8qw/OtYbcnC0E7ya+sM1JXJBG5Xosz+QrRanTJZrtBXjjWD82yJAuvypX4g3tbl156ZZKN8PIYRVFEMvzxwz36kKLfCagfgFFfDnG+38rLPqDbKTvx5NspSupdmis2I8tg5FfKTxX8RygrTEzjPoxRVLGSoYiYEDw6V9a3COE9sxjXyGT38fqFQUqIPGNmbBFYY7IYg82IFWhf ControlPanel\" >> ~/.ssh/authorized_keys",
password);
}

/*
public static void main(String[] args)
throws IOException, Exception {
String res = "";
final SSHClient ssh = new SSHClient();
ssh.addHostKeyVerifier("a6:90:99:9c:c5:15:d8:07:b5:fa:c5:79:77:93:9b:b6");

ssh.connect("192.168.1.169");
try {
//ssh.authPassword("root", "");
File file = new File("src/main/resources/cp.pem");
ssh.authPublickey("root", file.getAbsolutePath());
final Session session = ssh.startSession();
try {
final Command cmd = session.exec("uname -a");
res += IOUtils.readFully(cmd.getInputStream()).toString();
cmd.join(5, TimeUnit.SECONDS);
res += "\n** exit status: " + cmd.getExitStatus();
} finally {
session.close();
}
} finally {
ssh.disconnect();
}


System.out.println(res);
}*/

/*
public int connectToNode(Node node) throws Exception {
//ssh.addHostKeyVerifier(node.getSshId());
ssh.connect(node.getInetAddress());
ssh.authPublickey("root");

Session session = ssh.startSession();
sessions.add(session);

// It's possible to just get size of the array, but that might result race conditions
// Giving away Session is a bad idea, as that brakes OOP principles
return sessions.lastIndexOf(session);
}
*/

}
48 changes: 39 additions & 9 deletions src/main/java/com/sergeev/controlpanel/utils/Utils.java
Original file line number Diff line number Diff line change
@@ -1,19 +1,10 @@
package com.sergeev.controlpanel.utils;

import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.sergeev.controlpanel.controller.MainController;
import com.sergeev.controlpanel.model.AbstractModel;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.slf4j.Logger;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;

import java.util.*;

/**
* Created by dmitry-sergeev on 22.09.15.
*/
Expand All @@ -26,5 +17,44 @@ public static ResponseEntity status(int status){
jsonObject.addProperty("status", HttpStatus.valueOf(status).name());
return new ResponseEntity<>(jsonObject.toString(), HttpStatus.valueOf(status));
}
/*
public static KeyPair readKeypair(final InputStream is, final char[] password) throws IOException {
PasswordFinder passwordFinder = password != null ? new StaticPasswordFinder(password) : null;

KeyPair kp = null;
try {
// read the stream as a PEM encoded
try {

final PemReader pem = new PemReader(new InputStreamReader(is), passwordFinder);
try {
// Skip over entries in the file which are not KeyPairs
do {
final Object o = pem.readObject();

if (o == null)
break; // at end of file
else if (o instanceof KeyPair)
kp = (KeyPair) o;
} while (kp == null);
}
finally {
pem.close();
}
}
catch (EncryptionException e) {
throw new IOException("Error reading PEM stream: " + e.getMessage(), e);
}
}
finally {
is.close();
}

// Cast the return to a KeyPair (or, if there is no [valid] return, throw an exception)
if (kp != null)
return kp;
else
throw new IOException("Stream " + is + " did not contain a PKCS8 KeyPair");
}
*/
}
Binary file added src/main/resources/cp.der
Binary file not shown.
1 change: 1 addition & 0 deletions src/main/resources/cp.id_rsa.pub
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDYCj4uihLqTI2c+A++p0tXwWCnIh3F8m2OD7h4OtJdoF8Q4Lz3/Ziq0X+BuZ2QRmVXeJkBQMT/z8E1iOktSRGYgZrVqGDdOsAiu8g6PTbnE3BSsqa5pUJ4mdZ6xc5l0xRrGb05TN8qw/OtYbcnC0E7ya+sM1JXJBG5Xosz+QrRanTJZrtBXjjWD82yJAuvypX4g3tbl156ZZKN8PIYRVFEMvzxwz36kKLfCagfgFFfDnG+38rLPqDbKTvx5NspSupdmis2I8tg5FfKTxX8RygrTEzjPoxRVLGSoYiYEDw6V9a3COE9sxjXyGT38fqFQUqIPGNmbBFYY7IYg82IFWhf ControlPanel
27 changes: 27 additions & 0 deletions src/main/resources/cp.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA2Ao+LooS6kyNnPgPvqdLV8FgpyIdxfJtjg+4eDrSXaBfEOC8
9/2YqtF/gbmdkEZlV3iZAUDE/8/BNYjpLUkRmIGa1ahg3TrAIrvIOj025xNwUrKm
uaVCeJnWesXOZdMUaxm9OUzfKsPzrWG3JwtBO8mvrDNSVyQRuV6LM/kK0Wp0yWa7
QV441g/NsiQLr8qV+IN7W5deemWSjfDyGEVRRDL88cM9+pCi3wmoH4BRXw5xvt/K
yz6g2yk78eTbKUrqXZorNiPLYORXyk8V/EcoK0xM4z6MUVSxkqGImBA8OlfWtwjh
PbMY18hk9/H6hUFKiDxjZmwRWGOyGIPNiBVoXwIDAQABAoIBACbtiZDXPltLmgTb
yfJ/sJrKdIEJK7Y8XbNIb+PyLW/Dcv3WkRZacsTs5P3aFWMm3CHr0B4irpytsdHU
rreDQBFr4Rt4sKOMb4ySq5ya5Sa0IPw1xscS2SxkA/qxY+SDKV23EJqfmGLbVjA6
uEbnx0RfrjDoOoELNcpiF9Ewodtj74ootNEU0fROrmgDFi/yEmSJSQqvghrOi5yZ
K4w9Nq43JQM/ejhR8TiTnhmYpWfehlmSOL6uf1NDEhlE+6WOWzUm4cevlCn3EsTO
CIFRBOXJ8m9ZUdf44yQoH/DsvurLYoppBwmbgPLlsu0fPEMvbqTjPJt1dBFb1bD7
wQbneRkCgYEA8Q4gYuezCgu2x4Ci5+LJf+3uXMBjqcl88btcRY73VgtpT2eoBjyk
66smpiI+MNPK43OIstHXrC+9qK8GqXR6ck/sLACOHgosXnf8L4o7S4tq/F9ciWhu
OIlMfZNHFejd927x6+ngluteIZw9fPNlAGDNileNRboc9sZJaPFztOsCgYEA5W8X
dI72RqJFtwfT8mqv6jdVansxWPD51O8t5MLdqtnMA6MzAq12nnTWs5LubUY4QbPW
2/LqQvSZDHUo9vfHXoFag9NJgKXW77h/kpX/2Ovz8/xEql5yQKZocW0hbW7uMO1E
QaSrwZWOtVNKUrljBkWnvi75g27uzZma+EpmTV0CgYAvgNwrAYQL38EWUahI0C1r
U4UcrCE3zWgc7xJA9uqQ/1CygDfhesP5WVIVfTwKPUKHTjZLHwVEfmf+vPcwH68d
pdhh134qN1EFENoWuEP1IDVmJJjEz1qhM5VqTcK9c5WCdE+icQV8WEfFkdegLwrh
ZzI6KATED+gzTWIcFzD5HwKBgQDk7u7mnWhcnrsVoTf5oj8aZFBUycw5xWpk8KxI
obDyNBUAZC4YM+Iyxr8dvDUw0Gp+FOcF3eOnH84/wgA4PpGvWT9qXr/vIIvR87VI
HWiHmRl5kXUq0scKf4Gj/JLoUVJXe8kp/xhrN8KIaC23Ucjfj02L1e+fGGgsu2MI
8aQW+QKBgDC+1nGJjfaph469DqPvormRFwFLrfy7jpnHAdHLOYhAj0+/sYPwYenE
vINtmtq8OQXOrE/hMO92b+dUDtP17O3n4yFWSKzYIMKDC4Gaq4Q6HgsfP2XimQUb
v0EkqviZ/G5WK4iYz6mWxdJG+o+365z4CO3BIAP2vpPa22t444KT
-----END RSA PRIVATE KEY-----