001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * For further information about Alkacon Software GmbH & Co. KG, please see the
018 * company website: http://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: http://www.opencms.org
022 *
023 * You should have received a copy of the GNU Lesser General Public
024 * License along with this library; if not, write to the Free Software
025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026 */
027
028package org.opencms.security;
029
030import org.opencms.file.CmsGroup;
031import org.opencms.file.CmsUser;
032import org.opencms.util.CmsUUID;
033
034import java.io.Serializable;
035import java.util.ArrayList;
036import java.util.Collections;
037import java.util.HashMap;
038import java.util.Iterator;
039import java.util.List;
040import java.util.Map;
041
042/**
043 * An access control list contains the permission sets of all principals for a distinct resource
044 * that are calculated on the permissions defined by various access control entries.<p>
045 *
046 * <p>To each single resource, access control entries of type <code>CmsAccessControlEntry</code> can be assigned.
047 * An access control entry defines the permissions (both allowed and explicitly denied) of a user or group for this resource.</p>
048 *
049 * <p>By calling the method <code>getAccessControlList</code> the list is generated on the resource. It contains the result of
050 * merging both access control entries defined immediately on the resource and inherited along the folder hierarchie in the
051 * OpenCms virtual file system (controlled by flags in the entry).</p>
052 *
053 * <p>To check the permissions of a user on a distinct resource, the method <code>hasPermissions</code> in the driver manager
054 * is called in each operation. This method acts as access guard and matches the required permissions for the operation
055 * against the allowed and denied permissions defined for the user or groups of this user.</p>
056 *
057 * @since 6.0.0
058 */
059public class CmsAccessControlList implements Serializable {
060
061    /** The serial version id. */
062    private static final long serialVersionUID = -8772251229957990081L;
063    /**
064     * Collected permissions of a principal on this resource .
065     */
066    private Map<CmsUUID, CmsPermissionSetCustom> m_permissions;
067
068    /**
069     * Constructor to create an empty access control list for a given resource.<p>
070     *
071     */
072    public CmsAccessControlList() {
073
074        m_permissions = new HashMap<CmsUUID, CmsPermissionSetCustom>();
075    }
076
077    /**
078     * Adds an access control entry to the access control list.<p>
079     *
080     * @param entry the access control entry to add
081     */
082    public void add(CmsAccessControlEntry entry) {
083
084        CmsPermissionSetCustom p = m_permissions.get(entry.getPrincipal());
085        if (p == null) {
086            p = new CmsPermissionSetCustom();
087            m_permissions.put(entry.getPrincipal(), p);
088        }
089        p.addPermissions(entry.getPermissions());
090    }
091
092    /**
093     * Returns a clone of this Objects instance.<p>
094     *
095     * @return a clone of this instance
096     */
097    @Override
098    public Object clone() {
099
100        CmsAccessControlList acl = new CmsAccessControlList();
101        Iterator<CmsUUID> i = m_permissions.keySet().iterator();
102        while (i.hasNext()) {
103            CmsUUID id = i.next();
104            acl.m_permissions.put(id, (CmsPermissionSetCustom)(m_permissions.get(id)).clone());
105        }
106        return acl;
107    }
108
109    /**
110     * Returns the permission map of this access control list.<p>
111     *
112     * @return permission map
113     */
114    public Map<CmsUUID, CmsPermissionSetCustom> getPermissionMap() {
115
116        return m_permissions;
117    }
118
119    /**
120     * Calculates the permissions of the given user and his groups from the access control list.<p>
121     *
122     * @param user the user
123     * @param groups the groups of this user
124     * @param roles the roles of this user
125     *
126     * @return the summarized permission set of the user
127     */
128    public CmsPermissionSetCustom getPermissions(CmsUser user, List<CmsGroup> groups, List<CmsRole> roles) {
129
130        CmsPermissionSetCustom sum = new CmsPermissionSetCustom();
131        boolean hasPermissions = false;
132        CmsPermissionSet p = m_permissions.get(user.getId());
133        if (p != null) {
134            sum.addPermissions(p);
135            hasPermissions = true;
136        }
137        if (groups != null) {
138            int size = groups.size();
139            for (int i = 0; i < size; i++) {
140                I_CmsPrincipal principal = groups.get(i);
141                p = m_permissions.get(principal.getId());
142                if (p != null) {
143                    sum.addPermissions(p);
144                    hasPermissions = true;
145                }
146            }
147        }
148        if (roles != null) {
149            int size = roles.size();
150            for (int i = 0; i < size; i++) {
151                CmsRole role = roles.get(i);
152                p = m_permissions.get(role.getId());
153                if (p != null) {
154                    sum.addPermissions(p);
155                    hasPermissions = true;
156                }
157            }
158        }
159        if (!hasPermissions) {
160            // if no applicable entry is found check the 'all others' entry
161            p = m_permissions.get(CmsAccessControlEntry.PRINCIPAL_ALL_OTHERS_ID);
162            if (p != null) {
163                sum.addPermissions(p);
164            }
165        }
166        return sum;
167    }
168
169    /**
170     * Returns the permission set of a principal as stored in the access control list.<p>
171     *
172     * @param principalId the id of the principal (group or user)
173     *
174     * @return the current permissions of this single principal
175     */
176    public CmsPermissionSetCustom getPermissions(CmsUUID principalId) {
177
178        return m_permissions.get(principalId);
179    }
180
181    /**
182     * Calculates the permissions of the given user and his groups from the access control list.<p>
183     * The permissions are returned as permission string in the format {{+|-}{r|w|v|c|i}}*.
184     *
185     * @param user the user
186     * @param groups the groups of this user
187     * @param roles the roles of this user
188     *
189     * @return a string that displays the permissions
190     */
191    public String getPermissionString(CmsUser user, List<CmsGroup> groups, List<CmsRole> roles) {
192
193        return getPermissions(user, groups, roles).getPermissionString();
194    }
195
196    /**
197     * Returns the principals with specific permissions stored in this access control list.<p>
198     *
199     * @return enumeration of principals (each group or user)
200     */
201    public List<CmsUUID> getPrincipals() {
202
203        List<CmsUUID> principals = new ArrayList<CmsUUID>(m_permissions.keySet());
204        Collections.sort(principals, CmsAccessControlEntry.COMPARATOR_PRINCIPALS);
205        return principals;
206    }
207
208    /**
209     * Sets the allowed permissions of a given access control entry as allowed permissions in the access control list.<p>
210     * The denied permissions are left unchanged.
211     *
212     * @param entry the access control entry
213     */
214    public void setAllowedPermissions(CmsAccessControlEntry entry) {
215
216        CmsPermissionSetCustom p = m_permissions.get(entry.getPrincipal());
217        if (p == null) {
218            p = new CmsPermissionSetCustom();
219            m_permissions.put(entry.getPrincipal(), p);
220        }
221        p.setPermissions(entry.getAllowedPermissions(), p.getDeniedPermissions());
222    }
223
224    /**
225     * Sets the denied permissions of a given access control entry as denied permissions in the access control list.<p>
226     * The allowed permissions are left unchanged.
227     *
228     * @param entry the access control entry
229     */
230    public void setDeniedPermissions(CmsAccessControlEntry entry) {
231
232        CmsPermissionSetCustom p = m_permissions.get(entry.getPrincipal());
233        if (p == null) {
234            p = new CmsPermissionSetCustom();
235            m_permissions.put(entry.getPrincipal(), p);
236        }
237        p.setPermissions(p.getAllowedPermissions(), entry.getDeniedPermissions());
238    }
239}