diff --git a/samples/servletapi/servletapi.gradle b/samples/servletapi/servletapi.gradle new file mode 100644 index 0000000000..5161c79ab1 --- /dev/null +++ b/samples/servletapi/servletapi.gradle @@ -0,0 +1,34 @@ +// Servlet API integration sample build file + +apply plugin: 'war' + +def excludeModules = ['spring-security-acl', 'jsr250-api', 'ehcache', 'spring-jdbc', 'spring-tx'] + +configurations { + excludeModules.each {name -> + runtime.exclude module: name + } + + runtime.exclude group: 'org.aspectj' +} + +dependencies { + providedCompile "org.apache.tomcat:tomcat-servlet-api:$servletApiVersion" + + compile project(':spring-security-core'), + project(':spring-security-web'), + "javax.servlet:jstl:$jstlVersion", + "org.springframework:spring-beans:$springVersion", + "org.springframework:spring-context:$springVersion", + "org.springframework:spring-web:$springVersion", + "org.springframework:spring-webmvc:$springVersion" + + runtime project(':spring-security-config'), + project(':spring-security-taglibs'), + "org.springframework:spring-context-support:$springVersion", + "javax.servlet:jstl:$jstlVersion", + "org.slf4j:jcl-over-slf4j:$slf4jVersion", + "ch.qos.logback:logback-classic:$logbackVersion" +} + +eclipse.wtp.component.contextPath = "servletapi" diff --git a/samples/servletapi/src/main/java/org/springframework/security/samples/servletapi/mvc/LoginForm.java b/samples/servletapi/src/main/java/org/springframework/security/samples/servletapi/mvc/LoginForm.java new file mode 100644 index 0000000000..fc5a0eb117 --- /dev/null +++ b/samples/servletapi/src/main/java/org/springframework/security/samples/servletapi/mvc/LoginForm.java @@ -0,0 +1,36 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package org.springframework.security.samples.servletapi.mvc; + +/** + * + * @author Rob Winch + * + */ +public class LoginForm { + private String username; + private String password; + + public String getUsername() { + return username; + } + public void setUsername(String username) { + this.username = username; + } + public String getPassword() { + return password; + } + public void setPassword(String password) { + this.password = password; + } +} \ No newline at end of file diff --git a/samples/servletapi/src/main/java/org/springframework/security/samples/servletapi/mvc/ServletApiController.java b/samples/servletapi/src/main/java/org/springframework/security/samples/servletapi/mvc/ServletApiController.java new file mode 100644 index 0000000000..9e3a584d1a --- /dev/null +++ b/samples/servletapi/src/main/java/org/springframework/security/samples/servletapi/mvc/ServletApiController.java @@ -0,0 +1,192 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package org.springframework.security.samples.servletapi.mvc; + +import java.io.IOException; +import java.security.Principal; + +import javax.naming.AuthenticationException; +import javax.servlet.AsyncContext; +import javax.servlet.Servlet; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.web.access.ExceptionTranslationFilter; +import org.springframework.stereotype.Controller; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.servlet.mvc.support.RedirectAttributes; + +/** + * A Spring MVC Controller that demonstrates Spring Security's integration with the standard Servlet API's. Specifically + * it demonstrates the following: + *
+ * If we fail to authenticate, a {@link ServletException} is thrown that wraps the original + * {@link AuthenticationException} from Spring Security. This means we can catch the {@link ServletException} to + * display the error message. Alternatively, we could allow the {@link ServletException} to propegate and Spring + * Security's {@link ExceptionTranslationFilter} would catch it and process it appropriately. + *
+ *+ * In this method we choose to use Spring MVC's {@link ModelAttribute} to make things easier for our form. However, + * this is not necessary. We could have just as easily obtained the request parameters from the + * {@link HttpServletRequest} object. Remember all of these examples would work in a standard {@link Servlet} or + * anything with access to the {@link HttpServletRequest} and {@link HttpServletResponse}. + *
+ * + * @param request + * @param response + * @param loginForm + * @param result + * @return + * @throws ServletException + */ + @RequestMapping(value = "/login", method = RequestMethod.POST) + public String login(HttpServletRequest request, HttpServletResponse response, + @ModelAttribute LoginForm loginForm, BindingResult result) throws ServletException { + try { + request.login(loginForm.getUsername(), loginForm.getPassword()); + } catch(ServletException authenticationFailed) { + result.rejectValue(null, "authentication.failed", authenticationFailed.getMessage()); + return "login"; + } + return "redirect:/"; + } + + /** + * Demonstrates that invoking {@link HttpServletRequest#logout()} will log the user out. Note that the response does + * not get processed, so you need to write something to the response. + * @param request + * @param response + * @param redirect + * @return + * @throws ServletException + */ + @RequestMapping("/logout") + public String logout(HttpServletRequest request, HttpServletResponse response, RedirectAttributes redirect) throws ServletException { + request.logout(); + return "redirect:/"; + } + + /** + * Demonstrates Spring Security with {@link AsyncContext#start(Runnable)}. Spring Security will automatically + * transfer the {@link SecurityContext} from the thread that {@link AsyncContext#start(Runnable)} is invoked to the + * new Thread that invokes the {@link Runnable}. + * @param request + * @param response + */ + @RequestMapping("/async") + public void asynch(HttpServletRequest request, HttpServletResponse response) { + final AsyncContext async = request.startAsync(); + async.start(new Runnable() { + public void run() { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + try { + final HttpServletResponse asyncResponse = (HttpServletResponse) async.getResponse(); + asyncResponse.setStatus(HttpServletResponse.SC_OK); + asyncResponse.getWriter().write(String.valueOf(authentication)); + async.complete(); + } catch(Exception e) { + throw new RuntimeException(e); + } + } + }); + } + + /** + * Demonstrates that Spring Security automatically populates {@link HttpServletRequest#getRemoteUser()} with the + * current username. + * @param request + * @return + */ + @ModelAttribute("remoteUser") + public String remoteUser(HttpServletRequest request) { + return request.getRemoteUser(); + } + + /** + * Demonstrates that Spring Security automatically populates {@link HttpServletRequest#getUserPrincipal()} with the + * {@link Authentication} that is present on {@link SecurityContextHolder#getContext()} + * @param request + * @return + */ + @ModelAttribute("userPrincipal") + public Principal userPrincipal(HttpServletRequest request) { + return request.getUserPrincipal(); + } + + /** + * Spring MVC will automatically resolve any object that implements {@link Principal} using + * {@link HttpServletRequest#getUserPrincipal()}. This means you can easily resolve the {@link Authentication} just + * by adding it as an argument to your MVC controller. Alternatively, you could also have an argument of type + * {@link Principal} which would not couple your controller to Spring Security. + * @param authentication + * @return + */ + @ModelAttribute + public Authentication authentication(Authentication authentication) { + return authentication; + } + + @RequestMapping("/") + public String welcome() { + return "index"; + } + + @RequestMapping(value = "/login", method = RequestMethod.GET) + public String login(@ModelAttribute LoginForm loginForm) { + return "login"; + } +} \ No newline at end of file diff --git a/samples/servletapi/src/main/resources/applicationContext-security.xml b/samples/servletapi/src/main/resources/applicationContext-security.xml new file mode 100644 index 0000000000..565af9bb69 --- /dev/null +++ b/samples/servletapi/src/main/resources/applicationContext-security.xml @@ -0,0 +1,23 @@ + ++ Anyone can view this page. +
+ +You are currently authenticated
+This page demonstrates the use of HttpServletRequest.login(String,String) integration with Spring Security.
+
+
+
+
+
+ +
+