gpt4 book ai didi

spring - OAuth2多重身份验证中的空客户端

转载 作者:行者123 更新时间:2023-12-04 04:29:44 29 4
gpt4 key购买 nike

用于多因素身份验证的Spring OAuth2实现的完整代码已上传到a file sharing site that you can download by clicking on this link。以下说明说明了如何使用链接在任何计算机上重新创建当前问题。 提供500点奖励。


当前错误:



当用户尝试使用the Spring Boot OAuth2 app from the link in the preceding paragraph中的两因素身份验证进行身份验证时,将触发错误。当应用程序应在第二页上请求用户提供用于确认用户身份的个人识别码时,便会在该过程中抛出该错误。

鉴于空客户端正在触发此错误,问题似乎出在Spring Boot OAuth2中如何将ClientDetailsService连接到Custom OAuth2RequestFactory

entire debug log can be read at a file sharing site by clicking on this link。日志中的完整堆栈跟踪仅包含对应用程序中实际代码的一个引用,该行代码为:

AuthorizationRequest authorizationRequest =  
oAuth2RequestFactory.createAuthorizationRequest(paramsFromRequest(request));

调试日志中引发的错误是:
org.springframework.security.oauth2.provider.NoSuchClientException:  
No client with requested id: null

引发错误时的控制流:



我创建了以下流程图,以说明 @James' suggested implementation中的多因素身份验证请求的预期流程:




在前面的流程图中,当前错误在 用户名和密码 View GET/secure/two_factor_authenticated 步骤之间抛出。

此OP的解决方案仅限于FIRST PASS,即1.)穿越/oauth/authorize端点,然后2.)通过/oauth/authorize返回TwoFactorAuthenticationController端点。

因此,我们只想解决 NoSuchClientException,同时还演示了已在 ROLE_TWO_FACTOR_AUTHENTICATED中成功为客户端授予了 POST /secure/two_factor_authenticated。鉴于后续步骤很简单,只要用户以成功完成 的所有工件输入 SECOND PASS ,就可以将流程明显地打断到CustomOAuth2RequestFactory中的 SECOND PASS 条目中FIRST PASS 。只要我们在这里成功解决了 FIRST PASS SECOND PASS 可以是一个单独的问题。

相关代码异常(exception):



这是 AuthorizationServerConfigurerAdapter的代码,我尝试在其中建立连接:
@Configuration
@EnableAuthorizationServer
protected static class OAuth2AuthorizationConfig extends AuthorizationServerConfigurerAdapter {

@Autowired
private AuthenticationManager authenticationManager;

@Autowired//ADDED AS A TEST TO TRY TO HOOK UP THE CUSTOM REQUEST FACTORY
private ClientDetailsService clientDetailsService;

@Autowired//Added per: https://stackoverflow.com/questions/30319666/two-factor-authentication-with-spring-security-oauth2
private CustomOAuth2RequestFactory customOAuth2RequestFactory;

//THIS NEXT BEAN IS A TEST
@Bean CustomOAuth2RequestFactory customOAuth2RequestFactory(){
return new CustomOAuth2RequestFactory(clientDetailsService);
}

@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
KeyPair keyPair = new KeyStoreKeyFactory(
new ClassPathResource("keystore.jks"), "foobar".toCharArray()
)
.getKeyPair("test");
converter.setKeyPair(keyPair);
return converter;
}

@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("acme")//API: http://docs.spring.io/spring-security/oauth/apidocs/org/springframework/security/oauth2/config/annotation/builders/ClientDetailsServiceBuilder.ClientBuilder.html
.secret("acmesecret")
.authorizedGrantTypes("authorization_code", "refresh_token", "password")
.scopes("openid");
}

@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints//API: http://docs.spring.io/spring-security/oauth/apidocs/org/springframework/security/oauth2/config/annotation/web/configurers/AuthorizationServerEndpointsConfigurer.html
.authenticationManager(authenticationManager)
.accessTokenConverter(jwtAccessTokenConverter())
.requestFactory(customOAuth2RequestFactory);//Added per: https://stackoverflow.com/questions/30319666/two-factor-authentication-with-spring-security-oauth2
}

