Announcement Announcement Module
Collapse
No announcement yet.
How to Customize Spring Security? Page Title Module
Move Remove Collapse
This topic is closed
X
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • How to Customize Spring Security?

    Hey all,

    I am new to Spring and it is simply fabulous! Thanks to Rod Johnson and Co for developing this wonderful package.

    I have used the Spring Recipes book (a great book btw) and the Online Reference manual to successfully secure my web application using Spring Security. This is what I did till now:
    I have a legacy database with following tables and fields
    Code:
    user {usernum, username, password, active(logical), userrank}
    role {rolenum, rolename, active(logical)}
    userinrole {id, usernum, rolenum}
    The roles in the role table do not have a ROLE_ prefix, so I had to use a customized access decision manager. Because I am using a legacy database, I had to configure the <jdbc-user-service> element appropriately.

    Code:
    <beans:bean id="accessDecisionManager" class="org.springframework.security.vote.AffirmativeBased">
            <beans:property name="decisionVoters">
                <beans:bean class="org.springframework.security.vote.RoleVoter">
                    <beans:property name="rolePrefix" value=""/>
                </beans:bean>
            </beans:property>
    </beans:bean> 	
    	
    <http auto-config="true" access-decision-manager-ref="accessDecisionManager">
    	<intercept-url pattern="/protected.jsp" access="Admin" />
    </http>
    
    <authentication-provider>
    	<jdbc-user-service data-source-ref="dataSource" 
    		users-by-username-query="${security.user-query}" 
    		authorities-by-username-query="${security.authorities-query}" />
    </authentication-provider>
    Now, as you can see, the user table has a field named userrank. I would like to use this field to secure some URLs as well as some methods. That is, I would like to secure resources using this field apart from the roles assigned to a user.

    I hope I made sense. Can a Spring Security Guru please point me in the right direction. I am using Spring 2.5 and Spring Security 2.0.5.

    Thank you,
    Joe

  • #2
    Hey Guys,

    I figured out how to solve my problem. I had to write a custom UserDetailsService class and also a Custom UserDetails class that can hold the user's rank. I then wrote a Custom Voter class (called RankVoter) and added it to the Affirmative Access Decision Manager. Now I can protect resources using ranks by mentioning them in the access attribute of the <intercept-url> elements.

    I am posting some code that explains what I've done (with the hope that it might help someone looking for a solution to a similar issue)!

    Thanks,
    Joe

    Code:
    package springexample.security;
    
    import springexample.repository.UserDAO;
    import springexample.domain.Role;
    import springexample.domain.User;
    
    import org.springframework.security.GrantedAuthority;
    import org.springframework.security.GrantedAuthorityImpl;
    import org.springframework.security.userdetails.UserDetailsService; 
    import org.springframework.security.userdetails.UserDetails;
    import org.springframework.security.userdetails.UsernameNotFoundException;
    import org.springframework.dao.DataAccessException;
    
    public class ExampleUserDetailsService implements UserDetailsService {
    
    		private UserDAO userDAO;
    
    		public void setUserDAO(UserDAO userDAO) {
    			this.userDAO = userDAO;
    		}
    
    		public UserDetails loadUserByUsername(String username)
    				throws UsernameNotFoundException, DataAccessException {
    			// Get the user from the database
    			User user = userDAO.getUserByUsername(username);
    			if (user == null) return null;
    			
    			// Construct GrantedAuthorities from the roles associated with the user
    			int numRoles = user.getRoles().size();
    			GrantedAuthority[] grantedAuthorities = null;
    			if (numRoles > 0) {
    				grantedAuthorities = new GrantedAuthorityImpl[numRoles];
    				int roleNum = 0;
    				for (Role role : user.getRoles()) {
    					grantedAuthorities[roleNum++] = new GrantedAuthorityImpl(role.getName());
    				}
    			}
    
    			// Create an UserDetails object and return
    			ExampleUserDetails userDetails = new ExampleUserDetails (
    					user.getUsername(),
    					user.getPassword(),
    					user.getActive(),
    					true,
    					true,
    					true,
    					grantedAuthorities);
    
    			userDetails.setRank(user.getRank());
    			
    			return userDetails;
    		}
    
    }

    Code:
    package springexample.security;
    
    import org.springframework.security.GrantedAuthority;
    import org.springframework.security.userdetails.User;
    
    public class ExampleUserDetails extends User {
    	private static final long serialVersionUID = 100L;
    
    	private int rank;
    	
    	public ExampleUserDetails(String username, String password, boolean enabled,
    			boolean accountNonExpired, boolean credentialsNonExpired,
    			boolean accountNonLocked, GrantedAuthority[] authorities)
    			throws IllegalArgumentException {
    		super(username, password, enabled, accountNonExpired, credentialsNonExpired,
    				accountNonLocked, authorities);
    	}
    	
    	public void setRank(int rank) {
    		this.rank = rank;
    	}
    	
    	public int getRank() {
    		return this.rank;
    	}
    
    }
    Code:
    package springexample.security;
    
    import org.springframework.security.vote.AccessDecisionVoter;
    import org.springframework.security.ConfigAttribute;
    import org.springframework.security.ConfigAttributeDefinition;
    import org.springframework.security.Authentication;
    
    public class RankVoter implements AccessDecisionVoter {
    	@SuppressWarnings("unchecked")
    	public boolean supports(Class clazz) {
    		return true;
    	}
    	
    	// Checks to see if the attribute is a number
    	public boolean supports(ConfigAttribute attribute) {
    		String attrValue = attribute.getAttribute();
    		if (attrValue == null) return false;
    		try {
    			Integer.parseInt(attrValue);
    		} catch (NumberFormatException ex) {
    			return false;
    		}
    		return true;
    	}
    
    	public int vote(Authentication authentication, Object object, ConfigAttributeDefinition config) {
    		if (! (authentication.getPrincipal() instanceof ExampleUserDetails))
    			return ACCESS_DENIED;
    		
    		int userRank = ((ExampleUserDetails) authentication.getPrincipal()).getRank();
    		
    		int result = ACCESS_ABSTAIN;
    		for (Object element: config.getConfigAttributes()) {
    			ConfigAttribute attribute = (ConfigAttribute) element;
    			if (this.supports(attribute)) {
    				result = ACCESS_DENIED;
    				int attrValue = Integer.parseInt(attribute.getAttribute());
    				if (userRank <= attrValue)
    					return ACCESS_GRANTED; 
    			}
    		}
    		return result;
    	}
    }

    Comment


    • #3
      Hi Joe

      Could you please post your security xml code too.

      Thanks in advance
      Chan

      Comment


      • #4
        Sure Chan,

        Here's the xml...

        -Joe

        Code:
        <?xml version="1.0" encoding="UTF-8"?>
        <beans:beans xmlns="http://www.springframework.org/schema/security"
          xmlns:beans="http://www.springframework.org/schema/beans"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://www.springframework.org/schema/beans 
                   http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
                   http://www.springframework.org/schema/security 
                   http://www.springframework.org/schema/security/spring-security-2.0.1.xsd"> 
        	
        	<beans:bean id="accessDecisionManager" class="org.springframework.security.vote.AffirmativeBased">
                <beans:property name="decisionVoters">
                	<beans:list>
                    	<beans:bean class="org.springframework.security.vote.RoleVoter">
                        	<beans:property name="rolePrefix" value=""/>
                    	</beans:bean>
                    	
                    	<beans:bean class="springexample.security.RankVoter" />
                    </beans:list>
                </beans:property>
            </beans:bean> 	
        	
        	<beans:bean id="userDetailsService" class="springexample.security.ExampleUserDetailsService">
        		<beans:property name="userDAO" ref="userDAO" />
        	</beans:bean>
        	
        	<http auto-config="true" access-decision-manager-ref="accessDecisionManager">
        		<intercept-url pattern="/protected.jsp" access="Admin,2" />
        	</http>
        
        
        	<authentication-provider user-service-ref="userDetailsService">
        		<password-encoder hash="md5"  />
        	</authentication-provider>
        
        </beans:beans>

        Comment


        • #5
          Thanks Joe

          Comment

          Working...
          X