SUPPORT-8609 fix
This commit is contained in:
parent
d26799c630
commit
7f1793262d
3 changed files with 105 additions and 25 deletions
|
|
@ -13,6 +13,7 @@ import org.springframework.security.web.AuthenticationEntryPoint;
|
|||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
import org.springframework.security.web.authentication.logout.LogoutFilter;
|
||||
import org.springframework.security.web.authentication.session.NullAuthenticatedSessionStrategy;
|
||||
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
|
||||
import org.springframework.security.web.csrf.CsrfTokenRequestHandler;
|
||||
import org.springframework.security.web.csrf.XorCsrfTokenRequestAttributeHandler;
|
||||
|
|
@ -49,31 +50,22 @@ public class SecurityConfig {
|
|||
}
|
||||
|
||||
@Bean
|
||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
httpConfigure(http);
|
||||
http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
|
||||
http.addFilterBefore(new RequestContextFilter(), LogoutFilter.class);
|
||||
http.addFilterAfter(filterChainExceptionHandler, RequestContextFilter.class);
|
||||
return http.build();
|
||||
}
|
||||
|
||||
protected void httpConfigure(HttpSecurity httpSecurity) throws Exception {
|
||||
CookieCsrfTokenRepository tokenRepository = CookieCsrfTokenRepository.withHttpOnlyFalse();
|
||||
tokenRepository.setCookieName(TokenConstants.CSRF_TOKEN_NAME);
|
||||
tokenRepository.setHeaderName(TokenConstants.CSRF_HEADER_NAME);
|
||||
tokenRepository.setCookiePath("/");
|
||||
public SecurityFilterChain filterChain(HttpSecurity http,
|
||||
CookieCsrfTokenRepository tokenRepository)
|
||||
throws Exception {
|
||||
XorCsrfTokenRequestAttributeHandler delegate = new XorCsrfTokenRequestAttributeHandler();
|
||||
delegate.setCsrfRequestAttributeName(null);
|
||||
// Use only the handle() method of XorCsrfTokenRequestAttributeHandler and the
|
||||
// default implementation of resolveCsrfTokenValue() from CsrfTokenRequestHandler
|
||||
CsrfTokenRequestHandler requestHandler = delegate::handle;
|
||||
httpSecurity.authorizeHttpRequests(
|
||||
http.authorizeHttpRequests(
|
||||
(authorizeHttpRequests) -> authorizeHttpRequests.requestMatchers(PERMIT_ALL)
|
||||
.permitAll()
|
||||
.anyRequest()
|
||||
.authenticated())
|
||||
.csrf((csrf) -> csrf.csrfTokenRepository(tokenRepository)
|
||||
.csrfTokenRequestHandler(requestHandler))
|
||||
.csrfTokenRequestHandler(requestHandler)
|
||||
.sessionAuthenticationStrategy(new NullAuthenticatedSessionStrategy()))
|
||||
.logout((logout) -> logout.logoutUrl(ESIA_LOGOUT)
|
||||
.logoutSuccessHandler(new LogoutSuccessHandler(tokenRepository, esiaAuthService)))
|
||||
.exceptionHandling()
|
||||
|
|
@ -81,6 +73,19 @@ public class SecurityConfig {
|
|||
.and()
|
||||
.sessionManagement()
|
||||
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
|
||||
http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
|
||||
http.addFilterBefore(new RequestContextFilter(), LogoutFilter.class);
|
||||
http.addFilterAfter(filterChainExceptionHandler, RequestContextFilter.class);
|
||||
return http.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CookieCsrfTokenRepository cookieCsrfTokenRepository() {
|
||||
CookieCsrfTokenRepository tokenRepository = CookieCsrfTokenRepository.withHttpOnlyFalse();
|
||||
tokenRepository.setCookieName(TokenConstants.CSRF_TOKEN_NAME);
|
||||
tokenRepository.setHeaderName(TokenConstants.CSRF_HEADER_NAME);
|
||||
tokenRepository.setCookiePath("/");
|
||||
return tokenRepository;
|
||||
}
|
||||
|
||||
public AuthenticationEntryPoint entryPoint() {
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import javax.servlet.http.HttpServletResponse;
|
|||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import ervu.service.okopf.OkopfService;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import ru.micord.ervu.security.esia.token.TokensStore;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
|
@ -50,7 +51,6 @@ import ru.micord.ervu.security.webbpm.jwt.JwtAuthentication;
|
|||
import ru.micord.ervu.security.webbpm.jwt.helper.SecurityHelper;
|
||||
import ru.micord.ervu.security.webbpm.jwt.service.JwtTokenService;
|
||||
import ru.micord.ervu.security.webbpm.jwt.model.Token;
|
||||
import ru.micord.ervu.security.webbpm.jwt.util.SecurityUtil;
|
||||
|
||||
/**
|
||||
* @author Eduard Tihomirov
|
||||
|
|
@ -72,6 +72,8 @@ public class EsiaAuthService {
|
|||
private OkopfService okopfService;
|
||||
@Autowired
|
||||
private SecurityHelper securityHelper;
|
||||
@Autowired
|
||||
private AuthenticationManager authenticationManager;
|
||||
|
||||
@Value("${ervu.kafka.org.reply.topic}")
|
||||
private String requestReplyTopic;
|
||||
|
|
@ -211,16 +213,16 @@ public class EsiaAuthService {
|
|||
if (tokenResponse.getError() != null) {
|
||||
throw new RuntimeException(tokenResponse.getError_description());
|
||||
}
|
||||
String accessToken = tokenResponse.getAccess_token();
|
||||
String esiaAccessTokenStr = tokenResponse.getAccess_token();
|
||||
String esiaRefreshTokenStr = tokenResponse.getRefresh_token();
|
||||
|
||||
boolean hasRole = ulDataService.checkRole(accessToken);
|
||||
EsiaAccessToken esiaAccessToken = ulDataService.readToken(accessToken);
|
||||
boolean hasRole = ulDataService.checkRole(esiaAccessTokenStr);
|
||||
EsiaAccessToken esiaAccessToken = ulDataService.readToken(esiaAccessTokenStr);
|
||||
String prnOid = esiaAccessToken.getSbj_id();
|
||||
String refreshToken = tokenResponse.getRefresh_token();
|
||||
String ervuId = getErvuId(accessToken, prnOid);
|
||||
String ervuId = getErvuId(esiaAccessTokenStr, prnOid);
|
||||
Long expiresIn = tokenResponse.getExpires_in();
|
||||
TokensStore.addAccessToken(prnOid, accessToken, expiresIn);
|
||||
TokensStore.addRefreshToken(prnOid, refreshToken, expiresIn);
|
||||
TokensStore.addAccessToken(prnOid, esiaAccessTokenStr, expiresIn);
|
||||
TokensStore.addRefreshToken(prnOid, esiaRefreshTokenStr, expiresIn);
|
||||
Token token = jwtTokenService.createAccessToken(esiaAccessToken.getSbj_id(), expiresIn, ervuId, hasRole);
|
||||
int expiry = tokenResponse.getExpires_in().intValue();
|
||||
Cookie accessCookie = securityHelper.createAccessCookie(token.getValue(), expiry);
|
||||
|
|
@ -228,9 +230,10 @@ public class EsiaAuthService {
|
|||
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
|
||||
new UsernamePasswordAuthenticationToken(token.getUserAccountId(), null);
|
||||
SecurityContext context = SecurityContextHolder.createEmptyContext();
|
||||
JwtAuthentication authentication = new JwtAuthentication(usernamePasswordAuthenticationToken,
|
||||
JwtAuthentication jwtAuthentication = new JwtAuthentication(usernamePasswordAuthenticationToken,
|
||||
esiaAccessToken.getSbj_id(), token.getValue());
|
||||
context.setAuthentication(authentication);
|
||||
authenticationManager.authenticate(jwtAuthentication);
|
||||
context.setAuthentication(jwtAuthentication);
|
||||
SecurityContextHolder.setContext(context);
|
||||
Cookie authMarkerCookie = securityHelper.createAuthMarkerCookie("true", expiry);
|
||||
response.addCookie(authMarkerCookie);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,72 @@
|
|||
package ru.micord.ervu.security.listener;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.security.authentication.event.AuthenticationSuccessEvent;
|
||||
import org.springframework.security.web.csrf.CsrfTokenRepository;
|
||||
import org.springframework.security.web.csrf.CsrfTokenRequestAttributeHandler;
|
||||
import org.springframework.security.web.csrf.CsrfTokenRequestHandler;
|
||||
import org.springframework.security.web.csrf.DeferredCsrfToken;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.context.request.RequestAttributes;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
import static org.springframework.web.context.request.RequestAttributes.REFERENCE_REQUEST;
|
||||
|
||||
|
||||
@Component
|
||||
public class JwtUpdateListener implements ApplicationListener<AuthenticationSuccessEvent> {
|
||||
private final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||
|
||||
private final CsrfTokenRepository tokenRepository;
|
||||
private final Set<AntPathRequestMatcher> csrfUpdateRequiredPathMatchers;
|
||||
|
||||
private CsrfTokenRequestHandler requestHandler = new CsrfTokenRequestAttributeHandler();
|
||||
|
||||
@Autowired
|
||||
public JwtUpdateListener(CsrfTokenRepository tokenRepository) {
|
||||
Assert.notNull(tokenRepository, "tokenRepository cannot be null");
|
||||
this.tokenRepository = tokenRepository;
|
||||
this.csrfUpdateRequiredPathMatchers = Arrays.stream(new String[] {"/esia/auth"})
|
||||
.map(AntPathRequestMatcher::new)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(AuthenticationSuccessEvent event) {
|
||||
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
|
||||
HttpServletRequest request = (HttpServletRequest) Objects.requireNonNull(requestAttributes)
|
||||
.resolveReference(
|
||||
REFERENCE_REQUEST);
|
||||
HttpServletResponse response = ((ServletRequestAttributes) requestAttributes).getResponse();
|
||||
|
||||
//if csrf cookie update is not required return
|
||||
if (this.csrfUpdateRequiredPathMatchers.stream()
|
||||
.noneMatch(matcher -> matcher.matches(request))) {
|
||||
return;
|
||||
}
|
||||
boolean containsToken = this.tokenRepository.loadToken(request) != null;
|
||||
|
||||
if (containsToken) {
|
||||
this.tokenRepository.saveToken(null, request, response);
|
||||
DeferredCsrfToken deferredCsrfToken = this.tokenRepository.loadDeferredToken(request,
|
||||
response
|
||||
);
|
||||
this.requestHandler.handle(request, response, deferredCsrfToken::get);
|
||||
this.logger.debug("Replaced CSRF Token");
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue