5

Ich arbeite an einem Beispiel Spring Boot App mit OAuth2. Das Problem besteht darin, dass der unter localhost:8080 gehostete Client https://localhost:8443/oauth/authorize aufruft, um sich selbst zu autorisieren (impliziter Gewährungstyp), aber da /oauth/authorize erfordert, dass der Benutzer authentifiziert wird, werden sie auf die Anmeldeseite umgeleitet unter https://localhost:8443/login.Spring OAuth2 nicht zurück zum Client auf Formular Login

Dies ist alles erwartet, aber wenn der Benutzer auf der Anmeldeseite landet, fehlen alle Abfragezeichenfolgen einschließlich redirect_uri. Der Benutzer meldet sich an und wird zu https://localhost:8443 statt der angegebenen redirect_uri von http://localhost:8080 umgeleitet.

Gibt es eine Möglichkeit, den Benutzer nach dem Login mit dem Anmeldeformular des Servers zum Client zurückzuleiten? Fehle ich etwas in meiner Konfiguration? Ich kann mehr bei Bedarf posten.

Die authorise Anfrage wie folgt aussieht: https://localhost:8443/oauth/authorize?response_type=token&state=6c2bb162-0f26-4caa-abbe-b65f7e5c6a2e&redirect_uri=http%3A%2F%2Flocalhost%3A8080&client_id=admin

SecurityConfig:

@Configuration 
public static class WebSecurityConfig extends WebSecurityConfigurerAdapter { 

    private final Logger log = LoggerFactory.getLogger(WebSecurityConfig.class);       

    @Override 
    public void configure(WebSecurity web) throws Exception { 

     web.ignoring().antMatchers("/resources/**"); 
    }  

    @SuppressWarnings("deprecation") 
    @Override 
    protected void configure(HttpSecurity http) throws Exception {     

     http 
      .requestMatchers() 
       .antMatchers("/**") 
     .and() 
      .addFilterAfter(new CsrfCookieGeneratorFilter(), CsrfFilter.class) 
      .exceptionHandling() 
       .accessDeniedPage("/login?authorization_error=true") 
     .and() 
      .authorizeRequests() 
      .antMatchers("/resources/**", "/csrf").permitAll() 
      .anyRequest().authenticated() 
     .and() 
      .formLogin() 
       .loginPage("/login") 
       .usernameParameter("j_username") 
       .passwordParameter("j_password") 
       .defaultSuccessUrl("/", false) 
       .failureUrl("/login?authentication_error=true") 
       .permitAll() 
     .and() 
      .logout() 
       .logoutRequestMatcher(new AntPathRequestMatcher("/logout")) 
       .logoutSuccessUrl("/login") 
       .invalidateHttpSession(true) 
       .deleteCookies("JSESSIONID", "CSRF-TOKEN") 
       .permitAll() 
     .and() 
      .headers() 
       .frameOptions() 
       .disable(); 
    } 

OAuthConfig:

@Configuration 
@EnableAuthorizationServer 
protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter { 

    @Inject 
    @Qualifier("authenticationManagerBean") 
    private AuthenticationManager authenticationManager; 

    @Bean 
    public TokenStore tokenStore() { 

     return new InMemoryTokenStore(); 
    } 

    @Primary 
    @Bean 
    public ResourceServerTokenServices tokenServices() { 

     DefaultTokenServices tokenServices = new DefaultTokenServices(); 
     tokenServices.setSupportRefreshToken(true); 
     tokenServices.setTokenStore(tokenStore()); 

     return tokenServices; 
    }   

    @Bean 
    public ApprovalStore approvalStore() throws Exception { 

     TokenApprovalStore approvalStore = new TokenApprovalStore(); 
     approvalStore.setTokenStore(tokenStore()); 

     return approvalStore; 
    } 

    @Override 
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception { 

     clients 
      .inMemory() 
       .withClient("read-only") 
        .secret("readme") 
        .resourceIds(RESOURCE_ID) 
        .authorizedGrantTypes("implicit", "password", "refresh_token")       
        .authorities(Constant.USER) 
        .scopes("read") 
        .autoApprove(true) 
        .redirectUris("https://localhost:8443") 
       .and() 
       .withClient("admin") 
        .secret("admin") 
        .resourceIds(RESOURCE_ID) 
        .authorizedGrantTypes("implicit", "password", "refresh_token") 
        .authorities(Constant.USER, Constant.ADMIN) 
        .scopes("read", "write") 
        .autoApprove(true) 
        .redirectUris("https://localhost:8443", "http://localhost:8080") 
       .and() 
       .withClient("super-admin") 
        .secret("super") 
        .resourceIds(RESOURCE_ID) 
        .authorizedGrantTypes("implicit", "password", "refresh_token") 
        .authorities(Constant.USER, Constant.ADMIN) 
        .scopes("read", "write", "delete") 
        .redirectUris("https://localhost:8443"); 
    } 

    @Override 
    public void configure(AuthorizationServerEndpointsConfigurer configurer) throws Exception { 

     configurer 
      .tokenStore(tokenStore()) 
      .authenticationManager(authenticationManager); 
    }   

    @Override 
    public void configure(AuthorizationServerSecurityConfigurer security) 
      throws Exception { 

     security.realm("hubble/client"); 
    } 

} 

@Configuration 
@EnableResourceServer 
protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {   

    @Override 
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception { 

     resources.resourceId(RESOURCE_ID); 
    } 

    @Override 
    public void configure(HttpSecurity http) throws Exception { 

     http 
      .requestMatchers() 
       .antMatchers("/api/**") 
     .and() 
      .authorizeRequests() 
       .antMatchers(HttpMethod.OPTIONS, "/api/**").permitAll() 
       .antMatchers(HttpMethod.GET, "/api/**").access("#oauth2.hasScope('read')") 
       .antMatchers(HttpMethod.POST, "/api/**").access("#oauth2.hasScope('write')") 
       .antMatchers(HttpMethod.PATCH, "/api/**").access("#oauth2.hasScope('write')") 
       .antMatchers(HttpMethod.PUT, "/api/**").access("#oauth2.hasScope('write')") 
       .antMatchers(HttpMethod.DELETE, "/api/**").access("#oauth2.hasScope('delete')") 
       .antMatchers("/api/**").access("hasRole('" + Constant.USER + "')")     
     .and() 
      .anonymous().authorities(Constant.ANONYMOUS) 
     .and() 
      .sessionManagement() 
       .sessionCreationPolicy(SessionCreationPolicy.STATELESS);       
    } 
} 

@Configuration 
@EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true) 
protected static class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {  

