Как использовать специально созданный JWT для защиты моего API _WITHOUT_ с помощью oauth2

TL; DR - Как использовать специально созданный JWT для защиты моего API БЕЗ с помощью oauth2?

Я прочитал этот вопрос но я все еще не уверен, как распутать OAuth2 из аутентификации JWT в Spring Security 5. У меня странный случай, я попытаюсь объяснить

  1. мой SPA будет аутентифицироваться с Okta, чтобы получить токен доступа
  2. мой SPA отправит GET в мой загрузочный API (который я контролирую) в / token / exchange, который вернет настроенный JWT. Мой маршрут / токен / обмен проецируется через oauth2 с использованием стартера загрузки okta spring. У меня эта часть работает.
  3. мой SPA будет отправлять пользовательский JWT в качестве заголовка авторизации для всех последующих запросов к моему API. Мне нужно защитить все маршруты, начинающиеся с /api, чтобы принимались только запросы с моим пользовательским токеном.

Я избавлю вас от почему, если кому-то действительно не нужны подробности ... но, пожалуйста, поверьте мне, когда я говорю, что застрял между камнем и наковальней, и именно так мы решили решить проблему.

Я понимаю, что мне понадобятся два WebSecurityConfigurerAdapter, чтобы я мог защитить свой /token/exchange маршрут с помощью Okta, а все остальные маршруты - с помощью пользовательского JWT.

Я запутался в деталях фильтра безопасности. Должен ли я отменить один? Который из? Стоит ли делать новый фильтр? Куда его вставить? Я видел в Интернете пример, в котором используются GenericFilter, OncePerRequestFilter, UsernameAndPasswordFilter, BasicAuthFilter. Я немного завален вариантами ...

Для меня отметки +1 указали бы на возможность служить сообществу и продемонстрировали бы потребность, которую весенняя команда могла бы помочь удовлетворить.

------ кровавые подробности ------

у моего SPA в настоящее время есть настраиваемая страница входа в систему, которая отправляет кредиты моему API. Мой API выполняет вызов REST в Ping Federate, чтобы получить JWT с использованием типа предоставления password. Этот JWT возвращается в SPA, который SPA использует для всех последующих запросов.

Меня попросили преобразовать приложение для использования экземпляра Okta родительской компании. Я не контролирую его, и я не могу заставить его вернуть мне токен, который будет точно соответствовать токену Ping Federate, который в настоящее время ожидает мое приложение.

мой СПА - угловое приложение 1.5. прежде чем он будет загружен вручную, я планирую выполнить аутентификацию okta через перенаправление и обменять токен Okta на пользовательский токен. По сути, вместо того, чтобы передавать свои кредиты пользователей, я могу передать свой токен как своего рода ваучер ... потому что я больше никогда не увижу кредиты пользователей ... они будут вводиться только в Okta ... вроде все дело.

В моем API, просто используя тему токена okta, я могу найти все необходимые данные и построить токен, который по форме идентичен токену, предоставленному Ping Federate (который не возвращает типичный токен oauth2). Получив токен, который соответствует тому, что я получаю в настоящее время, большая часть логики API может продолжать работать «как есть».

-------- На данный момент неудачные попытки

Я вижу это в своих журналах

o.s.security.web.FilterChainProxy        : /api/entities at position 6 of 12 in additional filter chain; firing Filter: 'BearerTokenAuthenticationFilter'
o.s.s.authentication.ProviderManager     : Authentication attempt using org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationProvider
.s.a.DefaultAuthenticationEventPublisher : No event was found for the exception org.springframework.security.oauth2.core.OAuth2AuthenticationException
.o.s.r.w.BearerTokenAuthenticationFilter : Authentication request for failed: org.springframework.security.oauth2.core.OAuth2AuthenticationException: An error occurred while attempting to decode the Jwt: Signed JWT rejected: Another algorithm expected, or no matching key(s) found
o.s.s.w.header.writers.HstsHeaderWriter  : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@3ec543f6
s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed

