/*
 * Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
 *
 * 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
 *
 *      http://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.model;

import java.io.Serializable;
import java.util.List;

/**
 * Represents an access control list (ACL) for a domain object.
 *
 * <p>
 * An <tt>Acl</tt> represents all ACL entries for a given domain object. In order to avoid
 * needing references to the domain object itself, this interface handles indirection
 * between a domain object and an ACL object identity via the
 * {@link org.springframework.security.acls.model.ObjectIdentity} interface.
 * </p>
 *
 * <p>
 * Implementing classes may elect to return instances that represent
 * {@link org.springframework.security.acls.model.Permission} information for either some
 * OR all {@link org.springframework.security.acls.model.Sid} instances. Therefore, an
 * instance may NOT necessarily contain ALL <tt>Sid</tt>s for a given domain object.
 * </p>
 *
 * @author Ben Alex
 */
public interface Acl extends Serializable {

	/**
	 * Returns all of the entries represented by the present <tt>Acl</tt>. Entries
	 * associated with the <tt>Acl</tt> parents are not returned.
	 *
	 * <p>
	 * This method is typically used for administrative purposes.
	 * </p>
	 *
	 * <p>
	 * The order that entries appear in the array is important for methods declared in the
	 * {@link MutableAcl} interface. Furthermore, some implementations MAY use ordering as
	 * part of advanced permission checking.
	 * </p>
	 *
	 * <p>
	 * Do <em>NOT</em> use this method for making authorization decisions. Instead use
	 * {@link #isGranted(List, List, boolean)}.
	 * </p>
	 *
	 * <p>
	 * This method must operate correctly even if the <tt>Acl</tt> only represents a
	 * subset of <tt>Sid</tt>s. The caller is responsible for correctly handling the
	 * result if only a subset of <tt>Sid</tt>s is represented.
	 * </p>
	 *
	 * @return the list of entries represented by the <tt>Acl</tt>, or <tt>null</tt> if
	 * there are no entries presently associated with this <tt>Acl</tt>.
	 */
	List<AccessControlEntry> getEntries();

	/**
	 * Obtains the domain object this <tt>Acl</tt> provides entries for. This is immutable
	 * once an <tt>Acl</tt> is created.
	 *
	 * @return the object identity (never <tt>null</tt>)
	 */
	ObjectIdentity getObjectIdentity();

	/**
	 * Determines the owner of the <tt>Acl</tt>. The meaning of ownership varies by
	 * implementation and is unspecified.
	 *
	 * @return the owner (may be <tt>null</tt> if the implementation does not use
	 * ownership concepts)
	 */
	Sid getOwner();

	/**
	 * A domain object may have a parent for the purpose of ACL inheritance. If there is a
	 * parent, its ACL can be accessed via this method. In turn, the parent's parent
	 * (grandparent) can be accessed and so on.
	 *
	 * <p>
	 * This method solely represents the presence of a navigation hierarchy between the
	 * parent <tt>Acl</tt> and this <tt>Acl</tt>. For actual inheritance to take place,
	 * the {@link #isEntriesInheriting()} must also be <tt>true</tt>.
	 * </p>
	 *
	 * <p>
	 * This method must operate correctly even if the <tt>Acl</tt> only represents a
	 * subset of <tt>Sid</tt>s. The caller is responsible for correctly handling the
	 * result if only a subset of <tt>Sid</tt>s is represented.
	 * </p>
	 *
	 * @return the parent <tt>Acl</tt> (may be <tt>null</tt> if this <tt>Acl</tt> does not
	 * have a parent)
	 */
	Acl getParentAcl();

	/**
	 * Indicates whether the ACL entries from the {@link #getParentAcl()} should flow down
	 * into the current <tt>Acl</tt>.
	 * <p>
	 * The mere link between an <tt>Acl</tt> and a parent <tt>Acl</tt> on its own is
	 * insufficient to cause ACL entries to inherit down. This is because a domain object
	 * may wish to have entirely independent entries, but maintain the link with the
	 * parent for navigation purposes. Thus, this method denotes whether or not the
	 * navigation relationship also extends to the actual inheritance of entries.
	 * </p>
	 *
	 * @return <tt>true</tt> if parent ACL entries inherit into the current <tt>Acl</tt>
	 */
	boolean isEntriesInheriting();

