How to get csfr token if login page is disable - spring

for example a simple spring configuration
http.authorizeRequests()
.antMatchers(HttpMethod.POST,"/create").permitAll()
.anyRequest().authenticated()
.and().formLogin();
with csfr enabled, the request for "/create" endpoint will be redirected to login page, where I can find _csfr value, then I can make another post request with a new header "X-CSRF-Token", and finally request will be served.
But what if login page is disable? :
http.authorizeRequests()
.antMatchers(HttpMethod.POST,"/create").permitAll()
.anyRequest().authenticated()
//.and().formLogin();
server will return 403 forbiden, there will be no html page to parse, how can I get csfr value in this case?

Related

Form Login and HTTP Authorization header

I was checking the HTML code for the default form login page of Spring Security using Spring Boot. Apparently, there are 3 fields in the form (username, password and a hidden CSRF token) and it is a POST request.
I assumed that the HTTP request will not use Authorization header in this case - I have not seen any JavaScript code or something like that which encodes the username:password combination into a Base64 encoded string and puts it into HTTP Authorization header.
But when I checked the Google Chrome Developer tools Inspect, I find that the browser is actually sending the Authorization header with Basic scheme (with username and password Base64 encoded). Also the post body of the HTTP request again contained all the 3 fields (username, password and CSRF token).
How does this happen? Will the browser automatically recognize that this is as a login form and automatically create the Authorization header?
Please find my configuration below:
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.authorizeRequests()
.antMatchers("/admin").hasRole("ADMIN")
.antMatchers("/user").hasAnyRole("ADMIN", "USER")
.antMatchers("/").permitAll()
.and()
//.httpBasic();
.formLogin()
;
httpSecurity.csrf().disable();
}
Please note that I am testing using Form login.
I couldn't reproduce your issue. It would have been much confusing for me if it did
When I put back httpBasic() in config, as I expected I see WWW-Authenticate: Basic realm="Realm" in the server response, which makes the browser to create the login popup and Send the Authorization header on submission.
Do you see any such response header before the login form is displayed?

Spring Security OAuth2 login redirect to error page despite being successful

As to not reveal confidential information, the provider will be replaced by $PROVIDER.
The authorization works, but instead of redirecting me to the index, it redirects me to /error.
Steps to reproduce
Start the application
Go on any page, it will redirect me to http://localhost/oauth_login which displays a link login.
Click on the link login (which links to http://localhost/oauth2/authorization/$PROVIDER)
Get redirected to http://localhost/error
The error page displays the following (I formatted it for readability):
{
"timestamp":"2018-04-05T14:18:47.720+0000",
"status":999,
"error":"None",
"message":"No message available"
}
This is obviously the same parameters shown on the default Whitelabel Error Page, so really, the only problem is that it's in JSON except of being an HTML page. If I refresh http://localhost/error after, it shows me the normal Whitelabel Error Page.
Now this is where it gets weird, if I try to navigate to http://localhost/ after having been redirected to the error page, I am authenticated (the user data is there, so the authorization was successful). Basically, the issue is that I am redirected to http://localhost/error instead of http://localhost/.
Because it is fully functional (aside from the redirection), I will not post the whole security configuration, but I will instead limit it to relevant code:
SecurityConfiguration
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.csrf().disable()
.authorizeRequests().anyRequest()
.authenticated()
.and()
.oauth2Login()
.loginPage("/oauth_login")
.defaultSuccessUrl("/")
.failureUrl("/oauth_login")
.permitAll()
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/oauth_login").permitAll()
;
}
Relevant properties
spring.security.oauth2.client.registration.$PROVIDER.redirectUriTemplate=http://localhost/login/oauth2/code/$PROVIDER
Relevant information
Once I am authenticated on the website, I can navigate, refresh the page, do whatever I wish (until I log out).
TL;DR Authorization works but redirected to /error instead of /.
I actually found the answer to my own question, but I decided to post it anyways in case somebody runs into the same issue.
.defaultSuccessUrl("/")
should have been
.defaultSuccessUrl("/", true)
If you don't set it to true, it will automatically redirect the user to the last previous request, and in my case, the last request is made to the url /error, which explains my problem.
By setting it to true, you force the user to be redirected to whatever your defaultSuccessUrl is.
By looking at the logs, you can actually see it:
2018-04-05 11:04:09 DEBUG [-nio-80-exec-10] RequestAwareAuthenticationSuccessHandler : Redirecting to DefaultSavedRequest Url: http://localhost/error
2018-04-05 11:04:09 DEBUG [-nio-80-exec-10] o.s.security.web.DefaultRedirectStrategy : Redirecting to 'http://localhost/error'

