* [ISSUE #9906] cache token to improve performance * [ISSUE #9906] add cache token enable switch to application.properties * [ISSUE #9906] update javadoc * [ISSUE #9906] update javadoc * [ISSUE #9906] update unit test * [ISSUE #9906] make ci rerun
This commit is contained in:
parent
1ff7a3f6bd
commit
5a8c567633
@ -125,6 +125,7 @@ nacos.core.auth.server.identity.value=security
|
|||||||
|
|
||||||
### worked when nacos.core.auth.system.type=nacos
|
### worked when nacos.core.auth.system.type=nacos
|
||||||
### The token expiration in seconds:
|
### The token expiration in seconds:
|
||||||
|
nacos.core.auth.plugin.nacos.token.cache.enable=false
|
||||||
nacos.core.auth.plugin.nacos.token.expire.seconds=18000
|
nacos.core.auth.plugin.nacos.token.expire.seconds=18000
|
||||||
### The default token (Base64 string):
|
### The default token (Base64 string):
|
||||||
nacos.core.auth.plugin.nacos.token.secret.key=SecretKey012345678901234567890123456789012345678901234567890123456789
|
nacos.core.auth.plugin.nacos.token.secret.key=SecretKey012345678901234567890123456789012345678901234567890123456789
|
||||||
|
@ -148,6 +148,7 @@ nacos.core.auth.server.identity.value=security
|
|||||||
|
|
||||||
### worked when nacos.core.auth.system.type=nacos
|
### worked when nacos.core.auth.system.type=nacos
|
||||||
### The token expiration in seconds:
|
### The token expiration in seconds:
|
||||||
|
nacos.core.auth.plugin.nacos.token.cache.enable=false
|
||||||
nacos.core.auth.plugin.nacos.token.expire.seconds=18000
|
nacos.core.auth.plugin.nacos.token.expire.seconds=18000
|
||||||
### The default token (Base64 String):
|
### The default token (Base64 String):
|
||||||
nacos.core.auth.plugin.nacos.token.secret.key=SecretKey012345678901234567890123456789012345678901234567890123456789
|
nacos.core.auth.plugin.nacos.token.secret.key=SecretKey012345678901234567890123456789012345678901234567890123456789
|
||||||
|
@ -21,6 +21,7 @@ import com.alibaba.nacos.plugin.auth.impl.authenticate.LdapAuthenticationManager
|
|||||||
import com.alibaba.nacos.plugin.auth.impl.configuration.ConditionOnLdapAuth;
|
import com.alibaba.nacos.plugin.auth.impl.configuration.ConditionOnLdapAuth;
|
||||||
import com.alibaba.nacos.plugin.auth.impl.constant.AuthConstants;
|
import com.alibaba.nacos.plugin.auth.impl.constant.AuthConstants;
|
||||||
import com.alibaba.nacos.plugin.auth.impl.roles.NacosRoleServiceImpl;
|
import com.alibaba.nacos.plugin.auth.impl.roles.NacosRoleServiceImpl;
|
||||||
|
import com.alibaba.nacos.plugin.auth.impl.token.TokenManagerDelegate;
|
||||||
import com.alibaba.nacos.plugin.auth.impl.users.NacosUserDetailsServiceImpl;
|
import com.alibaba.nacos.plugin.auth.impl.users.NacosUserDetailsServiceImpl;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||||
@ -83,7 +84,7 @@ public class LdapAuthConfig {
|
|||||||
@Bean
|
@Bean
|
||||||
@Conditional(ConditionOnLdapAuth.class)
|
@Conditional(ConditionOnLdapAuth.class)
|
||||||
public IAuthenticationManager ldapAuthenticatoinManager(LdapTemplate ldapTemplate,
|
public IAuthenticationManager ldapAuthenticatoinManager(LdapTemplate ldapTemplate,
|
||||||
NacosUserDetailsServiceImpl userDetailsService, JwtTokenManager jwtTokenManager,
|
NacosUserDetailsServiceImpl userDetailsService, TokenManagerDelegate jwtTokenManager,
|
||||||
NacosRoleServiceImpl roleService) {
|
NacosRoleServiceImpl roleService) {
|
||||||
return new LdapAuthenticationManager(ldapTemplate, userDetailsService, jwtTokenManager, roleService,
|
return new LdapAuthenticationManager(ldapTemplate, userDetailsService, jwtTokenManager, roleService,
|
||||||
filterPrefix, caseSensitive);
|
filterPrefix, caseSensitive);
|
||||||
|
@ -26,6 +26,7 @@ import com.alibaba.nacos.plugin.auth.impl.authenticate.LdapAuthenticationManager
|
|||||||
import com.alibaba.nacos.plugin.auth.impl.constant.AuthSystemTypes;
|
import com.alibaba.nacos.plugin.auth.impl.constant.AuthSystemTypes;
|
||||||
import com.alibaba.nacos.plugin.auth.impl.filter.JwtAuthenticationTokenFilter;
|
import com.alibaba.nacos.plugin.auth.impl.filter.JwtAuthenticationTokenFilter;
|
||||||
import com.alibaba.nacos.plugin.auth.impl.roles.NacosRoleServiceImpl;
|
import com.alibaba.nacos.plugin.auth.impl.roles.NacosRoleServiceImpl;
|
||||||
|
import com.alibaba.nacos.plugin.auth.impl.token.TokenManagerDelegate;
|
||||||
import com.alibaba.nacos.plugin.auth.impl.users.NacosUserDetailsServiceImpl;
|
import com.alibaba.nacos.plugin.auth.impl.users.NacosUserDetailsServiceImpl;
|
||||||
import org.springframework.beans.factory.ObjectProvider;
|
import org.springframework.beans.factory.ObjectProvider;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
@ -66,7 +67,7 @@ public class NacosAuthConfig extends WebSecurityConfigurerAdapter {
|
|||||||
|
|
||||||
private final Environment env;
|
private final Environment env;
|
||||||
|
|
||||||
private final JwtTokenManager tokenProvider;
|
private final TokenManagerDelegate tokenProvider;
|
||||||
|
|
||||||
private final AuthConfigs authConfigs;
|
private final AuthConfigs authConfigs;
|
||||||
|
|
||||||
@ -76,7 +77,7 @@ public class NacosAuthConfig extends WebSecurityConfigurerAdapter {
|
|||||||
|
|
||||||
private final ControllerMethodsCache methodsCache;
|
private final ControllerMethodsCache methodsCache;
|
||||||
|
|
||||||
public NacosAuthConfig(Environment env, JwtTokenManager tokenProvider, AuthConfigs authConfigs,
|
public NacosAuthConfig(Environment env, TokenManagerDelegate tokenProvider, AuthConfigs authConfigs,
|
||||||
NacosUserDetailsServiceImpl userDetailsService,
|
NacosUserDetailsServiceImpl userDetailsService,
|
||||||
ObjectProvider<LdapAuthenticationProvider> ldapAuthenticationProvider,
|
ObjectProvider<LdapAuthenticationProvider> ldapAuthenticationProvider,
|
||||||
ControllerMethodsCache methodsCache) {
|
ControllerMethodsCache methodsCache) {
|
||||||
@ -166,7 +167,7 @@ public class NacosAuthConfig extends WebSecurityConfigurerAdapter {
|
|||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public IAuthenticationManager defaultAuthenticationManager(NacosUserDetailsServiceImpl userDetailsService,
|
public IAuthenticationManager defaultAuthenticationManager(NacosUserDetailsServiceImpl userDetailsService,
|
||||||
JwtTokenManager jwtTokenManager, NacosRoleServiceImpl roleService) {
|
TokenManagerDelegate jwtTokenManager, NacosRoleServiceImpl roleService) {
|
||||||
return new DefaultAuthenticationManager(userDetailsService, jwtTokenManager, roleService);
|
return new DefaultAuthenticationManager(userDetailsService, jwtTokenManager, roleService);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ import com.alibaba.nacos.plugin.auth.exception.AccessException;
|
|||||||
import com.alibaba.nacos.plugin.auth.impl.constant.AuthConstants;
|
import com.alibaba.nacos.plugin.auth.impl.constant.AuthConstants;
|
||||||
import com.alibaba.nacos.plugin.auth.impl.persistence.RoleInfo;
|
import com.alibaba.nacos.plugin.auth.impl.persistence.RoleInfo;
|
||||||
import com.alibaba.nacos.plugin.auth.impl.roles.NacosRoleServiceImpl;
|
import com.alibaba.nacos.plugin.auth.impl.roles.NacosRoleServiceImpl;
|
||||||
|
import com.alibaba.nacos.plugin.auth.impl.token.TokenManagerDelegate;
|
||||||
import com.alibaba.nacos.plugin.auth.impl.users.NacosUser;
|
import com.alibaba.nacos.plugin.auth.impl.users.NacosUser;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
@ -48,7 +49,7 @@ import java.util.List;
|
|||||||
public class NacosAuthManager {
|
public class NacosAuthManager {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private JwtTokenManager tokenManager;
|
private TokenManagerDelegate tokenManager;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private AuthenticationManager authenticationManager;
|
private AuthenticationManager authenticationManager;
|
||||||
|
@ -21,9 +21,9 @@ import com.alibaba.nacos.common.utils.StringUtils;
|
|||||||
import com.alibaba.nacos.core.utils.Loggers;
|
import com.alibaba.nacos.core.utils.Loggers;
|
||||||
import com.alibaba.nacos.plugin.auth.api.Permission;
|
import com.alibaba.nacos.plugin.auth.api.Permission;
|
||||||
import com.alibaba.nacos.plugin.auth.exception.AccessException;
|
import com.alibaba.nacos.plugin.auth.exception.AccessException;
|
||||||
import com.alibaba.nacos.plugin.auth.impl.JwtTokenManager;
|
|
||||||
import com.alibaba.nacos.plugin.auth.impl.constant.AuthConstants;
|
import com.alibaba.nacos.plugin.auth.impl.constant.AuthConstants;
|
||||||
import com.alibaba.nacos.plugin.auth.impl.roles.NacosRoleServiceImpl;
|
import com.alibaba.nacos.plugin.auth.impl.roles.NacosRoleServiceImpl;
|
||||||
|
import com.alibaba.nacos.plugin.auth.impl.token.TokenManagerDelegate;
|
||||||
import com.alibaba.nacos.plugin.auth.impl.users.NacosUser;
|
import com.alibaba.nacos.plugin.auth.impl.users.NacosUser;
|
||||||
import com.alibaba.nacos.plugin.auth.impl.users.NacosUserDetails;
|
import com.alibaba.nacos.plugin.auth.impl.users.NacosUserDetails;
|
||||||
import com.alibaba.nacos.plugin.auth.impl.users.NacosUserDetailsServiceImpl;
|
import com.alibaba.nacos.plugin.auth.impl.users.NacosUserDetailsServiceImpl;
|
||||||
@ -41,12 +41,12 @@ public class AbstractAuthenticationManager implements IAuthenticationManager {
|
|||||||
|
|
||||||
protected NacosUserDetailsServiceImpl userDetailsService;
|
protected NacosUserDetailsServiceImpl userDetailsService;
|
||||||
|
|
||||||
protected JwtTokenManager jwtTokenManager;
|
protected TokenManagerDelegate jwtTokenManager;
|
||||||
|
|
||||||
protected NacosRoleServiceImpl roleService;
|
protected NacosRoleServiceImpl roleService;
|
||||||
|
|
||||||
public AbstractAuthenticationManager(NacosUserDetailsServiceImpl userDetailsService,
|
public AbstractAuthenticationManager(NacosUserDetailsServiceImpl userDetailsService,
|
||||||
JwtTokenManager jwtTokenManager, NacosRoleServiceImpl roleService) {
|
TokenManagerDelegate jwtTokenManager, NacosRoleServiceImpl roleService) {
|
||||||
this.userDetailsService = userDetailsService;
|
this.userDetailsService = userDetailsService;
|
||||||
this.jwtTokenManager = jwtTokenManager;
|
this.jwtTokenManager = jwtTokenManager;
|
||||||
this.roleService = roleService;
|
this.roleService = roleService;
|
||||||
|
@ -16,8 +16,8 @@
|
|||||||
|
|
||||||
package com.alibaba.nacos.plugin.auth.impl.authenticate;
|
package com.alibaba.nacos.plugin.auth.impl.authenticate;
|
||||||
|
|
||||||
import com.alibaba.nacos.plugin.auth.impl.JwtTokenManager;
|
|
||||||
import com.alibaba.nacos.plugin.auth.impl.roles.NacosRoleServiceImpl;
|
import com.alibaba.nacos.plugin.auth.impl.roles.NacosRoleServiceImpl;
|
||||||
|
import com.alibaba.nacos.plugin.auth.impl.token.TokenManagerDelegate;
|
||||||
import com.alibaba.nacos.plugin.auth.impl.users.NacosUserDetailsServiceImpl;
|
import com.alibaba.nacos.plugin.auth.impl.users.NacosUserDetailsServiceImpl;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -28,8 +28,8 @@ import com.alibaba.nacos.plugin.auth.impl.users.NacosUserDetailsServiceImpl;
|
|||||||
*/
|
*/
|
||||||
public class DefaultAuthenticationManager extends AbstractAuthenticationManager {
|
public class DefaultAuthenticationManager extends AbstractAuthenticationManager {
|
||||||
|
|
||||||
public DefaultAuthenticationManager(NacosUserDetailsServiceImpl userDetailsService, JwtTokenManager jwtTokenManager,
|
public DefaultAuthenticationManager(NacosUserDetailsServiceImpl userDetailsService,
|
||||||
NacosRoleServiceImpl roleService) {
|
TokenManagerDelegate jwtTokenManager, NacosRoleServiceImpl roleService) {
|
||||||
super(userDetailsService, jwtTokenManager, roleService);
|
super(userDetailsService, jwtTokenManager, roleService);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,10 +19,10 @@ package com.alibaba.nacos.plugin.auth.impl.authenticate;
|
|||||||
import com.alibaba.nacos.common.utils.StringUtils;
|
import com.alibaba.nacos.common.utils.StringUtils;
|
||||||
import com.alibaba.nacos.core.utils.Loggers;
|
import com.alibaba.nacos.core.utils.Loggers;
|
||||||
import com.alibaba.nacos.plugin.auth.exception.AccessException;
|
import com.alibaba.nacos.plugin.auth.exception.AccessException;
|
||||||
import com.alibaba.nacos.plugin.auth.impl.JwtTokenManager;
|
|
||||||
import com.alibaba.nacos.plugin.auth.impl.constant.AuthConstants;
|
import com.alibaba.nacos.plugin.auth.impl.constant.AuthConstants;
|
||||||
import com.alibaba.nacos.plugin.auth.impl.persistence.User;
|
import com.alibaba.nacos.plugin.auth.impl.persistence.User;
|
||||||
import com.alibaba.nacos.plugin.auth.impl.roles.NacosRoleServiceImpl;
|
import com.alibaba.nacos.plugin.auth.impl.roles.NacosRoleServiceImpl;
|
||||||
|
import com.alibaba.nacos.plugin.auth.impl.token.TokenManagerDelegate;
|
||||||
import com.alibaba.nacos.plugin.auth.impl.users.NacosUser;
|
import com.alibaba.nacos.plugin.auth.impl.users.NacosUser;
|
||||||
import com.alibaba.nacos.plugin.auth.impl.users.NacosUserDetails;
|
import com.alibaba.nacos.plugin.auth.impl.users.NacosUserDetails;
|
||||||
import com.alibaba.nacos.plugin.auth.impl.users.NacosUserDetailsServiceImpl;
|
import com.alibaba.nacos.plugin.auth.impl.users.NacosUserDetailsServiceImpl;
|
||||||
@ -46,7 +46,7 @@ public class LdapAuthenticationManager extends AbstractAuthenticationManager {
|
|||||||
private final LdapTemplate ldapTemplate;
|
private final LdapTemplate ldapTemplate;
|
||||||
|
|
||||||
public LdapAuthenticationManager(LdapTemplate ldapTemplate, NacosUserDetailsServiceImpl userDetailsService,
|
public LdapAuthenticationManager(LdapTemplate ldapTemplate, NacosUserDetailsServiceImpl userDetailsService,
|
||||||
JwtTokenManager jwtTokenManager, NacosRoleServiceImpl roleService, String filterPrefix,
|
TokenManagerDelegate jwtTokenManager, NacosRoleServiceImpl roleService, String filterPrefix,
|
||||||
boolean caseSensitive) {
|
boolean caseSensitive) {
|
||||||
super(userDetailsService, jwtTokenManager, roleService);
|
super(userDetailsService, jwtTokenManager, roleService);
|
||||||
this.ldapTemplate = ldapTemplate;
|
this.ldapTemplate = ldapTemplate;
|
||||||
|
@ -26,13 +26,13 @@ import com.alibaba.nacos.config.server.model.Page;
|
|||||||
import com.alibaba.nacos.plugin.auth.api.IdentityContext;
|
import com.alibaba.nacos.plugin.auth.api.IdentityContext;
|
||||||
import com.alibaba.nacos.plugin.auth.constant.ActionTypes;
|
import com.alibaba.nacos.plugin.auth.constant.ActionTypes;
|
||||||
import com.alibaba.nacos.plugin.auth.exception.AccessException;
|
import com.alibaba.nacos.plugin.auth.exception.AccessException;
|
||||||
import com.alibaba.nacos.plugin.auth.impl.JwtTokenManager;
|
|
||||||
import com.alibaba.nacos.plugin.auth.impl.authenticate.IAuthenticationManager;
|
import com.alibaba.nacos.plugin.auth.impl.authenticate.IAuthenticationManager;
|
||||||
import com.alibaba.nacos.plugin.auth.impl.constant.AuthConstants;
|
import com.alibaba.nacos.plugin.auth.impl.constant.AuthConstants;
|
||||||
import com.alibaba.nacos.plugin.auth.impl.constant.AuthSystemTypes;
|
import com.alibaba.nacos.plugin.auth.impl.constant.AuthSystemTypes;
|
||||||
import com.alibaba.nacos.plugin.auth.impl.persistence.RoleInfo;
|
import com.alibaba.nacos.plugin.auth.impl.persistence.RoleInfo;
|
||||||
import com.alibaba.nacos.plugin.auth.impl.persistence.User;
|
import com.alibaba.nacos.plugin.auth.impl.persistence.User;
|
||||||
import com.alibaba.nacos.plugin.auth.impl.roles.NacosRoleServiceImpl;
|
import com.alibaba.nacos.plugin.auth.impl.roles.NacosRoleServiceImpl;
|
||||||
|
import com.alibaba.nacos.plugin.auth.impl.token.TokenManagerDelegate;
|
||||||
import com.alibaba.nacos.plugin.auth.impl.users.NacosUser;
|
import com.alibaba.nacos.plugin.auth.impl.users.NacosUser;
|
||||||
import com.alibaba.nacos.plugin.auth.impl.users.NacosUserDetailsServiceImpl;
|
import com.alibaba.nacos.plugin.auth.impl.users.NacosUserDetailsServiceImpl;
|
||||||
import com.alibaba.nacos.plugin.auth.impl.utils.PasswordEncoderUtil;
|
import com.alibaba.nacos.plugin.auth.impl.utils.PasswordEncoderUtil;
|
||||||
@ -70,7 +70,7 @@ import java.util.List;
|
|||||||
public class UserController {
|
public class UserController {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private JwtTokenManager jwtTokenManager;
|
private TokenManagerDelegate jwtTokenManager;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
@Deprecated
|
@Deprecated
|
||||||
@ -232,7 +232,7 @@ public class UserController {
|
|||||||
|
|
||||||
ObjectNode result = JacksonUtils.createEmptyJsonNode();
|
ObjectNode result = JacksonUtils.createEmptyJsonNode();
|
||||||
result.put(Constants.ACCESS_TOKEN, user.getToken());
|
result.put(Constants.ACCESS_TOKEN, user.getToken());
|
||||||
result.put(Constants.TOKEN_TTL, jwtTokenManager.getTokenValidityInSeconds());
|
result.put(Constants.TOKEN_TTL, jwtTokenManager.getTokenTtlInSeconds(user.getToken()));
|
||||||
result.put(Constants.GLOBAL_ADMIN, iAuthenticationManager.hasGlobalAdminRole(user));
|
result.put(Constants.GLOBAL_ADMIN, iAuthenticationManager.hasGlobalAdminRole(user));
|
||||||
result.put(Constants.USERNAME, user.getUserName());
|
result.put(Constants.USERNAME, user.getUserName());
|
||||||
return result;
|
return result;
|
||||||
|
@ -19,8 +19,8 @@ package com.alibaba.nacos.plugin.auth.impl.filter;
|
|||||||
import com.alibaba.nacos.api.common.Constants;
|
import com.alibaba.nacos.api.common.Constants;
|
||||||
import com.alibaba.nacos.common.utils.StringUtils;
|
import com.alibaba.nacos.common.utils.StringUtils;
|
||||||
import com.alibaba.nacos.plugin.auth.exception.AccessException;
|
import com.alibaba.nacos.plugin.auth.exception.AccessException;
|
||||||
import com.alibaba.nacos.plugin.auth.impl.JwtTokenManager;
|
|
||||||
import com.alibaba.nacos.plugin.auth.impl.constant.AuthConstants;
|
import com.alibaba.nacos.plugin.auth.impl.constant.AuthConstants;
|
||||||
|
import com.alibaba.nacos.plugin.auth.impl.token.TokenManagerDelegate;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
import org.springframework.web.filter.OncePerRequestFilter;
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
@ -40,9 +40,9 @@ public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
|
|||||||
|
|
||||||
private static final String TOKEN_PREFIX = "Bearer ";
|
private static final String TOKEN_PREFIX = "Bearer ";
|
||||||
|
|
||||||
private final JwtTokenManager tokenManager;
|
private final TokenManagerDelegate tokenManager;
|
||||||
|
|
||||||
public JwtAuthenticationTokenFilter(JwtTokenManager tokenManager) {
|
public JwtAuthenticationTokenFilter(TokenManagerDelegate tokenManager) {
|
||||||
this.tokenManager = tokenManager;
|
this.tokenManager = tokenManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,6 +78,10 @@ public class NacosJwtParser {
|
|||||||
return NacosSignatureAlgorithm.verify(token, key);
|
return NacosSignatureAlgorithm.verify(token, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long getExpireTimeInSeconds(String token) throws AccessException {
|
||||||
|
return NacosSignatureAlgorithm.getExpiredTimeInSeconds(token, key);
|
||||||
|
}
|
||||||
|
|
||||||
public class JwtBuilder {
|
public class JwtBuilder {
|
||||||
|
|
||||||
private final NacosJwtPayload nacosJwtPayload = new NacosJwtPayload();
|
private final NacosJwtPayload nacosJwtPayload = new NacosJwtPayload();
|
||||||
|
@ -135,6 +135,54 @@ public final class NacosSignatureAlgorithm {
|
|||||||
throw new AccessException("token expired!");
|
throw new AccessException("token expired!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get jwt expire time in seconds.
|
||||||
|
*
|
||||||
|
* @param jwt complete jwt string
|
||||||
|
* @param key for signature
|
||||||
|
* @return expire time in seconds
|
||||||
|
* @throws AccessException access exception
|
||||||
|
*/
|
||||||
|
public static long getExpiredTimeInSeconds(String jwt, Key key) throws AccessException {
|
||||||
|
if (StringUtils.isBlank(jwt)) {
|
||||||
|
throw new AccessException("user not found!");
|
||||||
|
}
|
||||||
|
String[] split = jwt.split("\\.");
|
||||||
|
if (split.length != JWT_PARTS) {
|
||||||
|
throw new AccessException("token invalid!");
|
||||||
|
}
|
||||||
|
String header = split[HEADER_POSITION];
|
||||||
|
String payload = split[PAYLOAD_POSITION];
|
||||||
|
String signature = split[SIGNATURE_POSITION];
|
||||||
|
|
||||||
|
NacosSignatureAlgorithm signatureAlgorithm = MAP.get(header);
|
||||||
|
if (signatureAlgorithm == null) {
|
||||||
|
throw new AccessException("unsupported signature algorithm");
|
||||||
|
}
|
||||||
|
return signatureAlgorithm.getExpireTimeInSeconds(header, payload, signature, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get jwt expire time in seconds.
|
||||||
|
*
|
||||||
|
* @param header header of jwt
|
||||||
|
* @param payload payload of jwt
|
||||||
|
* @param signature signature of jwt
|
||||||
|
* @param key for signature
|
||||||
|
* @return expire time in seconds
|
||||||
|
* @throws AccessException access exception
|
||||||
|
*/
|
||||||
|
public long getExpireTimeInSeconds(String header, String payload, String signature, Key key)
|
||||||
|
throws AccessException {
|
||||||
|
Mac macInstance = getMacInstance(key);
|
||||||
|
byte[] bytes = macInstance.doFinal((header + JWT_SEPERATOR + payload).getBytes(StandardCharsets.US_ASCII));
|
||||||
|
if (!URL_BASE64_ENCODER.encodeToString(bytes).equals(signature)) {
|
||||||
|
throw new AccessException("Invalid signature");
|
||||||
|
}
|
||||||
|
NacosJwtPayload nacosJwtPayload = JacksonUtils.toObj(URL_BASE64_DECODER.decode(payload), NacosJwtPayload.class);
|
||||||
|
return nacosJwtPayload.getExp();
|
||||||
|
}
|
||||||
|
|
||||||
private NacosSignatureAlgorithm(String alg, String jcaName, String header) {
|
private NacosSignatureAlgorithm(String alg, String jcaName, String header) {
|
||||||
this.algorithm = alg;
|
this.algorithm = alg;
|
||||||
this.jcaName = jcaName;
|
this.jcaName = jcaName;
|
||||||
|
@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 1999-2021 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.plugin.auth.impl.token;
|
||||||
|
|
||||||
|
import com.alibaba.nacos.plugin.auth.exception.AccessException;
|
||||||
|
import com.alibaba.nacos.plugin.auth.impl.users.NacosUser;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Token Manager Interface.
|
||||||
|
*
|
||||||
|
* @author majorhe
|
||||||
|
*/
|
||||||
|
public interface TokenManager {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create token.
|
||||||
|
*
|
||||||
|
* @param authentication auth info
|
||||||
|
* @return token
|
||||||
|
* @throws AccessException access exception
|
||||||
|
*/
|
||||||
|
String createToken(Authentication authentication) throws AccessException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create token.
|
||||||
|
*
|
||||||
|
* @param userName auth info
|
||||||
|
* @return token
|
||||||
|
* @throws AccessException access exception
|
||||||
|
*/
|
||||||
|
String createToken(String userName) throws AccessException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get auth Info.
|
||||||
|
*
|
||||||
|
* @param token token
|
||||||
|
* @return auth info
|
||||||
|
* @throws AccessException access exception
|
||||||
|
*/
|
||||||
|
Authentication getAuthentication(String token) throws AccessException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* validate token.
|
||||||
|
*
|
||||||
|
* @param token token
|
||||||
|
* @throws AccessException access exception
|
||||||
|
*/
|
||||||
|
void validateToken(String token) throws AccessException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* parse token.
|
||||||
|
*
|
||||||
|
* @param token token
|
||||||
|
* @return nacos user object
|
||||||
|
* @throws AccessException access exception
|
||||||
|
*/
|
||||||
|
NacosUser parseToken(String token) throws AccessException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* validate token.
|
||||||
|
*
|
||||||
|
* @return token validity in seconds
|
||||||
|
* @throws AccessException access exception
|
||||||
|
*/
|
||||||
|
long getTokenValidityInSeconds() throws AccessException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* validate token.
|
||||||
|
*
|
||||||
|
* @param token token
|
||||||
|
* @return token ttl in seconds
|
||||||
|
* @throws AccessException access exception
|
||||||
|
*/
|
||||||
|
long getTokenTtlInSeconds(String token) throws AccessException;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,92 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 1999-2021 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.plugin.auth.impl.token;
|
||||||
|
|
||||||
|
import com.alibaba.nacos.plugin.auth.exception.AccessException;
|
||||||
|
import com.alibaba.nacos.plugin.auth.impl.token.impl.CachedJwtTokenManager;
|
||||||
|
import com.alibaba.nacos.plugin.auth.impl.token.impl.JwtTokenManager;
|
||||||
|
import com.alibaba.nacos.plugin.auth.impl.users.NacosUser;
|
||||||
|
import com.alibaba.nacos.sys.env.EnvUtil;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* token manager delegate.
|
||||||
|
*
|
||||||
|
* @author majorhe
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class TokenManagerDelegate implements TokenManager {
|
||||||
|
|
||||||
|
public static final String NACOS_AUTH_TOKEN_CACHING_ENABLED = "nacos.core.auth.plugin.nacos.token.cache.enable";
|
||||||
|
|
||||||
|
private boolean tokenCacheEnabled = false;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private JwtTokenManager jwtTokenManager;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private CachedJwtTokenManager cachedJwtTokenManager;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void init() {
|
||||||
|
tokenCacheEnabled = EnvUtil.getProperty(NACOS_AUTH_TOKEN_CACHING_ENABLED, Boolean.class, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private TokenManager getExecuteTokenManager() {
|
||||||
|
return tokenCacheEnabled ? cachedJwtTokenManager : jwtTokenManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String createToken(Authentication authentication) throws AccessException {
|
||||||
|
return getExecuteTokenManager().createToken(authentication);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String createToken(String userName) throws AccessException {
|
||||||
|
return getExecuteTokenManager().createToken(userName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Authentication getAuthentication(String token) throws AccessException {
|
||||||
|
return getExecuteTokenManager().getAuthentication(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void validateToken(String token) throws AccessException {
|
||||||
|
getExecuteTokenManager().validateToken(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NacosUser parseToken(String token) throws AccessException {
|
||||||
|
return getExecuteTokenManager().parseToken(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getTokenValidityInSeconds() throws AccessException {
|
||||||
|
return getExecuteTokenManager().getTokenValidityInSeconds();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getTokenTtlInSeconds(String token) throws AccessException {
|
||||||
|
return getExecuteTokenManager().getTokenTtlInSeconds(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,246 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 1999-2021 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.plugin.auth.impl.token.impl;
|
||||||
|
|
||||||
|
import com.alibaba.nacos.plugin.auth.exception.AccessException;
|
||||||
|
import com.alibaba.nacos.plugin.auth.impl.token.TokenManager;
|
||||||
|
import com.alibaba.nacos.plugin.auth.impl.users.NacosUser;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cached JWT token manager.
|
||||||
|
*
|
||||||
|
* @author majorhe
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class CachedJwtTokenManager implements TokenManager {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* key: token string, value: token entity.
|
||||||
|
*/
|
||||||
|
private volatile Map<String, TokenEntity> tokenMap = new ConcurrentHashMap<>(1024);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* key: username, value: token entity. cache token created by self.
|
||||||
|
*/
|
||||||
|
private volatile Map<String, TokenEntity> userMap = new ConcurrentHashMap<>(128);
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private JwtTokenManager jwtTokenManager;
|
||||||
|
|
||||||
|
@Scheduled(initialDelay = 30000, fixedDelay = 60000)
|
||||||
|
private void cleanExpiredToken() {
|
||||||
|
List<String> tokens = new ArrayList<>();
|
||||||
|
tokenMap.forEach((k, v) -> {
|
||||||
|
if (v.getExpiredTimeMills() < System.currentTimeMillis()) {
|
||||||
|
tokens.add(k);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
tokens.forEach(e -> tokenMap.remove(e));
|
||||||
|
List<String> users = new ArrayList<>();
|
||||||
|
userMap.forEach((k, v) -> {
|
||||||
|
if (v.getExpiredTimeMills() < System.currentTimeMillis()) {
|
||||||
|
users.add(k);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
users.forEach(e -> userMap.remove(e));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String createToken(Authentication authentication) throws AccessException {
|
||||||
|
return createToken(authentication.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create token.
|
||||||
|
*
|
||||||
|
* @param username auth info
|
||||||
|
* @return token
|
||||||
|
* @throws AccessException access exception
|
||||||
|
*/
|
||||||
|
public String createToken(String username) throws AccessException {
|
||||||
|
if (userMap.containsKey(username)) {
|
||||||
|
String token = userMap.get(username).getToken();
|
||||||
|
long expiredTime = userMap.get(username).getExpiredTimeMills();
|
||||||
|
if (!needRefresh(expiredTime)) {
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String token = jwtTokenManager.createToken(username);
|
||||||
|
NacosUser user = jwtTokenManager.parseToken(token);
|
||||||
|
long expiredTime = System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(getTokenValidityInSeconds());
|
||||||
|
Authentication authentication = jwtTokenManager.getAuthentication(token);
|
||||||
|
TokenEntity model = new TokenEntity(token, username, expiredTime, authentication, user);
|
||||||
|
tokenMap.put(token, model);
|
||||||
|
userMap.put(username, model);
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get auth Info.
|
||||||
|
*
|
||||||
|
* @param token token
|
||||||
|
* @return auth info
|
||||||
|
* @throws AccessException access exception
|
||||||
|
*/
|
||||||
|
public Authentication getAuthentication(String token) throws AccessException {
|
||||||
|
if (!tokenMap.containsKey(token)) {
|
||||||
|
return jwtTokenManager.getAuthentication(token);
|
||||||
|
}
|
||||||
|
return tokenMap.get(token).getAuthentication();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* validate token.
|
||||||
|
*
|
||||||
|
* @param token token
|
||||||
|
* @throws AccessException access exception
|
||||||
|
*/
|
||||||
|
public void validateToken(String token) throws AccessException {
|
||||||
|
if (!tokenMap.containsKey(token)) {
|
||||||
|
// jwtTokenManager.validateToken(token) will throw runtime exception if token invalid
|
||||||
|
jwtTokenManager.validateToken(token);
|
||||||
|
// if token valid
|
||||||
|
Authentication authentication = jwtTokenManager.getAuthentication(token);
|
||||||
|
String username = authentication.getName();
|
||||||
|
if (username == null || username.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
long expiredTime = TimeUnit.SECONDS.toMillis(jwtTokenManager.getExpiredTimeInSeconds(token));
|
||||||
|
if (expiredTime <= System.currentTimeMillis()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
NacosUser user = jwtTokenManager.parseToken(token);
|
||||||
|
tokenMap.putIfAbsent(token, new TokenEntity(token, username, expiredTime, authentication, user));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NacosUser parseToken(String token) throws AccessException {
|
||||||
|
if (!tokenMap.containsKey(token)) {
|
||||||
|
Authentication authentication = jwtTokenManager.getAuthentication(token);
|
||||||
|
String username = authentication.getName();
|
||||||
|
if (username == null || username.isEmpty()) {
|
||||||
|
throw new AccessException("invalid token, username is empty");
|
||||||
|
}
|
||||||
|
long expiredTime = TimeUnit.SECONDS.toMillis(jwtTokenManager.getExpiredTimeInSeconds(token));
|
||||||
|
if (expiredTime <= System.currentTimeMillis()) {
|
||||||
|
throw new AccessException("expired token");
|
||||||
|
}
|
||||||
|
NacosUser user = jwtTokenManager.parseToken(token);
|
||||||
|
tokenMap.putIfAbsent(token, new TokenEntity(token, username, expiredTime, authentication, user));
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
return tokenMap.get(token).getNacosUser();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getTokenTtlInSeconds(String token) throws AccessException {
|
||||||
|
if (tokenMap.containsKey(token)) {
|
||||||
|
return TimeUnit.MILLISECONDS.toSeconds(
|
||||||
|
tokenMap.get(token).getExpiredTimeMills() - System.currentTimeMillis());
|
||||||
|
}
|
||||||
|
return jwtTokenManager.getTokenTtlInSeconds(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getTokenValidityInSeconds() {
|
||||||
|
return jwtTokenManager.getTokenValidityInSeconds();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean needRefresh(long expiredTimeMills) {
|
||||||
|
long refreshWindowMills = TimeUnit.SECONDS.toMillis(getTokenValidityInSeconds() / 10);
|
||||||
|
return System.currentTimeMillis() + refreshWindowMills > expiredTimeMills;
|
||||||
|
}
|
||||||
|
|
||||||
|
static class TokenEntity {
|
||||||
|
|
||||||
|
private String token;
|
||||||
|
|
||||||
|
private String userName;
|
||||||
|
|
||||||
|
private long expiredTimeMills;
|
||||||
|
|
||||||
|
private Authentication authentication;
|
||||||
|
|
||||||
|
private NacosUser nacosUser;
|
||||||
|
|
||||||
|
public TokenEntity(String token, String userName, long expiredTimeMills, Authentication authentication,
|
||||||
|
NacosUser nacosUser) {
|
||||||
|
this.token = token;
|
||||||
|
this.userName = userName;
|
||||||
|
this.expiredTimeMills = expiredTimeMills;
|
||||||
|
this.authentication = authentication;
|
||||||
|
this.nacosUser = nacosUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getToken() {
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setToken(String token) {
|
||||||
|
this.token = token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUserName() {
|
||||||
|
return userName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUserName(String userName) {
|
||||||
|
this.userName = userName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getExpiredTimeMills() {
|
||||||
|
return expiredTimeMills;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExpiredTimeMills(long expiredTimeMills) {
|
||||||
|
this.expiredTimeMills = expiredTimeMills;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Authentication getAuthentication() {
|
||||||
|
return authentication;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAuthentication(Authentication authentication) {
|
||||||
|
this.authentication = authentication;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NacosUser getNacosUser() {
|
||||||
|
return nacosUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNacosUser(NacosUser nacosUser) {
|
||||||
|
this.nacosUser = nacosUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "TokenEntity{" + "token='" + token + '\'' + ", userName='" + userName + '\'' + ", expiredTimeMills="
|
||||||
|
+ expiredTimeMills + ", authentication=" + authentication + ", nacosUser=" + nacosUser + '}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.alibaba.nacos.plugin.auth.impl;
|
package com.alibaba.nacos.plugin.auth.impl.token.impl;
|
||||||
|
|
||||||
import com.alibaba.nacos.common.event.ServerConfigChangeEvent;
|
import com.alibaba.nacos.common.event.ServerConfigChangeEvent;
|
||||||
import com.alibaba.nacos.common.notify.Event;
|
import com.alibaba.nacos.common.notify.Event;
|
||||||
@ -24,6 +24,7 @@ import com.alibaba.nacos.common.utils.StringUtils;
|
|||||||
import com.alibaba.nacos.plugin.auth.exception.AccessException;
|
import com.alibaba.nacos.plugin.auth.exception.AccessException;
|
||||||
import com.alibaba.nacos.plugin.auth.impl.constant.AuthConstants;
|
import com.alibaba.nacos.plugin.auth.impl.constant.AuthConstants;
|
||||||
import com.alibaba.nacos.plugin.auth.impl.jwt.NacosJwtParser;
|
import com.alibaba.nacos.plugin.auth.impl.jwt.NacosJwtParser;
|
||||||
|
import com.alibaba.nacos.plugin.auth.impl.token.TokenManager;
|
||||||
import com.alibaba.nacos.plugin.auth.impl.users.NacosUser;
|
import com.alibaba.nacos.plugin.auth.impl.users.NacosUser;
|
||||||
import com.alibaba.nacos.sys.env.EnvUtil;
|
import com.alibaba.nacos.sys.env.EnvUtil;
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
@ -34,6 +35,7 @@ import org.springframework.security.core.userdetails.User;
|
|||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JWT token manager.
|
* JWT token manager.
|
||||||
@ -42,7 +44,7 @@ import java.util.List;
|
|||||||
* @author nkorange
|
* @author nkorange
|
||||||
*/
|
*/
|
||||||
@Component
|
@Component
|
||||||
public class JwtTokenManager extends Subscriber<ServerConfigChangeEvent> {
|
public class JwtTokenManager extends Subscriber<ServerConfigChangeEvent> implements TokenManager {
|
||||||
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
private static final String AUTHORITIES_KEY = "auth";
|
private static final String AUTHORITIES_KEY = "auth";
|
||||||
@ -129,6 +131,15 @@ public class JwtTokenManager extends Subscriber<ServerConfigChangeEvent> {
|
|||||||
return tokenValidityInSeconds;
|
return tokenValidityInSeconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getTokenTtlInSeconds(String token) throws AccessException {
|
||||||
|
return jwtParser.getExpireTimeInSeconds(token) - TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis());
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getExpiredTimeInSeconds(String token) throws AccessException {
|
||||||
|
return jwtParser.getExpireTimeInSeconds(token);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEvent(ServerConfigChangeEvent event) {
|
public void onEvent(ServerConfigChangeEvent event) {
|
||||||
processProperties();
|
processProperties();
|
@ -18,10 +18,10 @@ package com.alibaba.nacos.plugin.auth.impl.controller;
|
|||||||
|
|
||||||
import com.alibaba.nacos.auth.config.AuthConfigs;
|
import com.alibaba.nacos.auth.config.AuthConfigs;
|
||||||
import com.alibaba.nacos.plugin.auth.exception.AccessException;
|
import com.alibaba.nacos.plugin.auth.exception.AccessException;
|
||||||
import com.alibaba.nacos.plugin.auth.impl.JwtTokenManager;
|
|
||||||
import com.alibaba.nacos.plugin.auth.impl.authenticate.IAuthenticationManager;
|
import com.alibaba.nacos.plugin.auth.impl.authenticate.IAuthenticationManager;
|
||||||
import com.alibaba.nacos.plugin.auth.impl.constant.AuthConstants;
|
import com.alibaba.nacos.plugin.auth.impl.constant.AuthConstants;
|
||||||
import com.alibaba.nacos.plugin.auth.impl.constant.AuthSystemTypes;
|
import com.alibaba.nacos.plugin.auth.impl.constant.AuthSystemTypes;
|
||||||
|
import com.alibaba.nacos.plugin.auth.impl.token.TokenManagerDelegate;
|
||||||
import com.alibaba.nacos.plugin.auth.impl.users.NacosUser;
|
import com.alibaba.nacos.plugin.auth.impl.users.NacosUser;
|
||||||
import com.alibaba.nacos.sys.env.EnvUtil;
|
import com.alibaba.nacos.sys.env.EnvUtil;
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
@ -39,6 +39,7 @@ import java.nio.charset.StandardCharsets;
|
|||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
|
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
@RunWith(MockitoJUnitRunner.class)
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
@ -56,6 +57,9 @@ public class UserControllerTest {
|
|||||||
@Mock
|
@Mock
|
||||||
private IAuthenticationManager authenticationManager;
|
private IAuthenticationManager authenticationManager;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private TokenManagerDelegate tokenManagerDelegate;
|
||||||
|
|
||||||
private UserController userController;
|
private UserController userController;
|
||||||
|
|
||||||
private NacosUser user;
|
private NacosUser user;
|
||||||
@ -78,8 +82,7 @@ public class UserControllerTest {
|
|||||||
AuthConstants.DEFAULT_TOKEN_EXPIRE_SECONDS.toString());
|
AuthConstants.DEFAULT_TOKEN_EXPIRE_SECONDS.toString());
|
||||||
|
|
||||||
EnvUtil.setEnvironment(mockEnvironment);
|
EnvUtil.setEnvironment(mockEnvironment);
|
||||||
JwtTokenManager jwtTokenManager = new JwtTokenManager();
|
injectObject("jwtTokenManager", tokenManagerDelegate);
|
||||||
injectObject("jwtTokenManager", jwtTokenManager);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -87,6 +90,7 @@ public class UserControllerTest {
|
|||||||
when(authenticationManager.authenticate(request)).thenReturn(user);
|
when(authenticationManager.authenticate(request)).thenReturn(user);
|
||||||
when(authenticationManager.hasGlobalAdminRole(user)).thenReturn(true);
|
when(authenticationManager.hasGlobalAdminRole(user)).thenReturn(true);
|
||||||
when(authConfigs.getNacosAuthSystemType()).thenReturn(AuthSystemTypes.NACOS.name());
|
when(authConfigs.getNacosAuthSystemType()).thenReturn(AuthSystemTypes.NACOS.name());
|
||||||
|
when(tokenManagerDelegate.getTokenTtlInSeconds(anyString())).thenReturn(18000L);
|
||||||
Object actual = userController.login("nacos", "nacos", response, request);
|
Object actual = userController.login("nacos", "nacos", response, request);
|
||||||
assertTrue(actual instanceof JsonNode);
|
assertTrue(actual instanceof JsonNode);
|
||||||
String actualString = actual.toString();
|
String actualString = actual.toString();
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package com.alibaba.nacos.plugin.auth.impl.jwt;
|
package com.alibaba.nacos.plugin.auth.impl.jwt;
|
||||||
|
|
||||||
|
import com.alibaba.nacos.plugin.auth.exception.AccessException;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.junit.MockitoJUnitRunner;
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
@ -80,6 +81,15 @@ public class NacosJwtParserTest {
|
|||||||
assertTrue(token.startsWith(NacosSignatureAlgorithm.HS512.getHeader()));
|
assertTrue(token.startsWith(NacosSignatureAlgorithm.HS512.getHeader()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetExpireTimeInSeconds() throws AccessException {
|
||||||
|
NacosJwtParser parser = new NacosJwtParser(
|
||||||
|
encode("SecretKey012345678901234567SecretKey0123456789012345678901289012"));
|
||||||
|
String token = parser.jwtBuilder().setUserName("nacos").setExpiredTime(100L).compact();
|
||||||
|
long expiredTimeSeconds = parser.getExpireTimeInSeconds(token);
|
||||||
|
assertTrue(expiredTimeSeconds * 1000 - System.currentTimeMillis() > 0);
|
||||||
|
}
|
||||||
|
|
||||||
private String encode(String key) {
|
private String encode(String key) {
|
||||||
return Base64.getEncoder().encodeToString(key.getBytes(StandardCharsets.UTF_8));
|
return Base64.getEncoder().encodeToString(key.getBytes(StandardCharsets.UTF_8));
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,112 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 1999-2021 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.plugin.auth.impl.token;
|
||||||
|
|
||||||
|
import com.alibaba.nacos.plugin.auth.exception.AccessException;
|
||||||
|
import com.alibaba.nacos.plugin.auth.impl.token.impl.CachedJwtTokenManager;
|
||||||
|
import com.alibaba.nacos.plugin.auth.impl.token.impl.JwtTokenManager;
|
||||||
|
import com.alibaba.nacos.plugin.auth.impl.users.NacosUser;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TokenManagerDelegateTest.
|
||||||
|
*
|
||||||
|
* @author majorhe
|
||||||
|
*/
|
||||||
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
public class TokenManagerDelegateTest {
|
||||||
|
|
||||||
|
private TokenManagerDelegate tokenManagerDelegate;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private CachedJwtTokenManager cachedJwtTokenManager;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private JwtTokenManager jwtTokenManager;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private Authentication authentication;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private NacosUser user;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
tokenManagerDelegate = new TokenManagerDelegate();
|
||||||
|
injectObject("jwtTokenManager", jwtTokenManager);
|
||||||
|
injectObject("cachedJwtTokenManager", cachedJwtTokenManager);
|
||||||
|
injectObject("tokenCacheEnabled", Boolean.TRUE);
|
||||||
|
when(cachedJwtTokenManager.getTokenValidityInSeconds()).thenReturn(100L);
|
||||||
|
when(cachedJwtTokenManager.getTokenTtlInSeconds(anyString())).thenReturn(100L);
|
||||||
|
when(cachedJwtTokenManager.getAuthentication(anyString())).thenReturn(authentication);
|
||||||
|
when(cachedJwtTokenManager.parseToken(anyString())).thenReturn(user);
|
||||||
|
when(cachedJwtTokenManager.createToken(anyString())).thenReturn("token");
|
||||||
|
when(cachedJwtTokenManager.createToken(authentication)).thenReturn("token");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateToken1() throws AccessException {
|
||||||
|
Assert.assertEquals("token", tokenManagerDelegate.createToken(authentication));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateToken2() throws AccessException {
|
||||||
|
Assert.assertEquals("token", tokenManagerDelegate.createToken("nacos"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAuthentication() throws AccessException {
|
||||||
|
Assert.assertNotNull(tokenManagerDelegate.getAuthentication("token"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateToken() throws AccessException {
|
||||||
|
tokenManagerDelegate.validateToken("token");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseToken() throws AccessException {
|
||||||
|
Assert.assertNotNull(tokenManagerDelegate.parseToken("token"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetTokenTtlInSeconds() throws AccessException {
|
||||||
|
Assert.assertTrue(tokenManagerDelegate.getTokenTtlInSeconds("token") > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetTokenValidityInSeconds() throws AccessException {
|
||||||
|
Assert.assertTrue(tokenManagerDelegate.getTokenValidityInSeconds() > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void injectObject(String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException {
|
||||||
|
Field field = TokenManagerDelegate.class.getDeclaredField(fieldName);
|
||||||
|
field.setAccessible(true);
|
||||||
|
field.set(tokenManagerDelegate, value);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,106 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 1999-2021 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.plugin.auth.impl.token.impl;
|
||||||
|
|
||||||
|
import com.alibaba.nacos.plugin.auth.exception.AccessException;
|
||||||
|
import com.alibaba.nacos.plugin.auth.impl.users.NacosUser;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CachedJwtTokenManagerTest.
|
||||||
|
*
|
||||||
|
* @author Majorhe
|
||||||
|
*/
|
||||||
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
public class CachedJwtTokenManagerTest {
|
||||||
|
|
||||||
|
private CachedJwtTokenManager cachedJwtTokenManager;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private JwtTokenManager jwtTokenManager;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private Authentication authentication;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private NacosUser user;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
cachedJwtTokenManager = new CachedJwtTokenManager();
|
||||||
|
injectObject("jwtTokenManager", jwtTokenManager);
|
||||||
|
when(jwtTokenManager.getTokenValidityInSeconds()).thenReturn(100L);
|
||||||
|
when(jwtTokenManager.getTokenTtlInSeconds(anyString())).thenReturn(100L);
|
||||||
|
when(jwtTokenManager.getExpiredTimeInSeconds(anyString())).thenReturn(System.currentTimeMillis());
|
||||||
|
when(jwtTokenManager.getAuthentication(anyString())).thenReturn(authentication);
|
||||||
|
when(jwtTokenManager.parseToken(anyString())).thenReturn(user);
|
||||||
|
when(jwtTokenManager.createToken(anyString())).thenReturn("token");
|
||||||
|
when(authentication.getName()).thenReturn("nacos");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateToken1() throws AccessException {
|
||||||
|
Assert.assertEquals("token", cachedJwtTokenManager.createToken(authentication));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateToken2() throws AccessException {
|
||||||
|
Assert.assertEquals("token", cachedJwtTokenManager.createToken("nacos"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAuthentication() throws AccessException {
|
||||||
|
Assert.assertNotNull(cachedJwtTokenManager.getAuthentication("token"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateToken() throws AccessException {
|
||||||
|
cachedJwtTokenManager.validateToken("token");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseToken() throws AccessException {
|
||||||
|
Assert.assertNotNull(cachedJwtTokenManager.parseToken("token"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetTokenTtlInSeconds() throws AccessException {
|
||||||
|
Assert.assertTrue(cachedJwtTokenManager.getTokenTtlInSeconds("token") > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetTokenValidityInSeconds() {
|
||||||
|
Assert.assertTrue(cachedJwtTokenManager.getTokenValidityInSeconds() > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void injectObject(String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException {
|
||||||
|
Field field = CachedJwtTokenManager.class.getDeclaredField(fieldName);
|
||||||
|
field.setAccessible(true);
|
||||||
|
field.set(cachedJwtTokenManager, value);
|
||||||
|
}
|
||||||
|
}
|
@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.alibaba.nacos.plugin.auth.impl;
|
package com.alibaba.nacos.plugin.auth.impl.token.impl;
|
||||||
|
|
||||||
import com.alibaba.nacos.plugin.auth.exception.AccessException;
|
import com.alibaba.nacos.plugin.auth.exception.AccessException;
|
||||||
import com.alibaba.nacos.plugin.auth.impl.constant.AuthConstants;
|
import com.alibaba.nacos.plugin.auth.impl.constant.AuthConstants;
|
||||||
@ -88,6 +88,16 @@ public class JwtTokenManagerTest {
|
|||||||
Assert.assertThrows(IllegalArgumentException.class, () -> createToken("0123456789ABCDEF0123456789ABCDE"));
|
Assert.assertThrows(IllegalArgumentException.class, () -> createToken("0123456789ABCDEF0123456789ABCDE"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetTokenTtlInSeconds() throws AccessException {
|
||||||
|
Assert.assertTrue(jwtTokenManager.getTokenTtlInSeconds(jwtTokenManager.createToken("nacos")) > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetExpiredTimeInSeconds() throws AccessException {
|
||||||
|
Assert.assertTrue(jwtTokenManager.getExpiredTimeInSeconds(jwtTokenManager.createToken("nacos")) > 0);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNacosJwtParser() throws AccessException {
|
public void testNacosJwtParser() throws AccessException {
|
||||||
String secretKey = "SecretKey0123$567890$234567890123456789012345678901234567890123456789";
|
String secretKey = "SecretKey0123$567890$234567890123456789012345678901234567890123456789";
|
Loading…
Reference in New Issue
Block a user