Package org.jboss.seam.security.permission

Source Code of org.jboss.seam.security.permission.JpaPermissionStore$PropertyTypeCriteria

package org.jboss.seam.security.permission;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Instance;
import javax.enterprise.inject.spi.BeanManager;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.Query;

import org.jboss.solder.logging.Logger;
import org.jboss.seam.security.annotations.permission.PermissionProperty;
import org.jboss.seam.security.annotations.permission.PermissionPropertyType;
import org.jboss.seam.security.permission.PermissionMetadata.ActionSet;
import org.jboss.solder.properties.Property;
import org.jboss.solder.properties.query.PropertyCriteria;
import org.jboss.solder.properties.query.PropertyQueries;
import org.picketlink.idm.spi.model.IdentityObject;

/**
* A permission store implementation that uses JPA as its persistence mechanism.
*
* @author Shane Bryzak
*/
@ApplicationScoped
public class JpaPermissionStore implements PermissionStore, Serializable {
    private static final long serialVersionUID = 4764590939669047915L;

    private static final Logger log = Logger.getLogger(JpaPermissionStore.class);

    private class PropertyTypeCriteria implements PropertyCriteria {
        private PermissionPropertyType pt;

        public PropertyTypeCriteria(PermissionPropertyType pt) {
            this.pt = pt;
        }

        public boolean fieldMatches(Field f) {
            return f.isAnnotationPresent(PermissionProperty.class) &&
                    f.getAnnotation(PermissionProperty.class).value().equals(pt);
        }

        public boolean methodMatches(Method m) {
            return m.isAnnotationPresent(PermissionProperty.class) &&
                    m.getAnnotation(PermissionProperty.class).value().equals(pt);
        }
    }

    private boolean enabled;

    private Class<?> identityPermissionClass;

    private Property<Object> identityProperty;
    private Property<?> relationshipTypeProperty;
    private Property<String> relationshipNameProperty;
    private Property<String> resourceProperty;
    private Property<Object> permissionProperty;

    private Map<Integer, String> queryCache = new HashMap<Integer, String>();

    private PermissionMetadata metadata;

    @Inject
    IdentifierPolicy identifierPolicy;
    @Inject
    BeanManager manager;

    @Inject
    Instance<EntityManager> entityManagerInstance;

    @Inject
    public void init() {
        metadata = new PermissionMetadata();

        // TODO see if we can scan for this automatically
        if (identityPermissionClass == null) {
            log.debug("No identityPermissionClass set, JpaPermissionStore will be unavailable.");
            enabled = false;
            return;
        }

        initProperties();
    }

    protected void initProperties() {
        identityProperty = PropertyQueries.createQuery(identityPermissionClass)
                .addCriteria(new PropertyTypeCriteria(PermissionPropertyType.IDENTITY))
                .getFirstResult();

        if (identityProperty == null) {
            throw new RuntimeException("Invalid identityPermissionClass " +
                    identityPermissionClass.getName() +
                    " - required annotation @PermissionProperty(IDENTITY) not found on any field or method.");
        }

        relationshipTypeProperty = PropertyQueries.createQuery(identityPermissionClass)
                .addCriteria(new PropertyTypeCriteria(PermissionPropertyType.RELATIONSHIP_TYPE))
                .getFirstResult();

        if (relationshipTypeProperty == null) {
            throw new RuntimeException("Invalid identityPermissionClass " +
                    identityPermissionClass.getName() +
                    " - required annotation @PermissionProperty(RELATIONSHIP_TYPE) not found on any field or method.");
        }

        relationshipNameProperty = PropertyQueries.<String>createQuery(identityPermissionClass)
                .addCriteria(new PropertyTypeCriteria(PermissionPropertyType.RELATIONSHIP_NAME))
                .getFirstResult();

        if (relationshipNameProperty == null) {
            throw new RuntimeException("Invalid identityPermissionClass " +
                    identityPermissionClass.getName() +
                    " - required annotation @PermissionProperty(RELATIONSHIP_NAME) not found on any field or method.");
        }

        resourceProperty = PropertyQueries.<String>createQuery(identityPermissionClass)
                .addCriteria(new PropertyTypeCriteria(PermissionPropertyType.RESOURCE))
                .getFirstResult();

        if (resourceProperty == null) {
            throw new RuntimeException("Invalid identityPermissionClass " +
                    identityPermissionClass.getName() +
                    " - required annotation @PermissionProperty(RESOURCE) not found on any field or method.");
        }

        permissionProperty = PropertyQueries.createQuery(identityPermissionClass)
                .addCriteria(new PropertyTypeCriteria(PermissionPropertyType.PERMISSION))
                .getFirstResult();

        if (permissionProperty == null) {
            throw new RuntimeException("Invalid identityPermissionClass " +
                    identityPermissionClass.getName() +
                    " - required annotation @PermissionProperty(PERMISSION) not found on any field or method.");
        }

        enabled = true;
    }

