Spring OAuth2 - Сервер авторизации - Разграничение пользователей на клиентах - PullRequest
0 голосов
/ 08 января 2019

Я застрял с моим заявлением. Звучит просто: у меня зарегистрировано два клиента на OAuth AuthorizationServer и два пользователя. Пользователь alpha может получить доступ к обоим приложениям ("androidapp" и "angularapp"), но пользователь beta может получить доступ только к одному из этих приложений (только "angularapp"). Как я могу дифференцировать пользователей и блокировать бета-версию для приложения "androidapp"?

Это код моего AuthServer:

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter{

    @Autowired private DataSource dataSource;
    @Autowired private AuthenticationManager authenticationManager;

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security
            .tokenKeyAccess("permitAll()")
            .checkTokenAccess("isAuthenticated()")
            ;
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory().withClient("angularapp")
        .secret(passwordEncoder.encode("12345"))
        .scopes("read", "write")
        .authorizedGrantTypes("password", "refresh_token")
        .accessTokenValiditySeconds(20000)
        .refreshTokenValiditySeconds(20000)
        .and()
        .withClient("androidapp")
        .secret(passwordEncoder.encode("67890"))
        .scopes("read", "write")
        .authorizedGrantTypes("password", "refresh_token")
        .accessTokenValiditySeconds(20000)
        .refreshTokenValiditySeconds(20000);
    }

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

        endpoints
            .authenticationManager(authenticationManager)
            .tokenStore(tokenStore())
            .accessTokenConverter(accessTokenConverter())
            ;

    }

    @Bean
    public JwtTokenStore tokenStore() {
        return new JwtTokenStore(accessTokenConverter());
    }

    @Bean
    public JwtAccessTokenConverter accessTokenConverter() {
        JwtAccessTokenConverter jwt = new JwtAccessTokenConverter();
        jwt.setSigningKey(JwtConfig.RSA_PRIVATE_KEY);
        jwt.setVerifierKey(JwtConfig.RSA_PUBLIC_KEY);
        return jwt;
    }

}

Заранее спасибо за ваши ответы.

Ответы [ 2 ]

0 голосов
/ 09 января 2019

В прошлом я решил создать подкласс ResourceOwnerPasswordTokenGranter и переопределить этот метод:

protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) {

Если вы копируете оригинальный метод из источников Spring, в определенный момент у вас есть доступ к client_id (client.getClientId()) и пользователю (userAuth.getPrincipal()).

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

Было бы замечательно, если бы у Spring Security был какой-то обратный вызов, чтобы избежать необходимости копировать части кода, чтобы сделать это. Я открыл https://github.com/spring-projects/spring-security-oauth/issues/791 для этого.

0 голосов
/ 09 января 2019

Мое решение здесь:

При выполнении метода loadClientByClientId объект Principal хранится в SecurityContext еще не существует, но это происходит, когда loadUserByUsername метод выполнен с небольшим наблюдением: Principal объект в этой точке содержит client_id, а не username, что приводит к настройке объекта UserDetailsService вместо ClientsDetailsService. Затем с реляционной сущностью (JPA) Я присоединился к client_id с username, дающим ожидаемый результат.

Итак, код для UserDetailsService агрегатов:

@Service
public class UsuarioService implements IUsuarioService, UserDetailsService{

    private Logger logger = LoggerFactory.getLogger(UsuarioService.class);

    @Autowired
    private IUsuarioDao usuarioDao;

    @Override
    @Transactional(readOnly=true)
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        Usuario usuario = usuarioDao.findByUsername(username);
        if( usuario == null ) {
            logger.error("Login error: Username not found in storage");
            throw new UsernameNotFoundException("Login error: Username not found in storage");
        }
        List<GrantedAuthority> authorities = usuario.getRoles().stream().map( role -> new SimpleGrantedAuthority( role.getNombre() )).collect(Collectors.toList());

        Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        String applicationID = "";
        if (principal instanceof UserDetails) {
            applicationID = ((UserDetails)principal).getUsername();
        } else {
            applicationID = principal.toString();
        }
        logger.info("Application: {} ", applicationID);

        if( applicationID == null || applicationID.isEmpty() ) {
            logger.error("Application ID can't be empty");
            throw new InsufficientAuthenticationException("Application ID can't be empty");
        }

        OAuthClientDetails app = findApplicationByUsername( usuario.getClientes(), applicationID);
        if( app == null ) {
            logger.error("Unauthorized user for application {}", applicationID);
            throw new UnapprovedClientAuthenticationException("Unauthorized user for application " + applicationID);
        }

        return new User(username, usuario.getPassword(), usuario.getEnabled(), true, true, true, authorities);
    }

    private OAuthClientDetails findApplicationByUsername( final List<OAuthClientDetails> list, final String clientID ){
        return list.stream().filter( p -> p.getClientId().equals(clientID) ).findAny().orElse(null); } }

А конфигурация AuthorizationServer:

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter{

    @Autowired DataSource dataSource;
    @Autowired @Qualifier("authenticationManagerBean") private AuthenticationManager authenticationManager;

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security
            .tokenKeyAccess("permitAll()") 
            .checkTokenAccess("isAuthenticated()") 
            ;
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.jdbc(dataSource);
    }

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

        endpoints
            .authenticationManager(authenticationManager)
            .tokenStore(tokenStore())
            .accessTokenConverter(accessTokenConverter())
            ;

    }

    @Bean
    public JwtTokenStore tokenStore() {
        return new JwtTokenStore(accessTokenConverter());
    }

    @Bean
    public JwtAccessTokenConverter accessTokenConverter() {
        JwtAccessTokenConverter jwt = new JwtAccessTokenConverter();
        jwt.setSigningKey(JwtConfig.RSA_PRIVATE_KEY);
        jwt.setVerifierKey(JwtConfig.RSA_PUBLIC_KEY);
        return jwt;
    }

}

Очень благодарен за помощь и идеи.

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