I am trying to create a Spring server for an android client and am using basic authentication. I have a controller as follows:
@RequestMapping(value = "login", method = RequestMethod.GET, produces = "application/json")
public @ResponseBody Message login(HttpSession session) {
logger.info("Accessing protected resource sid:"+session.getId());
return new Message(100, "Congratulations!", "You have logged in.");
}
@RequestMapping(value = "play", method = RequestMethod.GET, produces = "application/json")
public @ResponseBody Message play(HttpSession session) {
logger.info("Accessing protected play resource");
return new Message(100, "Congratulations!", "Launching play.");
}
Once the client has authenticated, during login, I don't want it to need to reauthenticate while calling play.
My security config is:
protected static class ApplicationSecurity extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/signup","/about").permitAll()
.anyRequest().authenticated()
.and()
.httpBasic().and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.ALWAYS);
// @formatter:on
}
}
I have tried to enable sessions above but if I try to print the session id in the request handlers in login and play, I get different ids after logging in with authentication. I am using HttpBasic security. Is it possible to have sessions in HttpBasic security? I read some articles which seemed to indicate that it is stateless and one cannot. Is there a workaround or do I have to switch to a different security model?
Client code:
On the client side, I send requests as follows for login.
@Override
protected Message doInBackground(Void... params) {
//final String url = getString(R.string.base_uri) + "/getmessage";
final String url = "http://10.0.2.2:8080/login";
// Populate the HTTP Basic Authentitcation header with the username and password
HttpAuthentication authHeader = new HttpBasicAuthentication(username, password);
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.setAuthorization(authHeader);
requestHeaders.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
// Create a new RestTemplate instance
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new MappingJacksonHttpMessageConverter());
try { // Make the network request
Log.d(TAG, url);
ResponseEntity<Message> response = restTemplate.exchange(url, HttpMethod.GET, new HttpEntity<Object>(requestHeaders), Message.class);
if(response.getBody().getId() == 100)
login_success = true;
return response.getBody();
I am trying to write the client code for 'play' similarly but without the need to pass the authentication header. I feel, I should somehow pass a session related parameter in the request header to notify the server that it is part of the same session but cant figure out how to do that.
You are trying to archive stateful communication with sessions, but it won't work since RestTemplate
is working in a stateless manner. It will not keep the state (i.e. the session id) from the login to the next call. Only by setting a custom ClientHttpRequestFactory
I could see this work (I'm not sure on Android).
If you want communication with state, you could look at Apache HttpClient. By using it with a HttpContext
that you re-use between requests, it will keep the state.
There is a possibility to fiddle with the session id yourself, but I can't recommend it.