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();
}
}