Unauthorized Client SSO при получении кода и состояния с сервера аутентификации Spring Oauth2 - PullRequest
0 голосов
/ 14 апреля 2020

Я сейчас работаю над проектом, используя Spring Boot и OAuth2 для аутентификации, и я новичок ie здесь. Я разделил сервер аутентификации (AS) и сервер ресурсов (RS) на два разных приложения, работающих на двух разных портах. У меня также есть клиентское приложение, работающее на другом порту, и я попытаюсь получить токен доступа от AS. Проблема в том, что, когда я обращаюсь к клиентскому приложению для аутентификации, оно перенаправляет меня в AS для аутентификации, а после ввода имени пользователя и пароля оно перенаправляет меня обратно в клиентское приложение. Так или иначе, он застревает на этом шаге, когда формирует al oop. Посмотрите на сетевой трафик c.

Затем я смотрю на консоль клиентского приложения, и она показывает this

Я провел исследование Inte rnet и, похоже, проблема в RS. Ниже приведены мои настройки как на AS, так и на RS. Также клиентское приложение.

Сервер аутентификации:

AuthenticationServerConfig. java

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

@Value("${jwt.certificate.store.file}")
private Resource keystore;

@Value("${jwt.certificate.store.password}")
private String keystorePassword;

@Value("${jwt.certificate.key.alias}")
private String keyAlias;

@Value("${jwt.certificate.key.password}")
private String keyPassword;
@Autowired
private UserDetailsService userDetailsService;

@Autowired
private ClientDetailsService clientDetails;

@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
    KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(
            keystore, keystorePassword.toCharArray());
    KeyPair keyPair = keyStoreKeyFactory.getKeyPair(
            keyAlias, keyPassword.toCharArray());
    JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
    converter.setKeyPair(keyPair);
    return converter;
}

@Override
public void configure(ClientDetailsServiceConfigurer clientDetailsServiceConfigurer) throws Exception{
    clientDetailsServiceConfigurer.withClientDetails(clientDetails);
}

@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
    endpoints
            .accessTokenConverter(jwtAccessTokenConverter())
            .userDetailsService(userDetailsService);
}
}

WebSecurityConfig. java

@EnableWebSecurity
@EnableOAuth2Client
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired
private UserDetailsService userDetailsService;

@Autowired
private PasswordEncoder passwordEncoder;

@Bean
public AuthenticationProvider authenticationProvider(){
    return new CustomDAOAuthenticationProvider(userDetailsService, passwordEncoder);
}

@Bean
public GrantedAuthoritiesMapper grantedAuthoritiesMapper() {
    SimpleAuthorityMapper simpleAuthorityMapper = new SimpleAuthorityMapper();
    simpleAuthorityMapper.setPrefix("ROLE_");
    simpleAuthorityMapper.setConvertToUpperCase(true);
    return simpleAuthorityMapper;
}

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception{
    auth.authenticationProvider(authenticationProvider());
}

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.csrf().disable()
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER).and()
            .authorizeRequests()
            .antMatchers( "/css/**", "/images/**", "/api/me").permitAll()
            .anyRequest().authenticated()
            .and().formLogin().loginPage("/login").permitAll()
            .defaultSuccessUrl("/api/me")
            .and().logout().logoutSuccessUrl("/login");
}
}

appilication. yml

server:
port: 7000
servlet:
  context-path: /e-auth

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/e_auth
    username: root
    password: password
    driver-class-name: com.mysql.cj.jdbc.Driver
  jpa:
    show-sql: false
    hibernate:
      ddl-auto: update
    properties:
      hibernate:
        dialect: org.hibernate.dialect.MySQL8Dialect
        enable_lazy_load_no_trans: true

jwt:
  certificate:
    store:
      file: classpath:/certificate/jwt.jks
      password: password
    key:
      alias: jwt
      password: password

Сервер ресурсов:

ResourceServerConfig. java

@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

