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     */
019    package org.apache.wiki.auth.acl;
020    
021    import java.io.Serializable;
022    import java.security.Permission;
023    import java.security.Principal;
024    import java.util.Enumeration;
025    import java.util.Vector;
026    
027    /**
028     *  JSPWiki implementation of an Access Control List.
029     *
030     *  @since 2.3
031     */
032    public 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            StringBuffer sb = new StringBuffer();
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