Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- @Configuration
- @EnableWebSecurity
- public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
- public static final String JWT_TOKEN_HEADER_PARAM = "X-Authorization";
- public static final String FORM_BASED_LOGIN_ENTRY_POINT = "/api/auth/login";
- public static final String TOKEN_BASED_AUTH_ENTRY_POINT = "/api/**";
- public static final String TOKEN_REFRESH_ENTRY_POINT = "/api/auth/token";
- @Autowired private RestAuthenticationEntryPoint authenticationEntryPoint;
- @Autowired private AuthenticationSuccessHandler successHandler;
- @Autowired private AuthenticationFailureHandler failureHandler;
- @Autowired private AjaxAuthenticationProvider ajaxAuthenticationProvider;
- @Autowired private JwtAuthenticationProvider jwtAuthenticationProvider;
- @Autowired private TokenExtractor tokenExtractor;
- @Autowired private AuthenticationManager authenticationManager;
- @Autowired private ObjectMapper objectMapper;
- protected AjaxLoginProcessingFilter buildAjaxLoginProcessingFilter() throws Exception {
- AjaxLoginProcessingFilter filter = new AjaxLoginProcessingFilter(FORM_BASED_LOGIN_ENTRY_POINT, successHandler, failureHandler, objectMapper);
- filter.setAuthenticationManager(this.authenticationManager);
- return filter;
- }
- protected JwtTokenAuthenticationProcessingFilter buildJwtTokenAuthenticationProcessingFilter() throws Exception {
- List<String> pathsToSkip = Arrays.asList(TOKEN_REFRESH_ENTRY_POINT, FORM_BASED_LOGIN_ENTRY_POINT);
- SkipPathRequestMatcher matcher = new SkipPathRequestMatcher(pathsToSkip, TOKEN_BASED_AUTH_ENTRY_POINT);
- JwtTokenAuthenticationProcessingFilter filter
- = new JwtTokenAuthenticationProcessingFilter(failureHandler, tokenExtractor, matcher);
- filter.setAuthenticationManager(this.authenticationManager);
- return filter;
- }
- @Bean
- @Override
- public AuthenticationManager authenticationManagerBean() throws Exception {
- return super.authenticationManagerBean();
- }
- @Override
- protected void configure(AuthenticationManagerBuilder auth) {
- auth.authenticationProvider(ajaxAuthenticationProvider);
- auth.authenticationProvider(jwtAuthenticationProvider);
- }
- @Bean
- protected BCryptPasswordEncoder passwordEncoder() {
- return new BCryptPasswordEncoder();
- }
- @Override
- protected void configure(HttpSecurity http) throws Exception {
- http
- .csrf().disable() // We don't need CSRF for JWT based authentication
- .exceptionHandling()
- .authenticationEntryPoint(this.authenticationEntryPoint)
- .and()
- .sessionManagement()
- .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
- .and()
- .authorizeRequests()
- .antMatchers(FORM_BASED_LOGIN_ENTRY_POINT).permitAll() // Login end-point
- .antMatchers(TOKEN_REFRESH_ENTRY_POINT).permitAll() // Token refresh end-point
- .antMatchers("/console").permitAll() // H2 Console Dash-board - only for testing
- .and()
- .authorizeRequests()
- .antMatchers(TOKEN_BASED_AUTH_ENTRY_POINT).authenticated() // Protected API End-points
- .and()
- .addFilterBefore(buildAjaxLoginProcessingFilter(), UsernamePasswordAuthenticationFilter.class)
- .addFilterBefore(buildJwtTokenAuthenticationProcessingFilter(), UsernamePasswordAuthenticationFilter.class);
- }
- }
- public class SkipPathRequestMatcher implements RequestMatcher {
- private OrRequestMatcher matchers;
- private RequestMatcher processingMatcher;
- public SkipPathRequestMatcher(List<String> pathsToSkip, String processingPath) {
- Assert.notNull(pathsToSkip);
- List<RequestMatcher> m = pathsToSkip.stream().map(path -> new AntPathRequestMatcher(path)).collect(Collectors.toList());
- matchers = new OrRequestMatcher(m);
- processingMatcher = new AntPathRequestMatcher(processingPath);
- }
- @Override
- public boolean matches(HttpServletRequest request) {
- if (matchers.matches(request)) {
- return false;
- }
- return processingMatcher.matches(request) ? true : false;
- }
- }
- @Component
- public class JwtAuthenticationProvider implements AuthenticationProvider {
- private final JwtSettings jwtSettings;
- @Autowired
- public JwtAuthenticationProvider(JwtSettings jwtSettings) {
- this.jwtSettings = jwtSettings;
- }
- @Override
- public Authentication authenticate(Authentication authentication) throws AuthenticationException {
- RawAccessJwtToken rawAccessToken = (RawAccessJwtToken) authentication.getCredentials();
- Jws<Claims> jwsClaims = rawAccessToken.parseClaims(jwtSettings.getTokenSigningKey());
- String subject = jwsClaims.getBody().getSubject();
- List<String> scopes = jwsClaims.getBody().get("scopes", List.class);
- List<GrantedAuthority> authorities = scopes.stream()
- .map(authority -> new SimpleGrantedAuthority(authority))
- .collect(Collectors.toList());
- UserContext context = UserContext.create(subject, authorities);
- return new JwtAuthenticationToken(context, context.getAuthorities());
- }
- @Override
- public boolean supports(Class<?> authentication) {
- return (JwtAuthenticationToken.class.isAssignableFrom(authentication));
- }
- }
- @Component
- public class JwtHeaderTokenExtractor implements TokenExtractor {
- public static String HEADER_PREFIX = "Bearer ";
- @Override
- public String extract(String header) {
- if (StringUtils.isBlank(header)) {
- throw new AuthenticationServiceException("Authorization header cannot be blank!");
- }
- if (header.length() < HEADER_PREFIX.length()) {
- throw new AuthenticationServiceException("Invalid authorization header size.");
- }
- return header.substring(HEADER_PREFIX.length(), header.length());
- }
- }
- public class JwtTokenAuthenticationProcessingFilter extends AbstractAuthenticationProcessingFilter {
- private final AuthenticationFailureHandler failureHandler;
- private final TokenExtractor tokenExtractor;
- @Autowired
- public JwtTokenAuthenticationProcessingFilter(AuthenticationFailureHandler failureHandler,
- TokenExtractor tokenExtractor, RequestMatcher matcher) {
- super(matcher);
- this.failureHandler = failureHandler;
- this.tokenExtractor = tokenExtractor;
- }
- @Override
- public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
- throws AuthenticationException, IOException, ServletException {
- String tokenPayload = request.getHeader(WebSecurityConfig.JWT_TOKEN_HEADER_PARAM);
- RawAccessJwtToken token = new RawAccessJwtToken(tokenExtractor.extract(tokenPayload));
- return getAuthenticationManager().authenticate(new JwtAuthenticationToken(token));
- }
- @Override
- protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
- Authentication authResult) throws IOException, ServletException {
- SecurityContext context = SecurityContextHolder.createEmptyContext();
- context.setAuthentication(authResult);
- SecurityContextHolder.setContext(context);
- chain.doFilter(request, response);
- }
- @Override
- protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
- AuthenticationException failed) throws IOException, ServletException {
- SecurityContextHolder.clearContext();
- failureHandler.onAuthenticationFailure(request, response, failed);
- }
- }
- public class AjaxLoginProcessingFilter extends AbstractAuthenticationProcessingFilter {
- private static Logger logger = LoggerFactory.getLogger(AjaxLoginProcessingFilter.class);
- private final AuthenticationSuccessHandler successHandler;
- private final AuthenticationFailureHandler failureHandler;
- private final ObjectMapper objectMapper;
- public AjaxLoginProcessingFilter(String defaultProcessUrl, AuthenticationSuccessHandler successHandler,
- AuthenticationFailureHandler failureHandler, ObjectMapper mapper) {
- super(defaultProcessUrl);
- this.successHandler = successHandler;
- this.failureHandler = failureHandler;
- this.objectMapper = mapper;
- }
- @Override
- public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
- throws AuthenticationException, IOException, ServletException {
- if (!HttpMethod.POST.name().equals(request.getMethod()) || !WebUtil.isAjax(request)) {
- if(logger.isDebugEnabled()) {
- logger.debug("Authentication method not supported. Request method: " + request.getMethod());
- }
- throw new AuthMethodNotSupportedException("Authentication method not supported");
- }
- LoginRequest loginRequest = objectMapper.readValue(request.getReader(), LoginRequest.class);
- if (StringUtils.isBlank(loginRequest.getUsername()) || StringUtils.isBlank(loginRequest.getPassword())) {
- throw new AuthenticationServiceException("Username or Password not provided");
- }
- UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword());
- return this.getAuthenticationManager().authenticate(token);
- }
- @Override
- protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
- Authentication authResult) throws IOException, ServletException {
- successHandler.onAuthenticationSuccess(request, response, authResult);
- }
- @Override
- protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
- AuthenticationException failed) throws IOException, ServletException {
- SecurityContextHolder.clearContext();
- failureHandler.onAuthenticationFailure(request, response, failed);
- }
- }
- @Component
- public class AjaxAuthenticationProvider implements AuthenticationProvider {
- private final BCryptPasswordEncoder encoder;
- private final DatabaseUserService userService;
- @Autowired
- public AjaxAuthenticationProvider(final DatabaseUserService userService, final BCryptPasswordEncoder encoder) {
- this.userService = userService;
- this.encoder = encoder;
- }
- @Override
- public Authentication authenticate(Authentication authentication) throws AuthenticationException {
- Assert.notNull(authentication, "No authentication data provided");
- String username = (String) authentication.getPrincipal();
- String password = (String) authentication.getCredentials();
- User user = userService.getByUsername(username).orElseThrow(() -> new UsernameNotFoundException("User not found: " + username));
- if (!encoder.matches(password, user.getPassword())) {
- throw new BadCredentialsException("Authentication Failed. Username or Password not valid.");
- }
- if (user.getRoles() == null) throw new InsufficientAuthenticationException("User has no roles assigned");
- List<GrantedAuthority> authorities = user.getRoles().stream()
- .map(authority -> new SimpleGrantedAuthority(authority.getRole().authority()))
- .collect(Collectors.toList());
- UserContext userContext = UserContext.create(user.getUsername(), authorities);
- return new UsernamePasswordAuthenticationToken(userContext, null, userContext.getAuthorities());
- }
- @Override
- public boolean supports(Class<?> authentication) {
- return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
- }
- }
Add Comment
Please, Sign In to add comment