Commit f95fd0c3 authored by michael.simon's avatar michael.simon
Browse files

change the ssh key decoder and management form

parent 082380d0
......@@ -10,8 +10,12 @@
******************************************************************************/
package edu.kit.scc.webreg.dao;
import java.util.List;
import edu.kit.scc.webreg.entity.SshPubKeyEntity;
public interface SshPubKeyDao extends BaseDao<SshPubKeyEntity, Long> {
List<SshPubKeyEntity> findByUser(Long userId);
}
......@@ -10,6 +10,8 @@
******************************************************************************/
package edu.kit.scc.webreg.dao.jpa;
import java.util.List;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Named;
......@@ -20,6 +22,13 @@ import edu.kit.scc.webreg.entity.SshPubKeyEntity;
@ApplicationScoped
public class JpaSshPubKeyDao extends JpaBaseDao<SshPubKeyEntity, Long> implements SshPubKeyDao {
@Override
@SuppressWarnings("unchecked")
public List<SshPubKeyEntity> findByUser(Long userId) {
return em.createQuery("select e from SshPubKeyEntity e where e.user.id = :userId")
.setParameter("userId", userId).getResultList();
}
@Override
public Class<SshPubKeyEntity> getEntityClass() {
return SshPubKeyEntity.class;
......
......@@ -25,7 +25,7 @@ public class SshPubKeyEntity extends AbstractBaseEntity {
@Column(name = "command", length = 1024)
private String command;
@Column(name = "from", length = 1024)
@Column(name = "ssh_from", length = 1024)
private String from;
@Column(name = "key_type", length = 32)
......@@ -45,14 +45,6 @@ public class SshPubKeyEntity extends AbstractBaseEntity {
this.user = user;
}
public SshPubKeyUsageType getKeyType() {
return usageType;
}
public void setKeyType(SshPubKeyUsageType usageType) {
this.usageType = usageType;
}
public String getName() {
return name;
}
......@@ -77,14 +69,6 @@ public class SshPubKeyEntity extends AbstractBaseEntity {
this.from = from;
}
public SshPubKeyUsageType getUsageType() {
return usageType;
}
public void setUsageType(SshPubKeyUsageType usageType) {
this.usageType = usageType;
}
public String getEncodedKey() {
return encodedKey;
}
......@@ -101,6 +85,18 @@ public class SshPubKeyEntity extends AbstractBaseEntity {
this.comment = comment;
}
public SshPubKeyUsageType getUsageType() {
return usageType;
}
public void setUsageType(SshPubKeyUsageType usageType) {
this.usageType = usageType;
}
public String getKeyType() {
return keyType;
}
public void setKeyType(String keyType) {
this.keyType = keyType;
}
......
......@@ -10,9 +10,13 @@
******************************************************************************/
package edu.kit.scc.webreg.service.ssh;
import java.util.List;
import edu.kit.scc.webreg.entity.SshPubKeyEntity;
import edu.kit.scc.webreg.service.BaseService;
public interface SshPubKeyService extends BaseService<SshPubKeyEntity, Long> {
List<SshPubKeyEntity> findByUser(Long userId);
}
......@@ -10,6 +10,8 @@
******************************************************************************/
package edu.kit.scc.webreg.service.ssh;
import java.util.List;
import javax.ejb.Stateless;
import javax.inject.Inject;
......@@ -26,6 +28,11 @@ public class SshPubKeyServiceImpl extends BaseServiceImpl<SshPubKeyEntity, Long>
@Inject
private SshPubKeyDao dao;
@Override
public List<SshPubKeyEntity> findByUser(Long userId) {
return dao.findByUser(userId);
}
@Override
protected BaseDao<SshPubKeyEntity, Long> getDao() {
return dao;
......
......@@ -20,16 +20,16 @@ import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.ECNamedCurveTable;
import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
import edu.kit.scc.webreg.entity.SshPubKeyEntity;
@ApplicationScoped
public class OpenSshKeyDecoder implements Serializable {
private static final long serialVersionUID = 1L;
public OpenSshPublicKey decode(String name, String opensshPublicKey) throws UnsupportedKeyTypeException {
public OpenSshPublicKey decode(SshPubKeyEntity pubKeyEntity) throws UnsupportedKeyTypeException {
OpenSshPublicKey key = new OpenSshPublicKey();
key.setName(name);
key.setValue(opensshPublicKey.trim());
key.setPubKeyEntity(pubKeyEntity);
return decode(key);
}
......@@ -39,6 +39,8 @@ public class OpenSshKeyDecoder implements Serializable {
try {
String type = decodeType(key);
key.getPubKeyEntity().setKeyType(type);
if (type.equals("ssh-rsa")) {
BigInteger e = decodeBigInt(key);
BigInteger m = decodeBigInt(key);
......@@ -71,7 +73,7 @@ public class OpenSshKeyDecoder implements Serializable {
}
private void getKeyBytes(OpenSshPublicKey key) throws UnsupportedKeyTypeException {
for (String part : key.getValue().split(" ")) {
for (String part : key.getPubKeyEntity().getEncodedKey().split(" ")) {
if (Base64.isBase64(part) && part.startsWith("AAAA")) {
key.setBaseDate(part);
key.setBytes(Base64.decodeBase64(part));
......
package edu.kit.scc.webreg.ssh;
import java.io.Serializable;
import java.math.BigInteger;
import java.security.AlgorithmParameters;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.spec.DSAPublicKeySpec;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.ECParameterSpec;
import java.security.spec.ECPoint;
import java.security.spec.ECPublicKeySpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.InvalidParameterSpecException;
import java.security.spec.RSAPublicKeySpec;
import javax.enterprise.context.ApplicationScoped;
import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.ECNamedCurveTable;
import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
@ApplicationScoped
public class OpenSshKeyDecoderOld implements Serializable {
private static final long serialVersionUID = 1L;
public OpenSshPublicKeyOld decode(String name, String opensshPublicKey) throws UnsupportedKeyTypeException {
OpenSshPublicKeyOld key = new OpenSshPublicKeyOld();
key.setName(name);
key.setValue(opensshPublicKey.trim());
return decode(key);
}
public OpenSshPublicKeyOld decode(OpenSshPublicKeyOld key) throws UnsupportedKeyTypeException {
getKeyBytes(key);
try {
String type = decodeType(key);
if (type.equals("ssh-rsa")) {
BigInteger e = decodeBigInt(key);
BigInteger m = decodeBigInt(key);
RSAPublicKeySpec spec = new RSAPublicKeySpec(m, e);
key.setPublicKey(KeyFactory.getInstance("RSA").generatePublic(spec));
} else if (type.equals("ssh-dss")) {
BigInteger p = decodeBigInt(key);
BigInteger q = decodeBigInt(key);
BigInteger g = decodeBigInt(key);
BigInteger y = decodeBigInt(key);
DSAPublicKeySpec spec = new DSAPublicKeySpec(y, p, q, g);
key.setPublicKey(KeyFactory.getInstance("DSA").generatePublic(spec));
} else if (type.startsWith("ecdsa-sha2-") &&
(type.endsWith("nistp256") || type.endsWith("nistp384") || type.endsWith("nistp521"))) {
// Based on RFC 5656, section 3.1 (https://tools.ietf.org/html/rfc5656#section-3.1)
String identifier = decodeType(key);
BigInteger q = decodeBigInt(key);
ECPoint ecPoint = getECPoint(q, identifier);
ECParameterSpec ecParameterSpec = getECParameterSpec(identifier);
ECPublicKeySpec spec = new ECPublicKeySpec(ecPoint, ecParameterSpec);
key.setPublicKey(KeyFactory.getInstance("EC").generatePublic(spec));
} else {
key.setDecoderResult("Unsupported key type");
}
return key;
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
key.setDecoderResult("Unable to decode public key");
return key;
}
}
private void getKeyBytes(OpenSshPublicKeyOld key) throws UnsupportedKeyTypeException {
for (String part : key.getValue().split(" ")) {
if (Base64.isBase64(part) && part.startsWith("AAAA")) {
key.setBaseDate(part);
key.setBytes(Base64.decodeBase64(part));
return;
}
}
throw new UnsupportedKeyTypeException("no Base64 part to decode");
}
private String decodeType(OpenSshPublicKeyOld key) {
int len = decodeInt(key);
String type = new String(key.getBytes(), key.getDecoderPos(), len);
key.increaseDecoderPos(len);
return type;
}
private int decodeInt(OpenSshPublicKeyOld key) {
byte[] bytes = key.getBytes();
int pos = key.getDecoderPos();
int header = ((bytes[pos] & 0xFF) << 24) | ((bytes[pos+1] & 0xFF) << 16)
| ((bytes[pos+2] & 0xFF) << 8) | (bytes[pos+3] & 0xFF);
key.increaseDecoderPos(4);
return header;
}
private BigInteger decodeBigInt(OpenSshPublicKeyOld key) {
int len = decodeInt(key);
byte[] bigIntBytes = new byte[len];
System.arraycopy(key.getBytes(), key.getDecoderPos(), bigIntBytes, 0, len);
key.increaseDecoderPos(len);
return new BigInteger(bigIntBytes);
}
ECPoint getECPoint(BigInteger q, String identifier) {
String name = identifier.replace("nist", "sec") + "r1";
ECNamedCurveParameterSpec ecSpec = ECNamedCurveTable.getParameterSpec(name);
org.bouncycastle.math.ec.ECPoint point = ecSpec.getCurve().decodePoint(q.toByteArray());
BigInteger x = point.getAffineXCoord().toBigInteger();
BigInteger y = point.getAffineYCoord().toBigInteger();
return new ECPoint(x, y);
}
ECParameterSpec getECParameterSpec(String identifier) throws UnsupportedKeyTypeException {
try {
// http://www.bouncycastle.org/wiki/pages/viewpage.action?pageId=362269#SupportedCurves(ECDSAandECGOST)-NIST(aliasesforSECcurves)
String name = identifier.replace("nist", "sec") + "r1";
AlgorithmParameters parameters = AlgorithmParameters.getInstance("EC");
parameters.init(new ECGenParameterSpec(name));
return parameters.getParameterSpec(ECParameterSpec.class);
} catch (InvalidParameterSpecException | NoSuchAlgorithmException e) {
throw new UnsupportedKeyTypeException("Unable to get parameter spec for identifier " + identifier, e);
}
}
}
......@@ -3,28 +3,22 @@ package edu.kit.scc.webreg.ssh;
import java.io.Serializable;
import java.security.PublicKey;
import com.fasterxml.jackson.annotation.JsonIgnore;
import edu.kit.scc.webreg.entity.SshPubKeyEntity;
public class OpenSshPublicKey implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private String value;
private SshPubKeyEntity pubKeyEntity;
@JsonIgnore
private byte[] bytes;
@JsonIgnore
private int decoderPos;
@JsonIgnore
private PublicKey publicKey;
@JsonIgnore
private String baseDate;
@JsonIgnore
private String decoderResult;
public OpenSshPublicKey() {
......@@ -76,19 +70,11 @@ public class OpenSshPublicKey implements Serializable {
this.decoderResult = decoderResult;
}
public String getName() {
return name;
public SshPubKeyEntity getPubKeyEntity() {
return pubKeyEntity;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
public void setPubKeyEntity(SshPubKeyEntity pubKeyEntity) {
this.pubKeyEntity = pubKeyEntity;
}
}
package edu.kit.scc.webreg.ssh;
import java.io.Serializable;
import java.security.PublicKey;
import com.fasterxml.jackson.annotation.JsonIgnore;
public class OpenSshPublicKeyOld implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private String value;
@JsonIgnore
private byte[] bytes;
@JsonIgnore
private int decoderPos;
@JsonIgnore
private PublicKey publicKey;
@JsonIgnore
private String baseDate;
@JsonIgnore
private String decoderResult;
public OpenSshPublicKeyOld() {
super();
decoderPos = 0;
}
public byte[] getBytes() {
return bytes;
}
public void setBytes(byte[] bytes) {
this.bytes = bytes;
}
public int getDecoderPos() {
return decoderPos;
}
public void setDecoderPos(int decoderPos) {
this.decoderPos = decoderPos;
}
public void increaseDecoderPos(int steps) {
this.decoderPos += steps;
}
public PublicKey getPublicKey() {
return publicKey;
}
public void setPublicKey(PublicKey publicKey) {
this.publicKey = publicKey;
}
public String getBaseDate() {
return baseDate;
}
public void setBaseDate(String baseDate) {
this.baseDate = baseDate;
}
public String getDecoderResult() {
return decoderResult;
}
public void setDecoderResult(String decoderResult) {
this.decoderResult = decoderResult;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
......@@ -10,7 +10,6 @@
******************************************************************************/
package edu.kit.scc.webreg.bean;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
......@@ -22,13 +21,10 @@ import javax.inject.Inject;
import org.slf4j.Logger;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import edu.kit.scc.webreg.entity.SshPubKeyEntity;
import edu.kit.scc.webreg.entity.UserEntity;
import edu.kit.scc.webreg.service.UserService;
import edu.kit.scc.webreg.service.ssh.SshPubKeyService;
import edu.kit.scc.webreg.session.SessionManager;
import edu.kit.scc.webreg.ssh.OpenSshKeyDecoder;
import edu.kit.scc.webreg.ssh.OpenSshPublicKey;
......@@ -57,6 +53,9 @@ public class UserSshKeyManagementBean implements Serializable {
@Inject
private FacesMessageGenerator messageGenerator;
@Inject
private SshPubKeyService sshPubKeyService;
private List<OpenSshPublicKey> keyList;
private String newKey;
......@@ -65,22 +64,15 @@ public class UserSshKeyManagementBean implements Serializable {
public void preRenderView(ComponentSystemEvent ev) {
if (user == null) {
user = userService.findByIdWithStore(sessionManager.getUserId());
keyList = new ArrayList<>();
if (user.getGenericStore().containsKey("ssh_key")) {
ObjectMapper om = new ObjectMapper();
try {
List<OpenSshPublicKey> tempKeyList = om.readValue(user.getGenericStore().get("ssh_key"),
new TypeReference<List<OpenSshPublicKey>>(){});
for (OpenSshPublicKey sshKey : tempKeyList) {
try {
keyList.add(keyDecoder.decode(sshKey));
} catch (UnsupportedKeyTypeException e) {
logger.warn("Unsupported key exception: ", e.getMessage());
}
}
} catch (IOException e) {
logger.warn("Could not read SSH keys from user: " + e.getMessage());
user = userService.findById(sessionManager.getUserId());
List<SshPubKeyEntity> sshPubKeyList = sshPubKeyService.findByUser(user.getId());
keyList = new ArrayList<>();
for (SshPubKeyEntity sshKey : sshPubKeyList) {
try {
keyList.add(keyDecoder.decode(sshKey));
} catch (UnsupportedKeyTypeException e) {
logger.warn("Unsupported key exception: ", e.getMessage());
messageGenerator.addResolvedErrorMessage("error_msg", "SSH Key not readable. Resetting keys.", false);
}
}
......@@ -89,30 +81,36 @@ public class UserSshKeyManagementBean implements Serializable {
public void deleteKey(String name) {
int removeIndex = -1;
SshPubKeyEntity removeEntity = null;
for (int i=0; i<keyList.size(); i++) {
if (keyList.get(i).getName().equals(name)) {
if (keyList.get(i).getPubKeyEntity().getName().equals(name)) {
removeIndex = i;
removeEntity = keyList.get(i).getPubKeyEntity();
break;
}
}
if (removeIndex != -1) {
keyList.remove(removeIndex);
keyList.remove(removeIndex);
sshPubKeyService.delete(removeEntity);
}
user.getGenericStore().put("ssh_key", buildSshKeyString());
user = userService.save(user);
messageGenerator.addResolvedInfoMessage("info", "ssh_key_deleted", false);
}
public void deployKey() {
OpenSshPublicKey key;
SshPubKeyEntity sshPubKeyEntity = sshPubKeyService.createNew();
sshPubKeyEntity.setName(newName);
sshPubKeyEntity.setEncodedKey(newKey);
sshPubKeyEntity.setUser(user);
try {
key = keyDecoder.decode(newName, newKey);
key = keyDecoder.decode(sshPubKeyEntity);
keyList.add(key);
user.getGenericStore().put("ssh_key", buildSshKeyString());
user = userService.save(user);
sshPubKeyEntity = sshPubKeyService.save(sshPubKeyEntity);
newKey = "";
newName = "";
if (key.getPublicKey() == null) {
......@@ -126,16 +124,16 @@ public class UserSshKeyManagementBean implements Serializable {
messageGenerator.addResolvedErrorMessage("error_msg", e.toString(), false);
}
}
/*
private String buildSshKeyString() {
ObjectMapper om = new ObjectMapper();
ArrayNode array = om.createArrayNode();
for (OpenSshPublicKey sshKey : keyList) {
for (OpenSshPublicKeyOld sshKey : keyList) {
array.add(om.convertValue(sshKey, JsonNode.class));
}
return array.toString();
}
*/
public UserEntity getUser() {
return user;
}
......
/*******************************************************************************
* Copyright (c) 2014 Michael Simon.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at