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.tags;
020    
021    import java.io.IOException;
022    import java.security.Permission;
023    
024    import org.apache.commons.lang.StringUtils;
025    
026    import org.apache.wiki.WikiPage;
027    import org.apache.wiki.WikiProvider;
028    import org.apache.wiki.WikiSession;
029    import org.apache.wiki.auth.AuthorizationManager;
030    import org.apache.wiki.auth.GroupPrincipal;
031    import org.apache.wiki.auth.permissions.AllPermission;
032    import org.apache.wiki.auth.permissions.GroupPermission;
033    import org.apache.wiki.auth.permissions.PermissionFactory;
034    import org.apache.wiki.auth.permissions.WikiPermission;
035    import org.apache.wiki.ui.Command;
036    import 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     */
064    public 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    }