ome.security.basic.BasicACLVoter.java Source code

Java tutorial

Introduction

Here is the source code for ome.security.basic.BasicACLVoter.java

Source

/*
 * ome.security.BasicACLVoter
 *
 *   Copyright 2006 University of Dundee. All rights reserved.
 *   Use is subject to license terms supplied in LICENSE.txt
 */

package ome.security.basic;

// Java imports

// Third-party libraries
import static ome.model.internal.Permissions.Right.WRITE;
import static ome.model.internal.Permissions.Role.GROUP;
import static ome.model.internal.Permissions.Role.USER;
import static ome.model.internal.Permissions.Role.WORLD;
import ome.annotations.RevisionDate;
import ome.annotations.RevisionNumber;
import ome.conditions.GroupSecurityViolation;
import ome.conditions.InternalException;
import ome.conditions.SecurityViolation;
import ome.model.IObject;
import ome.model.internal.Details;
import ome.model.internal.Permissions;
import ome.model.internal.Token;
import ome.model.internal.Permissions.Right;
import ome.model.internal.Permissions.Role;
import ome.security.ACLVoter;
import ome.security.SecuritySystem;
import ome.security.SystemTypes;
import ome.tools.hibernate.SecurityFilter;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.Assert;

/**
 * 
 * @author Josh Moore, josh.moore at gmx.de
 * @version $Revision$, $Date$
 * @see Token
 * @see SecuritySystem
 * @see Details
 * @see Permissions
 * @since 3.0-M3
 */
@RevisionDate("$Date$")
@RevisionNumber("$Revision$")
public class BasicACLVoter implements ACLVoter {

    private final static Log log = LogFactory.getLog(BasicACLVoter.class);

    protected final CurrentDetails currentUser;

    protected final SystemTypes sysTypes;

    protected final TokenHolder tokenHolder;

    protected final SecurityFilter securityFilter;

    public BasicACLVoter(CurrentDetails cd, SystemTypes sysTypes, TokenHolder tokenHolder,
            SecurityFilter securityFilter) {
        this.currentUser = cd;
        this.sysTypes = sysTypes;
        this.securityFilter = securityFilter;
        this.tokenHolder = tokenHolder;
    }

    // ~ Interface methods
    // =========================================================================

    /**
     * 
     */
    public boolean allowChmod(IObject iObject) {
        return currentUser.isOwnerOrSupervisor(iObject);
    }

    /**
     * delegates to SecurityFilter because that is where the logic is defined
     * for the {@link #enableReadFilter(Object) read filter}
     * 
     * Ignores the id for the moment.
     * 
     * Though we pass in whether or not a share is active for completeness, a
     * different {@link ACLVoter} implementation will almost certainly be active
     * for share use.
     */
    public boolean allowLoad(Class<? extends IObject> klass, Details d, long id) {
        Assert.notNull(klass);

        if (d == null || sysTypes.isSystemType(klass) || sysTypes.isInSystemGroup(d) || sysTypes.isInUserGroup(d)) {
            return true;
        }

        final BasicEventContext c = currentUser.current();
        final boolean nonPrivate = c.getCurrentGroupPermissions().isGranted(Role.GROUP, Right.READ)
                || c.getCurrentGroupPermissions().isGranted(Role.WORLD, Right.READ);
        final boolean isShare = c.getCurrentShareId() != null;
        final boolean adminOrPi = c.isCurrentUserAdmin()
                || c.getLeaderOfGroupsList().contains(c.getCurrentGroupId());
        return securityFilter.passesFilter(d, c.getGroup().getId(), c.getOwner().getId(), nonPrivate, adminOrPi,
                isShare);
    }

    public void throwLoadViolation(IObject iObject) throws SecurityViolation {
        Assert.notNull(iObject);
        throw new SecurityViolation("Cannot read " + iObject);
    }

    public boolean allowCreation(IObject iObject) {
        Assert.notNull(iObject);
        Class<?> cls = iObject.getClass();

        boolean sysType = sysTypes.isSystemType(cls) || sysTypes.isInSystemGroup(iObject.getDetails());

        if (!sysType && currentUser.isGraphCritical()) { // ticket:1769
            Long uid = currentUser.getOwner().getId();
            return objectBelongsToUser(iObject, uid);
        }

        else if (tokenHolder.hasPrivilegedToken(iObject)
                || currentUser.getCurrentEventContext().isCurrentUserAdmin()) {
            return true;
        }

        else if (sysType) {
            return false;
        }

        return true;
    }

