org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy.java Source code

Java tutorial

Introduction

Here is the source code for org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy.java

Source

/*
 * Copyright 2002-2016 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.springframework.security.acls.domain;

import java.util.List;

import org.springframework.security.acls.model.AccessControlEntry;
import org.springframework.security.acls.model.Acl;
import org.springframework.security.acls.model.NotFoundException;
import org.springframework.security.acls.model.Permission;
import org.springframework.security.acls.model.PermissionGrantingStrategy;
import org.springframework.security.acls.model.Sid;
import org.springframework.util.Assert;

public class DefaultPermissionGrantingStrategy implements PermissionGrantingStrategy {

    private final transient AuditLogger auditLogger;

    /**
     * Creates an instance with the logger which will be used to record granting and
     * denial of requested permissions.
     */
    public DefaultPermissionGrantingStrategy(AuditLogger auditLogger) {
        Assert.notNull(auditLogger, "auditLogger cannot be null");
        this.auditLogger = auditLogger;
    }

    /**
     * Determines authorization. The order of the <code>permission</code> and
     * <code>sid</code> arguments is <em>extremely important</em>! The method will iterate
     * through each of the <code>permission</code>s in the order specified. For each
     * iteration, all of the <code>sid</code>s will be considered, again in the order they
     * are presented. A search will then be performed for the first
     * {@link AccessControlEntry} object that directly matches that
     * <code>permission:sid</code> combination. When the <em>first full match</em> is
     * found (ie an ACE that has the SID currently being searched for and the exact
     * permission bit mask being search for), the grant or deny flag for that ACE will
     * prevail. If the ACE specifies to grant access, the method will return
     * <code>true</code>. If the ACE specifies to deny access, the loop will stop and the
     * next <code>permission</code> iteration will be performed. If each permission
     * indicates to deny access, the first deny ACE found will be considered the reason
     * for the failure (as it was the first match found, and is therefore the one most
     * logically requiring changes - although not always). If absolutely no matching ACE
     * was found at all for any permission, the parent ACL will be tried (provided that
     * there is a parent and {@link Acl#isEntriesInheriting()} is <code>true</code>. The
     * parent ACL will also scan its parent and so on. If ultimately no matching ACE is
     * found, a <code>NotFoundException</code> will be thrown and the caller will need to
     * decide how to handle the permission check. Similarly, if any of the SID arguments
     * presented to the method were not loaded by the ACL,
     * <code>UnloadedSidException</code> will be thrown.
     *
     * @param permission the exact permissions to scan for (order is important)
     * @param sids the exact SIDs to scan for (order is important)
     * @param administrativeMode if <code>true</code> denotes the query is for
     * administrative purposes and no auditing will be undertaken
     *
     * @return <code>true</code> if one of the permissions has been granted,
     * <code>false</code> if one of the permissions has been specifically revoked
     *
     * @throws NotFoundException if an exact ACE for one of the permission bit masks and
     * SID combination could not be found
     */
    public boolean isGranted(Acl acl, List<Permission> permission, List<Sid> sids, boolean administrativeMode)
            throws NotFoundException {

        final List<AccessControlEntry> aces = acl.getEntries();

        AccessControlEntry firstRejection = null;

        for (Permission p : permission) {
            for (Sid sid : sids) {
                // Attempt to find exact match for this permission mask and SID
                boolean scanNextSid = true;

                for (AccessControlEntry ace : aces) {

                    if ((ace.getPermission().getMask() == p.getMask()) && ace.getSid().equals(sid)) {
                        // Found a matching ACE, so its authorization decision will
                        // prevail
                        if (ace.isGranting()) {
                            // Success
                            if (!administrativeMode) {
                                auditLogger.logIfNeeded(true, ace);
                            }

                            return true;
                        }

                        // Failure for this permission, so stop search
                        // We will see if they have a different permission
                        // (this permission is 100% rejected for this SID)
                        if (firstRejection == null) {
                            // Store first rejection for auditing reasons
                            firstRejection = ace;
                        }

                        scanNextSid = false; // helps break the loop

                        break; // exit aces loop
                    }
                }

                if (!scanNextSid) {
                    break; // exit SID for loop (now try next permission)
                }
            }
        }

        if (firstRejection != null) {
            // We found an ACE to reject the request at this point, as no
            // other ACEs were found that granted a different permission
            if (!administrativeMode) {
                auditLogger.logIfNeeded(false, firstRejection);
            }

            return false;
        }

        // No matches have been found so far
        if (acl.isEntriesInheriting() && (acl.getParentAcl() != null)) {
            // We have a parent, so let them try to find a matching ACE
            return acl.getParentAcl().isGranted(permission, sids, false);
        } else {
            // We either have no parent, or we're the uppermost parent
            throw new NotFoundException("Unable to locate a matching ACE for passed permissions and SIDs");
        }
    }

}