summaryrefslogtreecommitdiffstats
path: root/src/main/java/com/gitblit/transport/ssh/SshKey.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/gitblit/transport/ssh/SshKey.java')
-rw-r--r--src/main/java/com/gitblit/transport/ssh/SshKey.java212
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;
+ }
+}