diff --git a/apm-dist/bin/webappService.bat b/apm-dist/bin/webappService.bat
index 1627db45a5..049164a8c5 100644
--- a/apm-dist/bin/webappService.bat
+++ b/apm-dist/bin/webappService.bat
@@ -37,5 +37,5 @@ if not defined JAVA_HOME (
set _EXECJAVA=java
)
-start "%WEBAPP_PROCESS_TITLE%" %_EXECJAVA% -jar %JARPATH%/skywalking-webapp.jar --server.port=8080 --collector.ribbon.listOfServers=127.0.0.1:10800 --logging.file=%LOG_FILE_LOCATION% --collector.ribbon.ReadTimeout=10000
+start "%WEBAPP_PROCESS_TITLE%" %_EXECJAVA% -jar %JARPATH%/skywalking-webapp.jar --spring.config.location=%JAR_PATH%/webapp.yml --logging.file=%LOG_FILE_LOCATION%
endlocal
diff --git a/apm-dist/bin/webappService.sh b/apm-dist/bin/webappService.sh
index 194e8d9c38..df0040dc76 100644
--- a/apm-dist/bin/webappService.sh
+++ b/apm-dist/bin/webappService.sh
@@ -34,9 +34,8 @@ _RUNJAVA=${JAVA_HOME}/bin/java
[ -z "$JAVA_HOME" ] && _RUNJAVA=java
eval exec "\"$_RUNJAVA\" ${JAVA_OPTS} -jar ${JAR_PATH}/skywalking-webapp.jar \
- --server.port=8080 --collector.ribbon.listOfServers=127.0.0.1:10800 \
+ --spring.config.location=${JAR_PATH}/webapp.yml \
--logging.file=${LOG_FILE_LOCATION} \
- --collector.ribbon.ReadTimeout=10000 \
2>${WEBAPP_LOG_DIR}/webapp-console.log 1> /dev/null &"
if [ $? -eq 0 ]; then
diff --git a/apm-dist/src/main/assembly/binary.xml b/apm-dist/src/main/assembly/binary.xml
index afdb0c0944..193e69343e 100644
--- a/apm-dist/src/main/assembly/binary.xml
+++ b/apm-dist/src/main/assembly/binary.xml
@@ -75,5 +75,10 @@
/webapp0644
+
+ ${project.basedir}/../apm-webapp/src/main/assembly/webapp.yml
+ /webapp
+ 0644
+
diff --git a/apm-webapp/src/main/assembly/webapp.yml b/apm-webapp/src/main/assembly/webapp.yml
new file mode 100644
index 0000000000..8e0f7d195c
--- /dev/null
+++ b/apm-webapp/src/main/assembly/webapp.yml
@@ -0,0 +1,29 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+server:
+ port: 8080
+
+collector:
+ path: /graphql
+ ribbon:
+ ReadTimeout: 10000
+ listOfServers: 127.0.0.1:10800
+
+security:
+ user:
+ admin:
+ password: admin
diff --git a/apm-webapp/src/main/java/org/apache/skywalking/apm/webapp/ApplicationStartUp.java b/apm-webapp/src/main/java/org/apache/skywalking/apm/webapp/ApplicationStartUp.java
index 5f3fe61022..f8f3dde22e 100644
--- a/apm-webapp/src/main/java/org/apache/skywalking/apm/webapp/ApplicationStartUp.java
+++ b/apm-webapp/src/main/java/org/apache/skywalking/apm/webapp/ApplicationStartUp.java
@@ -18,25 +18,17 @@
package org.apache.skywalking.apm.webapp;
-import org.apache.skywalking.apm.webapp.config.UIConfig;
-import org.apache.skywalking.apm.webapp.tools.RewritePathFilter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.support.SpringBootServletInitializer;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.annotation.Bean;
@SpringBootApplication
@EnableZuulProxy
public class ApplicationStartUp extends SpringBootServletInitializer {
- public static void main(String[] args) throws Exception {
- ApplicationContext applicationContext = SpringApplication.run(ApplicationStartUp.class, args);
- }
-
- @Bean
- public RewritePathFilter addWritePathFilter(UIConfig uiConfig) {
- return new RewritePathFilter(uiConfig.getRewritePath());
+ public static void main(String[] args) {
+ SpringApplication.run(ApplicationStartUp.class, args);
}
+
}
diff --git a/apm-webapp/src/main/java/org/apache/skywalking/apm/webapp/tools/CollectorServerList.java b/apm-webapp/src/main/java/org/apache/skywalking/apm/webapp/proxy/CollectorServerList.java
similarity index 98%
rename from apm-webapp/src/main/java/org/apache/skywalking/apm/webapp/tools/CollectorServerList.java
rename to apm-webapp/src/main/java/org/apache/skywalking/apm/webapp/proxy/CollectorServerList.java
index 95f3c2ecf2..2df2b0d672 100644
--- a/apm-webapp/src/main/java/org/apache/skywalking/apm/webapp/tools/CollectorServerList.java
+++ b/apm-webapp/src/main/java/org/apache/skywalking/apm/webapp/proxy/CollectorServerList.java
@@ -16,7 +16,7 @@
*
*/
-package org.apache.skywalking.apm.webapp.tools;
+package org.apache.skywalking.apm.webapp.proxy;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
diff --git a/apm-webapp/src/main/java/org/apache/skywalking/apm/webapp/tools/HttpClientTools.java b/apm-webapp/src/main/java/org/apache/skywalking/apm/webapp/proxy/HttpClientTools.java
similarity index 98%
rename from apm-webapp/src/main/java/org/apache/skywalking/apm/webapp/tools/HttpClientTools.java
rename to apm-webapp/src/main/java/org/apache/skywalking/apm/webapp/proxy/HttpClientTools.java
index da162a83b0..8fcc974abc 100644
--- a/apm-webapp/src/main/java/org/apache/skywalking/apm/webapp/tools/HttpClientTools.java
+++ b/apm-webapp/src/main/java/org/apache/skywalking/apm/webapp/proxy/HttpClientTools.java
@@ -16,7 +16,7 @@
*
*/
-package org.apache.skywalking.apm.webapp.tools;
+package org.apache.skywalking.apm.webapp.proxy;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
diff --git a/apm-webapp/src/main/java/org/apache/skywalking/apm/webapp/tools/RewritePathFilter.java b/apm-webapp/src/main/java/org/apache/skywalking/apm/webapp/proxy/RewritePathFilter.java
similarity index 80%
rename from apm-webapp/src/main/java/org/apache/skywalking/apm/webapp/tools/RewritePathFilter.java
rename to apm-webapp/src/main/java/org/apache/skywalking/apm/webapp/proxy/RewritePathFilter.java
index e3303f8210..83450aa7c6 100644
--- a/apm-webapp/src/main/java/org/apache/skywalking/apm/webapp/tools/RewritePathFilter.java
+++ b/apm-webapp/src/main/java/org/apache/skywalking/apm/webapp/proxy/RewritePathFilter.java
@@ -16,10 +16,12 @@
*
*/
-package org.apache.skywalking.apm.webapp.tools;
+package org.apache.skywalking.apm.webapp.proxy;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_DECORATION_FILTER_ORDER;
@@ -28,17 +30,23 @@ import static org.springframework.cloud.netflix.zuul.filters.support.FilterConst
*
* @author gaohongtao
*/
+@Component
+@ConfigurationProperties(prefix = "collector")
public class RewritePathFilter extends ZuulFilter {
private static final String REQUEST_URI = "requestURI";
- private static final int ORDER = PRE_DECORATION_FILTER_ORDER + 1;
+ private static final int ORDER = PRE_DECORATION_FILTER_ORDER + 2;
+
+ private String path;
- public RewritePathFilter(String rewritePath) {
- this.rewritePath = rewritePath;
+ public String getPath() {
+ return path;
}
- private final String rewritePath;
+ public void setPath(String path) {
+ this.path = path;
+ }
@Override
public int filterOrder() {
@@ -59,7 +67,7 @@ public class RewritePathFilter extends ZuulFilter {
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
- ctx.set(REQUEST_URI, rewritePath);
+ ctx.set(REQUEST_URI, path);
return null;
}
}
diff --git a/apm-webapp/src/main/java/org/apache/skywalking/apm/webapp/config/UIConfig.java b/apm-webapp/src/main/java/org/apache/skywalking/apm/webapp/security/Account.java
similarity index 68%
rename from apm-webapp/src/main/java/org/apache/skywalking/apm/webapp/config/UIConfig.java
rename to apm-webapp/src/main/java/org/apache/skywalking/apm/webapp/security/Account.java
index c5a1f298c7..cb33d86f7d 100644
--- a/apm-webapp/src/main/java/org/apache/skywalking/apm/webapp/config/UIConfig.java
+++ b/apm-webapp/src/main/java/org/apache/skywalking/apm/webapp/security/Account.java
@@ -16,21 +16,16 @@
*
*/
-package org.apache.skywalking.apm.webapp.config;
-
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.context.annotation.Configuration;
+package org.apache.skywalking.apm.webapp.security;
/**
- * @author peng-yongsheng
+ * Account of Login.
+ *
+ * @author gaohongtao
*/
-@Configuration
-public class UIConfig {
-
- @Value("${collector.path}")
- private String rewritePath;
+public interface Account {
- public String getRewritePath() {
- return rewritePath;
- }
+ String userName();
+
+ String password();
}
diff --git a/apm-webapp/src/main/java/org/apache/skywalking/apm/webapp/security/LoginFilter.java b/apm-webapp/src/main/java/org/apache/skywalking/apm/webapp/security/LoginFilter.java
new file mode 100644
index 0000000000..4c696beec7
--- /dev/null
+++ b/apm-webapp/src/main/java/org/apache/skywalking/apm/webapp/security/LoginFilter.java
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.webapp.security;
+
+import com.google.gson.Gson;
+import com.netflix.zuul.ZuulFilter;
+import com.netflix.zuul.context.RequestContext;
+import java.io.IOException;
+import javax.servlet.http.HttpServletResponse;
+import org.springframework.stereotype.Component;
+import org.springframework.util.ReflectionUtils;
+
+import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_DECORATION_FILTER_ORDER;
+
+/**
+ * Filter login request.
+ *
+ * @author gaohongtao
+ */
+@Component
+public class LoginFilter extends ZuulFilter {
+
+ private static final String REQUEST_URI = "requestURI";
+
+ private static final String LOGIN_URI = "/login/account";
+
+ private static final int ORDER = PRE_DECORATION_FILTER_ORDER + 1;
+
+ private final UserChecker checker;
+
+ public LoginFilter(final UserChecker checker) {
+ this.checker = checker;
+ }
+
+ @Override public String filterType() {
+ return "pre";
+ }
+
+ @Override public int filterOrder() {
+ return ORDER;
+ }
+
+ @Override public boolean shouldFilter() {
+ RequestContext ctx = RequestContext.getCurrentContext();
+ return ctx.get(REQUEST_URI).equals(LOGIN_URI);
+ }
+
+ @Override public Object run() {
+ RequestContext ctx = RequestContext.getCurrentContext();
+ Account loginAccount = null;
+ try {
+ loginAccount = ReaderAccount.newReaderAccount(ctx.getRequest().getReader());
+ } catch (IOException e) {
+ ReflectionUtils.rethrowRuntimeException(e);
+ }
+ Gson gson = new Gson();
+ String resStr;
+ if (checker.check(loginAccount)) {
+ resStr = gson.toJson(new ResponseData("ok", "admin"));
+ } else {
+ resStr = gson.toJson(new ResponseData("error", "guest"));
+ }
+ HttpServletResponse response = ctx.getResponse();
+ response.setContentType("application/json");
+ response.setCharacterEncoding("UTF-8");
+ ctx.setResponseStatusCode(HttpServletResponse.SC_OK);
+ ctx.setResponseBody(resStr);
+ ctx.setSendZuulResponse(false);
+ return null;
+ }
+
+ private static class ResponseData {
+ private final String status;
+ private final String currentAuthority;
+ ResponseData(final String status, final String currentAuthority) {
+ this.status = status;
+ this.currentAuthority = currentAuthority;
+ }
+ }
+}
diff --git a/apm-webapp/src/main/java/org/apache/skywalking/apm/webapp/security/ReaderAccount.java b/apm-webapp/src/main/java/org/apache/skywalking/apm/webapp/security/ReaderAccount.java
new file mode 100644
index 0000000000..9709f737de
--- /dev/null
+++ b/apm-webapp/src/main/java/org/apache/skywalking/apm/webapp/security/ReaderAccount.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.webapp.security;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import java.io.BufferedReader;
+
+/**
+ * A container of login information.
+ *
+ * @author gaohongtao
+ */
+class ReaderAccount implements Account {
+
+ private final static Gson GSON = new GsonBuilder().disableHtmlEscaping()
+ .setLenient().create();
+
+ private String userName;
+
+ private String password;
+
+ static ReaderAccount newReaderAccount(final BufferedReader accountReader) {
+ return GSON.fromJson(accountReader, ReaderAccount.class);
+ }
+
+ public String userName() {
+ return userName;
+ }
+
+ public String password() {
+ return password;
+ }
+}
diff --git a/apm-webapp/src/main/java/org/apache/skywalking/apm/webapp/security/UserChecker.java b/apm-webapp/src/main/java/org/apache/skywalking/apm/webapp/security/UserChecker.java
new file mode 100644
index 0000000000..785fe35167
--- /dev/null
+++ b/apm-webapp/src/main/java/org/apache/skywalking/apm/webapp/security/UserChecker.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.webapp.security;
+
+import com.google.common.base.Strings;
+import java.util.HashMap;
+import java.util.Map;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ * A Checker to check username and password.
+ *
+ * @author gaohongtao
+ */
+@Component
+@ConfigurationProperties(prefix = "security")
+public class UserChecker {
+
+ private Map user = new HashMap<>();
+
+ public Map getUser() {
+ return user;
+ }
+
+ boolean check(Account account) {
+ if (Strings.isNullOrEmpty(account.userName()) || Strings.isNullOrEmpty(account.password())) {
+ return false;
+ }
+ if (!user.containsKey(account.userName())) {
+ return false;
+ }
+ return user.get(account.userName()).password.equals(account.password());
+ }
+
+ public static class User {
+ private String password;
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+ }
+}
diff --git a/apm-webapp/src/main/resources/application.yml b/apm-webapp/src/main/resources/application.yml
index 20d57d51d8..69e5c96586 100644
--- a/apm-webapp/src/main/resources/application.yml
+++ b/apm-webapp/src/main/resources/application.yml
@@ -28,3 +28,8 @@ collector:
ribbon:
listOfServers: 127.0.0.1:10800
NIWSServerListClassName: org.apache.skywalking.apm.webapp.tools.CollectorServerList
+
+security:
+ user:
+ admin:
+ password: admin
diff --git a/apm-webapp/src/test/java/org/apache/skywalking/apm/webapp/tools/RewritePathFilterTest.java b/apm-webapp/src/test/java/org/apache/skywalking/apm/webapp/proxy/RewritePathFilterTest.java
similarity index 89%
rename from apm-webapp/src/test/java/org/apache/skywalking/apm/webapp/tools/RewritePathFilterTest.java
rename to apm-webapp/src/test/java/org/apache/skywalking/apm/webapp/proxy/RewritePathFilterTest.java
index b856fb6083..013d96d3f3 100644
--- a/apm-webapp/src/test/java/org/apache/skywalking/apm/webapp/tools/RewritePathFilterTest.java
+++ b/apm-webapp/src/test/java/org/apache/skywalking/apm/webapp/proxy/RewritePathFilterTest.java
@@ -1,60 +1,60 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package org.apache.skywalking.apm.webapp.tools;
-
-import com.netflix.zuul.context.RequestContext;
-import org.junit.Before;
-import org.junit.Test;
-
-import static org.hamcrest.core.Is.is;
-import static org.junit.Assert.*;
-import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_DECORATION_FILTER_ORDER;
-
-public class RewritePathFilterTest {
-
- private RewritePathFilter filter;
-
- @Before
- public void init() {
- filter = new RewritePathFilter("/graphql");
- }
-
- @Test
- public void filterOrder() {
- assertThat(filter.filterOrder(), is(PRE_DECORATION_FILTER_ORDER + 1));
- }
-
- @Test
- public void filterType() {
- assertThat(filter.filterType(), is("pre"));
- }
-
- @Test
- public void shouldFilter() {
- assertFalse(filter.shouldFilter());
- RequestContext.getCurrentContext().set("requestURI");
- assertTrue(filter.shouldFilter());
- }
-
- @Test
- public void run() {
- filter.run();
- assertThat(RequestContext.getCurrentContext().get("requestURI"), is("/graphql"));
- }
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.webapp.proxy;
+
+import com.netflix.zuul.context.RequestContext;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.*;
+import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_DECORATION_FILTER_ORDER;
+
+public class RewritePathFilterTest {
+
+ private RewritePathFilter filter = new RewritePathFilter();
+
+ @Before
+ public void init() {
+ filter.setPath("/graphql");
+ }
+
+ @Test
+ public void filterOrder() {
+ assertThat(filter.filterOrder(), is(PRE_DECORATION_FILTER_ORDER + 2));
+ }
+
+ @Test
+ public void filterType() {
+ assertThat(filter.filterType(), is("pre"));
+ }
+
+ @Test
+ public void shouldFilter() {
+ assertFalse(filter.shouldFilter());
+ RequestContext.getCurrentContext().set("requestURI");
+ assertTrue(filter.shouldFilter());
+ }
+
+ @Test
+ public void run() {
+ filter.run();
+ assertThat(RequestContext.getCurrentContext().get("requestURI"), is("/graphql"));
+ }
}
\ No newline at end of file
diff --git a/apm-webapp/src/test/java/org/apache/skywalking/apm/webapp/security/LoginFilterTest.java b/apm-webapp/src/test/java/org/apache/skywalking/apm/webapp/security/LoginFilterTest.java
new file mode 100644
index 0000000000..cb20ba2efa
--- /dev/null
+++ b/apm-webapp/src/test/java/org/apache/skywalking/apm/webapp/security/LoginFilterTest.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.webapp.security;
+
+import com.netflix.zuul.context.RequestContext;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_DECORATION_FILTER_ORDER;
+
+
+public class LoginFilterTest {
+
+ private LoginFilter loginFilter;
+
+ @Before
+ public void setUp() {
+ UserChecker checker = new UserChecker();
+ UserChecker.User user = new UserChecker.User();
+ user.setPassword("admin");
+ checker.getUser().put("admin", user);
+ loginFilter = new LoginFilter(checker);
+ }
+
+ @After
+ public void tearDown() {
+ RequestContext.testSetCurrentContext(null);
+ }
+
+ @Test
+ public void assertFilterType() {
+ assertThat(loginFilter.filterType(), is("pre"));
+ }
+
+ @Test
+ public void assertFilterOrder() {
+ assertThat(loginFilter.filterOrder(), is(PRE_DECORATION_FILTER_ORDER + 1));
+ }
+
+ @Test
+ public void assertShouldFilter() {
+ RequestContext ctx = new RequestContext();
+ ctx.set("requestURI", "/login/account");
+ RequestContext.testSetCurrentContext(ctx);
+ assertTrue(loginFilter.shouldFilter());
+ ctx.set("requestURI", "/dashboard");
+ assertFalse(loginFilter.shouldFilter());
+ }
+}
\ No newline at end of file
diff --git a/apm-webapp/src/test/java/org/apache/skywalking/apm/webapp/security/LoginTest.java b/apm-webapp/src/test/java/org/apache/skywalking/apm/webapp/security/LoginTest.java
new file mode 100644
index 0000000000..e077d51499
--- /dev/null
+++ b/apm-webapp/src/test/java/org/apache/skywalking/apm/webapp/security/LoginTest.java
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.webapp.security;
+
+import com.netflix.zuul.context.RequestContext;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.StringReader;
+import java.lang.reflect.UndeclaredThrowableException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class LoginTest {
+
+ private LoginFilter loginFilter;
+
+ @Mock
+ private RequestContext ctx;
+
+ @Mock
+ private HttpServletRequest request;
+
+ @Mock
+ private HttpServletResponse response;
+
+ @Before
+ public void setUp() {
+ UserChecker checker = new UserChecker();
+ UserChecker.User user = new UserChecker.User();
+ user.setPassword("admin");
+ checker.getUser().put("admin", user);
+ loginFilter = new LoginFilter(checker);
+ when(ctx.getRequest()).thenReturn(request);
+ when(ctx.getResponse()).thenReturn(response);
+ RequestContext.testSetCurrentContext(ctx);
+ }
+
+ @Test
+ public void assertSuccessLogin() throws IOException {
+ when(request.getReader()).thenReturn(new BufferedReader(new StringReader("{\"userName\": \"admin\", \"password\":\"admin\"}")));
+ loginFilter.run();
+ assertHeaderAndStatusCode();
+ verify(ctx).setResponseBody("{\"status\":\"ok\",\"currentAuthority\":\"admin\"}");
+ }
+
+ @Test
+ public void assertFailLogin() throws IOException {
+ when(request.getReader()).thenReturn(new BufferedReader(new StringReader("{\"userName\": \"admin\", \"password\":\"888888\"}")));
+ loginFilter.run();
+ assertHeaderAndStatusCode();
+ verify(ctx).setResponseBody("{\"status\":\"error\",\"currentAuthority\":\"guest\"}");
+ }
+
+ @Test(expected = UndeclaredThrowableException.class)
+ public void assertException() throws IOException {
+ when(request.getReader()).thenThrow(new IOException());
+ loginFilter.run();
+ }
+
+ private void assertHeaderAndStatusCode() {
+ verify(ctx).setResponseStatusCode(HttpServletResponse.SC_OK);
+ verify(response).setContentType("application/json");
+ verify(response).setCharacterEncoding("UTF-8");
+ }
+}
diff --git a/apm-webapp/src/test/java/org/apache/skywalking/apm/webapp/security/ReaderAccountTest.java b/apm-webapp/src/test/java/org/apache/skywalking/apm/webapp/security/ReaderAccountTest.java
new file mode 100644
index 0000000000..3cfe631a34
--- /dev/null
+++ b/apm-webapp/src/test/java/org/apache/skywalking/apm/webapp/security/ReaderAccountTest.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.webapp.security;
+
+import java.io.BufferedReader;
+import java.io.StringReader;
+import org.junit.Test;
+
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.*;
+
+public class ReaderAccountTest {
+
+ @Test
+ public void assertNewReaderAccount() {
+ Account account = ReaderAccount.newReaderAccount(new BufferedReader(new StringReader("{\"userName\": \"admin\", \"password\":\"888888\"}")));
+ assertThat(account.userName(), is("admin"));
+ assertThat(account.password(), is("888888"));
+ }
+
+}
\ No newline at end of file
diff --git a/apm-webapp/src/test/java/org/apache/skywalking/apm/webapp/security/UserCheckerTest.java b/apm-webapp/src/test/java/org/apache/skywalking/apm/webapp/security/UserCheckerTest.java
new file mode 100644
index 0000000000..81c266b413
--- /dev/null
+++ b/apm-webapp/src/test/java/org/apache/skywalking/apm/webapp/security/UserCheckerTest.java
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.webapp.security;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class UserCheckerTest {
+
+ @Test
+ public void assertCheckSuccess() {
+ UserChecker checker = new UserChecker();
+ UserChecker.User user = new UserChecker.User();
+ user.setPassword("888888");
+ checker.getUser().put("admin", user);
+ assertTrue(checker.check(new Account() {
+ @Override public String userName() {
+ return "admin";
+ }
+
+ @Override public String password() {
+ return "888888";
+ }
+ }));
+ }
+
+ @Test
+ public void assertCheckFail() {
+ UserChecker checker = new UserChecker();
+ UserChecker.User user = new UserChecker.User();
+ user.setPassword("123456");
+ checker.getUser().put("guest", user);
+ assertFalse(checker.check(new Account() {
+ @Override public String userName() {
+ return "admin";
+ }
+
+ @Override public String password() {
+ return "888888";
+ }
+ }));
+ assertFalse(checker.check(new Account() {
+ @Override public String userName() {
+ return "guest";
+ }
+
+ @Override public String password() {
+ return "888888";
+ }
+ }));
+ assertFalse(checker.check(new Account() {
+ @Override public String userName() {
+ return "admin";
+ }
+
+ @Override public String password() {
+ return "123456";
+ }
+ }));
+ assertFalse(checker.check(new Account() {
+ @Override public String userName() {
+ return "";
+ }
+
+ @Override public String password() {
+ return "123456";
+ }
+ }));
+ assertFalse(checker.check(new Account() {
+ @Override public String userName() {
+ return "admin";
+ }
+
+ @Override public String password() {
+ return "";
+ }
+ }));
+ }
+}
\ No newline at end of file
diff --git a/docs/cn/Deploy-backend-in-cluster-mode-CN.md b/docs/cn/Deploy-backend-in-cluster-mode-CN.md
index 4252e03081..d506d0acbb 100644
--- a/docs/cn/Deploy-backend-in-cluster-mode-CN.md
+++ b/docs/cn/Deploy-backend-in-cluster-mode-CN.md
@@ -109,11 +109,14 @@ configuration:
1. 解压安装包 `tar -xvf skywalking-dist.tar.gz`,windows用户可以选择zip包
2. 配置UI集群模式.
-UI的配置信息保存在 `bin/webappService.sh` 中 ( windows为`bin\webappService.bat`).
+UI的配置信息保存在 `webapp/webapp.yml` 中.
| 配置项 | 描述 |
|----------------------------------|----------------------------------------------------------------------------------|
| `server.port` | 监听端口 |
| `collector.ribbon.listOfServers` | collector命名服务地址.(与 `config/application.yml` 中的`naming.jetty`配置保持相同 ),多个Collector地址以`,`分割 |
+| `collector.path` | Collector查询uri. 默认: /graphql |
+| `collector.ribbon.ReadTimeout` | 查询超时时间. 默认: 10 秒 |
+| `security.user.*` | 登录用户名/密码. 默认: admin/admin |
3. 运行 `bin/webappService.sh`
diff --git a/docs/cn/Quick-start-CN.md b/docs/cn/Quick-start-CN.md
index a718cfbf30..1813beca80 100644
--- a/docs/cn/Quick-start-CN.md
+++ b/docs/cn/Quick-start-CN.md
@@ -4,4 +4,5 @@
1. [单机模式](Deploy-backend-in-standalone-mode-CN.md)
1. [集群模式](Deploy-backend-in-cluster-mode-CN.md)
1. 部署 Java Agent,[doc](Deploy-skywalking-agent-CN.md)
-1. 重启并访问系统功能,查看UI即可。
\ No newline at end of file
+1. 重启并访问系统功能,查看UI即可。
+1. 登录页面的默认用户名/密码是`admin/admin`。
\ No newline at end of file
diff --git a/docs/en/Deploy-backend-in-cluster-mode.md b/docs/en/Deploy-backend-in-cluster-mode.md
index d8745b16f0..3cc0a49151 100644
--- a/docs/en/Deploy-backend-in-cluster-mode.md
+++ b/docs/en/Deploy-backend-in-cluster-mode.md
@@ -131,14 +131,16 @@ configuration:
### Set UI
-The config items of UI is saved in `bin/webappService.sh` (`bin\webappService.bat` for windows).
+The config items of UI is saved in `webapp/webapp.yml`.
Change `collector.ribbon.listOfServers` by following the description, with matching `naming.jetty`.
| Config | Description |
|----------------------------------|------------------------------------------------------------------------------------------------------|
| `server.port` | Port to listen on. Default: 8080 |
| `collector.ribbon.listOfServers` | Address to access collector naming service.(Consist with `naming.jetty` in `config/application.yml`). Multiple collector addresses are split by ',' |
-
+| `collector.path` | Collector query uri. Default: /graphql |
+| `collector.ribbon.ReadTimeout` | Query timeout. Default: 10 seconds |
+| `security.user.*` | Login username/password. Default: admin/admin |
### Start up collector node
1. Run `bin/startup.sh` to start collector and UI together.
diff --git a/docs/en/Quick-start.md b/docs/en/Quick-start.md
index e259d36b10..f553453b19 100644
--- a/docs/en/Quick-start.md
+++ b/docs/en/Quick-start.md
@@ -6,6 +6,7 @@ Quick start is for end users to start up the SkyWalking quickly in local.
1. Install Java Agent. [Doc](Deploy-skywalking-agent.md)
1. Set your OS time(include time zone) correct.
1. Reboot your applications, and open UI.
+1. Default username/password for the login page is `admin/admin`.
If you want to deploy SkyWalking in server or cloud as a cluster, please following these two documents:
1. [Install javaagent](Deploy-skywalking-agent.md)