mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-05-31 01:02:14 +00:00
SEC-2095: Document Servlet API support
This commit is contained in:
parent
664220f304
commit
246c632f3a
@ -128,6 +128,7 @@
|
||||
</partintro>
|
||||
<xi:include href="security-filter-chain.xml"/>
|
||||
<xi:include href="core-filters.xml"/>
|
||||
<xi:include href="servlet-api.xml"/>
|
||||
<xi:include href="basic-and-digest-auth.xml"/>
|
||||
<xi:include href="remember-me-authentication.xml"/>
|
||||
<xi:include href="csrf.xml"/>
|
||||
|
167
docs/manual/src/docbook/servlet-api.xml
Normal file
167
docs/manual/src/docbook/servlet-api.xml
Normal file
@ -0,0 +1,167 @@
|
||||
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="servletapi"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<info>
|
||||
<title>Servlet API integration</title>
|
||||
</info>
|
||||
<para>This section describes how Spring Security is integrated with the Servlet API. The
|
||||
<link xlink:href="https://github.com/SpringSource/spring-security/blob/master/samples/servletapi-xml">servletapi-xml</link> sample application demonstrates
|
||||
the usage of each of these methods.</para>
|
||||
<section xml:id="servletapi-25">
|
||||
<title>Servlet 2.5+ Integration</title>
|
||||
<section xml:id="servletapi-remote-user">
|
||||
<title>HttpServletRequest.getRemoteUser()</title>
|
||||
<para>The <link xlink:href="http://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#getRemoteUser()">HttpServletRequest.getRemoteUser()</link>
|
||||
will return the result of <literal>SecurityContextHolder.getContext().getAuthentication().getName()</literal> which is typically the current
|
||||
username. This can be useful if you want to display the current username in your application. Additionally, checking if this
|
||||
is null can be used to indicate if a user has authenticated or is anonymous. Knowing if the user is authenticated or not can
|
||||
be useful for determining if certain UI elements should be shown or not (i.e. a log out link should only be displayed if the
|
||||
user is authenticated).</para>
|
||||
</section>
|
||||
<section xml:id="servletapi-user-principal">
|
||||
<title>HttpServletRequest.getUserPrincipal()</title>
|
||||
<para>The <link xlink:href="http://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#getUserPrincipal()">HttpServletRequest.getUserPrincipal()</link>
|
||||
will return the result of <literal>SecurityContextHolder.getContext().getAuthentication()</literal>. This means it is an <interfacename>Authentication</interfacename>
|
||||
which is typically an instance of <classname>UsernamePasswordAuthenticationToken</classname> when using username and password based authentication. This can be useful if
|
||||
you need additional information about your user. For example, you might have created a custom <interfacename>UserDetailsService</interfacename>
|
||||
that returns a custom <interfacename>UserDetails</interfacename> containing a first and last name for your user. You could obtain this information with the
|
||||
following:</para>
|
||||
<programlisting language="java"><![CDATA[Authentication auth = httpServletRequest.getUserPrincipal();
|
||||
// assume integrated custom UserDetails called MyCustomUserDetails
|
||||
// by default, typically instance of UserDetails
|
||||
MyCustomUserDetails userDetails = (MyCustomUserDetails) auth.getPrincipal();
|
||||
String firstName = userDetails.getFirstName();
|
||||
String lastName = userDetails.getLastName();
|
||||
]]></programlisting>
|
||||
<note>
|
||||
<para>It should be noted that it is typically bad practice to perform so much logic throughout your application. Instead, one should centralize it to reduce
|
||||
any coupling of Spring Security and the Servlet API's.
|
||||
</para>
|
||||
</note>
|
||||
</section>
|
||||
<section xml:id="servletapi-user-in-role">
|
||||
<title>HttpServletRequest.isUserInRole(String)</title>
|
||||
<para>The <link xlink:href="http://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#isUserInRole(java.lang.String)">HttpServletRequest.isUserInRole(String)</link>
|
||||
will determine if <literal>SecurityContextHolder.getContext().getAuthentication().getAuthorities()</literal> contains a
|
||||
<interfacename>GrantedAuthority</interfacename> with the role passed into <literal>isUserInRole(String)</literal>. Typically users should not pass in the "ROLE_" prefix
|
||||
into this method since it is added automatically. For example, if you want to determine if the current user has the authority "ROLE_ADMIN", you could use the
|
||||
the following:</para>
|
||||
<programlisting language="java"><![CDATA[boolean isAdmin = httpServletRequest.isUserInRole("ADMIN");]]></programlisting>
|
||||
<para>This might be useful to determine if certain UI components should be displayed. For example, you might display admin links only if the current
|
||||
user is an admin.</para>
|
||||
</section>
|
||||
</section>
|
||||
<section xml:id="servletapi-3">
|
||||
<title>Servlet 3+ Integration</title>
|
||||
<para>The following section describes the Servlet 3 methods that Spring Security integrates with.</para>
|
||||
<section xml:id="servletapi-authenticate">
|
||||
<title>HttpServletRequest.authenticate(HttpServletRequest,HttpServletResponse)</title>
|
||||
<para>The <link xlink:href="http://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#authenticate%28javax.servlet.http.HttpServletResponse%29">HttpServletRequest.authenticate(HttpServletRequest,HttpServletResponse)</link>
|
||||
method can be used to ensure that a user is authenticated. If they are not authenticated, the configured AuthenticationEntryPoint will be used to request the user to authenticate
|
||||
(i.e. redirect to the login page).</para>
|
||||
</section>
|
||||
<section xml:id="servletapi-login">
|
||||
<title>HttpServletRequest.login(String,String)</title>
|
||||
<para>The <link xlink:href="http://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#login%28java.lang.String,%20java.lang.String%29">HttpServletRequest.login(String,String)</link>
|
||||
method can be used to authenticate the user with the current <interfacename>AuthenticationManager</interfacename>. For example, the following would attempt to
|
||||
authenticate with the username "user" and password "password":</para>
|
||||
<programlisting language="java"><![CDATA[try {
|
||||
httpServletRequest.login("user","password");
|
||||
} catch(ServletException e) {
|
||||
// fail to authenticate
|
||||
}]]></programlisting>
|
||||
<note>
|
||||
<para>It is not necessary to catch the ServletException if you want Spring Security to process the failed authentication attempt.</para>
|
||||
</note>
|
||||
</section>
|
||||
<section xml:id="servletapi-logout">
|
||||
<title>HttpServletRequest.logout()</title>
|
||||
<para>The <link xlink:href="http://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#logout%28%29">HttpServletRequest.logout()</link>
|
||||
method can be used to log the current user out.</para>
|
||||
<para>Typically this means that the SecurityContextHolder will be cleared out, the HttpSession will be invalidated, any "Remember Me" authentication will be
|
||||
cleaned up, etc. However, the configured LogoutHandler implementations will vary depending on your Spring Security configuration. It is important to note
|
||||
that after HttpServletRequest.logout() has been invoked, you are still in charge of writing a response out. Typically this would involve a redirect to the
|
||||
welcome page.</para>
|
||||
</section>
|
||||
<section xml:id="servletapi-start-runnable">
|
||||
<title>AsyncContext.start(Runnable)</title>
|
||||
<para>The <link xlink:href="http://docs.oracle.com/javaee/6/api/javax/servlet/AsyncContext.html#start%28java.lang.Runnable%29">AsynchContext.start(Runnable)</link>
|
||||
method that ensures your credentials will be propagated to the new Thread. Using Spring Security's concurrency support, Spring Security overrides
|
||||
the AsyncContext.start(Runnable) to ensure that the current SecurityContext is used when processing the Runnable. For example, the following
|
||||
would output the current user's Authentication:</para>
|
||||
<programlisting language="java"><![CDATA[final AsyncContext async = httpServletRequest.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);
|
||||
}
|
||||
}
|
||||
});]]></programlisting>
|
||||
</section>
|
||||
<section xml:id="servletapi-async">
|
||||
<title>Async Servlet Support</title>
|
||||
<para>If you are using Java Based configuration, you are ready to go. If you are using XML configuration, there are
|
||||
a few updates that are necessary. The first step is to ensure you have updated your web.xml to use at least the 3.0 schema
|
||||
as shown below:</para>
|
||||
<programlisting language="xml"><![CDATA[<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">
|
||||
|
||||
</web-app>]]></programlisting>
|
||||
<para>Next you need to ensure that your springSecurityFilterChain is setup for processing asynchronous requests.</para>
|
||||
<programlisting language="xml"><![CDATA[<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>]]></programlisting>
|
||||
<para>That's it! Now Spring Security will ensure that your SecurityContext is propagated on asynchronous requests too.</para>
|
||||
<para>So how does it work? If you are not really interested, feel free to skip the remainder of this section, otherwise read on. Most of this
|
||||
is built into the Servlet specification, but there is a little bit of tweaking that Spring Security does to ensure things work with
|
||||
asynchronous requests properly. Prior to Spring Security 3.2, the SecurityContext from the SecurityContextHolder was automatically saved as soon
|
||||
as the HttpServletResponse was committed. This can cause issues in a Async environment. For example, consider the following:</para>
|
||||
<programlisting language="java"><![CDATA[httpServletRequest.startAsync();
|
||||
new Thread("AsyncThread") {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
// Do work
|
||||
TimeUnit.SECONDS.sleep(1);
|
||||
|
||||
// Write to and commit the httpServletResponse
|
||||
httpServletResponse.getOutputStream().flush();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}.start();]]></programlisting>
|
||||
<para>The issue is that this Thread is not known to Spring Security, so the SecurityContext is not propagated to it. This means when we commit the
|
||||
HttpServletResponse there is no SecuriytContext. When Spring Security automatically saved the SecurityContext on committing the HttpServletResponse it
|
||||
would lose our logged in user.</para>
|
||||
<para>Since version 3.2, Spring Security is smart enough to no longer automatically save the SecurityContext on commiting the HttpServletResponse
|
||||
as soon as HttpServletRequest.startAsync() is invoked.</para>
|
||||
</section>
|
||||
</section>
|
||||
<section xml:id="servletapi-31">
|
||||
<title>Servlet 3.1+ Integration</title>
|
||||
<para>The following section describes the Servlet 3.1 methods that Spring Security integrates with.</para>
|
||||
<section xml:id="servletapi-authenticate">
|
||||
<title>HttpServletRequest#changeSessionId()</title>
|
||||
<para>The <link xlink:href="http://docs.oracle.com/javaee/7/api/javax/servlet/http/HttpServletRequest.html#changeSessionId()">HttpServletRequest.changeSessionId()</link>
|
||||
is the default method for protecting against <link linkend="ns-session-fixation">Session Fixation</link> attacks in Servlet 3.1 and higher.</para>
|
||||
</section>
|
||||
</section>
|
||||
</chapter>
|
Loading…
x
Reference in New Issue
Block a user