How to skip oncePerRequest filter when using httpservletRequest.login() - spring-security

I am trying to login using httpServletRequest.login(), after registration for automatic login. BUT when I do this, I hit the OncePerRequest.doFilterInternal which checks the headers for an authorization header and kicks me out.
I dont think I am supposed to hit this for login, right now when I hit the route "api/v1/auth/login" I never hit the filter OncePerRequest.doFilterInternal. And its 200 response includes authorization jwt token as expected.
Am I not using the OncePerRequest.doFilterInternal correctly? I want to be able to login and set an authorization header in the response when a user registers.
Relevant code:
public class JwtTokenVerifier extends OncePerRequestFilter {
private final SecretKey secretKey;
private final JwtConfig jwtConfig;
public JwtTokenVerifier(SecretKey secretKey,
JwtConfig jwtConfig) {
this.secretKey = secretKey;
this.jwtConfig = jwtConfig;
}
#Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
String authorizationHeader = request.getHeader(jwtConfig.getAuthorizationHeader());
if (Strings.isNullOrEmpty(authorizationHeader) || !authorizationHeader.startsWith(jwtConfig.getTokenPrefix())) {
filterChain.doFilter(request, response);
return;
}
String token = authorizationHeader.replace(jwtConfig.getTokenPrefix(), "");
try {
Jws<Claims> claimsJws = Jwts.parser()
.setSigningKey(secretKey)
.parseClaimsJws(token);
Claims body = claimsJws.getBody();
String username = body.getSubject();
var authorities = (List<Map<String, String>>) body.get("authorities");
Set<SimpleGrantedAuthority> simpleGrantedAuthorities = authorities.stream()
.map(m -> new SimpleGrantedAuthority(m.get("authority")))
.collect(Collectors.toSet());
Authentication authentication = new UsernamePasswordAuthenticationToken(
username,
null,
simpleGrantedAuthorities
);
SecurityContextHolder.getContext().setAuthentication(authentication);
} catch (JwtException e) {
throw new IllegalStateException(String.format("Token %s cannot be trusted:", token));
}
filterChain.doFilter(request, response);
}
Config:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class ApplicationSecurityConfig extends
WebSecurityConfigurerAdapter {
private final AuthUserServiceImpl authUserServiceImpl;
private final IUserRepository iUserRepository;
private final PasswordEncoder passwordEncoder;
private final SecretKey secretKey;
private final JwtConfig jwtConfig;
private final AccessDeniedFilter accessDeniedFilter;
private final AuthenticationEntryPointFilter authenticationEntryPointFilter;
#Autowired
public ApplicationSecurityConfig(PasswordEncoder passwordEncoder,
AuthUserServiceImpl authUserServiceImpl,
SecretKey secretKey,
JwtConfig jwtConfig,
AccessDeniedFilter accessDeniedFilter,
AuthenticationEntryPointFilter authenticationEntryPointFilter,
IUserRepository iUserRepository) {
this.passwordEncoder = passwordEncoder;
this.authUserServiceImpl = authUserServiceImpl;
this.secretKey = secretKey;
this.jwtConfig = jwtConfig;
this.accessDeniedFilter = accessDeniedFilter;
this.authenticationEntryPointFilter = authenticationEntryPointFilter;
this.iUserRepository = iUserRepository;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors()
.and()
.csrf()
.disable()
.authorizeRequests()
.antMatchers("/", "index", "/css/*", "/js/*", "/api/v1/auth/register").permitAll()
.antMatchers("/api/**").hasAnyRole(ADMIN.name(), USER.name())
.anyRequest()
.authenticated()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.exceptionHandling()
.accessDeniedHandler(accessDeniedFilter)
.authenticationEntryPoint(authenticationEntryPointFilter)
.and()
.addFilter(jwtAuthorizationFilter())
.addFilterAfter(new JwtTokenVerifier(secretKey, jwtConfig), JwtUsernameAndPasswordJwtFilter.class);
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(daoAuthenticationProvider());
}
#Bean
CorsConfigurationSource corsConfigurationSource() {
final CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("whatever.com));
configuration.setAllowedMethods(ImmutableList.of("HEAD", "GET", "POST", "PUT", "DELETE", "OPTIONS"));
configuration.setAllowCredentials(true);
configuration.setAllowedHeaders(ImmutableList.of("Authorization", "Cache-Control", "Content-Type", "access-control-allow-origin"));
configuration.setExposedHeaders(Arrays.asList("Authorization"));
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
#Bean
public DaoAuthenticationProvider daoAuthenticationProvider() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(authUserServiceImpl);
provider.setPasswordEncoder(passwordEncoder);
return provider;
}
public JwtUsernameAndPasswordJwtFilter jwtAuthorizationFilter() throws Exception {
JwtUsernameAndPasswordJwtFilter jwtAuthenticationFilter = new JwtUsernameAndPasswordJwtFilter(authenticationManager(), jwtConfig, secretKey, iUserRepository);
jwtAuthenticationFilter.setFilterProcessesUrl("/api/v1/auth/login");
return jwtAuthenticationFilter;
}
}
#PostMapping("/register")
public ResponseEntity<?> registerUserAccount(
#Valid #RequestBody AuthUserRequest authUserRequest,
Errors errors) throws NullPointerException {
String password = authUserRequest.getPassword();
if (errors.hasErrors()) {
return ResponseEntity.badRequest().body(errors.getFieldError());
}
try {
iAuthUser.registerNewUserAccount(authUserRequest);
} catch (Exception e) {
return ResponseEntity.badRequest().build();
}
try {
httpServletRequest.login(authUserRequest.getUsername(), password);
} catch (ServletException e) {
System.out.println("Servlet Error: " + e);
}
return ResponseEntity.ok().build();
}

Related

Spring GraphQL authentication error handling

I am using Spring GraphQL and Spring Security in my project. I am authenticating users with JWTs so I have a security filter to check the validity of the token. When the token is invalid, an exception is thrown.
I am trying to return the message of the exception as a valid graphQL response but all I get is this:
{
"errors": {
"message": "Failed to execute 'text' on 'Response': body stream already read",
"stack": "TypeError: Failed to execute 'text' on 'Response': body stream already read\n at http://localhost:8080/graphiql?path=/graphql:78:33"
}
}
The error I am getting in the console is this:
com.auth0.jwt.exceptions.JWTDecodeException: The input is not a valid base 64 encoded string.
So, I want that in the "errors" "message".
This is the Security configuration:
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final AppUserDetailsService appUserDetailsService;
private final JwtFilter jwtFilter;
public SecurityConfig(AppUserDetailsService appUserDetailsService, JwtFilter jwtFilter) {
this.appUserDetailsService = appUserDetailsService;
this.jwtFilter = jwtFilter;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(appUserDetailsService);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/api/auth").permitAll()
.antMatchers("/graphiql").permitAll()
.antMatchers("/graphql").permitAll()
.anyRequest().authenticated()
.and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class);
}
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
and this is the jwtFilter:
#Log4j2
#Component
public class JwtFilter extends OncePerRequestFilter {
private final JwtUtil jwtUtil;
private final AppUserDetailsService userDetailsService;
public JwtFilter(JwtUtil jwtUtil, AppUserDetailsService userDetailsService) {
this.jwtUtil = jwtUtil;
this.userDetailsService = userDetailsService;
}
#Override
protected void doFilterInternal(#NotNull HttpServletRequest request,
#NotNull HttpServletResponse response,
#NotNull FilterChain filterChain) throws ServletException, IOException {
final String header = request.getHeader("Authorization");
String username = null;
String jwt = null;
try {
if (header != null && header.startsWith("Bearer ")) {
jwt = header.substring(7);
username = jwtUtil.getUsername(jwt);
}
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
if (jwtUtil.validateToken(jwt, userDetails)) {
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
authenticationToken.setDetails(
new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
}
}
} catch (Exception ex) {
log.error(ex.getMessage());
throw ex;
}
filterChain.doFilter(request, response);
}
}
Does anyone know how could I achieve that?
Thanks!

