Spring Boot, Rest, Security. implemetacja

0

Witam

Nigdy nie zabezpieczałem żadnej aplikacji za pomocą spring security, a zdecydowałem się na napisanie takiej na potrzebny projektu uczelnianego, poniżej przedstawie moje założenia, proszę o ich zweryfikowanie:

  • Java wystawia REST API za pomoca Springa, zostanie ono zabezpieczone Spring Security, za pomocą BASIC AUTH . Konsumentem będzie Angular JS (nie pisany przeze mnie, lecz przez kolegę który się go uczy). Jak na razie do wyslania żądania jest potrzebny token CSRF, oraz BasicAuth(2?), jest on wysyłany za każdym zapytaniem do REST.

Teraz moje pytania:
Jak powinno wyglądać połączenie tych dwóch światów (Angular i Java) za pomocą resta?
Czy potrzebny jest tutaj CSRF Token?
Czy wystarczy samo auth?
Albo może lepiej, proszę o podpowiedź jak wykonać zabezpieczenie apki, bo jak widać po poniższym kodzie, trochę się zagmatwałem w implementacji.

  • Konfiguracja security:
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    @Qualifier("customUserDetailsService")
    UserDetailsService userDetailsService;
    @Value("${auth.realm}")
    private String REALM;

    @Autowired
    public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser("user").password("user").roles("USER");
        auth.inMemoryAuthentication().withUser("admin").password("admin").roles("ADMIN");
        auth.userDetailsService(userDetailsService);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
                .and().authorizeRequests()
                .antMatchers("/").permitAll()
                .antMatchers("/api/**").hasRole("ADMIN")
                .and().httpBasic().realmName(REALM).authenticationEntryPoint(getBasicAuthEntryPoint())
                .and().logout().logoutSuccessUrl("/")
                .and().addFilterAfter(new CsrfTokenResponseHeaderBindingFilter(), CsrfFilter.class);
    }

    @Bean
    public AuthEntryPoint getBasicAuthEntryPoint() {
        return new AuthEntryPoint();
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers(HttpMethod.OPTIONS, "/**");
    }
  • UserDetails :
@Service("customUserDetailsService")
public class CustomUserDetailsService implements UserDetailsService {

    @Autowired
    private UserService userService;

    @Transactional(readOnly = true)
    public UserDetails loadUserByUsername(String ssoId) throws UsernameNotFoundException {
        User user = userService.findByLogin(ssoId);
        if (user == null) {
            throw new UsernameNotFoundException("Username not found");
        }
        return new org.springframework.security.core.userdetails.User(user.getLogin(), user.getPassword(),
                true, true, true, true, getGrantedAuthorities(user));
    }

    private List<GrantedAuthority> getGrantedAuthorities(User user) {
        List<GrantedAuthority> authorities = new ArrayList<>();

        for (Role role : user.getRole()) {
            authorities.add(new SimpleGrantedAuthority("ROLE_" + role.name()));
        }
        System.out.print("authorities :" + authorities);
        return authorities;
    }


-CSRF :
```java
public class CsrfTokenResponseHeaderBindingFilter extends OncePerRequestFilter {
    protected static final String REQUEST_ATTRIBUTE_NAME = "_csrf";
    protected static final String RESPONSE_HEADER_NAME = "X-CSRF-HEADER";
    protected static final String RESPONSE_PARAM_NAME = "X-CSRF-PARAM";
    protected static final String RESPONSE_TOKEN_NAME = "X-CSRF-TOKEN";

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, javax.servlet.FilterChain filterChain) throws ServletException, IOException {
        CsrfToken token = (CsrfToken) request.getAttribute(REQUEST_ATTRIBUTE_NAME);

        if (token != null) {
            response.setHeader(RESPONSE_HEADER_NAME, token.getHeaderName());
            response.setHeader(RESPONSE_PARAM_NAME, token.getParameterName());
            response.setHeader(RESPONSE_TOKEN_NAME, token.getToken());
        }

        filterChain.doFilter(request, response);
    }
}
  • oraz auth entry point
public class AuthEntryPoint extends BasicAuthenticationEntryPoint {

    @Value("${auth.realm}")
    private String REALM;

    @Override
    public void commence(final HttpServletRequest request,
                         final HttpServletResponse response,
                         final AuthenticationException authException) throws IOException, ServletException {
        //Authentication failed, send error response.
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        response.addHeader("WWW-Authenticate", "Basic realm=" + getRealmName() + "");

        PrintWriter writer = response.getWriter();
        writer.println("HTTP Status 401 : " + authException.getMessage());
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        setRealmName(REALM);
        super.afterPropertiesSet();
    }
}
0

up

0

Jak ja coś takiego robiłem to napisałem filtr do Spring Security który akceptował zapytania z tokenem, sprawdzał token i słał dalej "wewnętrznie" już zapytania z userem dla Security.

1 użytkowników online, w tym zalogowanych: 0, gości: 1