1
0

Add the cors-csrf module

This commit is contained in:
2026-08-28 09:33:22 +05:30
parent 73ab67b171
commit cad813e1ae
49 changed files with 3338 additions and 13 deletions

View File

@@ -0,0 +1,58 @@
==============================================================================
docs/output/01-mvc-only.txt
CORS configured with WebMvcConfigurer.addCorsMappings and nothing else.
Profile: mvconly
==============================================================================
# The security chain. Note what is NOT in it.
$ curl -s localhost:8080/diag/chain
{
"profiles": [
"mvconly"
],
"chains": [
{
"size": 11,
"filters": [
"DisableEncodeUrlFilter",
"WebAsyncManagerIntegrationFilter",
"SecurityContextHolderFilter",
"HeaderWriterFilter",
"LogoutFilter",
"BasicAuthenticationFilter",
"RequestCacheAwareFilter",
"SecurityContextHolderAwareRequestFilter",
"AnonymousAuthenticationFilter",
"ExceptionTranslationFilter",
"AuthorizationFilter"
]
}
]
}
# CorsConfigurationSource beans in the context.
$ curl -s localhost:8080/diag/cors-sources
{
"corsConfigurationSourceBeans": {
"mvcHandlerMappingIntrospector": "HandlerMappingIntrospector"
},
"hasBeanNamedCorsConfigurationSource": false
}
$ curl -s -i -X OPTIONS http://localhost:8080/api/data \
-H 'Origin: https://spa.example.com' \
-H 'Access-Control-Request-Method: POST' \
-H 'Access-Control-Request-Headers: content-type,x-xsrf-token'
HTTP/1.1 401
Set-Cookie: JSESSIONID=<session>; Path=/; HttpOnly; SameSite=Lax
WWW-Authenticate: Basic realm="Realm", charset="UTF-8"
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
X-Frame-Options: DENY
# The MVC CORS mapping is real - it just never runs, because the request is
# rejected at AuthorizationFilter (order 4200) and the DispatcherServlet is
# downstream of the entire filter chain.

View File

@@ -0,0 +1,56 @@
==============================================================================
docs/output/02-mvc-bridge.txt
The identical MVC CORS mapping plus one line: .cors(Customizer.withDefaults()).
Profile: mvcbridge
==============================================================================
$ curl -s localhost:8080/diag/chain
{
"profiles": [
"mvcbridge"
],
"chains": [
{
"size": 12,
"filters": [
"DisableEncodeUrlFilter",
"WebAsyncManagerIntegrationFilter",
"SecurityContextHolderFilter",
"HeaderWriterFilter",
"CorsFilter",
"LogoutFilter",
"BasicAuthenticationFilter",
"RequestCacheAwareFilter",
"SecurityContextHolderAwareRequestFilter",
"AnonymousAuthenticationFilter",
"ExceptionTranslationFilter",
"AuthorizationFilter"
]
}
]
}
$ curl -s -i -X OPTIONS http://localhost:8080/api/data \
-H 'Origin: https://spa.example.com' \
-H 'Access-Control-Request-Method: POST' \
-H 'Access-Control-Request-Headers: content-type,x-xsrf-token'
HTTP/1.1 200
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Access-Control-Allow-Origin: https://spa.example.com
Access-Control-Allow-Methods: GET,POST
Access-Control-Allow-Headers: content-type, x-xsrf-token
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 1800
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
X-Frame-Options: DENY
# CorsFilter is now in the chain at order 1000, between HeaderWriterFilter (900)
# and CsrfFilter (1100), and it short-circuits the preflight before authorization
# ever sees it. Note Access-Control-Max-Age: 1800 - that default comes from MVC's
# CorsRegistration, not from CorsConfiguration.

View File

