| /* |
| * 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; |
| } |
| } |