похоже, что Spring Security пытается аутентифицировать запросы, сделанные к /api/entities, с моей конфигурацией Okta oauth, а не с моим "ApiConfig", который сейчас я просто делаю весь свой /api/** общедоступным

@Configuration
@Order(1)
public class OktaWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .antMatcher("/token/exchange")
                .authorizeRequests()
                .antMatchers("/token/exchange").authenticated()
                .and()
                .oauth2ResourceServer().jwt();
        http.cors();
        http.csrf().disable();
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        // https://github.com/okta/okta-spring-boot/blob/master/oauth2/src/main/java/com/okta/spring/boot/oauth/Okta.java
        Okta.configureResourceServer401ResponseBody(http);
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers(HttpMethod.OPTIONS, "/**");
    }
}

а также

@Configuration
@Order(200)
public class ApiWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .antMatcher("/**")
                .authorizeRequests()
                .antMatchers("/public/**","/api/**").permitAll()
                .and()
                .authorizeRequests()
                .anyRequest()
                .authenticated();
        http.csrf().disable();
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        http.cors();
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers(HttpMethod.OPTIONS, "/**");
    }
}

любой запрос к /token/exchange должен иметь токен, предоставленный Okta. похоже, это работает так, как я ожидал. любой запрос к /api/** должен иметь мой собственный JWT. мой SPA отправляет настраиваемый JWT, но, пытаясь лучше понять ситуацию, я решил, что могу просто установить все /api вызовы на allowAll и доказать, что мой фильтр Okta не мешает.

при дополнительной отладке кажется, что BearerTokenAuthenticationFilter вызывается как вызовом /token/exchange, так и вызовом /api/entities. Оба раза он проверяет токен на провайдера Okta Oauth. Таким образом, он не работает с вызовом /api/entities, который имеет мой собственный токен .... НЕ токен okta

Я так запутался


person Jason    schedule 05.06.2020    source источник
comment
1 ясность, зачем у вас токен / биржа на вашем сервере? Когда происходит обмен токенами с сервера аутентификации с помощью SPA с использованием самой okta? токен, который вы получаете от okta, будет иметь области действия, которые вы можете использовать для предотвращения доступа к вашим API.   -  person silentsudo    schedule 05.06.2020
comment
@silentsudo Я обновил вопрос .... достаточно ли подробностей   -  person Jason    schedule 05.06.2020
comment
у жетона окта есть области действия ... да. API основан на утверждениях, а не на объемах, и я никогда не смогу получить токены okta, чтобы иметь необходимую информацию в заявках или объемах.   -  person Jason    schedule 05.06.2020


Ответы (1)


Не уверен, что правильно понимаю, поэтому пытаюсь резюмировать. Ты хочешь

  • получить токен из Okta с помощью вашего SPA
  • обменять этот токен на специальный токен, сгенерированный вашим API
  • Используйте последний для связи с API.

Использование 2 WebSecurityConfigurerAdapter реализаций - это один из способов решения этой проблемы, и я думаю, что это хороший вариант. Вам понадобится 1 WebSecurityConfigurerAdapter, который делегирует Okta и проверяет, можно ли доверять токену на конечной точке обмена. После проверки вы можете сгенерировать и вернуть токен пользователю.

Другой WebSecurityConfigurerAdapter будет простым, и вы можете найти множество ресурсов по нему в Интернете, но в основном для каждой защищенной конечной точки вам необходимо проверить токен.

Я запутался в деталях фильтра безопасности. Должен ли я отменить один?

Вы можете расширить OncePerRequestFilter, поскольку название подразумевает, что он будет вызываться не более одного раза для каждого запроса. Это позволит убедиться, что запрос содержит заголовок и он действителен, сопоставляет его с Authentication и помещает в SecurityContextHolder

Куда его вставить?

Вы можете вставить его до / после UsernamePasswordAuthenticationFilter, но вам, вероятно, следует прочитать , как архитектура Spring Security похоже,, чтобы получить хорошую идею.

person Krisz    schedule 05.06.2020
comment
Другой WebSecurityConfigurerAdapter был бы простым, и вы можете найти множество ресурсов о нем в Интернете, но в основном для каждой защищенной конечной точки вам необходимо проверить токен. - ›да, есть СЛИШКОМ много примеров, когда все делают по-разному ..... это моя проблема. Думаю, я понимаю, что я МОГУ делать .... Я не понимаю, почему мне следует использовать одну стратегию вместо другой. - person Jason; 05.06.2020
comment
Есть много разных способов решить эти проблемы с помощью Spring Security, просто придерживайтесь одного. В основном вам придется настроить его для использования вашего фильтра на указанных маршрутах. - person Krisz; 05.06.2020
comment
@Krisz, если мы просто реализуем сервер ресурсов с jwk-set-uri и issuer-uri, это решит задачу, если мы не будем рассматривать само приложение как oauth2client, в этом случае также токен будет сгенерирован okta, поправьте меня, если я ошибаюсь. - person silentsudo; 05.06.2020
comment
не уверен, что понимаю. Хотели бы вы реализовать свой собственный сервер авторизации, который выдает токены JWT? - person Krisz; 06.06.2020