@@ -0,0 +1,36 @@
==============================================================================
docs/output/03-security-source.txt
A @Bean named corsConfigurationSource. .cors(..) is never called - it is applied for us.
Profile: securitysource
==============================================================================
$ curl -s localhost:8080/diag/cors-sources
{
"corsConfigurationSourceBeans": {
"corsConfigurationSource": "UrlBasedCorsConfigurationSource",
"mvcHandlerMappingIntrospector": "HandlerMappingIntrospector"
},
"hasBeanNamedCorsConfigurationSource": true
}
$ curl -s -i -X OPTIONS http://localhost:8080/api/data \
-H 'Origin: https://spa.example.com' \
-H 'Access-Control-Request-Method: POST' \
-H 'Access-Control-Request-Headers: content-type,x-xsrf-token'
HTTP/1.1 200
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Access-Control-Allow-Origin: https://spa.example.com
Access-Control-Allow-Methods: GET,POST
Access-Control-Allow-Headers: content-type, x-xsrf-token
Access-Control-Allow-Credentials: true
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
X-Frame-Options: DENY
# Compare with 02: there is no Access-Control-Max-Age here. CorsConfiguration
# leaves maxAge null, so every single cross-origin call re-runs the preflight.

View File

@@ -0,0 +1,47 @@
==============================================================================
docs/output/04-three-identical-403s.txt
Origin not allowed, method not allowed, header not allowed. One status, one shape.
Profile: securitysource, CORS_LOG_LEVEL=DEBUG
==============================================================================
# 1. disallowed origin
HTTP/1.1 403
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
X-Frame-Options: DENY
# 2. disallowed method
HTTP/1.1 403
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
X-Frame-Options: DENY
# 3. disallowed request header
HTTP/1.1 403
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
X-Frame-Options: DENY
# body of a rejected preflight:
Invalid CORS request
# The only thing that distinguishes them is a DEBUG line from DefaultCorsProcessor:
<timestamp> DEBUG <pid> --- [cors-csrf-samesite] [nio-8080-exec-N] o.s.web.cors.DefaultCorsProcessor : Reject: 'https://evil.example.com' origin is not allowed
<timestamp> DEBUG <pid> --- [cors-csrf-samesite] [nio-8080-exec-N] o.s.web.cors.DefaultCorsProcessor : Reject: HTTP 'DELETE' is not allowed
<timestamp> DEBUG <pid> --- [cors-csrf-samesite] [nio-8080-exec-N] o.s.web.cors.DefaultCorsProcessor : Reject: headers '[authorization]' are not allowed
<timestamp> DEBUG <pid> --- [cors-csrf-samesite] [nio-8080-exec-N] o.s.web.cors.DefaultCorsProcessor : Reject: 'https://evil.example.com' origin is not allowed

View File

@@ -0,0 +1,39 @@
==============================================================================
docs/output/05-misnamed-bean.txt
The same UrlBasedCorsConfigurationSource bean, named apiCorsSource instead of
corsConfigurationSource. It starts. The preflight returns 200. It carries no CORS headers.
Profile: misnamed
==============================================================================
$ curl -s localhost:8080/diag/cors-sources
{
"corsConfigurationSourceBeans": {
"apiCorsSource": "UrlBasedCorsConfigurationSource",
"mvcHandlerMappingIntrospector": "HandlerMappingIntrospector"
},
"hasBeanNamedCorsConfigurationSource": false
}
$ curl -s -i -X OPTIONS http://localhost:8080/api/data \
-H 'Origin: https://spa.example.com' \
-H 'Access-Control-Request-Method: POST' \
-H 'Access-Control-Request-Headers: content-type,x-xsrf-token'
HTTP/1.1 200
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
X-Frame-Options: DENY
<timestamp> DEBUG <pid> --- [cors-csrf-samesite] [nio-8080-exec-N] o.s.web.cors.DefaultCorsProcessor : Skip: no CORS configuration has been provided
# Two different lookups. HttpSecurityConfiguration.applyCorsIfAvailable asks
# getBeanNamesForType(UrlBasedCorsConfigurationSource.class) and enables CORS if the
# array is non-empty, so the bean above DID switch the configurer on.
# CorsConfigurer.getCorsConfigurationSource then asks
# containsBeanDefinition("corsConfigurationSource"), which is false, and falls back
# to Spring MVC's registrations - of which there are none.
# CorsFilter returns from every preflight whether or not it found a configuration:
# if (!isValid || CorsUtils.isPreFlightRequest(request)) { return; }
# so the OPTIONS never reaches AuthorizationFilter and the client gets a bare 200.

View File

