Resource
@Entity
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Resource {
@Id
@GeneratedValue
private Integer id;
private String type;
private String value;
@ManyToMany(mappedBy = "resources", targetEntity = Role.class, fetch = FetchType.EAGER)
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
private Set<Role> roles;
/**
* The default constructor
*/
public Resource() {
}
/**
* Get role authorities as string
*
* @return
*/
@Transient
public String getRoleAuthorities() {
List<String> roleAuthorities = new ArrayList<String>();
for(Role role : roles) {
roleAuthorities.add(role.getName());
}
return StringUtils.join(roleAuthorities, ",");
}
/**
* @return the id
*/
public Integer getId() {
return id;
}
/**
* @return the type
*/
public String getType() {
return type;
}
/**
* @return the value
*/
public String getValue() {
return value;
}
/**
* @return the roles
*/
public Set<Role> getRoles() {
return roles;
}
/**
* @param id the id to set
*/
public void setId(Integer id) {
this.id = id;
}
/**
* @param type the type to set
*/
public void setType(String type) {
this.type = type;
}
/**
* @param value the value to set
*/
public void setValue(String value) {
this.value = value;
}
/**
* @param roles the roles to set
*/
public void setRoles(Set<Role> roles) {
this.roles = roles;
}
}
@Entity
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Role {
@Id
@GeneratedValue
private Integer id;
private String name;
private String description;
@ManyToMany(targetEntity = Resource.class, fetch = FetchType.EAGER)
@JoinTable(name = "role_resource", joinColumns = @JoinColumn(name = "role_id"), inverseJoinColumns = @JoinColumn(name = "resource_id"))
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
private Set<Resource> resources;
/**
* The default constructor
*/
public Role() {
}
/**
* @return the id
*/
public Integer getId() {
return id;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @return the description
*/
public String getDescription() {
return description;
}
/**
* @return the resources
*/
public Set<Resource> getResources() {
return resources;
}
/**
* @param id the id to set
*/
public void setId(Integer id) {
this.id = id;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @param description the description to set
*/
public void setDescription(String description) {
this.description = description;
}
/**
* @param resources the resources to set
*/
public void setResources(Set<Resource> resources) {
this.resources = resources;
}
}
@Entity
@Proxy(lazy = false)
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class User implements UserDetails {
private static final long serialVersionUID = 8026813053768023527L;
@Id
@GeneratedValue
private Integer id;
private String name;
private String password;
private boolean disabled;
@ManyToMany(targetEntity = Role.class, fetch = FetchType.EAGER)
@JoinTable(name = "user_role", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "role_id"))
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
private Set<Role> roles;
@Transient
private Map<String, List<Resource>> roleResources;
/**
* The default constructor
*/
public User() {
}
/* (non-Javadoc)
* @see org.springframework.security.userdetails.UserDetails#getAuthorities()
*/
public GrantedAuthority[] getAuthorities() {
List<GrantedAuthority> grantedAuthorities = new ArrayList<GrantedAuthority>(roles.size());
for(Role role : roles) {
grantedAuthorities.add(new GrantedAuthorityImpl(role.getName()));
}
return grantedAuthorities.toArray(new GrantedAuthority[roles.size()]);
}
/**
* Returns the authorites string
*
* eg.
* downpour --- ROLE_ADMIN,ROLE_USER
* robbin --- ROLE_ADMIN
*
* @return
*/
public String getAuthoritiesString() {
List<String> authorities = new ArrayList<String>();
for(GrantedAuthority authority : this.getAuthorities()) {
authorities.add(authority.getAuthority());
}
return StringUtils.join(authorities, ",");
}
/* (non-Javadoc)
* @see org.springframework.security.userdetails.UserDetails#getPassword()
*/
public String getPassword() {
return password;
}
/* (non-Javadoc)
* @see org.springframework.security.userdetails.UserDetails#getUsername()
*/
public String getUsername() {
return name;
}
/* (non-Javadoc)
* @see org.springframework.security.userdetails.UserDetails#isAccountNonExpired()
*/
public boolean isAccountNonExpired() {
return true;
}
/* (non-Javadoc)
* @see org.springframework.security.userdetails.UserDetails#isAccountNonLocked()
*/
public boolean isAccountNonLocked() {
return true;
}
/* (non-Javadoc)
* @see org.springframework.security.userdetails.UserDetails#isCredentialsNonExpired()
*/
public boolean isCredentialsNonExpired() {
return true;
}
/* (non-Javadoc)
* @see org.springframework.security.userdetails.UserDetails#isEnabled()
*/
public boolean isEnabled() {
return !disabled;
}
/**
* @return the id
*/
public Integer getId() {
return id;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @return the disabled
*/
public boolean isDisabled() {
return disabled;
}
/**
* @return the roles
*/
public Set<Role> getRoles() {
return roles;
}
/**
* @return the roleResources
*/
public Map<String, List<Resource>> getRoleResources() {
// init roleResources for the first time
if(this.roleResources == null) {
this.roleResources = new HashMap<String, List<Resource>>();
for(Role role : this.roles) {
String roleName = role.getName();
Set<Resource> resources = role.getResources();
for(Resource resource : resources) {
String key = roleName + "_" + resource.getType();
if(!this.roleResources.containsKey(key)) {
this.roleResources.put(key, new ArrayList<Resource>());
}
this.roleResources.get(key).add(resource);
}
}
}
return this.roleResources;
}
/**
* @param id the id to set
*/
public void setId(Integer id) {
this.id = id;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @param password the password to set
*/
public void setPassword(String password) {
this.password = password;
}
/**
* @param disabled the disabled to set
*/
public void setDisabled(boolean disabled) {
this.disabled = disabled;
}
/**
* @param roles the roles to set
*/
public void setRoles(Set<Role> roles) {
this.roles = roles;
}
}
public class SecureResourceFilterInvocationDefinitionSource implements FilterInvocationDefinitionSource, InitializingBean {
private UrlMatcher urlMatcher;
private boolean useAntPath = true;
private boolean lowercaseComparisons = true;
/**
* @param useAntPath the useAntPath to set
*/
public void setUseAntPath(boolean useAntPath) {
this.useAntPath = useAntPath;
}
/**
* @param lowercaseComparisons
*/
public void setLowercaseComparisons(boolean lowercaseComparisons) {
this.lowercaseComparisons = lowercaseComparisons;
}
/* (non-Javadoc)
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/
public void afterPropertiesSet() throws Exception {
// default url matcher will be RegexUrlPathMatcher
this.urlMatcher = new RegexUrlPathMatcher();
if (useAntPath) { // change the implementation if required
this.urlMatcher = new AntUrlPathMatcher();
}
// Only change from the defaults if the attribute has been set
if ("true".equals(lowercaseComparisons)) {
if (!this.useAntPath) {
((RegexUrlPathMatcher) this.urlMatcher).setRequiresLowerCaseUrl(true);
}
} else if ("false".equals(lowercaseComparisons)) {
if (this.useAntPath) {
((AntUrlPathMatcher) this.urlMatcher).setRequiresLowerCaseUrl(false);
}
}
}
/* (non-Javadoc)
* @see org.springframework.security.intercept.ObjectDefinitionSource#getAttributes(java.lang.Object)
*/
public ConfigAttributeDefinition getAttributes(Object filter) throws IllegalArgumentException {
FilterInvocation filterInvocation = (FilterInvocation) filter;
String requestURI = filterInvocation.getRequestUrl();
Map<String, String> urlAuthorities = this.getUrlAuthorities(filterInvocation);
String grantedAuthorities = null;
for(Iterator<Map.Entry<String, String>> iter = urlAuthorities.entrySet().iterator(); iter.hasNext();) {
Map.Entry<String, String> entry = iter.next();
String url = entry.getKey();
if(urlMatcher.pathMatchesUrl(url, requestURI)) {
grantedAuthorities = entry.getValue();
break;
}
}
if(grantedAuthorities != null) {
ConfigAttributeEditor configAttrEditor = new ConfigAttributeEditor();
configAttrEditor.setAsText(grantedAuthorities);
return (ConfigAttributeDefinition) configAttrEditor.getValue();
}
return null;
}
/* (non-Javadoc)
* @see org.springframework.security.intercept.ObjectDefinitionSource#getConfigAttributeDefinitions()
*/
@SuppressWarnings("unchecked")
public Collection getConfigAttributeDefinitions() {
return null;
}
/* (non-Javadoc)
* @see org.springframework.security.intercept.ObjectDefinitionSource#supports(java.lang.Class)
*/
@SuppressWarnings("unchecked")
public boolean supports(Class clazz) {
return true;
}
/**
*
* @param filterInvocation
* @return
*/
@SuppressWarnings("unchecked")
private Map<String, String> getUrlAuthorities(FilterInvocation filterInvocation) {
ServletContext servletContext = filterInvocation.getHttpRequest().getSession().getServletContext();
return (Map<String, String>)servletContext.getAttribute("urlAuthorities");
}
}
@Service("securityManager")
public class SecurityManagerSupport extends HibernateDaoSupport implements UserDetailsService, SecurityManager {
/**
* Init sessionFactory here because the annotation of Spring 2.5 can not support override inject
*
* @param sessionFactory
*/
@Autowired
public void init(SessionFactory sessionFactory) {
super.setSessionFactory(sessionFactory);
}
/* (non-Javadoc)
* @see org.springframework.security.userdetails.UserDetailsService#loadUserByUsername(java.lang.String)
*/
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException, DataAccessException {
List<User> users = getHibernateTemplate().find("FROM User user WHERE user.name = ? AND user.disabled = false", userName);
if(users.isEmpty()) {
throw new UsernameNotFoundException("User " + userName + " has no GrantedAuthority");
}
return users.get(0);
}
/* (non-Javadoc)
* @see com.javaeye.sample.security.SecurityManager#loadUrlAuthorities()
*/
public Map<String, String> loadUrlAuthorities() {
Map<String, String> urlAuthorities = new HashMap<String, String>();
List<Resource> urlResources = getHibernateTemplate().find("FROM Resource resource WHERE resource.type = ?", "URL");
for(Resource resource : urlResources) {
urlAuthorities.put(resource.getValue(), resource.getRoleAuthorities());
}
return urlAuthorities;
}
}
public class SecurityUserHolder {
/**
* Returns the current user
*
* @return
*/
public static User getCurrentUser() {
return (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
}
}
public interface SecurityManager {
public Map<String, String> loadUrlAuthorities();
}
public class ServletContextLoaderListener implements ServletContextListener {
/* (non-Javadoc)
* @see javax.servlet.ServletContextListener#contextInitialized(javax.servlet.ServletContextEvent)
*/
public void contextInitialized(ServletContextEvent servletContextEvent) {
ServletContext servletContext = servletContextEvent.getServletContext();
SecurityManager securityManager = this.getSecurityManager(servletContext);
Map<String, String> urlAuthorities = securityManager.loadUrlAuthorities();
servletContext.setAttribute("urlAuthorities", urlAuthorities);
}
/* (non-Javadoc)
* @see javax.servlet.ServletContextListener#contextDestroyed(javax.servlet.ServletContextEvent)
*/
public void contextDestroyed(ServletContextEvent servletContextEvent) {
servletContextEvent.getServletContext().removeAttribute("urlAuthorities");
}
/**
* Get SecurityManager from ApplicationContext
*
* @param servletContext
* @return
*/
protected SecurityManager getSecurityManager(ServletContext servletContext) {
return (SecurityManager) WebApplicationContextUtils.getWebApplicationContext(servletContext).getBean("securityManager");
}
}
public class Index extends HttpServlet {
private static final long serialVersionUID = -2695430823076562265L;
/* (non-Javadoc)
* @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
User user = SecurityUserHolder.getCurrentUser();
request.setAttribute("currentUser", user);
RequestDispatcher dispatcher = request.getRequestDispatcher("/index.jsp");
dispatcher.forward(request, response);
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="Yoda" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>Yoda</display-name>
<!-- Spring ApplicationContext Definition -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/classes/context/applicationContext-*.xml</param-value>
</context-param>
<!-- Spring security Filter -->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>index</servlet-name>
<servlet-class>com.javaeye.sample.web.servlet.Index</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>index</servlet-name>
<url-pattern>/index</url-pattern>
</servlet-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>com.javaeye.sample.web.loader.ServletContextLoaderListener</listener-class>
</listener>
</web-app>
<?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.4.xsd">
<beans:bean id="loggerListener" class="org.springframework.security.event.authentication.LoggerListener" />
<http access-denied-page="/403.jsp" >
<intercept-url pattern="/static/**" filters="none" />
<intercept-url pattern="/template/**" filters="none" />
<intercept-url pattern="/" filters="none" />
<intercept-url pattern="/login.jsp" filters="none" />
<form-login login-page="/login.jsp" authentication-failure-url="/login.jsp?error=true" default-target-url="/index" />
<logout logout-success-url="/login.jsp"/>
<http-basic />
</http>
<authentication-manager alias="authenticationManager"/>
<authentication-provider user-service-ref="securityManager">
<password-encoder hash="md5"/>
</authentication-provider>
<beans:bean id="accessDecisionManager" class="org.springframework.security.vote.AffirmativeBased">
<beans:property name="allowIfAllAbstainDecisions" value="false"/>
<beans:property name="decisionVoters">
<beans:list>
<beans:bean class="org.springframework.security.vote.RoleVoter"/>
<beans:bean class="org.springframework.security.vote.AuthenticatedVoter"/>
</beans:list>
</beans:property>
</beans:bean>
<beans:bean id="resourceSecurityInterceptor" class="org.springframework.security.intercept.web.FilterSecurityInterceptor">
<beans:property name="authenticationManager" ref="authenticationManager"/>
<beans:property name="accessDecisionManager" ref="accessDecisionManager"/>
<beans:property name="objectDefinitionSource" ref="secureResourceFilterInvocationDefinitionSource" />
<beans:property name="observeOncePerRequest" value="false" />
<custom-filter after="LAST" />
</beans:bean>
<beans:bean id="secureResourceFilterInvocationDefinitionSource" class="com.javaeye.sample.security.interceptor.SecureResourceFilterInvocationDefinitionSource" />
</beans:beans>