|
@@ -1,952 +0,0 @@
|
|
-<?xml version="1.0" encoding="UTF-8"?>
|
|
|
|
-<?oxygen RNGSchema="http://www.oasis-open.org/docbook/xml/5.0/rng/docbook.rng" type="xml"?>
|
|
|
|
-<article class="faq" xml:id="spring-security-faq" xmlns="http://docbook.org/ns/docbook"
|
|
|
|
- xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0">
|
|
|
|
- <info>
|
|
|
|
- <title>Frequently Answered Questions (FAQ)</title>
|
|
|
|
- </info>
|
|
|
|
- <section>
|
|
|
|
- <title>General Questions</title>
|
|
|
|
- <qandaset>
|
|
|
|
- <qandadiv>
|
|
|
|
- <qandaentry xml:id="faq-other-concerns">
|
|
|
|
- <question>
|
|
|
|
- <para>Will Spring Security take care of all my application security
|
|
|
|
- requirements?</para>
|
|
|
|
- </question>
|
|
|
|
- <answer>
|
|
|
|
- <para> Spring Security provides you with a very flexible framework for your
|
|
|
|
- authentication and authorization requirements, but there are many other
|
|
|
|
- considerations for building a secure application that are outside its
|
|
|
|
- scope. Web applications are vulnerable to all kinds of attacks which you
|
|
|
|
- should be familiar with, preferably before you start development so you
|
|
|
|
- can design and code with them in mind from the beginning. Check out the
|
|
|
|
- <link xlink:href="http://www.owasp.org/">OWASP web site</link> for
|
|
|
|
- information on the major issues facing web application developers and
|
|
|
|
- the countermeasures you can use against them.</para>
|
|
|
|
- </answer>
|
|
|
|
- </qandaentry>
|
|
|
|
- <qandaentry xml:id="faq-web-xml">
|
|
|
|
- <question>
|
|
|
|
- <para>Why not just use web.xml security?</para>
|
|
|
|
- </question>
|
|
|
|
- <answer>
|
|
|
|
- <para>Let's assume you're developing an enterprise application based on
|
|
|
|
- Spring. There are four security concerns you typically need to address:
|
|
|
|
- authentication, web request security, service layer security (i.e. your
|
|
|
|
- methods that implement business logic), and domain object instance
|
|
|
|
- security (i.e. different domain objects have different permissions).
|
|
|
|
- With these typical requirements in mind: <orderedlist>
|
|
|
|
- <listitem>
|
|
|
|
- <para><emphasis>Authentication</emphasis>: The servlet specification
|
|
|
|
- provides an approach to authentication. However, you will need
|
|
|
|
- to configure the container to perform authentication which
|
|
|
|
- typically requires editing of container-specific "realm"
|
|
|
|
- settings. This makes a non-portable configuration, and if you
|
|
|
|
- need to write an actual Java class to implement the container's
|
|
|
|
- authentication interface, it becomes even more non-portable.
|
|
|
|
- With Spring Security you achieve complete portability - right
|
|
|
|
- down to the WAR level. Also, Spring Security offers a choice of
|
|
|
|
- production-proven authentication providers and mechanisms,
|
|
|
|
- meaning you can switch your authentication approaches at
|
|
|
|
- deployment time. This is particularly valuable for software
|
|
|
|
- vendors writing products that need to work in an unknown target
|
|
|
|
- environment.</para>
|
|
|
|
- </listitem>
|
|
|
|
- <listitem>
|
|
|
|
- <para><emphasis>Web request security:</emphasis> The servlet
|
|
|
|
- specification provides an approach to secure your request URIs.
|
|
|
|
- However, these URIs can only be expressed in the servlet
|
|
|
|
- specification's own limited URI path format. Spring Security
|
|
|
|
- provides a far more comprehensive approach. For instance, you
|
|
|
|
- can use Ant paths or regular expressions, you can consider parts
|
|
|
|
- of the URI other than simply the requested page (e.g. you can
|
|
|
|
- consider HTTP GET parameters) and you can implement your own
|
|
|
|
- runtime source of configuration data. This means your web
|
|
|
|
- request security can be dynamically changed during the actual
|
|
|
|
- execution of your webapp.</para>
|
|
|
|
- </listitem>
|
|
|
|
- <listitem>
|
|
|
|
- <para><emphasis>Service layer and domain object security:</emphasis>
|
|
|
|
- The absence of support in the servlet specification for services
|
|
|
|
- layer security or domain object instance security represent
|
|
|
|
- serious limitations for multi-tiered applications. Typically
|
|
|
|
- developers either ignore these requirements, or implement
|
|
|
|
- security logic within their MVC controller code (or even worse,
|
|
|
|
- inside the views). There are serious disadvantages with this
|
|
|
|
- approach: <orderedlist>
|
|
|
|
- <listitem>
|
|
|
|
- <para><emphasis>Separation of concerns:</emphasis>
|
|
|
|
- Authorization is a crosscutting concern and should be
|
|
|
|
- implemented as such. MVC controllers or views
|
|
|
|
- implementing authorization code makes it more difficult
|
|
|
|
- to test both the controller and authorization logic,
|
|
|
|
- more difficult to debug, and will often lead to code
|
|
|
|
- duplication.</para>
|
|
|
|
- </listitem>
|
|
|
|
- <listitem>
|
|
|
|
- <para><emphasis>Support for rich clients and web
|
|
|
|
- services:</emphasis> If an additional client type must
|
|
|
|
- ultimately be supported, any authorization code embedded
|
|
|
|
- within the web layer is non-reusable. It should be
|
|
|
|
- considered that Spring remoting exporters only export
|
|
|
|
- service layer beans (not MVC controllers). As such
|
|
|
|
- authorization logic needs to be located in the services
|
|
|
|
- layer to support a multitude of client types.</para>
|
|
|
|
- </listitem>
|
|
|
|
- <listitem>
|
|
|
|
- <para><emphasis>Layering issues:</emphasis> An MVC
|
|
|
|
- controller or view is simply the incorrect architectural
|
|
|
|
- layer to implement authorization decisions concerning
|
|
|
|
- services layer methods or domain object instances.
|
|
|
|
- Whilst the Principal may be passed to the services layer
|
|
|
|
- to enable it to make the authorization decision, doing
|
|
|
|
- so would introduce an additional argument on every
|
|
|
|
- services layer method. A more elegant approach is to use
|
|
|
|
- a ThreadLocal to hold the Principal, although this would
|
|
|
|
- likely increase development time to a point where it
|
|
|
|
- would become more economical (on a cost-benefit basis)
|
|
|
|
- to simply use a dedicated security framework.</para>
|
|
|
|
- </listitem>
|
|
|
|
- <listitem>
|
|
|
|
- <para><emphasis>Authorisation code quality:</emphasis> It is
|
|
|
|
- often said of web frameworks that they "make it easier
|
|
|
|
- to do the right things, and harder to do the wrong
|
|
|
|
- things". Security frameworks are the same, because they
|
|
|
|
- are designed in an abstract manner for a wide range of
|
|
|
|
- purposes. Writing your own authorization code from
|
|
|
|
- scratch does not provide the "design check" a framework
|
|
|
|
- would offer, and in-house authorization code will
|
|
|
|
- typically lack the improvements that emerge from
|
|
|
|
- widespread deployment, peer review and new versions.
|
|
|
|
- </para>
|
|
|
|
- </listitem>
|
|
|
|
- </orderedlist></para>
|
|
|
|
- </listitem>
|
|
|
|
- </orderedlist></para>
|
|
|
|
- <para> For simple applications, servlet specification security may just be
|
|
|
|
- enough. Although when considered within the context of web container
|
|
|
|
- portability, configuration requirements, limited web request security
|
|
|
|
- flexibility, and non-existent services layer and domain object instance
|
|
|
|
- security, it becomes clear why developers often look to alternative
|
|
|
|
- solutions. </para>
|
|
|
|
- </answer>
|
|
|
|
- </qandaentry>
|
|
|
|
- <qandaentry xml:id="faq-requirements">
|
|
|
|
- <question>
|
|
|
|
- <para>What Java and Spring Framework versions are required?</para>
|
|
|
|
- </question>
|
|
|
|
- <answer>
|
|
|
|
- <para> Spring Security 3.0 and 3.1 require at least JDK 1.5 and also
|
|
|
|
- require Spring 3.0.3 as a minimum. Ideally you should be using the latest
|
|
|
|
- release versions to avoid problems.
|
|
|
|
- </para>
|
|
|
|
- <para> Spring Security 2.0.x requires a minimum JDK version of 1.4 and is
|
|
|
|
- built against Spring 2.0.x. It should also be compatible with
|
|
|
|
- applications using Spring 2.5.x. </para>
|
|
|
|
- </answer>
|
|
|
|
- </qandaentry>
|
|
|
|
- <qandaentry xml:id="faq-start-simple">
|
|
|
|
- <question>
|
|
|
|
- <para> I'm new to Spring Security and I need to build an application that
|
|
|
|
- supports CAS single sign-on over HTTPS, while allowing Basic
|
|
|
|
- authentication locally for certain URLs, authenticating against multiple
|
|
|
|
- back end user information sources (LDAP and JDBC). I've copied some
|
|
|
|
- configuration files I found but it doesn't work. What could be wrong? </para>
|
|
|
|
- <para>Or subsititute an alternative complex scenario...</para>
|
|
|
|
- </question>
|
|
|
|
- <answer>
|
|
|
|
- <para> Realistically, you need an understanding of the technolgies you are
|
|
|
|
- intending to use before you can successfully build applications with
|
|
|
|
- them. Security is complicated. Setting up a simple configuration using a
|
|
|
|
- login form and some hard-coded users using Spring Security's namespace
|
|
|
|
- is reasonably straightforward. Moving to using a backed JDBC database is
|
|
|
|
- also easy enough. But if you try and jump straight to a complicated
|
|
|
|
- deployment scenario like this you will almost certainly be frustrated.
|
|
|
|
- There is a big jump in the learning curve required to set up systems
|
|
|
|
- like CAS, configure LDAP servers and install SSL certificates properly.
|
|
|
|
- So you need to take things one step at a time. </para>
|
|
|
|
- <para> From a Spring Security perspective, the first thing you should do is
|
|
|
|
- follow the <quote>Getting Started</quote> guide on the web site. This
|
|
|
|
- will take you through a series of steps to get up and running and get
|
|
|
|
- some idea of how the framework operates. If you are using other
|
|
|
|
- technologies which you aren't familiar with then you should do some
|
|
|
|
- research and try to make sure you can use them in isolation before
|
|
|
|
- combining them in a complex system. </para>
|
|
|
|
- </answer>
|
|
|
|
- </qandaentry>
|
|
|
|
- </qandadiv>
|
|
|
|
- </qandaset>
|
|
|
|
- </section>
|
|
|
|
- <section>
|
|
|
|
- <title>Common Problems</title>
|
|
|
|
- <qandaset>
|
|
|
|
- <qandadiv>
|
|
|
|
- <title>Authentication</title>
|
|
|
|
- <qandaentry xml:id="faq-bad-credentials">
|
|
|
|
- <question>
|
|
|
|
- <para>When I try to log in, I get an error message that says "Bad
|
|
|
|
- Credentials". What's wrong?</para>
|
|
|
|
- </question>
|
|
|
|
- <answer>
|
|
|
|
- <para>This means that authentication has failed. It doesn't say why, as it
|
|
|
|
- is good practice to avoid giving details which might help an attacker
|
|
|
|
- guess account names or passwords.</para>
|
|
|
|
- <para>This also means that if you ask this question in the forum, you will
|
|
|
|
- not get an answer unless you provide additional information. As with any
|
|
|
|
- issue you should check the output from the debug log, note any exception
|
|
|
|
- stacktraces and related messages. Step through the code in a debugger to
|
|
|
|
- see where the authentication fails and why. Write a test case which
|
|
|
|
- exercises your authentication configuration outside of the application.
|
|
|
|
- More often than not, the failure is due to a difference in the password
|
|
|
|
- data stored in a database and that entered by the user. If you are using
|
|
|
|
- hashed passwords, make sure the value stored in your database is
|
|
|
|
- <emphasis>exactly</emphasis> the same as the value produced by the
|
|
|
|
- <interfacename>PasswordEncoder</interfacename> configured in your
|
|
|
|
- application.</para>
|
|
|
|
- </answer>
|
|
|
|
- </qandaentry>
|
|
|
|
-
|
|
|
|
- <qandaentry xml:id="faq-login-loop">
|
|
|
|
- <question>
|
|
|
|
- <para>My application goes into an "endless loop" when I try to login, what's
|
|
|
|
- going on?</para>
|
|
|
|
- </question>
|
|
|
|
- <answer>
|
|
|
|
- <para>A common user problem with infinite loop and redirecting to the login
|
|
|
|
- page is caused by accidently configuring the login page as a "secured"
|
|
|
|
- resource. Make sure your configuration allows anonymous access to the
|
|
|
|
- login page, either by excluding it from the security filter chain or
|
|
|
|
- marking it as requiring ROLE_ANONYMOUS.</para>
|
|
|
|
- <para>If your AccessDecisionManager includes an AuthenticatedVoter, you can
|
|
|
|
- use the attribute "IS_AUTHENTICATED_ANONYMOUSLY". This is automatically
|
|
|
|
- available if you are using the standard namespace configuration setup. </para>
|
|
|
|
- <para> From Spring Security 2.0.1 onwards, when you are using
|
|
|
|
- namespace-based configuration, a check will be made on loading the
|
|
|
|
- application context and a warning message logged if your login page
|
|
|
|
- appears to be protected. </para>
|
|
|
|
- </answer>
|
|
|
|
- </qandaentry>
|
|
|
|
- <qandaentry xml:id="faq-anon-access-denied">
|
|
|
|
- <question>
|
|
|
|
- <para>I get an exception with the message "Access is denied (user is
|
|
|
|
- anonymous);". What's wrong?</para>
|
|
|
|
- </question>
|
|
|
|
- <answer>
|
|
|
|
- <para> This is a debug level message which occurs the first time an
|
|
|
|
- anonymous user attempts to access a protected resource.
|
|
|
|
- <programlisting>
|
|
|
|
- DEBUG [ExceptionTranslationFilter] - Access is denied (user is anonymous); redirecting to authentication entry point
|
|
|
|
- org.springframework.security.AccessDeniedException: Access is denied
|
|
|
|
- at org.springframework.security.vote.AffirmativeBased.decide(AffirmativeBased.java:68)
|
|
|
|
- at org.springframework.security.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:262)
|
|
|
|
- </programlisting>
|
|
|
|
- It is normal and shouldn't be anything to worry about. </para>
|
|
|
|
- </answer>
|
|
|
|
- </qandaentry>
|
|
|
|
- <qandaentry xml:id="faq-cached-secure-page">
|
|
|
|
- <question>
|
|
|
|
- <para>Why can I still see a secured page even after I've logged out of my
|
|
|
|
- application?</para>
|
|
|
|
- </question>
|
|
|
|
- <answer>
|
|
|
|
- <para>The most common reason for this is that your browser has cached the
|
|
|
|
- page and you are seeing a copy which is being retrieved from the
|
|
|
|
- browsers cache. Verify this by checking whether the browser is actually
|
|
|
|
- sending the request (check your server access logs, the debug log or use
|
|
|
|
- a suitable browser debugging plugin such as <quote>Tamper Data</quote>
|
|
|
|
- for Firefox). This has nothing to do with Spring Security and you should
|
|
|
|
- configure your application or server to set the appropriate
|
|
|
|
- <literal>Cache-Control</literal> response headers. Note that SSL
|
|
|
|
- requests are never cached.</para>
|
|
|
|
- </answer>
|
|
|
|
- </qandaentry>
|
|
|
|
- <qandaentry xml:id="auth-exception-credentials-not-found">
|
|
|
|
- <question>
|
|
|
|
- <para>I get an exception with the message "An Authentication object was not
|
|
|
|
- found in the SecurityContext". What's wrong?</para>
|
|
|
|
- </question>
|
|
|
|
- <answer>
|
|
|
|
- <para> This is a another debug level message which occurs the first time an
|
|
|
|
- anonymous user attempts to access a protected resource, but when you do
|
|
|
|
- not have an <classname>AnonymousAuthenticationFilter</classname> in your
|
|
|
|
- filter chain configuration.
|
|
|
|
- <programlisting>
|
|
|
|
- DEBUG [ExceptionTranslationFilter] - Authentication exception occurred; redirecting to authentication entry point
|
|
|
|
- org.springframework.security.AuthenticationCredentialsNotFoundException:
|
|
|
|
- An Authentication object was not found in the SecurityContext
|
|
|
|
- at org.springframework.security.intercept.AbstractSecurityInterceptor.credentialsNotFound(AbstractSecurityInterceptor.java:342)
|
|
|
|
- at org.springframework.security.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:254)
|
|
|
|
- </programlisting>
|
|
|
|
- It is normal and shouldn't be anything to worry about. </para>
|
|
|
|
- </answer>
|
|
|
|
- </qandaentry>
|
|
|
|
- <qandaentry xml:id="faq-ldap-authentication">
|
|
|
|
- <question><para>I can't get LDAP authentication to work. What's wrong with my configuration?</para></question>
|
|
|
|
- <answer>
|
|
|
|
- <para>
|
|
|
|
- Note that the permissions for an LDAP directory often do not allow you to read the password
|
|
|
|
- for a user. Hence it is often not possible to use the <link linkend="faq-what-is-userdetailservice"><interfacename>UserDetailsService</interfacename>
|
|
|
|
- approach</link> where Spring Security compares the stored password with the one submitted by the user.
|
|
|
|
- The most common approach is to use LDAP <quote>bind</quote>, which is one of the operations
|
|
|
|
- supported by <link xlink:href="http://en.wikipedia.org/wiki/Lightweight_Directory_Access_Protocol">the LDAP protocol</link>.
|
|
|
|
- With this approach, Spring Security validates the password by attempting to authenticate to the directory
|
|
|
|
- as the user.
|
|
|
|
- </para>
|
|
|
|
- <para>The most common problem with LDAP authentication is a lack of knowledge of the
|
|
|
|
- directory server tree structure and configuration. This will be different in different
|
|
|
|
- companies, so you have to find it out yourself. Before adding a Spring Security LDAP
|
|
|
|
- configuration to an application, it's a good idea to write a simple test using standard
|
|
|
|
- Java LDAP code (without Spring Security involved), and make sure you can
|
|
|
|
- get that to work first. For example, to authenticate a user, you could use
|
|
|
|
- the following code:
|
|
|
|
- <programlisting language="java"><![CDATA[
|
|
|
|
- @Test
|
|
|
|
- public void ldapAuthenticationIsSuccessful() throws Exception {
|
|
|
|
- Hashtable<String,String> env = new Hashtable<String,String>();
|
|
|
|
- env.put(Context.SECURITY_AUTHENTICATION, "simple");
|
|
|
|
- env.put(Context.SECURITY_PRINCIPAL, "cn=joe,ou=users,dc=mycompany,dc=com");
|
|
|
|
- env.put(Context.PROVIDER_URL, "ldap://mycompany.com:389/dc=mycompany,dc=com");
|
|
|
|
- env.put(Context.SECURITY_CREDENTIALS, "joespassword");
|
|
|
|
- env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
|
|
|
|
-
|
|
|
|
- InitialLdapContext ctx = new InitialLdapContext(env, null);
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
- ]]></programlisting>
|
|
|
|
- </para>
|
|
|
|
- </answer>
|
|
|
|
- </qandaentry>
|
|
|
|
-
|
|
|
|
- </qandadiv>
|
|
|
|
- <qandadiv xml:id="faq-session-management">
|
|
|
|
- <title>Session Management</title>
|
|
|
|
- <para> Session management issues are a common source of forum questions. If you are
|
|
|
|
- developing Java web applications, you should understand how the session is
|
|
|
|
- maintained between the servlet container and the user's browser. You should also
|
|
|
|
- understand the difference between secure and non-secure cookies and the
|
|
|
|
- implications of using HTTP/HTTPS and switching between the two. Spring Security
|
|
|
|
- has nothing to do with maintaining the session or providing session identifiers.
|
|
|
|
- This is entirely handled by the servlet container. </para>
|
|
|
|
-
|
|
|
|
- <qandaentry xml:id="faq-concurrent-session-same-browser">
|
|
|
|
- <question>
|
|
|
|
- <para>I'm using Spring Security's concurrent session control to prevent
|
|
|
|
- users from logging in more than once at a time. When I open another
|
|
|
|
- browser window after logging in, it doesn't stop me from logging in
|
|
|
|
- again. Why can I log in more than once? </para>
|
|
|
|
- </question>
|
|
|
|
- <answer>
|
|
|
|
- <para>Browsers generally maintain a single session per browser instance. You
|
|
|
|
- cannot have two separate sessions at once. So if you log in again in
|
|
|
|
- another window or tab you are just reauthenticating in the same session.
|
|
|
|
- The server doesn't know anything about tabs, windows or browser
|
|
|
|
- instances. All it sees are HTTP requests and it ties those to a
|
|
|
|
- particular session according to the value of the the JSESSIONID cookie
|
|
|
|
- that they contain. When a user authenticates during a session, Spring
|
|
|
|
- Security's concurrent session control checks the number of
|
|
|
|
- <emphasis>other authenticated sessions</emphasis> that they have. If
|
|
|
|
- they are already authenticated with the same session, then
|
|
|
|
- re-authenticating will have no effect. </para>
|
|
|
|
- </answer>
|
|
|
|
- </qandaentry>
|
|
|
|
-
|
|
|
|
- <qandaentry xml:id="faq-new-session-on-authentication">
|
|
|
|
- <question>
|
|
|
|
- <para>Why does the session Id change when I authenticate through Spring
|
|
|
|
- Security?</para>
|
|
|
|
- </question>
|
|
|
|
- <answer>
|
|
|
|
- <para>With the default configuration, Spring Security changes the session ID
|
|
|
|
- when the user authenticates. If you're using a Servlet 3.1 or newer
|
|
|
|
- container, the session ID is simply changed. If you're using an older
|
|
|
|
- container, Spring Security invalidates the existing session, creates a
|
|
|
|
- new session, and transfers the session data to the new session. Changing
|
|
|
|
- the session identifier in this manner prevents
|
|
|
|
- <quote>session-fixation</quote> attacks. You can find more about this
|
|
|
|
- online and in the reference manual. </para>
|
|
|
|
- </answer>
|
|
|
|
- </qandaentry>
|
|
|
|
-
|
|
|
|
- <qandaentry xml:id="faq-tomcat-https-session">
|
|
|
|
- <question>
|
|
|
|
- <para> I'm using Tomcat (or some other servlet container) and have enabled
|
|
|
|
- HTTPS for my login page, switching back to HTTP afterwards. It doesn't
|
|
|
|
- work - I just end up back at the login page after authenticating.
|
|
|
|
- </para>
|
|
|
|
- </question>
|
|
|
|
- <answer>
|
|
|
|
- <para> This happens because sessions created under HTTPS, for which the
|
|
|
|
- session cookie is marked as <quote>secure</quote>, cannot subsequently
|
|
|
|
- be used under HTTP. The browser will not send the cookie back to the
|
|
|
|
- server and any session state will be lost (including the security
|
|
|
|
- context information). Starting a session in HTTP first should work as
|
|
|
|
- the session cookie won't be marked as secure. However, Spring
|
|
|
|
- Security's <link
|
|
|
|
- xlink:href="http://static.springsource.org/spring-security/site/docs/3.1.x/reference/springsecurity-single.html#ns-session-fixation"
|
|
|
|
- >Session Fixation Protection</link> can interfere with this because
|
|
|
|
- it results in a new session ID cookie being sent back to the user's
|
|
|
|
- browser, usually with the secure flag. To get around this, you can
|
|
|
|
- disable session fixation protection, but in newer Servlet containers
|
|
|
|
- you can also configure session cookies to never use the secure flag.
|
|
|
|
- Note that switching between HTTP and HTTPS
|
|
|
|
- is not a good idea in general, as any application which uses HTTP at all
|
|
|
|
- is vulnerable to man-in-the-middle attacks. To be truly secure, the user
|
|
|
|
- should begin accessing your site in HTTPS and continue using it until
|
|
|
|
- they log out. Even clicking on an HTTPS link from a page accessed over
|
|
|
|
- HTTP is potentially risky. If you need more convincing, check out a tool
|
|
|
|
- like <link xlink:href="http://www.thoughtcrime.org/software/sslstrip/"
|
|
|
|
- >sslstrip</link>. </para>
|
|
|
|
- </answer>
|
|
|
|
- </qandaentry>
|
|
|
|
-
|
|
|
|
- <qandaentry>
|
|
|
|
- <question>
|
|
|
|
- <para>I'm not switching between HTTP and HTTPS but my session is still
|
|
|
|
- getting lost</para>
|
|
|
|
- </question>
|
|
|
|
- <answer>
|
|
|
|
- <para>Sessions are maintained either by exchanging a session cookie or by
|
|
|
|
- adding the a <literal>jsessionid</literal> parameter to URLs (this
|
|
|
|
- happens automatically if you are using JSTL to output URLs, or if you
|
|
|
|
- call <literal>HttpServletResponse.encodeUrl</literal> on URLs (before a
|
|
|
|
- redirect, for example). If clients have cookies disabled, and you are
|
|
|
|
- not rewriting URLs to include the <literal>jsessionid</literal>, then
|
|
|
|
- the session will be lost. Note that the use of cookies is preferred for
|
|
|
|
- security reasons, as it does not expose the session information in the
|
|
|
|
- URL. </para>
|
|
|
|
- </answer>
|
|
|
|
- </qandaentry>
|
|
|
|
- <qandaentry xml:id="faq-session-listener-missing">
|
|
|
|
- <question>
|
|
|
|
- <para>I'm trying to use the concurrent session-control support but it won't
|
|
|
|
- let me log back in, even if I'm sure I've logged out and haven't
|
|
|
|
- exceeded the allowed sessions. </para>
|
|
|
|
- </question>
|
|
|
|
- <answer>
|
|
|
|
- <para>Make sure you have added the listener to your web.xml file. It is
|
|
|
|
- essential to make sure that the Spring Security session registry is
|
|
|
|
- notified when a session is destroyed. Without it, the session
|
|
|
|
- information will not be removed from the registry.</para>
|
|
|
|
- <programlisting language="xml"><![CDATA[
|
|
|
|
- <listener>
|
|
|
|
- <listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
|
|
|
|
- </listener> ]]>
|
|
|
|
- </programlisting>
|
|
|
|
- </answer>
|
|
|
|
- </qandaentry>
|
|
|
|
- <qandaentry xml:id="faq-unwanted-session-creation">
|
|
|
|
- <question>
|
|
|
|
- <para>Spring Security is creating a session somewhere, even though I've
|
|
|
|
- configured it not to, by setting the <literal>create-session</literal>
|
|
|
|
- attribute to <literal>never</literal>. </para>
|
|
|
|
- </question>
|
|
|
|
- <answer>
|
|
|
|
- <para>This usually means that the user's application is creating a session
|
|
|
|
- somewhere, but that they aren't aware of it. The most common culprit is
|
|
|
|
- a JSP. Many people aren't aware that JSPs create sessions by default. To
|
|
|
|
- prevent a JSP from creating a session, add the directive <literal><%@
|
|
|
|
- page session="false" %></literal> to the top of the page. </para>
|
|
|
|
- <para> If you are having trouble working out where a session is being
|
|
|
|
- created, you can add some debugging code to track down the location(s).
|
|
|
|
- One way to do this would be to add a
|
|
|
|
- <literal>javax.servlet.http.HttpSessionListener</literal> to your
|
|
|
|
- application, which calls <literal>Thread.dumpStack()</literal> in the
|
|
|
|
- <literal>sessionCreated</literal> method. </para>
|
|
|
|
- </answer>
|
|
|
|
- </qandaentry>
|
|
|
|
- </qandadiv>
|
|
|
|
- <qandadiv>
|
|
|
|
- <title>Miscellaneous</title>
|
|
|
|
- <qandaentry xml:id="faq-no-security-on-forward">
|
|
|
|
- <question>
|
|
|
|
- <para> I'm forwarding a request to another URL using the RequestDispatcher,
|
|
|
|
- but my security constraints aren't being applied. </para>
|
|
|
|
- </question>
|
|
|
|
- <answer>
|
|
|
|
- <para> Filters are not applied by default to forwards or includes. If you
|
|
|
|
- really want the security filters to be applied to forwards and/or
|
|
|
|
- includes, then you have to configure these explicitly in your web.xml
|
|
|
|
- using the <dispatcher> element, a child element of
|
|
|
|
- <filter-mapping>. </para>
|
|
|
|
- </answer>
|
|
|
|
- </qandaentry>
|
|
|
|
- <qandaentry xml:id="faq-method-security-in-web-context">
|
|
|
|
- <question>
|
|
|
|
- <para>I have added Spring Security's <global-method-security> element
|
|
|
|
- to my application context but if I add security annotations to my Spring
|
|
|
|
- MVC controller beans (Struts actions etc.) then they don't seem to have
|
|
|
|
- an effect.</para>
|
|
|
|
- </question>
|
|
|
|
- <answer>
|
|
|
|
- <para> In a Spring web application, the application context which holds the
|
|
|
|
- Spring MVC beans for the dispatcher servlet is often separate from the
|
|
|
|
- main application context. It is often defined in a file called
|
|
|
|
- <literal>myapp-servlet.xml</literal>, where <quote>myapp</quote> is the
|
|
|
|
- name assigned to the Spring <classname>DispatcherServlet</classname> in
|
|
|
|
- <filename>web.xml</filename>. An application can have multiple
|
|
|
|
- <classname>DispatcherServlet</classname>s, each with its own isolated
|
|
|
|
- application context. The beans in these <quote>child</quote> contexts
|
|
|
|
- are not visible to the rest of the application. The
|
|
|
|
- <quote>parent</quote> application context is loaded by the
|
|
|
|
- <classname>ContextLoaderListener</classname> you define in your
|
|
|
|
- <filename>web.xml</filename> and is visible to all the child contexts.
|
|
|
|
- This parent context is usually where you define your security
|
|
|
|
- configuration, including the
|
|
|
|
- <literal><global-method-security></literal> element). As a result
|
|
|
|
- any security constraints applied to methods in these web beans will not
|
|
|
|
- be enforced, since the beans cannot be seen from the
|
|
|
|
- <classname>DispatcherServlet</classname> context. You need to either
|
|
|
|
- move the <literal><global-method-security></literal> declaration
|
|
|
|
- to the web context or moved the beans you want secured into the main
|
|
|
|
- application context. </para>
|
|
|
|
- <para>Generally we would recommend applying method security at the service
|
|
|
|
- layer rather than on individual web controllers.</para>
|
|
|
|
- </answer>
|
|
|
|
- </qandaentry>
|
|
|
|
- <qandaentry xml:id="faq-no-filters-no-context">
|
|
|
|
- <question>
|
|
|
|
- <para>I have a user who has definitely been authenticated, but when I try to
|
|
|
|
- access the <classname>SecurityContextHolder</classname> during some
|
|
|
|
- requests, the <interfacename>Authentication</interfacename> is null. Why
|
|
|
|
- can't I see the user information? </para>
|
|
|
|
- </question>
|
|
|
|
- <answer>
|
|
|
|
- <para>If you have excluded the request from the security filter chain using
|
|
|
|
- the attribute <literal>filters='none'</literal> in the
|
|
|
|
- <literal><intercept-url></literal> element that matches the URL
|
|
|
|
- pattern, then the <classname>SecurityContextHolder</classname> will not
|
|
|
|
- be populated for that request. Check the debug log to see whether the
|
|
|
|
- request is passing through the filter chain. (You are reading the debug
|
|
|
|
- log, right?).</para>
|
|
|
|
- </answer>
|
|
|
|
- </qandaentry>
|
|
|
|
- </qandadiv>
|
|
|
|
- </qandaset>
|
|
|
|
- </section>
|
|
|
|
- <section>
|
|
|
|
- <title>Spring Security Architecture Questions</title>
|
|
|
|
- <qandaset>
|
|
|
|
- <qandadiv>
|
|
|
|
- <qandaentry xml:id="faq-where-is-class-x">
|
|
|
|
- <question>
|
|
|
|
- <para>How do I know which package class X is in?</para>
|
|
|
|
- </question>
|
|
|
|
- <answer>
|
|
|
|
- <para>The best way of locating classes is by installing the Spring Security
|
|
|
|
- source in your IDE. The distribution includes source jars for each of
|
|
|
|
- the modules the project is divided up into. Add these to your project
|
|
|
|
- source path and you can navigate directly to Spring Security classes
|
|
|
|
- (<command>Ctrl-Shift-T</command> in Eclipse). This also makes debugging
|
|
|
|
- easier and allows you to troubleshoot exceptions by looking directly at
|
|
|
|
- the code where they occur to see what's going on there. </para>
|
|
|
|
- </answer>
|
|
|
|
- </qandaentry>
|
|
|
|
- <qandaentry xml:id="faq-namespace-to-bean-mapping">
|
|
|
|
- <question>
|
|
|
|
- <para>How do the namespace elements map to conventional bean
|
|
|
|
- configurations?</para>
|
|
|
|
- </question>
|
|
|
|
- <answer>
|
|
|
|
- <para>There is a general overview of what beans are created by the namespace
|
|
|
|
- in the namespace appendix of the reference guide. There is also a
|
|
|
|
- detailed blog article called <quote>Behind the Spring Security
|
|
|
|
- Namespace</quote> on <link
|
|
|
|
- xlink:href="http://blog.springsource.com/2010/03/06/behind-the-spring-security-namespace/"
|
|
|
|
- >blog.springsource.com</link>. If want to know the full details then the
|
|
|
|
- code is in the <filename>spring-security-config</filename> module within
|
|
|
|
- the Spring Security 3.0 distribution. You should probably read the
|
|
|
|
- chapters on namespace parsing in the standard Spring Framework reference
|
|
|
|
- documentation first.</para>
|
|
|
|
- </answer>
|
|
|
|
- </qandaentry>
|
|
|
|
- <qandaentry xml:id="faq-role-prefix">
|
|
|
|
- <question>
|
|
|
|
- <para>What does <quote>ROLE_</quote> mean and why do I need it on my role
|
|
|
|
- names?</para>
|
|
|
|
- </question>
|
|
|
|
- <answer>
|
|
|
|
- <para>Spring Security has a voter-based architecture which means that an
|
|
|
|
- access decision is made by a series of
|
|
|
|
- <interfacename>AccessDecisionVoter</interfacename>s. The voters act on
|
|
|
|
- the <quote>configuration attributes</quote> which are specified for a
|
|
|
|
- secured resource (such as a method invocation). With this approach, not
|
|
|
|
- all attributes may be relevant to all voters and a voter needs to know
|
|
|
|
- when it should ignore an attribute (abstain) and when it should vote to
|
|
|
|
- grant or deny access based on the attribute value. The most common voter
|
|
|
|
- is the <classname>RoleVoter</classname> which by default votes whenever
|
|
|
|
- it finds an attribute with the <quote>ROLE_</quote> prefix. It makes a
|
|
|
|
- simple comparison of the attribute (such as <quote>ROLE_USER</quote>)
|
|
|
|
- with the names of the authorities which the current user has been
|
|
|
|
- assigned. If it finds a match (they have an authority called
|
|
|
|
- <quote>ROLE_USER</quote>), it votes to grant access, otherwise it votes
|
|
|
|
- to deny access. </para>
|
|
|
|
- <para> The prefix can be changed by setting the
|
|
|
|
- <literal>rolePrefix</literal> property of
|
|
|
|
- <classname>RoleVoter</classname>. If you only need to use roles in your
|
|
|
|
- application and have no need for other custom voters, then you can set
|
|
|
|
- the prefix to a blank string, in which case the
|
|
|
|
- <classname>RoleVoter</classname> will treat all attributes as roles.
|
|
|
|
- </para>
|
|
|
|
- </answer>
|
|
|
|
- </qandaentry>
|
|
|
|
- <qandaentry xml:id="faq-what-dependencies">
|
|
|
|
- <question>
|
|
|
|
- <para>How do I know which dependencies to add to my application to work with
|
|
|
|
- Spring Security?</para>
|
|
|
|
- </question>
|
|
|
|
- <answer>
|
|
|
|
- <para>It will depend on what features you are using and what type of
|
|
|
|
- application you are developing. With Spring Security 3.0, the project
|
|
|
|
- jars are divided into clearly distinct areas of functionality, so it is
|
|
|
|
- straightforward to work out which Spring Security jars you need from
|
|
|
|
- your application requirements. All applications will need the
|
|
|
|
- <filename>spring-security-core</filename> jar. If you're developing a
|
|
|
|
- web application, you need the <filename>spring-security-web</filename>
|
|
|
|
- jar. If you're using security namespace configuration you need the
|
|
|
|
- <filename>spring-security-config</filename> jar, for LDAP support you
|
|
|
|
- need the <filename>spring-security-ldap</filename> jar and so on. </para>
|
|
|
|
- <para> For third-party jars the situation isn't always quite so obvious. A
|
|
|
|
- good starting point is to copy those from one of the pre-built sample
|
|
|
|
- applications WEB-INF/lib directories. For a basic application, you can
|
|
|
|
- start with the tutorial sample. If you want to use LDAP, with an
|
|
|
|
- embedded test server, then use the LDAP sample as a starting point. The
|
|
|
|
- reference manual also includes
|
|
|
|
- <link xlink:href="http://static.springsource.org/spring-security/site/docs/3.1.x/reference/springsecurity-single.html#appendix-dependencies">an appendix</link> listing the first-level
|
|
|
|
- dependencies for each Spring Security module with some information on
|
|
|
|
- whether they are optional and what they are required for. </para>
|
|
|
|
- <para> If you are building your project with maven, then adding the
|
|
|
|
- appropriate Spring Security modules as dependencies to your pom.xml will
|
|
|
|
- automatically pull in the core jars that the framework requires. Any
|
|
|
|
- which are marked as "optional" in the Spring Security POM files will
|
|
|
|
- have to be added to your own pom.xml file if you need them. </para>
|
|
|
|
- </answer>
|
|
|
|
- </qandaentry>
|
|
|
|
- <qandaentry xml:id="faq-apacheds-deps">
|
|
|
|
- <question><para>What dependencies are needed to run an embedded ApacheDS LDAP server?</para></question>
|
|
|
|
- <answer><para>If you are using Maven, you need to add the folowing to your pom dependencies:<programlisting><![CDATA[
|
|
|
|
- <dependency>
|
|
|
|
- <groupId>org.apache.directory.server</groupId>
|
|
|
|
- <artifactId>apacheds-core</artifactId>
|
|
|
|
- <version>1.5.5</version>
|
|
|
|
- <scope>runtime</scope>
|
|
|
|
- </dependency>
|
|
|
|
- <dependency>
|
|
|
|
- <groupId>org.apache.directory.server</groupId>
|
|
|
|
- <artifactId>apacheds-server-jndi</artifactId>
|
|
|
|
- <version>1.5.5</version>
|
|
|
|
- <scope>runtime</scope>
|
|
|
|
- </dependency>
|
|
|
|
-]]></programlisting>. The other required jars should be pulled in transitively.
|
|
|
|
- </para></answer>
|
|
|
|
- </qandaentry>
|
|
|
|
- <qandaentry xml:id="faq-what-is-userdetailservice">
|
|
|
|
- <question>
|
|
|
|
- <para>What is a <interfacename>UserDetailsService</interfacename> and do I need
|
|
|
|
- one?</para>
|
|
|
|
- </question>
|
|
|
|
- <answer>
|
|
|
|
- <para><interfacename>UserDetailsService</interfacename> is a DAO interface
|
|
|
|
- for loading data that is specific to a user account. It has no other
|
|
|
|
- function other to load that data for use by other components within the
|
|
|
|
- framework. It is not responsible for authenticating the user.
|
|
|
|
- Authenticating a user with a username/password combination is most
|
|
|
|
- commonly performed by the
|
|
|
|
- <classname>DaoAuthenticationProvider</classname>, which is injected with
|
|
|
|
- a <interfacename>UserDetailsService</interfacename> to allow it to load
|
|
|
|
- the password (and other data) for a user in order to compare it with the
|
|
|
|
- submitted value. Note that if you are using LDAP,
|
|
|
|
- <link linkend="faq-ldap-authentication">this approach may not work</link>.</para>
|
|
|
|
- <para> If you want to customize the authentication process then you should
|
|
|
|
- implement <interfacename>AuthenticationProvider</interfacename>
|
|
|
|
- yourself. See this <link
|
|
|
|
- xlink:href="http://blog.springsource.com/2010/08/02/spring-security-in-google-app-engine/"
|
|
|
|
- > blog article</link> for an example integrating Spring Security
|
|
|
|
- authentication with Google App Engine. </para>
|
|
|
|
- </answer>
|
|
|
|
- </qandaentry>
|
|
|
|
- </qandadiv>
|
|
|
|
- </qandaset>
|
|
|
|
- </section>
|
|
|
|
- <section>
|
|
|
|
- <title>Common <quote>Howto</quote> Requests</title>
|
|
|
|
- <qandaset>
|
|
|
|
- <qandadiv>
|
|
|
|
- <qandaentry xml:id="faq-extra-login-fields">
|
|
|
|
- <question>
|
|
|
|
- <para>I need to login in with more information than just the username. How
|
|
|
|
- do I add support for extra login fields (e.g. a company name)?</para>
|
|
|
|
- </question>
|
|
|
|
- <answer>
|
|
|
|
- <para>This question comes up repeatedly in the Spring Security forum so you
|
|
|
|
- will find more information there by searching the archives (or through
|
|
|
|
- google).</para>
|
|
|
|
- <para> The submitted login information is processed by an instance of
|
|
|
|
- <classname>UsernamePasswordAuthenticationFilter</classname>. You will
|
|
|
|
- need to customize this class to handle the extra data field(s). One
|
|
|
|
- option is to use your own customized authentication token class (rather
|
|
|
|
- than the standard
|
|
|
|
- <classname>UsernamePasswordAuthenticationToken</classname>), another is
|
|
|
|
- simply to concatenate the extra fields with the username (for example,
|
|
|
|
- using a ":" as the separator) and pass them in the username property of
|
|
|
|
- <classname>UsernamePasswordAuthenticationToken</classname>. </para>
|
|
|
|
- <para> You will also need to customize the actual authentication process. If
|
|
|
|
- you are using a custom authentication token class, for example, you will
|
|
|
|
- have to write an <classname>AuthenticationProvider</classname> to handle
|
|
|
|
- it (or extend the standard
|
|
|
|
- <classname>DaoAuthenticationProvider</classname>). If you have
|
|
|
|
- concatenated the fields, you can implement your own
|
|
|
|
- <interfacename>UserDetailsService</interfacename> which splits them up
|
|
|
|
- and loads the appropriate user data for authentication. </para>
|
|
|
|
- </answer>
|
|
|
|
- </qandaentry>
|
|
|
|
- <qandaentry xml:id="faq-matching-url-fragments">
|
|
|
|
- <question>
|
|
|
|
- <para>How do I apply different <literal>intercept-url</literal> constraints
|
|
|
|
- where only the fragment value of the requested URLs differs (e.g.
|
|
|
|
- <literal>/foo#bar</literal> and <literal>/foo#blah</literal>?</para>
|
|
|
|
- </question>
|
|
|
|
- <answer>
|
|
|
|
- <para>You can't do this, since the fragment is not transmitted from the
|
|
|
|
- browser to the server. The URLs above are identical from the server's
|
|
|
|
- perspective. This is a common question from GWT users.</para>
|
|
|
|
- </answer>
|
|
|
|
- </qandaentry>
|
|
|
|
-
|
|
|
|
- <qandaentry xml:id="faq-request-details-in-user-service">
|
|
|
|
- <question>
|
|
|
|
- <para>How do I access the user's IP Address (or other web-request data) in a
|
|
|
|
- <interfacename>UserDetailsService</interfacename>?</para>
|
|
|
|
- </question>
|
|
|
|
- <answer>
|
|
|
|
- <para> Obviously you can't (without resorting to something like thread-local
|
|
|
|
- variables) since the only information supplied to the interface is the
|
|
|
|
- username. Instead of implementing
|
|
|
|
- <interfacename>UserDetailsService</interfacename>, you should implement
|
|
|
|
- <interfacename>AuthenticationProvider</interfacename> directly and
|
|
|
|
- extract the information from the supplied
|
|
|
|
- <interfacename>Authentication</interfacename> token. </para>
|
|
|
|
- <para> In a standard web setup, the <methodname>getDetails()</methodname>
|
|
|
|
- method on the <interfacename>Authentication</interfacename> object will
|
|
|
|
- return an instance of <classname>WebAuthenticationDetails</classname>.
|
|
|
|
- If you need additional information, you can inject a custom
|
|
|
|
- <interfacename>AuthenticationDetailsSource</interfacename> into the
|
|
|
|
- authentication filter you are using. If you are using the namespace, for
|
|
|
|
- example with the <literal><form-login></literal> element, then you
|
|
|
|
- should remove this element and replace it with a
|
|
|
|
- <literal><custom-filter></literal> declaration pointing to an
|
|
|
|
- explicitly configured
|
|
|
|
- <classname>UsernamePasswordAuthenticationFilter</classname>. </para>
|
|
|
|
- </answer>
|
|
|
|
- </qandaentry>
|
|
|
|
-
|
|
|
|
- <qandaentry xml:id="faq-access-session-from-user-service">
|
|
|
|
- <question>
|
|
|
|
- <para>How do I access the <interfacename>HttpSession</interfacename> from a
|
|
|
|
- <interfacename>UserDetailsService</interfacename>?</para>
|
|
|
|
- </question>
|
|
|
|
- <answer>
|
|
|
|
- <para>You can't, since the <interfacename>UserDetailsService</interfacename>
|
|
|
|
- has no awareness of the servlet API. If you want to store custom user
|
|
|
|
- data, then you should customize the
|
|
|
|
- <interfacename>UserDetails</interfacename> object which is returned.
|
|
|
|
- This can then be accessed at any point, via the thread-local
|
|
|
|
- <classname>SecurityContextHolder</classname>. A call to
|
|
|
|
- <literal>SecurityContextHolder.getContext().getAuthentication().getPrincipal()</literal>
|
|
|
|
- will return this custom object. </para>
|
|
|
|
- <para> If you really need to access the session, then it must be done by
|
|
|
|
- customizing the web tier. </para>
|
|
|
|
- </answer>
|
|
|
|
- </qandaentry>
|
|
|
|
-
|
|
|
|
- <qandaentry xml:id="faq-password-in-user-service">
|
|
|
|
- <question>
|
|
|
|
- <para>How do I access the user's password in a
|
|
|
|
- <interfacename>UserDetailsService</interfacename>?</para>
|
|
|
|
- </question>
|
|
|
|
- <answer>
|
|
|
|
- <para>You can't (and shouldn't). You are probably misunderstanding its purpose.
|
|
|
|
- See <quote><link linkend="faq-what-is-userdetailservice">What is a UserDetailsService?</link></quote>
|
|
|
|
- above.
|
|
|
|
- </para>
|
|
|
|
- </answer>
|
|
|
|
- </qandaentry>
|
|
|
|
-
|
|
|
|
- <qandaentry xml:id="faq-dynamic-url-metadata">
|
|
|
|
- <question>
|
|
|
|
- <para>How do I define the secured URLs within an application
|
|
|
|
- dynamically?</para>
|
|
|
|
- </question>
|
|
|
|
- <answer>
|
|
|
|
- <para>People often ask about how to store the mapping between secured URLs
|
|
|
|
- and security metadata attributes in a database, rather than in the
|
|
|
|
- application context. </para>
|
|
|
|
- <para> The first thing you should ask yourself is if you really need to do
|
|
|
|
- this. If an application requires securing, then it also requires that
|
|
|
|
- the security be tested thoroughly based on a defined policy. It may
|
|
|
|
- require auditing and acceptance testing before being rolled out into a
|
|
|
|
- production environment. A security-conscious organization should be
|
|
|
|
- aware that the benefits of their diligent testing process could be wiped
|
|
|
|
- out instantly by allowing the security settings to be modified at
|
|
|
|
- runtime by changing a row or two in a configuration database. If you
|
|
|
|
- have taken this into account (perhaps using multiple layers of security
|
|
|
|
- within your application) then Spring Security allows you to fully
|
|
|
|
- customize the source of security metadata. You can make it fully dynamic
|
|
|
|
- if you choose. </para>
|
|
|
|
- <para> Both method and web security are protected by subclasses of
|
|
|
|
- <classname>AbstractSecurityInterceptor</classname> which is configured
|
|
|
|
- with a <interfacename>SecurityMetadataSource</interfacename> from which
|
|
|
|
- it obtains the metadata for a particular method or filter invocation.
|
|
|
|
- For web security, the interceptor class is
|
|
|
|
- <classname>FilterSecurityInterceptor</classname> and it uses the marker
|
|
|
|
- interface
|
|
|
|
- <interfacename>FilterInvocationSecurityMetadataSource</interfacename>.
|
|
|
|
- The <quote>secured object</quote> type it operates on is a
|
|
|
|
- <classname>FilterInvocation</classname>. The default implementation
|
|
|
|
- which is used (both in the namespace <literal><http></literal> and
|
|
|
|
- when configuring the interceptor explicitly, stores the list of URL
|
|
|
|
- patterns and their corresponding list of <quote>configuration
|
|
|
|
- attributes</quote> (instances of
|
|
|
|
- <interfacename>ConfigAttribute</interfacename>) in an in-memory map. </para>
|
|
|
|
- <para> To load the data from an alternative source, you must be using an
|
|
|
|
- explicitly declared security filter chain (typically Spring Security's
|
|
|
|
- <classname>FilterChainProxy</classname>) in order to customize the
|
|
|
|
- <classname>FilterSecurityInterceptor</classname> bean. You can't use the
|
|
|
|
- namespace. You would then implement
|
|
|
|
- <interfacename>FilterInvocationSecurityMetadataSource</interfacename> to
|
|
|
|
- load the data as you please for a particular
|
|
|
|
- <classname>FilterInvocation</classname><footnote>
|
|
|
|
- <para>The <classname>FilterInvocation</classname> object contains the
|
|
|
|
- <classname>HttpServletRequest</classname>, so you can obtain the URL
|
|
|
|
- or any other relevant information on which to base your decision on
|
|
|
|
- what the list of returned attributes will contain.</para>
|
|
|
|
- </footnote>. A very basic outline would look something like this: <programlisting language="java"><![CDATA[
|
|
|
|
- public class MyFilterSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
|
|
|
|
-
|
|
|
|
- public List<ConfigAttribute> getAttributes(Object object) {
|
|
|
|
- FilterInvocation fi = (FilterInvocation) object;
|
|
|
|
- String url = fi.getRequestUrl();
|
|
|
|
- String httpMethod = fi.getRequest().getMethod();
|
|
|
|
- List<ConfigAttribute> attributes = new ArrayList<ConfigAttribute>();
|
|
|
|
-
|
|
|
|
- // Lookup your database (or other source) using this information and populate the
|
|
|
|
- // list of attributes
|
|
|
|
-
|
|
|
|
- return attributes;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public Collection<ConfigAttribute> getAllConfigAttributes() {
|
|
|
|
- return null;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public boolean supports(Class<?> clazz) {
|
|
|
|
- return FilterInvocation.class.isAssignableFrom(clazz);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- ]]></programlisting> For more information, look at the code for
|
|
|
|
- <classname>DefaultFilterInvocationSecurityMetadataSource</classname>.
|
|
|
|
- </para>
|
|
|
|
- </answer>
|
|
|
|
- </qandaentry>
|
|
|
|
-
|
|
|
|
- <qandaentry xml:id="faq-ldap-authorities">
|
|
|
|
- <question>
|
|
|
|
- <para>How do I authenticate against LDAP but load user roles from a
|
|
|
|
- database?</para>
|
|
|
|
- </question>
|
|
|
|
- <answer>
|
|
|
|
- <para> The <classname>LdapAuthenticationProvider</classname> bean (which handles
|
|
|
|
- normal LDAP authentication in Spring Security) is configured with two
|
|
|
|
- separate strategy interfaces, one which performs the authenticatation
|
|
|
|
- and one which loads the user authorities, called
|
|
|
|
- <interfacename>LdapAuthenticator</interfacename> and
|
|
|
|
- <interfacename>LdapAuthoritiesPopulator</interfacename> respectively.
|
|
|
|
- The <classname>DefaultLdapAuthoritiesPopulator</classname> loads the
|
|
|
|
- user authorities from the LDAP directory and has various configuration
|
|
|
|
- parameters to allow you to specify how these should be retrieved. </para>
|
|
|
|
- <para> To use JDBC instead, you can implement the interface yourself, using
|
|
|
|
- whatever SQL is appropriate for your schema: <programlisting language="java"><![CDATA[
|
|
|
|
- public class MyAuthoritiesPopulator implements LdapAuthoritiesPopulator {
|
|
|
|
- @Autowired
|
|
|
|
- JdbcTemplate template;
|
|
|
|
-
|
|
|
|
- List<GrantedAuthority> getGrantedAuthorities(DirContextOperations userData, String username) {
|
|
|
|
- List<GrantedAuthority> = template.query("select role from roles where username = ?",
|
|
|
|
- new String[] {username},
|
|
|
|
- new RowMapper<GrantedAuthority>() {
|
|
|
|
- /**
|
|
|
|
- * We're assuming here that you're using the standard convention of using the role
|
|
|
|
- * prefix "ROLE_" to mark attributes which are supported by Spring Security's RoleVoter.
|
|
|
|
- */
|
|
|
|
- public GrantedAuthority mapRow(ResultSet rs, int rowNum) throws SQLException {
|
|
|
|
- return new GrantedAuthorityImpl("ROLE_" + rs.getString(1);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- ]]></programlisting> You would then add a bean of this type to your application context and inject
|
|
|
|
- it into the <code>LdapAuthenticationProvider</code>. This is covered in
|
|
|
|
- the section on configuring LDAP using explicit Spring beans in the LDAP
|
|
|
|
- chapter of the reference manual. Note that you can't use the namespace
|
|
|
|
- for configuration in this case. You should also consult the Javadoc for
|
|
|
|
- the relevant classes and interfaces. </para>
|
|
|
|
- </answer>
|
|
|
|
- </qandaentry>
|
|
|
|
- <qandaentry xml:id="faq-namespace-post-processor">
|
|
|
|
- <question>
|
|
|
|
- <para>I want to modify the property of a bean that is created by the
|
|
|
|
- namespace, but there is nothing in the schema to support it. What can I
|
|
|
|
- do short of abandoning namespace use?</para>
|
|
|
|
- </question>
|
|
|
|
- <answer>
|
|
|
|
- <para>The namespace functionality is intentionally limited, so it doesn't
|
|
|
|
- cover everything that you can do with plain beans. If you want to do
|
|
|
|
- something simple, like modify a bean, or inject a different dependency,
|
|
|
|
- you can do this by adding a
|
|
|
|
- <interfacename>BeanPostProcessor</interfacename> to your configuration.
|
|
|
|
- More information can be found in the <link
|
|
|
|
- xlink:href="http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/htmlsingle/spring-framework-reference.html#beans-factory-extension-bpp"
|
|
|
|
- >Spring Reference Manual</link>. In order to do this, you need to know a
|
|
|
|
- bit about which beans are created, so you should also read the blog
|
|
|
|
- article in the above question on <link
|
|
|
|
- linkend="faq-namespace-to-bean-mapping">how the namespace maps to
|
|
|
|
- Spring beans</link>. </para>
|
|
|
|
- <para> Normally, you would add the functionality you require to the
|
|
|
|
- <methodname>postProcessBeforeInitialization</methodname> method of
|
|
|
|
- <interfacename>BeanPostProcessor</interfacename>. Let's say that you
|
|
|
|
- want to customize the
|
|
|
|
- <interfacename>AuthenticationDetailsSource</interfacename> used by the
|
|
|
|
- <classname>UsernamePasswordAuthenticationFilter</classname>, (created by
|
|
|
|
- the <literal>form-login</literal> element). You want to extract a
|
|
|
|
- particular header called <literal>CUSTOM_HEADER</literal>from the
|
|
|
|
- request and make use of it while authenticating the user. The processor
|
|
|
|
- class would look like this: <programlisting language="java"><![CDATA[
|
|
|
|
-public class BeanPostProcessor implements BeanPostProcessor {
|
|
|
|
-
|
|
|
|
- public Object postProcessAfterInitialization(Object bean, String name) {
|
|
|
|
- if (bean instanceof UsernamePasswordAuthenticationFilter) {
|
|
|
|
- System.out.println("********* Post-processing " + name);
|
|
|
|
- ((UsernamePasswordAuthenticationFilter)bean).setAuthenticationDetailsSource(
|
|
|
|
- new AuthenticationDetailsSource() {
|
|
|
|
- public Object buildDetails(Object context) {
|
|
|
|
- return ((HttpServletRequest)context).getHeader("CUSTOM_HEADER");
|
|
|
|
- }
|
|
|
|
- });
|
|
|
|
- }
|
|
|
|
- return bean;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public Object postProcessBeforeInitialization(Object bean, String name) {
|
|
|
|
- return bean;
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-]]></programlisting> You would then register this bean in your application context. Spring will
|
|
|
|
- automatically invoke it on the beans defined in the application context.
|
|
|
|
- </para>
|
|
|
|
- </answer>
|
|
|
|
- </qandaentry>
|
|
|
|
-
|
|
|
|
- </qandadiv>
|
|
|
|
- </qandaset>
|
|
|
|
- </section>
|
|
|
|
-</article>
|
|
|