Change default port (#316)
diff --git a/README.md b/README.md
index bd45c64..04792db 100644
--- a/README.md
+++ b/README.md
@@ -164,7 +164,10 @@
If you are deploying Pulsar Manager using the latest code, you can create a super-user using the following command. Then you can use the super user credentials to log in the Pulsar Manager UI.
```$xslt
+ CSRF_TOKEN=$(curl http://backend-service:7750/pulsar-manager/csrf-token)
curl \
+ -H 'X-XSRF-TOKEN: $CSRF_TOKEN' \
+ -H 'Cookie: XSRF-TOKEN=$CSRF_TOKEN;' \
-H "Content-Type: application/json" \
-X PUT http://backend-service:7750/pulsar-manager/users/superuser \
-d '{"name": "admin", "password": "apachepulsar", "description": "test", "email": "username@test.org"}'
diff --git a/build.gradle b/build.gradle
index b856ed3..786039c 100644
--- a/build.gradle
+++ b/build.gradle
@@ -142,6 +142,8 @@
compile group: 'org.glassfish.jersey.core', name: 'jersey-client', version: jerseyVersion
compile group: 'org.glassfish.jersey.inject', name: 'jersey-hk2', version: jerseyVersion
compile group: 'org.glassfish.jersey.media', name: 'jersey-media-json-jackson', version: jerseyVersion
+ compile group: 'org.springframework.boot', name: 'spring-boot-starter-security'
+ compile group: 'org.springframework.security', name: 'spring-security-config'
compileOnly group: 'org.projectlombok', name: 'lombok', version: lombokVersion
compileOnly group: 'org.springframework.boot', name: 'spring-boot-devtools', version: springBootVersion
testCompile group: 'org.springframework.boot', name: 'spring-boot-starter-test', version: springBootVersion
diff --git a/front-end/src/api/tokens.js b/front-end/src/api/tokens.js
index 4844cf2..0e7af41 100644
--- a/front-end/src/api/tokens.js
+++ b/front-end/src/api/tokens.js
@@ -56,3 +56,10 @@
method: 'get'
})
}
+
+export function getCsrfToken() {
+ return request({
+ url: SPRING_BASE_URL + '/csrf-token',
+ method: 'get'
+ })
+}
diff --git a/front-end/src/store/modules/user.js b/front-end/src/store/modules/user.js
index 0bae227..b2acd3c 100644
--- a/front-end/src/store/modules/user.js
+++ b/front-end/src/store/modules/user.js
@@ -15,6 +15,7 @@
import { getToken, setToken, removeToken } from '@/utils/auth'
import { setName, removeName } from '@/utils/username'
import { removeEnvironment } from '@/utils/environment'
+import { removeCsrfToken } from '@/utils/csrfToken'
import { Message } from 'element-ui'
import { setTenant, removeTenant } from '../../utils/tenant'
import { getUserInfo } from '@/api/users'
@@ -104,6 +105,7 @@
commit('SET_TOKEN', '')
commit('SET_ROLES', [])
removeToken()
+ removeCsrfToken()
removeName()
removeTenant()
removeEnvironment()
diff --git a/front-end/src/utils/csrfToken.js b/front-end/src/utils/csrfToken.js
new file mode 100644
index 0000000..d9014cf
--- /dev/null
+++ b/front-end/src/utils/csrfToken.js
@@ -0,0 +1,28 @@
+/*
+ * Licensed 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.
+ */
+import Cookies from 'js-cookie'
+
+const csrfToken = 'XSRF-TOKEN'
+
+export function getCsrfToken() {
+ return Cookies.get(csrfToken)
+}
+
+export function setCsrfToken(csrfToken) {
+ return Cookies.set(csrfToken, csrfToken)
+}
+
+export function removeCsrfToken() {
+ return Cookies.remove(csrfToken)
+}
diff --git a/front-end/src/utils/request.js b/front-end/src/utils/request.js
index 1f971ee..1a55e73 100644
--- a/front-end/src/utils/request.js
+++ b/front-end/src/utils/request.js
@@ -20,6 +20,7 @@
import { getEnvironment } from '@/utils/environment'
import { getTenant } from '@/utils/tenant'
import router from '../router'
+import { getCsrfToken } from '@/utils/csrfToken'
// create an axios instance
const service = axios.create({
@@ -37,6 +38,7 @@
config.headers['username'] = getName()
config.headers['tenant'] = getTenant()
config.headers['environment'] = getEnvironment()
+ config.headers['X-XSRF-TOKEN'] = getCsrfToken()
return config
},
error => {
diff --git a/front-end/src/views/login/index.vue b/front-end/src/views/login/index.vue
index f94bb63..f4b79c3 100644
--- a/front-end/src/views/login/index.vue
+++ b/front-end/src/views/login/index.vue
@@ -72,6 +72,8 @@
<script>
import LangSelect from '@/components/LangSelect'
import SocialSign from './socialsignin'
+import { getCsrfToken } from '@/api/tokens'
+import { setCsrfToken } from '@/utils/csrfToken'
export default {
name: 'Login',
@@ -118,6 +120,7 @@
},
created() {
// window.addEventListener('hashchange', this.afterQRScan)
+ this.fetchCsrfToken()
},
destroyed() {
window.removeEventListener('hashchange', this.afterQRScan)
@@ -172,6 +175,11 @@
// this.$router.push({ path: '/' })
// })
// }
+ },
+ fetchCsrfToken() {
+ getCsrfToken().then(response => {
+ setCsrfToken(response.headers['x-csrf-token'])
+ })
}
}
}
diff --git a/src/main/java/org/apache/pulsar/manager/controller/CsrfTokenController.java b/src/main/java/org/apache/pulsar/manager/controller/CsrfTokenController.java
new file mode 100644
index 0000000..535b3dc
--- /dev/null
+++ b/src/main/java/org/apache/pulsar/manager/controller/CsrfTokenController.java
@@ -0,0 +1,39 @@
+/**
+ * Licensed 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.pulsar.manager.controller;
+
+import io.swagger.annotations.Api;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.web.csrf.CsrfToken;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+import javax.servlet.http.HttpServletRequest;
+
+@RestController
+@RequestMapping(value = "/pulsar-manager")
+@Api(description = "Generate csrf token for per page.")
+public class CsrfTokenController {
+
+ @RequestMapping(value="/csrf-token", method= RequestMethod.GET)
+ public ResponseEntity<String> getCsrfToken(HttpServletRequest request) {
+ CsrfToken token = (CsrfToken)request.getAttribute(CsrfToken.class.getName());
+ HttpHeaders headers = new HttpHeaders();
+ headers.add("X-Csrf-Token", token.getToken());
+ return new ResponseEntity<> (token.getToken(), headers, HttpStatus.OK);
+ }
+
+}
diff --git a/src/main/java/org/apache/pulsar/manager/interceptor/AdminHandlerInterceptor.java b/src/main/java/org/apache/pulsar/manager/interceptor/AdminHandlerInterceptor.java
index 433e5d0..0d630d0 100644
--- a/src/main/java/org/apache/pulsar/manager/interceptor/AdminHandlerInterceptor.java
+++ b/src/main/java/org/apache/pulsar/manager/interceptor/AdminHandlerInterceptor.java
@@ -15,7 +15,6 @@
import com.google.common.collect.Maps;
import com.google.gson.Gson;
-import org.apache.commons.lang.StringUtils;
import org.apache.pulsar.manager.entity.EnvironmentEntity;
import org.apache.pulsar.manager.entity.EnvironmentsRepository;
import org.apache.pulsar.manager.entity.UserInfoEntity;
@@ -27,13 +26,11 @@
import org.springframework.beans.factory.annotation.Value;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
-import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import javax.validation.Valid;
import java.util.Map;
import java.util.Optional;
@@ -64,8 +61,9 @@
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// allow frontend requests, in case of front-end running on the same process of backend
- if (request.getRequestURI().startsWith("/ui")
- || request.getRequestURI().startsWith("/static")) {
+
+ if (request.getServletPath().startsWith("/ui")
+ || request.getServletPath().startsWith("/static")) {
return true;
}
String token = request.getHeader("token");
@@ -95,11 +93,11 @@
return false;
}
}
- String requestUri = request.getRequestURI();
+ String requestUri = request.getServletPath();
if (!requestUri.equals("/pulsar-manager/users/userInfo")) {
String environment = request.getHeader("environment");
Optional<EnvironmentEntity> environmentEntityOptional = environmentsRepository.findByName(environment);
- if (!request.getRequestURI().startsWith("/pulsar-manager/environments") && !environmentEntityOptional.isPresent()) {
+ if (!request.getServletPath().startsWith("/pulsar-manager/environments") && !environmentEntityOptional.isPresent()) {
map.put("message", "Currently there is no active environment, please set one");
response.setStatus(400);
response.getWriter().append(gson.toJson(map));
diff --git a/src/main/java/org/apache/pulsar/manager/interceptor/WebAppConfigurer.java b/src/main/java/org/apache/pulsar/manager/interceptor/WebAppConfigurer.java
index 0c97479..a70a2a5 100644
--- a/src/main/java/org/apache/pulsar/manager/interceptor/WebAppConfigurer.java
+++ b/src/main/java/org/apache/pulsar/manager/interceptor/WebAppConfigurer.java
@@ -35,6 +35,7 @@
registry.addInterceptor(adminHandlerInterceptor).addPathPatterns("/**")
.excludePathPatterns("/pulsar-manager/login")
.excludePathPatterns("/pulsar-manager/users/superuser")
+ .excludePathPatterns("/pulsar-manager/csrf-token")
.excludePathPatterns("/pulsar-manager/third-party-login/**")
// static front-end resources
.excludePathPatterns("/ui")
diff --git a/src/main/java/org/apache/pulsar/manager/security/SecurityConfig.java b/src/main/java/org/apache/pulsar/manager/security/SecurityConfig.java
new file mode 100644
index 0000000..a2f476d
--- /dev/null
+++ b/src/main/java/org/apache/pulsar/manager/security/SecurityConfig.java
@@ -0,0 +1,33 @@
+/**
+ * Licensed 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.pulsar.manager.security;
+
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
+
+/**
+ * Security Config.
+ */
+@SuppressWarnings("unchecked")
+@EnableWebSecurity
+public class SecurityConfig extends WebSecurityConfigurerAdapter {
+
+ @Override
+ public void configure(HttpSecurity http) throws Exception {
+ http.csrf()
+ .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());;
+ }
+}
diff --git a/src/main/java/org/apache/pulsar/manager/zuul/EnvironmentForward.java b/src/main/java/org/apache/pulsar/manager/zuul/EnvironmentForward.java
index d3336c0..da0d8cc 100644
--- a/src/main/java/org/apache/pulsar/manager/zuul/EnvironmentForward.java
+++ b/src/main/java/org/apache/pulsar/manager/zuul/EnvironmentForward.java
@@ -83,7 +83,8 @@
HttpServletRequest request = ctx.getRequest();
String redirect = request.getParameter("redirect");
- String requestUri = request.getRequestURI();
+ String requestUri = request.getServletPath();
+ request.getServletPath();
String token = request.getHeader("token");
if (!rolesService.isSuperUser(token)) {
@@ -129,17 +130,17 @@
}
private Object forwardRequest(RequestContext ctx, HttpServletRequest request, String serviceUrl) {
- ctx.put(REQUEST_URI_KEY, request.getRequestURI());
+ ctx.put(REQUEST_URI_KEY, request.getServletPath());
try {
Map<String, String> authHeader = pulsarAdminService.getAuthHeader(serviceUrl);
authHeader.entrySet().forEach(entry -> ctx.addZuulRequestHeader(entry.getKey(), entry.getValue()));
ctx.setRouteHost(new URL(serviceUrl));
- pulsarEvent.parsePulsarEvent(request.getRequestURI(), request);
+ pulsarEvent.parsePulsarEvent(request.getServletPath(), request);
log.info("Forward request to {} @ path {}",
- serviceUrl, request.getRequestURI());
+ serviceUrl, request.getServletPath());
} catch (MalformedURLException e) {
log.error("Route forward to {} path {} error: {}",
- serviceUrl, request.getRequestURI(), e.getMessage());
+ serviceUrl, request.getServletPath(), e.getMessage());
}
return null;
}
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index 46e0462..31a07b1 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -13,7 +13,7 @@
#
spring.cloud.refresh.refreshable=none
-server.port=8080
+server.port=7750
# configuration log
logging.path=