SUBMARINE-1294. Add simple type authentication for REST api
### What is this PR for?
Add simple type authentication for REST api.
Use [pac4j](https://www.pac4j.org/index.html) for token generation and validation. Considering need to adapt to java8, this PR is using 4.5.6 instead of version pac4j 5 for the time being.
### What type of PR is it?
Feature
### Todos
* [x] - Add some configs for authentication
* [x] - Add `SimpleFilter`
* [x] - Modified some login api processing logic (no logout available yet)
* [x] - Add test case
### What is the Jira issue?
https://issues.apache.org/jira/projects/SUBMARINE/issues/SUBMARINE-1294
### How should this be tested?
Have added a test case in `org.apache.submarine.server.security.SubmarineAuthSimpleTest`
### Screenshots (if appropriate)
No
### Questions:
* Do the license files need updating? No
* Are there breaking changes for older versions? Yes
* Does this need new documentation? Yes(link: https://github.com/apache/submarine/pull/975)
Author: cdmikechen <cdmikechen@hotmail.com>
Signed-off-by: Kevin <pingsutw@apache.org>
Closes #979 from cdmikechen/SUBMARINE-1294 and squashes the following commits:
2fff5bdc [cdmikechen] add a test user
b5d9b46c [cdmikechen] get config realtime
7c2b29fe [cdmikechen] init provider
0105bac5 [cdmikechen] remove some test
e0e0c25b [cdmikechen] change pc4j to 4.5.6 for adaptation of java8
909ffa9b [cdmikechen] Fist commit with pc4j 5.4.3 and test case
diff --git a/dev-support/database/submarine-data.sql b/dev-support/database/submarine-data.sql
index 3a767d3..423aee8 100644
--- a/dev-support/database/submarine-data.sql
+++ b/dev-support/database/submarine-data.sql
@@ -53,7 +53,7 @@
-- ----------------------------
-- Records of sys_user
-- ----------------------------
-INSERT INTO `sys_user` VALUES ('e9ca23d68d884d4ebb19d07889727dae', 'admin', 'administrator', '21232f297a57a5a743894a0e4a801fc3', 'avatar.png', '2018-12-05 00:00:00', NULL, 'dev@submarine.org', '18566666661', NULL, NULL, NULL, 1, 'admin', '2019-07-05 14:47:22', 'admin', '2019-07-05 14:47:22');
+INSERT INTO `sys_user` VALUES ('e9ca23d68d884d4ebb19d07889727dae', 'admin', 'administrator', '21232f297a57a5a743894a0e4a801fc3', 'avatar.png', '2018-12-05 00:00:00', NULL, 'dev@submarine.org', '18566666661', NULL, NULL, NULL, 0, 'admin', now(), 'admin', now());
-- ----------------------------
-- Records of team
diff --git a/pom.xml b/pom.xml
index 301decd..ad2f20c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -148,6 +148,8 @@
<!-- server API -->
<protobuf-java.version>3.14.0</protobuf-java.version>
<joda-time.version>2.10.8</joda-time.version>
+ <!-- pac4j -->
+ <pac4j.version>4.5.6</pac4j.version>
</properties>
<modules>
diff --git a/submarine-commons/commons-utils/src/main/java/org/apache/submarine/commons/utils/SubmarineConfVars.java b/submarine-commons/commons-utils/src/main/java/org/apache/submarine/commons/utils/SubmarineConfVars.java
index a96a885..9d1a403 100644
--- a/submarine-commons/commons-utils/src/main/java/org/apache/submarine/commons/utils/SubmarineConfVars.java
+++ b/submarine-commons/commons-utils/src/main/java/org/apache/submarine/commons/utils/SubmarineConfVars.java
@@ -75,7 +75,12 @@
SUBMARINE_SUBMITTER("submarine.submitter", "k8s"),
SUBMARINE_SERVER_SERVICE_NAME("submarine.server.service.name", "submarine-server"),
ENVIRONMENT_CONDA_MIN_VERSION("environment.conda.min.version", "4.0.1"),
- ENVIRONMENT_CONDA_MAX_VERSION("environment.conda.max.version", "4.11.10");
+ ENVIRONMENT_CONDA_MAX_VERSION("environment.conda.max.version", "4.11.10"),
+
+ /* auth */
+ SUBMARINE_AUTH_TYPE("submarine.auth.type", "none"),
+ SUBMARINE_AUTH_DEFAULT_SECRET("submarine.auth.default.secret", "SUBMARINE_SECRET_12345678901234567890"),
+ SUBMARINE_AUTH_MAX_AGE_ENV("submarine.auth.maxAge", 60 * 60 * 24);
private String varName;
@SuppressWarnings("rawtypes")
diff --git a/submarine-server/server-core/pom.xml b/submarine-server/server-core/pom.xml
index f891f5e..d33ff94 100644
--- a/submarine-server/server-core/pom.xml
+++ b/submarine-server/server-core/pom.xml
@@ -427,6 +427,34 @@
<artifactId>joda-time</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.pac4j</groupId>
+ <artifactId>pac4j-http</artifactId>
+ <version>${pac4j.version}</version>
+ <exclusions>
+ <exclusion>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-databind</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
+ <dependency>
+ <groupId>org.pac4j</groupId>
+ <artifactId>pac4j-jwt</artifactId>
+ <version>${pac4j.version}</version>
+ <exclusions>
+ <exclusion>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bcprov-jdk15on</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.ow2.asm</groupId>
+ <artifactId>asm</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
</dependencies>
<build>
diff --git a/submarine-server/server-core/src/main/java/org/apache/submarine/server/SubmarineServer.java b/submarine-server/server-core/src/main/java/org/apache/submarine/server/SubmarineServer.java
index 4eccbb5..4449880 100644
--- a/submarine-server/server-core/src/main/java/org/apache/submarine/server/SubmarineServer.java
+++ b/submarine-server/server-core/src/main/java/org/apache/submarine/server/SubmarineServer.java
@@ -20,6 +20,8 @@
import org.apache.log4j.PropertyConfigurator;
import org.apache.submarine.server.rest.provider.YamlEntityProvider;
+import org.apache.submarine.server.security.SecurityFactory;
+import org.apache.submarine.server.security.SecurityProvider;
import org.apache.submarine.server.workbench.websocket.NotebookServer;
import org.apache.submarine.server.websocket.WebSocketServer;
import org.eclipse.jetty.http.HttpVersion;
@@ -53,6 +55,8 @@
import javax.inject.Inject;
import javax.inject.Singleton;
+import javax.servlet.DispatcherType;
+import javax.servlet.Filter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
@@ -62,6 +66,8 @@
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
+import java.util.EnumSet;
+import java.util.Optional;
public class SubmarineServer extends ResourceConfig {
private static final Logger LOG = LoggerFactory.getLogger(SubmarineServer.class);
@@ -201,6 +207,14 @@
webApp.addServlet(new ServletHolder(RefreshServlet.class), "/user/*");
webApp.addServlet(new ServletHolder(RefreshServlet.class), "/workbench/*");
+ // add security filter
+ Optional<SecurityProvider> securityProvider = SecurityFactory.getSecurityProvider();
+ if (securityProvider.isPresent()) {
+ Class<Filter> filterClass = securityProvider.get().getFilterClass();
+ LOG.info("Add {} to support auth", filterClass);
+ webApp.addFilter(filterClass, "/*", EnumSet.of(DispatcherType.REQUEST));
+ }
+
handlers.setHandlers(new Handler[]{webApp});
return webApp;
diff --git a/submarine-server/server-core/src/main/java/org/apache/submarine/server/rest/workbench/LoginRestApi.java b/submarine-server/server-core/src/main/java/org/apache/submarine/server/rest/workbench/LoginRestApi.java
index 54abc57..f385a99 100644
--- a/submarine-server/server-core/src/main/java/org/apache/submarine/server/rest/workbench/LoginRestApi.java
+++ b/submarine-server/server-core/src/main/java/org/apache/submarine/server/rest/workbench/LoginRestApi.java
@@ -25,6 +25,8 @@
import org.apache.submarine.server.database.workbench.entity.SysUserEntity;
import org.apache.submarine.server.database.workbench.mappers.SysUserMapper;
import org.apache.submarine.server.database.utils.MyBatisUtil;
+import org.apache.submarine.server.security.common.CommonConfig;
+import org.apache.submarine.server.security.simple.SimpleLoginConfig;
import org.apache.submarine.server.utils.response.JsonResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -35,6 +37,7 @@
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Response;
+import java.util.Date;
import java.util.HashMap;
@Path("/auth")
@@ -60,16 +63,61 @@
SysUserMapper sysUserMapper = sqlSession.getMapper(SysUserMapper.class);
sysUser = sysUserMapper.login(mapParams);
if (sysUser != null) {
- sysUser.setToken("mock_token");
+ HashMap<String, Object> claimsMap = new HashMap<>();
+ claimsMap.put("username", sysUser.getUserName());
+ claimsMap.put("realName", sysUser.getRealName());
+ claimsMap.put("password", sysUser.getPassword());
+ claimsMap.put("avatar", sysUser.getAvatar());
+ claimsMap.put("sex", sysUser.getSex());
+ claimsMap.put("status", sysUser.getStatus());
+ claimsMap.put("phone", sysUser.getPhone());
+ claimsMap.put("email", sysUser.getEmail());
+ claimsMap.put("deptCode", sysUser.getDeptCode());
+ claimsMap.put("deptName", sysUser.getDeptName());
+ claimsMap.put("roleCode", sysUser.getRoleCode());
+ claimsMap.put("birthday", sysUser.getBirthday());
+ claimsMap.put("iat", new Date().getTime());
+ claimsMap.put("exp", new Date().getTime() + CommonConfig.MAX_AGE);
+ claimsMap.put("sub", "submarine");
+ claimsMap.put("jti", sysUser.getId());
+
+ String token = SimpleLoginConfig.getJwtGenerator().generate(claimsMap);
+ sysUser.setToken(token);
} else {
- LOG.info("User Not Found. Please try again");
+ LOG.warn("Can not find user {}", mapParams);
+ return new JsonResponse.Builder<>(Response.Status.UNAUTHORIZED)
+ .message("User Not Found. Please try again!")
+ .success(false)
+ .build();
}
} catch (Exception e) {
LOG.error(e.getMessage(), e);
- return new JsonResponse.Builder<>(Response.Status.OK).success(false).build();
+ return new JsonResponse.Builder<>(Response.Status.OK)
+ .message(e.getMessage())
+ .success(false)
+ .build();
}
- return new JsonResponse.Builder<SysUserEntity>(Response.Status.OK).success(true).result(sysUser).build();
+ return new JsonResponse.Builder<SysUserEntity>(Response.Status.OK)
+ .message("Login successfully!")
+ .success(true)
+ .result(sysUser)
+ .build();
+ }
+
+ /**
+ * Get user by unique name
+ */
+ public SysUserEntity getUserByName(String name) throws Exception {
+ SysUserEntity sysUser = null;
+ try (SqlSession sqlSession = MyBatisUtil.getSqlSession()) {
+ SysUserMapper sysUserMapper = sqlSession.getMapper(SysUserMapper.class);
+ sysUser = sysUserMapper.getUserByUniqueName(name);
+ } catch (Exception e) {
+ LOG.error(e.getMessage(), e);
+ throw new Exception(e);
+ }
+ return sysUser;
}
@POST
diff --git a/submarine-server/server-core/src/main/java/org/apache/submarine/server/security/SecurityFactory.java b/submarine-server/server-core/src/main/java/org/apache/submarine/server/security/SecurityFactory.java
new file mode 100644
index 0000000..d223244
--- /dev/null
+++ b/submarine-server/server-core/src/main/java/org/apache/submarine/server/security/SecurityFactory.java
@@ -0,0 +1,63 @@
+/*
+ * 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.submarine.server.security;
+
+import org.apache.submarine.commons.utils.SubmarineConfVars;
+import org.apache.submarine.commons.utils.SubmarineConfiguration;
+import org.apache.submarine.server.security.simple.SimpleSecurityProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+
+public class SecurityFactory {
+
+ private static final Logger LOG = LoggerFactory.getLogger(SecurityFactory.class);
+
+ private static final Map<String, SecurityProvider> providerMap;
+
+ public static SimpleSecurityProvider getSimpleSecurityProvider() {
+ return (SimpleSecurityProvider) providerMap.get("simple");
+ }
+
+ static {
+ // int provider map
+ providerMap = new HashMap<>();
+ providerMap.put("simple", new SimpleSecurityProvider());
+ }
+
+ public static void addProvider(String name, SecurityProvider provider) {
+ providerMap.put(name, provider);
+ }
+
+ public static Optional<SecurityProvider> getSecurityProvider() {
+ String authType = SubmarineConfiguration.getInstance()
+ .getString(SubmarineConfVars.ConfVars.SUBMARINE_AUTH_TYPE);
+ if (providerMap.containsKey(authType)) {
+ return Optional.ofNullable(providerMap.get(authType));
+ } else {
+ LOG.warn("current auth type is {} but we can not recognize, so use none!", authType);
+ return Optional.empty();
+ }
+ }
+
+}
diff --git a/submarine-server/server-core/src/main/java/org/apache/submarine/server/security/SecurityProvider.java b/submarine-server/server-core/src/main/java/org/apache/submarine/server/security/SecurityProvider.java
new file mode 100644
index 0000000..c775705
--- /dev/null
+++ b/submarine-server/server-core/src/main/java/org/apache/submarine/server/security/SecurityProvider.java
@@ -0,0 +1,61 @@
+/*
+ * 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.submarine.server.security;
+
+import org.pac4j.core.config.Config;
+import org.pac4j.core.profile.CommonProfile;
+
+import javax.servlet.Filter;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.Optional;
+
+/**
+ * Provide security methods for different authentication types
+ */
+public interface SecurityProvider<T extends Filter, R extends CommonProfile> {
+
+ String DEFAULT_AUTHORIZER = "isAuthenticated";
+
+ /**
+ * Get filter class
+ */
+ Class<T> getFilterClass();
+
+ /**
+ * Get pac4j config
+ */
+ Config getConfig();
+
+ /**
+ * Get pac4j client
+ */
+ String getClient(HttpServletRequest httpServletRequest);
+
+ /**
+ * Process authentication information and return user profile
+ */
+ Optional<R> perform(HttpServletRequest hsRequest, HttpServletResponse hsResponse);
+
+ /**
+ * Get user profile
+ */
+ Optional<R> getProfile(HttpServletRequest hsRequest, HttpServletResponse hsResponse);
+}
diff --git a/submarine-server/server-core/src/main/java/org/apache/submarine/server/security/common/CommonConfig.java b/submarine-server/server-core/src/main/java/org/apache/submarine/server/security/common/CommonConfig.java
new file mode 100644
index 0000000..83f1bb8
--- /dev/null
+++ b/submarine-server/server-core/src/main/java/org/apache/submarine/server/security/common/CommonConfig.java
@@ -0,0 +1,39 @@
+/*
+ * 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.submarine.server.security.common;
+
+import org.apache.submarine.commons.utils.SubmarineConfiguration;
+
+import static org.apache.submarine.commons.utils.SubmarineConfVars.ConfVars;
+
+public class CommonConfig {
+
+ public static final String LOGOUT_ENDPOINT = "/auth/logout";
+ public static final String AUTH_HEADER = "Authorization";
+ public static final String BEARER_HEADER_PREFIX = "Bearer ";
+
+ public static final int MAX_AGE;
+
+ static {
+ SubmarineConfiguration conf = SubmarineConfiguration.getInstance();
+ MAX_AGE = conf.getInt(ConfVars.SUBMARINE_AUTH_MAX_AGE_ENV);
+ }
+
+}
diff --git a/submarine-server/server-core/src/main/java/org/apache/submarine/server/security/common/CommonFilter.java b/submarine-server/server-core/src/main/java/org/apache/submarine/server/security/common/CommonFilter.java
new file mode 100644
index 0000000..a0a0fdc
--- /dev/null
+++ b/submarine-server/server-core/src/main/java/org/apache/submarine/server/security/common/CommonFilter.java
@@ -0,0 +1,46 @@
+/*
+ * 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.submarine.server.security.common;
+
+import org.pac4j.core.context.JEEContext;
+import org.pac4j.core.context.session.JEESessionStore;
+import org.pac4j.core.context.session.SessionStore;
+import org.pac4j.core.engine.DefaultCallbackLogic;
+import org.pac4j.core.engine.DefaultLogoutLogic;
+import org.pac4j.core.engine.DefaultSecurityLogic;
+import org.pac4j.core.http.adapter.HttpActionAdapter;
+import org.pac4j.core.http.adapter.JEEHttpActionAdapter;
+import org.pac4j.core.profile.CommonProfile;
+import org.pac4j.core.profile.UserProfile;
+
+public class CommonFilter {
+
+ public static final HttpActionAdapter DEFAULT_HTTP_ACTION_ADAPTER = JEEHttpActionAdapter.INSTANCE;
+
+ public static final DefaultCallbackLogic<CommonProfile, JEEContext> CALLBACK_LOGIC =
+ new DefaultCallbackLogic<>();
+
+ public static final DefaultSecurityLogic<UserProfile, JEEContext> SECURITY_LOGIC =
+ new DefaultSecurityLogic<>();
+
+ public static final DefaultLogoutLogic<UserProfile, JEEContext> LOGOUT_LOGIC = new DefaultLogoutLogic<>();
+
+ public static final SessionStore<JEEContext> SESSION_STORE = new JEESessionStore();
+}
diff --git a/submarine-server/server-core/src/main/java/org/apache/submarine/server/security/simple/SimpleFilter.java b/submarine-server/server-core/src/main/java/org/apache/submarine/server/security/simple/SimpleFilter.java
new file mode 100644
index 0000000..4bb9198
--- /dev/null
+++ b/submarine-server/server-core/src/main/java/org/apache/submarine/server/security/simple/SimpleFilter.java
@@ -0,0 +1,75 @@
+/*
+ * 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.submarine.server.security.simple;
+
+import org.apache.submarine.server.security.SecurityFactory;
+import org.apache.submarine.server.security.common.CommonFilter;
+import org.pac4j.jwt.profile.JwtProfile;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.Optional;
+
+/**
+ * Simple authentication
+ * Only users in submarine sys_user table can log in, and user is verified based on token
+ */
+public class SimpleFilter extends CommonFilter implements Filter {
+
+ private static final Logger LOG = LoggerFactory.getLogger(SimpleFilter.class);
+
+ private final SimpleSecurityProvider provider;
+
+ public SimpleFilter() {
+ this.provider = SecurityFactory.getSimpleSecurityProvider();
+ }
+
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException {
+ }
+
+ @Override
+ public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
+ FilterChain filterChain) throws IOException, ServletException {
+ HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
+ HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
+ // check header token
+ Optional<JwtProfile> profile = provider.perform(httpServletRequest, httpServletResponse);
+ // If the token can be correctly parsed then continue processing, otherwise return 401
+ if (profile.isPresent()) {
+ filterChain.doFilter(servletRequest, servletResponse);
+ } else {
+ httpServletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, "The token is not valid.");
+ }
+ }
+
+ @Override
+ public void destroy() {
+ }
+}
diff --git a/submarine-server/server-core/src/main/java/org/apache/submarine/server/security/simple/SimpleLoginConfig.java b/submarine-server/server-core/src/main/java/org/apache/submarine/server/security/simple/SimpleLoginConfig.java
new file mode 100644
index 0000000..e1e2939
--- /dev/null
+++ b/submarine-server/server-core/src/main/java/org/apache/submarine/server/security/simple/SimpleLoginConfig.java
@@ -0,0 +1,55 @@
+/*
+ * 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.submarine.server.security.simple;
+
+import org.apache.submarine.commons.utils.SubmarineConfiguration;
+import org.apache.submarine.server.security.common.CommonConfig;
+import org.pac4j.jwt.config.encryption.SecretEncryptionConfiguration;
+import org.pac4j.jwt.config.signature.SecretSignatureConfiguration;
+import org.pac4j.jwt.credentials.authenticator.JwtAuthenticator;
+import org.pac4j.jwt.profile.JwtGenerator;
+
+import static org.apache.submarine.commons.utils.SubmarineConfVars.ConfVars;
+
+public class SimpleLoginConfig extends CommonConfig {
+
+ private static final String SUBMARINE_SECRET;
+ private static final JwtAuthenticator JWT_AUTHENTICATOR;
+ private static final JwtGenerator JWT_GENERATOR;
+
+ static {
+ SubmarineConfiguration conf = SubmarineConfiguration.getInstance();
+ // Generating the token requires a secret key,
+ // if the user does not provide the secret key, we will use the default secret key
+ SUBMARINE_SECRET = conf.getString(ConfVars.SUBMARINE_AUTH_DEFAULT_SECRET);
+ JWT_AUTHENTICATOR = new JwtAuthenticator(
+ new SecretSignatureConfiguration(SUBMARINE_SECRET),
+ new SecretEncryptionConfiguration(SUBMARINE_SECRET));
+ JWT_GENERATOR = new JwtGenerator(new SecretSignatureConfiguration(SUBMARINE_SECRET));
+ }
+
+ public static JwtAuthenticator getJwtAuthenticator() {
+ return JWT_AUTHENTICATOR;
+ }
+
+ public static JwtGenerator getJwtGenerator() {
+ return JWT_GENERATOR;
+ }
+}
diff --git a/submarine-server/server-core/src/main/java/org/apache/submarine/server/security/simple/SimpleSecurityProvider.java b/submarine-server/server-core/src/main/java/org/apache/submarine/server/security/simple/SimpleSecurityProvider.java
new file mode 100644
index 0000000..3a35166
--- /dev/null
+++ b/submarine-server/server-core/src/main/java/org/apache/submarine/server/security/simple/SimpleSecurityProvider.java
@@ -0,0 +1,102 @@
+/*
+ * 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.submarine.server.security.simple;
+
+import org.apache.submarine.server.security.SecurityProvider;
+import org.apache.submarine.server.security.common.CommonConfig;
+import org.apache.submarine.server.security.common.CommonFilter;
+import org.pac4j.core.config.Config;
+import org.pac4j.core.context.JEEContext;
+import org.pac4j.core.matching.matcher.PathMatcher;
+import org.pac4j.core.profile.ProfileManager;
+import org.pac4j.core.profile.UserProfile;
+import org.pac4j.http.client.direct.HeaderClient;
+import org.pac4j.jwt.profile.JwtProfile;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.Collection;
+import java.util.Optional;
+
+public class SimpleSecurityProvider implements SecurityProvider<SimpleFilter, JwtProfile> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(SimpleSecurityProvider.class);
+
+ private Config pac4jConfig;
+
+ @Override
+ public Class<SimpleFilter> getFilterClass() {
+ return SimpleFilter.class;
+ }
+
+ @Override
+ public Config getConfig() {
+ if (pac4jConfig != null) {
+ return pac4jConfig;
+ }
+
+ // header client
+ HeaderClient headerClient = new HeaderClient(CommonConfig.AUTH_HEADER, CommonConfig.BEARER_HEADER_PREFIX,
+ SimpleLoginConfig.getJwtAuthenticator());
+
+ Config pac4jConfig = new Config(headerClient);
+ // skip web static resources
+ pac4jConfig.addMatcher("static", new PathMatcher().excludeRegex(
+ "^/.*(\\.map|\\.js|\\.css|\\.ico|\\.svg|\\.png|\\.html|\\.htm)$"));
+ // skip login rest api
+ pac4jConfig.addMatcher("api", new PathMatcher().excludeRegex("^/api/auth/login$"));
+ this.pac4jConfig = pac4jConfig;
+
+ return pac4jConfig;
+ }
+
+ @Override
+ public String getClient(HttpServletRequest httpServletRequest) {
+ return "HeaderClient";
+ }
+
+ @Override
+ public Optional<JwtProfile> perform(HttpServletRequest hsRequest, HttpServletResponse hsResponse) {
+ JEEContext context = new JEEContext(hsRequest, hsResponse, CommonFilter.SESSION_STORE);
+ UserProfile profile = CommonFilter.SECURITY_LOGIC.perform(
+ context,
+ pac4jConfig,
+ (JEEContext ctx, Collection<UserProfile> profiles, Object... parameters) -> {
+ if (profiles.isEmpty()) {
+ LOG.warn("No profiles found with default auth.");
+ return null;
+ } else {
+ return profiles.iterator().next();
+ }
+ },
+ CommonFilter.DEFAULT_HTTP_ACTION_ADAPTER,
+ getClient(hsRequest), DEFAULT_AUTHORIZER, "static,api", null);
+ return Optional.ofNullable((JwtProfile) profile);
+ }
+
+ @Override
+ public Optional<JwtProfile> getProfile(HttpServletRequest hsRequest, HttpServletResponse hsResponse) {
+ JEEContext context = new JEEContext(hsRequest, hsResponse, CommonFilter.SESSION_STORE);
+ ProfileManager<JwtProfile> manager = new ProfileManager<>(context);
+ return manager.get(true);
+ }
+}
diff --git a/submarine-server/server-core/src/test/java/org/apache/submarine/server/security/MockHttpServletRequest.java b/submarine-server/server-core/src/test/java/org/apache/submarine/server/security/MockHttpServletRequest.java
new file mode 100644
index 0000000..49d8e04
--- /dev/null
+++ b/submarine-server/server-core/src/test/java/org/apache/submarine/server/security/MockHttpServletRequest.java
@@ -0,0 +1,409 @@
+/*
+ * 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.submarine.server.security;
+
+import javax.servlet.AsyncContext;
+import javax.servlet.DispatcherType;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletInputStream;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import javax.servlet.http.HttpUpgradeHandler;
+import javax.servlet.http.Part;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.security.Principal;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+public class MockHttpServletRequest implements HttpServletRequest {
+
+ @Override
+ public String getAuthType() {
+ return null;
+ }
+
+ @Override
+ public Cookie[] getCookies() {
+ return new Cookie[0];
+ }
+
+ @Override
+ public long getDateHeader(String name) {
+ return 0;
+ }
+
+ private final HashMap<String, String> headers = new HashMap<>();
+
+ @Override
+ public String getHeader(String name) {
+ return headers.get(name);
+ }
+
+ @Override
+ public Enumeration<String> getHeaders(String name) {
+ return Collections.enumeration(Collections.singleton(headers.get(name)));
+ }
+
+ public void setHeader(String name, String value) {
+ headers.put(name, value);
+ }
+
+ @Override
+ public Enumeration<String> getHeaderNames() {
+ return Collections.enumeration(headers.keySet());
+ }
+
+ @Override
+ public int getIntHeader(String name) {
+ return 0;
+ }
+
+ @Override
+ public String getMethod() {
+ return null;
+ }
+
+ @Override
+ public String getPathInfo() {
+ return null;
+ }
+
+ @Override
+ public String getPathTranslated() {
+ return null;
+ }
+
+ @Override
+ public String getContextPath() {
+ return null;
+ }
+
+ @Override
+ public String getQueryString() {
+ return null;
+ }
+
+ @Override
+ public String getRemoteUser() {
+ return null;
+ }
+
+ @Override
+ public boolean isUserInRole(String role) {
+ return false;
+ }
+
+ @Override
+ public Principal getUserPrincipal() {
+ return null;
+ }
+
+ @Override
+ public String getRequestedSessionId() {
+ return null;
+ }
+
+ @Override
+ public String getRequestURI() {
+ return null;
+ }
+
+ private StringBuffer requestUrl;
+
+ @Override
+ public StringBuffer getRequestURL() {
+ return requestUrl;
+ }
+
+ public void setRequestURL(StringBuffer requestUrl) {
+ this.requestUrl = requestUrl;
+ }
+
+ @Override
+ public String getServletPath() {
+ return null;
+ }
+
+ @Override
+ public HttpSession getSession(boolean create) {
+ return null;
+ }
+
+ @Override
+ public HttpSession getSession() {
+ return null;
+ }
+
+ @Override
+ public String changeSessionId() {
+ return null;
+ }
+
+ @Override
+ public boolean isRequestedSessionIdValid() {
+ return false;
+ }
+
+ @Override
+ public boolean isRequestedSessionIdFromCookie() {
+ return false;
+ }
+
+ @Override
+ public boolean isRequestedSessionIdFromURL() {
+ return false;
+ }
+
+ @Override
+ public boolean isRequestedSessionIdFromUrl() {
+ return false;
+ }
+
+ @Override
+ public boolean authenticate(HttpServletResponse response) throws IOException, ServletException {
+ return false;
+ }
+
+ @Override
+ public void login(String username, String password) throws ServletException {
+
+ }
+
+ @Override
+ public void logout() throws ServletException {
+
+ }
+
+ @Override
+ public Collection<Part> getParts() throws IOException, ServletException {
+ return null;
+ }
+
+ @Override
+ public Part getPart(String name) throws IOException, ServletException {
+ return null;
+ }
+
+ @Override
+ public <T extends HttpUpgradeHandler> T upgrade(Class<T> handlerClass)
+ throws IOException, ServletException {
+ return null;
+ }
+
+ @Override
+ public String getCharacterEncoding() {
+ return null;
+ }
+
+ @Override
+ public void setCharacterEncoding(String env) throws UnsupportedEncodingException {
+
+ }
+
+ @Override
+ public int getContentLength() {
+ return 0;
+ }
+
+ @Override
+ public long getContentLengthLong() {
+ return 0;
+ }
+
+ @Override
+ public String getContentType() {
+ return null;
+ }
+
+ @Override
+ public ServletInputStream getInputStream() throws IOException {
+ return null;
+ }
+
+ @Override
+ public String getParameter(String name) {
+ return null;
+ }
+
+ @Override
+ public Enumeration<String> getParameterNames() {
+ return null;
+ }
+
+ @Override
+ public String[] getParameterValues(String name) {
+ return new String[0];
+ }
+
+ @Override
+ public Map<String, String[]> getParameterMap() {
+ return null;
+ }
+
+ @Override
+ public String getProtocol() {
+ return null;
+ }
+
+ @Override
+ public String getScheme() {
+ return null;
+ }
+
+ @Override
+ public String getServerName() {
+ return null;
+ }
+
+ @Override
+ public int getServerPort() {
+ return 0;
+ }
+
+ @Override
+ public BufferedReader getReader() throws IOException {
+ return null;
+ }
+
+ @Override
+ public String getRemoteAddr() {
+ return null;
+ }
+
+ @Override
+ public String getRemoteHost() {
+ return null;
+ }
+
+ private Map<String, Object> attributes = new HashMap<>();
+
+ @Override
+ public Object getAttribute(String name) {
+ return attributes.get(name);
+ }
+
+ @Override
+ public Enumeration<String> getAttributeNames() {
+ return Collections.enumeration(attributes.keySet());
+ }
+
+ @Override
+ public void setAttribute(String name, Object o) {
+ attributes.put(name, o);
+ }
+
+ @Override
+ public void removeAttribute(String name) {
+ attributes.remove(name);
+ }
+
+ @Override
+ public Locale getLocale() {
+ return null;
+ }
+
+ @Override
+ public Enumeration<Locale> getLocales() {
+ return null;
+ }
+
+ @Override
+ public boolean isSecure() {
+ return false;
+ }
+
+ @Override
+ public RequestDispatcher getRequestDispatcher(String path) {
+ return null;
+ }
+
+ @Override
+ public String getRealPath(String path) {
+ return null;
+ }
+
+ @Override
+ public int getRemotePort() {
+ return 0;
+ }
+
+ @Override
+ public String getLocalName() {
+ return null;
+ }
+
+ @Override
+ public String getLocalAddr() {
+ return null;
+ }
+
+ @Override
+ public int getLocalPort() {
+ return 0;
+ }
+
+ @Override
+ public ServletContext getServletContext() {
+ return null;
+ }
+
+ @Override
+ public AsyncContext startAsync() throws IllegalStateException {
+ return null;
+ }
+
+ @Override
+ public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse)
+ throws IllegalStateException {
+ return null;
+ }
+
+ @Override
+ public boolean isAsyncStarted() {
+ return false;
+ }
+
+ @Override
+ public boolean isAsyncSupported() {
+ return false;
+ }
+
+ @Override
+ public AsyncContext getAsyncContext() {
+ return null;
+ }
+
+ @Override
+ public DispatcherType getDispatcherType() {
+ return null;
+ }
+}
diff --git a/submarine-server/server-core/src/test/java/org/apache/submarine/server/security/SubmarineAuthSimpleTest.java b/submarine-server/server-core/src/test/java/org/apache/submarine/server/security/SubmarineAuthSimpleTest.java
new file mode 100644
index 0000000..b86b7b5
--- /dev/null
+++ b/submarine-server/server-core/src/test/java/org/apache/submarine/server/security/SubmarineAuthSimpleTest.java
@@ -0,0 +1,146 @@
+/*
+ * 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.submarine.server.security;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.reflect.TypeToken;
+import org.apache.submarine.commons.utils.SubmarineConfVars;
+import org.apache.submarine.commons.utils.SubmarineConfiguration;
+import org.apache.submarine.server.api.environment.EnvironmentId;
+import org.apache.submarine.server.database.workbench.entity.SysUserEntity;
+import org.apache.submarine.server.rest.workbench.LoginRestApi;
+import org.apache.submarine.server.rest.workbench.SysUserRestApi;
+import org.apache.submarine.server.security.simple.SimpleFilter;
+import org.apache.submarine.server.utils.gson.EnvironmentIdDeserializer;
+import org.apache.submarine.server.utils.gson.EnvironmentIdSerializer;
+import org.apache.submarine.server.utils.response.JsonResponse;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.pac4j.core.config.Config;
+import org.pac4j.core.util.Pac4jConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.core.Response;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.lang.reflect.Type;
+import java.util.Optional;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class SubmarineAuthSimpleTest {
+
+ private static final SubmarineConfiguration conf = SubmarineConfiguration.getInstance();
+
+ private static final GsonBuilder gsonBuilder = new GsonBuilder()
+ .registerTypeAdapter(EnvironmentId.class, new EnvironmentIdSerializer())
+ .registerTypeAdapter(EnvironmentId.class, new EnvironmentIdDeserializer());
+ private static final Gson gson = gsonBuilder.setDateFormat("yyyy-MM-dd HH:mm:ss").create();
+
+ private static final Logger LOG = LoggerFactory.getLogger(SubmarineAuthSimpleTest.class);
+
+ private static LoginRestApi loginRestApi;
+ private static SysUserRestApi sysUserRestApi;
+
+ @Before
+ public void before() {
+ conf.updateConfiguration("submarine.auth.type", "simple");
+ conf.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/submarine_test?" +
+ "useUnicode=true&" +
+ "characterEncoding=UTF-8&" +
+ "autoReconnect=true&" +
+ "failOverReadOnly=false&" +
+ "zeroDateTimeBehavior=convertToNull&" +
+ "useSSL=false");
+ conf.setJdbcUserName("submarine_test");
+ conf.setJdbcPassword("password_test");
+ loginRestApi = new LoginRestApi();
+ // add a test user
+ sysUserRestApi = new SysUserRestApi();
+ SysUserEntity user = new SysUserEntity();
+ user.setUserName("test");
+ user.setRealName("test");
+ user.setPassword("test");
+ user.setDeleted(0);
+ sysUserRestApi.add(user);
+ }
+
+ @Test
+ public void testSimpleType() throws ServletException, IOException {
+ // test auth type config
+ String authType = conf.getString(SubmarineConfVars.ConfVars.SUBMARINE_AUTH_TYPE);
+ assertEquals(authType, "simple");
+
+ // test provider
+ Optional<SecurityProvider> providerOptional = SecurityFactory.getSecurityProvider();
+ SecurityProvider provider = providerOptional.get();
+ assertNotNull(provider);
+ assertEquals(provider.getFilterClass(), SimpleFilter.class);
+ Config config = provider.getConfig();
+ assertTrue(config.getClients().findClient("headerClient").isPresent());
+
+ // test login api
+ String testUsrJson = "{\"username\":\"test\",\"password\":\"test\"}";
+ Response loginResp = loginRestApi.login(testUsrJson);
+ assertEquals(loginResp.getStatus(), Response.Status.OK.getStatusCode());
+ String entity = (String) loginResp.getEntity();
+ Type type = new TypeToken<JsonResponse<SysUserEntity>>() { }.getType();
+ JsonResponse<SysUserEntity> jsonResponse = gson.fromJson(entity, type);
+ String token = jsonResponse.getResult().getToken();
+ LOG.info("Get user token: " + token);
+
+ // create filter involved objects
+ // 1. test filter
+ SimpleFilter filterTest = new SimpleFilter();
+ filterTest.init(null);
+ // 2. filter chain
+ FilterChain mockFilterChain = Mockito.mock(FilterChain.class);
+ // 3. http request
+ MockHttpServletRequest mockRequest = new MockHttpServletRequest();
+ mockRequest.setRequestURL(new StringBuffer("/test/url"));
+ // 4. http response
+ HttpServletResponse mockResponse = Mockito.mock(HttpServletResponse.class);
+ StringWriter out = new StringWriter();
+ PrintWriter printOut = new PrintWriter(out);
+ when(mockResponse.getWriter()).thenReturn(printOut);
+
+ // test no header
+ filterTest.doFilter(mockRequest, mockResponse, mockFilterChain);
+ verify(mockResponse).sendError(HttpServletResponse.SC_UNAUTHORIZED, "The token is not valid.");
+
+ // test header
+ mockRequest.setHeader("Authorization", "Bearer " + token);
+ filterTest.doFilter(mockRequest, mockResponse, mockFilterChain);
+ verify(mockFilterChain).doFilter(mockRequest, mockResponse);
+ assertNotNull(mockRequest.getAttribute(Pac4jConstants.USER_PROFILES));
+ }
+
+}
diff --git a/submarine-server/server-core/src/test/resources/log4j.properties b/submarine-server/server-core/src/test/resources/log4j.properties
new file mode 100644
index 0000000..bef97ca
--- /dev/null
+++ b/submarine-server/server-core/src/test/resources/log4j.properties
@@ -0,0 +1,20 @@
+# 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. See accompanying LICENSE file.
+log4j.rootLogger = info, stdout
+
+log4j.appender.stdout = org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.Target = System.out
+log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n
+
+log4j.logger.org.apache.submarine = debug
+log4j.logger.org.pac4j = debug
diff --git a/submarine-server/server-database/src/main/java/org/apache/submarine/server/database/workbench/mappers/SysUserMapper.java b/submarine-server/server-database/src/main/java/org/apache/submarine/server/database/workbench/mappers/SysUserMapper.java
index 1528566..b0493fc 100644
--- a/submarine-server/server-database/src/main/java/org/apache/submarine/server/database/workbench/mappers/SysUserMapper.java
+++ b/submarine-server/server-database/src/main/java/org/apache/submarine/server/database/workbench/mappers/SysUserMapper.java
@@ -31,7 +31,11 @@
void add(SysUserEntity sysOrg);
- SysUserEntity getById(String id);
+ SysUserEntity getUserByName(Map<String, String> where);
+
+ void activeUser(String id);
+
+ SysUserEntity getUserByUniqueName(String name);
void updateBy(SysUserEntity sysUser);
diff --git a/submarine-server/server-database/src/main/resources/org/apache/submarine/database/mappers/SysUserMapper.xml b/submarine-server/server-database/src/main/resources/org/apache/submarine/database/mappers/SysUserMapper.xml
index f4b6f88..49c4e9e 100644
--- a/submarine-server/server-database/src/main/resources/org/apache/submarine/database/mappers/SysUserMapper.xml
+++ b/submarine-server/server-database/src/main/resources/org/apache/submarine/database/mappers/SysUserMapper.xml
@@ -50,7 +50,15 @@
</select>
<select id="login" parameterType="java.util.Map" resultMap="resultMap">
- SELECT * FROM sys_user WHERE user_name = #{username} AND password = #{password}
+ SELECT * FROM sys_user WHERE user_name = #{username} AND password = #{password} AND deleted = 0
+ </select>
+
+ <update id="activeUser" parameterType="String">
+ UPDATE sys_user SET delete = 0 where id = #{id}
+ </update>
+
+ <select id="getUserByUniqueName" parameterType="String" resultMap="resultMap">
+ SELECT * FROM sys_user WHERE user_name = #{mapParams.name}
</select>
<insert id="add" parameterType="org.apache.submarine.server.database.workbench.entity.SysUserEntity">