@@ -0,0 +1,44 @@
==============================================================================
docs/output/06-two-sources.txt
Two UrlBasedCorsConfigurationSource beans. The reference documentation says Spring Security
'won't automatically configure CORS support for you, because it cannot decide which one to
use'. In 7.1.1 it configures it, and the bean NAME decides.
Profile: twosources
==============================================================================
{
"corsConfigurationSourceBeans": {
"corsConfigurationSource": "UrlBasedCorsConfigurationSource",
"adminCorsSource": "UrlBasedCorsConfigurationSource",
"mvcHandlerMappingIntrospector": "HandlerMappingIntrospector"
},
"hasBeanNamedCorsConfigurationSource": true
}
# the origin allowed by the bean named corsConfigurationSource:
HTTP/1.1 200
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Access-Control-Allow-Origin: https://spa.example.com
Access-Control-Allow-Methods: GET,POST
Access-Control-Allow-Headers: content-type
Access-Control-Allow-Credentials: true
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
X-Frame-Options: DENY
# the origin allowed by adminCorsSource, which is never consulted:
HTTP/1.1 403
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
X-Frame-Options: DENY
<timestamp> DEBUG <pid> --- [cors-csrf-samesite] [nio-8080-exec-N] o.s.web.cors.DefaultCorsProcessor : Reject: 'https://admin.example.com' origin is not allowed

View File

@@ -0,0 +1,41 @@
==============================================================================
docs/output/07-wildcard-credentials.txt
allowedOrigins("*") together with allowCredentials(true). Legal to configure, illegal to
serve. The failure is thrown on the request, not at startup - and it does not surface as a 500.
Profile: wildcard
==============================================================================
HTTP/1.1 401
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
X-Frame-Options: DENY
Set-Cookie: JSESSIONID=<session>; Path=/; HttpOnly; SameSite=Lax
WWW-Authenticate: Basic realm="Realm", charset="UTF-8"
# and a plain authenticated GET, with correct credentials:
HTTP/1.1 401
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
X-Frame-Options: DENY
Set-Cookie: JSESSIONID=<session>; Path=/; HttpOnly; SameSite=Lax
WWW-Authenticate: Basic realm="Realm", charset="UTF-8"
java.lang.IllegalArgumentException: When allowCredentials is true, allowedOrigins cannot contain the special value "*" since that cannot be set on the "Access-Control-Allow-Origin" response header. To allow credentials to a set of origins, list them explicitly or consider using "allowedOriginPatterns" instead.
at org.springframework.web.cors.CorsConfiguration.validateAllowCredentials(CorsConfiguration.java:552) ~[spring-web-7.0.9.jar:7.0.9]
at org.springframework.web.cors.CorsConfiguration.checkOrigin(CorsConfiguration.java:678) ~[spring-web-7.0.9.jar:7.0.9]
at org.springframework.web.cors.DefaultCorsProcessor.checkOrigin(DefaultCorsProcessor.java:193) ~[spring-web-7.0.9.jar:7.0.9]
at org.springframework.web.cors.DefaultCorsProcessor.handleInternal(DefaultCorsProcessor.java:131) ~[spring-web-7.0.9.jar:7.0.9]
# 401, not 500. The exception escapes CorsFilter, Tomcat re-dispatches to /error,
# the security chain runs again on that dispatch without re-reading the credential,
# and the anonymous second pass is what answers.

View File

@@ -0,0 +1,54 @@
==============================================================================
docs/output/08-csrf-naive.txt
CookieCsrfTokenRepository.withHttpOnlyFalse() on its own - the recipe from every pre-6.0
tutorial. Three separate things go wrong.
Profile: csrfnaive
==============================================================================
# 1. The bootstrap GET. A SPA expects an XSRF-TOKEN cookie here.
HTTP/1.1 200
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
X-Frame-Options: DENY
# cookie jar after the GET:
(empty - no cookie was set)
# 2. POST with no token.
HTTP/1.1 401
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Set-Cookie: XSRF-TOKEN=<token>; Path=/
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
X-Frame-Options: DENY
Set-Cookie: JSESSIONID=<session>; Path=/; HttpOnly; SameSite=Lax
WWW-Authenticate: Basic realm="Realm", charset="UTF-8"
# cookie jar now:
localhost | FALSE | / | FALSE | 0 | XSRF-TOKEN | 4888debb-2e51-4742-b0e7-262c489825b9
# 3. POST echoing the raw cookie value back in X-XSRF-TOKEN, which is what every
# SPA snippet on the internet does.
HTTP/1.1 401
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
X-Frame-Options: DENY
WWW-Authenticate: Basic realm="Realm", charset="UTF-8"
<timestamp> DEBUG <pid> --- [cors-csrf-samesite] [nio-8080-exec-N] o.s.security.web.csrf.CsrfFilter : Invalid CSRF token found for http://localhost:8080/api/data
<timestamp> DEBUG <pid> --- [cors-csrf-samesite] [nio-8080-exec-N] o.s.security.web.csrf.CsrfFilter : Invalid CSRF token found for http://localhost:8080/api/data

