Мой пример использования таков: в многопользовательском приложении каждый арендатор может настроить свой собственный механизм аутентификации SSP IDP. Они также могут настроить, следует ли автоматически создавать новых пользователей в локальном приложении при аутентификации нового пользователя.
Я использую Spring Security и у меня работают несколько поставщиков Oauth2.
Когда у меня аутентифицируется новый пользователь на арендаторе, который не позволяет автоматически создавать новых пользователей, как мне переопределить аутентификацию, чтобы Spring Security воспринимал вход этого пользователя как неудачный и, следовательно, продолжал защищать доступ к все ресурсы в приложении?
И также, где я должен добавить код для создания нового пользователя, если разрешено автоматическое создание?
ОБНОВЛЕНИЕ:
Кажется, Основы таковы - для Spring Security 5 вам необходимо реализовать свой собственный OAuth2UserService, либо (или оба) из того, который принимает OAuth2UserRequest и возвращает OAuth2User или тот, который принимает OidcUserRequest и возвращает OidcUser.
Они могут быть настроены следующим образом:
protected void configure(HttpSecurity http) throws Exception
{
http...
.userInfoEndpoint()
.userService(securityUserService)
.oidcUserService(commonOAuth2UserService)
...;
}
, где securityUserService является @Component, реализующим OAuth2UserService, а commonOAuth2UserService является @Component, реализующим OAuth2UserService. Обратите внимание, что вам может понадобиться только один из них - я использую оба, потому что у меня несколько разных типов ВПЛ.
Однако это еще не полный ответ, потому что я все еще борюсь с одной вещью: мне нужно получить надежное значение из idToken, которое говорит мне, какого пользователя мне нужно искать. Я ожидал, что смогу передать это состояние как исходный запрос (путем реализации моего собственного OAuth2AuthorizationRequestResolver), но я обнаружил, что установленное там состояние не отображается в idToken ни для Okta, ни для Azure AD.
Кто-нибудь знает, почему значение состояния не выделяет его с другой стороны?
Кажется, что обходным решением может быть использование полученного мной адреса электронной почты, но каждый ВПЛ предоставляет это по-другому, и все они предостерегают от использования этих атрибутов для чего-то критического, так что это выглядит как очень простое решение, которое может работать сейчас, но не позже.
Предупреждение для тех, кто может следовать это: не отвлекайтесь на обильные ссылки на использование PrincipalExtractor и AuthoritiesExtractor, которые вы можете найти в Googling - эта старая технология больше не поддерживается в последней версии Spring Security.
Реализация OAuth2UserService:
@Component
public class CommonOAuth2UserService
implements OAuth2UserService<OidcUserRequest, OidcUser>
{
final OidcUserService delegate = new OidcUserService();
@Override
public OidcUser loadUser(OidcUserRequest userRequest)
throws OAuth2AuthenticationException
{
// Delegate to the default implementation for loading a user
OidcUser oidcUser = delegate.loadUser(userRequest);
Set<GrantedAuthority> mappedAuthorities = new HashSet<>();
mappedAuthorities.add(new SecurityRole("ROLE_USER"));
oidcUser = new DefaultOidcUser(mappedAuthorities, oidcUser.getIdToken(), oidcUser.getUserInfo());
return oidcUser;
}
}
и запрос OAuth2AuthorizationRequestResolver:
public class CustomAuthorizationRequestResolver
implements OAuth2AuthorizationRequestResolver
{
private OAuth2AuthorizationRequestResolver defaultResolver;
public CustomAuthorizationRequestResolver(
ClientRegistrationRepository repo
)
{
defaultResolver = new DefaultOAuth2AuthorizationRequestResolver(repo, "/oauth2/authorization");
}
@Override
public OAuth2AuthorizationRequest resolve(HttpServletRequest httpServletRequest)
{
OAuth2AuthorizationRequest request = defaultResolver.resolve(httpServletRequest);
if (request == null) return null;
OAuth2AuthorizationRequest returnreq = OAuth2AuthorizationRequest.from(request)
.state(request.getState() + ";euamid=kdc123")
.build();
return returnreq;
}
@Override
public OAuth2AuthorizationRequest resolve(HttpServletRequest httpServletRequest, String s)
{
OAuth2AuthorizationRequest request = defaultResolver.resolve(httpServletRequest, s);
if (request == null) return null;
return OAuth2AuthorizationRequest.from(request)
.state(request.getState()+";euamid=kdc123")
.build();
}
}