Reputation: 1590
I am developing a Spring REST application using Spring Boot. I am consuming the Spring REST APIs using angular JS client.
The stack I am using is :
Spring Boot 1.4.2 , Spring Security , Angular JS , Tomcat 8
My Issue Is :
1)At login , user gets succesfully authenticated. Custom authentication success handler returns 200 status code.
2)After authentication success , when clint sends another request to access a procted resource , HttpSession is NULL
3)Due to which when SecurityContextPersistenceFilter
tries to retrieve the SecurityContext
from HttpSession
it is returned as null and
and again server sends request to /login
resource
4)So my questions are :
1)Why is httpsesion is null for second request ?
2)I have observed that Spring security returns JSESSIONID
as cookie after first succesfull authentication.
3)But after that , client is NOT sending this JSESSIONID
in request hence second request won't be in same session.
4)If that is the case , how is SecurityContext
will be retrieved if SESSION
is not established ?
Please help as I am not able to proceed here
EDIT 1 :
I am using default in memory user provided by spring security. My security configuration is bellow :
@Configuration
@EnableWebSecurity
@ComponentScan({"com.atul.security"})
public class SecurityConfig extends WebSecurityConfigurerAdapter{
@Autowired
private RESTAuthenticationSuccessHandler authenticationSuccessHandler;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin().successHandler(authenticationSuccessHandler)
.and()
.csrf().disable()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS,"/*").permitAll()
.antMatchers("/index.html", "/home.html", "/login.html", "/").permitAll()
.anyRequest().authenticated()
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
}
I am getting below user as authenticated user :
org.springframework.security.authentication.AnonymousAuthenticationToken@9055c2bc:
Principal: anonymousUser; Credentials: [PROTECTED];
Authenticated: true;
Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364:
RemoteIpAddress: 0:0:0:0:0:0:0:1;
SessionId: null;
Granted Authorities: ROLE_ANONYMOUS
The request is now failing at : AbstractSecurityInterceptor
: AccessDecisionVoter
returning false for authenticated
expression and access denied exception is thrown
Upvotes: 0
Views: 2645
Reputation: 1590
After banging head for a long time , I am finally able to find out the solution.
Steps are :
1) Form based login requires session to be established . When authentication succeeds , server sends Set-Cookie:JSESSIONID=3974317C6DE34865B6726FCFD4C98C08; Path=/springbootrest; HttpOnly
header in response.
2)Browser has to send this header in every request else there will be no session established and authentication will fail
3)But since I was using CORS
(my server and ui app reside on different port on local system) , browser was not sending Cookie:JSESSIONID=3974317C6DE34865B6726FCFD4C98C08
in request failing the authentication.
4)I have to add below line $httpProvider.defaults.withCredentials = true;
in my angular js client after that browser started sending above header in request.
5)At server side I have to add below code in CORSFilter.
response.setHeader("Access-Control-Allow-Credentials","true");
response.setHeader("Access-Control-Allow-Origin", "http://localhost:8186");
response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "X-Requested-With, WWW-Authenticate, Authorization, Origin, Content-Type, Version");
response.setHeader("Access-Control-Expose-Headers", "X-Requested-With, WWW-Authenticate, Authorization, Origin, Content-Type");
final HttpServletRequest request = (HttpServletRequest) req;
if("OPTIONS".equalsIgnoreCase(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
} else {
chain.doFilter(req, res);
}
Upvotes: 1
Reputation: 3733
There is no session in rest because RESTFUL services don't maintain state, read this stack overflow post:
Do sessions really violate RESTfulness?
If you want to know how properly build spring security service based REST examine this tutorial:
http://www.baeldung.com/securing-a-restful-web-service-with-spring-security
Hope that this helps.
You are using formLogin security, which means you need to add some kind of data store to authenticate users against it.
Here is an example for in-memory data store from spring documentation:
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public UserDetailsService userDetailsService() throws Exception {
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
manager.createUser(User.withUsername("user").password("password").roles("USER").build());
manager.createUser(User.withUsername("admin").password("password").roles("USER","ADMIN").build());
return manager;
}
}
according to this example, you suppose to authenticate successfully with a username of user and password of password
You are trying to apply security with angularJS as your front technology, there's a great tutorial how to achieve that, I already implemented it on my project, here's the link:
https://spring.io/guides/tutorials/spring-security-and-angular-js/
For starter you need to use httpBasic and not formLogin as your security authentication method.
Upvotes: 1