2
0
Эх сурвалжийг харах

SEC-2092: Add servlet api example

Rob Winch 12 жил өмнө
parent
commit
22e333b9c6

+ 34 - 0
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"

+ 36 - 0
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;
+    }
+}

+ 192 - 0
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:
+ * <ul>
+ * <li>{@link #authenticate(HttpServletRequest, HttpServletResponse)} - Integration with
+ * {@link HttpServletRequest#authenticate(HttpServletResponse)}</li>
+ * <li>{@link #login(HttpServletRequest, HttpServletResponse, LoginForm, BindingResult)} - Integration with
+ * {@link HttpServletRequest#login(String, String)}</li>
+ * <li>{@link #logout(HttpServletRequest, HttpServletResponse)} - Integration with {@link HttpServletRequest#logout()}</li>
+ * <li>{@link #remoteUser(HttpServletRequest)} - Integration with {@link HttpServletRequest#getRemoteUser()}</li>
+ * <li>{@link #userPrincipal(HttpServletRequest)} - Integration with {@link HttpServletRequest#getUserPrincipal()}</li>
+ * <li>{@link #authentication(Authentication)} - Spring MVC's ability to resolve the {@link Authentication} since it is
+ * found on {@link HttpServletRequest#getUserPrincipal()}</li>
+ * </ul>
+ *
+ * @author Rob Winch
+ *
+ */
+@Controller
+public class ServletApiController {
+    /**
+     * Demonstrates that {@link HttpServletRequest#authenticate(HttpServletResponse)} will send the user to the log in
+     * page configured within Spring Security if the user is not already authenticated.
+     *
+     * @param request
+     * @param response
+     * @return
+     * @throws ServletException
+     * @throws IOException
+     */
+    @RequestMapping("/authenticate")
+    public String authenticate(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+        boolean authenticate = request.authenticate(response);
+        return authenticate ? "index" : null;
+    }
+
+    /**
+     * Demonstrates that you can authenticate with Spring Security using
+     * {@link HttpServletRequest#login(String, String)}.
+     *
+     * <p>
+     * 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.
+     * </p>
+     * <p>
+     * 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}.
+     * </p>
+     *
+     * @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";
+    }
+}

+ 23 - 0
samples/servletapi/src/main/resources/applicationContext-security.xml

@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<b:beans xmlns:b="http://www.springframework.org/schema/beans"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xmlns="http://www.springframework.org/schema/security"
+  xmlns:p="http://www.springframework.org/schema/p"
+  xmlns:util="http://www.springframework.org/schema/util"
+  xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd
+    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
+    http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd">
+
+  <http auto-config="true" use-expressions="true">
+    <intercept-url pattern="/**" access="permitAll"/>
+  </http>
+
+  <authentication-manager>
+    <authentication-provider>
+      <user-service>
+        <user name="user" password="password" authorities="ROLE_USER" />
+        <user name="admin" password="password" authorities="ROLE_USER,ROLE_ADMIN"/>
+      </user-service>
+    </authentication-provider>
+  </authentication-manager>
+</b:beans>

+ 24 - 0
samples/servletapi/src/main/webapp/WEB-INF/spring-servlet.xml

@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<b:beans xmlns="http://www.springframework.org/schema/mvc"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xmlns:b="http://www.springframework.org/schema/beans"
+  xmlns:p="http://www.springframework.org/schema/p"
+  xmlns:context="http://www.springframework.org/schema/context"
+  xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
+    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
+    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">
+
+  <context:component-scan base-package="org.springframework.security.samples.servletapi.mvc" />
+
+  <!-- Enables the Spring MVC @Controller programming model -->
+  <annotation-driven/>
+
+  <!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources/ directory -->
+  <resources mapping="/resources/**" location="/resources/" />
+
+  <!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
+  <b:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
+      p:prefix="/WEB-INF/views/"
+      p:suffix=".jsp" />
+
+</b:beans>

+ 44 - 0
samples/servletapi/src/main/webapp/WEB-INF/views/index.jsp

@@ -0,0 +1,44 @@
+<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
+<html>
+<head>
+<title>Welcome</title>
+</head>
+<body>
+  <h1>Home Page</h1>
+  <p>
+    Anyone can view this page.
+  </p>
+
+  <sec:authorize access="authenticated" var="authenticated"/>
+  <c:if test="${authenticated}">
+    <p>You are currently authenticated</p>
+    <dl>
+      <dt>HttpServletRequest.getRemoteUser()</dt>
+      <dd><c:out value="${remoteUser}"/></dd>
+      <dt>HttpServletRequest.getUserPrincipal()</dt>
+      <dd><c:out value="${userPrincipal}"/></dd>
+      <dt>Authentication</dt>
+      <dd><c:out value="${authentication}"/></dd>
+    </dl>
+  </c:if>
+  <ul>
+    <li>
+      <a href="<c:url value="/authenticate"/>">HttpServletRequest.authenticate(HttpServletResponse)</a>
+        - if you are authenticated already will simply return true. Otherwise, will redirect you to the log in page configured in your Spring Security configuration.
+    </li>
+    <li>
+      <a href="<c:url value="/async"/>">AsyncContext.start(Runnable)</a>
+        - will automatically transfer the current SecurityContext to the new Thread
+    </li>
+    <c:choose>
+      <c:when test="${authenticated}">
+        <li><a href="<c:url value="/logout"/>">HttpServletRequest.logout()</a></li>
+      </c:when>
+      <c:otherwise>
+        <li><a href="<c:url value="/login"/>">Fill out log in form</a> - allows the user to invoke HttpServletRequest.login(String,String)</li>
+      </c:otherwise>
+    </c:choose>
+  </ul>
+</body>
+</html>

+ 26 - 0
samples/servletapi/src/main/webapp/WEB-INF/views/login.jsp

@@ -0,0 +1,26 @@
+<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
+<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
+<html>
+<head>
+<title>Please Log In</title>
+</head>
+<body>
+  <h1>Please Log In</h1>
+  <p>This page demonstrates the use of HttpServletRequest.login(String,String) integration with Spring Security.</p>
+  <form:form action="./login" method="post" modelAttribute="loginForm">
+    <form:errors/>
+    <p>
+      <label for="username">Username</label>
+      <form:input path="username"/>
+    </p>
+    <p>
+      <label for="password">Password</label>
+      <form:password path="password"/>
+    </p>
+    <p>
+      <input type="submit" value="Log In"/>
+    </p>
+  </form:form>
+</body>
+</html>

+ 57 - 0
samples/servletapi/src/main/webapp/WEB-INF/web.xml

@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+      version="3.0">
+
+    <!--
+      - Location of the XML file that defines the root application context
+      - Applied by ContextLoaderListener.
+      -->
+    <context-param>
+        <param-name>contextConfigLocation</param-name>
+        <param-value>
+           classpath:applicationContext-security.xml
+        </param-value>
+    </context-param>
+
+   <!-- Nothing below here needs to be modified -->
+
+    <context-param>
+        <param-name>webAppRootKey</param-name>
+        <param-value>servletapi.root</param-value>
+    </context-param>
+
+    <filter>
+        <filter-name>springSecurityFilterChain</filter-name>
+        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
+        <async-supported>true</async-supported>
+    </filter>
+
+    <filter-mapping>
+      <filter-name>springSecurityFilterChain</filter-name>
+      <url-pattern>/*</url-pattern>
+      <dispatcher>REQUEST</dispatcher>
+      <dispatcher>ASYNC</dispatcher>
+    </filter-mapping>
+
+    <!--
+      - Loads the root application context of this web app at startup.
+      - The application context is then available via
+      - WebApplicationContextUtils.getWebApplicationContext(servletContext).
+    -->
+    <listener>
+        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
+    </listener>
+
+    <servlet>
+      <servlet-name>spring</servlet-name>
+      <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
+      <load-on-startup>1</load-on-startup>
+      <async-supported>true</async-supported>
+    </servlet>
+    <servlet-mapping>
+      <servlet-name>spring</servlet-name>
+      <url-pattern>/</url-pattern>
+    </servlet-mapping>
+</web-app>

+ 2 - 1
settings.gradle

@@ -23,7 +23,8 @@ def String[] samples = [
     'cas/server',
     'cas/sample',
     'ldap',
-    'jaas'
+    'jaas',
+    'servletapi'
 ]
 
 def String[] itest = [