How does JwtUsernameAndPasswordAuthenticationFilter work in this example?

Below is my example of Configuration, as far as I understand, JwtUsernameAndPasswordAuthenticationFilter works first ( it gets username, password from request, checks if they are correct and provides a token ), then - JwtTokenVerifier.
I have a few questions:
Is JwtUsernameAndPasswordAuthenticationFilter checks requests every time for containing username and password? If not, when does it check it? Once per what?
Why do we create Authentication object in JwtTokenVerifier class with no password ( just username and Authorities ) and put it in Context?
P.S. I do appreciate your answers! And know how dumb the question may seems to be.
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilter(new JwtUsernameAndPasswordAuthenticationFilter(authenticationManager(), jwtConfig, secretKey))
.addFilterAfter(new JwtTokenVerifier(secretKey, jwtConfig),JwtUsernameAndPasswordAuthenticationFilter.class)
.authorizeRequests()
.antMatchers("/", "index", "/css/*", "/js/*").permitAll()
.antMatchers("/api/**").hasRole(STUDENT.name())
.anyRequest()
.authenticated();
}
public class JwtUsernameAndPasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private final AuthenticationManager authenticationManager;
private final JwtConfig jwtConfig;
private final SecretKey secretKey;
public JwtUsernameAndPasswordAuthenticationFilter(AuthenticationManager authenticationManager,
JwtConfig jwtConfig,
SecretKey secretKey) {
this.authenticationManager = authenticationManager;
this.jwtConfig = jwtConfig;
this.secretKey = secretKey;
}
#Override
public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response) throws AuthenticationException {
try {
UsernameAndPasswordAuthenticationRequest authenticationRequest = new ObjectMapper()
.readValue(request.getInputStream(), UsernameAndPasswordAuthenticationRequest.class);
Authentication authentication = new UsernamePasswordAuthenticationToken(
authenticationRequest.getUsername(),
authenticationRequest.getPassword()
);
Authentication authenticate = authenticationManager.authenticate(authentication);
return authenticate;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
#Override
protected void successfulAuthentication(HttpServletRequest request,
HttpServletResponse response,
FilterChain chain,
Authentication authResult) throws IOException, ServletException {
String token = Jwts.builder()
.setSubject(authResult.getName())
.claim("authorities", authResult.getAuthorities())
.setIssuedAt(new Date())
.setExpiration(java.sql.Date.valueOf(LocalDate.now().plusDays(jwtConfig.getTokenExpirationAfterDays())))
.signWith(secretKey)
.compact();
response.addHeader(jwtConfig.getAuthorizationHeader(), jwtConfig.getTokenPrefix() + token);
}
}
public class JwtTokenVerifier extends OncePerRequestFilter {
private final SecretKey secretKey;
private final JwtConfig jwtConfig;
public JwtTokenVerifier(SecretKey secretKey,
JwtConfig jwtConfig) {
this.secretKey = secretKey;
this.jwtConfig = jwtConfig;
}
#Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
String authorizationHeader = request.getHeader(jwtConfig.getAuthorizationHeader());
if (Strings.isNullOrEmpty(authorizationHeader) || !authorizationHeader.startsWith(jwtConfig.getTokenPrefix())) {
filterChain.doFilter(request, response);
return;
}
String token = authorizationHeader.replace(jwtConfig.getTokenPrefix(), "");
try {
Jws<Claims> claimsJws = Jwts.parser()
.setSigningKey(secretKey)
.parseClaimsJws(token);
Claims body = claimsJws.getBody();
String username = body.getSubject();
var authorities = (List<Map<String, String>>) body.get("authorities");
Set<SimpleGrantedAuthority> simpleGrantedAuthorities = authorities.stream()
.map(m -> new SimpleGrantedAuthority(m.get("authority")))
.collect(Collectors.toSet());
Authentication authentication = new UsernamePasswordAuthenticationToken(
username,
null,
simpleGrantedAuthorities
);
SecurityContextHolder.getContext().setAuthentication(authentication);
} catch (JwtException e) {
throw new IllegalStateException(String.format("Token %s cannot be trusted", token));
}
filterChain.doFilter(request, response);
}
}
JwtUsernameAndPasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter, and by default its triggered when you make a "POST" call to "/login". This can be changed by calling the setFilterProcessesUrl(<PATH_HERE>) in the JwtUsernameAndPasswordAuthenticationFilter's constructor.
You don't keep the password in the Authentication object simply because it's not needed, and it's safer to keep the password off-memory because anyone with access to the memory dump can retrieve the password.

