選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

SshKey.java 5.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  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.Buffer;
  24. import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
  25. import org.eclipse.jgit.lib.Constants;
  26. import com.gitblit.Constants.AccessPermission;
  27. import com.gitblit.utils.StringUtils;
  28. import com.google.common.base.Joiner;
  29. /**
  30. * Class that encapsulates a public SSH key and it's metadata.
  31. *
  32. * @author James Moger
  33. *
  34. */
  35. public class SshKey implements Serializable {
  36. private static final long serialVersionUID = 1L;
  37. private String rawData;
  38. private PublicKey publicKey;
  39. private String comment;
  40. private String fingerprint;
  41. private String toString;
  42. private AccessPermission permission;
  43. public SshKey(String data) {
  44. // strip out line breaks (issue-571)
  45. this.rawData = Joiner.on("").join(data.replace("\r\n", "\n").split("\n"));
  46. this.permission = AccessPermission.PUSH;
  47. }
  48. public SshKey(PublicKey key) {
  49. this.publicKey = key;
  50. this.comment = "";
  51. this.permission = AccessPermission.PUSH;
  52. }
  53. public PublicKey getPublicKey() {
  54. if (publicKey == null && rawData != null) {
  55. // instantiate the public key from the raw key data
  56. final String[] parts = rawData.split(" ", 3);
  57. if (comment == null && parts.length == 3) {
  58. comment = parts[2];
  59. }
  60. final byte[] bin = Base64.decodeBase64(Constants.encodeASCII(parts[1]));
  61. try {
  62. publicKey = new ByteArrayBuffer(bin).getRawPublicKey();
  63. } catch (SshException e) {
  64. throw new RuntimeException(e);
  65. }
  66. }
  67. return publicKey;
  68. }
  69. public String getAlgorithm() {
  70. return getPublicKey().getAlgorithm();
  71. }
  72. public String getComment() {
  73. if (comment == null && rawData != null) {
  74. // extract comment from the raw data
  75. final String[] parts = rawData.split(" ", 3);
  76. if (parts.length == 3) {
  77. comment = parts[2];
  78. }
  79. }
  80. return comment;
  81. }
  82. public void setComment(String comment) {
  83. this.comment = comment;
  84. if (rawData != null) {
  85. rawData = null;
  86. }
  87. }
  88. /**
  89. * Returns true if this key may be used to clone or fetch.
  90. *
  91. * @return true if this key can be used to clone or fetch
  92. */
  93. public boolean canClone() {
  94. return permission.atLeast(AccessPermission.CLONE);
  95. }
  96. /**
  97. * Returns true if this key may be used to push changes.
  98. *
  99. * @return true if this key can be used to push changes
  100. */
  101. public boolean canPush() {
  102. return permission.atLeast(AccessPermission.PUSH);
  103. }
  104. /**
  105. * Returns the access permission for the key.
  106. *
  107. * @return the access permission for the key
  108. */
  109. public AccessPermission getPermission() {
  110. return permission;
  111. }
  112. /**
  113. * Control the access permission assigned to this key.
  114. *
  115. * @param value
  116. */
  117. public void setPermission(AccessPermission value) throws IllegalArgumentException {
  118. List<AccessPermission> permitted = Arrays.asList(AccessPermission.SSHPERMISSIONS);
  119. if (!permitted.contains(value)) {
  120. throw new IllegalArgumentException("Illegal SSH public key permission specified: " + value);
  121. }
  122. this.permission = value;
  123. }
  124. public String getRawData() {
  125. if (rawData == null && publicKey != null) {
  126. // build the raw data manually from the public key
  127. Buffer buf = new ByteArrayBuffer();
  128. // 1: identify the algorithm
  129. buf.putRawPublicKey(publicKey);
  130. String alg = buf.getString();
  131. // 2: encode the key
  132. buf.clear();
  133. buf.putPublicKey(publicKey);
  134. String b64 = Base64.encodeBase64String(buf.getBytes());
  135. String c = getComment();
  136. rawData = alg + " " + b64 + (StringUtils.isEmpty(c) ? "" : (" " + c));
  137. }
  138. return rawData;
  139. }
  140. public String getFingerprint() {
  141. if (fingerprint == null) {
  142. StringBuilder sb = new StringBuilder();
  143. // append the key hash as colon-separated pairs
  144. String hash;
  145. if (rawData != null) {
  146. final String[] parts = rawData.split(" ", 3);
  147. final byte [] bin = Base64.decodeBase64(Constants.encodeASCII(parts[1]));
  148. hash = StringUtils.getMD5(bin);
  149. } else {
  150. // TODO calculate the correct hash from a PublicKey instance
  151. hash = StringUtils.getMD5(getPublicKey().getEncoded());
  152. }
  153. for (int i = 0; i < hash.length(); i += 2) {
  154. sb.append(hash.charAt(i)).append(hash.charAt(i + 1)).append(':');
  155. }
  156. sb.setLength(sb.length() - 1);
  157. fingerprint = sb.toString();
  158. }
  159. return fingerprint;
  160. }
  161. @Override
  162. public boolean equals(Object o) {
  163. if (o instanceof PublicKey) {
  164. return getPublicKey().equals(o);
  165. } else if (o instanceof SshKey) {
  166. return getPublicKey().equals(((SshKey) o).getPublicKey());
  167. }
  168. return false;
  169. }
  170. @Override
  171. public int hashCode() {
  172. return getPublicKey().hashCode();
  173. }
  174. @Override
  175. public String toString() {
  176. if (toString == null) {
  177. StringBuilder sb = new StringBuilder();
  178. // TODO append the keysize
  179. int keySize = 0;
  180. if (keySize > 0) {
  181. sb.append(keySize).append(' ');
  182. }
  183. // append fingerprint
  184. sb.append(' ');
  185. sb.append(getFingerprint());
  186. // append the comment
  187. String c = getComment();
  188. if (!StringUtils.isEmpty(c)) {
  189. sb.append(' ');
  190. sb.append(c);
  191. }
  192. // append algorithm
  193. String alg = getAlgorithm();
  194. if (!StringUtils.isEmpty(alg)) {
  195. sb.append(" (").append(alg).append(")");
  196. }
  197. toString = sb.toString();
  198. }
  199. return toString;
  200. }
  201. }