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, 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.ui.dialogs.permissions;
029
030import org.opencms.file.CmsObject;
031import org.opencms.file.history.CmsHistoryPrincipal;
032import org.opencms.main.CmsException;
033import org.opencms.main.CmsLog;
034import org.opencms.security.CmsAccessControlEntry;
035import org.opencms.security.CmsPermissionSet;
036import org.opencms.security.CmsPrincipal;
037import org.opencms.security.CmsRole;
038import org.opencms.security.I_CmsPrincipal;
039import org.opencms.ui.A_CmsUI;
040import org.opencms.ui.CmsVaadinUtils;
041import org.opencms.workplace.commons.Messages;
042
043import java.util.Arrays;
044
045import org.apache.commons.logging.Log;
046
047import com.vaadin.ui.Component;
048import com.vaadin.ui.CssLayout;
049import com.vaadin.v7.data.Container;
050import com.vaadin.v7.data.Item;
051import com.vaadin.v7.data.Property.ValueChangeEvent;
052import com.vaadin.v7.data.Property.ValueChangeListener;
053import com.vaadin.v7.data.util.IndexedContainer;
054import com.vaadin.v7.shared.ui.label.ContentMode;
055import com.vaadin.v7.ui.CheckBox;
056import com.vaadin.v7.ui.DefaultFieldFactory;
057import com.vaadin.v7.ui.Field;
058import com.vaadin.v7.ui.Label;
059import com.vaadin.v7.ui.Table;
060import com.vaadin.v7.ui.TableFieldFactory;
061import com.vaadin.v7.ui.VerticalLayout;
062
063/**
064 * Displays the permission settings for a single principal.<p>
065 */
066public class CmsPermissionView extends CssLayout {
067
068    /**
069     * Permission change handler.<p>
070     */
071    public interface PermissionChangeHandler {
072
073        /**
074         * Called to delete a permission set.<p>
075         *
076         * @param principalType the principal type
077         * @param principalName the principal name
078         */
079        void deletePermissionSet(String principalType, String principalName);
080
081        /**
082         * Called on view changes, allowing for resizing or centering.<p>
083         */
084        void onViewChange();
085
086        /**
087         * Sets a changed permission set.<p>
088         *
089         * @param permissionBean bean for permission
090         */
091        void setPermissions(CmsPermissionBean permissionBean);
092    }
093
094    /** The logger instance for this class. */
095    private static final Log LOG = CmsLog.getLog(CmsPermissionView.class);
096
097    /** The allowed table property id. */
098    private static final String PROPERTY_ALLOWED = "allowed";
099
100    /** The denied table property id. */
101    private static final String PROPERTY_DENIED = "denied";
102
103    /** The display allowed table property id. */
104    private static final String PROPERTY_DISPLAY_ALLOWED = "display_allowed";
105
106    /** The display denied table property id. */
107    private static final String PROPERTY_DISPLAY_DENIED = "display_denied";
108
109    /** The label table property id. */
110    private static final String PROPERTY_LABEL = "label";
111
112    /** The value table property id. */
113    private static final String PROPERTY_VALUE = "value";
114
115    /** The serial version id. */
116    private static final long serialVersionUID = 3440901877277200393L;
117
118    /** Constant for unknown type. */
119    private static final String UNKNOWN_TYPE = "Unknown";
120
121    /** The value change listener for all fields of this view. */
122    final ValueChangeListener m_valueChangeListener = new ValueChangeListener() {
123
124        private static final long serialVersionUID = 3923093753370151014L;
125
126        public void valueChange(ValueChangeEvent event) {
127
128            setPermissions();
129
130        }
131    };
132
133    /** The button bar. */
134    private VerticalLayout m_buttonBar;
135
136    /** The permission change handler. */
137    private PermissionChangeHandler m_changeHandler;
138
139    /** The editable flag. */
140    private boolean m_editable;
141
142    /** The access control entry to display. */
143    private CmsAccessControlEntry m_entry;
144
145    /** The table field factory. */
146    private final TableFieldFactory m_fieldFactory = new DefaultFieldFactory() {
147
148        private static final long serialVersionUID = 1L;
149
150        /**
151         * @see com.vaadin.ui.DefaultFieldFactory#createField(com.vaadin.v7.data.Container, java.lang.Object, java.lang.Object, com.vaadin.ui.Component)
152         */
153        @Override
154        public Field<?> createField(Container container, Object itemId, Object propertyId, Component uiContext) {
155
156            Field<?> result = null;
157            if (PROPERTY_ALLOWED.equals(propertyId) || PROPERTY_DENIED.equals(propertyId)) {
158                result = super.createField(container, itemId, propertyId, uiContext);
159                result.addValueChangeListener(m_valueChangeListener);
160                result.setCaption("");
161            }
162            return result;
163        }
164    };
165
166    /** The inherit check box. */
167    private CheckBox m_inheritCheckbox;
168
169    /** The overwrite check box. */
170    private CheckBox m_overwriteCheckbox;
171
172    /** The permissions table. */
173    private Table m_permissions;
174
175    /** The principal name. */
176    private String m_principalName;
177
178    /** The principal type. */
179    private String m_principalType;
180
181    /** The responsible check box. */
182    private CheckBox m_responsibleCheckbox;
183
184    /**
185     * Constructor.<p>
186     *
187     * @param entry the access control entry
188     * @param editable the editable flag
189     * @param isFolder the is folder flag
190     * @param inheritedFrom the inherited from path
191     * @param changeHandler the change handler
192     */
193    public CmsPermissionView(
194        CmsAccessControlEntry entry,
195        boolean editable,
196        boolean isFolder,
197        String inheritedFrom,
198        PermissionChangeHandler changeHandler) {
199
200        m_changeHandler = changeHandler;
201        m_editable = editable;
202        m_entry = entry;
203        CmsVaadinUtils.readAndLocalizeDesign(this, CmsVaadinUtils.getWpMessagesForCurrentLocale(), null);
204        CmsObject cms = A_CmsUI.getCmsObject();
205        m_responsibleCheckbox.addValueChangeListener(m_valueChangeListener);
206        m_overwriteCheckbox.addValueChangeListener(m_valueChangeListener);
207        m_inheritCheckbox.addValueChangeListener(m_valueChangeListener);
208
209        // get name and type of the current entry
210        I_CmsPrincipal principal;
211        try {
212            principal = CmsPrincipal.readPrincipalIncludingHistory(cms, entry.getPrincipal());
213        } catch (CmsException e) {
214            principal = null;
215            LOG.debug(e.getLocalizedMessage(), e);
216        }
217        m_principalName = (principal != null) ? principal.getName() : entry.getPrincipal().toString();
218
219        int flags = 0;
220        if ((principal != null) && (principal instanceof CmsHistoryPrincipal)) {
221            // there is a history principal entry, handle it
222            if (principal.isGroup()) {
223                flags = CmsAccessControlEntry.ACCESS_FLAGS_GROUP;
224            } else {
225                flags = CmsAccessControlEntry.ACCESS_FLAGS_USER;
226            }
227        } else if ((principal != null) && principal.isGroup()) {
228            flags = CmsAccessControlEntry.ACCESS_FLAGS_GROUP;
229        } else if ((principal != null) && principal.isUser()) {
230            flags = CmsAccessControlEntry.ACCESS_FLAGS_USER;
231        } else if ((m_principalName != null)
232            && m_principalName.equals(CmsAccessControlEntry.PRINCIPAL_ALL_OTHERS_ID.toString())) {
233            m_principalName = CmsAccessControlEntry.PRINCIPAL_ALL_OTHERS_NAME;
234            m_responsibleCheckbox.setVisible(false);
235            flags = CmsAccessControlEntry.ACCESS_FLAGS_ALLOTHERS;
236        } else if ((m_principalName != null)
237            && m_principalName.equals(CmsAccessControlEntry.PRINCIPAL_OVERWRITE_ALL_ID.toString())) {
238            m_principalName = CmsAccessControlEntry.PRINCIPAL_OVERWRITE_ALL_NAME;
239            flags = CmsAccessControlEntry.ACCESS_FLAGS_OVERWRITE_ALL;
240        } else {
241            // check if it is the case of a role
242            CmsRole role = CmsRole.valueOfId(entry.getPrincipal());
243            if (role != null) {
244                m_principalName = role.getRoleName();
245                flags = CmsAccessControlEntry.ACCESS_FLAGS_ROLE;
246            }
247        }
248
249        if ((flags > 0) && ((entry.getFlags() & flags) == 0)) {
250            // the flag is set to the wrong principal type
251            if (LOG.isErrorEnabled()) {
252                LOG.error(
253                    Messages.get().getBundle(A_CmsUI.get().getLocale()).key(
254                        Messages.ERR_INVALID_ACE_1,
255                        entry.toString()));
256            }
257            entry = new CmsAccessControlEntry(
258                entry.getResource(),
259                entry.getPrincipal(),
260                entry.getAllowedPermissions(),
261                entry.getDeniedPermissions(),
262                (entry.getFlags() | flags));
263        } else if (entry.getFlags() < CmsAccessControlEntry.ACCESS_FLAGS_USER) {
264            // the flag is set to NO principal type
265            if (LOG.isErrorEnabled()) {
266                LOG.error(
267                    Messages.get().getBundle(A_CmsUI.get().getLocale()).key(
268                        Messages.ERR_INVALID_ACE_1,
269                        entry.toString()));
270            }
271            entry = new CmsAccessControlEntry(
272                entry.getResource(),
273                entry.getPrincipal(),
274                entry.getAllowedPermissions(),
275                entry.getDeniedPermissions(),
276                (entry.getFlags() | CmsAccessControlEntry.ACCESS_FLAGS_GROUP));
277        }
278
279        m_principalType = getEntryType(entry.getFlags(), false);
280
281        if (m_principalName == null) {
282            m_principalName = "";
283        }
284
285        boolean isOverwriteAll = false;
286        if (flags == CmsAccessControlEntry.ACCESS_FLAGS_OVERWRITE_ALL) {
287            isOverwriteAll = true;
288        }
289
290        if (!isOverwriteAll) {
291
292            // get all permissions of the current entry
293            CmsPermissionSet permissions = entry.getPermissions();
294            IndexedContainer container = getPermissionContainer(permissions);
295            m_permissions.setContainerDataSource(container);
296            m_permissions.setColumnReorderingAllowed(false);
297            m_permissions.setColumnHeader(PROPERTY_LABEL, CmsVaadinUtils.getMessageText(Messages.GUI_PERMISSION_0));
298            m_permissions.setColumnHeader(
299                PROPERTY_ALLOWED,
300                CmsVaadinUtils.getMessageText(Messages.GUI_PERMISSION_ALLOWED_0));
301            m_permissions.setColumnHeader(
302                PROPERTY_DISPLAY_ALLOWED,
303                CmsVaadinUtils.getMessageText(Messages.GUI_PERMISSION_ALLOWED_0));
304            m_permissions.setColumnHeader(
305                PROPERTY_DENIED,
306                CmsVaadinUtils.getMessageText(Messages.GUI_PERMISSION_DENIED_0));
307            m_permissions.setColumnHeader(
308                PROPERTY_DISPLAY_DENIED,
309                CmsVaadinUtils.getMessageText(Messages.GUI_PERMISSION_DENIED_0));
310
311            m_permissions.setPageLength(5);
312            m_permissions.setSortEnabled(false);
313            m_permissions.setVisible(true);
314            if (m_editable) {
315
316                m_permissions.setVisibleColumns(PROPERTY_LABEL, PROPERTY_ALLOWED, PROPERTY_DENIED);
317                m_permissions.setTableFieldFactory(m_fieldFactory);
318                m_permissions.setEditable(m_editable);
319                m_responsibleCheckbox.setValue(isResponsible(entry.getFlags()));
320                m_overwriteCheckbox.setValue(isOverWritingInherited(entry.getFlags()));
321                m_inheritCheckbox.setVisible(isFolder);
322                m_inheritCheckbox.setValue(Boolean.valueOf(m_entry.isInheriting()));
323
324                m_buttonBar.setVisible(true);
325            } else {
326                m_permissions.setVisibleColumns(PROPERTY_LABEL, PROPERTY_DISPLAY_ALLOWED, PROPERTY_DISPLAY_DENIED);
327            }
328        }
329    }
330
331    /**
332     * Gets the name of the principal.<p>
333     *
334     * @return String
335     */
336    public String getPrincipalName() {
337
338        return m_principalName;
339    }
340
341    /**
342     * Hides the denied permissions column.<p>
343     */
344    public void hideDeniedColumn() {
345
346        if (m_editable) {
347            m_permissions.setVisibleColumns(PROPERTY_LABEL, PROPERTY_ALLOWED);
348        } else {
349            m_permissions.setVisibleColumns(PROPERTY_LABEL, PROPERTY_DISPLAY_ALLOWED);
350        }
351    }
352
353    /**
354     * Checks if view is editable.<p>
355     *
356     * @return true if view is editable
357     */
358    public boolean isEditable() {
359
360        return m_editable;
361    }
362
363    /**
364     * Determines the type of the current access control entry.<p>
365     *
366     * @param flags the value of the current flags
367     * @param all to include all types, or just user and groups
368     *
369     * @return String representation of the ace type
370     */
371    protected String getEntryType(int flags, boolean all) {
372
373        for (int i = 0; i < getTypes(all).length; i++) {
374            if ((flags & getTypesInt()[i]) > 0) {
375                return getTypes(all)[i];
376            }
377        }
378        return UNKNOWN_TYPE;
379    }
380
381    /**
382     * Returns a String array with the possible entry types.<p>
383     *
384     * @param all to include all types, or just user, groups and roles
385     *
386     * @return the possible types
387     */
388    protected String[] getTypes(boolean all) {
389
390        if (!all) {
391            String[] array = new String[3];
392            return Arrays.asList(CmsPermissionDialog.PRINCIPAL_TYPES).subList(0, 3).toArray(array);
393        }
394        return CmsPermissionDialog.PRINCIPAL_TYPES;
395    }
396
397    /**
398     * Returns an int array with possible entry types.<p>
399     *
400     * @return the possible types as int array
401     */
402    protected int[] getTypesInt() {
403
404        return CmsPermissionDialog.PRINCIPAL_TYPES_INT;
405    }
406
407    /**
408     * Checks if a certain permission of a permission set is allowed.<p>
409     *
410     * @param p the current CmsPermissionSet
411     * @param value the int value of the permission to check
412     * @return true if the permission is allowed, otherwise false
413     */
414    protected Boolean isAllowed(CmsPermissionSet p, int value) {
415
416        if ((p.getAllowedPermissions() & value) > 0) {
417            return Boolean.TRUE;
418        }
419        return Boolean.FALSE;
420    }
421
422    /**
423     * Checks if a certain permission of a permission set is denied.<p>
424     *
425     * @param p the current CmsPermissionSet
426     * @param value the int value of the permission to check
427     * @return true if the permission is denied, otherwise false
428     */
429    protected Boolean isDenied(CmsPermissionSet p, int value) {
430
431        if ((p.getDeniedPermissions() & value) > 0) {
432            return Boolean.TRUE;
433        }
434        return Boolean.FALSE;
435    }
436
437    /**
438     * Check if the current permissions are overwriting the inherited ones.<p>
439     *
440     * @param flags value of all flags of the current entry
441     * @return true if permissions are overwriting the inherited ones, otherwise false
442     */
443    protected Boolean isOverWritingInherited(int flags) {
444
445        if ((flags & CmsAccessControlEntry.ACCESS_FLAGS_OVERWRITE) > 0) {
446            return Boolean.TRUE;
447        }
448        return Boolean.FALSE;
449    }
450
451    /**
452     * Check if the user is a responsible for the resource.<p>
453     *
454     * @param flags value of all flags of the current entry
455     * @return true if user is responsible for the resource, otherwise false
456     */
457    protected Boolean isResponsible(int flags) {
458
459        if ((flags & CmsAccessControlEntry.ACCESS_FLAGS_RESPONSIBLE) > 0) {
460            return Boolean.TRUE;
461        }
462        return Boolean.FALSE;
463    }
464
465    /**
466     * Deletes the current permission set.<p>
467     */
468    void deletePermissionSet() {
469
470        m_changeHandler.deletePermissionSet(m_principalType, m_principalName);
471    }
472
473    /**
474     * Generates the permissions data container.<p>
475     *
476     * @param permissions the permission set
477     *
478     * @return the container
479     */
480    IndexedContainer getPermissionContainer(CmsPermissionSet permissions) {
481
482        IndexedContainer result = new IndexedContainer();
483        result.addContainerProperty(PROPERTY_LABEL, String.class, "");
484        result.addContainerProperty(PROPERTY_VALUE, Integer.class, null);
485        result.addContainerProperty(PROPERTY_ALLOWED, Boolean.class, Boolean.FALSE);
486        result.addContainerProperty(PROPERTY_DISPLAY_ALLOWED, Label.class, null);
487        result.addContainerProperty(PROPERTY_DENIED, Boolean.class, Boolean.FALSE);
488        result.addContainerProperty(PROPERTY_DISPLAY_DENIED, Label.class, null);
489        for (String key : CmsPermissionSet.getPermissionKeys()) {
490            int flag = CmsPermissionSet.getPermissionValue(key);
491            Item entry = result.addItem(key);
492            entry.getItemProperty(PROPERTY_LABEL).setValue(CmsVaadinUtils.getMessageText(key));
493            entry.getItemProperty(PROPERTY_ALLOWED).setValue(isAllowed(permissions, flag));
494            entry.getItemProperty(PROPERTY_DISPLAY_ALLOWED).setValue(getCheckBoxLabel(isAllowed(permissions, flag)));
495            entry.getItemProperty(PROPERTY_DENIED).setValue(isDenied(permissions, flag));
496            entry.getItemProperty(PROPERTY_DISPLAY_DENIED).setValue(getCheckBoxLabel(isDenied(permissions, flag)));
497            entry.getItemProperty(PROPERTY_VALUE).setValue(Integer.valueOf(flag));
498        }
499
500        return result;
501    }
502
503    /**
504     * Sets the current permissions.<p>
505     */
506    void setPermissions() {
507
508        IndexedContainer container = (IndexedContainer)m_permissions.getContainerDataSource();
509        int allowed = 0;
510        int denied = 0;
511        for (Object itemId : container.getItemIds()) {
512            Item item = container.getItem(itemId);
513            Integer value = (Integer)item.getItemProperty(PROPERTY_VALUE).getValue();
514            if (((Boolean)item.getItemProperty(PROPERTY_ALLOWED).getValue()).booleanValue()) {
515                allowed |= value.intValue();
516            }
517            if (((Boolean)item.getItemProperty(PROPERTY_DENIED).getValue()).booleanValue()) {
518                denied |= value.intValue();
519            }
520        }
521        int flags = m_entry.getFlags();
522
523        // modify the ace flags to determine inheritance of the current ace
524        if (m_inheritCheckbox.getValue().booleanValue()) {
525            flags |= CmsAccessControlEntry.ACCESS_FLAGS_INHERIT;
526        } else {
527            flags &= ~CmsAccessControlEntry.ACCESS_FLAGS_INHERIT;
528        }
529
530        // modify the ace flags to determine overwriting of inherited ace
531        if (m_overwriteCheckbox.getValue().booleanValue()) {
532            flags |= CmsAccessControlEntry.ACCESS_FLAGS_OVERWRITE;
533        } else {
534            flags &= ~CmsAccessControlEntry.ACCESS_FLAGS_OVERWRITE;
535        }
536
537        if (m_responsibleCheckbox.getValue().booleanValue()) {
538            flags |= CmsAccessControlEntry.ACCESS_FLAGS_RESPONSIBLE;
539        } else {
540            flags &= ~CmsAccessControlEntry.ACCESS_FLAGS_RESPONSIBLE;
541        }
542
543        m_changeHandler.setPermissions(new CmsPermissionBean(m_principalType, m_principalName, allowed, denied, flags));
544    }
545
546    /**
547     * Generates a check box label.<p>
548     *
549     * @param value the value to display
550     *
551     * @return the label
552     */
553    private Label getCheckBoxLabel(Boolean value) {
554
555        String content;
556        if (value.booleanValue()) {
557            content = "<input type='checkbox' disabled='true' checked='true' />";
558        } else {
559            content = "<input type='checkbox' disabled='true' />";
560        }
561
562        return new Label(content, ContentMode.HTML);
563    }
564
565}