	/**
	 * This is the actual authorization logic method, and must be used whenever ACL
	 * authorization decisions are required.
	 *
	 * <p>
	 * An array of <tt>Sid</tt>s are presented, representing security identifies of the
	 * current principal. In addition, an array of <tt>Permission</tt>s is presented which
	 * will have one or more bits set in order to indicate the permissions needed for an
	 * affirmative authorization decision. An array is presented because holding
	 * <em>any</em> of the <tt>Permission</tt>s inside the array will be sufficient for an
	 * affirmative authorization.
	 * </p>
	 *
	 * <p>
	 * The actual approach used to make authorization decisions is left to the
	 * implementation and is not specified by this interface. For example, an
	 * implementation <em>MAY</em> search the current ACL in the order the ACL entries
	 * have been stored. If a single entry is found that has the same active bits as are
	 * shown in a passed <tt>Permission</tt>, that entry's grant or deny state may
	 * determine the authorization decision. If the case of a deny state, the deny
	 * decision will only be relevant if all other <tt>Permission</tt>s passed in the
	 * array have also been unsuccessfully searched. If no entry is found that match the
	 * bits in the current ACL, provided that {@link #isEntriesInheriting()} is
	 * <tt>true</tt>, the authorization decision may be passed to the parent ACL. If there
	 * is no matching entry, the implementation MAY throw an exception, or make a
	 * predefined authorization decision.
	 * </p>
	 *
	 * <p>
	 * This method must operate correctly even if the <tt>Acl</tt> only represents a
	 * subset of <tt>Sid</tt>s, although the implementation is permitted to throw one of
	 * the signature-defined exceptions if the method is called requesting an
	 * authorization decision for a {@link Sid} that was never loaded in this <tt>Acl</tt>
	 * .
	 * </p>
	 *
	 * @param permission the permission or permissions required (at least one entry
	 * required)
	 * @param sids the security identities held by the principal (at least one entry
	 * required)
	 * @param administrativeMode if <tt>true</tt> denotes the query is for administrative
	 * purposes and no logging or auditing (if supported by the implementation) should be
	 * undertaken
	 *
	 * @return <tt>true</tt> if authorization is granted
	 *
	 * @throws NotFoundException MUST be thrown if an implementation cannot make an
	 * authoritative authorization decision, usually because there is no ACL information
	 * for this particular permission and/or SID
	 * @throws UnloadedSidException thrown if the <tt>Acl</tt> does not have details for
	 * one or more of the <tt>Sid</tt>s passed as arguments
	 */
	boolean isGranted(List<Permission> permission, List<Sid> sids,
			boolean administrativeMode) throws NotFoundException, UnloadedSidException;

	/**
	 * For efficiency reasons an <tt>Acl</tt> may be loaded and <em>not</em> contain
	 * entries for every <tt>Sid</tt> in the system. If an <tt>Acl</tt> has been loaded
	 * and does not represent every <tt>Sid</tt>, all methods of the <tt>Acl</tt> can only
	 * be used within the limited scope of the <tt>Sid</tt> instances it actually
	 * represents.
	 * <p>
	 * It is normal to load an <tt>Acl</tt> for only particular <tt>Sid</tt>s if read-only
	 * authorization decisions are being made. However, if user interface reporting or
	 * modification of <tt>Acl</tt>s are desired, an <tt>Acl</tt> should be loaded with
	 * all <tt>Sid</tt>s. This method denotes whether or not the specified <tt>Sid</tt>s
	 * have been loaded or not.
	 * </p>
	 *
	 * @param sids one or more security identities the caller is interest in knowing
	 * whether this <tt>Sid</tt> supports
	 *
	 * @return <tt>true</tt> if every passed <tt>Sid</tt> is represented by this
	 * <tt>Acl</tt> instance
	 */
	boolean isSidLoaded(List<Sid> sids);
}
