diff --git a/docs/manual/src/docs/asciidoc/_includes/additional-topics.adoc b/docs/manual/src/docs/asciidoc/_includes/additional-topics.adoc new file mode 100644 index 0000000000..b9644a97aa --- /dev/null +++ b/docs/manual/src/docs/asciidoc/_includes/additional-topics.adoc @@ -0,0 +1,2915 @@ + +[[advanced-topics]] += Additional Topics +In this part we cover features which require knowledge of previous chapters as well as some of the more advanced and less-commonly used features of the framework. + +[[domain-acls]] +== Domain Object Security (ACLs) + +[[domain-acls-overview]] +=== Overview +Complex applications often will find the need to define access permissions not simply at a web request or method invocation level. +Instead, security decisions need to comprise both who (`Authentication`), where (`MethodInvocation`) and what (`SomeDomainObject`). +In other words, authorization decisions also need to consider the actual domain object instance subject of a method invocation. + +Imagine you're designing an application for a pet clinic. +There will be two main groups of users of your Spring-based application: staff of the pet clinic, as well as the pet clinic's customers. +The staff will have access to all of the data, whilst your customers will only be able to see their own customer records. +To make it a little more interesting, your customers can allow other users to see their customer records, such as their "puppy preschool" mentor or president of their local "Pony Club". +Using Spring Security as the foundation, you have several approaches that can be used: + +* Write your business methods to enforce the security. +You could consult a collection within the `Customer` domain object instance to determine which users have access. +By using the `SecurityContextHolder.getContext().getAuthentication()`, you'll be able to access the `Authentication` object. +* Write an `AccessDecisionVoter` to enforce the security from the `GrantedAuthority[]` s stored in the `Authentication` object. +This would mean your `AuthenticationManager` would need to populate the `Authentication` with custom ``GrantedAuthority[]``s representing each of the `Customer` domain object instances the principal has access to. +* Write an `AccessDecisionVoter` to enforce the security and open the target `Customer` domain object directly. +This would mean your voter needs access to a DAO that allows it to retrieve the `Customer` object. +It would then access the `Customer` object's collection of approved users and make the appropriate decision. + + +Each one of these approaches is perfectly legitimate. +However, the first couples your authorization checking to your business code. +The main problems with this include the enhanced difficulty of unit testing and the fact it would be more difficult to reuse the `Customer` authorization logic elsewhere. +Obtaining the `GrantedAuthority[]` s from the `Authentication` object is also fine, but will not scale to large numbers of `Customer` s. +If a user might be able to access 5,000 `Customer` s (unlikely in this case, but imagine if it were a popular vet for a large Pony Club!) the amount of memory consumed and time required to construct the `Authentication` object would be undesirable. +The final method, opening the `Customer` directly from external code, is probably the best of the three. +It achieves separation of concerns, and doesn't misuse memory or CPU cycles, but it is still inefficient in that both the `AccessDecisionVoter` and the eventual business method itself will perform a call to the DAO responsible for retrieving the `Customer` object. +Two accesses per method invocation is clearly undesirable. +In addition, with every approach listed you'll need to write your own access control list (ACL) persistence and business logic from scratch. + +Fortunately, there is another alternative, which we'll talk about below. + + +[[domain-acls-key-concepts]] +=== Key Concepts +Spring Security's ACL services are shipped in the `spring-security-acl-xxx.jar`. +You will need to add this JAR to your classpath to use Spring Security's domain object instance security capabilities. + +Spring Security's domain object instance security capabilities centre on the concept of an access control list (ACL). +Every domain object instance in your system has its own ACL, and the ACL records details of who can and can't work with that domain object. +With this in mind, Spring Security delivers three main ACL-related capabilities to your application: + +* A way of efficiently retrieving ACL entries for all of your domain objects (and modifying those ACLs) +* A way of ensuring a given principal is permitted to work with your objects, before methods are called +* A way of ensuring a given principal is permitted to work with your objects (or something they return), after methods are called + +As indicated by the first bullet point, one of the main capabilities of the Spring Security ACL module is providing a high-performance way of retrieving ACLs. +This ACL repository capability is extremely important, because every domain object instance in your system might have several access control entries, and each ACL might inherit from other ACLs in a tree-like structure (this is supported out-of-the-box by Spring Security, and is very commonly used). +Spring Security's ACL capability has been carefully designed to provide high performance retrieval of ACLs, together with pluggable caching, deadlock-minimizing database updates, independence from ORM frameworks (we use JDBC directly), proper encapsulation, and transparent database updating. + +Given databases are central to the operation of the ACL module, let's explore the four main tables used by default in the implementation. +The tables are presented below in order of size in a typical Spring Security ACL deployment, with the table with the most rows listed last: + + + +* ACL_SID allows us to uniquely identify any principal or authority in the system ("SID" stands for "security identity"). +The only columns are the ID, a textual representation of the SID, and a flag to indicate whether the textual representation refers to a principal name or a `GrantedAuthority`. +Thus, there is a single row for each unique principal or `GrantedAuthority`. +When used in the context of receiving a permission, a SID is generally called a "recipient". + +* ACL_CLASS allows us to uniquely identify any domain object class in the system. +The only columns are the ID and the Java class name. +Thus, there is a single row for each unique Class we wish to store ACL permissions for. + +* ACL_OBJECT_IDENTITY stores information for each unique domain object instance in the system. +Columns include the ID, a foreign key to the ACL_CLASS table, a unique identifier so we know which ACL_CLASS instance we're providing information for, the parent, a foreign key to the ACL_SID table to represent the owner of the domain object instance, and whether we allow ACL entries to inherit from any parent ACL. +We have a single row for every domain object instance we're storing ACL permissions for. + +* Finally, ACL_ENTRY stores the individual permissions assigned to each recipient. +Columns include a foreign key to the ACL_OBJECT_IDENTITY, the recipient (ie a foreign key to ACL_SID), whether we'll be auditing or not, and the integer bit mask that represents the actual permission being granted or denied. +We have a single row for every recipient that receives a permission to work with a domain object. + + + + +As mentioned in the last paragraph, the ACL system uses integer bit masking. +Don't worry, you need not be aware of the finer points of bit shifting to use the ACL system, but suffice to say that we have 32 bits we can switch on or off. +Each of these bits represents a permission, and by default the permissions are read (bit 0), write (bit 1), create (bit 2), delete (bit 3) and administer (bit 4). +It's easy to implement your own `Permission` instance if you wish to use other permissions, and the remainder of the ACL framework will operate without knowledge of your extensions. + +It is important to understand that the number of domain objects in your system has absolutely no bearing on the fact we've chosen to use integer bit masking. +Whilst you have 32 bits available for permissions, you could have billions of domain object instances (which will mean billions of rows in ACL_OBJECT_IDENTITY and quite probably ACL_ENTRY). +We make this point because we've found sometimes people mistakenly believe they need a bit for each potential domain object, which is not the case. + +Now that we've provided a basic overview of what the ACL system does, and what it looks like at a table structure, let's explore the key interfaces. +The key interfaces are: + + +* `Acl`: Every domain object has one and only one `Acl` object, which internally holds the `AccessControlEntry` s as well as knows the owner of the `Acl`. +An Acl does not refer directly to the domain object, but instead to an `ObjectIdentity`. +The `Acl` is stored in the ACL_OBJECT_IDENTITY table. + +* `AccessControlEntry`: An `Acl` holds multiple `AccessControlEntry` s, which are often abbreviated as ACEs in the framework. +Each ACE refers to a specific tuple of `Permission`, `Sid` and `Acl`. +An ACE can also be granting or non-granting and contain audit settings. +The ACE is stored in the ACL_ENTRY table. + +* `Permission`: A permission represents a particular immutable bit mask, and offers convenience functions for bit masking and outputting information. +The basic permissions presented above (bits 0 through 4) are contained in the `BasePermission` class. + +* `Sid`: The ACL module needs to refer to principals and `GrantedAuthority[]` s. +A level of indirection is provided by the `Sid` interface, which is an abbreviation of "security identity". +Common classes include `PrincipalSid` (to represent the principal inside an `Authentication` object) and `GrantedAuthoritySid`. +The security identity information is stored in the ACL_SID table. + +* `ObjectIdentity`: Each domain object is represented internally within the ACL module by an `ObjectIdentity`. +The default implementation is called `ObjectIdentityImpl`. + +* `AclService`: Retrieves the `Acl` applicable for a given `ObjectIdentity`. +In the included implementation (`JdbcAclService`), retrieval operations are delegated to a `LookupStrategy`. +The `LookupStrategy` provides a highly optimized strategy for retrieving ACL information, using batched retrievals `(BasicLookupStrategy`) and supporting custom implementations that leverage materialized views, hierarchical queries and similar performance-centric, non-ANSI SQL capabilities. + +* `MutableAclService`: Allows a modified `Acl` to be presented for persistence. +It is not essential to use this interface if you do not wish. + + + +Please note that our out-of-the-box AclService and related database classes all use ANSI SQL. +This should therefore work with all major databases. +At the time of writing, the system had been successfully tested using Hypersonic SQL, PostgreSQL, Microsoft SQL Server and Oracle. + +Two samples ship with Spring Security that demonstrate the ACL module. +The first is the Contacts Sample, and the other is the Document Management System (DMS) Sample. +We suggest taking a look over these for examples. + + +[[domain-acls-getting-started]] +=== Getting Started +To get starting using Spring Security's ACL capability, you will need to store your ACL information somewhere. +This necessitates the instantiation of a `DataSource` using Spring. +The `DataSource` is then injected into a `JdbcMutableAclService` and `BasicLookupStrategy` instance. +The latter provides high-performance ACL retrieval capabilities, and the former provides mutator capabilities. +Refer to one of the samples that ship with Spring Security for an example configuration. +You'll also need to populate the database with the four ACL-specific tables listed in the last section (refer to the ACL samples for the appropriate SQL statements). + +Once you've created the required schema and instantiated `JdbcMutableAclService`, you'll next need to ensure your domain model supports interoperability with the Spring Security ACL package. +Hopefully `ObjectIdentityImpl` will prove sufficient, as it provides a large number of ways in which it can be used. +Most people will have domain objects that contain a `public Serializable getId()` method. +If the return type is long, or compatible with long (eg an int), you will find you need not give further consideration to `ObjectIdentity` issues. +Many parts of the ACL module rely on long identifiers. +If you're not using long (or an int, byte etc), there is a very good chance you'll need to reimplement a number of classes. +We do not intend to support non-long identifiers in Spring Security's ACL module, as longs are already compatible with all database sequences, the most common identifier data type, and are of sufficient length to accommodate all common usage scenarios. + +The following fragment of code shows how to create an `Acl`, or modify an existing `Acl`: + +[source,java] +---- +// Prepare the information we'd like in our access control entry (ACE) +ObjectIdentity oi = new ObjectIdentityImpl(Foo.class, new Long(44)); +Sid sid = new PrincipalSid("Samantha"); +Permission p = BasePermission.ADMINISTRATION; + +// Create or update the relevant ACL +MutableAcl acl = null; +try { +acl = (MutableAcl) aclService.readAclById(oi); +} catch (NotFoundException nfe) { +acl = aclService.createAcl(oi); +} + +// Now grant some permissions via an access control entry (ACE) +acl.insertAce(acl.getEntries().length, p, sid, true); +aclService.updateAcl(acl); +---- + + + +In the example above, we're retrieving the ACL associated with the "Foo" domain object with identifier number 44. +We're then adding an ACE so that a principal named "Samantha" can "administer" the object. +The code fragment is relatively self-explanatory, except the insertAce method. +The first argument to the insertAce method is determining at what position in the Acl the new entry will be inserted. +In the example above, we're just putting the new ACE at the end of the existing ACEs. +The final argument is a Boolean indicating whether the ACE is granting or denying. +Most of the time it will be granting (true), but if it is denying (false), the permissions are effectively being blocked. + +Spring Security does not provide any special integration to automatically create, update or delete ACLs as part of your DAO or repository operations. +Instead, you will need to write code like shown above for your individual domain objects. +It's worth considering using AOP on your services layer to automatically integrate the ACL information with your services layer operations. +We've found this quite an effective approach in the past. + +Once you've used the above techniques to store some ACL information in the database, the next step is to actually use the ACL information as part of authorization decision logic. +You have a number of choices here. +You could write your own `AccessDecisionVoter` or `AfterInvocationProvider` that respectively fires before or after a method invocation. +Such classes would use `AclService` to retrieve the relevant ACL and then call `Acl.isGranted(Permission[] permission, Sid[] sids, boolean administrativeMode)` to decide whether permission is granted or denied. +Alternately, you could use our `AclEntryVoter`, `AclEntryAfterInvocationProvider` or `AclEntryAfterInvocationCollectionFilteringProvider` classes. +All of these classes provide a declarative-based approach to evaluating ACL information at runtime, freeing you from needing to write any code. +Please refer to the sample applications to learn how to use these classes. + + +[[preauth]] +== Pre-Authentication Scenarios +There are situations where you want to use Spring Security for authorization, but the user has already been reliably authenticated by some external system prior to accessing the application. +We refer to these situations as "pre-authenticated" scenarios. +Examples include X.509, Siteminder and authentication by the Java EE container in which the application is running. +When using pre-authentication, Spring Security has to + +* Identify the user making the request. + +* Obtain the authorities for the user. + + +The details will depend on the external authentication mechanism. +A user might be identified by their certificate information in the case of X.509, or by an HTTP request header in the case of Siteminder. +If relying on container authentication, the user will be identified by calling the `getUserPrincipal()` method on the incoming HTTP request. +In some cases, the external mechanism may supply role/authority information for the user but in others the authorities must be obtained from a separate source, such as a `UserDetailsService`. + + +=== Pre-Authentication Framework Classes +Because most pre-authentication mechanisms follow the same pattern, Spring Security has a set of classes which provide an internal framework for implementing pre-authenticated authentication providers. +This removes duplication and allows new implementations to be added in a structured fashion, without having to write everything from scratch. +You don't need to know about these classes if you want to use something like <>, as it already has a namespace configuration option which is simpler to use and get started with. +If you need to use explicit bean configuration or are planning on writing your own implementation then an understanding of how the provided implementations work will be useful. +You will find classes under the `org.springframework.security.web.authentication.preauth`. +We just provide an outline here so you should consult the Javadoc and source where appropriate. + + +==== AbstractPreAuthenticatedProcessingFilter +This class will check the current contents of the security context and, if empty, it will attempt to extract user information from the HTTP request and submit it to the `AuthenticationManager`. +Subclasses override the following methods to obtain this information: + +[source,java] +---- +protected abstract Object getPreAuthenticatedPrincipal(HttpServletRequest request); + +protected abstract Object getPreAuthenticatedCredentials(HttpServletRequest request); +---- + + +After calling these, the filter will create a `PreAuthenticatedAuthenticationToken` containing the returned data and submit it for authentication. +By "authentication" here, we really just mean further processing to perhaps load the user's authorities, but the standard Spring Security authentication architecture is followed. + +Like other Spring Security authentication filters, the pre-authentication filter has an `authenticationDetailsSource` property which by default will create a `WebAuthenticationDetails` object to store additional information such as the session-identifier and originating IP address in the `details` property of the `Authentication` object. +In cases where user role information can be obtained from the pre-authentication mechanism, the data is also stored in this property, with the details implementing the `GrantedAuthoritiesContainer` interface. +This enables the authentication provider to read the authorities which were externally allocated to the user. +We'll look at a concrete example next. + + +[[j2ee-preauth-details]] +===== J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource +If the filter is configured with an `authenticationDetailsSource` which is an instance of this class, the authority information is obtained by calling the `isUserInRole(String role)` method for each of a pre-determined set of "mappable roles". +The class gets these from a configured `MappableAttributesRetriever`. +Possible implementations include hard-coding a list in the application context and reading the role information from the `` information in a `web.xml` file. +The pre-authentication sample application uses the latter approach. + +There is an additional stage where the roles (or attributes) are mapped to Spring Security `GrantedAuthority` objects using a configured `Attributes2GrantedAuthoritiesMapper`. +The default will just add the usual `ROLE_` prefix to the names, but it gives you full control over the behaviour. + + +==== PreAuthenticatedAuthenticationProvider +The pre-authenticated provider has little more to do than load the `UserDetails` object for the user. +It does this by delegating to an `AuthenticationUserDetailsService`. +The latter is similar to the standard `UserDetailsService` but takes an `Authentication` object rather than just user name: + +[source,java] +---- +public interface AuthenticationUserDetailsService { + UserDetails loadUserDetails(Authentication token) throws UsernameNotFoundException; +} +---- + +This interface may have also other uses but with pre-authentication it allows access to the authorities which were packaged in the `Authentication` object, as we saw in the previous section. +The `PreAuthenticatedGrantedAuthoritiesUserDetailsService` class does this. +Alternatively, it may delegate to a standard `UserDetailsService` via the `UserDetailsByNameServiceWrapper` implementation. + +==== Http403ForbiddenEntryPoint +The `AuthenticationEntryPoint` was discussed in the <> chapter. +Normally it is responsible for kick-starting the authentication process for an unauthenticated user (when they try to access a protected resource), but in the pre-authenticated case this doesn't apply. +You would only configure the `ExceptionTranslationFilter` with an instance of this class if you aren't using pre-authentication in combination with other authentication mechanisms. +It will be called if the user is rejected by the `AbstractPreAuthenticatedProcessingFilter` resulting in a null authentication. +It always returns a `403`-forbidden response code if called. + + +=== Concrete Implementations +X.509 authentication is covered in its <>. +Here we'll look at some classes which provide support for other pre-authenticated scenarios. + + +==== Request-Header Authentication (Siteminder) +An external authentication system may supply information to the application by setting specific headers on the HTTP request. +A well-known example of this is Siteminder, which passes the username in a header called `SM_USER`. +This mechanism is supported by the class `RequestHeaderAuthenticationFilter` which simply extracts the username from the header. +It defaults to using the name `SM_USER` as the header name. +See the Javadoc for more details. + +[TIP] +==== +Note that when using a system like this, the framework performs no authentication checks at all and it is __extremely__ important that the external system is configured properly and protects all access to the application. +If an attacker is able to forge the headers in their original request without this being detected then they could potentially choose any username they wished. +==== + +===== Siteminder Example Configuration +A typical configuration using this filter would look like this: + +[source,xml] +---- + + + + + + + + + + + + + + + + + + + + + +---- + +We've assumed here that the <> is being used for configuration. +It's also assumed that you have added a `UserDetailsService` (called "userDetailsService") to your configuration to load the user's roles. + + +==== Java EE Container Authentication +The class `J2eePreAuthenticatedProcessingFilter` will extract the username from the `userPrincipal` property of the `HttpServletRequest`. +Use of this filter would usually be combined with the use of Java EE roles as described above in <>. + +There is a sample application in the codebase which uses this approach, so get hold of the code from github and have a look at the application context file if you are interested. +The code is in the `samples/xml/preauth` directory. + + +[[ldap]] +== LDAP Authentication + + +[[ldap-overview]] +=== Overview +LDAP is often used by organizations as a central repository for user information and as an authentication service. +It can also be used to store the role information for application users. + +There are many different scenarios for how an LDAP server may be configured so Spring Security's LDAP provider is fully configurable. +It uses separate strategy interfaces for authentication and role retrieval and provides default implementations which can be configured to handle a wide range of situations. + +You should be familiar with LDAP before trying to use it with Spring Security. +The following link provides a good introduction to the concepts involved and a guide to setting up a directory using the free LDAP server OpenLDAP: http://www.zytrax.com/books/ldap/[http://www.zytrax.com/books/ldap/]. +Some familiarity with the JNDI APIs used to access LDAP from Java may also be useful. +We don't use any third-party LDAP libraries (Mozilla, JLDAP etc.) in the LDAP provider, but extensive use is made of Spring LDAP, so some familiarity with that project may be useful if you plan on adding your own customizations. + +When using LDAP authentication, it is important to ensure that you configure LDAP connection pooling properly. +If you are unfamiliar with how to do this, you can refer to the http://docs.oracle.com/javase/jndi/tutorial/ldap/connect/config.html[Java LDAP documentation]. + +=== Using LDAP with Spring Security +LDAP authentication in Spring Security can be roughly divided into the following stages. + +* Obtaining the unique LDAP "Distinguished Name", or DN, from the login name. +This will often mean performing a search in the directory, unless the exact mapping of usernames to DNs is known in advance. +So a user might enter the name "joe" when logging in, but the actual name used to authenticate to LDAP will be the full DN, such as `uid=joe,ou=users,dc=spring,dc=io`. + +* Authenticating the user, either by "binding" as that user or by performing a remote "compare" operation of the user's password against the password attribute in the directory entry for the DN. + +* Loading the list of authorities for the user. + +The exception is when the LDAP directory is just being used to retrieve user information and authenticate against it locally. +This may not be possible as directories are often set up with limited read access for attributes such as user passwords. + +We will look at some configuration scenarios below. +For full information on available configuration options, please consult the security namespace schema (information from which should be available in your XML editor). + + +[[ldap-server]] +=== Configuring an LDAP Server +The first thing you need to do is configure the server against which authentication should take place. +This is done using the `` element from the security namespace. +This can be configured to point at an external LDAP server, using the `url` attribute: + +[source,xml] +---- + +---- + +==== Using an Embedded Test Server +The `` element can also be used to create an embedded server, which can be very useful for testing and demonstrations. +In this case you use it without the `url` attribute: + +[source,xml] +---- + +---- + +Here we've specified that the root DIT of the directory should be "dc=springframework,dc=org", which is the default. +Used this way, the namespace parser will create an embedded Apache Directory server and scan the classpath for any LDIF files, which it will attempt to load into the server. +You can customize this behaviour using the `ldif` attribute, which defines an LDIF resource to be loaded: + +[source,xml] +---- + +---- + +This makes it a lot easier to get up and running with LDAP, since it can be inconvenient to work all the time with an external server. +It also insulates the user from the complex bean configuration needed to wire up an Apache Directory server. +Using plain Spring Beans the configuration would be much more cluttered. +You must have the necessary Apache Directory dependency jars available for your application to use. +These can be obtained from the LDAP sample application. + +==== Using Bind Authentication +This is the most common LDAP authentication scenario. + +[source,xml] +---- + +---- + +This simple example would obtain the DN for the user by substituting the user login name in the supplied pattern and attempting to bind as that user with the login password. +This is OK if all your users are stored under a single node in the directory. +If instead you wished to configure an LDAP search filter to locate the user, you could use the following: + +[source,xml] +---- + +---- + +If used with the server definition above, this would perform a search under the DN `ou=people,dc=springframework,dc=org` using the value of the `user-search-filter` attribute as a filter. +Again the user login name is substituted for the parameter in the filter name, so it will search for an entry with the `uid` attribute equal to the user name. +If `user-search-base` isn't supplied, the search will be performed from the root. + +==== Loading Authorities +How authorities are loaded from groups in the LDAP directory is controlled by the following attributes. + +* `group-search-base`. +Defines the part of the directory tree under which group searches should be performed. +* `group-role-attribute`. +The attribute which contains the name of the authority defined by the group entry. +Defaults to `cn` +* `group-search-filter`. +The filter which is used to search for group membership. +The default is `uniqueMember={0}`, corresponding to the `groupOfUniqueNames` LDAP class footnote:[Note that this is different from the default configuration of the underlying `DefaultLdapAuthoritiesPopulator` which uses `member={0}`.]. +In this case, the substituted parameter is the full distinguished name of the user. +The parameter `{1}` can be used if you want to filter on the login name. + +So if we used the following configuration + +[source,xml] +---- + +---- + +and authenticated successfully as user "ben", the subsequent loading of authorities would perform a search under the directory entry `ou=groups,dc=springframework,dc=org`, looking for entries which contain the attribute `uniqueMember` with value `uid=ben,ou=people,dc=springframework,dc=org`. +By default the authority names will have the prefix `ROLE_` prepended. +You can change this using the `role-prefix` attribute. +If you don't want any prefix, use `role-prefix="none"`. +For more information on loading authorities, see the Javadoc for the `DefaultLdapAuthoritiesPopulator` class. + +=== Implementation Classes +The namespace configuration options we've used above are simple to use and much more concise than using Spring beans explicitly. +There are situations when you may need to know how to configure Spring Security LDAP directly in your application context. +You may wish to customize the behaviour of some of the classes, for example. +If you're happy using namespace configuration then you can skip this section and the next one. + +The main LDAP provider class, `LdapAuthenticationProvider`, doesn't actually do much itself but delegates the work to two other beans, an `LdapAuthenticator` and an `LdapAuthoritiesPopulator` which are responsible for authenticating the user and retrieving the user's set of `GrantedAuthority` s respectively. + + +[[ldap-ldap-authenticators]] +==== LdapAuthenticator Implementations +The authenticator is also responsible for retrieving any required user attributes. +This is because the permissions on the attributes may depend on the type of authentication being used. +For example, if binding as the user, it may be necessary to read them with the user's own permissions. + +There are currently two authentication strategies supplied with Spring Security: + +* Authentication directly to the LDAP server ("bind" authentication). + +* Password comparison, where the password supplied by the user is compared with the one stored in the repository. +This can either be done by retrieving the value of the password attribute and checking it locally or by performing an LDAP "compare" operation, where the supplied password is passed to the server for comparison and the real password value is never retrieved. + +[[ldap-ldap-authenticators-common]] +===== Common Functionality +Before it is possible to authenticate a user (by either strategy), the distinguished name (DN) has to be obtained from the login name supplied to the application. +This can be done either by simple pattern-matching (by setting the `setUserDnPatterns` array property) or by setting the `userSearch` property. +For the DN pattern-matching approach, a standard Java pattern format is used, and the login name will be substituted for the parameter `{0}`. +The pattern should be relative to the DN that the configured `SpringSecurityContextSource` will bind to (see the section on <> for more information on this). +For example, if you are using an LDAP server with the URL `ldap://monkeymachine.co.uk/dc=springframework,dc=org`, and have a pattern `uid={0},ou=greatapes`, then a login name of "gorilla" will map to a DN `uid=gorilla,ou=greatapes,dc=springframework,dc=org`. +Each configured DN pattern will be tried in turn until a match is found. +For information on using a search, see the section on <> below. +A combination of the two approaches can also be used - the patterns will be checked first and if no matching DN is found, the search will be used. + + +[[ldap-ldap-authenticators-bind]] +===== BindAuthenticator +The class `BindAuthenticator` in the package `org.springframework.security.ldap.authentication` implements the bind authentication strategy. +It simply attempts to bind as the user. + + +[[ldap-ldap-authenticators-password]] +===== PasswordComparisonAuthenticator +The class `PasswordComparisonAuthenticator` implements the password comparison authentication strategy. + + +[[ldap-context-source]] +==== Connecting to the LDAP Server +The beans discussed above have to be able to connect to the server. +They both have to be supplied with a `SpringSecurityContextSource` which is an extension of Spring LDAP's `ContextSource`. +Unless you have special requirements, you will usually configure a `DefaultSpringSecurityContextSource` bean, which can be configured with the URL of your LDAP server and optionally with the username and password of a "manager" user which will be used by default when binding to the server (instead of binding anonymously). +For more information read the Javadoc for this class and for Spring LDAP's `AbstractContextSource`. + + +[[ldap-searchobjects]] +==== LDAP Search Objects +Often a more complicated strategy than simple DN-matching is required to locate a user entry in the directory. +This can be encapsulated in an `LdapUserSearch` instance which can be supplied to the authenticator implementations, for example, to allow them to locate a user. +The supplied implementation is `FilterBasedLdapUserSearch`. + + +[[ldap-searchobjects-filter]] +===== FilterBasedLdapUserSearch +This bean uses an LDAP filter to match the user object in the directory. +The process is explained in the Javadoc for the corresponding search method on the http://java.sun.com/j2se/1.4.2/docs/api/javax/naming/directory/DirContext.html#search(javax.naming.Name%2C%2520java.lang.String%2C%2520java.lang.Object%5B%5D%2C%2520javax.naming.directory.SearchControls)[JDK DirContext class]. +As explained there, the search filter can be supplied with parameters. +For this class, the only valid parameter is `{0}` which will be replaced with the user's login name. + + +[[ldap-authorities]] +==== LdapAuthoritiesPopulator +After authenticating the user successfully, the `LdapAuthenticationProvider` will attempt to load a set of authorities for the user by calling the configured `LdapAuthoritiesPopulator` bean. +The `DefaultLdapAuthoritiesPopulator` is an implementation which will load the authorities by searching the directory for groups of which the user is a member (typically these will be `groupOfNames` or `groupOfUniqueNames` entries in the directory). +Consult the Javadoc for this class for more details on how it works. + +If you want to use LDAP only for authentication, but load the authorities from a difference source (such as a database) then you can provide your own implementation of this interface and inject that instead. + +[[ldap-bean-config]] +==== Spring Bean Configuration +A typical configuration, using some of the beans we've discussed here, might look like this: + +[source,xml] +---- + + + + + + + + + + + + uid={0},ou=people + + + + + + + + + + + +---- + +This would set up the provider to access an LDAP server with URL `ldap://monkeymachine:389/dc=springframework,dc=org`. +Authentication will be performed by attempting to bind with the DN `uid=,ou=people,dc=springframework,dc=org`. +After successful authentication, roles will be assigned to the user by searching under the DN `ou=groups,dc=springframework,dc=org` with the default filter `(member=)`. +The role name will be taken from the "ou" attribute of each match. + +To configure a user search object, which uses the filter `(uid=)` for use instead of the DN-pattern (or in addition to it), you would configure the following bean + +[source,xml] +---- + + + + + + +---- + +and use it by setting the `BindAuthenticator` bean's `userSearch` property. +The authenticator would then call the search object to obtain the correct user's DN before attempting to bind as this user. + + +[[ldap-custom-user-details]] +==== LDAP Attributes and Customized UserDetails +The net result of an authentication using `LdapAuthenticationProvider` is the same as a normal Spring Security authentication using the standard `UserDetailsService` interface. +A `UserDetails` object is created and stored in the returned `Authentication` object. +As with using a `UserDetailsService`, a common requirement is to be able to customize this implementation and add extra properties. +When using LDAP, these will normally be attributes from the user entry. +The creation of the `UserDetails` object is controlled by the provider's `UserDetailsContextMapper` strategy, which is responsible for mapping user objects to and from LDAP context data: + +[source,java] +---- +public interface UserDetailsContextMapper { + +UserDetails mapUserFromContext(DirContextOperations ctx, String username, + Collection authorities); + +void mapUserToContext(UserDetails user, DirContextAdapter ctx); +} +---- + +Only the first method is relevant for authentication. +If you provide an implementation of this interface and inject it into the `LdapAuthenticationProvider`, you have control over exactly how the UserDetails object is created. +The first parameter is an instance of Spring LDAP's `DirContextOperations` which gives you access to the LDAP attributes which were loaded during authentication. +The `username` parameter is the name used to authenticate and the final parameter is the collection of authorities loaded for the user by the configured `LdapAuthoritiesPopulator`. + +The way the context data is loaded varies slightly depending on the type of authentication you are using. +With the `BindAuthenticator`, the context returned from the bind operation will be used to read the attributes, otherwise the data will be read using the standard context obtained from the configured `ContextSource` (when a search is configured to locate the user, this will be the data returned by the search object). + + +[[ldap-active-directory]] +=== Active Directory Authentication +Active Directory supports its own non-standard authentication options, and the normal usage pattern doesn't fit too cleanly with the standard `LdapAuthenticationProvider`. +Typically authentication is performed using the domain username (in the form `user@domain`), rather than using an LDAP distinguished name. +To make this easier, Spring Security 3.1 has an authentication provider which is customized for a typical Active Directory setup. + + +==== ActiveDirectoryLdapAuthenticationProvider +Configuring `ActiveDirectoryLdapAuthenticationProvider` is quite straightforward. +You just need to supply the domain name and an LDAP URL supplying the address of the server footnote:[It is also possible to obtain the server's IP address using a DNS lookup. +This is not currently supported, but hopefully will be in a future version.]. +An example configuration would then look like this: + +[source,xml] +---- + + + + + +} +---- + +Note that there is no need to specify a separate `ContextSource` in order to define the server location - the bean is completely self-contained. +A user named "Sharon", for example, would then be able to authenticate by entering either the username `sharon` or the full Active Directory `userPrincipalName`, namely `sharon@mydomain.com`. +The user's directory entry will then be located, and the attributes returned for possible use in customizing the created `UserDetails` object (a `UserDetailsContextMapper` can be injected for this purpose, as described above). +All interaction with the directory takes place with the identity of the user themselves. +There is no concept of a "manager" user. + +By default, the user authorities are obtained from the `memberOf` attribute values of the user entry. +The authorities allocated to the user can again be customized using a `UserDetailsContextMapper`. +You can also inject a `GrantedAuthoritiesMapper` into the provider instance to control the authorities which end up in the `Authentication` object. + +===== Active Directory Error Codes +By default, a failed result will cause a standard Spring Security `BadCredentialsException`. +If you set the property `convertSubErrorCodesToExceptions` to `true`, the exception messages will be parsed to attempt to extract the Active Directory-specific error code and raise a more specific exception. +Check the class Javadoc for more information. + +[[oauth2login-advanced]] +== OAuth 2.0 Login -- Advanced Configuration + +`HttpSecurity.oauth2Login()` provides a number of configuration options for customizing OAuth 2.0 Login. +The main configuration options are grouped into their protocol endpoint counterparts. + +For example, `oauth2Login().authorizationEndpoint()` allows configuring the _Authorization Endpoint_, +whereas `oauth2Login().tokenEndpoint()` allows configuring the _Token Endpoint_. + +The following code shows an example: + +[source,java] +---- +@EnableWebSecurity +public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + .oauth2Login() + .authorizationEndpoint() + ... + .redirectionEndpoint() + ... + .tokenEndpoint() + ... + .userInfoEndpoint() + ... + } +} +---- + +The main goal of the `oauth2Login()` DSL was to closely align with the naming, as defined in the specifications. + +The OAuth 2.0 Authorization Framework defines the https://tools.ietf.org/html/rfc6749#section-3[Protocol Endpoints] as follows: + +The authorization process utilizes two authorization server endpoints (HTTP resources): + +* Authorization Endpoint: Used by the client to obtain authorization from the resource owner via user-agent redirection. +* Token Endpoint: Used by the client to exchange an authorization grant for an access token, typically with client authentication. + +As well as one client endpoint: + +* Redirection Endpoint: Used by the authorization server to return responses +containing authorization credentials to the client via the resource owner user-agent. + +The OpenID Connect Core 1.0 specification defines the http://openid.net/specs/openid-connect-core-1_0.html#UserInfo[UserInfo Endpoint] as follows: + +The UserInfo Endpoint is an OAuth 2.0 Protected Resource that returns claims about the authenticated end-user. +To obtain the requested claims about the end-user, the client makes a request to the UserInfo Endpoint +by using an access token obtained through OpenID Connect Authentication. +These claims are normally represented by a JSON object that contains a collection of name-value pairs for the claims. + +The following code shows the complete configuration options available for the `oauth2Login()` DSL: + +[source,java] +---- +@EnableWebSecurity +public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + .oauth2Login() + .clientRegistrationRepository(this.clientRegistrationRepository()) + .authorizedClientService(this.authorizedClientService()) + .loginPage("/login") + .authorizationEndpoint() + .baseUri(this.authorizationRequestBaseUri()) + .authorizationRequestRepository(this.authorizationRequestRepository()) + .and() + .redirectionEndpoint() + .baseUri(this.authorizationResponseBaseUri()) + .and() + .tokenEndpoint() + .accessTokenResponseClient(this.accessTokenResponseClient()) + .and() + .userInfoEndpoint() + .userAuthoritiesMapper(this.userAuthoritiesMapper()) + .userService(this.oauth2UserService()) + .oidcUserService(this.oidcUserService()) + .customUserType(GitHubOAuth2User.class, "github"); + } +} +---- + +The sections to follow go into more detail on each of the configuration options available: + +* <> +* <> +* <> +* <> +* <> + + +[[oauth2login-advanced-login-page]] +=== OAuth 2.0 Login Page + +By default, the OAuth 2.0 Login Page is auto-generated by the `DefaultLoginPageGeneratingFilter`. +The default login page shows each configured OAuth Client with its `ClientRegistration.clientName` +as a link, which is capable of initiating the Authorization Request (or OAuth 2.0 Login). + +The link's destination for each OAuth Client defaults to the following: + +`OAuth2AuthorizationRequestRedirectFilter.DEFAULT_AUTHORIZATION_REQUEST_BASE_URI` + "/{registrationId}" + +The following line shows an example: + +[source,html] +---- +Google +---- + +To override the default login page, +configure `oauth2Login().loginPage()` and (optionally) `oauth2Login().authorizationEndpoint().baseUri()`. + +The following listing shows an example: + +[source,java] +---- +@EnableWebSecurity +public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + .oauth2Login() + .loginPage("/login/oauth2") + ... + .authorizationEndpoint() + .baseUri("/login/oauth2/authorization") + .... + } +} +---- + +[IMPORTANT] +You need to provide a `@Controller` with a `@RequestMapping("/login/oauth2")` that is capable of rendering the custom login page. + +[TIP] +==== +As noted earlier, configuring `oauth2Login().authorizationEndpoint().baseUri()` is optional. +However, if you choose to customize it, ensure the link to each OAuth Client matches the `authorizationEndpoint().baseUri()`. + +The following line shows an example: + +[source,html] +---- +Google +---- +==== + +[[oauth2login-advanced-authorization-endpoint]] +=== Authorization Endpoint + + +[[oauth2login-advanced-authorization-request-repository]] +==== `AuthorizationRequestRepository` + +`AuthorizationRequestRepository` is responsible for the persistence of the `OAuth2AuthorizationRequest` +from the time the Authorization Request is initiated to the time the Authorization Response +is received (the callback). + +[TIP] +The `OAuth2AuthorizationRequest` is used to correlate and validate the Authorization Response. + +The default implementation of `AuthorizationRequestRepository` is `HttpSessionOAuth2AuthorizationRequestRepository`, +which stores the `OAuth2AuthorizationRequest` in the `HttpSession`. + +If you would like to provide a custom implementation of `AuthorizationRequestRepository` +that stores the attributes of `OAuth2AuthorizationRequest` in a `Cookie`, +configure it as shown in the following example: + +[source,java] +---- +@EnableWebSecurity +public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + .oauth2Login() + .authorizationEndpoint() + .authorizationRequestRepository(this.cookieAuthorizationRequestRepository()) + ... + } + + private AuthorizationRequestRepository cookieAuthorizationRequestRepository() { + return new HttpCookieOAuth2AuthorizationRequestRepository(); + } +} +---- + +[[oauth2login-advanced-redirection-endpoint]] +=== Redirection Endpoint + +The Redirection Endpoint is used by the Authorization Server for returning the Authorization Response +(which contains the authorization credentials) to the client via the Resource Owner user-agent. + +[TIP] +OAuth 2.0 Login leverages the Authorization Code Grant. +Therefore, the authorization credential is the authorization code. + +The default Authorization Response `baseUri` (redirection endpoint) is `*/login/oauth2/code/**`, which is defined in `OAuth2LoginAuthenticationFilter.DEFAULT_FILTER_PROCESSES_URI`. + +If you would like to customize the Authorization Response `baseUri`, configure it as shown in the following example: + +[source,java] +---- +@EnableWebSecurity +public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + .oauth2Login() + .redirectionEndpoint() + .baseUri("/login/oauth2/callback/*") + .... + } +} +---- + +[IMPORTANT] +==== +You also need to ensure the `ClientRegistration.redirectUriTemplate` matches the custom Authorization Response `baseUri`. + +The following listing shows an example: + +[source,java] +---- +return CommonOAuth2Provider.GOOGLE.getBuilder("google") + .clientId("google-client-id") + .clientSecret("google-client-secret") + .redirectUriTemplate("{baseUrl}/login/oauth2/callback/{registrationId}") + .build(); +---- +==== + +[[oauth2login-advanced-token-endpoint]] +=== Token Endpoint + + +[[oauth2login-advanced-token-client]] +==== OAuth2AccessTokenResponseClient + +`OAuth2AccessTokenResponseClient` is responsible for exchanging an authorization grant credential +for an access token credential at the Authorization Server's Token Endpoint. + +The default implementation of `OAuth2AccessTokenResponseClient` is `NimbusAuthorizationCodeTokenResponseClient`, +which exchanges an authorization code for an access token at the Token Endpoint. + +[NOTE] +`NimbusAuthorizationCodeTokenResponseClient` uses the https://connect2id.com/products/nimbus-oauth-openid-connect-sdk[Nimbus OAuth 2.0 SDK] internally. + +If you would like to provide a custom implementation of `OAuth2AccessTokenResponseClient` +that uses Spring Framework 5 reactive `WebClient` for initiating requests to the Token Endpoint, +configure it as shown in the following example: + +[source,java] +---- +@EnableWebSecurity +public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + .oauth2Login() + .tokenEndpoint() + .accessTokenResponseClient(this.accessTokenResponseClient()) + ... + } + + private OAuth2AccessTokenResponseClient accessTokenResponseClient() { + return new SpringWebClientAuthorizationCodeTokenResponseClient(); + } +} +---- + +[[oauth2login-advanced-userinfo-endpoint]] +=== UserInfo Endpoint + +The UserInfo Endpoint includes a number of configuration options, as described in the following sub-sections: + +* <> +* <> +* <> +* <> + + +[[oauth2login-advanced-map-authorities]] +==== Mapping User Authorities + +After the user successfully authenticates with the OAuth 2.0 Provider, +the `OAuth2User.getAuthorities()` (or `OidcUser.getAuthorities()`) may be mapped to a new set of `GrantedAuthority` instances, +which will be supplied to `OAuth2AuthenticationToken` when completing the authentication. + +[TIP] +`OAuth2AuthenticationToken.getAuthorities()` is used for authorizing requests, such as in `hasRole('USER')` or `hasRole('ADMIN')`. + +There are a couple of options to choose from when mapping user authorities: + +* <> +* <> + +[[oauth2login-advanced-map-authorities-grantedauthoritiesmapper]] +===== Using a `GrantedAuthoritiesMapper` + +Provide an implementation of `GrantedAuthoritiesMapper` and configure it as shown in the following example: + +[source,java] +---- +@EnableWebSecurity +public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + .oauth2Login() + .userInfoEndpoint() + .userAuthoritiesMapper(this.userAuthoritiesMapper()) + ... + } + + private GrantedAuthoritiesMapper userAuthoritiesMapper() { + return (authorities) -> { + Set mappedAuthorities = new HashSet<>(); + + authorities.forEach(authority -> { + if (OidcUserAuthority.class.isInstance(authority)) { + OidcUserAuthority oidcUserAuthority = (OidcUserAuthority)authority; + + OidcIdToken idToken = oidcUserAuthority.getIdToken(); + OidcUserInfo userInfo = oidcUserAuthority.getUserInfo(); + + // Map the claims found in idToken and/or userInfo + // to one or more GrantedAuthority's and add it to mappedAuthorities + + } else if (OAuth2UserAuthority.class.isInstance(authority)) { + OAuth2UserAuthority oauth2UserAuthority = (OAuth2UserAuthority)authority; + + Map userAttributes = oauth2UserAuthority.getAttributes(); + + // Map the attributes found in userAttributes + // to one or more GrantedAuthority's and add it to mappedAuthorities + + } + }); + + return mappedAuthorities; + }; + } +} +---- + +Alternatively, you may register a `GrantedAuthoritiesMapper` `@Bean` to have it automatically applied to the configuration, as shown in the following example: + +[source,java] +---- +@EnableWebSecurity +public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http.oauth2Login(); + } + + @Bean + public GrantedAuthoritiesMapper userAuthoritiesMapper() { + ... + } +} +---- + +[[oauth2login-advanced-map-authorities-oauth2userservice]] +===== Delegation-based strategy with `OAuth2UserService` + +This strategy is advanced compared to using a `GrantedAuthoritiesMapper`, however, it's also more flexible +as it gives you access to the `OAuth2UserRequest` and `OAuth2User` (when using an OAuth 2.0 UserService) +or `OidcUserRequest` and `OidcUser` (when using an OpenID Connect 1.0 UserService). + +The `OAuth2UserRequest` (and `OidcUserRequest`) provides you access to the associated `OAuth2AccessToken`, +which is very useful in the cases where the _delegator_ needs to fetch authority information +from a protected resource before it can map the custom authorities for the user. + +The following example shows how to implement and configure a delegation-based strategy using an OpenID Connect 1.0 UserService: + +[source,java] +---- +@EnableWebSecurity +public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + .oauth2Login() + .userInfoEndpoint() + .oidcUserService(this.oidcUserService()) + ... + } + + private OAuth2UserService oidcUserService() { + final OidcUserService delegate = new OidcUserService(); + + return (userRequest) -> { + // Delegate to the default implementation for loading a user + OidcUser oidcUser = delegate.loadUser(userRequest); + + OAuth2AccessToken accessToken = userRequest.getAccessToken(); + Set mappedAuthorities = new HashSet<>(); + + // TODO + // 1) Fetch the authority information from the protected resource using accessToken + // 2) Map the authority information to one or more GrantedAuthority's and add it to mappedAuthorities + + // 3) Create a copy of oidcUser but use the mappedAuthorities instead + oidcUser = new DefaultOidcUser(mappedAuthorities, oidcUser.getIdToken(), oidcUser.getUserInfo()); + + return oidcUser; + }; + } +} +---- + +[[oauth2login-advanced-custom-user]] +==== Configuring a Custom OAuth2User + +`CustomUserTypesOAuth2UserService` is an implementation of an `OAuth2UserService` +that provides support for custom `OAuth2User` types. + +If the default implementation (`DefaultOAuth2User`) does not suit your needs, +you can define your own implementation of `OAuth2User`. + +The following code demonstrates how you would register a custom `OAuth2User` type for GitHub: + +[source,java] +---- +@EnableWebSecurity +public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + .oauth2Login() + .userInfoEndpoint() + .customUserType(GitHubOAuth2User.class, "github") + ... + } +} +---- + +The following code shows an example of a custom `OAuth2User` type for GitHub: + +[source,java] +---- +public class GitHubOAuth2User implements OAuth2User { + private List authorities = + AuthorityUtils.createAuthorityList("ROLE_USER"); + private Map attributes; + private String id; + private String name; + private String login; + private String email; + + @Override + public Collection getAuthorities() { + return this.authorities; + } + + @Override + public Map getAttributes() { + if (this.attributes == null) { + this.attributes = new HashMap<>(); + this.attributes.put("id", this.getId()); + this.attributes.put("name", this.getName()); + this.attributes.put("login", this.getLogin()); + this.attributes.put("email", this.getEmail()); + } + return attributes; + } + + public String getId() { + return this.id; + } + + public void setId(String id) { + this.id = id; + } + + @Override + public String getName() { + return this.name; + } + + public void setName(String name) { + this.name = name; + } + + public String getLogin() { + return this.login; + } + + public void setLogin(String login) { + this.login = login; + } + + public String getEmail() { + return this.email; + } + + public void setEmail(String email) { + this.email = email; + } +} +---- + +[TIP] +`id`, `name`, `login`, and `email` are attributes returned in GitHub's UserInfo Response. +For detailed information returned from the UserInfo Endpoint, see the API documentation +for https://developer.github.com/v3/users/#get-the-authenticated-user["Get the authenticated user"]. + +[[oauth2login-advanced-oauth2-user-service]] +==== OAuth 2.0 UserService + +`DefaultOAuth2UserService` is an implementation of an `OAuth2UserService` +that supports standard OAuth 2.0 Provider's. + +[NOTE] +`OAuth2UserService` obtains the user attributes +of the end-user (the resource owner) from the UserInfo Endpoint (by using the +access token granted to the client during the authorization flow) +and returns an `AuthenticatedPrincipal` in the form of an `OAuth2User`. + +If the default implementation does not suit your needs, you can define your own implementation of `OAuth2UserService` +for standard OAuth 2.0 Provider's. + +The following configuration demonstrates how to configure a custom `OAuth2UserService`: + +[source,java] +---- +@EnableWebSecurity +public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + .oauth2Login() + .userInfoEndpoint() + .userService(this.oauth2UserService()) + ... + } + + private OAuth2UserService oauth2UserService() { + return new CustomOAuth2UserService(); + } +} +---- + +[[oauth2login-advanced-oidc-user-service]] +==== OpenID Connect 1.0 UserService + +`OidcUserService` is an implementation of an `OAuth2UserService` +that supports OpenID Connect 1.0 Provider's. + +[NOTE] +`OAuth2UserService` is responsible for obtaining the user attributes +of the end user (the resource owner) from the UserInfo Endpoint (by using the +access token granted to the client during the authorization flow) +and return an `AuthenticatedPrincipal` in the form of an `OidcUser`. + +If the default implementation does not suit your needs, you can define your own implementation of `OAuth2UserService` +for OpenID Connect 1.0 Provider's. + +The following configuration demonstrates how to configure a custom OpenID Connect 1.0 `OAuth2UserService`: + +[source,java] +---- +@EnableWebSecurity +public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + .oauth2Login() + .userInfoEndpoint() + .oidcUserService(this.oidcUserService()) + ... + } + + private OAuth2UserService oidcUserService() { + return new CustomOidcUserService(); + } +} +---- + +[[taglibs]] +== JSP Tag Libraries +Spring Security has its own taglib which provides basic support for accessing security information and applying security constraints in JSPs. + + +=== Declaring the Taglib +To use any of the tags, you must have the security taglib declared in your JSP: + +[source,xml] +---- +<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %> +---- + +[[taglibs-authorize]] +=== The authorize Tag +This tag is used to determine whether its contents should be evaluated or not. +In Spring Security 3.0, it can be used in two ways footnote:[ +The legacy options from Spring Security 2.0 are also supported, but discouraged. +]. +The first approach uses a <>, specified in the `access` attribute of the tag. +The expression evaluation will be delegated to the `SecurityExpressionHandler` defined in the application context (you should have web expressions enabled in your `` namespace configuration to make sure this service is available). +So, for example, you might have + +[source,xml] +---- + + +This content will only be visible to users who have the "supervisor" authority in their list of GrantedAuthoritys. + + +---- + +When used in conjuction with Spring Security's PermissionEvaluator, the tag can also be used to check permissions. +For example: + +[source,xml] +---- + + +This content will only be visible to users who have read or write permission to the Object found as a request attribute named "domain". + + +---- + +A common requirement is to only show a particular link, if the user is actually allowed to click it. +How can we determine in advance whether something will be allowed? This tag can also operate in an alternative mode which allows you to define a particular URL as an attribute. +If the user is allowed to invoke that URL, then the tag body will be evaluated, otherwise it will be skipped. +So you might have something like + +[source,xml] +---- + + +This content will only be visible to users who are authorized to send requests to the "/admin" URL. + + +---- + +To use this tag there must also be an instance of `WebInvocationPrivilegeEvaluator` in your application context. +If you are using the namespace, one will automatically be registered. +This is an instance of `DefaultWebInvocationPrivilegeEvaluator`, which creates a dummy web request for the supplied URL and invokes the security interceptor to see whether the request would succeed or fail. +This allows you to delegate to the access-control setup you defined using `intercept-url` declarations within the `` namespace configuration and saves having to duplicate the information (such as the required roles) within your JSPs. +This approach can also be combined with a `method` attribute, supplying the HTTP method, for a more specific match. + +The Boolean result of evaluating the tag (whether it grants or denies access) can be stored in a page context scope variable by setting the `var` attribute to the variable name, avoiding the need for duplicating and re-evaluating the condition at other points in the page. + + +==== Disabling Tag Authorization for Testing +Hiding a link in a page for unauthorized users doesn't prevent them from accessing the URL. +They could just type it into their browser directly, for example. +As part of your testing process, you may want to reveal the hidden areas in order to check that links really are secured at the back end. +If you set the system property `spring.security.disableUISecurity` to `true`, the `authorize` tag will still run but will not hide its contents. +By default it will also surround the content with `...` tags. +This allows you to display "hidden" content with a particular CSS style such as a different background colour. +Try running the "tutorial" sample application with this property enabled, for example. + +You can also set the properties `spring.security.securedUIPrefix` and `spring.security.securedUISuffix` if you want to change surrounding text from the default `span` tags (or use empty strings to remove it completely). + + +=== The authentication Tag +This tag allows access to the current `Authentication` object stored in the security context. +It renders a property of the object directly in the JSP. +So, for example, if the `principal` property of the `Authentication` is an instance of Spring Security's `UserDetails` object, then using `` will render the name of the current user. + +Of course, it isn't necessary to use JSP tags for this kind of thing and some people prefer to keep as little logic as possible in the view. +You can access the `Authentication` object in your MVC controller (by calling `SecurityContextHolder.getContext().getAuthentication()`) and add the data directly to your model for rendering by the view. + + +=== The accesscontrollist Tag +This tag is only valid when used with Spring Security's ACL module. +It checks a comma-separated list of required permissions for a specified domain object. +If the current user has all of those permissions, then the tag body will be evaluated. +If they don't, it will be skipped. +An example might be + +CAUTION: In general this tag should be considered deprecated. +Instead use the <>. + +[source,xml] +---- + + +This will be shown if the user has all of the permissions represented by the values "1" or "2" on the given object. + + +---- + +The permissions are passed to the `PermissionFactory` defined in the application context, converting them to ACL `Permission` instances, so they may be any format which is supported by the factory - they don't have to be integers, they could be strings like `READ` or `WRITE`. +If no `PermissionFactory` is found, an instance of `DefaultPermissionFactory` will be used. +The `AclService` from the application context will be used to load the `Acl` instance for the supplied object. +The `Acl` will be invoked with the required permissions to check if all of them are granted. + +This tag also supports the `var` attribute, in the same way as the `authorize` tag. + + +=== The csrfInput Tag +If CSRF protection is enabled, this tag inserts a hidden form field with the correct name and value for the CSRF protection token. +If CSRF protection is not enabled, this tag outputs nothing. + +Normally Spring Security automatically inserts a CSRF form field for any `` tags you use, but if for some reason you cannot use ``, `csrfInput` is a handy replacement. + +You should place this tag within an HTML `
` block, where you would normally place other input fields. +Do NOT place this tag within a Spring `` block. +Spring Security handles Spring forms automatically. + +[source,xml] +---- +
+ + Name:
+ + ... + +---- + + +=== The csrfMetaTags Tag +If CSRF protection is enabled, this tag inserts meta tags containing the CSRF protection token form field and header names and CSRF protection token value. +These meta tags are useful for employing CSRF protection within JavaScript in your applications. + +You should place `csrfMetaTags` within an HTML `` block, where you would normally place other meta tags. +Once you use this tag, you can access the form field name, header name, and token value easily using JavaScript. +JQuery is used in this example to make the task easier. + +[source,xml] +---- + + + + CSRF Protected JavaScript Page + + +