Spring SPNEGO without form

I have some questions about setting up SPNEGO without use of form fall back.
I am writing a web service that uses SPNEGO authentication and returns a signed JWT for the authenticated principal. I don't have any use for forms (can't use forms with authentication-only principals, for example).
Can I skip the formLogin() and logout() parts as shown in the spring SPNEGO reference, and use the zero-argument SpnegoEntryPoint constructor?
It seems from looking at the source for SPNEGO filter that if the Authorization header is missing then the filter doesn't actually return a 401 Unauthorized response with a WWW-Authenticate: Negotiate challenge to the caller. That is, there is no else to the check on line 135. Am I reading this correctly? The RFC states
If the server receives a request for an access-protected object, and
if an acceptable Authorization header has not been sent, the server
responds with a "401 Unauthorized" status code, and a "WWW-
Authenticate:" header
If the above is correct, are clients expected to preemptively send the Authorization header?
Thanks!
EDIT (and probably RESOLVED): My original security config had:
http.exceptionHandling()
.authenticationEntryPoint(spnegoEntryPoint())
.and()
.authorizeRequests()
.antMatchers("/v1/**").permitAll()
.anyRequest().authenticated()
.and()
.addFilterBefore()...`
When I remove .antMatchers("/v1/**").permitAll() the SpnegoEntryPoint kicks in and I now see a 401 with WWW-Authenticate: Negotiate response.
Of course now I get a Server not found in Kerberos database gss_init_sec_context() failure but i suspect that has to do with SPN setup or host name resolution (since I am testing this locally on my Macbook) than the Spring app.
Will update once finally when I get this working.
Yes, the zero argument cosntructor is correct.
The Filter is not responsible for setting the Status and Header. The SpnegoEntryPoint is. org.springframework.security.kerberos.web.authentication.SpnegoEntryPoint.commence(HttpServletRequest, HttpServletResponse, AuthenticationException)
No, see 2.

POST request "Full authentication is required to access this resource"

Does anybody encountered the error "Full authentication is required to access this resource" trying to authenticate by using POST request oauth/token?
Curl command:
curl localhost:85/oauth/token -d grant_type=password -d client_id=web_app -d username=reader -d password=reader
Response:
{"timestamp":1486841819620,"status":401,"error":"Unauthorized","message":"Full authentication is required to access this resource","path":"/oauth/token"}
ResourceServerConfiguration configure
http .csrf().disable() .authorizeRequests() .antMatchers("/**").authenticated() .antMatchers(HttpMethod.GET, "/me").hasAuthority("FOO_READ")
WebSecurityConfig configure
http .csrf().disable() .exceptionHandling() .authenticationEntryPoint((request, response, authException) -> response.sendError(HttpServletResponse.SC_UNAUTHORIZED))
Thanks!
This error message is from your own back end server. It is a spring framework error. If you check this with 2 providers, you can see that the error message is the same for both. The source of the problem, in my case, was my wrong mapping as a call back url. I configured my server to permit all requests that hit the endpoint localhost:8080/oauth2/callback/** to pass without authentication while the callback coming from the providers was configured as localhost:8080/login/oauth2/**. I did this mistake following this tutorial. For any reason, if there is a mismatch between these configurations, you will get the error.

Spring filter and cookies

I am facing issue while getting the cookie from subsequent request.
I have loginFilter where I am setting the cookie in response like below.
httpResponse.addCookie(new Cookie("TOKEN", "ABCXYSSSS"));
I can see both the cookies i.e JSESSIONID and TOKEN are avaiable in browser.
And when user access new request then I am getting only JSESSIONID in request, not getting TOKEN cookie in request
To get the cookie from repsonse
httpRequest.getCookies();
Could anybody provide me the input on this.

Resources