* 使用自定义jwt生成 * add unit test; fix log msg. * add license
This commit is contained in:
parent
986c024ccc
commit
ade3f8295f
@ -29,7 +29,7 @@
|
||||
<packaging>jar</packaging>
|
||||
<name>nacos-plugin-default-impl ${project.version}</name>
|
||||
<url>https://nacos.io</url>
|
||||
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.nacos</groupId>
|
||||
@ -45,27 +45,13 @@
|
||||
<artifactId>nacos-sys</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba.nacos</groupId>
|
||||
<artifactId>nacos-config</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-impl</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-jackson</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.ldap</groupId>
|
||||
<artifactId>spring-ldap-core</artifactId>
|
||||
|
@ -20,14 +20,12 @@ import com.alibaba.nacos.common.event.ServerConfigChangeEvent;
|
||||
import com.alibaba.nacos.common.notify.Event;
|
||||
import com.alibaba.nacos.common.notify.NotifyCenter;
|
||||
import com.alibaba.nacos.common.notify.listener.Subscriber;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import com.alibaba.nacos.plugin.auth.exception.AccessException;
|
||||
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.users.NacosUser;
|
||||
import com.alibaba.nacos.sys.env.EnvUtil;
|
||||
import io.jsonwebtoken.Claims;
|
||||
import io.jsonwebtoken.JwtParser;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.jsonwebtoken.SignatureAlgorithm;
|
||||
import io.jsonwebtoken.io.Decoders;
|
||||
import io.jsonwebtoken.security.Keys;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
@ -35,10 +33,7 @@ import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* JWT token manager.
|
||||
@ -49,6 +44,7 @@ import java.util.concurrent.TimeUnit;
|
||||
@Component
|
||||
public class JwtTokenManager extends Subscriber<ServerConfigChangeEvent> {
|
||||
|
||||
@Deprecated
|
||||
private static final String AUTHORITIES_KEY = "auth";
|
||||
|
||||
/**
|
||||
@ -56,9 +52,7 @@ public class JwtTokenManager extends Subscriber<ServerConfigChangeEvent> {
|
||||
*/
|
||||
private volatile long tokenValidityInSeconds;
|
||||
|
||||
private volatile JwtParser jwtParser;
|
||||
|
||||
private volatile SecretKey secretKey;
|
||||
private volatile NacosJwtParser jwtParser;
|
||||
|
||||
public JwtTokenManager() {
|
||||
NotifyCenter.registerSubscriber(this);
|
||||
@ -72,14 +66,13 @@ public class JwtTokenManager extends Subscriber<ServerConfigChangeEvent> {
|
||||
String encodedSecretKey = EnvUtil.getProperty(AuthConstants.TOKEN_SECRET_KEY,
|
||||
AuthConstants.DEFAULT_TOKEN_SECRET_KEY);
|
||||
try {
|
||||
this.secretKey = Keys.hmacShaKeyFor(Decoders.BASE64.decode(encodedSecretKey));
|
||||
this.jwtParser = new NacosJwtParser(encodedSecretKey);
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException(
|
||||
"the length of must great than or equal 32 bytes; And the secret key must be encoded by base64",
|
||||
"the length of secret key must great than or equal 32 bytes; And the secret key must be encoded by base64",
|
||||
e);
|
||||
}
|
||||
|
||||
this.jwtParser = Jwts.parserBuilder().setSigningKey(secretKey).build();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -99,13 +92,7 @@ public class JwtTokenManager extends Subscriber<ServerConfigChangeEvent> {
|
||||
* @return token
|
||||
*/
|
||||
public String createToken(String userName) {
|
||||
|
||||
Date validity = new Date(
|
||||
System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(this.getTokenValidityInSeconds()));
|
||||
|
||||
Claims claims = Jwts.claims().setSubject(userName);
|
||||
return Jwts.builder().setClaims(claims).setExpiration(validity).signWith(secretKey, SignatureAlgorithm.HS256)
|
||||
.compact();
|
||||
return jwtParser.jwtBuilder().setUserName(userName).setExpiredTime(this.tokenValidityInSeconds).compact();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -114,13 +101,12 @@ public class JwtTokenManager extends Subscriber<ServerConfigChangeEvent> {
|
||||
* @param token token
|
||||
* @return auth info
|
||||
*/
|
||||
public Authentication getAuthentication(String token) {
|
||||
Claims claims = jwtParser.parseClaimsJws(token).getBody();
|
||||
public Authentication getAuthentication(String token) throws AccessException {
|
||||
NacosUser nacosUser = jwtParser.parse(token);
|
||||
|
||||
List<GrantedAuthority> authorities = AuthorityUtils.commaSeparatedStringToAuthorityList(
|
||||
(String) claims.get(AUTHORITIES_KEY));
|
||||
List<GrantedAuthority> authorities = AuthorityUtils.commaSeparatedStringToAuthorityList(StringUtils.EMPTY);
|
||||
|
||||
User principal = new User(claims.getSubject(), "", authorities);
|
||||
User principal = new User(nacosUser.getUserName(), "", authorities);
|
||||
return new UsernamePasswordAuthenticationToken(principal, "", authorities);
|
||||
}
|
||||
|
||||
@ -129,8 +115,8 @@ public class JwtTokenManager extends Subscriber<ServerConfigChangeEvent> {
|
||||
*
|
||||
* @param token token
|
||||
*/
|
||||
public void validateToken(String token) {
|
||||
jwtParser.parseClaimsJws(token);
|
||||
public void validateToken(String token) throws AccessException {
|
||||
jwtParser.parse(token);
|
||||
}
|
||||
|
||||
public long getTokenValidityInSeconds() {
|
||||
|
@ -26,7 +26,6 @@ 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.roles.NacosRoleServiceImpl;
|
||||
import com.alibaba.nacos.plugin.auth.impl.users.NacosUser;
|
||||
import io.jsonwebtoken.ExpiredJwtException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
@ -150,16 +149,11 @@ public class NacosAuthManager {
|
||||
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!");
|
||||
}
|
||||
tokenManager.validateToken(token);
|
||||
|
||||
}
|
||||
|
||||
private NacosUser getNacosUser(String token) {
|
||||
private NacosUser getNacosUser(String token) throws AccessException {
|
||||
Authentication authentication = tokenManager.getAuthentication(token);
|
||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||
|
||||
|
@ -18,6 +18,7 @@ package com.alibaba.nacos.plugin.auth.impl.filter;
|
||||
|
||||
import com.alibaba.nacos.api.common.Constants;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
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 org.springframework.security.core.Authentication;
|
||||
@ -52,9 +53,12 @@ public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
|
||||
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);
|
||||
try {
|
||||
Authentication authentication = this.tokenManager.getAuthentication(jwt);
|
||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||
} catch (AccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
|
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright 1999-2022 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.jwt;
|
||||
|
||||
import com.alibaba.nacos.plugin.auth.exception.AccessException;
|
||||
import com.alibaba.nacos.plugin.auth.impl.users.NacosUser;
|
||||
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.Key;
|
||||
import java.util.Base64;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* JwtParse.
|
||||
*
|
||||
* @author Weizhan▪Yun
|
||||
* @date 2023/1/15 21:38
|
||||
*/
|
||||
@SuppressWarnings("PMD.UndefineMagicConstantRule")
|
||||
public class NacosJwtParser {
|
||||
|
||||
private final NacosSignatureAlgorithm signatureAlgorithm;
|
||||
|
||||
private final Key key;
|
||||
|
||||
public NacosJwtParser(String base64edKey) {
|
||||
byte[] decode;
|
||||
try {
|
||||
decode = Base64.getDecoder().decode(base64edKey);
|
||||
} catch (IllegalArgumentException e) {
|
||||
decode = base64edKey.getBytes(StandardCharsets.US_ASCII);
|
||||
}
|
||||
|
||||
int bitLength = decode.length << 3;
|
||||
if (bitLength < 256) {
|
||||
String msg = "The specified key byte array is " + bitLength + " bits which "
|
||||
+ "is not secure enough for any JWT HMAC-SHA algorithm. The JWT "
|
||||
+ "JWA Specification (RFC 7518, Section 3.2) states that keys used with HMAC-SHA algorithms MUST have a "
|
||||
+ "size >= 256 bits (the key size must be greater than or equal to the hash "
|
||||
+ "output size). See https://tools.ietf.org/html/rfc7518#section-3.2 for more information.";
|
||||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
|
||||
if (bitLength < 384) {
|
||||
this.signatureAlgorithm = NacosSignatureAlgorithm.HS256;
|
||||
} else if (bitLength < 512) {
|
||||
this.signatureAlgorithm = NacosSignatureAlgorithm.HS384;
|
||||
} else {
|
||||
this.signatureAlgorithm = NacosSignatureAlgorithm.HS512;
|
||||
}
|
||||
this.key = new SecretKeySpec(decode, signatureAlgorithm.getJcaName());
|
||||
}
|
||||
|
||||
private String sign(NacosJwtPayload payload) {
|
||||
return signatureAlgorithm.sign(payload, key);
|
||||
}
|
||||
|
||||
public JwtBuilder jwtBuilder() {
|
||||
return new JwtBuilder();
|
||||
}
|
||||
|
||||
public NacosUser parse(String token) throws AccessException {
|
||||
return NacosSignatureAlgorithm.verify(token, key);
|
||||
}
|
||||
|
||||
public class JwtBuilder {
|
||||
|
||||
private final NacosJwtPayload nacosJwtPayload = new NacosJwtPayload();
|
||||
|
||||
public JwtBuilder setUserName(String userName) {
|
||||
this.nacosJwtPayload.setSub(userName);
|
||||
return this;
|
||||
}
|
||||
|
||||
public JwtBuilder setExpiredTime(long validSeconds) {
|
||||
this.nacosJwtPayload.setExp(TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()) + validSeconds);
|
||||
return this;
|
||||
}
|
||||
|
||||
public String compact() {
|
||||
return sign(nacosJwtPayload);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 1999-2022 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.jwt;
|
||||
|
||||
import com.alibaba.nacos.common.utils.JacksonUtils;
|
||||
|
||||
/**
|
||||
* NacosJwtPayload.
|
||||
*
|
||||
* @author Weizhan▪Yun
|
||||
* @date 2023/1/15 21:27
|
||||
*/
|
||||
public class NacosJwtPayload {
|
||||
|
||||
private String sub;
|
||||
|
||||
private long exp = System.currentTimeMillis() / 1000L;
|
||||
|
||||
public String getSub() {
|
||||
return sub;
|
||||
}
|
||||
|
||||
public void setSub(String sub) {
|
||||
this.sub = sub;
|
||||
}
|
||||
|
||||
public long getExp() {
|
||||
return exp;
|
||||
}
|
||||
|
||||
public void setExp(long exp) {
|
||||
this.exp = exp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JacksonUtils.toJson(this);
|
||||
}
|
||||
}
|
@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Copyright 1999-2022 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.jwt;
|
||||
|
||||
import com.alibaba.nacos.common.utils.JacksonUtils;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import com.alibaba.nacos.plugin.auth.exception.AccessException;
|
||||
import com.alibaba.nacos.plugin.auth.impl.users.NacosUser;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.Key;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Base64;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* SignAlgorithm.
|
||||
*
|
||||
* @author Weizhan▪Yun
|
||||
* @date 2023/1/15 16:42
|
||||
*/
|
||||
public final class NacosSignatureAlgorithm {
|
||||
|
||||
private static final String JWT_SEPERATOR = ".";
|
||||
|
||||
private static final int HEADER_POSITION = 0;
|
||||
|
||||
private static final int PAYLOAD_POSITION = 1;
|
||||
|
||||
private static final int SIGNATURE_POSITION = 2;
|
||||
|
||||
private static final int JWT_PARTS = 3;
|
||||
|
||||
private static final String HS256_JWT_HEADER = "eyJhbGciOiJIUzI1NiJ9";
|
||||
|
||||
private static final String HS384_JWT_HEADER = "eyJhbGciOiJIUzM4NCJ9";
|
||||
|
||||
private static final String HS512_JWT_HEADER = "eyJhbGciOiJIUzUxMiJ9";
|
||||
|
||||
private static final Base64.Encoder URL_BASE64_ENCODER = Base64.getUrlEncoder().withoutPadding();
|
||||
|
||||
private static final Base64.Decoder URL_BASE64_DECODER = Base64.getUrlDecoder();
|
||||
|
||||
private static final Map<String, NacosSignatureAlgorithm> MAP = new HashMap<>(4);
|
||||
|
||||
public static final NacosSignatureAlgorithm HS256 = new NacosSignatureAlgorithm("HS256", "HmacSHA256",
|
||||
HS256_JWT_HEADER);
|
||||
|
||||
public static final NacosSignatureAlgorithm HS384 = new NacosSignatureAlgorithm("HS384", "HmacSHA384",
|
||||
HS384_JWT_HEADER);
|
||||
|
||||
public static final NacosSignatureAlgorithm HS512 = new NacosSignatureAlgorithm("HS512", "HmacSHA512",
|
||||
HS512_JWT_HEADER);
|
||||
|
||||
private final String algorithm;
|
||||
|
||||
private final String jcaName;
|
||||
|
||||
private final String header;
|
||||
|
||||
static {
|
||||
MAP.put(HS256_JWT_HEADER, HS256);
|
||||
MAP.put(HS384_JWT_HEADER, HS384);
|
||||
MAP.put(HS512_JWT_HEADER, HS512);
|
||||
}
|
||||
|
||||
/**
|
||||
* verify jwt.
|
||||
*
|
||||
* @param jwt complete jwt string
|
||||
* @param key for signature
|
||||
* @return object for payload
|
||||
* @throws AccessException access exception
|
||||
*/
|
||||
public static NacosUser verify(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");
|
||||
}
|
||||
NacosUser user = signatureAlgorithm.verify(header, payload, signature, key);
|
||||
user.setToken(jwt);
|
||||
return user;
|
||||
}
|
||||
|
||||
/**
|
||||
* verify jwt.
|
||||
*
|
||||
* @param header header of jwt
|
||||
* @param payload payload of jwt
|
||||
* @param signature signature of jwt
|
||||
* @param key for signature
|
||||
* @return object for payload
|
||||
* @throws AccessException access exception
|
||||
*/
|
||||
public NacosUser verify(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);
|
||||
if (nacosJwtPayload.getExp() >= TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis())) {
|
||||
return new NacosUser(nacosJwtPayload.getSub());
|
||||
}
|
||||
|
||||
throw new AccessException("token expired!");
|
||||
}
|
||||
|
||||
private NacosSignatureAlgorithm(String alg, String jcaName, String header) {
|
||||
this.algorithm = alg;
|
||||
this.jcaName = jcaName;
|
||||
this.header = header;
|
||||
}
|
||||
|
||||
String sign(NacosJwtPayload nacosJwtPayload, Key key) {
|
||||
String jwtWithoutSign = header + JWT_SEPERATOR + URL_BASE64_ENCODER.encodeToString(
|
||||
nacosJwtPayload.toString().getBytes(StandardCharsets.UTF_8));
|
||||
Mac macInstance = getMacInstance(key);
|
||||
byte[] bytes = jwtWithoutSign.getBytes(StandardCharsets.US_ASCII);
|
||||
String signature = URL_BASE64_ENCODER.encodeToString(macInstance.doFinal(bytes));
|
||||
return jwtWithoutSign + JWT_SEPERATOR + signature;
|
||||
}
|
||||
|
||||
private Mac getMacInstance(Key key) {
|
||||
try {
|
||||
Mac instance = Mac.getInstance(jcaName);
|
||||
instance.init(key);
|
||||
return instance;
|
||||
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
|
||||
throw new IllegalArgumentException("Invalid key: " + key);
|
||||
}
|
||||
}
|
||||
|
||||
public String getAlgorithm() {
|
||||
return algorithm;
|
||||
}
|
||||
|
||||
public String getJcaName() {
|
||||
return jcaName;
|
||||
}
|
||||
|
||||
public String getHeader() {
|
||||
return header;
|
||||
}
|
||||
}
|
@ -17,6 +17,7 @@
|
||||
package com.alibaba.nacos.plugin.auth.impl.roles;
|
||||
|
||||
import com.alibaba.nacos.auth.config.AuthConfigs;
|
||||
import com.alibaba.nacos.common.utils.CollectionUtils;
|
||||
import com.alibaba.nacos.common.utils.ConcurrentHashSet;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import com.alibaba.nacos.config.server.model.Page;
|
||||
@ -32,7 +33,6 @@ import com.alibaba.nacos.plugin.auth.impl.persistence.RoleInfo;
|
||||
import com.alibaba.nacos.plugin.auth.impl.persistence.RolePersistService;
|
||||
import com.alibaba.nacos.plugin.auth.impl.users.NacosUser;
|
||||
import com.alibaba.nacos.plugin.auth.impl.users.NacosUserDetailsServiceImpl;
|
||||
import io.jsonwebtoken.lang.Collections;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Service;
|
||||
@ -124,7 +124,7 @@ public class NacosRoleServiceImpl {
|
||||
}
|
||||
|
||||
List<RoleInfo> roleInfoList = getRoles(nacosUser.getUserName());
|
||||
if (Collections.isEmpty(roleInfoList)) {
|
||||
if (CollectionUtils.isEmpty(roleInfoList)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -144,7 +144,7 @@ public class NacosRoleServiceImpl {
|
||||
// For other roles, use a pattern match to decide if pass or not.
|
||||
for (RoleInfo roleInfo : roleInfoList) {
|
||||
List<PermissionInfo> permissionInfoList = getPermissions(roleInfo.getRole());
|
||||
if (Collections.isEmpty(permissionInfoList)) {
|
||||
if (CollectionUtils.isEmpty(permissionInfoList)) {
|
||||
continue;
|
||||
}
|
||||
for (PermissionInfo permissionInfo : permissionInfoList) {
|
||||
@ -165,7 +165,7 @@ public class NacosRoleServiceImpl {
|
||||
Page<RoleInfo> roleInfoPage = getRolesFromDatabase(username, StringUtils.EMPTY, DEFAULT_PAGE_NO, Integer.MAX_VALUE);
|
||||
if (roleInfoPage != null) {
|
||||
roleInfoList = roleInfoPage.getPageItems();
|
||||
if (!Collections.isEmpty(roleInfoList)) {
|
||||
if (!CollectionUtils.isEmpty(roleInfoList)) {
|
||||
roleInfoMap.put(username, roleInfoList);
|
||||
}
|
||||
}
|
||||
@ -188,7 +188,7 @@ public class NacosRoleServiceImpl {
|
||||
Integer.MAX_VALUE);
|
||||
if (permissionInfoPage != null) {
|
||||
permissionInfoList = permissionInfoPage.getPageItems();
|
||||
if (!Collections.isEmpty(permissionInfoList)) {
|
||||
if (!CollectionUtils.isEmpty(permissionInfoList)) {
|
||||
permissionInfoMap.put(role, permissionInfoList);
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,13 @@ public class NacosUser extends User {
|
||||
|
||||
private boolean globalAdmin = false;
|
||||
|
||||
public NacosUser() {
|
||||
}
|
||||
|
||||
public NacosUser(String userName) {
|
||||
setUserName(userName);
|
||||
}
|
||||
|
||||
public String getToken() {
|
||||
return token;
|
||||
}
|
||||
|
@ -16,9 +16,10 @@
|
||||
|
||||
package com.alibaba.nacos.plugin.auth.impl;
|
||||
|
||||
import com.alibaba.nacos.plugin.auth.exception.AccessException;
|
||||
import com.alibaba.nacos.plugin.auth.impl.constant.AuthConstants;
|
||||
import com.alibaba.nacos.plugin.auth.impl.jwt.NacosJwtParser;
|
||||
import com.alibaba.nacos.sys.env.EnvUtil;
|
||||
import io.jsonwebtoken.io.Encoders;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@ -28,6 +29,8 @@ import org.springframework.mock.env.MockEnvironment;
|
||||
import org.springframework.security.core.Authentication;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Base64;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class JwtTokenManagerTest {
|
||||
@ -37,7 +40,7 @@ public class JwtTokenManagerTest {
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockEnvironment mockEnvironment = new MockEnvironment();
|
||||
mockEnvironment.setProperty(AuthConstants.TOKEN_SECRET_KEY, Encoders.BASE64.encode(
|
||||
mockEnvironment.setProperty(AuthConstants.TOKEN_SECRET_KEY, Base64.getEncoder().encodeToString(
|
||||
"SecretKey0123$567890$234567890123456789012345678901234567890123456789".getBytes(
|
||||
StandardCharsets.UTF_8)));
|
||||
mockEnvironment.setProperty(AuthConstants.TOKEN_EXPIRE_SECONDS,
|
||||
@ -49,19 +52,19 @@ public class JwtTokenManagerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateTokenAndSecretKeyWithoutSpecialSymbol() {
|
||||
public void testCreateTokenAndSecretKeyWithoutSpecialSymbol() throws AccessException {
|
||||
createToken("SecretKey0123567890234567890123456789012345678901234567890123456789");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateTokenAndSecretKeyWithSpecialSymbol() {
|
||||
public void testCreateTokenAndSecretKeyWithSpecialSymbol() throws AccessException {
|
||||
createToken("SecretKey01234@#!5678901234567890123456789012345678901234567890123456789");
|
||||
}
|
||||
|
||||
private void createToken(String secretKey) {
|
||||
private void createToken(String secretKey) throws AccessException {
|
||||
MockEnvironment mockEnvironment = new MockEnvironment();
|
||||
mockEnvironment.setProperty(AuthConstants.TOKEN_SECRET_KEY,
|
||||
Encoders.BASE64.encode(secretKey.getBytes(StandardCharsets.UTF_8)));
|
||||
Base64.getEncoder().encodeToString(secretKey.getBytes(StandardCharsets.UTF_8)));
|
||||
mockEnvironment.setProperty(AuthConstants.TOKEN_EXPIRE_SECONDS,
|
||||
AuthConstants.DEFAULT_TOKEN_EXPIRE_SECONDS.toString());
|
||||
|
||||
@ -74,7 +77,7 @@ public class JwtTokenManagerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAuthentication() {
|
||||
public void getAuthentication() throws AccessException {
|
||||
String nacosToken = jwtTokenManager.createToken("nacos");
|
||||
Authentication authentication = jwtTokenManager.getAuthentication(nacosToken);
|
||||
Assert.assertNotNull(authentication);
|
||||
@ -84,4 +87,34 @@ public class JwtTokenManagerTest {
|
||||
public void testInvalidSecretKey() {
|
||||
Assert.assertThrows(IllegalArgumentException.class, () -> createToken("0123456789ABCDEF0123456789ABCDE"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNacosJwtParser() throws AccessException {
|
||||
String secretKey = "SecretKey0123$567890$234567890123456789012345678901234567890123456789";
|
||||
MockEnvironment mockEnvironment = new MockEnvironment();
|
||||
mockEnvironment.setProperty(AuthConstants.TOKEN_SECRET_KEY,
|
||||
Base64.getEncoder().encodeToString(secretKey.getBytes(StandardCharsets.UTF_8)));
|
||||
mockEnvironment.setProperty(AuthConstants.TOKEN_EXPIRE_SECONDS,
|
||||
AuthConstants.DEFAULT_TOKEN_EXPIRE_SECONDS.toString());
|
||||
|
||||
EnvUtil.setEnvironment(mockEnvironment);
|
||||
|
||||
JwtTokenManager jwtTokenManager = new JwtTokenManager();
|
||||
String nacosToken = jwtTokenManager.createToken("nacos");
|
||||
Assert.assertNotNull(nacosToken);
|
||||
System.out.println("oldToken: " + nacosToken);
|
||||
|
||||
jwtTokenManager.validateToken(nacosToken);
|
||||
NacosJwtParser nacosJwtParser = new NacosJwtParser(
|
||||
Base64.getEncoder().encodeToString(secretKey.getBytes(StandardCharsets.UTF_8)));
|
||||
|
||||
//check old token
|
||||
nacosJwtParser.parse(nacosToken);
|
||||
|
||||
//create new token
|
||||
String newToken = nacosJwtParser.jwtBuilder().setUserName("nacos").setExpiredTime(TimeUnit.DAYS.toSeconds(10L))
|
||||
.compact();
|
||||
System.out.println("newToken: " + newToken);
|
||||
jwtTokenManager.validateToken(newToken);
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,6 @@ import com.alibaba.nacos.plugin.auth.impl.constant.AuthSystemTypes;
|
||||
import com.alibaba.nacos.plugin.auth.impl.users.NacosUser;
|
||||
import com.alibaba.nacos.sys.env.EnvUtil;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import io.jsonwebtoken.io.Encoders;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@ -37,6 +36,7 @@ import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.lang.reflect.Field;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Base64;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.when;
|
||||
@ -71,7 +71,7 @@ public class UserControllerTest {
|
||||
injectObject("authManager", authManager);
|
||||
|
||||
MockEnvironment mockEnvironment = new MockEnvironment();
|
||||
mockEnvironment.setProperty(AuthConstants.TOKEN_SECRET_KEY, Encoders.BASE64.encode(
|
||||
mockEnvironment.setProperty(AuthConstants.TOKEN_SECRET_KEY, Base64.getEncoder().encodeToString(
|
||||
"SecretKey0123$567890$234567890123456789012345678901234567890123456789".getBytes(
|
||||
StandardCharsets.UTF_8)));
|
||||
mockEnvironment.setProperty(AuthConstants.TOKEN_EXPIRE_SECONDS,
|
||||
|
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 1999-2022 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.jwt;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Base64;
|
||||
|
||||
/**
|
||||
* NacosJwtParserTest.
|
||||
*
|
||||
* @author Weizhan▪Yun
|
||||
* @date 2023/2/1 16:32
|
||||
*/
|
||||
public class NacosJwtParserTest extends TestCase {
|
||||
|
||||
@Test
|
||||
public void testParseWithOriginKey() {
|
||||
new NacosJwtParser("SecretKey012345678901234567890123456789012345678901234567890123456789");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseWith16Key() {
|
||||
Exception e = null;
|
||||
try {
|
||||
new NacosJwtParser("SecretKey0123456");
|
||||
} catch (Exception exception) {
|
||||
e = exception;
|
||||
}
|
||||
|
||||
assertNotNull(e);
|
||||
assertEquals(IllegalArgumentException.class, e.getClass());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseWith32Key() {
|
||||
NacosJwtParser parser = new NacosJwtParser(encode("SecretKey01234567890123456789012"));
|
||||
String token = parser.jwtBuilder().setUserName("nacos").setExpiredTime(100L).compact();
|
||||
|
||||
assertTrue(token.startsWith(NacosSignatureAlgorithm.HS256.getHeader()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseWith48Key() {
|
||||
NacosJwtParser parser = new NacosJwtParser(encode("SecretKey012345678901234567890120124568aa9012345"));
|
||||
String token = parser.jwtBuilder().setUserName("nacos").setExpiredTime(100L).compact();
|
||||
|
||||
assertTrue(token.startsWith(NacosSignatureAlgorithm.HS384.getHeader()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseWith64Key() {
|
||||
NacosJwtParser parser = new NacosJwtParser(
|
||||
encode("SecretKey012345678901234567SecretKey0123456789012345678901289012"));
|
||||
String token = parser.jwtBuilder().setUserName("nacos").setExpiredTime(100L).compact();
|
||||
|
||||
assertTrue(token.startsWith(NacosSignatureAlgorithm.HS512.getHeader()));
|
||||
}
|
||||
|
||||
private String encode(String key) {
|
||||
return Base64.getEncoder().encodeToString(key.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user