@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer//API: http://docs.spring.io/spring-security/oauth/apidocs/org/springframework/security/oauth2/config/annotation/web/configurers/AuthorizationServerSecurityConfigurer.html
.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()");
}

}

这是 TwoFactorAuthenticationFilter的代码,其中包含上面触发错误的代码:
package demo;

import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.provider.AuthorizationRequest;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.OAuth2RequestFactory;
import org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;

//This class is added per: https://stackoverflow.com/questions/30319666/two-factor-authentication-with-spring-security-oauth2
/**
* Stores the oauth authorizationRequest in the session so that it can
* later be picked by the {@link com.example.CustomOAuth2RequestFactory}
* to continue with the authoriztion flow.
*/
public class TwoFactorAuthenticationFilter extends OncePerRequestFilter {

private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
private OAuth2RequestFactory oAuth2RequestFactory;
//These next two are added as a test to avoid the compilation errors that happened when they were not defined.
public static final String ROLE_TWO_FACTOR_AUTHENTICATED = "ROLE_TWO_FACTOR_AUTHENTICATED";
public static final String ROLE_TWO_FACTOR_AUTHENTICATION_ENABLED = "ROLE_TWO_FACTOR_AUTHENTICATION_ENABLED";

@Autowired
public void setClientDetailsService(ClientDetailsService clientDetailsService) {
oAuth2RequestFactory = new DefaultOAuth2RequestFactory(clientDetailsService);
}

private boolean twoFactorAuthenticationEnabled(Collection<? extends GrantedAuthority> authorities) {
return authorities.stream().anyMatch(
authority -> ROLE_TWO_FACTOR_AUTHENTICATION_ENABLED.equals(authority.getAuthority())
);
}

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
// Check if the user hasn't done the two factor authentication.
if (AuthenticationUtil.isAuthenticated() && !AuthenticationUtil.hasAuthority(ROLE_TWO_FACTOR_AUTHENTICATED)) {
AuthorizationRequest authorizationRequest = oAuth2RequestFactory.createAuthorizationRequest(paramsFromRequest(request));
/* Check if the client's authorities (authorizationRequest.getAuthorities()) or the user's ones
require two factor authenticatoin. */
if (twoFactorAuthenticationEnabled(authorizationRequest.getAuthorities()) ||
twoFactorAuthenticationEnabled(SecurityContextHolder.getContext().getAuthentication().getAuthorities())) {
// Save the authorizationRequest in the session. This allows the CustomOAuth2RequestFactory
// to return this saved request to the AuthenticationEndpoint after the user successfully
// did the two factor authentication.
request.getSession().setAttribute(CustomOAuth2RequestFactory.SAVED_AUTHORIZATION_REQUEST_SESSION_ATTRIBUTE_NAME, authorizationRequest);

// redirect the the page where the user needs to enter the two factor authentiation code
redirectStrategy.sendRedirect(request, response,
ServletUriComponentsBuilder.fromCurrentContextPath()
.path(TwoFactorAuthenticationController.PATH)
.toUriString());
return;
}
}

filterChain.doFilter(request, response);
}

private Map<String, String> paramsFromRequest(HttpServletRequest request) {
Map<String, String> params = new HashMap<>();
for (Entry<String, String[]> entry : request.getParameterMap().entrySet()) {
params.put(entry.getKey(), entry.getValue()[0]);
}
return params;
}
}

在计算机上重新创建问题:



您可以按照以下简单步骤在几分钟内在任何计算机上重新创建问题:

1.)下载 zipped version of the app from a file sharing site by clicking on this link

2.)通过键入以下内容来解压缩应用程序: tar -zxvf oauth2.tar(1).gz
3.)通过导航到 authserver,然后键入 oauth2/authserver来启动 mvn spring-boot:run应用程序。

4.)导航到 resource,然后键入 oauth2/resource,以启动 mvn spring-boot:run应用程序

