2017-02-11 2 views
1

Я рад, что вы здесь читаете мой вопрос :)Spring Security - двойная аутентификация: X.509 для терминала, Логин форма для пользователя

Я занимаюсь разработкой веб-приложения, в весенне-ботинке за продажи магазин. Я создал систему входа в систему, которая использует formLogin() для авторизации пользователей (она работает как шарм), но я столкнулся с проблемой, когда обращается к обнаружению, в котором компьютер зарегистрирован пользователем. В качестве других фактов только определенные компьютеры должны иметь доступ к сайту и только одному пользователю. Кроме того, у меня есть (пользователь и терминал), реализованный в базе данных, связанной с JPA-данными Spring, и терминал имеет внешний ключ для пользователя (ноль, когда к нему никто не подключен).

После 3-дневного поиска в Google я пришел к выводу, что лучший способ реализовать это - установить сертификаты X.509 на каждом компьютере для взаимной аутентификации и использовать привилегию loginForm для пользователей. (У терминалов нет разрешений, но такая конфигурация, как «это должно работать с этим кассовым аппаратом» или «это должно использовать принтер квитанций»).

Таким образом, код-часть ... Это моя текущая конфигурация Spring Security:

@Configuration 
@EnableWebSecurity 
public class SecurityConfiguration extends WebSecurityConfigurerAdapter { 

    @Autowired 
    UserDetailsService userDetailsService; 

    @Autowired 
    DataSource dataSource; 

    @Autowired 
    public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception { 
     auth.userDetailsService(userDetailsService); 
     auth.authenticationProvider(authenticationProvider()); 
    } 

    @Override 
    protected void configure(HttpSecurity http) throws Exception { 
     http 
      .authorizeRequests() 
       .antMatchers("/", "/index", "/static/**", "/login", "/catalogo/**").permitAll() 
       .anyRequest().authenticated() 
       .and() 
      .formLogin() 
       .loginPage("/login") 
       .loginProcessingUrl("/login") 
       .usernameParameter("username") 
       .passwordParameter("password") 
       .and() 
      .logout() 
       .logoutRequestMatcher(new AntPathRequestMatcher("/logout")) 
       .invalidateHttpSession(true) 
       .clearAuthentication(true) 
       .and() 
      .rememberMe() 
       .rememberMeParameter("remember-me") 
       .tokenRepository(persistentTokenRepository()) 
       .tokenValiditySeconds(86400).and() 
      .csrf() 
       .and() 
      .exceptionHandling().accessDeniedPage("/Access_Denied"); 
    } 

    @Bean 
    public PasswordEncoder passwordEncoder() { 
     return new BCryptPasswordEncoder(); 
    } 

    @Bean 
    public DaoAuthenticationProvider authenticationProvider() { 
     DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider(); 
     authenticationProvider.setUserDetailsService(userDetailsService); 
     authenticationProvider.setPasswordEncoder(passwordEncoder()); 
     return authenticationProvider; 
    } 

    @Bean 
    public AuthenticationTrustResolver getAuthenticationTrustResolver() { 
     return new AuthenticationTrustResolverImpl(); 
    } 

    @Bean 
    public PersistentTokenRepository persistentTokenRepository() { 
     JdbcTokenRepositoryImpl tokenRepositoryImpl = new JdbcTokenRepositoryImpl(); 
     tokenRepositoryImpl.setDataSource(dataSource); 
     return tokenRepositoryImpl; 
    } 
} 

И это мой UserDetailService:

@Service("customUserDetailsService") 
public class CustomUserDetailsService implements UserDetailsService { 
    private static final Logger logger = LoggerFactory.getLogger(CustomUserDetailsService.class); 

    // This is my user model service in Spring-data JPA, I have one too for terminals 
    @Autowired 
    private SecurityUserService securityUserService; 

    @Transactional(readOnly=true) 
    public UserDetails loadUserByUsername(String username) 
      throws UsernameNotFoundException { 
     SecurityUser user = securityUserService.findByUsername(username); 
     logger.info("User : {}", user); 
     if(user==null){ 
      logger.info("User not found"); 
      throw new UsernameNotFoundException("Username not found"); 
     } 
     return new org.springframework.security.core.userdetails.User(
       user.getUsername(), user.getPassword(), true, true, true, 
       true, getGrantedAuthorities(getPermissions(user))); 
    } 

    private List<GrantedAuthority> getGrantedAuthorities(List<String> permisos) { 
     List<GrantedAuthority> authorities = new ArrayList<>(); 
     for (String permiso : permisos) { 
      authorities.add(new SimpleGrantedAuthority(permiso)); 
     } 
     return authorities; 
    } 

    private List<String> getPermissions(SecurityUser user) { 
     List<String> privileges = new ArrayList<>(); 
     List<SecurityPermission> collection = new ArrayList<>(); 

     for (SecurityRole role : user.getRoles()) { 
      collection.addAll(role.getPermissions()); 
     } 

     collection.addAll(user.getPermissions()); 

     for (SecurityPermission item : collection) { 
      privileges.add(item.getName()); 
     } 
     return privileges; 
    } 
} 

В основном теперь я должен добавить X .509 аутентификация сертификата. Я сделал это без формы входа и работал хорошо, но я не знаю, как обращаться с ними вместе.

Благодарим за помощь.

PS: если вы думаете, что у вас есть еще одно возможное решение этой проблемы, не бойтесь оставлять его

ответ

0

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

Настройте канал TLS, требующий, чтобы клиент представил сертификат. Браузер предложит пользователю выбрать один из хранилища ключей. Сервер проверит его, и, если он будет принят, будет закреплен безопасный канал.

Конфигурация специфична для каждого сервера, поэтому ищите документацию.

Вам нужно будет установить клиентские сертификаты на каждом компьютере, и если вы используете selfsigned сертификат, установить также открытую часть в хранилище доверенных, чтобы избежать предупреждений браузера

Можно было бы использовать X509Certificate на стороне клиента, чтобы идентифицировать пользователей и избежать формы входа в систему. Для этого требуется выдать сертификат для каждого пользователя и установить его на компьютере/с, который пользователь будет использовать. Если вы используете общие компьютеры, сертификаты должны быть защищены паролем. вероятно, не является хорошей альтернативой вам

Смежные вопросы