You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

SshKey.java 5.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. /*
  2. * Copyright 2014 gitblit.com.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. package com.gitblit.transport.ssh;
  17. import java.io.Serializable;
  18. import java.security.PublicKey;
  19. import java.util.Arrays;
  20. import java.util.List;
  21. import org.apache.commons.codec.binary.Base64;
  22. import org.apache.sshd.common.SshException;
  23. import org.apache.sshd.common.util.Buffer;
  24. import org.eclipse.jgit.lib.Constants;
  25. import com.gitblit.Constants.AccessPermission;
  26. import com.gitblit.utils.StringUtils;
  27. /**
  28. * Class that encapsulates a public SSH key and it's metadata.
  29. *
  30. * @author James Moger
  31. *
  32. */
  33. public class SshKey implements Serializable {
  34. private static final long serialVersionUID = 1L;
  35. private String rawData;
  36. private PublicKey publicKey;
  37. private String comment;
  38. private String fingerprint;
  39. private String toString;
  40. private AccessPermission permission;
  41. public SshKey(String data) {
  42. this.rawData = data;
  43. this.permission = AccessPermission.PUSH;
  44. }
  45. public SshKey(PublicKey key) {
  46. this.publicKey = key;
  47. this.comment = "";
  48. this.permission = AccessPermission.PUSH;
  49. }
  50. public PublicKey getPublicKey() {
  51. if (publicKey == null && rawData != null) {
  52. // instantiate the public key from the raw key data
  53. final String[] parts = rawData.split(" ", 3);
  54. if (comment == null && parts.length == 3) {
  55. comment = parts[2];
  56. }
  57. final byte[] bin = Base64.decodeBase64(Constants.encodeASCII(parts[1]));
  58. try {
  59. publicKey = new Buffer(bin).getRawPublicKey();
  60. } catch (SshException e) {
  61. throw new RuntimeException(e);
  62. }
  63. }
  64. return publicKey;
  65. }
  66. public String getAlgorithm() {
  67. return getPublicKey().getAlgorithm();
  68. }
  69. public String getComment() {
  70. if (comment == null && rawData != null) {
  71. // extract comment from the raw data
  72. final String[] parts = rawData.split(" ", 3);
  73. if (parts.length == 3) {
  74. comment = parts[2];
  75. }
  76. }
  77. return comment;
  78. }
  79. public void setComment(String comment) {
  80. this.comment = comment;
  81. if (rawData != null) {
  82. rawData = null;
  83. }
  84. }
  85. /**
  86. * Returns true if this key may be used to clone or fetch.
  87. *
  88. * @return true if this key can be used to clone or fetch
  89. */
  90. public boolean canClone() {
  91. return permission.atLeast(AccessPermission.CLONE);
  92. }
  93. /**
  94. * Returns true if this key may be used to push changes.
  95. *
  96. * @return true if this key can be used to push changes
  97. */
  98. public boolean canPush() {
  99. return permission.atLeast(AccessPermission.PUSH);
  100. }
  101. /**
  102. * Returns the access permission for the key.
  103. *
  104. * @return the access permission for the key
  105. */
  106. public AccessPermission getPermission() {
  107. return permission;
  108. }
  109. /**
  110. * Control the access permission assigned to this key.
  111. *
  112. * @param value
  113. */
  114. public void setPermission(AccessPermission value) throws IllegalArgumentException {
  115. List<AccessPermission> permitted = Arrays.asList(AccessPermission.SSHPERMISSIONS);
  116. if (!permitted.contains(value)) {
  117. throw new IllegalArgumentException("Illegal SSH public key permission specified: " + value);
  118. }
  119. this.permission = value;
  120. }
  121. public String getRawData() {
  122. if (rawData == null && publicKey != null) {
  123. // build the raw data manually from the public key
  124. Buffer buf = new Buffer();
  125. // 1: identify the algorithm
  126. buf.putRawPublicKey(publicKey);
  127. String alg = buf.getString();
  128. // 2: encode the key
  129. buf.clear();
  130. buf.putPublicKey(publicKey);
  131. String b64 = Base64.encodeBase64String(buf.getBytes());
  132. String c = getComment();
  133. rawData = alg + " " + b64 + (StringUtils.isEmpty(c) ? "" : (" " + c));
  134. }
  135. return rawData;
  136. }
  137. public String getFingerprint() {
  138. if (fingerprint == null) {
  139. StringBuilder sb = new StringBuilder();
  140. // append the key hash as colon-separated pairs
  141. String hash;
  142. if (rawData != null) {
  143. final String[] parts = rawData.split(" ", 3);
  144. final byte [] bin = Base64.decodeBase64(Constants.encodeASCII(parts[1]));
  145. hash = StringUtils.getMD5(bin);
  146. } else {
  147. // TODO calculate the correct hash from a PublicKey instance
  148. hash = StringUtils.getMD5(getPublicKey().getEncoded());
  149. }
  150. for (int i = 0; i < hash.length(); i += 2) {
  151. sb.append(hash.charAt(i)).append(hash.charAt(i + 1)).append(':');
  152. }
  153. sb.setLength(sb.length() - 1);
  154. fingerprint = sb.toString();
  155. }
  156. return fingerprint;
  157. }
  158. @Override
  159. public boolean equals(Object o) {
  160. if (o instanceof PublicKey) {
  161. return getPublicKey().equals(o);
  162. } else if (o instanceof SshKey) {
  163. return getPublicKey().equals(((SshKey) o).getPublicKey());
  164. }
  165. return false;
  166. }
  167. @Override
  168. public int hashCode() {
  169. return getPublicKey().hashCode();
  170. }
  171. @Override
  172. public String toString() {
  173. if (toString == null) {
  174. StringBuilder sb = new StringBuilder();
  175. // TODO append the keysize
  176. int keySize = 0;
  177. if (keySize > 0) {
  178. sb.append(keySize).append(' ');
  179. }
  180. // append fingerprint
  181. sb.append(' ');
  182. sb.append(getFingerprint());
  183. // append the comment
  184. String c = getComment();
  185. if (!StringUtils.isEmpty(c)) {
  186. sb.append(' ');
  187. sb.append(c);
  188. }
  189. // append algorithm
  190. String alg = getAlgorithm();
  191. if (!StringUtils.isEmpty(alg)) {
  192. sb.append(" (").append(alg).append(")");
  193. }
  194. toString = sb.toString();
  195. }
  196. return toString;
  197. }
  198. }