5.)通过导航到 ui,然后键入 oauth2/ui来启动 mvn spring-boot:run应用程序

6.)打开网络浏览器并导航到 http : // localhost : 8080
7.)单击 Login,然后输入 Frodo作为用户,并输入 MyRing作为密码,然后单击提交。 这将触发上面显示的错误。

您可以通过以下方式查看完整的源代码:

a。)将Maven项目导入到您的IDE中,或通过

b。)在解压缩的目录中导航并使用文本编辑器打开。

注意:上面的文件共享链接中的代码是 the Spring Boot OAuth2 GitHub sample at this linksuggestions for 2 Factor Authentication offered by @James at this link的组合。 Spring Boot GitHub示例的唯一更改是在 authserver应用程序中,尤其是在 authserver/src/main/java authserver/src/main/resources/templates 中。

遇到的问题:

根据@AbrahamGrief的建议,我添加了一个 FilterConfigurationBean,它解决了 NoSuchClientException。但是OP询问如何通过图中的控制流完成 500点赏金来完成 FIRST PASS

然后,我通过在 ROLE_TWO_FACTOR_AUTHENTICATION_ENABLED中设置 Users.loadUserByUername()来缩小问题的范围,如下所示:
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
String password;
List<GrantedAuthority> auth = AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_USER");
if (username.equals("Samwise")) {//ROLE_TWO_FACTOR_AUTHENTICATION_ENABLED will need to come from the resource, NOT the user
auth = AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_HOBBIT, ROLE_TWO_FACTOR_AUTHENTICATION_ENABLED");
password = "TheShire";
}
else if (username.equals("Frodo")){//ROLE_TWO_FACTOR_AUTHENTICATION_ENABLED will need to come from the resource, NOT the user
auth = AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_HOBBIT, ROLE_TWO_FACTOR_AUTHENTICATION_ENABLED");
password = "MyRing";
}
else{throw new UsernameNotFoundException("Username was not found. ");}
return new org.springframework.security.core.userdetails.User(username, password, auth);
}

这消除了配置客户端和资源的需要,因此当前问题仍然很狭窄。但是,下一个障碍是Spring Security拒绝用户对 /security/two_factor_authentication的请求。 需要做哪些进一步的更改才能通过控制流完成FIRST PASS,以便POST /secure/two_factor_authentication可以SYSO ROLE_TWO_FACTOR_AUTHENTICATED进行?

最佳答案

该项目需要大量的修改才能实现所描述的流程,这超出了单个问题的范围。该答案将仅关注如何解决:

org.springframework.security.oauth2.provider.NoSuchClientException: No client with requested id: null



在Spring Boot授权服务器中运行时尝试使用 SecurityWebApplicationInitializerFilter bean时。

发生此异常的原因是因为 WebApplicationInitializer instances are not run by Spring Boot。这包括将在部署到独立Servlet容器的WAR中工作的所有 AbstractSecurityWebApplicationInitializer子类。因此,发生的事情是Spring Boot根据 @Bean注释创建了过滤器,忽略了 AbstractSecurityWebApplicationInitializer,并将过滤器应用于所有URL。同时,您只希望将过滤器应用于尝试传递给 addMappingForUrlPatterns的那些URL。

相反,要将Servlet过滤器应用于Spring Boot中的特定URL,您应该 define a FilterConfigurationBean 。对于问题中描述的流程,该流程正尝试将自定义 TwoFactorAuthenticationFilter应用于 /oauth/authorize,如下所示:
@Bean
public FilterRegistrationBean twoFactorAuthenticationFilterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(twoFactorAuthenticationFilter());
registration.addUrlPatterns("/oauth/authorize");
registration.setName("twoFactorAuthenticationFilter");
return registration;
}

@Bean
public TwoFactorAuthenticationFilter twoFactorAuthenticationFilter() {
return new TwoFactorAuthenticationFilter();
}

关于spring - OAuth2多重身份验证中的空客户端,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36899386/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com