JWT Bearer token not received?

I want to use Spring security to perform authentication and authorization on 2 separated server.
I've authenticated successfully and received a JWT token on the first server.
Now I am sending a request to the second server with the JWT authorization token, but the server can't see it; basically getHeader() from getJwtFromRequest(HttpServletRequest request) returns null.
This is the server code:
//imports...
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(
securedEnabled = true,
jsr250Enabled = true,
prePostEnabled = true
)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
CustomUserDetailsService customUserDetailsService;
#Autowired
private JwtAuthenticationEntryPoint unauthorizedHandler;
#Bean
public JwtAuthenticationFilter jwtAuthenticationFilter() {
return new JwtAuthenticationFilter();
}
#Override
public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder
.userDetailsService(customUserDetailsService)
.passwordEncoder(passwordEncoder());
}
#Bean(BeanIds.AUTHENTICATION_MANAGER)
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors()
.and()
.csrf()
.disable()
.exceptionHandling()
.authenticationEntryPoint(unauthorizedHandler)
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/",
"/favicon.ico",
"/**/*.png",
"/**/*.gif",
"/**/*.svg",
"/**/*.jpg",
"/**/*.html",
"/**/*.css",
"/**/*.js")
.permitAll()
.antMatchers("/api/auth/**")
.permitAll()
.antMatchers("/api/user/checkUsernameAvailability", "/api/user/checkEmailAvailability")
.permitAll()
.antMatchers(HttpMethod.GET, "/api/polls/**", "/api/users/**")
.permitAll()
.anyRequest()
.authenticated();
// Add our custom JWT security filter
http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}
}
//imports...
public class JwtAuthenticationFilter extends OncePerRequestFilter {
#Autowired
private JwtTokenProvider tokenProvider;
#Autowired
private CustomUserDetailsService customUserDetailsService;
private static final Logger logger = LoggerFactory.getLogger(JwtAuthenticationFilter.class);
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
try {
String jwt = getJwtFromRequest(request);
if (StringUtils.hasText(jwt) && tokenProvider.validateToken(jwt)) {
Long userId = tokenProvider.getUserIdFromJWT(jwt);
UserDetails userDetails = customUserDetailsService.loadUserById(userId);
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
} catch (Exception ex) {
logger.error("Could not set user authentication in security context", ex);
}
filterChain.doFilter(request, response);
}
private String getJwtFromRequest(HttpServletRequest request) {
String bearerToken = request.getHeader("Authorization");
// bearerToken prints null!
System.out.println("AUTHORIZATION: "+bearerToken);
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
return bearerToken.substring(7, bearerToken.length());
}
return null;
}
}
But the token is present on the request:
The authorization header was stripped on the edge server

