Spring Session 1.0.0.M1 cookie domain attribute - spring

I have integrated Spring Session with Redis into my SpringBoot app. It seems that all works well except the cookie domain attribute. I just found how to set the cookie session domain attribute for in tomcat i.e. method "setSessionCookieDomain", but that does not work. for example.
I had configured domain attribute in the context of the tomcat for example the domain attribute of the cookie.
#Bean
public TomcatContextCustomizer tomcatContextCustomizer() {
System.out.println("TOMCATCONTEXTCUSTOMIZER INITILIZED");
return new TomcatContextCustomizer() {
#Override
public void customize(Context context) {
context.addServletContainerInitializer(new WsSci(), null);
context.setUseHttpOnly(true);
context.setPath("/");
context.setSessionCookiePath("/");
context.setSessionCookieDomain(".127.0.0.5");
// context.setSessionCookieDomain(".localhost");
// context.setSessionCookieDomain(".test.blabla.com");
}
};
}
When i open the https trace in wireshark and click follow ssl stream, here is what i get. All other attributes are listed except the domain. So my question is how do I set the domain attribute correctly in Spring Session 1.0.0.M1, Does spring session somehow override the tomcat context?
GET / HTTP/1.1
Host: 127.0.0.5:8888
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:34.0) Gecko/20100101 Firefox/34.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Lang: keep-alive
: keep-alive
: keep-alive
: keep-alive
: keep-alive
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
Strict-Transport-Security: max-age=31536000 ; includeSubDomains
X-Frame-Options: DENY
X-Content-Security-Policy: script-src 'self'; object-src 'self'
Content-Security-Policy: script-src 'self'; object-src 'self'
X-WebKit-CSP: default-src 'self'
X-Application-Context: application:Production
Set-Cookie: SESSION=5d0a738f-f011-4e43-a1ee-d691b8eba94c; Path=/; Secure; HttpOnly
Content-Type: text/html;charset=UTF-8
Conten10:01:27 GMT
10:01:27 GMT
10:01:27 GMT
10:01:27 GMT
10:01:27 GMT
<!DOCTYPE html>

Thanks for bringing this up. Spring Session should allow configuring the domain via the SessionCookieConfig but doesn't. I have created gh-87 to address this.

Related

Wrong response from the server - It seems my FrontEnd is getting Options response instead of Post

