001 package org.trails.hibernate;
002
003 import java.io.Serializable;
004
005 import org.acegisecurity.GrantedAuthority;
006 import org.acegisecurity.context.SecurityContext;
007 import org.acegisecurity.context.SecurityContextHolder;
008 import org.hibernate.criterion.DetachedCriteria;
009 import org.hibernate.criterion.Restrictions;
010 import org.hibernate.criterion.SimpleExpression;
011 import org.trails.security.EntityModificationInterception;
012 import org.trails.security.annotation.ViewRequiresAssociation;
013 import org.trails.security.annotation.ViewRequiresRole;
014
015 public class SecurePersistenceServiceImpl extends HibernatePersistenceServiceImpl {
016 @Override
017 protected DetachedCriteria alterCriteria(Class type, DetachedCriteria criteria) {
018 SecurityContext context = SecurityContextHolder.getContext();
019 // Assume that context should have been established for each request, and if it's not,
020 // it's an internal service call
021 if (context == null || context.getAuthentication() == null) return criteria;
022
023 // Check first if user has permission granted by a role
024 ViewRequiresRole viewRoleRestriction = (ViewRequiresRole)type.getAnnotation(ViewRequiresRole.class );
025 if (viewRoleRestriction != null) for (GrantedAuthority authority : context.getAuthentication().getAuthorities())
026 for (String role : viewRoleRestriction.value()) if (authority.getAuthority().equals(role) ) return criteria;
027
028 ViewRequiresAssociation viewRestriction = (ViewRequiresAssociation)type.getAnnotation(ViewRequiresAssociation.class );
029
030 if (viewRoleRestriction == null && viewRestriction == null) return criteria;
031
032 if (viewRestriction == null) {
033 // At this point we know the user should have no access to the entities, because there's
034 // a role restriction but user doesn't have a suitable role and there's no association
035 // We can throw an exception here, but it wouldn't be consistent with how assiative restriction
036 // is handled (just returns a query with no results) and would change the semantics
037 // throw new EntitySecurityException(null, "No suitable role or association");
038
039 // We should do:
040 //criteria.setMaxResults(0);
041 // but DetachedCriteria doesn't support setMaxResults()
042 // http://opensource.atlassian.com/projects/hibernate/browse/HHH-912
043 // Ugly HACK instead
044 return criteria.add(Restrictions.idEq(null) );
045 }
046
047 String currentUsername = context.getAuthentication().getName();
048 String ownerPropertyAssociation = viewRestriction.value();
049 // username as in Acegi UserDetails
050 SimpleExpression usernameRestriction = Restrictions.eq("username",currentUsername);
051 if ("".equals(ownerPropertyAssociation)) criteria.add(usernameRestriction);
052 else criteria.createCriteria(ownerPropertyAssociation).add(usernameRestriction);
053 return criteria;
054 }
055
056 public <T> T loadInstance(final Class<T> type, Serializable id)
057 {
058 return getInstance(type, id);
059 }
060
061 }