blob: ab44854a5cf5acf4858bd4f808e9f583fea36272 [file] [log] [blame]
/*
* Copyright 2014 gitblit.com.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
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) {
throw new RuntimeException(e);
}
}
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;
}
}