Spring Security Access Denied Handler is called when the HttpServletResponse is already committed

I have an HTTP API, protected with Spring Security and JWT.
I get a 401 when I'm trying to access a protected resource.
I get the resource if I'm authenticated (JWT is valid) and I have the correct role. The resource is protected with #PreAuthorize("hasRole('USER')").
The issue I have is that when I don't have the correct role I'd like to return a 403 (in the following code it is a 401 for the sake of testing).
But right know I get a 500 because of the AccessDeniedException which is thrown when the role is incorrect.
The weird thing is that it goes to my JwtAccessDeniedHandler custom code but the response is already committed (isCommitted() == true) so whenever I try to set the status etc it does nothing.
Do you have any ideas about what could be misconfigured or missing?
Config:
#Slf4j
#EnableWebSecurity
#EnableGlobalMethodSecurity(
prePostEnabled = true,
securedEnabled = true,
jsr250Enabled = true
)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private ObjectMapper objectMapper;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.addFilterBefore(
jwtAuthenticationFilter(joseHelper(jsonWebKey())),
UsernamePasswordAuthenticationFilter.class)
.authorizeRequests()
.antMatchers("/auth/**").permitAll()
.anyRequest().authenticated()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.csrf().disable()
.exceptionHandling()
.authenticationEntryPoint(new JwtAuthenticationEntryPoint())
.accessDeniedHandler(new JwtAccessDeniedHandler());
}
#Bean
public JwtAuthenticationFilter jwtAuthenticationFilter(JoseHelper joseHelper) {
return new JwtAuthenticationFilter(joseHelper);
}
#Bean
public JoseHelper joseHelper(PublicJsonWebKey key) {
return new JoseHelper(key);
}
#Bean
public PublicJsonWebKey jsonWebKey() throws IOException, JoseException {
return RsaJwkGenerator.generateJwk(2048);
}
private void sendUnauthorized(HttpServletResponse httpServletResponse) throws IOException {
httpServletResponse.setContentType("application/json");
httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
ApiError apiError = ApiError.builder()
.code(HttpStatus.UNAUTHORIZED.name())
.message(HttpStatus.UNAUTHORIZED.getReasonPhrase())
.httpStatus(HttpStatus.UNAUTHORIZED)
.build();
httpServletResponse.getWriter().print(objectMapper.writeValueAsString(apiError));
}
private class JwtAccessDeniedHandler implements AccessDeniedHandler {
#Override
public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {
log.info("accessDeniedHandler", e);
sendUnauthorized(httpServletResponse);
}
}
private class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
#Override
public void commence(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
AuthenticationException e) throws IOException, ServletException {
sendUnauthorized(httpServletResponse);
}
}
}
Filter:
#Slf4j
#Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
private static final String BEARER = "Bearer ";
private JoseHelper joseHelper;
#Autowired
public JwtAuthenticationFilter(JoseHelper joseHelper) {
this.joseHelper = joseHelper;
}
#Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
String header = httpServletRequest.getHeader("Authorization");
if (header == null || !header.startsWith(BEARER)) {
log.error("JWT token is not valid");
filterChain.doFilter(httpServletRequest, httpServletResponse);
return;
}
final String encryptedToken = header.substring(BEARER.length());
try {
final String decryptedJwt = joseHelper.decryptJwt(encryptedToken);
final String verifiedJwt = joseHelper.verifyJwt(decryptedJwt);
final JwtClaims jwtClaims = joseHelper.parse(verifiedJwt);
List<SimpleGrantedAuthority> authorities = jwtClaims.getStringListClaimValue("userRoles")
.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList());
JwtAuthenticationToken jwtAuthenticationToken = new JwtAuthenticationToken(jwtClaims, null, authorities);
SecurityContextHolder.getContext().setAuthentication(jwtAuthenticationToken);
filterChain.doFilter(httpServletRequest, httpServletResponse);
} catch (JoseException | InvalidJwtException | MalformedClaimException e) {
log.error("JWT token is not valid", e);
filterChain.doFilter(httpServletRequest, httpServletResponse);
}
}
}
The issue was because I use Jersey apparently. I didn't really had time to investigate the why right now.
Once I registered an exception mapper in my JerseyConfig I was able to capture and handle the AccessDeniedException correctly.
And from that point the access denied handler is not called anymore and becomes useless.
A bit weird, but there is probably a good reason.

