001/* 
002    Licensed to the Apache Software Foundation (ASF) under one
003    or more contributor license agreements.  See the NOTICE file
004    distributed with this work for additional information
005    regarding copyright ownership.  The ASF licenses this file
006    to you under the Apache License, Version 2.0 (the
007    "License"); you may not use this file except in compliance
008    with the License.  You may obtain a copy of the License at
009
010       http://www.apache.org/licenses/LICENSE-2.0
011
012    Unless required by applicable law or agreed to in writing,
013    software distributed under the License is distributed on an
014    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015    KIND, either express or implied.  See the License for the
016    specific language governing permissions and limitations
017    under the License.  
018 */
019package org.apache.wiki.auth.acl;
020
021import java.io.Serializable;
022import java.security.Permission;
023import java.security.Principal;
024import java.util.Enumeration;
025import java.util.Vector;
026
027/**
028 *  JSPWiki implementation of an Access Control List.
029 *
030 *  @since 2.3
031 */
032public class AclImpl implements Acl, Serializable
033{
034    private static final long serialVersionUID = 1L;
035    private final Vector<AclEntry> m_entries = new Vector<AclEntry>();
036
037    /**
038     * Constructs a new AclImpl instance.
039     */
040    public AclImpl()
041    {
042    }
043    
044    /**
045     * Returns all Principal objects assigned a given Permission in the access
046     * control list. The Principals returned are those that have been granted
047     * either the supplied permission, or a permission implied by the supplied
048     * permission. Principals are not "expanded" if they are a role or group.
049     * @param permission the permission to search for
050     * @return an array of Principals possessing the permission
051     */
052    public Principal[] findPrincipals( Permission permission )
053    {
054        Vector<Principal> principals = new Vector<Principal>();
055        Enumeration<AclEntry> entries = entries();
056        
057        while (entries.hasMoreElements()) 
058        {
059            AclEntry entry = entries.nextElement();
060            Enumeration<Permission> permissions = entry.permissions();
061            while ( permissions.hasMoreElements() ) 
062            {
063                Permission perm = permissions.nextElement();
064                if ( perm.implies( permission ) ) 
065                {
066                    principals.add( entry.getPrincipal() );
067                }
068            }
069        }
070        return principals.toArray( new Principal[principals.size()] );
071    }
072  
073    private boolean hasEntry( AclEntry entry )
074    {
075        if( entry == null )
076        {
077            return false;
078        }
079
080        for( AclEntry e : m_entries )
081        {
082            Principal ep     = e.getPrincipal();
083            Principal entryp = entry.getPrincipal();
084
085            if( ep == null || entryp == null )
086            {
087                throw new IllegalArgumentException( "Entry is null; check code, please (entry="+entry+"; e="+e+")" );
088            }
089            
090            if( ep.getName().equals( entryp.getName() ) )
091            {
092                return true;
093            }
094        }
095
096        return false;
097    }
098
099    /**
100     * Adds an ACL entry to this ACL. An entry associates a principal (e.g., an
101     * individual or a group) with a set of permissions. Each principal can have
102     * at most one positive ACL entry, specifying permissions to be granted to
103     * the principal. If there is already an ACL entry already in the ACL, false
104     * is returned.
105     * @param entry - the ACL entry to be added to this ACL
106     * @return true on success, false if an entry of the same type (positive or
107     *         negative) for the same principal is already present in this ACL
108     */
109    public synchronized boolean addEntry( AclEntry entry )
110    {
111        if( entry.getPrincipal() == null )
112        {
113            throw new IllegalArgumentException( "Entry principal cannot be null" );
114        }
115
116        if( hasEntry( entry ) )
117        {
118            return false;
119        }
120        
121        m_entries.add( entry );
122
123        return true;
124    }
125
126    /**
127     * Removes an ACL entry from this ACL.
128     * @param entry the ACL entry to be removed from this ACL
129     * @return true on success, false if the entry is not part of this ACL
130     */
131    public synchronized boolean removeEntry( AclEntry entry )
132    {
133        return m_entries.remove( entry );
134    }
135
136    /**
137     * Returns an enumeration of the entries in this ACL. Each element in the
138     * enumeration is of type AclEntry.
139     * @return an enumeration of the entries in this ACL.
140     */
141    public Enumeration< AclEntry > entries()
142    {
143        return m_entries.elements();
144    }
145
146    /**
147     * Returns an AclEntry for a supplied Principal, or <code>null</code> if
148     * the Principal does not have a matching AclEntry.
149     * @param principal the principal to search for
150     * @return the AclEntry associated with the principal, or <code>null</code>
151     */
152    public AclEntry getEntry( Principal principal )
153    {
154        for( AclEntry entry : m_entries )
155        {
156            if( entry.getPrincipal().getName().equals( principal.getName() ) )
157            {
158                return entry;
159            }
160        }
161
162        return null;
163    }
164
165    /**
166     * Returns a string representation of the contents of this Acl.
167     * @return the string representation
168     */
169    public String toString()
170    {
171        StringBuilder sb = new StringBuilder();
172
173        for( AclEntry entry : m_entries )
174        {
175            Principal pal = entry.getPrincipal();
176
177            if( pal != null )
178                sb.append( "  user = "+pal.getName()+": " );
179            else
180                sb.append( "  user = null: " );
181
182            sb.append( "(" );
183            for( Enumeration<Permission> perms = entry.permissions(); perms.hasMoreElements(); )
184            {
185                Permission perm = perms.nextElement();
186                sb.append( perm.toString() );
187            }
188            sb.append( ")\n" );
189        }
190
191        return sb.toString();
192    }
193
194    /**
195     * Returns <code>true</code>, if this Acl is empty.
196     * @return the result
197     * @since 2.4.68
198     */
199    public boolean isEmpty()
200    {
201        return m_entries.isEmpty();
202    }
203
204}
205