1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.linecorp.centraldogma.server.metadata;
18
19 import static com.google.common.base.Preconditions.checkArgument;
20 import static java.util.Objects.requireNonNull;
21
22 import java.util.Map;
23 import java.util.function.Function;
24 import java.util.stream.Collectors;
25
26 import javax.annotation.Nullable;
27
28 import com.fasterxml.jackson.annotation.JsonCreator;
29 import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
30 import com.fasterxml.jackson.annotation.JsonInclude;
31 import com.fasterxml.jackson.annotation.JsonInclude.Include;
32 import com.fasterxml.jackson.annotation.JsonProperty;
33 import com.google.common.base.MoreObjects;
34 import com.google.common.collect.ImmutableMap;
35
36 import com.linecorp.centraldogma.server.internal.admin.service.TokenNotFoundException;
37
38
39
40
41 @JsonIgnoreProperties(ignoreUnknown = true)
42 @JsonInclude(Include.NON_NULL)
43 public final class Tokens {
44
45 static final String SECRET_PREFIX = "appToken-";
46
47
48
49
50 private final Map<String, Token> appIds;
51
52
53
54
55 private final Map<String, String> secrets;
56
57
58
59
60 public Tokens() {
61 this(ImmutableMap.of(), ImmutableMap.of());
62 }
63
64
65
66
67 @JsonCreator
68 public Tokens(@JsonProperty("appIds") Map<String, Token> appIds,
69 @JsonProperty("secrets") Map<String, String> secrets) {
70 this.appIds = requireNonNull(appIds, "appIds");
71 this.secrets = requireNonNull(secrets, "secrets");
72 }
73
74
75
76
77 @JsonProperty
78 public Map<String, Token> appIds() {
79 return appIds;
80 }
81
82
83
84
85 @JsonProperty
86 public Map<String, String> secrets() {
87 return secrets;
88 }
89
90
91
92
93 public Token get(String appId) {
94 final Token token = getOrDefault(appId, null);
95 if (token != null) {
96 return token;
97 }
98 throw new TokenNotFoundException("Application ID not found: " + appId);
99 }
100
101
102
103
104
105 @Nullable
106 public Token getOrDefault(String appId, @Nullable Token defaultValue) {
107 requireNonNull(appId, "appId");
108 final Token token = appIds.get(appId);
109 if (token != null) {
110 return token;
111 }
112 return defaultValue;
113 }
114
115
116
117
118 public Token findBySecret(String secret) {
119 final Token token = findBySecretOrDefault(secret, null);
120 if (token != null) {
121 return token;
122 }
123 throw new TokenNotFoundException("Secret not found: " + secret);
124 }
125
126
127
128
129
130 @Nullable
131 public Token findBySecretOrDefault(String secret, @Nullable Token defaultValue) {
132 requireNonNull(secret, "secret");
133 if (!secret.startsWith(SECRET_PREFIX)) {
134 return defaultValue;
135 }
136 final String appId = secrets.get(secret);
137 if (appId != null) {
138 return getOrDefault(appId, defaultValue);
139 }
140 return defaultValue;
141 }
142
143
144
145
146 public Tokens withoutSecret() {
147 final Map<String, Token> appIds =
148 appIds().values().stream()
149 .map(Token::withoutSecret)
150 .collect(Collectors.toMap(Token::id, Function.identity()));
151 return new Tokens(appIds, ImmutableMap.of());
152 }
153
154 @Override
155 public String toString() {
156 return MoreObjects.toStringHelper(this)
157 .add("appIds", appIds())
158 .add("secrets", secrets())
159 .toString();
160 }
161
162
163
164
165 public static boolean isValidSecret(@Nullable String secret) {
166 return secret != null && secret.startsWith(SECRET_PREFIX);
167 }
168
169
170
171
172 public static void validateSecret(String secret) {
173 checkArgument(isValidSecret(secret),
174 "invalid secret: " + secret +
175 " (secret must start with '" + SECRET_PREFIX + "')");
176 }
177 }