Unable to redirect to CAS for single log out from spring

I am developing an application which has an angular2 frontend and a spring boot backend. For the authentication I am using CAS. Single sign on is working properly, but the single log out is not working and not even redirecting to cas/logout endpoint.(I am sending a POST to my spring boot app's /logout url from angular app )
CAS version - 4.2.2
CAS client core - 3.4
I followed http://docs.spring.io/spring-security/site/migrate/current/3-to-4/html5/migrate-3-to-4-jc.html#m3to4-filter-urls-cas and did necessary changes to Authentication Filter and Logout filter. But still I couldn't identify the issue. Any help is much appreciated.
Security Config
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true, jsr250Enabled = true)
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private AuthProperties properties;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.addFilterAfter(csrfHeaderFilter(), CsrfFilter.class)
.addFilterBefore(requestSingleLogoutFilter(), LogoutFilter.class)
.addFilterBefore(singleSignOutFilter(), CasAuthenticationFilter.class)
.addFilterBefore(casAuthenticationFilter(), BasicAuthenticationFilter.class)
.exceptionHandling()
.authenticationEntryPoint(casAuthenticationEntryPoint())
.and()
.logout()
.logoutUrl("/logout")
.invalidateHttpSession(true)
.deleteCookies("JSESSIONID")
.permitAll()
.and()
.authorizeRequests()
.antMatchers("//**").authenticated()
.antMatchers("/test").permitAll()
.and()
.csrf()
.csrfTokenRepository(csrfTokenRepository());
}
/***
* Service Properties refer to the application which is being authenticated
* Typically in this case, the service is the authentication engine or auth app
*/
#Bean
public ServiceProperties serviceProperties() {
ServiceProperties sp = new ServiceProperties();
sp.setService(properties.getAppServiceSecurity());
sp.setArtifactParameter("casTicket");
sp.setAuthenticateAllArtifacts(true);
sp.setSendRenew(false);
return sp;
}
#Bean
public CasAuthenticationProvider casAuthenticationProvider() throws Exception {
CasAuthenticationProvider casAuthenticationProvider = new CasAuthenticationProvider();
casAuthenticationProvider.setAuthenticationUserDetailsService(userService());
casAuthenticationProvider.setServiceProperties(serviceProperties());
if (properties.isCasProxyTicket()) {
casAuthenticationProvider.setTicketValidator(cas30ServiceProxyTicketValidator());
casAuthenticationProvider.setStatelessTicketCache(ehManager());
} else {
casAuthenticationProvider.setTicketValidator(cas30ServiceTicketValidator());
}
casAuthenticationProvider.setKey(properties.getProviderKey());
return casAuthenticationProvider;
}
#Bean
public SessionAuthenticationStrategy sessionStrategy() {
SessionAuthenticationStrategy sessionStrategy = new SessionFixationProtectionStrategy();
return sessionStrategy;
}
#Bean
public Cas30ServiceTicketValidator cas30ServiceTicketValidator() {
return new Cas30ServiceTicketValidator(properties.getCasUrlPrefix());
}
#Bean
public CasAuthenticationFilter casAuthenticationFilter() throws Exception {
CasAuthenticationFilter casAuthenticationFilter = new CasAuthenticationFilter();
casAuthenticationFilter.setAuthenticationManager(authenticationManager());
casAuthenticationFilter.setSessionAuthenticationStrategy(sessionStrategy());
casAuthenticationFilter.setProxyGrantingTicketStorage(pgtStorage());
casAuthenticationFilter.setFilterProcessesUrl("/login/cas");
casAuthenticationFilter.setProxyReceptorUrl(properties.getCasProxyReceptor());
return casAuthenticationFilter;
}
#Bean
public CasAuthenticationEntryPoint casAuthenticationEntryPoint() {
CasAuthenticationEntryPoint casAuthenticationEntryPoint = new TBXCasAuthenticationEntryPoint();
casAuthenticationEntryPoint.setLoginUrl(properties.getCasLoginUrl());
casAuthenticationEntryPoint.setServiceProperties(serviceProperties());
return casAuthenticationEntryPoint;
}
#Bean
public LogoutFilter requestSingleLogoutFilter() {
StringBuffer stringBuffer = new StringBuffer("");
stringBuffer.append(properties.getCasLogoutUrl());
LogoutFilter logoutFilter = new LogoutFilter("https://localhost:9443/cas/logout", new SecurityContextLogoutHandler());//env.getRequiredProperty(CAS_URL_LOGOUT) + "?service="+ env.getRequiredProperty(APP_SERVICE_HOME)
logoutFilter.setFilterProcessesUrl("/logout");
return logoutFilter;
}
#Bean
public SingleSignOutFilter singleSignOutFilter() {
SingleSignOutFilter filter = new SingleSignOutFilter();
filter.setArtifactParameterName(Protocol.CAS3.getArtifactParameterName());
filter.setCasServerUrlPrefix("https://localhost:9443/cas");
filter.setIgnoreInitConfiguration(true);
return filter;
}
#Bean
public Filter csrfHeaderFilter() {
return new OncePerRequestFilter() {
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
if (csrf != null) {
Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
if (cookie != null) {
} else {
}
String token = csrf.getToken();
if (cookie == null || token != null && !token.equals(cookie.getValue())) {
cookie = new Cookie("XSRF-TOKEN", token);
cookie.setPath("/");
response.addCookie(cookie);
}
}
filterChain.doFilter(request, response);
}
};
}
#Bean
public CsrfTokenRepository csrfTokenRepository() {
HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
repository.setHeaderName("X-XSRF-TOKEN");
return repository;
}
/**
* configure via WebSecurity provides the fonts, images, scripts, styles and views to be removed
* from the security features, because, access to these scripts is a must regarding the user experience
**/
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers("/fonts*//**")
.antMatchers("/images1*//**")
.antMatchers("/scripts*//**")
.antMatchers("/styles*//**")
.antMatchers("/views*//**")
.antMatchers("/i18n*//**");
}
#Bean
public UserPrincipleHandler userService() {
UserPrincipleHandler userPrincipleServiceHanlder = new UserPrincipleHandler();
return userPrincipleServiceHanlder;
}
#Bean
public RequestContextListener requestContextListener() {
return new RequestContextListener();
}
#Bean
public RequestContextFilter requestContextFilter() {
return new RequestContextFilter();
}
#Bean
public ServiceAuthenticationDetailsSource serviceAuthenticationDataSource() {
ServiceAuthenticationDetailsSource serviceDetailSource = new ServiceAuthenticationDetailsSource(serviceProperties());
return serviceDetailSource;
}
#Bean
public SimpleUrlAuthenticationFailureHandler simpleUrlAuthentication() {
SimpleUrlAuthenticationFailureHandler failureHandler = new SimpleUrlAuthenticationFailureHandler();
failureHandler.setDefaultFailureUrl(properties.getCasFailureUrl());
return failureHandler;
}
#Bean
public ProxyList proxyChainList() {
List<String> list = properties.getProxyList();
String[] stringArray = Arrays.copyOf(list.toArray(), list.size(), String[].class);
List<String[]> urls = new ArrayList<String[]>();
urls.add(stringArray);
ProxyList proxyList = new ProxyList(urls);
return proxyList;
}
#Bean
public ProxyGrantingTicketStorageImpl pgtStorage() {
ProxyGrantingTicketStorageImpl pgtImpl = new ProxyGrantingTicketStorageImpl();
return pgtImpl;
}
#Bean
public SpringCacheBasedTicketCache ehManager() throws Exception {
SpringCacheBasedTicketCache ehmanager = new SpringCacheBasedTicketCache(cacheMap());
return ehmanager;
}
#Bean
public ConcurrentMapCache cacheMap() {
ConcurrentMapCache conCacheMap = new ConcurrentMapCache("casTickets");
conCacheMap.put("casTickets", 50);
return conCacheMap;
}
#Bean
public Cas30ProxyTicketValidator cas30ServiceProxyTicketValidator() {
Cas30ProxyTicketValidator validator = new Cas30ProxyTicketValidator(properties.getCasUrlPrefix());//env.getRequiredProperty(CAS_URL_PREFIX)
StringBuffer stringBuffer = new StringBuffer("");
stringBuffer.append(properties.getAppServiceHome()).append(properties.getCasProxyReceptor());
validator.setProxyCallbackUrl(stringBuffer.toString());//env.getRequiredProperty(APP_SERVICE_HOME)+"login/cas/proxyreceptor"
validator.setProxyGrantingTicketStorage(pgtStorage());
validator.setAllowedProxyChains(proxyChainList());
validator.setAcceptAnyProxy(false);
return validator;
}
}

Resources