diff options
Diffstat (limited to 'src/main/java/com/gitblit/transport/ssh/SshKey.java')
-rw-r--r-- | src/main/java/com/gitblit/transport/ssh/SshKey.java | 212 |
1 files changed, 212 insertions, 0 deletions
diff --git a/src/main/java/com/gitblit/transport/ssh/SshKey.java b/src/main/java/com/gitblit/transport/ssh/SshKey.java new file mode 100644 index 00000000..6a20d7dd --- /dev/null +++ b/src/main/java/com/gitblit/transport/ssh/SshKey.java @@ -0,0 +1,212 @@ +package com.gitblit.transport.ssh; + +import java.io.Serializable; +import java.security.PublicKey; +import java.util.Arrays; +import java.util.List; + +import org.apache.commons.codec.binary.Base64; +import org.apache.sshd.common.SshException; +import org.apache.sshd.common.util.Buffer; +import org.eclipse.jgit.lib.Constants; + +import com.gitblit.Constants.AccessPermission; +import com.gitblit.utils.StringUtils; + +/** + * Class that encapsulates a public SSH key and it's metadata. + * + * @author James Moger + * + */ +public class SshKey implements Serializable { + + private static final long serialVersionUID = 1L; + + private String rawData; + + private PublicKey publicKey; + + private String comment; + + private String fingerprint; + + private String toString; + + private AccessPermission permission; + + public SshKey(String data) { + this.rawData = data; + this.permission = AccessPermission.PUSH; + } + + public SshKey(PublicKey key) { + this.publicKey = key; + this.comment = ""; + this.permission = AccessPermission.PUSH; + } + + public PublicKey getPublicKey() { + if (publicKey == null && rawData != null) { + // instantiate the public key from the raw key data + final String[] parts = rawData.split(" ", 3); + if (comment == null && parts.length == 3) { + comment = parts[2]; + } + final byte[] bin = Base64.decodeBase64(Constants.encodeASCII(parts[1])); + try { + publicKey = new Buffer(bin).getRawPublicKey(); + } catch (SshException e) { + e.printStackTrace(); + } + } + return publicKey; + } + + public String getAlgorithm() { + return getPublicKey().getAlgorithm(); + } + + public String getComment() { + if (comment == null && rawData != null) { + // extract comment from the raw data + final String[] parts = rawData.split(" ", 3); + if (parts.length == 3) { + comment = parts[2]; + } + } + return comment; + } + + public void setComment(String comment) { + this.comment = comment; + if (rawData != null) { + rawData = null; + } + } + + /** + * Returns true if this key may be used to clone or fetch. + * + * @return true if this key can be used to clone or fetch + */ + public boolean canClone() { + return permission.atLeast(AccessPermission.CLONE); + } + + /** + * Returns true if this key may be used to push changes. + * + * @return true if this key can be used to push changes + */ + public boolean canPush() { + return permission.atLeast(AccessPermission.PUSH); + } + + /** + * Returns the access permission for the key. + * + * @return the access permission for the key + */ + public AccessPermission getPermission() { + return permission; + } + + /** + * Control the access permission assigned to this key. + * + * @param value + */ + public void setPermission(AccessPermission value) throws IllegalArgumentException { + List<AccessPermission> permitted = Arrays.asList(AccessPermission.SSHPERMISSIONS); + if (!permitted.contains(value)) { + throw new IllegalArgumentException("Illegal SSH public key permission specified: " + value); + } + this.permission = value; + } + + public String getRawData() { + if (rawData == null && publicKey != null) { + // build the raw data manually from the public key + Buffer buf = new Buffer(); + + // 1: identify the algorithm + buf.putRawPublicKey(publicKey); + String alg = buf.getString(); + + // 2: encode the key + buf.clear(); + buf.putPublicKey(publicKey); + String b64 = Base64.encodeBase64String(buf.getBytes()); + + String c = getComment(); + rawData = alg + " " + b64 + (StringUtils.isEmpty(c) ? "" : (" " + c)); + } + return rawData; + } + + public String getFingerprint() { + if (fingerprint == null) { + StringBuilder sb = new StringBuilder(); + // append the key hash as colon-separated pairs + String hash; + if (rawData != null) { + final String[] parts = rawData.split(" ", 3); + final byte [] bin = Base64.decodeBase64(Constants.encodeASCII(parts[1])); + hash = StringUtils.getMD5(bin); + } else { + // TODO calculate the correct hash from a PublicKey instance + hash = StringUtils.getMD5(getPublicKey().getEncoded()); + } + for (int i = 0; i < hash.length(); i += 2) { + sb.append(hash.charAt(i)).append(hash.charAt(i + 1)).append(':'); + } + sb.setLength(sb.length() - 1); + fingerprint = sb.toString(); + } + return fingerprint; + } + + @Override + public boolean equals(Object o) { + if (o instanceof PublicKey) { + return getPublicKey().equals(o); + } else if (o instanceof SshKey) { + return getPublicKey().equals(((SshKey) o).getPublicKey()); + } + return false; + } + + @Override + public int hashCode() { + return getPublicKey().hashCode(); + } + + @Override + public String toString() { + if (toString == null) { + StringBuilder sb = new StringBuilder(); + // TODO append the keysize + int keySize = 0; + if (keySize > 0) { + sb.append(keySize).append(' '); + } + // append fingerprint + sb.append(' '); + sb.append(getFingerprint()); + // append the comment + String c = getComment(); + if (!StringUtils.isEmpty(c)) { + sb.append(' '); + sb.append(c); + } + // append algorithm + String alg = getAlgorithm(); + if (!StringUtils.isEmpty(alg)) { + sb.append(" (").append(alg).append(")"); + } + toString = sb.toString(); + } + return toString; + } +} |