    /**
     * Creates a Query that returns a list of permission records for the specified parameters.
     *
     * @param target         The target of the permission, may be null
     * @param targets        A set of permission targets, may be null
     * @param recipient      The permission recipient, may be null
     * @param discrimination A discrimination (either user, role or both), required
     * @return Query The query generated for the provided parameters
     */
    protected Query createPermissionQuery(Object target, Set<?> targets,
                                          IdentityObject identity) {
        if (target != null && targets != null) {
            throw new IllegalArgumentException("Cannot specify both target and targets");
        }

        int queryKey = (target != null) ? 1 : 0;
        queryKey |= (targets != null) ? 2 : 0;
        queryKey |= (identity != null) ? 4 : 0;

        if (!queryCache.containsKey(queryKey)) {
            boolean conditionsAdded = false;

            StringBuilder q = new StringBuilder();
            q.append("select p from ");
            q.append(identityPermissionClass.getName());
            q.append(" p");

            if (target != null) {
                q.append(" where p.");
                q.append(resourceProperty.getName());
                q.append(" = :target");
                conditionsAdded = true;
            }

            if (targets != null) {
                q.append(" where p.");
                q.append(resourceProperty.getName());
                q.append(" in (:targets)");
                conditionsAdded = true;
            }

            if (identity != null) {
                q.append(conditionsAdded ? " and p." : " where p.");
                q.append(identityProperty.getName());
                q.append(" = :identity");
                conditionsAdded = true;
            }

            queryCache.put(queryKey, q.toString());
        }

        Query query = lookupEntityManager().createQuery(queryCache.get(queryKey));

        if (target != null) query.setParameter("target", identifierPolicy.getIdentifier(target));

        if (targets != null) {
            Set<String> identifiers = new HashSet<String>();
            for (Object t : targets) {
                identifiers.add(identifierPolicy.getIdentifier(t));
            }
            query.setParameter("targets", identifiers);
        }

        if (identity != null) query.setParameter("identity", resolveIdentityEntity(identity));

        return query;
    }

    public boolean grantPermission(Permission permission) {
        return updatePermissionActions(permission.getResource(), permission.getIdentity(),
                new String[]{permission.getPermission()}, true);
    }

    public boolean revokePermission(Permission permission) {
        return updatePermissionActions(permission.getResource(), permission.getIdentity(),
                new String[]{permission.getPermission()}, false);
    }

    /**
     * This is where the bulk of the actual work happens.
     *
     * @param target    The target object to update permissions for
     * @param recipient The recipient to update permissions for
     * @param actions   The actions that will be updated
     * @param set       true if the specified actions are to be granted, false if they are to be revoked
     * @return true if the operation is successful
     */
    protected boolean updatePermissionActions(Object resource, IdentityObject identity, String[] actions,
                                              boolean set) {
        try {
            List<?> permissions = createPermissionQuery(resource, null, identity).getResultList();

            if (permissions.isEmpty()) {
                if (!set) return true;

                ActionSet actionSet = metadata.createActionSet(resource.getClass(), null);
                for (String action : actions) {
                    actionSet.add(action);
                }

                Object instance = identityPermissionClass.newInstance();
                resourceProperty.setValue(instance, identifierPolicy.getIdentifier(resource));
                permissionProperty.setValue(instance, actionSet.toString());
                identityProperty.setValue(instance, resolveIdentityEntity(identity));

                lookupEntityManager().persist(instance);
                return true;
            }

            Object instance = permissions.get(0);

            ActionSet actionSet = metadata.createActionSet(resource.getClass(),
                    permissionProperty.getValue(instance).toString());

            for (String action : actions) {
                if (set) {
                    actionSet.add(action);
                } else {
                    actionSet.remove(action);
                }
            }

            if (permissions.size() > 1) {
                // Same as with roles, consolidate the records if there is more than one
                for (Object p : permissions) {
                    actionSet.addMembers(permissionProperty.getValue(p).toString());
                    if (!p.equals(instance)) {
                        lookupEntityManager().remove(p);
                    }
                }
            }

            if (!actionSet.isEmpty()) {
                permissionProperty.setValue(instance, actionSet.toString());
                lookupEntityManager().merge(instance);
            } else {
                // No actions remaining in set, so just remove the record
                lookupEntityManager().remove(instance);
            }

            return true;
        } catch (Exception ex) {
            throw new RuntimeException("Could not grant permission", ex);
        }
    }

    public boolean grantPermissions(List<Permission> permissions) {
        // Target/Recipient/Action map
        Map<Object, Map<IdentityObject, List<Permission>>> groupedPermissions = groupPermissions(permissions);

        for (Object resource : groupedPermissions.keySet()) {
            Map<IdentityObject, List<Permission>> recipientPermissions = groupedPermissions.get(resource);

            for (IdentityObject recipient : recipientPermissions.keySet()) {
                List<Permission> ps = recipientPermissions.get(recipient);
                String[] actions = new String[ps.size()];
                for (int i = 0; i < ps.size(); i++) actions[i] = ps.get(i).getPermission();
                updatePermissionActions(resource, recipient, actions, true);
            }
        }

        return true;
    }