I have read a lot about CORS, preflight etc, I know the problem is related to it, but couldn't figure out, what's going on here.
I'm using VueJs and SpringBoot with Spring Security and jsonwebtoken.
When I make a POST request /login on Postman:
{
"username":"admin",
"password":"password"
}
I got the right response with the expected token:
http 200 with headers:
{
Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsImV4cCI6MTYwODI5OTIxMn0.9oXFpm9DivR3DNPcBaoc_KgsqNdBJbkFq_oA4pBJbXF2iUwx7_XfBwv-Xcn-da9LS9M5zxd8oRslr_wdVyoQkA,
X-Content-Type-Options:nosniff
X-XSS-Protection:1; mode=block
Cache-Control:no-cache, no-store, max-age=0, must-revalidate
Pragma:no-cache
Expires:0
X-Frame-Options:DENY
Content-Length:0
}
However, when the front-End calls the service I got the following answer with the wrong header, there is no token:
http 200 with headers
{
cache-control: "no-cache, no-store, max-age=0, must-revalidate",
content-length: "0", expires: "0", pragma: "no-cache"
}
When I open the browser with security disabled it works fine as well, I got the expected token on the header...
"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --user-data-dir="C://Chrome dev session" --disable-web-security
So it seems to be related to Cors indeed, but I don't get any Cors error message!
I used fiddler to track the requests and responses and I notice that the option method is happening, So my first question is, should the options response go up to the front-end? as far as I know the options stay within the browser boundary and then the browser makes the post request (if the server allowed).
Options Request:
OPTIONS http://ec2-52-4-252-232.compute-1.amazonaws.com:9090/login HTTP/1.1
Host: ec2-52-4-252-232.compute-1.amazonaws.com:9090
Connection: keep-alive
Accept: */*
Access-Control-Request-Method: POST
Access-Control-Request-Headers: authorization
Origin: http://s3-sa-east-1.amazonaws.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36
Sec-Fetch-Mode: cors
Referer: http://s3-sa-east-1.amazonaws.com/
Accept-Encoding: gzip, deflate
Accept-Language: pt-BR,pt;q=0.9,en-US;q=0.8,en;q=0.7,es;q=0.6
Options Response:
HTTP/1.1 200
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Access-Control-Allow-Origin: http://s3-sa-east-1.amazonaws.com
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: authorization
Access-Control-Allow-Credentials: true
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Length: 0
Date: Tue, 08 Dec 2020 14:58:56 GMT
Post Request:
POST http://ec2-52-4-252-232.compute-1.amazonaws.com:9090/login HTTP/1.1
Host: ec2-52-4-252-232.compute-1.amazonaws.com:9090
Connection: keep-alive
Content-Length: 42
Accept: application/json, text/plain, */*
Authorization: undefined
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Origin: http://s3-sa-east-1.amazonaws.com
Referer: http://s3-sa-east-1.amazonaws.com/
Accept-Encoding: gzip, deflate
Accept-Language: pt-BR,pt;q=0.9,en-US;q=0.8,en;q=0.7,es;q=0.6
{
"username":"admin",
"password":"password"
}
Post Response:
HTTP/1.1 200
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Access-Control-Allow-Origin: http://s3-sa-east-1.amazonaws.com
Access-Control-Allow-Credentials: true
Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsImV4cCI6MTYwODI5OTUzNn0.0UgsNHd9Aw9Ei5aq-k0y74BlxJ92-j7w-FrryZaDAwzLC1a2OpSH3rXhRWGIul3wqpWLbqJ7icNlM3d590UFWw
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Length: 0
Date: Tue, 08 Dec 2020 14:58:56 GMT
Part of My front-end Code:
login({ commit }, user) {
const cors = require('cors')({
origin: true
});
const qs = require('querystring')
return new Promise((resolve, reject) => {
commit('auth_request')
axios({
url: process.env.VUE_APP_BACKEND_ENDPOINT + '/login', data: user, method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded'}
})
.then(resp => {
console.log(resp.headers)
const token = resp.headers["authorization"]
localStorage.setItem('token', token)
axios.defaults.headers.common['Authorization'] = token
commit('auth_success', token, user.username)
resolve(resp)
})
.catch(err => {
commit('auth_error')
localStorage.removeItem('token')
reject(err)
})
})
Part of my Back-End Code:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.cors().configurationSource(corsConfigurationSource()).and()
.csrf().disable().authorizeRequests()
.antMatchers("/home").permitAll()
.antMatchers(HttpMethod.POST, "/login").permitAll()
.anyRequest().authenticated()
.and()
// filtra requisições de login
.addFilterBefore(new JWTLoginFilter("/login", authenticationManager()),
UsernamePasswordAuthenticationFilter.class)
// filtra outras requisições para verificar a presença do JWT no header
.addFilterBefore(new JWTAuthenticationFilter(),
UsernamePasswordAuthenticationFilter.class);
}
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
List<String> allowOrigins = Arrays.asList("*");
configuration.setAllowedOrigins(allowOrigins);
configuration.setAllowedMethods(singletonList("*"));
configuration.setAllowedHeaders(singletonList("*"));
//in case authentication is enabled this flag MUST be set, otherwise CORS requests will fail
//configuration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// cria uma conta default
auth.inMemoryAuthentication()
.withUser("admin")
.password("{noop}password")
.roles("ADMIN");
}
}```
Anyone knows what's going on here ? Why the Post response isn't coming to the front-end ?
I spend many hours but couldn't solve it, so I appreciate any help.
I can reproduce your Postman request with curl:
curl -vv -H "Content-Type: application/x-www-form-urlencoded" http://ec2-52-4-252-232.compute-1.amazonaws.com:9090/login -d '{"username":"admin", "password":"password"}'
Returns a 200 with the Authorization header filled in.
Can you run the frontend code with the Network tab in Developer Tools open and see how the POST request looks?
And possibly right-click and "copy as cURL" and then compare it to the curl request above.
Actually my problem wasn't related to options method as I thought, the problem was that I was missing the Access-Control-Expose-Headers which should also be presented in the headers of server response.
I just set it on my springboot app and it worked fine !
List<String> exposedHeaders = Arrays.asList("Authorization");
configuration.setExposedHeaders(exposedHeaders);
I got the answer from this one: axios response headers missing data when running in vuejs app

Why Spring Boot application does not work with relative quality factor of HTTP?

Lets suppose I have a Spring Boot application:
dependencies {
implementation("org.springframework.boot:spring-boot-starter-webflux:2.4.0")
}
with a simple RestController:
#RestController
class TestController {
#PostMapping("/test")
suspend fun test(#RequestBody request: Map<String, String>) {
throw RuntimeException("test")
}
}
When I use httpie client to make requests, then the result looks like:
➜ ~ http post :8080/test param=value --verbose
POST /test HTTP/1.1
Accept: application/json, */*;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Length: 18
Content-Type: application/json
Host: localhost:8080
User-Agent: HTTPie/2.3.0
{
"param": "value"
}
HTTP/1.1 500 Internal Server Error
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Length: 309
Content-Type: text/html;charset=UTF-8
Expires: 0
Pragma: no-cache
Referrer-Policy: no-referrer
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1 ; mode=block
<html><body><h1>Whitelabel Error Page</h1><p>This application has no configured error view, so you are seeing this as a fallback.</p><div id='created'>Wed Dec 09 22:24:52 MSK 2020</div><div>[906bb33e-5] There was an unexpected error (type=Internal Server Error, status=500).</div><div>test</div></body></html>
When I use cURL:
➜ ~ curl -XPOST localhost:8080/test -d '{"param": "value"}' -H "Content-type: application/json" -v
Note: Unnecessary use of -X or --request, POST is already inferred.
* Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
> POST /test HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.64.1
> Accept: */*
> Content-type: application/json
> Content-Length: 18
>
* upload completely sent off: 18 out of 18 bytes
< HTTP/1.1 500 Internal Server Error
< Content-Type: application/json
< Content-Length: 170
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-Content-Type-Options: nosniff
< X-Frame-Options: DENY
< X-XSS-Protection: 1 ; mode=block
< Referrer-Policy: no-referrer
<
* Connection #0 to host localhost left intact
{"timestamp":1607541989698,"path":"/test","status":500,"error":"Internal Server Error","message":"test","requestId":"7f249f68-9","exception":"java.lang.RuntimeException"}* Closing connection 0
The difference in header Accept. Httpie uses Accept: application/json, */*;q=0.5 header with relative quality factor 0.5 and, despite the fact that I requested JSON if possible (and it's possible), the application returns HTML representation.
Is it how Spring Boot should work and I do something wrong?
UPD: Everything works fine with Tomcat (spring-boot-starter-web). After some debugging I found that, when Tomcat used, errors are handled by org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController and for Netty it is org.springframework.boot.autoconfigure.web.reactive.error.DefaultErrorWebExceptionHandler. It looks like the source of misbehavior is here: when MediaType.ALL is removed from acceptedMediaTypes .

golang http client returning wrong content type

I have a very simple Go program that performs HTTP HEAD on a URL, and prints the content-type of the response:
package main
import (
"fmt"
"net/http"
)
func main() {
resp, _ := http.Head("https://jira.softwareplant.com/servicedesk/customer/portal/1/")
fmt.Println(resp.Header.Get("Content-Type"))
}
When I run it, it returns the following:
$ go run url.go
application/octet-stream;charset=UTF-8
However, when I do the same using curl, it returns a different content type (both in the original response, and after the redirect):
$ curl -I -L https://jira.softwareplant.com/servicedesk/customer/portal/1/
HTTP/1.1 302
Date: Thu, 11 Jun 2020 18:07:26 GMT
Content-Type: text/html;charset=UTF-8
Connection: keep-alive
X-AREQUESTID: 1207x5410258x1
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Content-Security-Policy: frame-ancestors 'self'
X-ASEN: SEN-L15483924
Set-Cookie: atlassian.xsrf.token=BWV3-4JDO-FP3E-CBA1_b0942d30c14d689f92051e7b2d8467e0a0ce2129_lout; Path=/; Secure
Set-Cookie: JSESSIONID=8FE57CA54FEC626F0521327DCBA1D3DB; Path=/; Secure; HttpOnly
X-ASESSIONID: 18hzbge
X-AUSERNAME: anonymous
Location: /plugins/servlet/desk/portal/1/
HTTP/1.1 302
Date: Thu, 11 Jun 2020 18:07:26 GMT
Content-Type: text/html;charset=UTF-8
Connection: keep-alive
X-AREQUESTID: 1207x5410259x1
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Content-Security-Policy: frame-ancestors 'self'
X-ASEN: SEN-L15483924
Set-Cookie: atlassian.xsrf.token=BWV3-4JDO-FP3E-CBA1_fcd3f481d084e039075ebbce34039870d7cd044d_lout; Path=/; Secure
Set-Cookie: JSESSIONID=7B895577760D8E31F02B818FA8C0E1B2; Path=/; Secure; HttpOnly
X-ASESSIONID: 289ito
X-AUSERNAME: anonymous
Location: /servicedesk/customer/portal/1//user/login?destination=portal%2F1/
HTTP/1.1 200
Date: Thu, 11 Jun 2020 18:07:26 GMT
Content-Type: text/html;charset=UTF-8
Connection: keep-alive
X-AREQUESTID: 1207x5410260x1
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Content-Security-Policy: frame-ancestors 'self'
X-ASEN: SEN-L15483924
Set-Cookie: atlassian.xsrf.token=BWV3-4JDO-FP3E-CBA1_dc371dbc76497b29f1fa939a65dc6dd5b3488e7f_lout; Path=/; Secure
Set-Cookie: JSESSIONID=E17E2F0C4B7CA5C9ADDC4BE468A5D459; Path=/; Secure; HttpOnly
X-ASESSIONID: 1byquf1
X-AUSERNAME: anonymous
Cache-Control: no-cache, no-store, no-transform
Am I doing something wrong? Is there a way in Go to get the correct content-type for such URLs?
I am using Golang 1.14.4 on Ubuntu. The above URL is not the only one that has this issue.
If you change the Accept header sent by Go, you will get Content-Type: text/html;charset=UTF-8:
package main
import (
"fmt"
"net/http"
)
func main() {
client := &http.Client{}
req, _ := http.NewRequest("HEAD", "https://jira.softwareplant.com/servicedesk/customer/portal/1/", nil)
req.Header.Set("Accept", "*/*")
resp, _ := client.Do(req)
fmt.Println(resp.Header.Get("Content-Type"))
}

Certain cookies are blocked cross domain when using an ajax request

I'm using a react app running on localhost:3000 which makes ajax requests to our website. We recently switched our authentification system from using WordPress authentification to https://github.com/delight-im/PHP-Auth.
Since then, using the same settings inside ajax and on our web server, our authentification cookies are not sent cross domain. However, it's working when requesting them from the same domain.
Our request:
fetchLoginStatus = () => {
const ajax = new XMLHttpRequest();
ajax.withCredentials = true;
ajax.open("POST", "https://our-website.com/src/php/checkLoggedIn.php");
ajax.onload = () => {
const response = JSON.parse(ajax.responseText);
};
ajax.send();
};
Our request headers (from localhost:3000):
:authority: my-website.com
:method: POST
:path: /src/php/checkLoggedIn.php
:scheme: https
accept: */*
accept-encoding: gzip, deflate, br
accept-language: de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7
content-length: 0
cookie: plesk-items-per-page; plesk-sort-field, phpMyAdmin; databases-active-list-state-collapsed; plesk-list-type; io=R_dL3fjUEYe64ykHAAAp; isAsyncProgressBarCollapsed=true; PLESKSESSID; plesk-sort-dir;
origin: https://localhost:3000
referer: https://localhost:3000/
Our response headers (we are running an nginx server):
access-control-allow-credentials: true
access-control-allow-headers: origin, x-requested-with, content-type
access-control-allow-methods: PUT, GET, POST, DELETE, OPTIONS access-`
control-allow-origin: https://localhost:3000
cache-control: no-store, no-cache, must-revalidate
content-encoding: br
content-type: text/html; charset=UTF-8
date: Sun, 10 Mar 2019 15:26:08 GMT
expires: Thu, 19 Nov 1981 08:52:00 GMT pragma:
no-cache server: nginx
set-cookie: PHPSESSID=someId;
path=/; SameSite=Lax status: 200
vary: Accept-Encoding
x-powered-by: PleskLin`
When I don't send the request cross-domain PHPSESSID is inside the cookies of my request headers. However when I send the request from localhost:3000 it's not there.
Does somebody know how I can send the PHPSESSID from localhost too?
Thanks for any help in advance!
Asked the same question inside the github repository and the owner solved it.
https://github.com/delight-im/PHP-Auth/issues/154
Solution:
vendor/delight-im/auth/src/UserManager.php
Replace Session::regenerate(true); with Session::regenerate(true, null);
vendor/delight-im/auth/src/Auth.php
Replace #Session::start(); with #Session::start(null);
Replace Session::regenerate(true); with Session::regenerate(true, null);
After $cookie->setSecureOnly($params['secure']); append $cookie-
>setSameSiteRestriction(null); in all three (!) occurrences

CORS Between Spring Boot(Spring Security) and Enterprise Authentication applications

I am getting CORS issue even after setting required headers, like Access-Control-Allow-Origin to http://localhost:4200, Access-Control-Allow-Credentials to true and so on.
Response from previous request:
HTTP/1.1 302 Found
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: Special-Response-Header, Header2
Access-Control-Allow-Origin: http://localhost:4200
Access-Control-Expose-Headers: Special-Response-Header, Header2
Access-Control-Max-Age: 3600
Access-Control-Request-Headers: Special-Response-Header, Header2
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Length: 0 Date: Mon, 18 Jun 2018 13:03:46 GMT
Expires: 0
Location: <<Replace with Org Authentication URL>>
Origin: http://localhost:4200
Pragma: no-cache
Set-Cookie: dtCookie=8$C38554BBC14802D7BCFE9A5E047AA962;domain=rbc.com;path=/ Set-Cookie: JSESSIONID=26A7EB71BD36D31EFE6A701320DFA0C3;path=/;Secure;HttpOnly Set-Cookie: __VCAP_ID__=0a838736-ad8b-40b9-4aa5-e972; Path=/; HttpOnly; Secure Strict-Transport-Security: max-age=31536000 ; includeSubDomains X-Content-Type-Options: nosniff X-Frame-Options: DENY X-Vcap-Request-Id: 61cc9d4e-29ba-4b11-7f0b-82ec01cbc0a6 X-Xss-Protection: 1; mode=block
Current Request :
GET <<Replace with Org Authentication Get method params>>
HTTP/1.1
Host: mrkdlvaiaas493.devfg.rbc.com:9443
Connection: keep-alive
Accept: application/json, text/plain, */*
Origin: null
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36 Referer: http://localhost:4200/startBatch/2018-04-27 Accept-Encoding: gzip, deflate, br Accept-Language: en-US,en;q=0.9
Error :
Failed to <<Replace with Org Authentication URL>>: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.
Try declare a bean like this: (to enable cors)
#Configuration
public class SecurityBasicConfigurations {
#Bean
public WebMvcConfigurer corsOriginConfigurer() {
return new WebMvcConfigurer() {
#Override
public void addCorsMappings( CorsRegistry registry ) {
registry.addMapping( "/*" )
.allowedMethods( "*" )
.allowedOrigins( "http://localhost:4200" )
.allowedHeaders( "*" );
}
};
}
}

Resources