Подтвердить что ты не робот

Интеграция Spring Безопасность OAuth2 и Spring Социальные

Я работаю с приложением Spring Boot + Spring Security OAuth2, которое, на мой взгляд, вдохновлено примерами из Dave Syer. Приложение настроено как сервер авторизации OAuth2, с одним открытым клиентом, использующим поток учетных данных пароля владельца ресурса. Успешный токен настроен как JWT.

Открытый Angular клиент отправляет POST-запрос в /oauth/token с базовым заголовком auth, содержащим идентификатор клиента и секретный код (это был самый простой способ проверить подлинность клиента, даже если секрет не является конфиденциальным), Тело запроса содержит имя пользователя, пароль и тип гранта "пароль".

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

Я пытаюсь добавить дополнительный поток аутентификации SSO, используя Spring Social. У меня есть Spring Social, настроенный для аутентификации через внешних поставщиков через /auth/ [provider]; однако в следующих запросах уже не установлен корректный набор SecurityContext. Возможно, Spring Security OAuth сервер или клиент переопределяют SecurityContext?

Если я могу правильно установить SecurityContext после Spring Social потока, у меня есть новый TokenGranter, который разрешает новый тип гранта "social", который будет проверять SecurityContextHolder для пользователя, прошедшего предварительную проверку.

Мне интересно как решение моей конкретной проблемы с SecurityContext (я считаю, что это проблема с Spring OAuth + Социальная интеграция), либо другой подход для аутентификации с внешними поставщиками и получения действительного JWT из нашего собственный сервер auth.

Спасибо!

4b9b3361

Ответ 1

У меня была аналогичная проблема в JHipster -генерированном веб-приложении. Наконец, я решил пойти с опцией SocialAuthenticationFilter из Spring Social (через SpringSocialConfigurer). После успешного социального входа сервер автоматически генерирует и возвращает "собственный" токен доступа через перенаправление к клиентскому приложению.

Здесь моя попытка:

@Configuration
@EnableResourceServer
protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter implements EnvironmentAware {

    //...

    @Inject
    private AuthorizationServerTokenServices authTokenServices;

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

        SpringSocialConfigurer socialCfg = new SpringSocialConfigurer();
        socialCfg
            .addObjectPostProcessor(new ObjectPostProcessor<SocialAuthenticationFilter>() {
                @SuppressWarnings("unchecked")
                public SocialAuthenticationFilter postProcess(SocialAuthenticationFilter filter){
                    filter.setAuthenticationSuccessHandler(
                            new SocialAuthenticationSuccessHandler(
                                    authTokenServices,
                                    YOUR_APP_CLIENT_ID
                            )
                        );
                    return filter;
                }
            });

        http
            //... lots of other configuration ...
            .apply(socialCfg);
    }        
}

И класс SocialAuthenticationSuccessHandler:

public class SocialAuthenticationSuccessHandler implements AuthenticationSuccessHandler {

    public static final String REDIRECT_PATH_BASE = "/#/login";
    public static final String FIELD_TOKEN = "access_token";
    public static final String FIELD_EXPIRATION_SECS = "expires_in";

    private final Logger log = LoggerFactory.getLogger(getClass());
    private final AuthorizationServerTokenServices authTokenServices;
    private final String localClientId;

    public SocialAuthenticationSuccessHandler(AuthorizationServerTokenServices authTokenServices, String localClientId){
        this.authTokenServices = authTokenServices;
        this.localClientId = localClientId;
    }

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request,
            HttpServletResponse response, Authentication authentication)
                    throws IOException, ServletException {
        log.debug("Social user authenticated: " + authentication.getPrincipal() + ", generating and sending local auth");
        OAuth2AccessToken oauth2Token = authTokenServices.createAccessToken(convertAuthentication(authentication)); //Automatically checks validity
        String redirectUrl = new StringBuilder(REDIRECT_PATH_BASE)
            .append("?").append(FIELD_TOKEN).append("=")
            .append(encode(oauth2Token.getValue()))
            .append("&").append(FIELD_EXPIRATION_SECS).append("=")
            .append(oauth2Token.getExpiresIn())
            .toString();
        log.debug("Sending redirection to " + redirectUrl);
        response.sendRedirect(redirectUrl);
    }

    private OAuth2Authentication convertAuthentication(Authentication authentication) {
        OAuth2Request request = new OAuth2Request(null, localClientId, null, true, null,
                null, null, null, null);
        return new OAuth2Authentication(request,
                //Other option: new UsernamePasswordAuthenticationToken(authentication.getPrincipal(), "N/A", authorities)
                new PreAuthenticatedAuthenticationToken(authentication.getPrincipal(), "N/A")
                );
    }

    private String encode(String in){
        String res = in;
        try {
            res = UriUtils.encode(in, GeneralConstants.ENCODING_UTF8);
        } catch(UnsupportedEncodingException e){
            log.error("ERROR: unsupported encoding: " + GeneralConstants.ENCODING_UTF8, e);
        }
        return res;
    }
}

Таким образом, ваше клиентское приложение получит маркер доступа к веб-приложению через перенаправление до /#/login?access_token=my_access_token&expires_in=seconds_to_expiration, если вы установите соответствующий REDIRECT_PATH_BASE в SocialAuthenticationSuccessHandler.

Надеюсь, это поможет.

Ответ 2

Во-первых, я настоятельно рекомендую вам отказаться от предоставления пароля для такого прецедента.
Публичные клиенты (JavaScript, установленные приложения) не могут хранить конфиденциальность своего клиента, поэтому они НЕ ДОЛЖНЫ быть назначены: любой посетитель, проверяющий ваш код JavaScript, может обнаружить секрет и, таким образом, реализовать ту же страницу аутентификации, которую вы используете, сохраняя ваши пароли пользователей в процесс.

Неявный грант был создан именно для того, что вы делаете.
Использование потока, основанного на перенаправлении, имеет то преимущество, что механизм проверки подлинности до сервера авторизации вместо того, чтобы каждое из ваших приложений имеет его часть: это в основном определение Single Sign On (SSO).

С учетом сказанного ваш вопрос тесно связан с этим, на который я только что ответил: Собственный сервер Spring OAuth2 вместе с поставщиками OAuth 3rdparty

Подводя итог ответу:

В конце концов, это о том, как ваш сервер авторизации защищает AuthorizationEndpoint:/oauth/authorize. Поскольку ваш сервер авторизации работает, у вас уже есть класс конфигурации, расширяющий WebSecurityConfigurerAdapter, который обрабатывает безопасность для /oauth/authorize с помощью formLogin. Это то, где вам нужно интегрировать социальные вещи.

Вы просто не можете использовать предоставление пароля для достижения того, чего вы пытаетесь достичь, вы должны перенаправить ваш публичный клиент на сервер авторизации. Затем сервер авторизации перенаправляет на социальный логин в качестве механизма безопасности для конечной точки /oauth/authorize.

Ответ 3

Я реализовал spring oauth2 для защиты моих служб отдыха и, кроме того, добавил социальный логин и неявный регистрационный учет для первого входа в систему. для пользователя пользователя вы можете генерировать токен, используя только имя пользователя и пароль, чтобы генерировать токен для социального пользователя. для этого вам необходимо реализовать фильтр, который будет перехватывать ваш запрос /oauth/token перед обработкой. здесь, если вы хотите сгенерировать токен для социального пользователя, пропустите имя пользователя и токен facebook, здесь вы можете использовать токен facebook как пароль и генерировать токен для пользователя facebook. если токен facebook обновлен, вам также нужно написать триггер db, чтобы обновить токен в пользовательской таблице.... возможно, это поможет вам