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