Blog

Understanding Spring Security – Part 3 – Method Security

by | Jul 27, 2012 | Content Security, Webapps | 1 comment

Since version 2.0, Spring Security has improved support significantly for adding security to various service layer methods. Method Security, in nature, is slightly more complicated than the simple allow or deny system seen in URL Based Spring Security. This security method allows you to supplement the traditional Spring beans application context syntax with elements from traditional XML schema.

In Spring Security, it is possible to secure individual methods for authentication. In order to use method security, the following lines need to be added to the files specified:

In security.xml

<global-method-security pre-post-annotations="enabled"/>

The above line activates method security using pre and post annotations throughout your application. The next step to securing your methods is to add annotations like the one below for each of your methods:

@PreAuthorize("hasRole('ROLE_USER')")

The above annotation is added before the method declaration in the interface for the method that you want to secure. The role names should start with “ROLE_” prefix in order for spring security to detect them as being roles. It is possible to configure this prefix if needed.

The other available method security annotations are:

@PreAuthorize("hasPermission(#item, 'admin')")   
public void addPermission(Item item,…);

In the above example, the #item refers to the argument “item”, and evaluates whether the user has the permission ‘admin’ to this particular item.

Spring Security has the following five built in permissions:
1.Read
2.Write
3.Create
4.Delete
5.Admin
It is possible to create custom permissions, which may be numbered up to 32.

The hasPermission evaluator can be configured to use a custom permission evaluator by adding an expression handler to the global-method-security tag. The expression handler has a property named “permissionEvaluator” which refers to our custom permission evaluator. The custom permission evaluator has access to the authentication object, through which we can get the user details of the current user, as well as the target Domain Object. The target domain object is the one for which the permission is being evaluated. This gives us a high degree of flexibility to evaluate the permission using the properties of either of those objects.

There are other annotation options as listed below:

@PreAuthorize("#item.property == authentication.property")   
public void myMethod(Item item);

** “authentication” is a built in expression for Authentication in the security context.

@PreAuthorize("hasRole('ROLE_USER')")   
@PostFilter("hasPermission(filterObject, 'read') or hasPermission(filterObject, 'admin')")   
public List<Contact> getAll();

PostFilters filters the returned collection and filters the list by removing each ‘filterObject” to which the current user does not have ‘read’ permissions.

Another way to protect the methods is to use protect-pointcut.

	<global-method-security>
		<protect-pointcut expression="execution(* com.mycompany.*Service.*(..))"
			access="ROLE_USER" />
	</global-method-security>

This protects all the methods that match the expression provided and only users with the role specified in the access property are allowed access to them.

 

According to the reference documentation, The SecurityContextHolder is the most fundamental object in Spring Security. It holds the user details in the Authentication object. A user is considered authenticated when the SecurityContextHolder contains a fully populated Authentication object.

The following code from the reference docs shows how to query the Authentication object:

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

	if (principal instanceof UserDetails) {
		String username = ((UserDetails) principal).getUsername();
	} else {
		String username = principal.toString();
	}

The principal object returned above can be cast into a UserDetails object. This UserDetails object can then be cast into the application specific user object. The following method in the UserDetailsService accepts a string based username argument and returns a UserDetails object:

UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;

JdbcDaoImpl and InMemoryDaoImpl are some of the implentations of the UserDetailsService interface provided by Spring Security. UserDetailsService is just that – it provides user details but does not authenticate a user.

The AuthenticationManager inserts GrantedAuthority objects into the Authentication object to be read by the AccessDecisionManager. The AccessDecisionManager makes the final access control decision based on the AccessDecisionVoter responses. Each AccessDecisionManager polls one or more AccessDecisionVoters specified in the security.xml config file. It passes all the arguments to all the voters. For each argument, each voter has only three options (int) to return – ACCESS_GRANTED, ACCESS_DENIED or ACCESS_ABSTAIN. A voter returns ACCESS_ABSTAIN when the config attriute it is asked to vote on does not apply. For example, if a RoleVoter is asked to vote on anything other than the role of a user, it will return ACCESS_ABSTAIN.

The following AccessDecisionManagers are available:
•AffirmativeBased (Any yes)
•ConsensusBased (Simple Majority yes, property to decide what to do if all decisions abstain)
•UnanimousBased (All yes or abstain).

The following voters are provided by Spring Security:
•RoleVoter (Votes only whether the user has a specified Role.)
•AuthenticatedVoter (Checks whether the user is anonymous, fully-authenticated or remember-me authenticated)

It is also possible to create custom voters.

Categories

Need a bit more info on how Armedia can help you?

Feel free to schedule a 30-minute no-obligations meeting.

1 Comment

  1. arin

    Thanks. Nice informative article. I have one question related to IMO Spring.Is this frequently used nowadays?

    Reply

Submit a Comment

Your email address will not be published. Required fields are marked *