Revise cloud scheduler authentication (#1766)
diff --git a/elasticjob-cloud/elasticjob-cloud-scheduler/src/main/java/org/apache/shardingsphere/elasticjob/cloud/console/security/AuthenticationConstants.java b/elasticjob-cloud/elasticjob-cloud-scheduler/src/main/java/org/apache/shardingsphere/elasticjob/cloud/console/security/AuthenticationConstants.java
index 1b1c0a2..e42064b 100644
--- a/elasticjob-cloud/elasticjob-cloud-scheduler/src/main/java/org/apache/shardingsphere/elasticjob/cloud/console/security/AuthenticationConstants.java
+++ b/elasticjob-cloud/elasticjob-cloud-scheduler/src/main/java/org/apache/shardingsphere/elasticjob/cloud/console/security/AuthenticationConstants.java
@@ -17,12 +17,16 @@
package org.apache.shardingsphere.elasticjob.cloud.console.security;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+
/**
* Authentication constants.
*/
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class AuthenticationConstants {
-
+
public static final String LOGIN_URI = "/api/login";
-
+
public static final String HEADER_NAME = "accessToken";
}
diff --git a/elasticjob-cloud/elasticjob-cloud-scheduler/src/main/java/org/apache/shardingsphere/elasticjob/cloud/console/security/AuthenticationFilter.java b/elasticjob-cloud/elasticjob-cloud-scheduler/src/main/java/org/apache/shardingsphere/elasticjob/cloud/console/security/AuthenticationFilter.java
index b368a4a..60da27f 100644
--- a/elasticjob-cloud/elasticjob-cloud-scheduler/src/main/java/org/apache/shardingsphere/elasticjob/cloud/console/security/AuthenticationFilter.java
+++ b/elasticjob-cloud/elasticjob-cloud-scheduler/src/main/java/org/apache/shardingsphere/elasticjob/cloud/console/security/AuthenticationFilter.java
@@ -18,65 +18,68 @@
package org.apache.shardingsphere.elasticjob.cloud.console.security;
import com.google.common.base.Strings;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
import io.netty.buffer.ByteBufUtil;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaderNames;
+import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpUtil;
-import java.util.Collections;
-import java.util.Optional;
import lombok.RequiredArgsConstructor;
-import org.apache.shardingsphere.elasticjob.infra.json.GsonFactory;
import org.apache.shardingsphere.elasticjob.restful.Filter;
import org.apache.shardingsphere.elasticjob.restful.Http;
import org.apache.shardingsphere.elasticjob.restful.deserializer.RequestBodyDeserializer;
import org.apache.shardingsphere.elasticjob.restful.deserializer.RequestBodyDeserializerFactory;
import org.apache.shardingsphere.elasticjob.restful.filter.FilterChain;
+import java.util.Collections;
+import java.util.Optional;
+
/**
* Authentication filter.
*/
@RequiredArgsConstructor
public final class AuthenticationFilter implements Filter {
-
+
+ private final Gson gson = new GsonBuilder().disableHtmlEscaping().create();
+
private final AuthenticationService authenticationService;
-
+
@Override
public void doFilter(final FullHttpRequest httpRequest, final FullHttpResponse httpResponse, final FilterChain filterChain) {
- if (AuthenticationConstants.LOGIN_URI.equals(httpRequest.uri())) {
+ if (HttpMethod.POST.equals(httpRequest.method()) && AuthenticationConstants.LOGIN_URI.equals(httpRequest.uri())) {
handleLogin(httpRequest, httpResponse);
- } else {
- String accessToken = httpRequest.headers().get(AuthenticationConstants.HEADER_NAME);
- if (!Strings.isNullOrEmpty(accessToken) && accessToken.equals(authenticationService.getToken())) {
- filterChain.next(httpRequest);
- } else {
- respondWithUnauthorized(httpResponse);
- }
+ return;
}
+ String accessToken = httpRequest.headers().get(AuthenticationConstants.HEADER_NAME);
+ if (Strings.isNullOrEmpty(accessToken) || !accessToken.equals(authenticationService.getToken())) {
+ respondWithUnauthorized(httpResponse);
+ return;
+ }
+ filterChain.next(httpRequest);
}
-
+
private void handleLogin(final FullHttpRequest httpRequest, final FullHttpResponse httpResponse) {
byte[] bytes = ByteBufUtil.getBytes(httpRequest.content());
- String mimeType = Optional.ofNullable(HttpUtil.getMimeType(httpRequest))
- .orElseGet(() -> HttpUtil.getMimeType(Http.DEFAULT_CONTENT_TYPE)).toString();
+ String mimeType = Optional.ofNullable(HttpUtil.getMimeType(httpRequest)).orElseGet(() -> HttpUtil.getMimeType(Http.DEFAULT_CONTENT_TYPE)).toString();
RequestBodyDeserializer deserializer = RequestBodyDeserializerFactory.getRequestBodyDeserializer(mimeType);
AuthenticationInfo authenticationInfo = deserializer.deserialize(AuthenticationInfo.class, bytes);
boolean result = authenticationService.check(authenticationInfo);
- if (result) {
- String token = GsonFactory.getGson().toJson(Collections.singletonMap(AuthenticationConstants.HEADER_NAME,
- authenticationService.getToken()));
- respond(httpResponse, HttpResponseStatus.OK, token.getBytes());
- } else {
+ if (!result) {
respondWithUnauthorized(httpResponse);
+ return;
}
+ String token = gson.toJson(Collections.singletonMap(AuthenticationConstants.HEADER_NAME, authenticationService.getToken()));
+ respond(httpResponse, HttpResponseStatus.OK, token.getBytes());
}
-
+
private void respondWithUnauthorized(final FullHttpResponse httpResponse) {
- String result = GsonFactory.getGson().toJson(Collections.singletonMap("message", "Unauthorized."));
+ String result = gson.toJson(Collections.singletonMap("message", "Unauthorized."));
respond(httpResponse, HttpResponseStatus.UNAUTHORIZED, result.getBytes());
}
-
+
private void respond(final FullHttpResponse httpResponse, final HttpResponseStatus status, final byte[] result) {
httpResponse.setStatus(status);
httpResponse.headers().set(HttpHeaderNames.CONTENT_TYPE, Http.DEFAULT_CONTENT_TYPE);
diff --git a/elasticjob-cloud/elasticjob-cloud-scheduler/src/main/java/org/apache/shardingsphere/elasticjob/cloud/console/security/AuthenticationInfo.java b/elasticjob-cloud/elasticjob-cloud-scheduler/src/main/java/org/apache/shardingsphere/elasticjob/cloud/console/security/AuthenticationInfo.java
index e4f246f..a0d0da8 100644
--- a/elasticjob-cloud/elasticjob-cloud-scheduler/src/main/java/org/apache/shardingsphere/elasticjob/cloud/console/security/AuthenticationInfo.java
+++ b/elasticjob-cloud/elasticjob-cloud-scheduler/src/main/java/org/apache/shardingsphere/elasticjob/cloud/console/security/AuthenticationInfo.java
@@ -20,12 +20,14 @@
import lombok.Getter;
import lombok.Setter;
+/**
+ * Authentication info.
+ */
@Getter
@Setter
public final class AuthenticationInfo {
-
+
private String username;
-
+
private String password;
-
}
diff --git a/elasticjob-cloud/elasticjob-cloud-scheduler/src/main/java/org/apache/shardingsphere/elasticjob/cloud/console/security/AuthenticationService.java b/elasticjob-cloud/elasticjob-cloud-scheduler/src/main/java/org/apache/shardingsphere/elasticjob/cloud/console/security/AuthenticationService.java
index cf6adb9..a07cf58 100644
--- a/elasticjob-cloud/elasticjob-cloud-scheduler/src/main/java/org/apache/shardingsphere/elasticjob/cloud/console/security/AuthenticationService.java
+++ b/elasticjob-cloud/elasticjob-cloud-scheduler/src/main/java/org/apache/shardingsphere/elasticjob/cloud/console/security/AuthenticationService.java
@@ -18,20 +18,23 @@
package org.apache.shardingsphere.elasticjob.cloud.console.security;
import com.google.common.base.Strings;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
import org.apache.commons.codec.binary.Base64;
import org.apache.shardingsphere.elasticjob.cloud.scheduler.env.AuthConfiguration;
import org.apache.shardingsphere.elasticjob.cloud.scheduler.env.BootstrapEnvironment;
-import org.apache.shardingsphere.elasticjob.infra.json.GsonFactory;
/**
* User authentication service.
*/
public final class AuthenticationService {
-
+
+ private final Gson gson = new GsonBuilder().disableHtmlEscaping().create();
+
private final Base64 base64 = new Base64();
-
+
private final BootstrapEnvironment env = BootstrapEnvironment.getINSTANCE();
-
+
/**
* Check auth.
*
@@ -45,13 +48,13 @@
AuthConfiguration userAuthConfiguration = env.getUserAuthConfiguration();
return userAuthConfiguration.getAuthUsername().equals(authenticationInfo.getUsername()) && userAuthConfiguration.getAuthPassword().equals(authenticationInfo.getPassword());
}
-
+
/**
* Get user authentication token.
*
* @return authentication token
*/
public String getToken() {
- return base64.encodeToString(GsonFactory.getGson().toJson(env.getUserAuthConfiguration()).getBytes());
+ return base64.encodeToString(gson.toJson(env.getUserAuthConfiguration()).getBytes());
}
}
diff --git a/elasticjob-cloud/elasticjob-cloud-scheduler/src/test/java/org/apache/shardingsphere/elasticjob/cloud/console/HttpTestUtil.java b/elasticjob-cloud/elasticjob-cloud-scheduler/src/test/java/org/apache/shardingsphere/elasticjob/cloud/console/HttpTestUtil.java
index 16081da..df71491 100644
--- a/elasticjob-cloud/elasticjob-cloud-scheduler/src/test/java/org/apache/shardingsphere/elasticjob/cloud/console/HttpTestUtil.java
+++ b/elasticjob-cloud/elasticjob-cloud-scheduler/src/test/java/org/apache/shardingsphere/elasticjob/cloud/console/HttpTestUtil.java
@@ -44,13 +44,13 @@
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class HttpTestUtil {
-
+
private static final AuthenticationService AUTH_SERVICE = new AuthenticationService();
-
+
private static void setAuth(final HttpRequestBase httpRequestBase) {
httpRequestBase.setHeader(AuthenticationConstants.HEADER_NAME, AUTH_SERVICE.getToken());
}
-
+
/**
* Send post request.
*
@@ -66,11 +66,11 @@
throw new HttpClientException("send a post request for '%s' failed", e, url);
}
}
-
+
/**
* Send post request.
*
- * @param url url
+ * @param url url
* @param content content
* @return http status code
*/
@@ -87,11 +87,11 @@
throw new HttpClientException("send a post request for '%s' with parameter '%s' failed", e, url, content);
}
}
-
+
/**
* Send put request.
*
- * @param url url
+ * @param url url
* @param content content
* @return http status code
*/
@@ -129,7 +129,7 @@
/**
* Send get request.
*
- * @param url url
+ * @param url url
* @param content content
* @return http result
*/
@@ -163,11 +163,11 @@
throw new HttpClientException("send a delete request for '%s' failed", e, url);
}
}
-
+
/**
* Send post request.
*
- * @param url url
+ * @param url url
* @param content content
* @return http response
*/
@@ -183,7 +183,7 @@
throw new HttpClientException("send a post request for '%s' with parameter '%s' failed", e, url, content);
}
}
-
+
/**
* Send get request.
*
diff --git a/elasticjob-cloud/elasticjob-cloud-scheduler/src/test/java/org/apache/shardingsphere/elasticjob/cloud/console/controller/CloudLoginTest.java b/elasticjob-cloud/elasticjob-cloud-scheduler/src/test/java/org/apache/shardingsphere/elasticjob/cloud/console/controller/CloudLoginTest.java
index f7e25ee..7ff5229 100644
--- a/elasticjob-cloud/elasticjob-cloud-scheduler/src/test/java/org/apache/shardingsphere/elasticjob/cloud/console/controller/CloudLoginTest.java
+++ b/elasticjob-cloud/elasticjob-cloud-scheduler/src/test/java/org/apache/shardingsphere/elasticjob/cloud/console/controller/CloudLoginTest.java
@@ -17,13 +17,7 @@
package org.apache.shardingsphere.elasticjob.cloud.console.controller;
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertThat;
-
import com.google.gson.JsonObject;
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.util.EntityUtils;
import org.apache.shardingsphere.elasticjob.cloud.console.AbstractCloudControllerTest;
@@ -35,6 +29,13 @@
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
@RunWith(MockitoJUnitRunner.class)
public class CloudLoginTest extends AbstractCloudControllerTest {
@@ -50,7 +51,7 @@
String token = GsonFactory.getGson().fromJson(entity, JsonObject.class).get(AuthenticationConstants.HEADER_NAME).getAsString();
assertThat(token, is(authenticationService.getToken()));
}
-
+
@Test
public void assertLoginFail() {
Map<String, String> authInfo = new HashMap<>();
@@ -59,7 +60,7 @@
CloseableHttpResponse actual = HttpTestUtil.unauthorizedPost("http://127.0.0.1:19000/api/login", authInfo);
assertThat(actual.getStatusLine().getStatusCode(), is(401));
}
-
+
@Test
public void assertUnauthorized() {
assertThat(HttpTestUtil.unauthorizedGet("http://127.0.0.1:19000/api/unauthorized"), is(401));