package org.magnum.mobilecloud.video;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.http.HttpStatus;
import org.magnum.mobilecloud.video.client.VideoSvcApi;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.security.web.savedrequest.NullRequestCache;
@Configuration
// Setup Spring Security to intercept incoming requests to the Controllers
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
// This anonymous inner class' onAuthenticationSuccess() method is invoked
// whenever a client successfully logs in. The class just sends back an
// HTTP 200 OK status code to the client so that they know they logged
// in correctly. The class does not redirect the client anywhere like the
// default handler does with a HTTP 302 response. The redirect has been
// removed to be friendlier to mobile clients and Retrofit.
private static final AuthenticationSuccessHandler NO_REDIRECT_SUCCESS_HANDLER = new AuthenticationSuccessHandler() {
@Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication)
throws IOException, ServletException {
response.setStatus(HttpStatus.SC_OK);
}
};
// Normally, the logout success handler redirects the client to the login page. We
// just want to let the client know that it succcessfully logged out and make the
// response a bit of JSON so that Retrofit can handle it. The handler sends back
// a 200 OK response and an empty JSON object.
private static final LogoutSuccessHandler JSON_LOGOUT_SUCCESS_HANDLER = new LogoutSuccessHandler() {
@Override
public void onLogoutSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication)
throws IOException, ServletException {
response.setStatus(HttpStatus.SC_OK);
response.setContentType("application/json");
response.getWriter().write("{}");
}
};
/**
* This method is used to inject access control policies into Spring
* security to control what resources / paths / http methods clients have
* access to.
*/
@Override
protected void configure(final HttpSecurity http) throws Exception {
// By default, Spring inserts a token into web pages to prevent
// cross-site request forgery attacks.
// See: http://en.wikipedia.org/wiki/Cross-site_request_forgery
//
// Unfortunately, there is no easy way with the default setup to communicate
// these CSRF tokens to a mobile client so we disable them.
// Don't worry, the next iteration of the example will fix this
// problem.
http.csrf().disable();
// We don't want to cache requests during login
http.requestCache().requestCache(new NullRequestCache());
// Allow all clients to access the login page and use
// it to login
http.formLogin()
// The default login url on Spring is "j_security_check" ...
// which isn't very friendly. We change the login url to
// something more reasonable ("/login").
.loginProcessingUrl(VideoSvcApi.LOGIN_PATH)
// The default login system is designed to redirect you to
// another URL after you successfully authenticate. For mobile
// clients, we don't want to be redirected, we just want to tell
// them that they successfully authenticated and return a session
// cookie to them. this extra configuration option ensures that the
// client isn't redirected anywhere with an HTTP 302 response code.
.successHandler(NO_REDIRECT_SUCCESS_HANDLER)
// Allow everyone to access the login URL
.permitAll();
// Make sure that clients can logout too!!
http.logout()
// Change the default logout path to /logout
.logoutUrl(VideoSvcApi.LOGOUT_PATH)
// Make sure that a redirect is not sent to the client
// on logout
.logoutSuccessHandler(JSON_LOGOUT_SUCCESS_HANDLER)
// Allow everyone to access the logout URL
.permitAll();
// Require clients to login and have an account with the "user" role
// in order to access /video
// http.authorizeRequests().antMatchers("/video").hasRole("user");
// Require clients to login and have an account with the "user" role
// in order to send a POST request to /video
// http.authorizeRequests().antMatchers(HttpMethod.POST, "/video").hasRole("user");
// We force clients to authenticate before accessing ANY URLs
// other than the login and lougout that we have configured above.
http.authorizeRequests().anyRequest().authenticated();
}
/**
*
* This method is used to setup the users that will be able to login to the
* system. This is a VERY insecure setup that is using two hardcoded users /
* passwords and should never be used for anything other than local testing
* on a machine that is not accessible via the Internet. Even if you use
* this code for testing, at the bare minimum, you should change the
* passwords listed below.
*
* @param auth
* @throws Exception
*/
@Autowired
protected void registerAuthentication(
final AuthenticationManagerBuilder auth) throws Exception {
// This example creates a simple in-memory UserDetailService that
// is provided by Spring
auth.inMemoryAuthentication()
.withUser("coursera")
.password("changeit")
.authorities("admin","user")
.and()
.withUser("student")
.password("changeit")
.authorities("user");
}
}