    public void throwCreationViolation(IObject iObject) throws SecurityViolation {
        Assert.notNull(iObject);

        boolean sysType = sysTypes.isSystemType(iObject.getClass())
                || sysTypes.isInSystemGroup(iObject.getDetails());

        if (!sysType && currentUser.isGraphCritical()) { // ticket:1769
            throw new GroupSecurityViolation(iObject + "-insertion violates " + "group-security.");
        }

        throw new SecurityViolation(
                iObject + " is a System-type, and may only be " + "created through privileged APIs.");
    }

    public boolean allowUpdate(IObject iObject, Details trustedDetails) {
        return allowUpdateOrDelete(iObject, trustedDetails, true);
    }

    public void throwUpdateViolation(IObject iObject) throws SecurityViolation {
        Assert.notNull(iObject);

        boolean sysType = sysTypes.isSystemType(iObject.getClass())
                || sysTypes.isInSystemGroup(iObject.getDetails());

        if (!sysType && currentUser.isGraphCritical()) { // ticket:1769
            throw new GroupSecurityViolation(iObject + "-modification violates " + "group-security.");
        }

        throw new SecurityViolation("Updating " + iObject + " not allowed.");
    }

    public boolean allowDelete(IObject iObject, Details trustedDetails) {
        return allowUpdateOrDelete(iObject, trustedDetails, false);
    }

    public void throwDeleteViolation(IObject iObject) throws SecurityViolation {
        Assert.notNull(iObject);
        throw new SecurityViolation("Deleting " + iObject + " not allowed.");
    }

    private boolean allowUpdateOrDelete(IObject iObject, Details trustedDetails, boolean update) {
        Assert.notNull(iObject);

        BasicEventContext c = currentUser.current();
        Long uid = c.getCurrentUserId();

        boolean sysType = sysTypes.isSystemType(iObject.getClass())
                || sysTypes.isInSystemGroup(iObject.getDetails());
        boolean sysTypeOrUsrGroup = sysType || sysTypes.isInUserGroup(iObject.getDetails());

        // needs no details info
        if (tokenHolder.hasPrivilegedToken(iObject)) {
            return true; // ticket:1794, allow move to "user
        } else if (update && !sysTypeOrUsrGroup && currentUser.isGraphCritical()) { //ticket:1769
            return objectBelongsToUser(iObject, uid);
        } else if (c.isCurrentUserAdmin()) {
            return true;
        } else if (sysType) {
            return false;
        }

        // previously we were taking the details directly from iObject
        // iObject, however, is in a critical state. Values such as
        // Permissions, owner, and group may have been changed.
        Details d = trustedDetails;

        // this can now only happen if a table doesn't have permissions
        // and there aren't any of those. so let it be updated.
        if (d == null) {
            return true;
        }

        // the owner and group information might be null if the type
        // is intended to be a system-type but isn't marked as one
        // via SecuritySystem.isSystemType(). A NPE here might imply
        // that that information is out of sync.
        Long o = d.getOwner() == null ? null : d.getOwner().getId();
        Long g = d.getGroup() == null ? null : d.getGroup().getId();

        // needs no permissions info
        if (g != null && c.getLeaderOfGroupsList().contains(g)) {
            return true;
        }

        Permissions p = d.getPermissions();

        // this should never occur.
        if (p == null) {
            throw new InternalException("Permissions null! Security system "
                    + "failure -- refusing to continue. The Permissions should " + "be set to a default value.");
        }

        // standard
        if (p.isGranted(WORLD, WRITE)) {
            return true;
        }
        if (p.isGranted(USER, WRITE) && o != null && o.equals(c.getOwner().getId())) {
            return true;
        }
        /* ticket:1992 - removing concept of GROUP-WRITE
        if (p.isGranted(GROUP, WRITE) && g != null
            && c.getMemberOfGroupsList().contains(g)) {
        return true;
        }
        */

        return false;
    }

    /**
     * @param iObject
     * @param uid
     * @return
     * @DEV.TODO this is less problematic than linking.
     */
    private boolean objectBelongsToUser(IObject iObject, Long uid) {
        Long oid = iObject.getDetails().getOwner().getId();
        return uid.equals(oid); // Only allow own objects!
    }

    private Long group(Details d) {
        if (d == null || d.getGroup() == null) {
            return null;
        }
        return d.getGroup().getId();
    }

}