    public boolean revokePermissions(List<Permission> permissions) {
        // Target/Recipient/Action map
        Map<Object, Map<IdentityObject, List<Permission>>> groupedPermissions = groupPermissions(permissions);

        for (Object target : groupedPermissions.keySet()) {
            Map<IdentityObject, List<Permission>> recipientPermissions = groupedPermissions.get(target);

            for (IdentityObject identity : recipientPermissions.keySet()) {
                List<Permission> ps = recipientPermissions.get(identity);
                String[] actions = new String[ps.size()];
                for (int i = 0; i < ps.size(); i++) actions[i] = ps.get(i).getPermission();
                updatePermissionActions(target, identity, actions, false);
            }
        }

        return true;
    }

    /**
     * Groups a list of arbitrary permissions into a more easily-consumed structure
     *
     * @param permissions The list of permissions to group
     * @return
     */
    private Map<Object, Map<IdentityObject, List<Permission>>> groupPermissions(List<Permission> permissions) {
        // Target/Recipient/Action map
        Map<Object, Map<IdentityObject, List<Permission>>> groupedPermissions = new HashMap<Object, Map<IdentityObject, List<Permission>>>();

        for (Permission permission : permissions) {
            if (!groupedPermissions.containsKey(permission.getResource())) {
                groupedPermissions.put(permission.getResource(), new HashMap<IdentityObject, List<Permission>>());
            }

            Map<IdentityObject, List<Permission>> recipientPermissions = groupedPermissions.get(permission.getResource());
            if (!recipientPermissions.containsKey(permission.getIdentity())) {
                List<Permission> perms = new ArrayList<Permission>();
                perms.add(permission);
                recipientPermissions.put(permission.getIdentity(), perms);
            } else {
                recipientPermissions.get(permission.getIdentity()).add(permission);
            }
        }

        return groupedPermissions;
    }

    /**
     * @param recipient
     * @return The entity or name representing the permission recipient
     */
    protected Object resolveIdentityEntity(IdentityObject identity) {
        // TODO implement this method (we already know the identity's entity class)

        return identity.getName();
    }

    /**
     * Returns a list of all user and role permissions for the specified action for all specified target objects
     */
    public List<Permission> listPermissions(Set<Object> targets, String action) {
        // TODO limit the number of targets passed at a single time to 25
        return listPermissions(null, targets, action);
    }

    /**
     * Returns a list of all user and role permissions for a specific permission target and action.
     */
    public List<Permission> listPermissions(Object target, String action) {
        return listPermissions(target, null, action);
    }

    protected List<Permission> listPermissions(Object resource, Set<Object> targets, String action) {
        if (identityPermissionClass == null) return null;

        if (resource != null && targets != null) {
            throw new IllegalArgumentException("Cannot specify both target and targets");
        }

        List<Permission> permissions = new ArrayList<Permission>();

        if (targets != null && targets.isEmpty()) return permissions;

        // First query for user permissions
        Query permissionQuery = targets != null ?
                createPermissionQuery(null, targets, null) :
                createPermissionQuery(resource, null, null);

        List<?> userPermissions = permissionQuery.getResultList();

        Map<String, Object> identifierCache = null;

        if (targets != null) {
            identifierCache = new HashMap<String, Object>();

            for (Object t : targets) {
                identifierCache.put(identifierPolicy.getIdentifier(t), t);
            }
        }

        for (Object permission : userPermissions) {
            ActionSet actionSet = null;

            if (targets != null) {
                //target = identifierCache.get(targetProperty.getValue(permission));
                if (resource != null) {
                    //actionSet = metadata.createActionSet(target.getClass(),
                    // actionProperty.getValue(permission).toString());
                }
            } else {
                //actionSet = metadata.createActionSet(target.getClass(),
                //    actionProperty.getValue(permission).toString());
            }

            if (resource != null && (action == null || (actionSet != null && actionSet.contains(action)))) {
                // FIXME
                IdentityObject identity = null; //lookupPrincipal(principalCache, permission);

                if (action != null) {
                    permissions.add(new Permission(resource, action, identity));
                } else {
                    for (String a : actionSet.members()) {
                        permissions.add(new Permission(resource, a, identity));
                    }
                }
            }
        }

        return permissions;
    }

    public List<Permission> listPermissions(Object target) {
        return listPermissions(target, null);
    }

    public List<String> listAvailableActions(Object target) {
        return metadata.listAllowableActions(target.getClass());
    }

    private EntityManager lookupEntityManager() {
        return entityManagerInstance.get();
    }

    public Class<?> getIdentityPermissionClass() {
        return identityPermissionClass;
    }

    public void setIdentityPermissionClass(Class<?> identityPermissionClass) {
        this.identityPermissionClass = identityPermissionClass;
    }

    public void clearPermissions(Object resource) {
        EntityManager em = lookupEntityManager();
        String identifier = identifierPolicy.getIdentifier(resource);

        em.createQuery(
                "delete from " + identityPermissionClass.getName() + " p where p." +
                        resourceProperty.getName() + " = :resource")
                .setParameter("resource", identifier)
                .executeUpdate();
    }

    public boolean isEnabled() {
        return enabled;
    }
}
TOP

Related Classes of org.jboss.seam.security.permission.JpaPermissionStore$PropertyTypeCriteria

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.