Code refactor.

This commit is contained in:
svlada 2016-08-17 15:38:35 +02:00
parent 717c3e35cc
commit b2c2098a09
19 changed files with 250 additions and 67 deletions

View File

@ -1,11 +1,11 @@
package com.svlada.profile.endpoint;
import org.apache.commons.lang3.NotImplementedException;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import com.svlada.security.auth.JwtAuthenticationToken;
import com.svlada.security.model.UserContext;
/**
@ -18,7 +18,7 @@ import com.svlada.security.model.UserContext;
@RestController
public class ProfileEndpoint {
@RequestMapping(value="/api/me", method=RequestMethod.GET)
public @ResponseBody UserContext get() {
throw new NotImplementedException("Not implemented");
public @ResponseBody UserContext get(JwtAuthenticationToken token) {
return (UserContext) token.getPrincipal();
}
}

View File

@ -0,0 +1,14 @@
package com.svlada.security;
import com.svlada.security.model.UserContext;
/**
*
* @author vladimir.stankovic
*
* Aug 17, 2016
*/
public interface UserService {
public UserContext getByUsername(String username);
public UserContext getByUsernameAndPassword(String username, String password);
}

View File

@ -5,8 +5,6 @@ import java.util.Collection;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import com.svlada.security.model.JwtToken;
import com.svlada.security.model.SafeJwtToken;
import com.svlada.security.model.UnsafeJwtToken;
import com.svlada.security.model.UserContext;
@ -21,9 +19,7 @@ import com.svlada.security.model.UserContext;
public class JwtAuthenticationToken extends AbstractAuthenticationToken {
private static final long serialVersionUID = 2877954820905567501L;
private JwtToken safeToken;
private UnsafeJwtToken unsafeToken;
private UserContext userContext;
public JwtAuthenticationToken(UnsafeJwtToken unsafeToken) {
@ -32,9 +28,9 @@ public class JwtAuthenticationToken extends AbstractAuthenticationToken {
this.setAuthenticated(false);
}
public JwtAuthenticationToken(UserContext userContext, SafeJwtToken token, Collection<? extends GrantedAuthority> authorities) {
public JwtAuthenticationToken(UserContext userContext, Collection<? extends GrantedAuthority> authorities) {
super(authorities);
this.safeToken = token;
this.unsafeToken = null;
this.userContext = userContext;
super.setAuthenticated(true);
}
@ -50,7 +46,7 @@ public class JwtAuthenticationToken extends AbstractAuthenticationToken {
@Override
public Object getCredentials() {
return null;
return unsafeToken;
}
@Override
@ -58,16 +54,9 @@ public class JwtAuthenticationToken extends AbstractAuthenticationToken {
return this.userContext;
}
public JwtToken getSafeToken() {
return this.safeToken;
}
public UnsafeJwtToken getUnsafeToken() {
return unsafeToken;
}
@Override
public void eraseCredentials() {
public void eraseCredentials() {
super.eraseCredentials();
this.unsafeToken = null;
}
}

View File

@ -0,0 +1,24 @@
package com.svlada.security.auth;
import javax.servlet.http.HttpServletRequest;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import com.svlada.security.config.WebSecurityConfig;
/**
* Skip processing of Refresh token URL endpoint.
*
* @author vladimir.stankovic
*
* Aug 17, 2016
*/
public class RefreshTokenRequestMatcher implements RequestMatcher {
private AntPathRequestMatcher matcher = new AntPathRequestMatcher(WebSecurityConfig.TOKEN_REFRESH_ENTRY_POINT);
@Override
public boolean matches(HttpServletRequest request) {
return matcher.matches(request) ? false : true;
}
}

View File

@ -8,11 +8,8 @@ import org.springframework.security.core.AuthenticationException;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import com.svlada.security.auth.JwtAuthenticationToken;
import com.svlada.security.model.JwtTokenFactory;
import com.svlada.security.model.SafeJwtToken;
import com.svlada.security.model.UserContext;
import com.svlada.security.service.UserService;
import com.svlada.user.service.DatabaseUserService;
/**
*
@ -22,12 +19,11 @@ import com.svlada.security.service.UserService;
*/
@Component
public class AjaxAuthenticationProvider implements AuthenticationProvider {
private final JwtTokenFactory tokenFactory;
private final UserService userService;
private final DatabaseUserService userService;
@Autowired
public AjaxAuthenticationProvider(final JwtTokenFactory tokenFactory, final UserService userService) {
this.tokenFactory = tokenFactory;
public AjaxAuthenticationProvider(final DatabaseUserService userService) {
this.userService = userService;
}
@ -38,11 +34,9 @@ public class AjaxAuthenticationProvider implements AuthenticationProvider {
String username = (String) authentication.getPrincipal();
String password = (String) authentication.getCredentials();
UserContext userContext = userService.loadUser(username, password);
UserContext userContext = userService.getByUsernameAndPassword(username, password);
SafeJwtToken safeJwtToken = tokenFactory.createSafeToken(userContext);
return new JwtAuthenticationToken(userContext, safeJwtToken, userContext.getAuthorities());
return new UsernamePasswordAuthenticationToken(userContext, null, userContext.getAuthorities());
}
@Override

View File

@ -16,10 +16,12 @@ import org.springframework.security.web.authentication.AuthenticationSuccessHand
import org.springframework.stereotype.Component;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.svlada.security.auth.JwtAuthenticationToken;
import com.svlada.security.model.JwtToken;
import com.svlada.security.model.JwtTokenFactory;
import com.svlada.security.model.UserContext;
/**
* AjaxAwareAuthenticationSuccessHandler
*
* @author vladimir.stankovic
*
@ -28,16 +30,21 @@ import com.svlada.security.model.JwtToken;
@Component
public class AjaxAwareAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
private final ObjectMapper mapper;
private final JwtTokenFactory tokenFactory;
@Autowired
public AjaxAwareAuthenticationSuccessHandler(ObjectMapper mapper) {
public AjaxAwareAuthenticationSuccessHandler(final ObjectMapper mapper, final JwtTokenFactory tokenFactory) {
this.mapper = mapper;
this.tokenFactory = tokenFactory;
}
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
JwtToken token = ((JwtAuthenticationToken) authentication).getSafeToken();
UserContext userContext = (UserContext) authentication.getPrincipal();
JwtToken token = tokenFactory.createSafeToken(userContext);
JwtToken refreshToken = tokenFactory.createRefreshToken(userContext);
response.setStatus(HttpStatus.OK.value());
response.setContentType(MediaType.APPLICATION_JSON_VALUE);

View File

@ -53,6 +53,9 @@ public class AjaxLoginProcessingFilter extends AbstractAuthenticationProcessingF
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");
}
@ -61,7 +64,7 @@ public class AjaxLoginProcessingFilter extends AbstractAuthenticationProcessingF
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);

View File

@ -0,0 +1,15 @@
package com.svlada.security.auth.jwt;
/**
* BloomFilterTokenVerifier
*
* @author vladimir.stankovic
*
* Aug 17, 2016
*/
public class BloomFilterTokenVerifier implements TokenVerifier {
@Override
public boolean verify(String jti) {
return true;
}
}

View File

@ -6,14 +6,12 @@ import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.stereotype.Component;
import com.svlada.security.UserService;
import com.svlada.security.auth.JwtAuthenticationToken;
import com.svlada.security.config.JwtSettings;
import com.svlada.security.model.JwtToken;
import com.svlada.security.model.JwtTokenFactory;
import com.svlada.security.model.SafeJwtToken;
import com.svlada.security.model.UnsafeJwtToken;
import com.svlada.security.model.UserContext;
import com.svlada.security.service.UserService;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
@ -30,27 +28,23 @@ import io.jsonwebtoken.Jws;
public class JwtAuthenticationProvider implements AuthenticationProvider {
private final UserService userService;
private final JwtSettings jwtSettings;
private final JwtTokenFactory jwtTokenFactory;
@Autowired
public JwtAuthenticationProvider(UserService userService, JwtSettings jwtSettings, JwtTokenFactory jwtTokenFactory) {
public JwtAuthenticationProvider(UserService userService, JwtSettings jwtSettings) {
this.userService = userService;
this.jwtSettings = jwtSettings;
this.jwtTokenFactory = jwtTokenFactory;
}
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
UnsafeJwtToken unsafeToken = ((JwtAuthenticationToken) authentication).getUnsafeToken();
UnsafeJwtToken unsafeToken = (UnsafeJwtToken) authentication.getCredentials();
Jws<Claims> jwsClaims = unsafeToken.parseClaims(jwtSettings.getTokenSigningKey());
String subject = jwsClaims.getBody().getSubject();
UserContext context = userService.loadUser(subject);
SafeJwtToken safeToken = jwtTokenFactory.createSafeToken(unsafeToken.getToken(), jwsClaims.getBody());
UserContext context = userService.getByUsername(subject);
JwtAuthenticationToken authToken = new JwtAuthenticationToken(context, safeToken, context.getAuthorities());
return authToken;
return new JwtAuthenticationToken(context, context.getAuthorities());
}
@Override

View File

@ -8,16 +8,17 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.util.matcher.RequestMatcher;
import com.svlada.security.auth.JwtAuthenticationToken;
import com.svlada.security.auth.jwt.extractor.TokenExtractor;
import com.svlada.security.config.WebSecurityConfig;
import com.svlada.security.model.JwtTokenFactory;
import com.svlada.security.model.UnsafeJwtToken;
@ -36,9 +37,9 @@ public class JwtTokenAuthenticationProcessingFilter extends AbstractAuthenticati
@Autowired
public JwtTokenAuthenticationProcessingFilter(AuthenticationFailureHandler failureHandler,
JwtTokenFactory tokenFactory,
@Qualifier("jwtHeaderTokenExtractor") TokenExtractor tokenExtractor,
String defaultFilterProcessesUrl) {
super(defaultFilterProcessesUrl);
TokenExtractor tokenExtractor,
RequestMatcher requestMatcher) {
super(requestMatcher);
this.failureHandler = failureHandler;
this.tokenExtractor = tokenExtractor;
this.tokenFactory = tokenFactory;
@ -47,7 +48,7 @@ public class JwtTokenAuthenticationProcessingFilter extends AbstractAuthenticati
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException, IOException, ServletException {
String tokenPayload = request.getHeader("X-Authorization");
String tokenPayload = request.getHeader(WebSecurityConfig.JWT_TOKEN_HEADER_PARAM);
UnsafeJwtToken token = tokenFactory.createUnsafeToken(tokenExtractor.extract(tokenPayload));
return getAuthenticationManager().authenticate(new JwtAuthenticationToken(token));
}

View File

@ -0,0 +1,11 @@
package com.svlada.security.auth.jwt;
/**
*
* @author vladimir.stankovic
*
* Aug 17, 2016
*/
public interface TokenVerifier {
public boolean verify(String jti);
}

View File

@ -24,14 +24,14 @@ public class JwtSettings {
/**
* {@link JwtToken} can be refreshed during this timeframe.
*/
private Integer tokenValidationTimeframe;
private Integer refreshTokenExpTime;
public Integer getTokenValidationTimeframe() {
return tokenValidationTimeframe;
public Integer getRefreshTokenExpTime() {
return refreshTokenExpTime;
}
public void setTokenValidationTimeframe(Integer tokenValidationTimeframe) {
this.tokenValidationTimeframe = tokenValidationTimeframe;
public void setRefreshTokenExpTime(Integer refreshTokenExpTime) {
this.refreshTokenExpTime = refreshTokenExpTime;
}
public Integer getTokenExpirationTime() {

View File

@ -9,14 +9,20 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.svlada.security.RestAuthenticationEntryPoint;
import com.svlada.security.auth.RefreshTokenRequestMatcher;
import com.svlada.security.auth.ajax.AjaxAuthenticationProvider;
import com.svlada.security.auth.ajax.AjaxLoginProcessingFilter;
import com.svlada.security.auth.jwt.JwtAuthenticationProvider;
import com.svlada.security.auth.jwt.JwtTokenAuthenticationProcessingFilter;
import com.svlada.security.auth.jwt.extractor.TokenExtractor;
import com.svlada.security.model.JwtTokenFactory;
/**
* WebSecurityConfig
@ -28,13 +34,19 @@ import com.svlada.security.auth.ajax.AjaxLoginProcessingFilter;
@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 JwtTokenFactory tokenFactory;
@Autowired private AuthenticationManager authenticationManager;
@ -46,6 +58,13 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
filter.setAuthenticationManager(this.authenticationManager);
return filter;
}
@Bean
protected JwtTokenAuthenticationProcessingFilter buildJwtTokenAuthenticationProcessingFilter() throws Exception {
JwtTokenAuthenticationProcessingFilter filter = new JwtTokenAuthenticationProcessingFilter(failureHandler, tokenFactory, tokenExtractor, new RefreshTokenRequestMatcher());
filter.setAuthenticationManager(this.authenticationManager);
return filter;
}
@Bean
@Override
@ -55,6 +74,12 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
protected void configure(AuthenticationManagerBuilder auth) {
auth.authenticationProvider(ajaxAuthenticationProvider);
auth.authenticationProvider(jwtAuthenticationProvider);
}
@Bean
protected BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
@ -71,7 +96,9 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
.and()
.authorizeRequests()
.antMatchers(FORM_BASED_LOGIN_ENTRY_POINT).permitAll() // Login end-point
.antMatchers(TOKEN_REFRESH_ENTRY_POINT).permitAll() // Token refresh end-point
.and()
.addFilterBefore(buildAjaxLoginProcessingFilter(), UsernamePasswordAuthenticationFilter.class);
.addFilterBefore(buildAjaxLoginProcessingFilter(), UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(buildJwtTokenAuthenticationProcessingFilter(), UsernamePasswordAuthenticationFilter.class);
}
}

View File

@ -0,0 +1,60 @@
package com.svlada.security.endpoint;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import com.svlada.security.UserService;
import com.svlada.security.auth.jwt.TokenVerifier;
import com.svlada.security.config.JwtSettings;
import com.svlada.security.config.WebSecurityConfig;
import com.svlada.security.exceptions.InvalidJwtToken;
import com.svlada.security.model.JwtToken;
import com.svlada.security.model.JwtTokenFactory;
import com.svlada.security.model.UnsafeJwtToken;
import com.svlada.security.model.UserContext;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
/**
* RefreshTokenEndpoint
*
* @author vladimir.stankovic
*
* Aug 17, 2016
*/
@RestController
public class RefreshTokenEndpoint {
@Autowired private JwtTokenFactory tokenFactory;
@Autowired private JwtSettings jwtSettings;
@Autowired private UserService userService;
@Autowired private TokenVerifier tokenVerifier;
@RequestMapping(value="/api/auth/token", method=RequestMethod.GET, produces={ MediaType.APPLICATION_JSON_VALUE })
public @ResponseBody JwtToken refreshToken(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
UnsafeJwtToken unsafeToken = this.tokenFactory.createUnsafeToken(request.getHeader(WebSecurityConfig.JWT_TOKEN_HEADER_PARAM));
Jws<Claims> jwsClaims = unsafeToken.parseClaims(jwtSettings.getTokenSigningKey());
String subject = jwsClaims.getBody().getSubject();
String jti = jwsClaims.getBody().getId();
if (!tokenVerifier.verify(jti)) {
throw new InvalidJwtToken();
}
UserContext userContext = userService.getByUsername(subject);
return tokenFactory.createSafeToken(userContext);
}
}

View File

@ -0,0 +1,12 @@
package com.svlada.security.exceptions;
/**
* JwtTokenNotValid
*
* @author vladimir.stankovic
*
* Aug 17, 2016
*/
public class InvalidJwtToken extends RuntimeException {
private static final long serialVersionUID = -294671188037098603L;
}

View File

@ -1,5 +1,7 @@
package com.svlada.security.model;
import java.util.UUID;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
@ -53,7 +55,7 @@ public class JwtTokenFactory {
return new SafeJwtToken(token, claims);
}
public SafeJwtToken refreshToken(SafeJwtToken safeJwtToken) {
return null;
}
@ -74,4 +76,25 @@ public class JwtTokenFactory {
public UnsafeJwtToken createUnsafeToken(String tokenPayload) {
return new UnsafeJwtToken(tokenPayload);
}
public JwtToken createRefreshToken(UserContext userContext) {
if (StringUtils.isBlank(userContext.getUsername())) {
throw new IllegalArgumentException("Cannot create JWT Token without username");
}
DateTime currentTime = new DateTime();
Claims claims = Jwts.claims().setSubject(userContext.getUsername());
String token = Jwts.builder()
.setClaims(claims)
.setIssuer(settings.getTokenIssuer())
.setId(UUID.randomUUID().toString())
.setIssuedAt(currentTime.toDate())
.setExpiration(currentTime.plusMinutes(settings.getRefreshTokenExpTime()).toDate())
.signWith(SignatureAlgorithm.HS512, settings.getTokenSigningKey())
.compact();
return new SafeJwtToken(token, claims);
}
}

View File

@ -1,5 +1,7 @@
package com.svlada.security.model;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.BadCredentialsException;
import com.svlada.security.exceptions.JwtExpiredTokenException;
@ -13,6 +15,8 @@ import io.jsonwebtoken.SignatureException;
import io.jsonwebtoken.UnsupportedJwtException;
public class UnsafeJwtToken implements JwtToken {
private static Logger logger = LoggerFactory.getLogger(UnsafeJwtToken.class);
private String token;
public UnsafeJwtToken(String token) {
@ -30,8 +34,10 @@ public class UnsafeJwtToken implements JwtToken {
try {
return Jwts.parser().setSigningKey(signingKey).parseClaimsJws(this.token);
} catch (UnsupportedJwtException | MalformedJwtException | IllegalArgumentException | SignatureException ex) {
logger.error("Invalid JWT Token", ex);
throw new BadCredentialsException("Invalid JWT token: ", ex);
} catch (ExpiredJwtException expiredEx) {
logger.info("JWT Token is expired", expiredEx);
throw new JwtExpiredTokenException(this, "JWT Token expired", expiredEx);
}
}

View File

@ -1,4 +1,4 @@
package com.svlada.security.repository;
package com.svlada.user.repository;
import org.springframework.data.jpa.repository.JpaRepository;

View File

@ -1,4 +1,4 @@
package com.svlada.security.service;
package com.svlada.user.service;
import java.util.ArrayList;
import java.util.List;
@ -8,9 +8,10 @@ import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Service;
import com.svlada.security.UserService;
import com.svlada.security.model.UserContext;
import com.svlada.security.model.UserRole;
import com.svlada.security.repository.UserRepository;
import com.svlada.user.repository.UserRepository;
/**
* Mock implementation.
@ -20,21 +21,23 @@ import com.svlada.security.repository.UserRepository;
* Aug 4, 2016
*/
@Service
public class UserService {
public class DatabaseUserService implements UserService {
private final UserRepository userRepository;
@Autowired
public UserService(UserRepository userRepository) {
public DatabaseUserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public UserContext loadUser(String username, String password) {
@Override
public UserContext getByUsernameAndPassword(String username, String password) {
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
authorities.add(new SimpleGrantedAuthority(UserRole.ADMIN.authority()));
return new UserContext(username, authorities);
}
public UserContext loadUser(String username) {
@Override
public UserContext getByUsername(String username) {
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
authorities.add(new SimpleGrantedAuthority(UserRole.ADMIN.authority()));
return new UserContext(username, authorities);