View File

@@ -0,0 +1,25 @@
==============================================================================
docs/output/09-error-dispatch.txt
The identical CSRF failure, with one extra filter chain that permits /error.
Profile: csrfnaive,errorpermit
==============================================================================
HTTP/1.1 403
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Set-Cookie: XSRF-TOKEN=<token>; Path=/
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
X-Frame-Options: DENY
{"timestamp":"<timestamp>","status":403,"error":"Forbidden","path":"/api/data"}
# 403, and a body. Without the /error chain the same request answers 401 with an
# empty body and a WWW-Authenticate header - see 08. AccessDeniedHandlerImpl calls
# response.sendError(403), the container re-dispatches to /error, and the security
# chain runs a second time on that dispatch. BasicAuthenticationFilter extends
# OncePerRequestFilter and skips error dispatches, so the second pass is anonymous
# and AuthorizationFilter answers 401 over the top of the 403.

View File

@@ -0,0 +1,47 @@
==============================================================================
docs/output/10-csrf-spa.txt
The same flow under csrf.spa(), added in Spring Security 7.0.
Profile: csrfspa
==============================================================================
# 1. The bootstrap GET now DOES set the cookie.
HTTP/1.1 200
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Set-Cookie: XSRF-TOKEN=<token>; Path=/
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
X-Frame-Options: DENY
# 2. POST with no token still fails, as it must.
HTTP/1.1 401
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
X-Frame-Options: DENY
Set-Cookie: JSESSIONID=<session>; Path=/; HttpOnly; SameSite=Lax
WWW-Authenticate: Basic realm="Realm", charset="UTF-8"
# 3. POST echoing the raw cookie value in X-XSRF-TOKEN.
HTTP/1.1 200
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
X-Frame-Options: DENY
{"created":true,"received":"{}","cookies":"XSRF-TOKEN"}
# Note the cookie attributes: Path=/ and nothing else. No SameSite, no Secure,
# no HttpOnly. A cookie with no SameSite attribute is treated as Lax, so a
# genuinely cross-site SPA still never receives it. See 12.

View File

@@ -0,0 +1,24 @@
==============================================================================
docs/output/11-spa-ordering.txt
.csrf(c -> c.csrfTokenRepository(custom).spa()) - the custom repository asked for a cookie
named MY-CSRF and a header named X-CSRF-TOKEN. Neither reaches the running application.
Profile: spaorder
==============================================================================
HTTP/1.1 200
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Set-Cookie: XSRF-TOKEN=<token>; Path=/
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
X-Frame-Options: DENY
# cookie jar:
localhost | FALSE | / | FALSE | 0 | XSRF-TOKEN | 42573eea-76d6-4bc6-a14b-bff76640461d
# spa() assigns csrfTokenRepository and requestHandler unconditionally; it is not a
# 'defaults if unset' method. Swap the two calls and MY-CSRF appears.

View File