@Qualifier("jwtTokenStore")
@Autowired
TokenStore tokenStore;

@Override
public void configure(HttpSecurity http) throws Exception {
    http
            .authorizeRequests()
            .anyRequest().authenticated()
            .and().exceptionHandling()
            .authenticationEntryPoint((httpServletRequest, httpServletResponse, authException)
                    -> httpServletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED))
            .accessDeniedHandler((httpServletRequest, httpServletResponse, authException)
                    -> httpServletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED));
}

public void configure(ResourceServerSecurityConfigurer resource){
    resource.tokenStore(tokenStore)
            .resourceId("USER_ADMIN_RESOURCE");
}

}

ResoucreController. java

@RestController
@RequestMapping("/api")
public class ResourcesController {

@GetMapping("/user")
public Object returnPrincipal(Principal user){
    return SecurityContextHolder.getContext().getAuthentication().getPrincipal();
}
}

application.yml

server:
port: 7003
servlet:
  context-path: /e-resrc

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/e_data
    username: root
    password: password
    driver-class-name: com.mysql.cj.jdbc.Driver
  jpa:
    show-sql: false
    hibernate:
      ddl-auto: update
    properties:
      hibernate:
        dialect: org.hibernate.dialect.MySQL8Dialect
        enable_lazy_load_no_trans: true
  security:
    oauth2:
      resource:
        jwt:
          keyValue: |
            -----BEGIN PUBLIC KEY-----
            -----END PUBLIC KEY-----

Клиентское приложение:

WebSecurityConfig. java

@Configuration
@EnableOAuth2Sso
@Order(0)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.csrf().disable()
            .antMatcher("/**")
            .authorizeRequests()
            .antMatchers("/login**").permitAll()
            .anyRequest().authenticated()
            .and().httpBasic();
}
}

application.yml

server:
  port: 7002
  servlet:
    context-path: /e-connect

security:
  oauth2:
    client:
      access-token-uri: http://localhost:7000/e-auth/oauth/token
      user-authorization-uri: http://localhost:7000/e-auth/oauth/authorize
      client-id: app
      client-secret: password
    resource:
      user-info-uri: http://localhost:7003/e-resrc/api/user

Подводя итог: я получаю следующее сообщение от консоли клиентского приложения и AS не выдает токен доступа для клиентского приложения.

WARN 12820 --- [nio-7002-exec-9] o.s.b.a.s.o.r.UserInfoTokenServices: Could not fetch user details: class org.springframework.security.oauth2.common.exceptions.InvalidRequestException, 
Possible CSRF detected - state parameter was required but no state could be found

Также я смог использовать Postman для получения токена доступа от AS с потоком authorization_code. Дополнительный код можно найти в моем хранилище на GitHub: https://github.com/augustus981/E-Connect

Пожалуйста, помогите мне с этим. Я застрял на этой неделе и не знаю, как это исправить.

ОБНОВЛЕНИЕ 1:

Я настроил клиентское приложение следующим образом, чтобы увидеть что там происходит, и вещи go довольно странные. Когда клиентское приложение впервые отправляет идентификатор клиента, redirectURI, тип ответа и состояние в AS.

http://localhost:7000/e-auth/oauth/authorize?client_id=app&redirect_uri=http://localhost:7002/e-connect/login&response_type=code&state=z3WDTJ

Затем AS перенаправляет обратно на redirectURI с кодом и точным состоянием, клиентское приложение сообщает, что оно не авторизовано (401). Это URI перенаправления, которое клиентское приложение сообщает, что оно неавторизовано. Я понятия не имею, что происходит.

http://localhost:7002/e-connect/login?code=SiHmGB&state=z3WDTJ

Поэтому я разрешаю все подключения к "/ login **", но тем не менее оно не авторизовано.

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.csrf().disable()
            .authorizeRequests()
            .antMatchers("/login**", "/error**").permitAll()
            .anyRequest().authenticated()
            .and()
            .formLogin()
            .and().httpBasic();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...