-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Expand file tree
/
Copy pathAuthServiceClient.java
More file actions
285 lines (251 loc) · 12.5 KB
/
AuthServiceClient.java
File metadata and controls
285 lines (251 loc) · 12.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
package client;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Objects;
import javax.annotation.Nonnull;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import play.mvc.Http;
import com.datahub.authentication.Authentication;
/**
* This class is responsible for coordinating authentication with the backend Metadata Service.
*/
@Slf4j
public class AuthServiceClient {
private static final String GENERATE_SESSION_TOKEN_ENDPOINT = "auth/generateSessionTokenForUser";
private static final String SIGN_UP_ENDPOINT = "auth/signUp";
private static final String RESET_NATIVE_USER_CREDENTIALS_ENDPOINT = "auth/resetNativeUserCredentials";
private static final String VERIFY_NATIVE_USER_CREDENTIALS_ENDPOINT = "auth/verifyNativeUserCredentials";
private static final String ACCESS_TOKEN_FIELD = "accessToken";
private static final String USER_ID_FIELD = "userId";
private static final String USER_URN_FIELD = "userUrn";
private static final String FULL_NAME_FIELD = "fullName";
private static final String EMAIL_FIELD = "email";
private static final String TITLE_FIELD = "title";
private static final String PASSWORD_FIELD = "password";
private static final String INVITE_TOKEN_FIELD = "inviteToken";
private static final String RESET_TOKEN_FIELD = "resetToken";
private static final String IS_NATIVE_USER_CREATED_FIELD = "isNativeUserCreated";
private static final String ARE_NATIVE_USER_CREDENTIALS_RESET_FIELD = "areNativeUserCredentialsReset";
private static final String DOES_PASSWORD_MATCH_FIELD = "doesPasswordMatch";
private final String metadataServiceHost;
private final Integer metadataServicePort;
private final Boolean metadataServiceUseSsl;
private final Authentication systemAuthentication;
public AuthServiceClient(@Nonnull final String metadataServiceHost, @Nonnull final Integer metadataServicePort,
@Nonnull final Boolean useSsl, @Nonnull final Authentication systemAuthentication) {
this.metadataServiceHost = Objects.requireNonNull(metadataServiceHost);
this.metadataServicePort = Objects.requireNonNull(metadataServicePort);
this.metadataServiceUseSsl = Objects.requireNonNull(useSsl);
this.systemAuthentication = Objects.requireNonNull(systemAuthentication);
}
/**
* Call the Auth Service to generate a session token for a particular user with a unique actor id, or throws an exception if generation fails.
*
* Notice that the "userId" parameter should NOT be of type "urn", but rather the unique id of an Actor of type
* USER.
*/
@Nonnull
public String generateSessionTokenForUser(@Nonnull final String userId) {
Objects.requireNonNull(userId, "userId must not be null");
CloseableHttpClient httpClient = HttpClients.createDefault();
try {
final String protocol = this.metadataServiceUseSsl ? "https" : "http";
final HttpPost request = new HttpPost(String.format("%s://%s:%s/%s", protocol, this.metadataServiceHost,
this.metadataServicePort, GENERATE_SESSION_TOKEN_ENDPOINT));
// Build JSON request to generate a token on behalf of a user.
String json = String.format("{ \"%s\":\"%s\" }", USER_ID_FIELD, userId);
request.setEntity(new StringEntity(json));
// Add authorization header with DataHub frontend system id and secret.
request.addHeader(Http.HeaderNames.AUTHORIZATION, this.systemAuthentication.getCredentials());
CloseableHttpResponse response = httpClient.execute(request);
final HttpEntity entity = response.getEntity();
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK && entity != null) {
// Successfully generated a token for the User
final String jsonStr = EntityUtils.toString(entity);
return getAccessTokenFromJson(jsonStr);
} else {
throw new RuntimeException(
String.format("Bad response from the Metadata Service: %s %s",
response.getStatusLine().toString(), response.getEntity().toString()));
}
} catch (Exception e) {
throw new RuntimeException("Failed to generate session token for user", e);
} finally {
try {
httpClient.close();
} catch (Exception e) {
log.warn("Failed to close http client", e);
}
}
}
/**
* Call the Auth Service to create a native Datahub user.
*/
@Nonnull
public boolean signUp(@Nonnull final String userUrn, @Nonnull final String fullName, @Nonnull final String email,
@Nonnull final String title, @Nonnull final String password, @Nonnull final String inviteToken) {
Objects.requireNonNull(userUrn, "userUrn must not be null");
Objects.requireNonNull(fullName, "fullName must not be null");
Objects.requireNonNull(email, "email must not be null");
Objects.requireNonNull(title, "title must not be null");
Objects.requireNonNull(password, "password must not be null");
Objects.requireNonNull(inviteToken, "inviteToken must not be null");
CloseableHttpClient httpClient = HttpClients.createDefault();
try {
final String protocol = this.metadataServiceUseSsl ? "https" : "http";
final HttpPost request =
new HttpPost(String.format("%s://%s:%s/%s", protocol, this.metadataServiceHost, this.metadataServicePort,
SIGN_UP_ENDPOINT));
// Build JSON request to verify credentials for a native user.
String json =
String.format("{ \"%s\":\"%s\", \"%s\":\"%s\", \"%s\":\"%s\", \"%s\":\"%s\", \"%s\":\"%s\", \"%s\":\"%s\" }",
USER_URN_FIELD, userUrn, FULL_NAME_FIELD, fullName, EMAIL_FIELD, email, TITLE_FIELD, title,
PASSWORD_FIELD, password, INVITE_TOKEN_FIELD, inviteToken);
request.setEntity(new StringEntity(json));
// Add authorization header with DataHub frontend system id and secret.
request.addHeader(Http.HeaderNames.AUTHORIZATION, this.systemAuthentication.getCredentials());
CloseableHttpResponse response = httpClient.execute(request);
final HttpEntity entity = response.getEntity();
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK && entity != null) {
// Successfully generated a token for the User
final String jsonStr = EntityUtils.toString(entity);
return getIsNativeUserCreatedFromJson(jsonStr);
} else {
throw new RuntimeException(
String.format("Bad response from the Metadata Service: %s %s", response.getStatusLine().toString(),
response.getEntity().toString()));
}
} catch (Exception e) {
throw new RuntimeException("Failed to create user", e);
} finally {
try {
httpClient.close();
} catch (Exception e) {
log.warn("Failed to close http client", e);
}
}
}
/**
* Call the Auth Service to reset credentials for a native DataHub user.
*/
@Nonnull
public boolean resetNativeUserCredentials(@Nonnull final String userUrn, @Nonnull final String password,
@Nonnull final String resetToken) {
Objects.requireNonNull(userUrn, "userUrn must not be null");
Objects.requireNonNull(password, "password must not be null");
Objects.requireNonNull(resetToken, "reset token must not be null");
CloseableHttpClient httpClient = HttpClients.createDefault();
try {
final String protocol = this.metadataServiceUseSsl ? "https" : "http";
final HttpPost request = new HttpPost(
String.format("%s://%s:%s/%s", protocol, this.metadataServiceHost, this.metadataServicePort,
RESET_NATIVE_USER_CREDENTIALS_ENDPOINT));
// Build JSON request to verify credentials for a native user.
String json =
String.format("{ \"%s\":\"%s\", \"%s\":\"%s\", \"%s\":\"%s\" }", USER_URN_FIELD, userUrn,
PASSWORD_FIELD, password, RESET_TOKEN_FIELD, resetToken);
request.setEntity(new StringEntity(json));
// Add authorization header with DataHub frontend system id and secret.
request.addHeader(Http.HeaderNames.AUTHORIZATION, this.systemAuthentication.getCredentials());
CloseableHttpResponse response = httpClient.execute(request);
final HttpEntity entity = response.getEntity();
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK && entity != null) {
// Successfully generated a token for the User
final String jsonStr = EntityUtils.toString(entity);
return getAreNativeUserCredentialsResetFromJson(jsonStr);
} else {
throw new RuntimeException(
String.format("Bad response from the Metadata Service: %s %s", response.getStatusLine().toString(),
response.getEntity().toString()));
}
} catch (Exception e) {
throw new RuntimeException("Failed to reset credentials for user", e);
} finally {
try {
httpClient.close();
} catch (Exception e) {
log.warn("Failed to close http client", e);
}
}
}
/**
* Call the Auth Service to verify the credentials for a native Datahub user.
*/
@Nonnull
public boolean verifyNativeUserCredentials(@Nonnull final String userUrn, @Nonnull final String password) {
Objects.requireNonNull(userUrn, "userUrn must not be null");
Objects.requireNonNull(password, "password must not be null");
CloseableHttpClient httpClient = HttpClients.createDefault();
try {
final String protocol = this.metadataServiceUseSsl ? "https" : "http";
final HttpPost request = new HttpPost(
String.format("%s://%s:%s/%s", protocol, this.metadataServiceHost, this.metadataServicePort,
VERIFY_NATIVE_USER_CREDENTIALS_ENDPOINT));
// Build JSON request to verify credentials for a native user.
String json =
String.format("{ \"%s\":\"%s\", \"%s\":\"%s\" }", USER_URN_FIELD, userUrn, PASSWORD_FIELD, password);
request.setEntity(new StringEntity(json));
// Add authorization header with DataHub frontend system id and secret.
request.addHeader(Http.HeaderNames.AUTHORIZATION, this.systemAuthentication.getCredentials());
CloseableHttpResponse response = httpClient.execute(request);
final HttpEntity entity = response.getEntity();
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK && entity != null) {
// Successfully generated a token for the User
final String jsonStr = EntityUtils.toString(entity);
return getDoesPasswordMatchFromJson(jsonStr);
} else {
throw new RuntimeException(
String.format("Bad response from the Metadata Service: %s %s", response.getStatusLine().toString(),
response.getEntity().toString()));
}
} catch (Exception e) {
throw new RuntimeException("Failed to verify credentials for user", e);
} finally {
try {
httpClient.close();
} catch (Exception e) {
log.warn("Failed to close http client", e);
}
}
}
private String getAccessTokenFromJson(final String jsonStr) {
ObjectMapper mapper = new ObjectMapper();
try {
return mapper.readTree(jsonStr).get(ACCESS_TOKEN_FIELD).asText();
} catch (Exception e) {
// Do not log the raw json in case it contains access token.
throw new IllegalArgumentException("Failed to parse JSON received from the MetadataService!");
}
}
private boolean getIsNativeUserCreatedFromJson(final String jsonStr) {
ObjectMapper mapper = new ObjectMapper();
try {
return mapper.readTree(jsonStr).get(IS_NATIVE_USER_CREATED_FIELD).asBoolean();
} catch (Exception e) {
throw new IllegalArgumentException("Failed to parse JSON received from the MetadataService!");
}
}
private boolean getAreNativeUserCredentialsResetFromJson(final String jsonStr) {
ObjectMapper mapper = new ObjectMapper();
try {
return mapper.readTree(jsonStr).get(ARE_NATIVE_USER_CREDENTIALS_RESET_FIELD).asBoolean();
} catch (Exception e) {
throw new IllegalArgumentException("Failed to parse JSON received from the MetadataService!");
}
}
private boolean getDoesPasswordMatchFromJson(final String jsonStr) {
ObjectMapper mapper = new ObjectMapper();
try {
return mapper.readTree(jsonStr).get(DOES_PASSWORD_MATCH_FIELD).asBoolean();
} catch (Exception e) {
throw new IllegalArgumentException("Failed to parse JSON received from the MetadataService!");
}
}
}