Skip to content

Commit

Permalink
[ISSUE #9859] 重构默认插件的登陆/鉴权逻辑 (#9889)
Browse files Browse the repository at this point in the history
* refactor auth logic;fix conflict

* update unit test.
  • Loading branch information
YunWZ authored Feb 3, 2023
1 parent 35b9884 commit 42b28f9
Show file tree
Hide file tree
Showing 20 changed files with 585 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
* @author wfnuser
*/
@Component
@Deprecated
public class CustomAuthenticationProvider implements AuthenticationProvider {

@Autowired
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
* @author wfnuser
*/
@Component
@Deprecated
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {

private static final Logger LOGGER = LoggerFactory.getLogger(JwtAuthenticationEntryPoint.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ private void processProperties() {
* @param authentication auth info
* @return token
*/
@Deprecated
public String createToken(Authentication authentication) {
return createToken(authentication.getName());
}
Expand All @@ -101,6 +102,7 @@ public String createToken(String userName) {
* @param token token
* @return auth info
*/
@Deprecated
public Authentication getAuthentication(String token) throws AccessException {
NacosUser nacosUser = jwtParser.parse(token);

Expand All @@ -116,7 +118,11 @@ public Authentication getAuthentication(String token) throws AccessException {
* @param token token
*/
public void validateToken(String token) throws AccessException {
jwtParser.parse(token);
parseToken(token);
}

public NacosUser parseToken(String token) throws AccessException {
return jwtParser.parse(token);
}

public long getTokenValidityInSeconds() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

package com.alibaba.nacos.plugin.auth.impl;

import com.alibaba.nacos.plugin.auth.impl.authenticate.IAuthenticationManager;
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.constant.AuthConstants;
import com.alibaba.nacos.plugin.auth.impl.roles.NacosRoleServiceImpl;
Expand All @@ -34,7 +36,7 @@
*
* @author onewe
*/
@Configuration
@Configuration(proxyBeanMethods = false)
@EnableAutoConfiguration(exclude = LdapAutoConfiguration.class)
public class LdapAuthConfig {

Expand Down Expand Up @@ -78,4 +80,13 @@ public LdapAuthenticationProvider ldapAuthenticationProvider(LdapTemplate ldapTe
caseSensitive);
}

@Bean
@Conditional(ConditionOnLdapAuth.class)
public IAuthenticationManager ldapAuthenticatoinManager(LdapTemplate ldapTemplate,
NacosUserDetailsServiceImpl userDetailsService, JwtTokenManager jwtTokenManager,
NacosRoleServiceImpl roleService) {
return new LdapAuthenticationManager(ldapTemplate, userDetailsService, jwtTokenManager, roleService,
filterPrefix, caseSensitive);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,13 @@

package com.alibaba.nacos.plugin.auth.impl;

import com.alibaba.nacos.plugin.auth.impl.authenticate.LdapAuthenticationManager;
import com.alibaba.nacos.plugin.auth.impl.constant.AuthConstants;
import com.alibaba.nacos.sys.utils.ApplicationUtils;

/**
* ldap auth plugin service.
*
* @author onewe
*/
public class LdapAuthPluginService extends NacosAuthPluginService {
Expand All @@ -28,4 +31,11 @@ public class LdapAuthPluginService extends NacosAuthPluginService {
public String getAuthServiceName() {
return AuthConstants.LDAP_AUTH_PLUGIN_TYPE;
}

@Override
protected void checkNacosAuthManager() {
if (null == authenticationManager) {
authenticationManager = ApplicationUtils.getBean(LdapAuthenticationManager.class);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,9 @@
*
* @author zjw
*/
@Deprecated
public class LdapAuthenticationProvider implements AuthenticationProvider {

private static final String DEFAULT_PASSWORD = "nacos";

private static final String LDAP_PREFIX = "LDAP_";

private final NacosUserDetailsServiceImpl userDetailsService;

private final NacosRoleServiceImpl nacosRoleService;
Expand Down Expand Up @@ -95,12 +92,12 @@ public Authentication authenticate(Authentication authentication) throws Authent

UserDetails userDetails;
try {
userDetails = userDetailsService.loadUserByUsername(LDAP_PREFIX + username);
userDetails = userDetailsService.loadUserByUsername(AuthConstants.LDAP_PREFIX + username);
} catch (UsernameNotFoundException exception) {
String nacosPassword = PasswordEncoderUtil.encode(DEFAULT_PASSWORD);
userDetailsService.createUser(LDAP_PREFIX + username, nacosPassword);
String nacosPassword = PasswordEncoderUtil.encode(AuthConstants.LDAP_DEFAULT_PASSWORD);
userDetailsService.createUser(AuthConstants.LDAP_PREFIX + username, nacosPassword);
User user = new User();
user.setUsername(LDAP_PREFIX + username);
user.setUsername(AuthConstants.LDAP_PREFIX + username);
user.setPassword(nacosPassword);
userDetails = new NacosUserDetails(user);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,17 @@
import com.alibaba.nacos.auth.config.AuthConfigs;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.core.code.ControllerMethodsCache;
import com.alibaba.nacos.plugin.auth.impl.authenticate.AuthenticationNamagerDelegator;
import com.alibaba.nacos.plugin.auth.impl.authenticate.DefaultAuthenticationManager;
import com.alibaba.nacos.plugin.auth.impl.authenticate.IAuthenticationManager;
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.filter.JwtAuthenticationTokenFilter;
import com.alibaba.nacos.plugin.auth.impl.roles.NacosRoleServiceImpl;
import com.alibaba.nacos.plugin.auth.impl.users.NacosUserDetailsServiceImpl;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.BeanIds;
Expand Down Expand Up @@ -148,4 +154,19 @@ protected void configure(HttpSecurity http) throws Exception {
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}

@Bean
@Primary
public IAuthenticationManager authenticationManager(
ObjectProvider<LdapAuthenticationManager> ldapAuthenticatoinManagerObjectProvider,
ObjectProvider<DefaultAuthenticationManager> defaultAuthenticationManagers, AuthConfigs authConfigs) {
return new AuthenticationNamagerDelegator(defaultAuthenticationManagers,
ldapAuthenticatoinManagerObjectProvider, authConfigs);
}

@Bean
public IAuthenticationManager defaultAuthenticationManager(NacosUserDetailsServiceImpl userDetailsService,
JwtTokenManager jwtTokenManager, NacosRoleServiceImpl roleService) {
return new DefaultAuthenticationManager(userDetailsService, jwtTokenManager, roleService);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
* @since 1.2.0
*/
@Component
@Deprecated
public class NacosAuthManager {

@Autowired
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,14 @@
package com.alibaba.nacos.plugin.auth.impl;

import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.plugin.auth.api.IdentityContext;
import com.alibaba.nacos.plugin.auth.api.Permission;
import com.alibaba.nacos.plugin.auth.api.Resource;
import com.alibaba.nacos.plugin.auth.constant.ActionTypes;
import com.alibaba.nacos.plugin.auth.exception.AccessException;
import com.alibaba.nacos.plugin.auth.impl.authenticate.DefaultAuthenticationManager;
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.users.NacosUser;
import com.alibaba.nacos.plugin.auth.spi.server.AuthPluginService;
Expand All @@ -39,6 +42,9 @@
@SuppressWarnings("PMD.ServiceOrDaoClassShouldEndWithImplRule")
public class NacosAuthPluginService implements AuthPluginService {

@Deprecated
private static final String USER_IDENTITY_PARAM_KEY = "user";

private static final List<String> IDENTITY_NAMES = new LinkedList<String>() {
{
add(AuthConstants.AUTHORIZATION_HEADER);
Expand All @@ -48,7 +54,7 @@ public class NacosAuthPluginService implements AuthPluginService {
}
};

private NacosAuthManager nacosAuthManager;
protected IAuthenticationManager authenticationManager;

@Override
public Collection<String> identityNames() {
Expand All @@ -64,17 +70,34 @@ public boolean enableAuth(ActionTypes action, String type) {
@Override
public boolean validateIdentity(IdentityContext identityContext, Resource resource) throws AccessException {
checkNacosAuthManager();
NacosUser user = nacosAuthManager.login(identityContext);
identityContext.setParameter(AuthConstants.NACOS_USER_KEY, user);
String token = resolveToken(identityContext);
NacosUser nacosUser;
if (StringUtils.isNotBlank(token)) {
nacosUser = authenticationManager.authenticate(token);
} else {
String userName = (String) identityContext.getParameter(AuthConstants.PARAM_USERNAME);
String password = (String) identityContext.getParameter(AuthConstants.PARAM_PASSWORD);
nacosUser = authenticationManager.authenticate(userName, password);
}
identityContext.setParameter(AuthConstants.NACOS_USER_KEY, nacosUser);
identityContext.setParameter(com.alibaba.nacos.plugin.auth.constant.Constants.Identity.IDENTITY_ID,
user.getUserName());
nacosUser.getUserName());
return true;
}

private String resolveToken(IdentityContext identityContext) {
String bearerToken = identityContext.getParameter(AuthConstants.AUTHORIZATION_HEADER, StringUtils.EMPTY);
if (StringUtils.isNotBlank(bearerToken) && bearerToken.startsWith(AuthConstants.TOKEN_PREFIX)) {
return bearerToken.substring(AuthConstants.TOKEN_PREFIX.length());
}

return identityContext.getParameter(Constants.ACCESS_TOKEN, StringUtils.EMPTY);
}

@Override
public Boolean validateAuthority(IdentityContext identityContext, Permission permission) throws AccessException {
NacosUser user = (NacosUser) identityContext.getParameter(AuthConstants.NACOS_USER_KEY);
nacosAuthManager.auth(permission, user);
authenticationManager.authorize(permission, user);

return true;
}
Expand All @@ -84,9 +107,9 @@ public String getAuthServiceName() {
return AuthConstants.AUTH_PLUGIN_TYPE;
}

private void checkNacosAuthManager() {
if (null == nacosAuthManager) {
nacosAuthManager = ApplicationUtils.getBean(NacosAuthManager.class);
protected void checkNacosAuthManager() {
if (null == authenticationManager) {
authenticationManager = ApplicationUtils.getBean(DefaultAuthenticationManager.class);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
/*
* 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.authenticate;

import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.core.utils.Loggers;
import com.alibaba.nacos.plugin.auth.api.Permission;
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.roles.NacosRoleServiceImpl;
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.NacosUserDetailsServiceImpl;
import com.alibaba.nacos.plugin.auth.impl.utils.PasswordEncoderUtil;

import javax.servlet.http.HttpServletRequest;

/**
* AbstractAuthenticationManager.
*
* @author Weizhan▪Yun
* @date 2023/1/13 12:48
*/
public class AbstractAuthenticationManager implements IAuthenticationManager {

protected NacosUserDetailsServiceImpl userDetailsService;

protected JwtTokenManager jwtTokenManager;

protected NacosRoleServiceImpl roleService;

public AbstractAuthenticationManager(NacosUserDetailsServiceImpl userDetailsService,
JwtTokenManager jwtTokenManager, NacosRoleServiceImpl roleService) {
this.userDetailsService = userDetailsService;
this.jwtTokenManager = jwtTokenManager;
this.roleService = roleService;
}

@Override
public NacosUser authenticate(String username, String rawPassword) throws AccessException {
if (StringUtils.isBlank(username) || StringUtils.isBlank(rawPassword)) {
throw new AccessException("user not found!");
}

NacosUserDetails nacosUserDetails = (NacosUserDetails) userDetailsService.loadUserByUsername(username);
if (nacosUserDetails == null || !PasswordEncoderUtil.matches(rawPassword, nacosUserDetails.getPassword())) {
throw new AccessException("user not found!");
}
return new NacosUser(nacosUserDetails.getUsername(), jwtTokenManager.createToken(username));
}

@Override
public NacosUser authenticate(String token) throws AccessException {
if (StringUtils.isBlank(token)) {
throw new AccessException("user not found!");
}

return jwtTokenManager.parseToken(token);
}

@Override
public NacosUser authenticate(HttpServletRequest httpServletRequest) throws AccessException {
String token = resolveToken(httpServletRequest);

NacosUser user;
if (StringUtils.isNotBlank(token)) {
user = authenticate(token);
} else {
String userName = httpServletRequest.getParameter(AuthConstants.PARAM_USERNAME);
String password = httpServletRequest.getParameter(AuthConstants.PARAM_PASSWORD);
user = authenticate(userName, password);
}

return user;
}

@Override
public void authorize(Permission permission, NacosUser nacosUser) throws AccessException {
if (Loggers.AUTH.isDebugEnabled()) {
Loggers.AUTH.debug("auth permission: {}, nacosUser: {}", permission, nacosUser);
}
if (nacosUser.isGlobalAdmin()) {
return;
}
if (hasGlobalAdminRole(nacosUser)) {
return;
}

if (!roleService.hasPermission(nacosUser, permission)) {
throw new AccessException("authorization failed!");
}
}

private String resolveToken(HttpServletRequest request) {
String bearerToken = request.getHeader(AuthConstants.AUTHORIZATION_HEADER);
if (StringUtils.isNotBlank(bearerToken) && bearerToken.startsWith(AuthConstants.TOKEN_PREFIX)) {
return bearerToken.substring(AuthConstants.TOKEN_PREFIX.length());
}
bearerToken = request.getParameter(Constants.ACCESS_TOKEN);

return bearerToken;
}

@Override
public boolean hasGlobalAdminRole(String username) {
return roleService.hasGlobalAdminRole(username);
}

@Override
public boolean hasGlobalAdminRole(NacosUser nacosUser) {
if (nacosUser.isGlobalAdmin()) {
return true;
}
nacosUser.setGlobalAdmin(hasGlobalAdminRole(nacosUser.getUserName()));
return nacosUser.isGlobalAdmin();
}
}
Loading

0 comments on commit 42b28f9

Please sign in to comment.