Http request use new plugin.

This commit is contained in:
KomachiSion 2022-01-20 16:04:20 +08:00
parent d2e11a3de7
commit 88818d0816
6 changed files with 146 additions and 110 deletions

View File

@ -58,7 +58,7 @@ public abstract class AbstractProtocolAuthService<R> implements ProtocolAuthServ
}
@Override
public boolean validateAuthority(IdentityContext identityContext, Permission permission) {
public boolean validateAuthority(IdentityContext identityContext, Permission permission) throws AccessException {
if (!authConfigs.isAuthEnabled()) {
return true;
}

View File

@ -51,8 +51,9 @@ public interface AuthPluginService {
* @param identityContext where we can find the user information.
* @param permission permission to auth.
* @return Boolean if the user has the resource authority.
* @throws AccessException if authentication is failed
*/
Boolean validateAuthority(IdentityContext identityContext, Permission permission);
Boolean validateAuthority(IdentityContext identityContext, Permission permission) throws AccessException;
/**
* AuthPluginService Name which for conveniently find AuthPluginService instance.

View File

@ -43,7 +43,7 @@ public class HttpProtocolAuthService extends AbstractProtocolAuthService<HttpSer
private final HttpIdentityContextBuilder identityContextBuilder;
protected HttpProtocolAuthService(AuthConfigs authConfigs) {
public HttpProtocolAuthService(AuthConfigs authConfigs) {
super(authConfigs);
resourceParserMap = new HashMap<>(2);
identityContextBuilder = new HttpIdentityContextBuilder(authConfigs);

View File

@ -19,8 +19,10 @@ 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.AuthPluginService;
import com.alibaba.nacos.auth.api.IdentityContext;
import com.alibaba.nacos.auth.api.Permission;
import com.alibaba.nacos.auth.exception.AccessException;
import com.alibaba.nacos.auth.model.User;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.config.server.auth.RoleInfo;
@ -39,6 +41,8 @@ import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
/**
@ -48,7 +52,21 @@ import java.util.List;
* @since 1.2.0
*/
@Component
public class NacosAuthManager implements AuthManager {
@SuppressWarnings("PMD.ServiceOrDaoClassShouldEndWithImplRule")
public class NacosAuthManager implements AuthManager, AuthPluginService {
private static final String AUTH_PLUGIN_TYPE = "nacos";
private static final String USER_IDENTITY_PARAM_KEY = "user";
private static final List<String> IDENTITY_NAMES = new LinkedList<String>() {
{
add(AuthConstants.AUTHORIZATION_HEADER);
add(Constants.ACCESS_TOKEN);
add(AuthConstants.PARAM_USERNAME);
add(AuthConstants.PARAM_PASSWORD);
}
};
@Autowired
private JwtTokenManager tokenManager;
@ -63,34 +81,8 @@ public class NacosAuthManager implements AuthManager {
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(AuthConstants.GLOBAL_ADMIN_ROLE)) {
user.setGlobalAdmin(true);
break;
}
}
}
validate0(token);
NacosUser user = getNacosUser(token);
req.getSession().setAttribute(RequestUtil.NACOS_USER_KEY, user);
return user;
}
@ -99,46 +91,39 @@ public class NacosAuthManager implements AuthManager {
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(AuthConstants.GLOBAL_ADMIN_ROLE)) {
user.setGlobalAdmin(true);
break;
}
}
}
return user;
validate0(token);
return getNacosUser(token);
}
@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!");
}
auth0(permission, user);
}
@Override
public Collection<String> identityNames() {
return IDENTITY_NAMES;
}
@Override
public boolean validateIdentity(IdentityContext identityContext) throws AccessException {
String token = resolveToken(identityContext);
validate0(token);
NacosUser user = getNacosUser(token);
identityContext.setParameter(USER_IDENTITY_PARAM_KEY, user);
return true;
}
@Override
public Boolean validateAuthority(IdentityContext identityContext, Permission permission) throws AccessException {
NacosUser user = (NacosUser) identityContext.getParameter(USER_IDENTITY_PARAM_KEY);
auth0(permission, user);
return true;
}
@Override
public String getAuthServiceName() {
return AUTH_PLUGIN_TYPE;
}
/**
@ -173,7 +158,20 @@ public class NacosAuthManager implements AuthManager {
String password = request.getHeader(AuthConstants.PARAM_PASSWORD);
bearerToken = resolveTokenFromUser(userName, password);
}
return bearerToken;
}
private String resolveToken(IdentityContext identityContext) throws AccessException {
String bearerToken = identityContext.getParameter(AuthConstants.AUTHORIZATION_HEADER, StringUtils.EMPTY);
if (StringUtils.isNotBlank(bearerToken) && bearerToken.startsWith(AuthConstants.TOKEN_PREFIX)) {
return bearerToken.substring(7);
}
bearerToken = identityContext.getParameter(Constants.ACCESS_TOKEN, StringUtils.EMPTY);
if (StringUtils.isBlank(bearerToken)) {
String userName = (String) identityContext.getParameter(AuthConstants.PARAM_USERNAME);
String password = (String) identityContext.getParameter(AuthConstants.PARAM_PASSWORD);
bearerToken = resolveTokenFromUser(userName, password);
}
return bearerToken;
}
@ -196,4 +194,48 @@ public class NacosAuthManager implements AuthManager {
return tokenManager.createToken(finalName);
}
private void validate0(String token) throws AccessException {
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!");
}
}
private NacosUser getNacosUser(String token) {
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(AuthConstants.GLOBAL_ADMIN_ROLE)) {
user.setGlobalAdmin(true);
break;
}
}
}
return user;
}
private void auth0(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!");
}
}
}

View File

@ -16,6 +16,8 @@
package com.alibaba.nacos.core.auth;
import com.alibaba.nacos.auth.config.AuthConfigs;
import com.alibaba.nacos.core.code.ControllerMethodsCache;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -29,9 +31,9 @@ import org.springframework.context.annotation.Configuration;
public class AuthConfig {
@Bean
public FilterRegistrationBean authFilterRegistration() {
public FilterRegistrationBean authFilterRegistration(AuthFilter authFilter) {
FilterRegistrationBean<AuthFilter> registration = new FilterRegistrationBean<>();
registration.setFilter(authFilter());
registration.setFilter(authFilter);
registration.addUrlPatterns("/*");
registration.setName("authFilter");
registration.setOrder(6);
@ -40,7 +42,7 @@ public class AuthConfig {
}
@Bean
public AuthFilter authFilter() {
return new AuthFilter();
public AuthFilter authFilter(AuthConfigs authConfigs, ControllerMethodsCache methodsCache) {
return new AuthFilter(authConfigs, methodsCache);
}
}

View File

@ -16,20 +16,20 @@
package com.alibaba.nacos.core.auth;
import com.alibaba.nacos.auth.AuthManager;
import com.alibaba.nacos.auth.HttpProtocolAuthService;
import com.alibaba.nacos.auth.annotation.Secured;
import com.alibaba.nacos.auth.api.IdentityContext;
import com.alibaba.nacos.auth.api.Permission;
import com.alibaba.nacos.auth.api.Resource;
import com.alibaba.nacos.auth.config.AuthConfigs;
import com.alibaba.nacos.auth.exception.AccessException;
import com.alibaba.nacos.auth.api.Permission;
import com.alibaba.nacos.auth.parser.ResourceParser;
import com.alibaba.nacos.common.utils.ExceptionUtil;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.core.code.ControllerMethodsCache;
import com.alibaba.nacos.sys.env.Constants;
import com.alibaba.nacos.core.utils.Loggers;
import com.alibaba.nacos.core.utils.WebUtils;
import com.alibaba.nacos.common.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import com.alibaba.nacos.sys.env.Constants;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
@ -51,16 +51,20 @@ import java.util.concurrent.ConcurrentHashMap;
*/
public class AuthFilter implements Filter {
@Autowired
private AuthConfigs authConfigs;
private final AuthConfigs authConfigs;
@Autowired
private AuthManager authManager;
private final ControllerMethodsCache methodsCache;
@Autowired
private ControllerMethodsCache methodsCache;
private final HttpProtocolAuthService protocolAuthService;
private Map<Class<? extends ResourceParser>, ResourceParser> parserInstance = new ConcurrentHashMap<>();
private final Map<Class<? extends ResourceParser>, ResourceParser> parserInstance = new ConcurrentHashMap<>();
public AuthFilter(AuthConfigs authConfigs, ControllerMethodsCache methodsCache) {
this.authConfigs = authConfigs;
this.methodsCache = methodsCache;
this.protocolAuthService = new HttpProtocolAuthService(authConfigs);
this.protocolAuthService.initialize();
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
@ -114,22 +118,19 @@ public class AuthFilter implements Filter {
}
Secured secured = method.getAnnotation(Secured.class);
Resource resource = protocolAuthService.parseResource(req, secured);
IdentityContext identityContext = protocolAuthService.parseIdentity(req);
boolean result = protocolAuthService.validateIdentity(identityContext);
if (!result) {
// TODO Get reason of failure
throw new AccessException("Validate Identity failed.");
}
String action = secured.action().toString();
String resource = secured.resource();
if (StringUtils.isBlank(resource)) {
ResourceParser parser = getResourceParser(secured.parser());
resource = parser.parseName(req);
result = protocolAuthService.validateAuthority(identityContext, new Permission(resource, action));
if (!result) {
// TODO Get reason of failure
throw new AccessException("Validate Authority failed.");
}
if (StringUtils.isBlank(resource)) {
// deny if we don't find any resource:
throw new AccessException("resource name invalid!");
}
Resource resourceObj = new Resource(null, null, resource, secured.signType(), null);
authManager.auth(new Permission(resourceObj, action), authManager.login(req));
}
chain.doFilter(request, response);
} catch (AccessException e) {
@ -144,14 +145,4 @@ public class AuthFilter implements Filter {
resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Server failed," + e.getMessage());
}
}
private ResourceParser getResourceParser(Class<? extends ResourceParser> parseClass)
throws IllegalAccessException, InstantiationException {
ResourceParser parser = parserInstance.get(parseClass);
if (parser == null) {
parser = parseClass.newInstance();
parserInstance.put(parseClass, parser);
}
return parser;
}
}