Spring Security (2) – Shared Components

SecurityContextHolder And Authentication Objects

The most fundamental object is SecurityContextHolder. This is where we store details of the present security context of the application, which includes details of the principal currently using the application. By default the SecurityContextHolder uses a ThreadLocal to store these details, which means that the security context is always available to methods in the same thread of execution, even if the security context is not explicitly passed around as an argument to those methods. Using a ThreadLocal in this way is quite safe if care is taken to clear the thread after the present principal’s request is processed. Of course, Spring Security takes care of this for you automatically so there is no need to worry about it.

 

Inside the SecurityContextHolder we store details of the principal currently interacting with the application. Spring Security uses an Authentication object to represent this information. Whilst you won’t normally need to create an Authentication object yourself, it is fairly common for users to query the Authentication object. You can use the following code block – from anywhere in your application – to obtain the name of the authenticated user, for example:

Object obj = SecurityContextHolder.getContext().getAuthentication().getPrincipal();

 

if (obj instanceof UserDetails) {

  String username = ((UserDetails)obj).getUsername();

} else {

  String username = obj.toString();

}

 

The UserDetailsService

Another item to note from the above code fragment is that you can obtain a principal from the Authentication object. The principal is just an Object. Most of the time this can be cast into a UserDetails object. UserDetails is a central interface in Spring Security. It represents a principal, but in an extensible and application-specific way. Think of UserDetails as the adapter between your own user database and what Spring Security needs inside the SecurityContextHolder. Being a representation of something from your own user database, quite often you will cast the UserDetails to the original object that your application provided, so you can call business-specific methods (like getEmail(), getEmployeeNumber() and so on).

By now you’re probably wondering, so when do I provide a UserDetails object? How do I do that? I thought you said this thing was declarative and I didn’t need to write any Java code – what gives? The short answer is that there is a special interface called UserDetailsService. The only method on this interface accepts a String-based username argument and returns a UserDetails. Most authentication providers that ship with Spring Security delegate to a UserDetailsService as part of the authentication process. The UserDetailsService is used to build the Authentication object that is stored in the SecurityContextHolder. The good news is that we provide a number of UserDetailsService implementations, including one that uses an in-memory map and another that uses JDBC. Most users tend to write their own, though, with such implementations often simply sitting on top of an existing Data Access Object (DAO) that represents their employees, customers, or other users of the enterprise application. Remember the advantage that whatever your UserDetailsService returns can always be obtained from the SecurityContextHolder, as per the above code fragment.

 

The following example is a demonstration of how to write a customised authentication

 

Firstly, we need to have a look what is inside the UserDetailsService.

package org.springframework.security.userdetails;

 

public interface UserDetailsService  {

  

org.springframework.security.userdetails.UserDetails

       loadUserByUsername(java.lang.String s)

            throws org.springframework.security.userdetails.UsernameNotFoundException,

                            org.springframework.dao.DataAccessException;

}

 

As you can imagine, you will need to create an object that implements UserDetails to hold the user info (such as emailAddress). Meanwhile, you also need to implements the loadUserByUsername() method, where you will use the username to fetch the user record and assign it to the object that used to implement UseDetails.

 

    public UserBean loadUserByUsername(String userName) throws UsernameNotFoundException {

        UserMain userMain = this.userDao.findByUserName(userName);

        if (userMain == null) {

            throw new UsernameNotFoundException(new StringBuilder().append("UserMain not found for ").append(userName).toString());

        }

        UserBean userBean = new UserBean();

        userBean.setUser(userMain);

        return userBean;

    }

 

In the preceding code, UserBean is class that implements UserDetails. (The loadUserByUsername() method should be called when you user login). Now we can get the UserBean object with the following block code.

 

UserBean user = ((AuthenticationImpl) SecurityContextHolder.getContext().getAuthentication())

.getDetails().getUserBean();

 

AuthenticationImpl implements org.springframework.security.Authentication and overwrite the getDetails method to return an object that has a property of UserBean.

 

GrantedAuthority

Another important method provided by Authentication is getAuthorities(). This method provides an array of GrantedAuthority objects. A GrantedAuthority is, not surprisingly, an authority that is granted to the principal. Such authorities are usually "roles", such as ROLE_ADMINISTRATOR or ROLE_HR_SUPERVISOR.

 

Recap of major building blocks of Spring Security

·         SecurityContextHolder, to provide any type access to the SecurityContext.

·         SecurityContext, to hold the Authentication and possibly request-specific security information.

·         HttpSessionContextIntegrationFilter, to store the SecurityContext in the HttpSession between web requests.

·         Authentication, to represent the principal in a Spring Security-specific manner.

·         GrantedAuthority, to reflect the application-wide permissions granted to a principal.

·         UserDetails, to provide the necessary information to build an Authentication object from your application’s DAOs.

·         UserDetailsService, to create a UserDetails when passed in a String-based username (or certificate ID or alike).

Advertisements
This entry was posted in Spring. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s