title: WebSecurityConfiguration antMatcher() not ignoring specific url for external API in integration test
body: <p>I am while implementation of AWS Cognito security mechanism in my Spring Boot application. I met a problem with already existing integration test for external API after enabling security.
  As a test result I am receiving an error:</p>
  <blockquote>
  <p>2020-11-15 18:18:20.033 ERROR 12072 --- [           main]
  .c.s.f.AwsCognitoJwtAuthenticationFilter : Invalid Action, no token
  found MockHttpServletResponse:
  Status = 401
  Error message = null
  Headers = [Access-Control-Allow-Origin:&quot;*&quot;, Access-Control-Allow-Methods:&quot;POST, GET, OPTIONS, PUT, DELETE&quot;,
  Access-Control-Max-Age:&quot;3600&quot;,
  Access-Control-Allow-Credentials:&quot;true&quot;,
  Access-Control-Allow-Headers:&quot;content-type,Authorization&quot;,
  Content-Type:&quot;application/json&quot;]
  Content type = application/json
  Body = {&quot;data&quot;:null,&quot;exception&quot;:{&quot;message&quot;:&quot;JWT Handle exception&quot;,&quot;httpStatusCode&quot;:&quot;INTERNAL_SERVER_ERROR&quot;,&quot;detail&quot;:null}}</p>
  </blockquote>
  <p>My <code>WebSecurityConfiguration</code> looks like:</p>
  <pre><code>@Configuration
  @EnableWebSecurity
  @EnableGlobalMethodSecurity(prePostEnabled = true)
  @EnableTransactionManagement
  public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
  
    private CustomAuthenticationProvider authProvider;
    private AwsCognitoJwtAuthenticationFilter awsCognitoJwtAuthenticationFilter;
    private AccountControllerExceptionHandler exceptionHandler;
    private static final String LOGIN_URL = &quot;/auth/login&quot;;
    private static final String LOGOUT_URL = &quot;/auth/signOut&quot;;
  
    @Autowired
    public WebSecurityConfiguration(
        CustomAuthenticationProvider authProvider,
        AwsCognitoJwtAuthenticationFilter awsCognitoJwtAuthenticationFilter,
        AccountControllerExceptionHandler exceptionHandler) {
      this.authProvider = authProvider;
      this.awsCognitoJwtAuthenticationFilter = awsCognitoJwtAuthenticationFilter;
      this.exceptionHandler = exceptionHandler;
    }
  
    public WebSecurityConfiguration() {
      super(true);
    }
  
    @Override
    protected void configure(AuthenticationManagerBuilder auth) {
      auth.authenticationProvider(authProvider).eraseCredentials(false);
    }
  
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
      return super.authenticationManagerBean();
    }
  
    @Override
    public void configure(WebSecurity web) {
      // TokenAuthenticationFilter will ignore the below paths
      web.ignoring().antMatchers(&quot;/auth&quot;);
      web.ignoring().antMatchers(&quot;/auth/**&quot;);
      web.ignoring().antMatchers(&quot;/v2/api-docs&quot;);
      web.ignoring().antMatchers(GET, &quot;/nutrition/api/**&quot;);
      web.ignoring().antMatchers(GET, &quot;/**&quot;);
      web.ignoring().antMatchers(HttpMethod.OPTIONS, &quot;/**&quot;);
    }
  
    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
      httpSecurity
          .addFilterAfter(corsFilter(), ExceptionTranslationFilter.class)
          .exceptionHandling()
          .authenticationEntryPoint(new SecurityAuthenticationEntryPoint())
          .accessDeniedHandler(new RestAccessDeniedHandler())
          .and()
          .anonymous()
          .and()
          .sessionManagement()
          .sessionCreationPolicy(STATELESS)
          .and()
          .authorizeRequests()
          .antMatchers(&quot;/auth&quot;)
          .permitAll()
          .anyRequest()
          .authenticated()
          .and()
          .addFilterBefore(
              awsCognitoJwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
          .formLogin(formLogin -&gt; formLogin.loginProcessingUrl(LOGIN_URL).failureHandler(exceptionHandler))
          .logout(logout -&gt; logout.permitAll().logoutUrl(LOGOUT_URL))
          .csrf(AbstractHttpConfigurer::disable);
    }
  
    private CorsFilter corsFilter() {
      UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
  
      CorsConfiguration config = new CorsConfiguration();
      config.setAllowCredentials(true);
      config.addAllowedOrigin(&quot;*&quot;);
      config.addAllowedHeader(ORIGIN);
      config.addAllowedHeader(CONTENT_TYPE);
      config.addAllowedHeader(ACCEPT);
      config.addAllowedHeader(AUTHORIZATION);
      config.addAllowedMethod(GET);
      config.addAllowedMethod(PUT);
      config.addAllowedMethod(POST);
      config.addAllowedMethod(OPTIONS);
      config.addAllowedMethod(DELETE);
      config.addAllowedMethod(PATCH);
      config.setMaxAge(3600L);
  
      source.registerCorsConfiguration(&quot;/v2/api-docs&quot;, config);
      source.registerCorsConfiguration(&quot;/**&quot;, config);
  
      return new CorsFilter();
    }
  }
  
  </code></pre>
  <p><code>AwsCognitoJwtAuthenticationFilter</code></p>
  <pre><code>@Slf4j
  public class AwsCognitoJwtAuthenticationFilter extends OncePerRequestFilter {
  
    private static final String ERROR_OCCURRED_WHILE_PROCESSING_THE_TOKEN =
        &quot;Error occured while processing the token&quot;;
    private static final String INVALID_TOKEN_MESSAGE = &quot;Invalid Token&quot;;
  
    private final AwsCognitoIdTokenProcessor awsCognitoIdTokenProcessor;
  
    @Autowired private ApplicationContext appContext;
  
    public AwsCognitoJwtAuthenticationFilter(AwsCognitoIdTokenProcessor awsCognitoIdTokenProcessor) {
      this.awsCognitoIdTokenProcessor = awsCognitoIdTokenProcessor;
    }
  
    private void createExceptionResponse(
        ServletRequest request, ServletResponse response, CognitoException exception)
        throws IOException {
      HttpServletRequest req = (HttpServletRequest) request;
      ExceptionController exceptionController;
      ObjectMapper objMapper = new ObjectMapper();
  
      exceptionController = appContext.getBean(ExceptionController.class);
      ResponseData&lt;Object&gt; responseData = exceptionController.handleJwtException(req, exception);
  
      HttpServletResponse httpResponse = CorsHelper.addResponseHeaders(response);
  
      final HttpServletResponseWrapper wrapper = new HttpServletResponseWrapper(httpResponse);
      wrapper.setStatus(HttpStatus.UNAUTHORIZED.value());
      wrapper.setContentType(APPLICATION_JSON_VALUE);
      wrapper.getWriter().println(objMapper.writeValueAsString(responseData));
      wrapper.getWriter().flush();
    }
  
    @Override
    protected void doFilterInternal(
        HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
        throws ServletException, IOException {
      Authentication authentication;
      try {
        authentication = awsCognitoIdTokenProcessor.getAuthentication(request);
  
        SecurityContextHolder.getContext().setAuthentication(authentication);
  
      } catch (BadJOSEException e) {
        SecurityContextHolder.clearContext();
        log.error(e.getMessage());
        createExceptionResponse(
            request,
            response,
            new CognitoException(
                INVALID_TOKEN_MESSAGE,
                CognitoException.INVALID_TOKEN_EXCEPTION_CODE,
                e.getMessage()));
        return;
      } catch (CognitoException e) {
        SecurityContextHolder.clearContext();
        log.error(e.getMessage());
        createExceptionResponse(
            request,
            response,
            new CognitoException(
                e.getErrorMessage(),
                CognitoException.INVALID_TOKEN_EXCEPTION_CODE,
                e.getDetailErrorMessage()));
        return;
      } catch (Exception e) {
        SecurityContextHolder.clearContext();
        log.error(e.getMessage());
        createExceptionResponse(
            request,
            response,
            new CognitoException(
                ERROR_OCCURRED_WHILE_PROCESSING_THE_TOKEN,
                CognitoException.INVALID_TOKEN_EXCEPTION_CODE,
                e.getMessage()));
        return;
      }
  
      filterChain.doFilter(request, response);
    }
  }
  
  </code></pre>
  <p><code>AwsCognitoIdTokenProcessor</code></p>
  <pre><code>@AllArgsConstructor
  @NoArgsConstructor
  public class AwsCognitoIdTokenProcessor {
  
    private static final String INVALID_TOKEN = &quot;Invalid Token&quot;;
    private static final String NO_TOKEN_FOUND = &quot;Invalid Action, no token found&quot;;
  
    private static final String ROLE_PREFIX = &quot;ROLE_&quot;;
    private static final String EMPTY_STRING = &quot;&quot;;
  
    private ConfigurableJWTProcessor&lt;SecurityContext&gt; configurableJWTProcessor;
  
    private AWSConfig jwtConfiguration;
  
    private String extractAndDecodeJwt(String token) {
      String tokenResult = token;
  
      if (token != null &amp;&amp; token.startsWith(&quot;Bearer &quot;)) {
        tokenResult = token.substring(&quot;Bearer &quot;.length());
      }
      return tokenResult;
    }
  
    @SuppressWarnings(&quot;unchecked&quot;)
    public Authentication getAuthentication(HttpServletRequest request)
        throws ParseException, BadJOSEException, JOSEException {
      String idToken = request.getHeader(HTTP_HEADER);
      if (idToken == null) {
        throw new CognitoException(
            NO_TOKEN_FOUND,
            NO_TOKEN_PROVIDED_EXCEPTION,
            &quot;No token found in Http Authorization Header&quot;);
      } else {
  
        idToken = extractAndDecodeJwt(idToken);
        JWTClaimsSet claimsSet;
  
        claimsSet = configurableJWTProcessor.process(idToken, null);
  
        if (!isIssuedCorrectly(claimsSet)) {
          throw new CognitoException(
              INVALID_TOKEN,
              INVALID_TOKEN_EXCEPTION_CODE,
              String.format(
                  &quot;Issuer %s in JWT token doesn't match cognito idp %s&quot;,
                  claimsSet.getIssuer(), jwtConfiguration.getCognitoIdentityPoolUrl()));
        }
  
        if (!isIdToken(claimsSet)) {
          throw new CognitoException(
              INVALID_TOKEN, NOT_A_TOKEN_EXCEPTION, &quot;JWT Token doesn't seem to be an ID Token&quot;);
        }
  
        String username = claimsSet.getClaims().get(USER_NAME_FIELD).toString();
  
        List&lt;String&gt; groups = (List&lt;String&gt;) claimsSet.getClaims().get(COGNITO_GROUPS);
        List&lt;GrantedAuthority&gt; grantedAuthorities =
            convertList(
                groups, group -&gt; new SimpleGrantedAuthority(ROLE_PREFIX + group.toUpperCase()));
        User user = new User(username, EMPTY_STRING, grantedAuthorities);
        return new CognitoJwtAuthentication(user, claimsSet, grantedAuthorities);
      }
    }
  
    private boolean isIssuedCorrectly(JWTClaimsSet claimsSet) {
      return claimsSet.getIssuer().equals(jwtConfiguration.getCognitoIdentityPoolUrl());
    }
  
    private boolean isIdToken(JWTClaimsSet claimsSet) {
      return claimsSet.getClaim(&quot;token_use&quot;).equals(&quot;id&quot;);
    }
  
    private static &lt;T, U&gt; List&lt;U&gt; convertList(List&lt;T&gt; from, Function&lt;T, U&gt; func) {
      return from.stream().map(func).collect(Collectors.toList());
    }
  }
  
  </code></pre>
  <p><code>CognitoJwtAutoConfiguration</code></p>
  <pre><code>@Configuration
  @Import(AWSConfig.class)
  @ConditionalOnClass({AwsCognitoJwtAuthenticationFilter.class, AwsCognitoIdTokenProcessor.class})
  public class CognitoJwtAutoConfiguration {
  
    private final AWSConfig jwtConfiguration;
  
    public CognitoJwtAutoConfiguration(AWSConfig jwtConfiguration) {
      this.jwtConfiguration = jwtConfiguration;
    }
  
    @Bean
    @Scope(value = &quot;request&quot;, proxyMode = ScopedProxyMode.TARGET_CLASS)
    public CognitoJwtIdTokenCredentialsHolder awsCognitoCredentialsHolder() {
      return new CognitoJwtIdTokenCredentialsHolder();
    }
  
    @Bean
    public AwsCognitoIdTokenProcessor awsCognitoIdTokenProcessor() {
      return new AwsCognitoIdTokenProcessor();
    }
  
    @Bean
    public CognitoJwtAuthenticationProvider jwtAuthenticationProvider() {
      return new CognitoJwtAuthenticationProvider();
    }
  
    @Bean
    public AwsCognitoJwtAuthenticationFilter awsCognitoJwtAuthenticationFilter() {
      return new AwsCognitoJwtAuthenticationFilter(awsCognitoIdTokenProcessor());
    }
  
    @SuppressWarnings({&quot;rawtypes&quot;, &quot;unchecked&quot;})
    @Bean
    public ConfigurableJWTProcessor configurableJWTProcessor() throws MalformedURLException {
      ResourceRetriever resourceRetriever =
          new DefaultResourceRetriever(CONNECTION_TIMEOUT, READ_TIMEOUT);
      // https://cognito-idp.{region}.amazonaws.com/{userPoolId}/.well-known/jwks.json.
      URL jwkSetURL = new URL(jwtConfiguration.getJwkUrl());
      // Creates the JSON Web Key (JWK)
      JWKSource keySource = new RemoteJWKSet(jwkSetURL, resourceRetriever);
      ConfigurableJWTProcessor jwtProcessor = new DefaultJWTProcessor();
      JWSKeySelector keySelector = new JWSVerificationKeySelector(RS256, keySource);
      jwtProcessor.setJWSKeySelector(keySelector);
      return jwtProcessor;
    }
  
    @Bean
    public AWSCognitoIdentityProvider awsCognitoIdentityProvider() {
      return AWSCognitoIdentityProviderClientBuilder.standard()
          .withRegion(Regions.EU_CENTRAL_1)
          .withCredentials(getCredentialsProvider())
          .build();
    }
  
    @Bean
    public AWSCredentialsProvider getCredentialsProvider() {
      return new ClasspathPropertiesFileCredentialsProvider();
    }
  }
  </code></pre>
  <p>I want to exclude my controller URL from being considered as an endpoint which requires authorization.</p>
  <p>Based on sight tested controller looks like:</p>
  <pre><code>@RestController
  @RequestMapping(&quot;/nutrition/api/&quot;)
  class NutritionixApiController {
  
    private ProductFacadeImpl productFacadeImpl;
  
    public NutritionixApiController(
        ProductFacadeImpl productFacadeImpl) {
      this.productFacadeImpl = productFacadeImpl;
    }
  
    @GetMapping(&quot;/productDetails&quot;)
    public ResponseEntity&lt;Set&lt;RecipeIngredient&gt;&gt; productsDetails(@RequestParam String query) {
    //logic here
    }
  }
  </code></pre>
  <p>I have tried to whitelist URL <code>&quot;/nutrition/api/**&quot;</code> in method <code>configure(WebSecurity web)</code>
  aby adding:</p>
  <pre><code>web.ignoring().antMatchers(GET, &quot;/nutrition/api/**&quot;);
  </code></pre>
  <p>or</p>
  <pre><code>web.ignoring().antMatchers(GET, &quot;/**&quot;);
  </code></pre>
  <p>but without desirable effect. I am a little bit confused about why <code>ignoring.antMatchers()</code> not working so I will be grateful for suggestions on how to fix the above problem.</p>
  <p>EDIT</p>
  <p>I came back to the topic but with the same result. In <code>WebSecurityConfiguration</code> I commented out <code>@EnableGlobalMethodSecurity(prePostEnabled = true)</code> to try configuration without <code>prePostEnabled = true</code> but without desirable effect. I have the same problem with endpoint <code>/auth</code> which is ignored in the configuration.
  I patterned after tutorial which is working and available here <a href="https://github.com/ihuaylupo/cognitoAuthentication" rel="nofollow noreferrer">click</a>
  but I refactored my code a little to get rid of field injection with <code>@Autowired</code> but without doing radical changes and logic under the hood.</p>
  <p>Moreover class <code>CustomAuthenticationProvider</code> looks like:</p>
  <pre><code>@Component
  @RequiredArgsConstructor
  public class CustomAuthenticationProvider implements AuthenticationProvider {
  
    private final CognitoAuthenticationService cognitoService;
  
    @SuppressWarnings(&quot;unchecked&quot;)
    @Override
    public Authentication authenticate(Authentication authentication) {
      AuthenticationRequest authenticationRequest;
  
      if (authentication != null) {
        authenticationRequest = new AuthenticationRequest();
        Map&lt;String, String&gt; credentials = (Map&lt;String, String&gt;) authentication.getCredentials();
        authenticationRequest.setNewPassword(credentials.get(NEW_PASS_WORD_KEY));
        authenticationRequest.setPassword(credentials.get(PASS_WORD_KEY));
        authenticationRequest.setUsername(authentication.getName());
  
        SpringSecurityUser userAuthenticated = cognitoService.authenticate(authenticationRequest);
        if (userAuthenticated != null) {
  
          Map&lt;String, String&gt; authenticatedCredentials = new HashMap&lt;&gt;();
          authenticatedCredentials.put(ACCESS_TOKEN_KEY, userAuthenticated.getAccessToken());
          authenticatedCredentials.put(EXPIRES_IN_KEY, userAuthenticated.getExpiresIn().toString());
          authenticatedCredentials.put(ID_TOKEN_KEY, userAuthenticated.getIdToken());
          authenticatedCredentials.put(PASS_WORD_KEY, userAuthenticated.getPassword());
          authenticatedCredentials.put(REFRESH_TOKEN_KEY, userAuthenticated.getRefreshToken());
          authenticatedCredentials.put(TOKEN_TYPE_KEY, userAuthenticated.getTokenType());
          return new UsernamePasswordAuthenticationToken(
              userAuthenticated.getUsername(),
              authenticatedCredentials,
              userAuthenticated.getAuthorities());
        } else {
          return null;
        }
      } else {
        throw new UsernameNotFoundException(&quot;No application user for given username&quot;);
      }
    }
  
    @Override
    public boolean supports(Class&lt;?&gt; authentication) {
      return authentication.equals(UsernamePasswordAuthenticationToken.class);
    }
  }
  </code></pre>
  <p>To be honest I don't know what can be done more to solve this problem with not working filter. Will be grateful for help.</p>