Spring Security Facebook OAuth2 - problem z autoryzacją z frontendu

0

Moja aplikacja to angularowy frontend oraz springowy backend. Do tej pory security było zaimplementowane za pomocą JWT, chciałem jednak by użytkownicy mieli opcję zalogowania swoim kontem z Facebooka, udało mi się całośc skonfigurować i cały flow wygląda teraz w ten sposób:

-Użytkownik na frontendzie klika "Kontynuj przez Facebooka", co po stronie frontendu robi w sumie tyle

 public loginWithFacebook() {
    window.location.href = 'http://localhost:8080/oauth2/authorize/facebook?redirect_uri=http://localhost:4200/facebook';
  }

Następuje przekierowanie na endpoint mojego backendu, który za pomocą magii spring-security-oauth2-client, przekierowuje mnie na Facebooka by potwierdzić logowanie.
Po potwierdzeniu, odpalony zostaje AuthenticationSuccessHandler, którego implementacja wygląda tak

@Component
@RequiredArgsConstructor
public class OAuth2AuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
    private final TokenProvider tokenProvider;
    private final CookieRequestRepository cookieRequestRepository;

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {
        String targetUrl = determineTargetUrl(request, response, authentication);
        clearAuthenticationAttributes(request, response);
        getRedirectStrategy().sendRedirect(request, response, targetUrl);
    }

    protected String determineTargetUrl(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
        Optional<String> redirectUri = getCookie(request, REDIRECT_URI_PARAM_COOKIE_NAME).map(Cookie::getValue);
        String targetUrl = redirectUri.orElse(getDefaultTargetUrl());
        String token = tokenProvider.createToken(authentication);
        return UriComponentsBuilder.fromUriString(targetUrl + "/" + token)
                .build().toUriString();
    }

    protected void clearAuthenticationAttributes(HttpServletRequest request, HttpServletResponse response) {
        super.clearAuthenticationAttributes(request);
        cookieRequestRepository.removeAuthorizationRequestCookies(request, response);
    }
}

Tutaj po prostu generuje token JWT, taki jakiego używałem do tej pory do zarządzania security oraz przekierowywuje użytkownika do redirect_uri który to podałem w requeście (dopieo teraz się zastanawiam czemu po prostu tego również nie zapiszę w application.properties ale to nie jest problem obecnie).
Następnie wygenerowany token przekazuje w tym redirect_uri do frontendu, tam go odczytuje, zapisuje w localStorage, wszystko do tej pory gra.

Problem pojawia się gdy tego tokenu chcę użyć - mogę go żywcem wyjąć z pamięci przeglądarki, wkleić do postmana i wszystkie endpointy mojego backendu odpowiadają poprawnie.
Jeżeli jednak korzystająć z tego samego tokenu, z poziomu frontendu spróbuje uderzyć do endpointu który wymaga autoryzacji, dostaję

screenshot-20191228230332.png

Próbuje zrozumieć co się tutaj dzieje i jak to naprawić... Skoro jestem już zalogowany, strzelam pod zabezpieczony endpoint z poprawnym tokenem, to czemu i tak leci jakiś dziwny redirect do Facebooka?

Poniżej wklejam jeszcze konfigurację security po stronie Springa

  @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.addFilterBefore(tokenAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
        http
            .cors()
                .and()
            .sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
            .csrf().disable()
            .formLogin() .disable()
            .httpBasic().disable()
            .authorizeRequests()
            .antMatchers("/auth/**",
                    "/oauth2/**",
                    "/policy",
                    "/user/**",
                    "/tags",
                    "/quiz",
                    "/quiz/list",
                    "/quiz/search"
                    ).permitAll()
            .anyRequest()
            .authenticated()
                .and()
            .oauth2Login()
                .authorizationEndpoint().baseUri("/oauth2/authorize")
            .authorizationRequestRepository(cookieRequestRepository)
                .and()
            .redirectionEndpoint().baseUri("/oauth2/callback/*")
                .and()
            .userInfoEndpoint().userService(oAuth2UserService)
                .and()
            .successHandler(successHandler)
            .failureHandler(failureHandler);
    }
0

Jakby kogoś ciekawiło - problemy były dwa ;)

  1. Zła obsługa błędów, myślałem że mając @ControllerAdvice który łapie wyjątki będzie dobrze. Brakowało jednak implementacji AuthenticationEntryPoint, powodowało to że przy strzale bez / z błędnym tokenem nie dostawałem 401 i jakiś error message, tylko odpowiedź w postaci HTMLa z Facebooka. Nie jestem pewien co po otrzymaniu takiej odpowiedzi Angular próbował zrobić, ale w jakiś sposób próbował strzelać bezpośrednio do Facebooka.

  2. Błędny token - założyłem, że kolega który implementował frontend i pisał między innymi interceptor który dodaje token do headerów requestów, zrobił to dobrze. Zapomniał jednak o dopisaniu "Bearer " przed tokenem, a moja implementacja backendu tego wymagała. W efekcie uznawałem taki token za niepoprawny i rzucałem błędem autoryzacji, co powodowało odpowiedź z punktu 1.

1 użytkowników online, w tym zalogowanych: 0, gości: 1