@@ -0,0 +1,59 @@
==============================================================================
docs/output/12-samesite.txt
The Set-Cookie headers this application emits under four configurations, and what
SpecCookieJar - a model of RFC 6265bis 5.5 and 5.8.3 - does with them.
==============================================================================
## csrf.spa() defaults, session cookie left at same-site=lax
Set-Cookie: XSRF-TOKEN=<token>; Path=/
Set-Cookie: JSESSIONID=<session>; Path=/; HttpOnly; SameSite=Lax
## session cookie set to same-site=none, secure=false
Set-Cookie: XSRF-TOKEN=<token>; Path=/
Set-Cookie: JSESSIONID=<session>; Path=/; HttpOnly; SameSite=None
## crosssite profile: SameSite=None and Secure on both cookies
Set-Cookie: XSRF-TOKEN=<token>; Path=/; Secure; SameSite=None
Set-Cookie: JSESSIONID=<session>; Path=/; Secure; HttpOnly; SameSite=None
## crosssite profile with -DOMIT_SECURE=true
Set-Cookie: XSRF-TOKEN=<token>; Path=/; SameSite=None
Set-Cookie: JSESSIONID=<session>; Path=/; HttpOnly; SameSite=None
## The same headers, run through SpecCookieJar
{
"origin": "not trustworthy (plain http)",
"setCookieOutcomes": {
"JSESSIONID=s1; Path=/; HttpOnly; SameSite=Lax": "stored",
"JSESSIONID=s2; Path=/; HttpOnly; SameSite=None": "REJECTED JSESSIONID: SameSite=None and no Secure attribute - RFC 6265bis 5.5",
"JSESSIONID=s3; Path=/; Secure; HttpOnly; SameSite=None": "REJECTED JSESSIONID: SameSite=None with Secure, but the origin is not trustworthy so Secure is not honoured - RFC 6265bis 5.5",
"XSRF-TOKEN=t1; Path=/": "stored",
"XSRF-TOKEN=t2; Path=/; SameSite=None": "REJECTED XSRF-TOKEN: SameSite=None and no Secure attribute - RFC 6265bis 5.5",
"XSRF-TOKEN=t3; Path=/; Secure; SameSite=None": "REJECTED XSRF-TOKEN: SameSite=None with Secure, but the origin is not trustworthy so Secure is not honoured - RFC 6265bis 5.5"
},
"sentOnSameSiteRequest": "JSESSIONID=s1; XSRF-TOKEN=t1",
"sentOnCrossSiteTopLevelNavigation": "JSESSIONID=s1; XSRF-TOKEN=t1",
"sentOnCrossSiteFetch": "(no cookies sent)"
}
{
"origin": "trustworthy (https, or http://localhost)",
"setCookieOutcomes": {
"JSESSIONID=s1; Path=/; HttpOnly; SameSite=Lax": "stored",
"JSESSIONID=s2; Path=/; HttpOnly; SameSite=None": "REJECTED JSESSIONID: SameSite=None and no Secure attribute - RFC 6265bis 5.5",
"JSESSIONID=s3; Path=/; Secure; HttpOnly; SameSite=None": "stored",
"XSRF-TOKEN=t1; Path=/": "stored",
"XSRF-TOKEN=t2; Path=/; SameSite=None": "REJECTED XSRF-TOKEN: SameSite=None and no Secure attribute - RFC 6265bis 5.5",
"XSRF-TOKEN=t3; Path=/; Secure; SameSite=None": "stored"
},
"sentOnSameSiteRequest": "JSESSIONID=s3; XSRF-TOKEN=t3",
"sentOnCrossSiteTopLevelNavigation": "JSESSIONID=s3; XSRF-TOKEN=t3",
"sentOnCrossSiteFetch": "JSESSIONID=s3; XSRF-TOKEN=t3"
}
# Read the second block first: over a trustworthy origin, the only two of the six
# that reach a cross-site fetch are the two carrying Secure AND SameSite=None.
# Then read the first: over plain http, none do -
# which is why a cross-site SPA cannot be developed against http://127.0.0.1.
# (http://localhost itself is treated as trustworthy by current browsers; a bare IP
# is not.)

View File

