package com.captechconsulting.config; import com.captechconsulting.facade.Versions; import com.captechconsulting.security.HeaderAuthenticationFilter; import com.captechconsulting.security.HeaderUtil; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.userdetails.User; import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.security.web.access.AccessDeniedHandler; import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler; import org.springframework.security.web.authentication.logout.LogoutFilter; import javax.servlet.Filter; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; import java.security.GeneralSecurityException; @Configuration @EnableWebMvcSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { private static final String ACCESS_DENIED_JSON = "{\"message\":\"You are not privileged to request this resource.\", \"access-denied\":true,\"cause\":\"AUTHORIZATION_FAILURE\"}"; private static final String UNAUTHORIZED_JSON = "{\"message\":\"Full authentication is required to access this resource.\", \"access-denied\":true,\"cause\":\"NOT AUTHENTICATED\"}"; @Autowired private HeaderUtil headerUtil; @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication(). withUser("user").password("password").roles("USER"). and(). withUser("admin").password("password").roles("USER", "ADMIN"); } @Override protected void configure(HttpSecurity http) throws Exception { CustomAuthenticationSuccessHandler successHandler = new CustomAuthenticationSuccessHandler(); successHandler.headerUtil(headerUtil); http. addFilterBefore(authenticationFilter(), LogoutFilter.class). csrf().disable(). formLogin().successHandler(successHandler). loginProcessingUrl("/login"). and(). logout(). logoutSuccessUrl("/logout"). and(). sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS). and(). exceptionHandling(). accessDeniedHandler(new CustomAccessDeniedHandler()). authenticationEntryPoint(new CustomAuthenticationEntryPoint()). and(). authorizeRequests(). antMatchers(HttpMethod.POST, "/login").permitAll(). antMatchers(HttpMethod.POST, "/logout").authenticated(). antMatchers(HttpMethod.GET, "/**").hasRole("USER"). antMatchers(HttpMethod.POST, "/**").hasRole("ADMIN"). antMatchers(HttpMethod.DELETE, "/**").hasRole("ADMIN"). anyRequest().authenticated(); } private Filter authenticationFilter() { HeaderAuthenticationFilter headerAuthenticationFilter = new HeaderAuthenticationFilter(); headerAuthenticationFilter.userDetailsService(userDetailsService()); headerAuthenticationFilter.headerUtil(headerUtil); return headerAuthenticationFilter; } private static class CustomAccessDeniedHandler implements AccessDeniedHandler { @Override public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException { response.setContentType(Versions.V1_0); response.setStatus(HttpServletResponse.SC_FORBIDDEN); PrintWriter out = response.getWriter(); out.print(ACCESS_DENIED_JSON); out.flush(); out.close(); } } private static class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint { @Override public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { response.setContentType(Versions.V1_0); response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); PrintWriter out = response.getWriter(); out.print(UNAUTHORIZED_JSON); out.flush(); out.close(); } } private static class CustomAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler { private HeaderUtil headerUtil; @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws ServletException, IOException { try { String token = headerUtil.createAuthToken(((User) authentication.getPrincipal()).getUsername()); ObjectMapper mapper = new ObjectMapper(); ObjectNode node = mapper.createObjectNode().put("token", token); PrintWriter out = response.getWriter(); out.print(node.toString()); out.flush(); out.close(); } catch (GeneralSecurityException e) { throw new ServletException("Unable to create the auth token", e); } clearAuthenticationAttributes(request); } private void headerUtil(HeaderUtil headerUtil) { this.headerUtil = headerUtil; } } }