[ISSUE#5696] Fix auth server type (#7004)
* Add MySQL DataBase * Add Derby Database * Replace Auth Server * Revise: change to AuthSystemType
This commit is contained in:
parent
fea9d7271b
commit
e3b7f0e79f
@ -16,10 +16,10 @@
|
|||||||
|
|
||||||
package com.alibaba.nacos.address.auth;
|
package com.alibaba.nacos.address.auth;
|
||||||
|
|
||||||
import com.alibaba.nacos.auth.AuthManager;
|
import com.alibaba.nacos.auth.AuthService;
|
||||||
|
import com.alibaba.nacos.auth.context.IdentityContext;
|
||||||
import com.alibaba.nacos.auth.exception.AccessException;
|
import com.alibaba.nacos.auth.exception.AccessException;
|
||||||
import com.alibaba.nacos.auth.model.Permission;
|
import com.alibaba.nacos.auth.model.Permission;
|
||||||
import com.alibaba.nacos.auth.model.User;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Address server auth manager.
|
* Address server auth manager.
|
||||||
@ -28,21 +28,22 @@ import com.alibaba.nacos.auth.model.User;
|
|||||||
*
|
*
|
||||||
* @author xiweng.yy
|
* @author xiweng.yy
|
||||||
*/
|
*/
|
||||||
public class AddressServerAuthManager implements AuthManager {
|
public class AddressServerAuthManager implements AuthService {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public User login(Object request) throws AccessException {
|
public IdentityContext login(IdentityContext identityContext) throws AccessException {
|
||||||
User result = new User();
|
IdentityContext result = new IdentityContext();
|
||||||
result.setUserName("nacos");
|
identityContext.setParameter("username", "nacos");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public User loginRemote(Object request) throws AccessException {
|
public Boolean authorityAccess(IdentityContext identityContext, Permission permission) throws AccessException {
|
||||||
return null;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void auth(Permission permission, User user) throws AccessException {
|
public String getAuthServiceName() {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
package com.alibaba.nacos.address.configuration;
|
package com.alibaba.nacos.address.configuration;
|
||||||
|
|
||||||
import com.alibaba.nacos.address.auth.AddressServerAuthManager;
|
import com.alibaba.nacos.address.auth.AddressServerAuthManager;
|
||||||
import com.alibaba.nacos.auth.AuthManager;
|
import com.alibaba.nacos.auth.AuthService;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
@ -31,8 +31,8 @@ import org.springframework.context.annotation.Configuration;
|
|||||||
public class AddressServerSpringConfiguration {
|
public class AddressServerSpringConfiguration {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnMissingBean(value = AuthManager.class)
|
@ConditionalOnMissingBean(value = AuthService.class)
|
||||||
public AuthManager getAuthManager() {
|
public AuthService getAuthService() {
|
||||||
return new AddressServerAuthManager();
|
return new AddressServerAuthManager();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,8 @@ import org.springframework.web.cors.CorsUtils;
|
|||||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||||
public class NacosAuthConfig extends WebSecurityConfigurerAdapter {
|
public class NacosAuthConfig extends WebSecurityConfigurerAdapter {
|
||||||
|
|
||||||
|
public static final String NACOS_IDENTITY_KEY = "identity";
|
||||||
|
|
||||||
public static final String AUTHORIZATION_HEADER = "Authorization";
|
public static final String AUTHORIZATION_HEADER = "Authorization";
|
||||||
|
|
||||||
public static final String SECURITY_IGNORE_URLS_SPILT_CHAR = ",";
|
public static final String SECURITY_IGNORE_URLS_SPILT_CHAR = ",";
|
||||||
@ -90,6 +92,8 @@ public class NacosAuthConfig extends WebSecurityConfigurerAdapter {
|
|||||||
ignoreUrls = DEFAULT_ALL_PATH_PATTERN;
|
ignoreUrls = DEFAULT_ALL_PATH_PATTERN;
|
||||||
} else if (AuthSystemTypes.LDAP.name().equalsIgnoreCase(authConfigs.getNacosAuthSystemType())) {
|
} else if (AuthSystemTypes.LDAP.name().equalsIgnoreCase(authConfigs.getNacosAuthSystemType())) {
|
||||||
ignoreUrls = DEFAULT_ALL_PATH_PATTERN;
|
ignoreUrls = DEFAULT_ALL_PATH_PATTERN;
|
||||||
|
} else if (AuthSystemTypes.USERNAME_PASSWORD.name().equalsIgnoreCase(authConfigs.getNacosAuthSystemType())) {
|
||||||
|
ignoreUrls = DEFAULT_ALL_PATH_PATTERN;
|
||||||
}
|
}
|
||||||
if (StringUtils.isBlank(authConfigs.getNacosAuthSystemType())) {
|
if (StringUtils.isBlank(authConfigs.getNacosAuthSystemType())) {
|
||||||
ignoreUrls = env.getProperty(PROPERTY_IGNORE_URLS, DEFAULT_ALL_PATH_PATTERN);
|
ignoreUrls = env.getProperty(PROPERTY_IGNORE_URLS, DEFAULT_ALL_PATH_PATTERN);
|
||||||
@ -107,6 +111,8 @@ public class NacosAuthConfig extends WebSecurityConfigurerAdapter {
|
|||||||
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
|
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
|
||||||
} else if (AuthSystemTypes.LDAP.name().equalsIgnoreCase(authConfigs.getNacosAuthSystemType())) {
|
} else if (AuthSystemTypes.LDAP.name().equalsIgnoreCase(authConfigs.getNacosAuthSystemType())) {
|
||||||
auth.authenticationProvider(ldapAuthenticationProvider);
|
auth.authenticationProvider(ldapAuthenticationProvider);
|
||||||
|
} else if (AuthSystemTypes.USERNAME_PASSWORD.name().equalsIgnoreCase(authConfigs.getNacosAuthSystemType())) {
|
||||||
|
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,9 +121,8 @@ public class NacosAuthConfig extends WebSecurityConfigurerAdapter {
|
|||||||
|
|
||||||
if (StringUtils.isBlank(authConfigs.getNacosAuthSystemType())) {
|
if (StringUtils.isBlank(authConfigs.getNacosAuthSystemType())) {
|
||||||
http.csrf().disable().cors()// We don't need CSRF for JWT based authentication
|
http.csrf().disable().cors()// We don't need CSRF for JWT based authentication
|
||||||
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
|
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests()
|
||||||
.authorizeRequests().requestMatchers(CorsUtils::isPreFlightRequest).permitAll()
|
.requestMatchers(CorsUtils::isPreFlightRequest).permitAll().antMatchers(LOGIN_ENTRY_POINT).permitAll().and().authorizeRequests()
|
||||||
.antMatchers(LOGIN_ENTRY_POINT).permitAll().and().authorizeRequests()
|
|
||||||
.antMatchers(TOKEN_BASED_AUTH_ENTRY_POINT).authenticated().and().exceptionHandling()
|
.antMatchers(TOKEN_BASED_AUTH_ENTRY_POINT).authenticated().and().exceptionHandling()
|
||||||
.authenticationEntryPoint(new JwtAuthenticationEntryPoint());
|
.authenticationEntryPoint(new JwtAuthenticationEntryPoint());
|
||||||
// disable cache
|
// disable cache
|
||||||
|
@ -17,20 +17,20 @@
|
|||||||
package com.alibaba.nacos.auth;
|
package com.alibaba.nacos.auth;
|
||||||
|
|
||||||
import com.alibaba.nacos.api.common.Constants;
|
import com.alibaba.nacos.api.common.Constants;
|
||||||
|
import com.alibaba.nacos.auth.common.AuthSystemTypes;
|
||||||
import com.alibaba.nacos.auth.context.IdentityContext;
|
import com.alibaba.nacos.auth.context.IdentityContext;
|
||||||
import com.alibaba.nacos.auth.exception.AccessException;
|
import com.alibaba.nacos.auth.exception.AccessException;
|
||||||
import com.alibaba.nacos.auth.model.Permission;
|
import com.alibaba.nacos.auth.model.Permission;
|
||||||
import com.alibaba.nacos.auth.roles.NacosAuthRoleServiceImpl;
|
import com.alibaba.nacos.auth.roles.NacosAuthRoleServiceImpl;
|
||||||
import com.alibaba.nacos.auth.roles.RoleInfo;
|
import com.alibaba.nacos.auth.roles.RoleInfo;
|
||||||
import com.alibaba.nacos.common.utils.StringUtils;
|
import com.alibaba.nacos.common.utils.StringUtils;
|
||||||
|
import com.alibaba.nacos.sys.utils.ApplicationUtils;
|
||||||
import io.jsonwebtoken.ExpiredJwtException;
|
import io.jsonwebtoken.ExpiredJwtException;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.AuthenticationException;
|
import org.springframework.security.core.AuthenticationException;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -39,33 +39,33 @@ import java.util.List;
|
|||||||
*
|
*
|
||||||
* @author wuyfee
|
* @author wuyfee
|
||||||
*/
|
*/
|
||||||
@Component
|
|
||||||
public class NacosAuthServiceImpl implements AuthService {
|
public class NacosAuthServiceImpl implements AuthService {
|
||||||
|
|
||||||
private static final String TOKEN_PREFIX = "Bearer ";
|
private static final String TOKEN_PREFIX = "Bearer ";
|
||||||
|
|
||||||
private static final String PARAM_USERNAME = "username";
|
|
||||||
|
|
||||||
private static final String PARAM_PASSWORD = "password";
|
private static final String PARAM_PASSWORD = "password";
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private JwtTokenManager jwtTokenManager;
|
private JwtTokenManager jwtTokenManager;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private AuthenticationManager authenticationManager;
|
private AuthenticationManager authenticationManager;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private NacosAuthRoleServiceImpl roleService;
|
private NacosAuthRoleServiceImpl roleService;
|
||||||
|
|
||||||
|
public NacosAuthServiceImpl() {
|
||||||
|
jwtTokenManager = ApplicationUtils.getBean(JwtTokenManager.class);
|
||||||
|
authenticationManager = ApplicationUtils.getBean(AuthenticationManager.class);
|
||||||
|
roleService = ApplicationUtils.getBean(NacosAuthRoleServiceImpl.class);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IdentityContext login(IdentityContext identityContext) throws AccessException {
|
public IdentityContext login(IdentityContext identityContext) throws AccessException {
|
||||||
String username = (String) identityContext.getParameter(Constants.USERNAME);
|
String username = (String) identityContext.getParameter(Constants.USERNAME);
|
||||||
String password = (String) identityContext.getParameter(PARAM_PASSWORD);
|
String password = (String) identityContext.getParameter(PARAM_PASSWORD);
|
||||||
String finalName;
|
String finalName;
|
||||||
Authentication authenticate;
|
Authentication authenticate;
|
||||||
try {
|
try {
|
||||||
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username,
|
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
|
||||||
password);
|
|
||||||
authenticate = authenticationManager.authenticate(authenticationToken);
|
authenticate = authenticationManager.authenticate(authenticationToken);
|
||||||
} catch (AuthenticationException e) {
|
} catch (AuthenticationException e) {
|
||||||
throw new AccessException("unknown user!");
|
throw new AccessException("unknown user!");
|
||||||
@ -81,18 +81,8 @@ public class NacosAuthServiceImpl implements AuthService {
|
|||||||
SecurityContextHolder.getContext().setAuthentication(jwtTokenManager.getAuthentication(token));
|
SecurityContextHolder.getContext().setAuthentication(jwtTokenManager.getAuthentication(token));
|
||||||
|
|
||||||
IdentityContext authResult = new IdentityContext();
|
IdentityContext authResult = new IdentityContext();
|
||||||
authResult.setParameter(Constants.USERNAME, finalName);
|
setIdentityContext(finalName, token, identityContext);
|
||||||
authResult.setParameter(Constants.ACCESS_TOKEN, token);
|
setIdentityContext(finalName, token, authResult);
|
||||||
authResult.setParameter(Constants.GLOBAL_ADMIN, false);
|
|
||||||
List<RoleInfo> roleInfoList = roleService.getRoles(username);
|
|
||||||
if (roleInfoList != null) {
|
|
||||||
for (RoleInfo roleInfo : roleInfoList) {
|
|
||||||
if (roleInfo.getRole().equals(NacosAuthRoleServiceImpl.GLOBAL_ADMIN_ROLE)) {
|
|
||||||
authResult.setParameter(Constants.GLOBAL_ADMIN, true);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return authResult;
|
return authResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,6 +101,7 @@ public class NacosAuthServiceImpl implements AuthService {
|
|||||||
username = (String) login(identityContext).getParameter(Constants.USERNAME);
|
username = (String) login(identityContext).getParameter(Constants.USERNAME);
|
||||||
} else {
|
} else {
|
||||||
username = getUsernameFromToken(token);
|
username = getUsernameFromToken(token);
|
||||||
|
setIdentityContext(username, token, identityContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!roleService.hasPermission(username, permission)) {
|
if (!roleService.hasPermission(username, permission)) {
|
||||||
@ -121,7 +112,7 @@ public class NacosAuthServiceImpl implements AuthService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getAuthServiceName() {
|
public String getAuthServiceName() {
|
||||||
return "NacosAuthServiceImpl";
|
return AuthSystemTypes.USERNAME_PASSWORD.name();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -141,4 +132,26 @@ public class NacosAuthServiceImpl implements AuthService {
|
|||||||
|
|
||||||
return authentication.getName();
|
return authentication.getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set NacosUser.
|
||||||
|
*
|
||||||
|
* @param username username.
|
||||||
|
* @param token user access token.
|
||||||
|
*/
|
||||||
|
public void setIdentityContext(String username, String token, IdentityContext identityContext) {
|
||||||
|
identityContext.setParameter(Constants.USERNAME, username);
|
||||||
|
identityContext.setParameter(Constants.ACCESS_TOKEN, token);
|
||||||
|
identityContext.setParameter(Constants.GLOBAL_ADMIN, false);
|
||||||
|
List<RoleInfo> roleInfoList = roleService.getRoles(username);
|
||||||
|
if (roleInfoList != null) {
|
||||||
|
for (RoleInfo roleInfo : roleInfoList) {
|
||||||
|
if (roleInfo.getRole().equals(NacosAuthRoleServiceImpl.GLOBAL_ADMIN_ROLE)) {
|
||||||
|
identityContext.setParameter(Constants.GLOBAL_ADMIN, true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@ public class AuthConfigs extends Subscriber<ServerConfigChangeEvent> {
|
|||||||
* Authority key set.
|
* Authority key set.
|
||||||
*/
|
*/
|
||||||
@Value("${nacos.core.auth.authorityKey:}")
|
@Value("${nacos.core.auth.authorityKey:}")
|
||||||
private String[] authorityKey;
|
private String[] authorityKey;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether auth enabled.
|
* Whether auth enabled.
|
||||||
@ -160,6 +160,7 @@ public class AuthConfigs extends Subscriber<ServerConfigChangeEvent> {
|
|||||||
serverIdentityValue = EnvUtil.getProperty("nacos.core.auth.server.identity.value", "");
|
serverIdentityValue = EnvUtil.getProperty("nacos.core.auth.server.identity.value", "");
|
||||||
enableUserAgentAuthWhite = EnvUtil.getProperty("nacos.core.auth.enable.userAgentAuthWhite", Boolean.class, false);
|
enableUserAgentAuthWhite = EnvUtil.getProperty("nacos.core.auth.enable.userAgentAuthWhite", Boolean.class, false);
|
||||||
authorityKey = EnvUtil.getProperty("nacos.core.auth.authorityKey", "").split(",");
|
authorityKey = EnvUtil.getProperty("nacos.core.auth.authorityKey", "").split(",");
|
||||||
|
nacosAuthSystemType = EnvUtil.getProperty("nacos.core.auth.system.type", "");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOGGER.warn("Upgrade auth config from env failed, use old value", e);
|
LOGGER.warn("Upgrade auth config from env failed, use old value", e);
|
||||||
}
|
}
|
||||||
|
@ -32,5 +32,9 @@ public enum AuthSystemTypes {
|
|||||||
/**
|
/**
|
||||||
* LDAP.
|
* LDAP.
|
||||||
*/
|
*/
|
||||||
LDAP
|
LDAP,
|
||||||
|
/**
|
||||||
|
* username password authentication.
|
||||||
|
*/
|
||||||
|
USERNAME_PASSWORD
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ package com.alibaba.nacos.auth.context;
|
|||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Identity Context.
|
* Identity Context.
|
||||||
@ -46,4 +47,12 @@ public class IdentityContext {
|
|||||||
*/
|
*/
|
||||||
public void setParameter(String key, Object value) {
|
public void setParameter(String key, Object value) {
|
||||||
param.put(key, value); }
|
param.put(key, value); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get all keys of param map.
|
||||||
|
* @return set all param keys.
|
||||||
|
*/
|
||||||
|
public Set<String> getAllKey() {
|
||||||
|
return param.keySet();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -217,5 +217,4 @@ public class ExternalDataSourceServiceImpl implements DataSourceService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import com.alibaba.nacos.auth.persist.repository.PaginationHelper;
|
|||||||
import org.springframework.context.annotation.Conditional;
|
import org.springframework.context.annotation.Conditional;
|
||||||
import org.springframework.jdbc.core.JdbcTemplate;
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
|
|
||||||
@Conditional(value = ConditionOnEmbeddedStorage.class)
|
@Conditional(value = ConditionOnEmbeddedStorage.class)
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
com.alibaba.nacos.auth.NacosAuthServiceImpl
|
@ -23,8 +23,6 @@ import org.junit.Before;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.springframework.mock.env.MockEnvironment;
|
import org.springframework.mock.env.MockEnvironment;
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
public class AuthConfigsTest {
|
public class AuthConfigsTest {
|
||||||
@ -39,7 +37,9 @@ public class AuthConfigsTest {
|
|||||||
|
|
||||||
private static final boolean TEST_ENABLE_UA_WHITE = true;
|
private static final boolean TEST_ENABLE_UA_WHITE = true;
|
||||||
|
|
||||||
private static final String AUTHORITYKEY = "username,password,token,tenant";
|
private static final String AUTHORITY_KEY = "accessToken,username,password";
|
||||||
|
|
||||||
|
private static final String AUTH_SYSTEM_TYPES = AuthSystemTypes.USERNAME_PASSWORD.name();
|
||||||
|
|
||||||
private AuthConfigs authConfigs;
|
private AuthConfigs authConfigs;
|
||||||
|
|
||||||
@ -59,7 +59,8 @@ public class AuthConfigsTest {
|
|||||||
environment.setProperty("nacos.core.auth.server.identity.key", TEST_SERVER_IDENTITY_KEY);
|
environment.setProperty("nacos.core.auth.server.identity.key", TEST_SERVER_IDENTITY_KEY);
|
||||||
environment.setProperty("nacos.core.auth.server.identity.value", TEST_SERVER_IDENTITY_VALUE);
|
environment.setProperty("nacos.core.auth.server.identity.value", TEST_SERVER_IDENTITY_VALUE);
|
||||||
environment.setProperty("nacos.core.auth.enable.userAgentAuthWhite", String.valueOf(TEST_ENABLE_UA_WHITE));
|
environment.setProperty("nacos.core.auth.enable.userAgentAuthWhite", String.valueOf(TEST_ENABLE_UA_WHITE));
|
||||||
environment.setProperty("nacos.core.auth.enable.authorityKey", AUTHORITYKEY);
|
environment.setProperty("nacos.core.auth.enable.authorityKey", AUTHORITY_KEY);
|
||||||
|
environment.setProperty("nacos.core.auth.system.type", AUTH_SYSTEM_TYPES);
|
||||||
|
|
||||||
authConfigs.onEvent(ServerConfigChangeEvent.newEvent());
|
authConfigs.onEvent(ServerConfigChangeEvent.newEvent());
|
||||||
assertEquals(TEST_AUTH_ENABLED, authConfigs.isAuthEnabled());
|
assertEquals(TEST_AUTH_ENABLED, authConfigs.isAuthEnabled());
|
||||||
@ -67,6 +68,7 @@ public class AuthConfigsTest {
|
|||||||
assertEquals(TEST_SERVER_IDENTITY_KEY, authConfigs.getServerIdentityKey());
|
assertEquals(TEST_SERVER_IDENTITY_KEY, authConfigs.getServerIdentityKey());
|
||||||
assertEquals(TEST_SERVER_IDENTITY_VALUE, authConfigs.getServerIdentityValue());
|
assertEquals(TEST_SERVER_IDENTITY_VALUE, authConfigs.getServerIdentityValue());
|
||||||
assertEquals(TEST_ENABLE_UA_WHITE, authConfigs.isEnableUserAgentAuthWhite());
|
assertEquals(TEST_ENABLE_UA_WHITE, authConfigs.isEnableUserAgentAuthWhite());
|
||||||
Assert.assertTrue(Arrays.equals(AUTHORITYKEY.split(","), authConfigs.getAuthorityKey()));
|
assertEquals(AUTH_SYSTEM_TYPES, authConfigs.getNacosAuthSystemType());
|
||||||
|
Assert.assertArrayEquals(AUTHORITY_KEY.split(","), authConfigs.getAuthorityKey());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,16 +18,15 @@ package com.alibaba.nacos.auth.common;
|
|||||||
|
|
||||||
import com.alibaba.nacos.auth.AuthPluginManager;
|
import com.alibaba.nacos.auth.AuthPluginManager;
|
||||||
import com.alibaba.nacos.auth.AuthService;
|
import com.alibaba.nacos.auth.AuthService;
|
||||||
import com.alibaba.nacos.auth.context.IdentityContext;
|
import com.alibaba.nacos.sys.utils.ApplicationUtils;
|
||||||
import com.alibaba.nacos.auth.exception.AccessException;
|
|
||||||
import com.alibaba.nacos.auth.model.Permission;
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.Mockito;
|
|
||||||
import org.mockito.junit.MockitoJUnitRunner;
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
@ -45,39 +44,29 @@ public class AuthPluginManagerTest {
|
|||||||
private AuthPluginManager authPluginManager;
|
private AuthPluginManager authPluginManager;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private AuthService authService;
|
private ConfigurableApplicationContext context;
|
||||||
|
|
||||||
private static final String TYPE = "test";
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
private IdentityContext identityContext;
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
private Permission permission;
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws NoSuchFieldException, IllegalAccessException {
|
public void setUp() throws NoSuchFieldException, IllegalAccessException {
|
||||||
|
ApplicationUtils.injectContext(context);
|
||||||
|
|
||||||
authPluginManager = AuthPluginManager.getInstance();
|
authPluginManager = AuthPluginManager.getInstance();
|
||||||
Class<AuthPluginManager> authPluginManagerClass = AuthPluginManager.class;
|
Class<AuthPluginManager> authPluginManagerClass = AuthPluginManager.class;
|
||||||
Field authPlugins = authPluginManagerClass.getDeclaredField("authServiceMap");
|
Field authPlugins = authPluginManagerClass.getDeclaredField("authServiceMap");
|
||||||
authPlugins.setAccessible(true);
|
authPlugins.setAccessible(true);
|
||||||
Map<String, AuthService> authServiceMap = (Map<String, AuthService>) authPlugins.get(authPluginManager);
|
Map<String, AuthService> authServiceMap = (Map<String, AuthService>) authPlugins.get(authPluginManager);
|
||||||
authServiceMap.put(TYPE, authService);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetInstance() {
|
public void testGetInstance() {
|
||||||
AuthPluginManager instance = AuthPluginManager.getInstance();
|
AuthPluginManager instance = AuthPluginManager.getInstance();
|
||||||
|
|
||||||
Assert.assertNotNull(instance);
|
Assert.assertNotNull(instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFindAuthServiceSpiImpl() throws AccessException {
|
public void testFindAuthServiceSpiImpl() {
|
||||||
Mockito.when(authService.authorityAccess(identityContext, permission)).thenReturn(true);
|
Optional<AuthService> authServiceImpl = authPluginManager.findAuthServiceSpiImpl(AuthSystemTypes.USERNAME_PASSWORD.name());
|
||||||
Mockito.when(authService.getAuthServiceName()).thenReturn(TYPE);
|
|
||||||
Optional<AuthService> authServiceImpl = authPluginManager.findAuthServiceSpiImpl(TYPE);
|
|
||||||
Assert.assertTrue(authServiceImpl.isPresent());
|
Assert.assertTrue(authServiceImpl.isPresent());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -16,27 +16,27 @@
|
|||||||
|
|
||||||
package com.alibaba.nacos.config.server.auth;
|
package com.alibaba.nacos.config.server.auth;
|
||||||
|
|
||||||
import com.alibaba.nacos.auth.AuthManager;
|
import com.alibaba.nacos.auth.AuthService;
|
||||||
|
import com.alibaba.nacos.auth.context.IdentityContext;
|
||||||
import com.alibaba.nacos.auth.exception.AccessException;
|
import com.alibaba.nacos.auth.exception.AccessException;
|
||||||
import com.alibaba.nacos.auth.model.Permission;
|
import com.alibaba.nacos.auth.model.Permission;
|
||||||
import com.alibaba.nacos.auth.model.User;
|
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
public class MockAuthManager implements AuthManager {
|
public class MockAuthManager implements AuthService {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public User login(Object request) throws AccessException {
|
public IdentityContext login(IdentityContext identityContext) throws AccessException {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public User loginRemote(Object request) throws AccessException {
|
public Boolean authorityAccess(IdentityContext identityContext, Permission permission) throws AccessException {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void auth(Permission permission, User user) throws AccessException {
|
public String getAuthServiceName() {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package com.alibaba.nacos.console.controller;
|
package com.alibaba.nacos.console.controller;
|
||||||
|
|
||||||
|
import com.alibaba.nacos.auth.NacosAuthConfig;
|
||||||
import com.alibaba.nacos.auth.annotation.Secured;
|
import com.alibaba.nacos.auth.annotation.Secured;
|
||||||
import com.alibaba.nacos.auth.common.ActionTypes;
|
import com.alibaba.nacos.auth.common.ActionTypes;
|
||||||
import com.alibaba.nacos.common.model.RestResult;
|
import com.alibaba.nacos.common.model.RestResult;
|
||||||
@ -26,7 +27,6 @@ import com.alibaba.nacos.config.server.service.repository.PersistService;
|
|||||||
import com.alibaba.nacos.console.enums.NamespaceTypeEnum;
|
import com.alibaba.nacos.console.enums.NamespaceTypeEnum;
|
||||||
import com.alibaba.nacos.console.model.Namespace;
|
import com.alibaba.nacos.console.model.Namespace;
|
||||||
import com.alibaba.nacos.console.model.NamespaceAllInfo;
|
import com.alibaba.nacos.console.model.NamespaceAllInfo;
|
||||||
import com.alibaba.nacos.console.security.nacos.NacosAuthConfig;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
@ -16,11 +16,11 @@
|
|||||||
|
|
||||||
package com.alibaba.nacos.console.controller;
|
package com.alibaba.nacos.console.controller;
|
||||||
|
|
||||||
|
import com.alibaba.nacos.auth.NacosAuthConfig;
|
||||||
import com.alibaba.nacos.auth.annotation.Secured;
|
import com.alibaba.nacos.auth.annotation.Secured;
|
||||||
import com.alibaba.nacos.auth.common.ActionTypes;
|
import com.alibaba.nacos.auth.common.ActionTypes;
|
||||||
import com.alibaba.nacos.common.model.RestResultUtils;
|
import com.alibaba.nacos.common.model.RestResultUtils;
|
||||||
import com.alibaba.nacos.common.utils.StringUtils;
|
import com.alibaba.nacos.common.utils.StringUtils;
|
||||||
import com.alibaba.nacos.console.security.nacos.NacosAuthConfig;
|
|
||||||
import com.alibaba.nacos.console.security.nacos.roles.NacosRoleServiceImpl;
|
import com.alibaba.nacos.console.security.nacos.roles.NacosRoleServiceImpl;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
|
@ -16,11 +16,11 @@
|
|||||||
|
|
||||||
package com.alibaba.nacos.console.controller;
|
package com.alibaba.nacos.console.controller;
|
||||||
|
|
||||||
|
import com.alibaba.nacos.auth.NacosAuthConfig;
|
||||||
import com.alibaba.nacos.auth.annotation.Secured;
|
import com.alibaba.nacos.auth.annotation.Secured;
|
||||||
import com.alibaba.nacos.auth.common.ActionTypes;
|
import com.alibaba.nacos.auth.common.ActionTypes;
|
||||||
import com.alibaba.nacos.common.model.RestResultUtils;
|
import com.alibaba.nacos.common.model.RestResultUtils;
|
||||||
import com.alibaba.nacos.common.utils.StringUtils;
|
import com.alibaba.nacos.common.utils.StringUtils;
|
||||||
import com.alibaba.nacos.console.security.nacos.NacosAuthConfig;
|
|
||||||
import com.alibaba.nacos.console.security.nacos.roles.NacosRoleServiceImpl;
|
import com.alibaba.nacos.console.security.nacos.roles.NacosRoleServiceImpl;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
|
@ -17,22 +17,26 @@
|
|||||||
package com.alibaba.nacos.console.controller;
|
package com.alibaba.nacos.console.controller;
|
||||||
|
|
||||||
import com.alibaba.nacos.api.common.Constants;
|
import com.alibaba.nacos.api.common.Constants;
|
||||||
|
import com.alibaba.nacos.auth.AuthPluginManager;
|
||||||
|
import com.alibaba.nacos.auth.AuthService;
|
||||||
|
import com.alibaba.nacos.auth.NacosAuthConfig;
|
||||||
import com.alibaba.nacos.auth.annotation.Secured;
|
import com.alibaba.nacos.auth.annotation.Secured;
|
||||||
import com.alibaba.nacos.auth.common.ActionTypes;
|
import com.alibaba.nacos.auth.common.ActionTypes;
|
||||||
import com.alibaba.nacos.auth.common.AuthConfigs;
|
import com.alibaba.nacos.auth.common.AuthConfigs;
|
||||||
import com.alibaba.nacos.auth.common.AuthSystemTypes;
|
import com.alibaba.nacos.auth.common.AuthSystemTypes;
|
||||||
|
import com.alibaba.nacos.auth.context.HttpIdentityContextBuilder;
|
||||||
|
import com.alibaba.nacos.auth.context.IdentityContext;
|
||||||
|
import com.alibaba.nacos.auth.context.IdentityContextBuilder;
|
||||||
import com.alibaba.nacos.auth.exception.AccessException;
|
import com.alibaba.nacos.auth.exception.AccessException;
|
||||||
|
import com.alibaba.nacos.auth.JwtTokenManager;
|
||||||
|
|
||||||
import com.alibaba.nacos.common.model.RestResult;
|
import com.alibaba.nacos.common.model.RestResult;
|
||||||
import com.alibaba.nacos.common.model.RestResultUtils;
|
import com.alibaba.nacos.common.model.RestResultUtils;
|
||||||
import com.alibaba.nacos.common.utils.JacksonUtils;
|
import com.alibaba.nacos.common.utils.JacksonUtils;
|
||||||
import com.alibaba.nacos.config.server.auth.RoleInfo;
|
import com.alibaba.nacos.config.server.auth.RoleInfo;
|
||||||
import com.alibaba.nacos.config.server.model.User;
|
import com.alibaba.nacos.config.server.model.User;
|
||||||
import com.alibaba.nacos.config.server.utils.RequestUtil;
|
|
||||||
import com.alibaba.nacos.console.security.nacos.JwtTokenManager;
|
|
||||||
import com.alibaba.nacos.console.security.nacos.NacosAuthConfig;
|
|
||||||
import com.alibaba.nacos.console.security.nacos.NacosAuthManager;
|
|
||||||
import com.alibaba.nacos.console.security.nacos.roles.NacosRoleServiceImpl;
|
import com.alibaba.nacos.console.security.nacos.roles.NacosRoleServiceImpl;
|
||||||
import com.alibaba.nacos.console.security.nacos.users.NacosUser;
|
|
||||||
import com.alibaba.nacos.console.security.nacos.users.NacosUserDetailsServiceImpl;
|
import com.alibaba.nacos.console.security.nacos.users.NacosUserDetailsServiceImpl;
|
||||||
import com.alibaba.nacos.console.utils.PasswordEncoderUtil;
|
import com.alibaba.nacos.console.utils.PasswordEncoderUtil;
|
||||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||||
@ -83,9 +87,6 @@ public class UserController {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private AuthConfigs authConfigs;
|
private AuthConfigs authConfigs;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private NacosAuthManager authManager;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new user.
|
* Create a new user.
|
||||||
*
|
*
|
||||||
@ -134,21 +135,21 @@ public class UserController {
|
|||||||
*
|
*
|
||||||
* @param username username of user
|
* @param username username of user
|
||||||
* @param newPassword new password of user
|
* @param newPassword new password of user
|
||||||
* @param response http response
|
* @param response http response
|
||||||
* @param request http request
|
* @param request http request
|
||||||
* @return ok if update succeed
|
* @return ok if update succeed
|
||||||
* @throws IllegalArgumentException if user not exist or oldPassword is incorrect
|
* @throws IllegalArgumentException if user not exist or oldPassword is incorrect
|
||||||
* @since 1.2.0
|
* @since 1.2.0
|
||||||
*/
|
*/
|
||||||
@PutMapping
|
@PutMapping
|
||||||
@Secured(resource = NacosAuthConfig.UPDATE_PASSWORD_ENTRY_POINT, action = ActionTypes.WRITE)
|
@Secured(resource = NacosAuthConfig.UPDATE_PASSWORD_ENTRY_POINT, action = ActionTypes.WRITE)
|
||||||
public Object updateUser(@RequestParam String username, @RequestParam String newPassword,
|
public Object updateUser(@RequestParam String username, @RequestParam String newPassword, HttpServletResponse response,
|
||||||
HttpServletResponse response, HttpServletRequest request) throws IOException {
|
HttpServletRequest request) throws IOException {
|
||||||
// admin or same user
|
// admin or same user
|
||||||
if (!hasPermission(username, request)) {
|
if (!hasPermission(username, request)) {
|
||||||
response.sendError(HttpServletResponse.SC_FORBIDDEN, "authorization failed!");
|
response.sendError(HttpServletResponse.SC_FORBIDDEN, "authorization failed!");
|
||||||
}
|
}
|
||||||
|
|
||||||
User user = userDetailsService.getUserFromDatabase(username);
|
User user = userDetailsService.getUserFromDatabase(username);
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
throw new IllegalArgumentException("user " + username + " not exist!");
|
throw new IllegalArgumentException("user " + username + " not exist!");
|
||||||
@ -158,22 +159,23 @@ public class UserController {
|
|||||||
|
|
||||||
return RestResultUtils.success("update user ok!");
|
return RestResultUtils.success("update user ok!");
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasPermission(String username, HttpServletRequest request) {
|
private boolean hasPermission(String username, HttpServletRequest request) {
|
||||||
if (!authConfigs.isAuthEnabled()) {
|
if (!authConfigs.isAuthEnabled()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (Objects.isNull(request.getAttribute(RequestUtil.NACOS_USER_KEY))) {
|
if (Objects.isNull(request.getAttribute(NacosAuthConfig.NACOS_IDENTITY_KEY))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
IdentityContext context = (IdentityContext) request.getAttribute(NacosAuthConfig.NACOS_IDENTITY_KEY);
|
||||||
NacosUser user = (NacosUser) request.getAttribute(RequestUtil.NACOS_USER_KEY);
|
|
||||||
// admin
|
// admin
|
||||||
if (user.isGlobalAdmin()) {
|
if ((Boolean) context.getParameter(Constants.GLOBAL_ADMIN)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// same user
|
// same user
|
||||||
return user.getUserName().equals(username);
|
String authorityUserName = (String) context.getParameter(Constants.USERNAME);
|
||||||
|
return authorityUserName.equals(username);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -203,26 +205,28 @@ public class UserController {
|
|||||||
* @throws AccessException if user info is incorrect
|
* @throws AccessException if user info is incorrect
|
||||||
*/
|
*/
|
||||||
@PostMapping("/login")
|
@PostMapping("/login")
|
||||||
public Object login(@RequestParam String username, @RequestParam String password, HttpServletResponse response,
|
public Object login(@RequestParam String username, @RequestParam String password, HttpServletResponse response, HttpServletRequest request)
|
||||||
HttpServletRequest request) throws AccessException {
|
throws AccessException {
|
||||||
|
if (AuthSystemTypes.NACOS.name().equalsIgnoreCase(authConfigs.getNacosAuthSystemType()) || AuthSystemTypes.LDAP.name()
|
||||||
if (AuthSystemTypes.NACOS.name().equalsIgnoreCase(authConfigs.getNacosAuthSystemType()) || AuthSystemTypes.LDAP
|
.equalsIgnoreCase(authConfigs.getNacosAuthSystemType()) || AuthSystemTypes.USERNAME_PASSWORD.name()
|
||||||
.name().equalsIgnoreCase(authConfigs.getNacosAuthSystemType())) {
|
.equalsIgnoreCase(authConfigs.getNacosAuthSystemType())) {
|
||||||
NacosUser user = (NacosUser) authManager.login(request);
|
AuthService authService = AuthPluginManager.getInstance().findAuthServiceSpiImpl(authConfigs.getNacosAuthSystemType()).get();
|
||||||
|
IdentityContextBuilder<HttpServletRequest> identityContextBuilder = new HttpIdentityContextBuilder(authConfigs);
|
||||||
|
IdentityContext identityContext = authService.login(identityContextBuilder.build(request));
|
||||||
|
|
||||||
response.addHeader(NacosAuthConfig.AUTHORIZATION_HEADER, NacosAuthConfig.TOKEN_PREFIX + user.getToken());
|
response.addHeader(NacosAuthConfig.AUTHORIZATION_HEADER,
|
||||||
|
NacosAuthConfig.TOKEN_PREFIX + identityContext.getParameter(Constants.ACCESS_TOKEN));
|
||||||
|
|
||||||
ObjectNode result = JacksonUtils.createEmptyJsonNode();
|
ObjectNode result = JacksonUtils.createEmptyJsonNode();
|
||||||
result.put(Constants.ACCESS_TOKEN, user.getToken());
|
result.put(Constants.ACCESS_TOKEN, (String) identityContext.getParameter(Constants.ACCESS_TOKEN));
|
||||||
result.put(Constants.TOKEN_TTL, authConfigs.getTokenValidityInSeconds());
|
result.put(Constants.TOKEN_TTL, authConfigs.getTokenValidityInSeconds());
|
||||||
result.put(Constants.GLOBAL_ADMIN, user.isGlobalAdmin());
|
result.put(Constants.GLOBAL_ADMIN, (Boolean) identityContext.getParameter(Constants.GLOBAL_ADMIN));
|
||||||
result.put(Constants.USERNAME, user.getUserName());
|
result.put(Constants.USERNAME, (String) identityContext.getParameter(Constants.USERNAME));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create Authentication class through username and password, the implement class is UsernamePasswordAuthenticationToken
|
// create Authentication class through username and password, the implement class is UsernamePasswordAuthenticationToken
|
||||||
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username,
|
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
|
||||||
password);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// use the method authenticate of AuthenticationManager(default implement is ProviderManager) to valid Authentication
|
// use the method authenticate of AuthenticationManager(default implement is ProviderManager) to valid Authentication
|
||||||
@ -266,8 +270,8 @@ public class UserController {
|
|||||||
return RestResultUtils.failed(HttpStatus.INTERNAL_SERVER_ERROR.value(), "Update userpassword failed");
|
return RestResultUtils.failed(HttpStatus.INTERNAL_SERVER_ERROR.value(), "Update userpassword failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fuzzy matching username.
|
* Fuzzy matching username.
|
||||||
*
|
*
|
||||||
|
@ -1,76 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
|
||||||
*
|
|
||||||
* 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 com.alibaba.nacos.console.filter;
|
|
||||||
|
|
||||||
import com.alibaba.nacos.api.common.Constants;
|
|
||||||
import com.alibaba.nacos.common.utils.StringUtils;
|
|
||||||
import com.alibaba.nacos.console.security.nacos.JwtTokenManager;
|
|
||||||
import com.alibaba.nacos.console.security.nacos.NacosAuthConfig;
|
|
||||||
import org.springframework.security.core.Authentication;
|
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
|
||||||
import org.springframework.web.filter.OncePerRequestFilter;
|
|
||||||
|
|
||||||
import javax.servlet.FilterChain;
|
|
||||||
import javax.servlet.ServletException;
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* jwt auth token filter.
|
|
||||||
*
|
|
||||||
* @author wfnuser
|
|
||||||
*/
|
|
||||||
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
|
|
||||||
|
|
||||||
private static final String TOKEN_PREFIX = "Bearer ";
|
|
||||||
|
|
||||||
private final JwtTokenManager tokenManager;
|
|
||||||
|
|
||||||
public JwtAuthenticationTokenFilter(JwtTokenManager tokenManager) {
|
|
||||||
this.tokenManager = tokenManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
|
|
||||||
throws IOException, ServletException {
|
|
||||||
|
|
||||||
String jwt = resolveToken(request);
|
|
||||||
|
|
||||||
if (StringUtils.isNotBlank(jwt) && SecurityContextHolder.getContext().getAuthentication() == null) {
|
|
||||||
this.tokenManager.validateToken(jwt);
|
|
||||||
Authentication authentication = this.tokenManager.getAuthentication(jwt);
|
|
||||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
|
||||||
}
|
|
||||||
chain.doFilter(request, response);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get token from header.
|
|
||||||
*/
|
|
||||||
private String resolveToken(HttpServletRequest request) {
|
|
||||||
String bearerToken = request.getHeader(NacosAuthConfig.AUTHORIZATION_HEADER);
|
|
||||||
if (StringUtils.isNotBlank(bearerToken) && bearerToken.startsWith(TOKEN_PREFIX)) {
|
|
||||||
return bearerToken.substring(TOKEN_PREFIX.length());
|
|
||||||
}
|
|
||||||
String jwt = request.getParameter(Constants.ACCESS_TOKEN);
|
|
||||||
if (StringUtils.isNotBlank(jwt)) {
|
|
||||||
return jwt;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,57 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
|
||||||
*
|
|
||||||
* 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 com.alibaba.nacos.console.security.nacos;
|
|
||||||
|
|
||||||
import com.alibaba.nacos.console.security.nacos.users.NacosUserDetailsServiceImpl;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.security.authentication.AuthenticationProvider;
|
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
|
||||||
import org.springframework.security.core.Authentication;
|
|
||||||
import org.springframework.security.core.AuthenticationException;
|
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* auth provider.
|
|
||||||
*
|
|
||||||
* @author wfnuser
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
public class CustomAuthenticationProvider implements AuthenticationProvider {
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private NacosUserDetailsServiceImpl userDetailsService;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
|
||||||
|
|
||||||
String username = (String) authentication.getPrincipal();
|
|
||||||
String password = (String) authentication.getCredentials();
|
|
||||||
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
|
|
||||||
|
|
||||||
if (!password.equals(userDetails.getPassword())) {
|
|
||||||
return new UsernamePasswordAuthenticationToken(username, null, null);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean supports(Class<?> aClass) {
|
|
||||||
return aClass.equals(UsernamePasswordAuthenticationToken.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,46 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
|
||||||
*
|
|
||||||
* 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 com.alibaba.nacos.console.security.nacos;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.security.core.AuthenticationException;
|
|
||||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* jwt auth fail point.
|
|
||||||
*
|
|
||||||
* @author wfnuser
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
|
|
||||||
|
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(JwtAuthenticationEntryPoint.class);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e)
|
|
||||||
throws IOException, ServletException {
|
|
||||||
LOGGER.error("Responding with unauthorized error. Message:{}, url:{}", e.getMessage(), request.getRequestURI());
|
|
||||||
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,103 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
|
||||||
*
|
|
||||||
* 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 com.alibaba.nacos.console.security.nacos;
|
|
||||||
|
|
||||||
import com.alibaba.nacos.auth.common.AuthConfigs;
|
|
||||||
import io.jsonwebtoken.Claims;
|
|
||||||
import io.jsonwebtoken.Jwts;
|
|
||||||
import io.jsonwebtoken.SignatureAlgorithm;
|
|
||||||
import io.jsonwebtoken.security.Keys;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
|
||||||
import org.springframework.security.core.Authentication;
|
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
|
||||||
import org.springframework.security.core.authority.AuthorityUtils;
|
|
||||||
import org.springframework.security.core.userdetails.User;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* JWT token manager.
|
|
||||||
*
|
|
||||||
* @author wfnuser
|
|
||||||
* @author nkorange
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
public class JwtTokenManager {
|
|
||||||
|
|
||||||
private static final String AUTHORITIES_KEY = "auth";
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private AuthConfigs authConfigs;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create token.
|
|
||||||
*
|
|
||||||
* @param authentication auth info
|
|
||||||
* @return token
|
|
||||||
*/
|
|
||||||
public String createToken(Authentication authentication) {
|
|
||||||
return createToken(authentication.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create token.
|
|
||||||
*
|
|
||||||
* @param userName auth info
|
|
||||||
* @return token
|
|
||||||
*/
|
|
||||||
public String createToken(String userName) {
|
|
||||||
|
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
|
|
||||||
Date validity;
|
|
||||||
validity = new Date(now + authConfigs.getTokenValidityInSeconds() * 1000L);
|
|
||||||
|
|
||||||
Claims claims = Jwts.claims().setSubject(userName);
|
|
||||||
return Jwts.builder().setClaims(claims).setExpiration(validity)
|
|
||||||
.signWith(Keys.hmacShaKeyFor(authConfigs.getSecretKeyBytes()), SignatureAlgorithm.HS256).compact();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get auth Info.
|
|
||||||
*
|
|
||||||
* @param token token
|
|
||||||
* @return auth info
|
|
||||||
*/
|
|
||||||
public Authentication getAuthentication(String token) {
|
|
||||||
Claims claims = Jwts.parserBuilder().setSigningKey(authConfigs.getSecretKeyBytes()).build()
|
|
||||||
.parseClaimsJws(token).getBody();
|
|
||||||
|
|
||||||
List<GrantedAuthority> authorities = AuthorityUtils
|
|
||||||
.commaSeparatedStringToAuthorityList((String) claims.get(AUTHORITIES_KEY));
|
|
||||||
|
|
||||||
User principal = new User(claims.getSubject(), "", authorities);
|
|
||||||
return new UsernamePasswordAuthenticationToken(principal, "", authorities);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* validate token.
|
|
||||||
*
|
|
||||||
* @param token token
|
|
||||||
*/
|
|
||||||
public void validateToken(String token) {
|
|
||||||
Jwts.parserBuilder().setSigningKey(authConfigs.getSecretKeyBytes()).build().parseClaimsJws(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,169 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
|
||||||
*
|
|
||||||
* 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 com.alibaba.nacos.console.security.nacos;
|
|
||||||
|
|
||||||
import com.alibaba.nacos.common.utils.CollectionUtils;
|
|
||||||
import com.alibaba.nacos.config.server.auth.RoleInfo;
|
|
||||||
import com.alibaba.nacos.config.server.model.User;
|
|
||||||
import com.alibaba.nacos.console.security.nacos.roles.NacosRoleServiceImpl;
|
|
||||||
import com.alibaba.nacos.console.security.nacos.users.NacosUserDetails;
|
|
||||||
import com.alibaba.nacos.console.security.nacos.users.NacosUserDetailsServiceImpl;
|
|
||||||
import com.alibaba.nacos.console.utils.PasswordEncoderUtil;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
|
||||||
import org.springframework.security.authentication.AuthenticationProvider;
|
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
|
||||||
import org.springframework.security.core.Authentication;
|
|
||||||
import org.springframework.security.core.AuthenticationException;
|
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
|
||||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import javax.naming.CommunicationException;
|
|
||||||
import javax.naming.Context;
|
|
||||||
import javax.naming.directory.DirContext;
|
|
||||||
import javax.naming.ldap.InitialLdapContext;
|
|
||||||
import javax.naming.ldap.LdapContext;
|
|
||||||
import java.util.Hashtable;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static com.alibaba.nacos.console.security.nacos.roles.NacosRoleServiceImpl.GLOBAL_ADMIN_ROLE;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* LDAP auth provider.
|
|
||||||
*
|
|
||||||
* @author zjw
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
public class LdapAuthenticationProvider implements AuthenticationProvider {
|
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(LdapAuthenticationProvider.class);
|
|
||||||
|
|
||||||
private static final String FACTORY = "com.sun.jndi.ldap.LdapCtxFactory";
|
|
||||||
|
|
||||||
private static final String TIMEOUT = "com.sun.jndi.ldap.connect.timeout";
|
|
||||||
|
|
||||||
private static final String DEFAULT_PASSWORD = "nacos";
|
|
||||||
|
|
||||||
private static final String LDAP_PREFIX = "LDAP_";
|
|
||||||
|
|
||||||
private static final String DEFAULT_SECURITY_AUTH = "simple";
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private NacosUserDetailsServiceImpl userDetailsService;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private NacosRoleServiceImpl nacosRoleService;
|
|
||||||
|
|
||||||
@Value(("${nacos.core.auth.ldap.url:ldap://localhost:389}"))
|
|
||||||
private String ldapUrl;
|
|
||||||
|
|
||||||
@Value(("${nacos.core.auth.ldap.timeout:3000}"))
|
|
||||||
private String time;
|
|
||||||
|
|
||||||
@Value(("${nacos.core.auth.ldap.userdn:cn={0},ou=user,dc=company,dc=com}"))
|
|
||||||
private String userNamePattern;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
|
||||||
String username = (String) authentication.getPrincipal();
|
|
||||||
String password = (String) authentication.getCredentials();
|
|
||||||
|
|
||||||
if (isAdmin(username)) {
|
|
||||||
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
|
|
||||||
if (PasswordEncoderUtil.matches(password, userDetails.getPassword())) {
|
|
||||||
return new UsernamePasswordAuthenticationToken(userDetails, password, userDetails.getAuthorities());
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ldapLogin(username, password)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
UserDetails userDetails;
|
|
||||||
try {
|
|
||||||
userDetails = userDetailsService.loadUserByUsername(LDAP_PREFIX + username);
|
|
||||||
} catch (UsernameNotFoundException exception) {
|
|
||||||
String nacosPassword = PasswordEncoderUtil.encode(DEFAULT_PASSWORD);
|
|
||||||
userDetailsService.createUser(LDAP_PREFIX + username, nacosPassword);
|
|
||||||
User user = new User();
|
|
||||||
user.setUsername(LDAP_PREFIX + username);
|
|
||||||
user.setPassword(nacosPassword);
|
|
||||||
userDetails = new NacosUserDetails(user);
|
|
||||||
}
|
|
||||||
return new UsernamePasswordAuthenticationToken(userDetails, password, userDetails.getAuthorities());
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isAdmin(String username) {
|
|
||||||
List<RoleInfo> roleInfos = nacosRoleService.getRoles(username);
|
|
||||||
if (CollectionUtils.isEmpty(roleInfos)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
for (RoleInfo roleinfo : roleInfos) {
|
|
||||||
if (GLOBAL_ADMIN_ROLE.equals(roleinfo.getRole())) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean ldapLogin(String username, String password) throws AuthenticationException {
|
|
||||||
Hashtable<String, String> env = new Hashtable<>();
|
|
||||||
env.put(Context.INITIAL_CONTEXT_FACTORY, FACTORY);
|
|
||||||
env.put(Context.PROVIDER_URL, ldapUrl);
|
|
||||||
env.put(Context.SECURITY_AUTHENTICATION, DEFAULT_SECURITY_AUTH);
|
|
||||||
|
|
||||||
env.put(Context.SECURITY_PRINCIPAL, userNamePattern.replace("{0}", username));
|
|
||||||
env.put(Context.SECURITY_CREDENTIALS, password);
|
|
||||||
env.put(TIMEOUT, time);
|
|
||||||
LdapContext ctx = null;
|
|
||||||
try {
|
|
||||||
ctx = new InitialLdapContext(env, null);
|
|
||||||
} catch (CommunicationException e) {
|
|
||||||
LOG.error("LDAP Service connect timeout:{}", e.getMessage());
|
|
||||||
throw new RuntimeException("LDAP Service connect timeout");
|
|
||||||
} catch (javax.naming.AuthenticationException e) {
|
|
||||||
LOG.error("login error:{}", e.getMessage());
|
|
||||||
throw new RuntimeException("login error!");
|
|
||||||
} catch (Exception e) {
|
|
||||||
LOG.warn("Exception cause by:{}", e.getMessage());
|
|
||||||
return false;
|
|
||||||
} finally {
|
|
||||||
closeContext(ctx);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean supports(Class<?> aClass) {
|
|
||||||
return aClass.equals(UsernamePasswordAuthenticationToken.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void closeContext(DirContext ctx) {
|
|
||||||
if (ctx != null) {
|
|
||||||
try {
|
|
||||||
ctx.close();
|
|
||||||
} catch (Exception e) {
|
|
||||||
LOG.error("Exception closing context", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,138 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
|
||||||
*
|
|
||||||
* 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 com.alibaba.nacos.console.security.nacos;
|
|
||||||
|
|
||||||
import com.alibaba.nacos.auth.common.AuthConfigs;
|
|
||||||
import com.alibaba.nacos.auth.common.AuthSystemTypes;
|
|
||||||
import com.alibaba.nacos.common.utils.StringUtils;
|
|
||||||
import com.alibaba.nacos.console.filter.JwtAuthenticationTokenFilter;
|
|
||||||
import com.alibaba.nacos.console.security.nacos.users.NacosUserDetailsServiceImpl;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.core.env.Environment;
|
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
|
||||||
import org.springframework.security.config.BeanIds;
|
|
||||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
|
||||||
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
|
||||||
import org.springframework.security.config.annotation.web.builders.WebSecurity;
|
|
||||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
|
||||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
|
||||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
|
||||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
|
||||||
import org.springframework.web.cors.CorsUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Spring security config.
|
|
||||||
*
|
|
||||||
* @author Nacos
|
|
||||||
*/
|
|
||||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
|
||||||
public class NacosAuthConfig extends WebSecurityConfigurerAdapter {
|
|
||||||
|
|
||||||
public static final String AUTHORIZATION_HEADER = "Authorization";
|
|
||||||
|
|
||||||
public static final String SECURITY_IGNORE_URLS_SPILT_CHAR = ",";
|
|
||||||
|
|
||||||
public static final String LOGIN_ENTRY_POINT = "/v1/auth/login";
|
|
||||||
|
|
||||||
public static final String TOKEN_BASED_AUTH_ENTRY_POINT = "/v1/auth/**";
|
|
||||||
|
|
||||||
public static final String TOKEN_PREFIX = "Bearer ";
|
|
||||||
|
|
||||||
public static final String CONSOLE_RESOURCE_NAME_PREFIX = "console/";
|
|
||||||
|
|
||||||
public static final String UPDATE_PASSWORD_ENTRY_POINT = CONSOLE_RESOURCE_NAME_PREFIX + "user/password";
|
|
||||||
|
|
||||||
private static final String DEFAULT_ALL_PATH_PATTERN = "/**";
|
|
||||||
|
|
||||||
private static final String PROPERTY_IGNORE_URLS = "nacos.security.ignore.urls";
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private Environment env;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private JwtTokenManager tokenProvider;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private AuthConfigs authConfigs;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private NacosUserDetailsServiceImpl userDetailsService;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private LdapAuthenticationProvider ldapAuthenticationProvider;
|
|
||||||
|
|
||||||
@Bean(name = BeanIds.AUTHENTICATION_MANAGER)
|
|
||||||
@Override
|
|
||||||
public AuthenticationManager authenticationManagerBean() throws Exception {
|
|
||||||
return super.authenticationManagerBean();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void configure(WebSecurity web) {
|
|
||||||
|
|
||||||
String ignoreUrls = null;
|
|
||||||
if (AuthSystemTypes.NACOS.name().equalsIgnoreCase(authConfigs.getNacosAuthSystemType())) {
|
|
||||||
ignoreUrls = DEFAULT_ALL_PATH_PATTERN;
|
|
||||||
} else if (AuthSystemTypes.LDAP.name().equalsIgnoreCase(authConfigs.getNacosAuthSystemType())) {
|
|
||||||
ignoreUrls = DEFAULT_ALL_PATH_PATTERN;
|
|
||||||
}
|
|
||||||
if (StringUtils.isBlank(authConfigs.getNacosAuthSystemType())) {
|
|
||||||
ignoreUrls = env.getProperty(PROPERTY_IGNORE_URLS, DEFAULT_ALL_PATH_PATTERN);
|
|
||||||
}
|
|
||||||
if (StringUtils.isNotBlank(ignoreUrls)) {
|
|
||||||
for (String each : ignoreUrls.trim().split(SECURITY_IGNORE_URLS_SPILT_CHAR)) {
|
|
||||||
web.ignoring().antMatchers(each.trim());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
|
||||||
if (AuthSystemTypes.NACOS.name().equalsIgnoreCase(authConfigs.getNacosAuthSystemType())) {
|
|
||||||
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
|
|
||||||
} else if (AuthSystemTypes.LDAP.name().equalsIgnoreCase(authConfigs.getNacosAuthSystemType())) {
|
|
||||||
auth.authenticationProvider(ldapAuthenticationProvider);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void configure(HttpSecurity http) throws Exception {
|
|
||||||
|
|
||||||
if (StringUtils.isBlank(authConfigs.getNacosAuthSystemType())) {
|
|
||||||
http.csrf().disable().cors()// We don't need CSRF for JWT based authentication
|
|
||||||
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
|
|
||||||
.and().authorizeRequests().requestMatchers(CorsUtils::isPreFlightRequest).permitAll()
|
|
||||||
.antMatchers(LOGIN_ENTRY_POINT).permitAll()
|
|
||||||
.and().authorizeRequests().antMatchers(TOKEN_BASED_AUTH_ENTRY_POINT).authenticated()
|
|
||||||
.and().exceptionHandling().authenticationEntryPoint(new JwtAuthenticationEntryPoint());
|
|
||||||
// disable cache
|
|
||||||
http.headers().cacheControl();
|
|
||||||
|
|
||||||
http.addFilterBefore(new JwtAuthenticationTokenFilter(tokenProvider),
|
|
||||||
UsernamePasswordAuthenticationFilter.class);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public PasswordEncoder passwordEncoder() {
|
|
||||||
return new BCryptPasswordEncoder();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,204 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
|
||||||
*
|
|
||||||
* 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 com.alibaba.nacos.console.security.nacos;
|
|
||||||
|
|
||||||
import com.alibaba.nacos.api.common.Constants;
|
|
||||||
import com.alibaba.nacos.api.remote.request.Request;
|
|
||||||
import com.alibaba.nacos.auth.AuthManager;
|
|
||||||
import com.alibaba.nacos.auth.exception.AccessException;
|
|
||||||
import com.alibaba.nacos.auth.model.Permission;
|
|
||||||
import com.alibaba.nacos.auth.model.User;
|
|
||||||
import com.alibaba.nacos.common.utils.StringUtils;
|
|
||||||
import com.alibaba.nacos.config.server.auth.RoleInfo;
|
|
||||||
import com.alibaba.nacos.config.server.utils.RequestUtil;
|
|
||||||
import com.alibaba.nacos.console.security.nacos.roles.NacosRoleServiceImpl;
|
|
||||||
import com.alibaba.nacos.console.security.nacos.users.NacosUser;
|
|
||||||
import com.alibaba.nacos.core.utils.Loggers;
|
|
||||||
import io.jsonwebtoken.ExpiredJwtException;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
|
||||||
import org.springframework.security.core.Authentication;
|
|
||||||
import org.springframework.security.core.AuthenticationException;
|
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builtin access control entry of Nacos.
|
|
||||||
*
|
|
||||||
* @author nkorange
|
|
||||||
* @since 1.2.0
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
public class NacosAuthManager implements AuthManager {
|
|
||||||
|
|
||||||
private static final String TOKEN_PREFIX = "Bearer ";
|
|
||||||
|
|
||||||
private static final String PARAM_USERNAME = "username";
|
|
||||||
|
|
||||||
private static final String PARAM_PASSWORD = "password";
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private JwtTokenManager tokenManager;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private AuthenticationManager authenticationManager;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private NacosRoleServiceImpl roleService;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public User login(Object request) throws AccessException {
|
|
||||||
HttpServletRequest req = (HttpServletRequest) request;
|
|
||||||
String token = resolveToken(req);
|
|
||||||
if (StringUtils.isBlank(token)) {
|
|
||||||
throw new AccessException("user not found!");
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
tokenManager.validateToken(token);
|
|
||||||
} catch (ExpiredJwtException e) {
|
|
||||||
throw new AccessException("token expired!");
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new AccessException("token invalid!");
|
|
||||||
}
|
|
||||||
|
|
||||||
Authentication authentication = tokenManager.getAuthentication(token);
|
|
||||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
|
||||||
|
|
||||||
String username = authentication.getName();
|
|
||||||
NacosUser user = new NacosUser();
|
|
||||||
user.setUserName(username);
|
|
||||||
user.setToken(token);
|
|
||||||
List<RoleInfo> roleInfoList = roleService.getRoles(username);
|
|
||||||
if (roleInfoList != null) {
|
|
||||||
for (RoleInfo roleInfo : roleInfoList) {
|
|
||||||
if (roleInfo.getRole().equals(NacosRoleServiceImpl.GLOBAL_ADMIN_ROLE)) {
|
|
||||||
user.setGlobalAdmin(true);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
req.setAttribute(RequestUtil.NACOS_USER_KEY, user);
|
|
||||||
return user;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public User loginRemote(Object request) throws AccessException {
|
|
||||||
Request req = (Request) request;
|
|
||||||
String token = resolveToken(req);
|
|
||||||
if (StringUtils.isBlank(token)) {
|
|
||||||
throw new AccessException("user not found!");
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
tokenManager.validateToken(token);
|
|
||||||
} catch (ExpiredJwtException e) {
|
|
||||||
throw new AccessException("token expired!");
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new AccessException("token invalid!");
|
|
||||||
}
|
|
||||||
|
|
||||||
Authentication authentication = tokenManager.getAuthentication(token);
|
|
||||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
|
||||||
|
|
||||||
String username = authentication.getName();
|
|
||||||
NacosUser user = new NacosUser();
|
|
||||||
user.setUserName(username);
|
|
||||||
user.setToken(token);
|
|
||||||
List<RoleInfo> roleInfoList = roleService.getRoles(username);
|
|
||||||
if (roleInfoList != null) {
|
|
||||||
for (RoleInfo roleInfo : roleInfoList) {
|
|
||||||
if (roleInfo.getRole().equals(NacosRoleServiceImpl.GLOBAL_ADMIN_ROLE)) {
|
|
||||||
user.setGlobalAdmin(true);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return user;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void auth(Permission permission, User user) throws AccessException {
|
|
||||||
if (Loggers.AUTH.isDebugEnabled()) {
|
|
||||||
Loggers.AUTH.debug("auth permission: {}, user: {}", permission, user);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!roleService.hasPermission(user.getUserName(), permission)) {
|
|
||||||
throw new AccessException("authorization failed!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get token from header.
|
|
||||||
*/
|
|
||||||
private String resolveToken(HttpServletRequest request) throws AccessException {
|
|
||||||
String bearerToken = request.getHeader(NacosAuthConfig.AUTHORIZATION_HEADER);
|
|
||||||
if (StringUtils.isNotBlank(bearerToken) && bearerToken.startsWith(TOKEN_PREFIX)) {
|
|
||||||
return bearerToken.substring(7);
|
|
||||||
}
|
|
||||||
bearerToken = request.getParameter(Constants.ACCESS_TOKEN);
|
|
||||||
if (StringUtils.isBlank(bearerToken)) {
|
|
||||||
String userName = request.getParameter(PARAM_USERNAME);
|
|
||||||
String password = request.getParameter(PARAM_PASSWORD);
|
|
||||||
bearerToken = resolveTokenFromUser(userName, password);
|
|
||||||
}
|
|
||||||
|
|
||||||
return bearerToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get token from header.
|
|
||||||
*/
|
|
||||||
private String resolveToken(Request request) throws AccessException {
|
|
||||||
String bearerToken = request.getHeader(NacosAuthConfig.AUTHORIZATION_HEADER);
|
|
||||||
if (StringUtils.isNotBlank(bearerToken) && bearerToken.startsWith(TOKEN_PREFIX)) {
|
|
||||||
return bearerToken.substring(7);
|
|
||||||
}
|
|
||||||
bearerToken = request.getHeader(Constants.ACCESS_TOKEN);
|
|
||||||
if (StringUtils.isBlank(bearerToken)) {
|
|
||||||
String userName = request.getHeader(PARAM_USERNAME);
|
|
||||||
String password = request.getHeader(PARAM_PASSWORD);
|
|
||||||
bearerToken = resolveTokenFromUser(userName, password);
|
|
||||||
}
|
|
||||||
|
|
||||||
return bearerToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String resolveTokenFromUser(String userName, String rawPassword) throws AccessException {
|
|
||||||
String finalName;
|
|
||||||
Authentication authenticate;
|
|
||||||
try {
|
|
||||||
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userName,
|
|
||||||
rawPassword);
|
|
||||||
authenticate = authenticationManager.authenticate(authenticationToken);
|
|
||||||
} catch (AuthenticationException e) {
|
|
||||||
throw new AccessException("unknown user!");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (null == authenticate || StringUtils.isBlank(authenticate.getName())) {
|
|
||||||
finalName = userName;
|
|
||||||
} else {
|
|
||||||
finalName = authenticate.getName();
|
|
||||||
}
|
|
||||||
|
|
||||||
return tokenManager.createToken(finalName);
|
|
||||||
}
|
|
||||||
}
|
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package com.alibaba.nacos.console.security.nacos.roles;
|
package com.alibaba.nacos.console.security.nacos.roles;
|
||||||
|
|
||||||
|
import com.alibaba.nacos.auth.NacosAuthConfig;
|
||||||
import com.alibaba.nacos.auth.common.AuthConfigs;
|
import com.alibaba.nacos.auth.common.AuthConfigs;
|
||||||
import com.alibaba.nacos.auth.model.Permission;
|
import com.alibaba.nacos.auth.model.Permission;
|
||||||
import com.alibaba.nacos.common.utils.StringUtils;
|
import com.alibaba.nacos.common.utils.StringUtils;
|
||||||
@ -24,7 +25,6 @@ import com.alibaba.nacos.config.server.auth.PermissionPersistService;
|
|||||||
import com.alibaba.nacos.config.server.auth.RoleInfo;
|
import com.alibaba.nacos.config.server.auth.RoleInfo;
|
||||||
import com.alibaba.nacos.config.server.auth.RolePersistService;
|
import com.alibaba.nacos.config.server.auth.RolePersistService;
|
||||||
import com.alibaba.nacos.config.server.model.Page;
|
import com.alibaba.nacos.config.server.model.Page;
|
||||||
import com.alibaba.nacos.console.security.nacos.NacosAuthConfig;
|
|
||||||
import com.alibaba.nacos.console.security.nacos.users.NacosUserDetailsServiceImpl;
|
import com.alibaba.nacos.console.security.nacos.users.NacosUserDetailsServiceImpl;
|
||||||
import com.alibaba.nacos.core.utils.Loggers;
|
import com.alibaba.nacos.core.utils.Loggers;
|
||||||
import io.jsonwebtoken.lang.Collections;
|
import io.jsonwebtoken.lang.Collections;
|
||||||
|
@ -36,8 +36,8 @@ server.servlet.contextPath=/nacos
|
|||||||
|
|
||||||
### Connect URL of DB:
|
### Connect URL of DB:
|
||||||
# db.url.0=jdbc:mysql://127.0.0.1:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
|
# db.url.0=jdbc:mysql://127.0.0.1:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
|
||||||
# db.user.0=nacos
|
# db.user.0=root
|
||||||
# db.password.0=nacos
|
# db.password.0=2016210285
|
||||||
|
|
||||||
#*************** Naming Module Related Configurations ***************#
|
#*************** Naming Module Related Configurations ***************#
|
||||||
### Data dispatch task execution period in milliseconds:
|
### Data dispatch task execution period in milliseconds:
|
||||||
@ -114,11 +114,11 @@ server.tomcat.basedir=
|
|||||||
### The ignore urls of auth, is deprecated in 1.2.0:
|
### The ignore urls of auth, is deprecated in 1.2.0:
|
||||||
nacos.security.ignore.urls=/,/error,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-ui/public/**,/v1/auth/**,/v1/console/health/**,/actuator/**,/v1/console/server/**
|
nacos.security.ignore.urls=/,/error,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-ui/public/**,/v1/auth/**,/v1/console/health/**,/actuator/**,/v1/console/server/**
|
||||||
|
|
||||||
### The auth system to use, currently only 'nacos' and 'ldap' is supported:
|
### The auth system to use, currently only 'USERNAME_PASSWORD' and 'ldap' is supported:
|
||||||
nacos.core.auth.system.type=nacos
|
nacos.core.auth.system.type=USERNAME_PASSWORD
|
||||||
|
|
||||||
### If turn on auth system:
|
### If turn on auth system:
|
||||||
nacos.core.auth.enabled=false
|
nacos.core.auth.enabled=true
|
||||||
|
|
||||||
### worked when nacos.core.auth.system.type=ldap,{0} is Placeholder,replace login username
|
### worked when nacos.core.auth.system.type=ldap,{0} is Placeholder,replace login username
|
||||||
# nacos.core.auth.ldap.url=ldap://localhost:389
|
# nacos.core.auth.ldap.url=ldap://localhost:389
|
||||||
@ -142,7 +142,7 @@ nacos.core.auth.server.identity.key=serverIdentity
|
|||||||
nacos.core.auth.server.identity.value=security
|
nacos.core.auth.server.identity.value=security
|
||||||
|
|
||||||
### authority key in request:
|
### authority key in request:
|
||||||
nacos.core.auth.authorityKey=authority,username,password
|
nacos.core.auth.authorityKey=accessToken,username,password
|
||||||
|
|
||||||
#*************** Istio Related Configurations ***************#
|
#*************** Istio Related Configurations ***************#
|
||||||
### If turn on the MCP server:
|
### If turn on the MCP server:
|
||||||
|
@ -1,88 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
|
||||||
*
|
|
||||||
* 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 com.alibaba.nacos.console.controller;
|
|
||||||
|
|
||||||
import com.alibaba.nacos.auth.common.AuthConfigs;
|
|
||||||
import com.alibaba.nacos.auth.common.AuthSystemTypes;
|
|
||||||
import com.alibaba.nacos.auth.exception.AccessException;
|
|
||||||
import com.alibaba.nacos.console.security.nacos.NacosAuthManager;
|
|
||||||
import com.alibaba.nacos.console.security.nacos.users.NacosUser;
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
import org.mockito.Mock;
|
|
||||||
import org.mockito.junit.MockitoJUnitRunner;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
|
||||||
import static org.junit.Assert.assertThat;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
|
|
||||||
@RunWith(MockitoJUnitRunner.class)
|
|
||||||
public class UserControllerTest {
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
private HttpServletRequest request;
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
private HttpServletResponse response;
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
private AuthConfigs authConfigs;
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
private NacosAuthManager authManager;
|
|
||||||
|
|
||||||
private UserController userController;
|
|
||||||
|
|
||||||
private NacosUser user;
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void setUp() throws Exception {
|
|
||||||
userController = new UserController();
|
|
||||||
user = new NacosUser();
|
|
||||||
user.setUserName("nacos");
|
|
||||||
user.setGlobalAdmin(true);
|
|
||||||
user.setToken("1234567890");
|
|
||||||
injectObject("authConfigs", authConfigs);
|
|
||||||
injectObject("authManager", authManager);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testLoginWithAuthedUser() throws AccessException {
|
|
||||||
when(authManager.login(request)).thenReturn(user);
|
|
||||||
when(authConfigs.getNacosAuthSystemType()).thenReturn(AuthSystemTypes.NACOS.name());
|
|
||||||
when(authConfigs.getTokenValidityInSeconds()).thenReturn(18000L);
|
|
||||||
Object actual = userController.login("nacos", "nacos", response, request);
|
|
||||||
assertThat(actual, instanceOf(JsonNode.class));
|
|
||||||
String actualString = actual.toString();
|
|
||||||
assertTrue(actualString.contains("\"accessToken\":\"1234567890\""));
|
|
||||||
assertTrue(actualString.contains("\"tokenTtl\":18000"));
|
|
||||||
assertTrue(actualString.contains("\"globalAdmin\":true"));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void injectObject(String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException {
|
|
||||||
Field field = UserController.class.getDeclaredField(fieldName);
|
|
||||||
field.setAccessible(true);
|
|
||||||
field.set(userController, value);
|
|
||||||
}
|
|
||||||
}
|
|
@ -16,9 +16,14 @@
|
|||||||
|
|
||||||
package com.alibaba.nacos.core.auth;
|
package com.alibaba.nacos.core.auth;
|
||||||
|
|
||||||
import com.alibaba.nacos.auth.AuthManager;
|
import com.alibaba.nacos.auth.AuthPluginManager;
|
||||||
|
import com.alibaba.nacos.auth.AuthService;
|
||||||
|
import com.alibaba.nacos.auth.NacosAuthConfig;
|
||||||
import com.alibaba.nacos.auth.annotation.Secured;
|
import com.alibaba.nacos.auth.annotation.Secured;
|
||||||
import com.alibaba.nacos.auth.common.AuthConfigs;
|
import com.alibaba.nacos.auth.common.AuthConfigs;
|
||||||
|
import com.alibaba.nacos.auth.context.HttpIdentityContextBuilder;
|
||||||
|
import com.alibaba.nacos.auth.context.IdentityContext;
|
||||||
|
import com.alibaba.nacos.auth.context.IdentityContextBuilder;
|
||||||
import com.alibaba.nacos.auth.exception.AccessException;
|
import com.alibaba.nacos.auth.exception.AccessException;
|
||||||
import com.alibaba.nacos.auth.model.Permission;
|
import com.alibaba.nacos.auth.model.Permission;
|
||||||
import com.alibaba.nacos.auth.parser.ResourceParser;
|
import com.alibaba.nacos.auth.parser.ResourceParser;
|
||||||
@ -53,9 +58,6 @@ public class AuthFilter implements Filter {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private AuthConfigs authConfigs;
|
private AuthConfigs authConfigs;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private AuthManager authManager;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ControllerMethodsCache methodsCache;
|
private ControllerMethodsCache methodsCache;
|
||||||
|
|
||||||
@ -123,9 +125,11 @@ public class AuthFilter implements Filter {
|
|||||||
// deny if we don't find any resource:
|
// deny if we don't find any resource:
|
||||||
throw new AccessException("resource name invalid!");
|
throw new AccessException("resource name invalid!");
|
||||||
}
|
}
|
||||||
|
AuthService authService = AuthPluginManager.getInstance().findAuthServiceSpiImpl(authConfigs.getNacosAuthSystemType()).get();
|
||||||
authManager.auth(new Permission(resource, action), authManager.login(req));
|
IdentityContextBuilder<HttpServletRequest> identityContextBuilder = new HttpIdentityContextBuilder(authConfigs);
|
||||||
|
IdentityContext identityContext = identityContextBuilder.build(req);
|
||||||
|
authService.authorityAccess(identityContext, new Permission(resource, action));
|
||||||
|
req.setAttribute(NacosAuthConfig.NACOS_IDENTITY_KEY, identityContext);
|
||||||
}
|
}
|
||||||
chain.doFilter(request, response);
|
chain.doFilter(request, response);
|
||||||
} catch (AccessException e) {
|
} catch (AccessException e) {
|
||||||
|
@ -20,9 +20,13 @@ import com.alibaba.nacos.api.exception.NacosException;
|
|||||||
import com.alibaba.nacos.api.remote.request.Request;
|
import com.alibaba.nacos.api.remote.request.Request;
|
||||||
import com.alibaba.nacos.api.remote.request.RequestMeta;
|
import com.alibaba.nacos.api.remote.request.RequestMeta;
|
||||||
import com.alibaba.nacos.api.remote.response.Response;
|
import com.alibaba.nacos.api.remote.response.Response;
|
||||||
import com.alibaba.nacos.auth.AuthManager;
|
import com.alibaba.nacos.auth.AuthPluginManager;
|
||||||
|
import com.alibaba.nacos.auth.AuthService;
|
||||||
import com.alibaba.nacos.auth.annotation.Secured;
|
import com.alibaba.nacos.auth.annotation.Secured;
|
||||||
import com.alibaba.nacos.auth.common.AuthConfigs;
|
import com.alibaba.nacos.auth.common.AuthConfigs;
|
||||||
|
import com.alibaba.nacos.auth.context.GrpcIdentityContextBuilder;
|
||||||
|
import com.alibaba.nacos.auth.context.IdentityContext;
|
||||||
|
import com.alibaba.nacos.auth.context.IdentityContextBuilder;
|
||||||
import com.alibaba.nacos.auth.exception.AccessException;
|
import com.alibaba.nacos.auth.exception.AccessException;
|
||||||
import com.alibaba.nacos.auth.model.Permission;
|
import com.alibaba.nacos.auth.model.Permission;
|
||||||
import com.alibaba.nacos.auth.parser.ResourceParser;
|
import com.alibaba.nacos.auth.parser.ResourceParser;
|
||||||
@ -47,9 +51,6 @@ public class RemoteRequestAuthFilter extends AbstractRequestFilter {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private AuthConfigs authConfigs;
|
private AuthConfigs authConfigs;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private AuthManager authManager;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Response filter(Request request, RequestMeta meta, Class handlerClazz) throws NacosException {
|
public Response filter(Request request, RequestMeta meta, Class handlerClazz) throws NacosException {
|
||||||
|
|
||||||
@ -75,14 +76,18 @@ public class RemoteRequestAuthFilter extends AbstractRequestFilter {
|
|||||||
// deny if we don't find any resource:
|
// deny if we don't find any resource:
|
||||||
throw new AccessException("resource name invalid!");
|
throw new AccessException("resource name invalid!");
|
||||||
}
|
}
|
||||||
|
AuthService authService = AuthPluginManager.getInstance().findAuthServiceSpiImpl(authConfigs.getNacosAuthSystemType()).get();
|
||||||
authManager.auth(new Permission(resource, action), authManager.loginRemote(request));
|
|
||||||
|
IdentityContextBuilder<Request> identityContextBuilder = new GrpcIdentityContextBuilder(authConfigs);
|
||||||
|
IdentityContext identityContext = identityContextBuilder.build(request);
|
||||||
|
authService.authorityAccess(identityContext, new Permission(resource, action));
|
||||||
|
for (String key : identityContext.getAllKey()) {
|
||||||
|
request.putHeader(key, (String) identityContext.getParameter(key));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (AccessException e) {
|
} catch (AccessException e) {
|
||||||
if (Loggers.AUTH.isDebugEnabled()) {
|
if (Loggers.AUTH.isDebugEnabled()) {
|
||||||
Loggers.AUTH.debug("access denied, request: {}, reason: {}", request.getClass().getSimpleName(),
|
Loggers.AUTH.debug("access denied, request: {}, reason: {}", request.getClass().getSimpleName(), e.getErrMsg());
|
||||||
e.getErrMsg());
|
|
||||||
}
|
}
|
||||||
Response defaultResponseInstance = getDefaultResponseInstance(handlerClazz);
|
Response defaultResponseInstance = getDefaultResponseInstance(handlerClazz);
|
||||||
defaultResponseInstance.setErrorInfo(NacosException.NO_RIGHT, e.getErrMsg());
|
defaultResponseInstance.setErrorInfo(NacosException.NO_RIGHT, e.getErrMsg());
|
||||||
|
@ -17,19 +17,21 @@
|
|||||||
|
|
||||||
package com.alibaba.nacos.core.auth;
|
package com.alibaba.nacos.core.auth;
|
||||||
|
|
||||||
import com.alibaba.nacos.auth.AuthManager;
|
|
||||||
import com.alibaba.nacos.auth.annotation.Secured;
|
import com.alibaba.nacos.auth.annotation.Secured;
|
||||||
import com.alibaba.nacos.auth.common.AuthConfigs;
|
import com.alibaba.nacos.auth.common.AuthConfigs;
|
||||||
import com.alibaba.nacos.common.constant.HttpHeaderConsts;
|
import com.alibaba.nacos.common.constant.HttpHeaderConsts;
|
||||||
import com.alibaba.nacos.core.code.ControllerMethodsCache;
|
import com.alibaba.nacos.core.code.ControllerMethodsCache;
|
||||||
import com.alibaba.nacos.sys.env.Constants;
|
import com.alibaba.nacos.sys.env.Constants;
|
||||||
|
import com.alibaba.nacos.sys.utils.ApplicationUtils;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.Mockito;
|
import org.mockito.Mockito;
|
||||||
import org.mockito.junit.MockitoJUnitRunner;
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
import org.springframework.mock.web.MockHttpServletRequest;
|
import org.springframework.mock.web.MockHttpServletRequest;
|
||||||
import org.springframework.mock.web.MockHttpServletResponse;
|
import org.springframework.mock.web.MockHttpServletResponse;
|
||||||
|
|
||||||
@ -56,10 +58,15 @@ public class AuthFilterTest {
|
|||||||
private AuthConfigs authConfigs;
|
private AuthConfigs authConfigs;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private AuthManager authManager;
|
private ControllerMethodsCache methodsCache;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private ControllerMethodsCache methodsCache;
|
private ConfigurableApplicationContext context;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
ApplicationUtils.injectContext(context);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDoFilter() {
|
public void testDoFilter() {
|
||||||
@ -73,13 +80,13 @@ public class AuthFilterTest {
|
|||||||
Mockito.when(authConfigs.isEnableUserAgentAuthWhite()).thenReturn(true);
|
Mockito.when(authConfigs.isEnableUserAgentAuthWhite()).thenReturn(true);
|
||||||
request.addHeader(HttpHeaderConsts.USER_AGENT_HEADER, Constants.NACOS_SERVER_HEADER);
|
request.addHeader(HttpHeaderConsts.USER_AGENT_HEADER, Constants.NACOS_SERVER_HEADER);
|
||||||
authFilter.doFilter(request, response, filterChain);
|
authFilter.doFilter(request, response, filterChain);
|
||||||
|
|
||||||
Mockito.when(authConfigs.isEnableUserAgentAuthWhite()).thenReturn(false);
|
Mockito.when(authConfigs.isEnableUserAgentAuthWhite()).thenReturn(false);
|
||||||
Mockito.when(authConfigs.getServerIdentityKey()).thenReturn("1");
|
Mockito.when(authConfigs.getServerIdentityKey()).thenReturn("1");
|
||||||
Mockito.when(authConfigs.getServerIdentityValue()).thenReturn("2");
|
Mockito.when(authConfigs.getServerIdentityValue()).thenReturn("2");
|
||||||
request.addHeader("1", "2");
|
request.addHeader("1", "2");
|
||||||
authFilter.doFilter(request, response, filterChain);
|
authFilter.doFilter(request, response, filterChain);
|
||||||
|
|
||||||
Mockito.when(authConfigs.getServerIdentityValue()).thenReturn("3");
|
Mockito.when(authConfigs.getServerIdentityValue()).thenReturn("3");
|
||||||
authFilter.doFilter(request, response, filterChain);
|
authFilter.doFilter(request, response, filterChain);
|
||||||
|
|
||||||
@ -93,7 +100,7 @@ public class AuthFilterTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class MockFilterChain implements FilterChain {
|
class MockFilterChain implements FilterChain {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse) throws IOException, ServletException {
|
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse) throws IOException, ServletException {
|
||||||
System.out.println("filter chain executed");
|
System.out.println("filter chain executed");
|
||||||
|
@ -147,7 +147,7 @@ nacos.core.auth.system.type=nacos
|
|||||||
nacos.core.auth.enabled=false
|
nacos.core.auth.enabled=false
|
||||||
|
|
||||||
### authority key in request:
|
### authority key in request:
|
||||||
nacos.core.auth.authorityKey=authority,username,password
|
nacos.core.auth.authorityKey=accessToken,username,password
|
||||||
|
|
||||||
### worked when nacos.core.auth.system.type=ldap,{0} is Placeholder,replace login username
|
### worked when nacos.core.auth.system.type=ldap,{0} is Placeholder,replace login username
|
||||||
# nacos.core.auth.ldap.url=ldap://localhost:389
|
# nacos.core.auth.ldap.url=ldap://localhost:389
|
||||||
|
Loading…
Reference in New Issue
Block a user