@@ -0,0 +1,34 @@
==============================================================================
docs/output/13-tests.txt
mvn -B test
==============================================================================
09:33:03.378 [main] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper -- Found @SpringBootConfiguration com.ankurm.cors.CorsCsrfApplication for test class com.ankurm.cors.CsrfAndCookieTests$Naive
09:33:03.464 [main] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper -- Found @SpringBootConfiguration com.ankurm.cors.CorsCsrfApplication for test class com.ankurm.cors.CsrfAndCookieTests$Naive
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.904 s -- in CookieCsrfTokenRepository.withHttpOnlyFalse() on its own
<timestamp> INFO <pid> --- [cors-csrf-samesite] [ main] .b.t.c.SpringBootTestContextBootstrapper : Found @SpringBootConfiguration com.ankurm.cors.CorsCsrfApplication for test class com.ankurm.cors.CsrfAndCookieTests$Spa
<timestamp> INFO <pid> --- [cors-csrf-samesite] [ main] .b.t.c.SpringBootTestContextBootstrapper : Found @SpringBootConfiguration com.ankurm.cors.CorsCsrfApplication for test class com.ankurm.cors.CsrfAndCookieTests$Spa
[INFO] Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.444 s -- in csrf.spa()
[INFO] Tests run: 6, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.028 s -- in SpecCookieJar - the storage and sending rules a browser applies
<timestamp> INFO <pid> --- [cors-csrf-samesite] [ main] .b.t.c.SpringBootTestContextBootstrapper : Found @SpringBootConfiguration com.ankurm.cors.CorsCsrfApplication for test class com.ankurm.cors.CsrfAndCookieTests$Ordering
<timestamp> INFO <pid> --- [cors-csrf-samesite] [ main] .b.t.c.SpringBootTestContextBootstrapper : Found @SpringBootConfiguration com.ankurm.cors.CorsCsrfApplication for test class com.ankurm.cors.CsrfAndCookieTests$Ordering
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.362 s -- in csrfTokenRepository(..) before spa()
[INFO] Tests run: 0, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 3.783 s -- in com.ankurm.cors.CsrfAndCookieTests
<timestamp> INFO <pid> --- [cors-csrf-samesite] [ main] .b.t.c.SpringBootTestContextBootstrapper : Found @SpringBootConfiguration com.ankurm.cors.CorsCsrfApplication for test class com.ankurm.cors.CorsContractTests$MvcOnly
<timestamp> INFO <pid> --- [cors-csrf-samesite] [ main] .b.t.c.SpringBootTestContextBootstrapper : Found @SpringBootConfiguration com.ankurm.cors.CorsCsrfApplication for test class com.ankurm.cors.CorsContractTests$MvcOnly
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.305 s -- in CORS on the MVC layer only
<timestamp> INFO <pid> --- [cors-csrf-samesite] [ main] .b.t.c.SpringBootTestContextBootstrapper : Found @SpringBootConfiguration com.ankurm.cors.CorsCsrfApplication for test class com.ankurm.cors.CorsContractTests$Misnamed
<timestamp> INFO <pid> --- [cors-csrf-samesite] [ main] .b.t.c.SpringBootTestContextBootstrapper : Found @SpringBootConfiguration com.ankurm.cors.CorsCsrfApplication for test class com.ankurm.cors.CorsContractTests$Misnamed
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.264 s -- in the right type under the wrong bean name
<timestamp> INFO <pid> --- [cors-csrf-samesite] [ main] .b.t.c.SpringBootTestContextBootstrapper : Found @SpringBootConfiguration com.ankurm.cors.CorsCsrfApplication for test class com.ankurm.cors.CorsContractTests$SecuritySource
<timestamp> INFO <pid> --- [cors-csrf-samesite] [ main] .b.t.c.SpringBootTestContextBootstrapper : Found @SpringBootConfiguration com.ankurm.cors.CorsCsrfApplication for test class com.ankurm.cors.CorsContractTests$SecuritySource
[INFO] Tests run: 4, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.225 s -- in a bean named corsConfigurationSource
<timestamp> INFO <pid> --- [cors-csrf-samesite] [ main] .b.t.c.SpringBootTestContextBootstrapper : Found @SpringBootConfiguration com.ankurm.cors.CorsCsrfApplication for test class com.ankurm.cors.CorsContractTests$TwoSources
<timestamp> INFO <pid> --- [cors-csrf-samesite] [ main] .b.t.c.SpringBootTestContextBootstrapper : Found @SpringBootConfiguration com.ankurm.cors.CorsCsrfApplication for test class com.ankurm.cors.CorsContractTests$TwoSources
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.235 s -- in two UrlBasedCorsConfigurationSource beans
<timestamp> INFO <pid> --- [cors-csrf-samesite] [ main] .b.t.c.SpringBootTestContextBootstrapper : Found @SpringBootConfiguration com.ankurm.cors.CorsCsrfApplication for test class com.ankurm.cors.CorsContractTests$MvcBridge
<timestamp> INFO <pid> --- [cors-csrf-samesite] [ main] .b.t.c.SpringBootTestContextBootstrapper : Found @SpringBootConfiguration com.ankurm.cors.CorsCsrfApplication for test class com.ankurm.cors.CorsContractTests$MvcBridge
[INFO] Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.217 s -- in the same MVC configuration plus .cors(withDefaults())
[INFO] Tests run: 0, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.256 s -- in com.ankurm.cors.CorsContractTests
[INFO] Tests run: 23, Failures: 0, Errors: 0, Skipped: 0
[INFO] BUILD SUCCESS