1   /*
2    * Copyright 2017 LINE Corporation
3    *
4    * LINE Corporation licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   https://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
14   * under the License.
15   */
16  
17  package com.linecorp.centraldogma.server.internal.mirror.credential;
18  
19  import static com.linecorp.centraldogma.server.CentralDogmaConfig.convertValue;
20  import static com.linecorp.centraldogma.server.internal.mirror.credential.MirrorCredentialUtil.requireNonEmpty;
21  
22  import java.util.List;
23  import java.util.Objects;
24  import java.util.regex.Pattern;
25  
26  import javax.annotation.Nullable;
27  
28  import org.slf4j.Logger;
29  import org.slf4j.LoggerFactory;
30  
31  import com.fasterxml.jackson.annotation.JsonCreator;
32  import com.fasterxml.jackson.annotation.JsonProperty;
33  import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
34  import com.google.common.base.CharMatcher;
35  import com.google.common.base.MoreObjects.ToStringHelper;
36  import com.google.common.base.Splitter;
37  import com.google.common.collect.ImmutableList;
38  
39  public final class PublicKeyMirrorCredential extends AbstractMirrorCredential {
40  
41      private static final Logger logger = LoggerFactory.getLogger(PublicKeyMirrorCredential.class);
42  
43      private static final Splitter NEWLINE_SPLITTER = Splitter.on(CharMatcher.anyOf("\n\r"))
44                                                               .omitEmptyStrings()
45                                                               .trimResults();
46  
47      private static final int PUBLIC_KEY_PREVIEW_LEN = 40;
48  
49      private final String username;
50      private final String publicKey;
51      private final String privateKey;
52      @Nullable
53      private final String passphrase;
54  
55      @JsonCreator
56      public PublicKeyMirrorCredential(@JsonProperty("id") @Nullable String id,
57                                       @JsonProperty("hostnamePatterns") @Nullable
58                                       @JsonDeserialize(contentAs = Pattern.class)
59                                       Iterable<Pattern> hostnamePatterns,
60                                       @JsonProperty("username") String username,
61                                       @JsonProperty("publicKey") String publicKey,
62                                       @JsonProperty("privateKey") String privateKey,
63                                       @JsonProperty("passphrase") @Nullable String passphrase) {
64  
65          super(id, hostnamePatterns);
66  
67          this.username = requireNonEmpty(username, "username");
68          this.publicKey = requireNonEmpty(publicKey, "publicKey");
69          this.privateKey = requireNonEmpty(privateKey, "privateKey");
70          this.passphrase = passphrase;
71      }
72  
73      public String username() {
74          return username;
75      }
76  
77      public String publicKey() {
78          return publicKey;
79      }
80  
81      public List<String> privateKey() {
82          String converted;
83          try {
84              converted = convertValue(privateKey, "credentials.privateKey");
85          } catch (Throwable t) {
86              // Just use it as is for backward compatibility.
87              logger.debug("Failed to convert the key of the credential. username: {}, id: {}",
88                           username, id(), t);
89              converted = privateKey;
90          }
91          assert converted != null;
92          // privateKey is converted into a list of Strings that will be used as an input of
93          // KeyPairResourceLoader.loadKeyPairs(...)
94          return ImmutableList.copyOf(NEWLINE_SPLITTER.splitToList(converted));
95      }
96  
97      @Nullable
98      public String passphrase() {
99          try {
100             return convertValue(passphrase, "credentials.passphrase");
101         } catch (Throwable t) {
102             // The passphrase probably has `:` without prefix. Just return it as is for backward compatibility.
103             logger.debug("Failed to convert the passphrase of the credential. username: {}, id: {}",
104                          username, id(), t);
105             return passphrase;
106         }
107     }
108 
109     @Override
110     public boolean equals(Object o) {
111         if (this == o) {
112             return true;
113         }
114 
115         if (!(o instanceof PublicKeyMirrorCredential)) {
116             return false;
117         }
118 
119         if (!super.equals(o)) {
120             return false;
121         }
122 
123         final PublicKeyMirrorCredential that = (PublicKeyMirrorCredential) o;
124 
125         return username.equals(that.username) &&
126                Objects.equals(publicKey, that.publicKey) &&
127                Objects.equals(privateKey, that.privateKey) &&
128                Objects.equals(passphrase, that.passphrase);
129     }
130 
131     @Override
132     public int hashCode() {
133         return Objects.hash(super.hashCode(), username, publicKey, privateKey, passphrase);
134     }
135 
136     @Override
137     void addProperties(ToStringHelper helper) {
138         helper.add("username", username)
139               .add("publicKey", publicKeyPreview(publicKey));
140     }
141 
142     public static String publicKeyPreview(String publicKey) {
143         if (publicKey.length() > PUBLIC_KEY_PREVIEW_LEN) {
144             return publicKey.substring(0, PUBLIC_KEY_PREVIEW_LEN) + "..";
145         }
146         return publicKey;
147     }
148 }