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.tags;
020
021import org.apache.commons.lang3.StringUtils;
022import org.apache.wiki.WikiPage;
023import org.apache.wiki.WikiProvider;
024import org.apache.wiki.WikiSession;
025import org.apache.wiki.auth.AuthorizationManager;
026import org.apache.wiki.auth.GroupPrincipal;
027import org.apache.wiki.auth.permissions.AllPermission;
028import org.apache.wiki.auth.permissions.GroupPermission;
029import org.apache.wiki.auth.permissions.PermissionFactory;
030import org.apache.wiki.auth.permissions.WikiPermission;
031import org.apache.wiki.ui.Command;
032import org.apache.wiki.ui.GroupCommand;
033
034import java.io.IOException;
035import java.security.Permission;
036
037/**
038 *  Tells whether the user in the current wiki context possesses a particular
039 *  permission. The permission is typically a PagePermission (e.g., "edit", "view",
040 *  "delete", "comment", "upload"). It may also be a wiki-wide WikiPermission
041 *  ("createPages", "createGroups", "editProfile", "editPreferences", "login")
042 *  or the administrator permission ("allPermission"). GroupPermissions 
043 *  (e.g., "viewGroup", "editGroup", "deleteGroup").
044 *  <p>
045 *  Since 2.6, it is possible to list several permissions or use negative permissions,
046 *  e.g.
047 *  <pre>
048 *     &lt;wiki:Permission permission="edit|rename|view"&gt;
049 *        You have edit, rename, or  view permissions!
050 *     &lt;/wiki:Permission&gt;
051 *  </pre>
052 *  
053 *  or
054 *
055 *  <pre>
056 *     &lt;wiki:Permission permission="!upload"&gt;
057 *        You do not have permission to upload!
058 *     &lt;/wiki:Permission&gt;
059 *  </pre>
060 *  
061 *  @since 2.0
062 */
063public class PermissionTag
064    extends WikiTagBase
065{
066    private static final String ALL_PERMISSION   = "allPermission";
067    private static final String CREATE_GROUPS    = "createGroups";
068    private static final String CREATE_PAGES     = "createPages";
069    private static final String DELETE_GROUP     = "deleteGroup";
070    private static final String EDIT             = "edit";
071    private static final String EDIT_GROUP       = "editGroup";
072    private static final String EDIT_PREFERENCES = "editPreferences";
073    private static final String EDIT_PROFILE     = "editProfile";
074    private static final String LOGIN            = "login";
075    private static final String VIEW_GROUP       = "viewGroup";
076    
077    private static final long serialVersionUID = 3761412993048982325L;
078    
079    private String[] m_permissionList;
080
081    /**
082     * Initializes the tag.
083     */
084    @Override
085    public void initTag()
086    {
087        super.initTag();
088        m_permissionList = null;
089    }
090
091    /**
092     * Sets the permissions to look for (case sensitive).  See above for the format.
093     * 
094     * @param permission A list of permissions
095     */
096    public void setPermission( String permission )
097    {
098        m_permissionList = StringUtils.split(permission,'|');
099    }
100
101    /**
102     *  Checks a single permission.
103     *  
104     *  @param permission
105     *  @return true if granted, false if not
106     */
107    private boolean checkPermission( String permission )
108    {
109        WikiSession session        = m_wikiContext.getWikiSession();
110        WikiPage    page           = m_wikiContext.getPage();
111        AuthorizationManager mgr   = m_wikiContext.getEngine().getAuthorizationManager();
112        boolean gotPermission     = false;
113        
114        if ( CREATE_GROUPS.equals( permission ) || CREATE_PAGES.equals( permission )
115            || EDIT_PREFERENCES.equals( permission ) || EDIT_PROFILE.equals( permission )
116            || LOGIN.equals( permission ) )
117        {
118            gotPermission = mgr.checkPermission( session, new WikiPermission( page.getWiki(), permission ) );
119        }
120        else if ( VIEW_GROUP.equals( permission ) 
121            || EDIT_GROUP.equals( permission )
122            || DELETE_GROUP.equals( permission ) )
123        {
124            Command command = m_wikiContext.getCommand();
125            gotPermission = false;
126            if ( command instanceof GroupCommand && command.getTarget() != null )
127            {
128                GroupPrincipal group = (GroupPrincipal)command.getTarget();
129                String groupName = group.getName();
130                String action = "view";
131                if( EDIT_GROUP.equals( permission ) )
132                {
133                    action = "edit";
134                }
135                else if ( DELETE_GROUP.equals( permission ) )
136                {
137                    action = "delete";
138                }
139                gotPermission = mgr.checkPermission( session, new GroupPermission( groupName, action ) );
140            }
141        }
142        else if ( ALL_PERMISSION.equals( permission ) )
143        {
144            gotPermission = mgr.checkPermission( session, new AllPermission( m_wikiContext.getEngine().getApplicationName() ) );
145        }
146        else if ( page != null )
147        {
148            //
149            //  Edit tag also checks that we're not trying to edit an
150            //  old version: they cannot be edited.
151            //
152            if( EDIT.equals(permission) )
153            {
154                WikiPage latest = m_wikiContext.getEngine().getPage( page.getName() );
155                if( page.getVersion() != WikiProvider.LATEST_VERSION &&
156                    latest.getVersion() != page.getVersion() )
157                {
158                    return false;
159                }
160            }
161
162            Permission p = PermissionFactory.getPagePermission( page, permission );
163            gotPermission = mgr.checkPermission( session,
164                                                  p );
165        }
166        
167        return gotPermission;
168    }
169    
170    /**
171     * Initializes the tag.
172     * @return the result of the tag: SKIP_BODY or EVAL_BODY_CONTINUE
173     * @throws IOException this exception will never be thrown
174     */
175    @Override
176    public final int doWikiStartTag()
177        throws IOException
178    {
179        for( int i = 0; i < m_permissionList.length; i++ )
180        {
181            String perm = m_permissionList[i];
182         
183            boolean hasPermission = false;
184
185            if( perm.charAt(0) == '!' )
186            {
187                hasPermission = !checkPermission( perm.substring(1) );
188            }
189            else
190            {
191                hasPermission = checkPermission( perm );
192            }
193            
194            if( hasPermission )
195                return EVAL_BODY_INCLUDE;
196        }
197
198        return SKIP_BODY;
199    }
200}