    @Override 
    protected MethodSecurityExpressionHandler createExpressionHandler() { 

     OAuth2MethodSecurityExpressionHandler methodHandler = new OAuth2MethodSecurityExpressionHandler(); 

     return methodHandler; 
    } 
} 
+0

Es funktioniert für mich (ich nie den 'defaultSuccessUrl verwenden()', aber ich sehe kein offensichtliches Problem damit) . Können Sie einen Link zu einem vollständigen Projekt veröffentlichen? –

+0

Danke @DaveSyer für einen Blick! Ich versuchte defaultSuccessUrl() in der Hoffnung, dass es mein Problem lösen würde, aber keine Würfel mit oder ohne. Es funktioniert, wenn ich/oauth/** mit basic auth statt einem Formular-Login schütze. Ich werde versuchen, das Projekt morgen auf GitHub zu veröffentlichen und einen Link bereitzustellen. –

+3

Hallo, Irgendwelche Erfolge damit? Ich habe das gleiche Problem. – pborbas

Antwort

0

Das Problem mit Formularauthentifizierung erfolgt nur, und es ist nicht auf OAuth verwendet. Der org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint verfügt über eine buildRedirectUrlToLoginPage-Methode, die die Anmelde-URL erstellt und die Abfragezeichenfolgen vergisst.

Zur Zeit haben wir es mit einem Workaround gelöst.

  1. statt den Benutzer auf die authorize-URL umzuleiten, leiten wir direkt zur Anmeldeseite um.
  2. Die Anmeldeseite verfügt über einen Controller, der überprüft, ob der Benutzer bereits angemeldet war. Wenn dies der Fall ist, wird die autorisierte URL mit der redirect_uri, falls vorhanden, oder der Standard-App-URL redirect_uri weitergeleitet.
  3. von hier wird die redirect_uri korrekt von der Autorisierung URL behandelt.

Ein Beispiel LoginController aus Schritt 2 könnte wie folgt aussehen:

@Controller 
@RequestMapping(value = {"/login"}) 
public class LoginController { 
    @RequestMapping(method = RequestMethod.GET) 
    public String getPage(HttpServletRequest request, HttpServletResponse response, Principal principal) 
      throws IOException { 
     if (principal != null) { //depends on your security config, maybe you want to check the security context instead if you allow anonym access 
      String redirect_uri = request.getParameter("redirect_uri"); 
      //here you must get all the other attributes thats needed for the authorize url 
      if (redirect_uri == null) { 
       redirect_uri = "https://your.default.app.url"; 
      }   
      return "redirect:https://localhost:8443/oauth/authorize?response_type=token&state=6c2bb162-0f26-4caa-abbe-b65f7e5c6a2e&client_id=admin&redirect_uri=" + URLEncoder.encode(redirect_uri, "UTF-8"); 
     } 
     return "login"; 
    } 
} 
Verwandte Themen