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.Principal;
023import java.util.ArrayList;
024import java.util.List;
025import java.util.ResourceBundle;
026
027import javax.servlet.http.HttpServletRequest;
028
029import org.apache.wiki.WikiContext;
030import org.apache.wiki.WikiEngine;
031import org.apache.wiki.WikiSession;
032import org.apache.wiki.auth.AuthenticationManager;
033import org.apache.wiki.auth.GroupPrincipal;
034import org.apache.wiki.auth.UserManager;
035import org.apache.wiki.auth.WikiSecurityException;
036import org.apache.wiki.auth.authorize.Role;
037import org.apache.wiki.auth.user.UserProfile;
038import org.apache.wiki.i18n.InternationalizationManager;
039import org.apache.wiki.preferences.Preferences;
040import org.apache.wiki.util.TextUtil;
041
042/**
043 * <p>
044 * Returns user profile attributes, or empty strings if the user has not been
045 * validated. This tag has a single attribute, "property."
046 * The <code>property</code> attribute may contain one of the following
047 * case-insensitive values:
048 * </p>
049 * <ul>
050 * <li><code>created</code> - creation date</li>
051 * <li><code>email</code> - user's e-mail address</li>
052 * <li><code>fullname</code> - user's full name</li>
053 * <li><code>groups</code> - a sorted list of the groups a user belongs to</li>
054 * <li><code>loginname</code> - user's login name. If the current user does not have
055 * a profile, the user's login principal (such as one provided by a container
056 * login module, user cookie, or anonyous IP address), will supply the login
057 * name property</li>
058 * <li><code>roles</code> - a sorted list of the roles a user possesses</li>
059 * <li><code>wikiname</code> - user's wiki name</li>
060 * <li><code>modified</code> - last modification date</li>
061 * <li><code>exists</code> - evaluates the body of the tag if user's profile exists
062 * in the user database
063 * <li><code>new</code> - evaluates the body of the tag if user's profile does not
064 * exist in the user database
065 * <li><code>canChangeLoginName</code> - always true if custom auth used; also true for container auth
066 * and current UserDatabase.isSharedWithContainer() is true.</li>
067 * <li><code>canChangePassword</code> - always true if custom auth used; also true for container auth
068 * and current UserDatabase.isSharedWithContainer() is true.</li>
069 * </ul>
070 * <p>In addition, the values <code>exists</code>, <code>new</code>, <code>canChangeLoginName</code>
071 * and <code>canChangeLoginName</code> can also be prefixed with <code>!</code> to indicate the
072 * negative condition (for example, <code>!exists</code>).</p>
073 * @since 2.3
074 */
075public class UserProfileTag extends WikiTagBase
076{
077    private static final long serialVersionUID = 3258410625431582003L;
078
079    public  static final String BLANK = "(not set)";
080
081    private static final String CREATED   = "created";
082
083    private static final String EMAIL     = "email";
084
085    private static final String EXISTS    = "exists";
086
087    private static final String NOT_EXISTS= "!exists";
088
089    private static final String FULLNAME  = "fullname";
090
091    private static final String GROUPS    = "groups";
092
093    private static final String LOGINNAME = "loginname";
094
095    private static final String MODIFIED  = "modified";
096
097    private static final String NEW       = "new";
098
099    private static final String NOT_NEW   = "!new";
100
101    private static final String ROLES     = "roles";
102
103    private static final String WIKINAME  = "wikiname";
104
105    private static final String CHANGE_LOGIN_NAME     = "canchangeloginname";
106
107    private static final String NOT_CHANGE_LOGIN_NAME = "!canchangeloginname";
108
109    private static final String CHANGE_PASSWORD       = "canchangepassword";
110
111    private static final String NOT_CHANGE_PASSWORD   = "!canchangepassword";
112
113    private String             m_prop;
114
115    public void initTag()
116    {
117        super.initTag();
118        m_prop = null;
119    }
120
121    public final int doWikiStartTag() throws IOException, WikiSecurityException
122    {
123        UserManager manager = m_wikiContext.getEngine().getUserManager();
124        UserProfile profile = manager.getUserProfile( m_wikiContext.getWikiSession() );
125        String result = null;
126
127        if ( EXISTS.equals( m_prop ) || NOT_NEW.equals( m_prop ) )
128        {
129            return profile.isNew() ? SKIP_BODY : EVAL_BODY_INCLUDE;
130        }
131        else if ( NEW.equals( m_prop ) || NOT_EXISTS.equals( m_prop ) )
132        {
133            return profile.isNew() ? EVAL_BODY_INCLUDE : SKIP_BODY;
134        }
135
136        else if ( CREATED.equals( m_prop ) && profile.getCreated() != null )
137        {
138            result = profile.getCreated().toString();
139        }
140        else if ( EMAIL.equals( m_prop ) )
141        {
142            result = profile.getEmail();
143        }
144        else if ( FULLNAME.equals( m_prop ) )
145        {
146            result = profile.getFullname();
147        }
148        else if ( GROUPS.equals( m_prop ) )
149        {
150            result = printGroups( m_wikiContext );
151        }
152        else if ( LOGINNAME.equals( m_prop ) )
153        {
154            result = profile.getLoginName();
155        }
156        else if ( MODIFIED.equals( m_prop ) && profile.getLastModified() != null )
157        {
158            result = profile.getLastModified().toString();
159        }
160        else if ( ROLES.equals( m_prop ) )
161        {
162            result = printRoles( m_wikiContext );
163        }
164        else if ( WIKINAME.equals( m_prop ) )
165        {
166            result = profile.getWikiName();
167
168            if( result == null )
169            {
170                //
171                //  Default back to the declared user name
172                //
173                WikiEngine engine = this.m_wikiContext.getEngine();
174                WikiSession wikiSession = WikiSession.getWikiSession( engine, (HttpServletRequest)pageContext.getRequest() );
175                Principal user = wikiSession.getUserPrincipal();
176
177                if( user != null )
178                {
179                    result = user.getName();
180                }
181            }
182        }
183        else if ( CHANGE_PASSWORD.equals( m_prop ) || CHANGE_LOGIN_NAME.equals( m_prop ) )
184        {
185            AuthenticationManager authMgr = m_wikiContext.getEngine().getAuthenticationManager();
186            if ( !authMgr.isContainerAuthenticated() )
187            {
188                return EVAL_BODY_INCLUDE;
189            }
190        }
191        else if ( NOT_CHANGE_PASSWORD.equals( m_prop ) || NOT_CHANGE_LOGIN_NAME.equals( m_prop ) )
192        {
193            AuthenticationManager authMgr = m_wikiContext.getEngine().getAuthenticationManager();
194            if ( authMgr.isContainerAuthenticated() )
195            {
196                return EVAL_BODY_INCLUDE;
197            }
198        }
199
200        if ( result != null )
201        {
202            pageContext.getOut().print( TextUtil.replaceEntities(result) );
203        }
204        return SKIP_BODY;
205    }
206
207    public void setProperty( String property )
208    {
209        m_prop = property.toLowerCase().trim();
210    }
211
212    /**
213     * Returns a sorted list of the {@link org.apache.wiki.auth.authorize.Group} objects a user possesses
214     * in his or her WikiSession. The result is computed by consulting
215     * {@link org.apache.wiki.WikiSession#getRoles()}
216     * and extracting those that are of type Group.
217     * @return the list of groups, sorted by name
218     */
219    public static String printGroups( WikiContext context )
220    {
221        Principal[] roles = context.getWikiSession().getRoles();
222        List<String> tempRoles = new ArrayList<String>();
223        ResourceBundle rb = Preferences.getBundle( context, InternationalizationManager.CORE_BUNDLE );
224        
225        for ( Principal role : roles )
226        {
227            if( role instanceof GroupPrincipal )
228            {
229                tempRoles.add( role.getName() );
230            }
231        }
232        if ( tempRoles.size() == 0 )
233        {
234            return rb.getString("userprofile.nogroups");
235        }
236
237        StringBuilder sb = new StringBuilder();
238        for ( int i = 0; i < tempRoles.size(); i++ )
239        {
240            String name = tempRoles.get( i );
241
242            sb.append( name );
243            if ( i < ( tempRoles.size() - 1 ) )
244            {
245                sb.append(',');
246                sb.append(' ');
247            }
248
249        }
250        return sb.toString();
251    }
252
253    /**
254     * Returns a sorted list of the {@link org.apache.wiki.auth.authorize.Role} objects a user possesses
255     * in his or her WikiSession. The result is computed by consulting
256     * {@link org.apache.wiki.WikiSession#getRoles()}
257     * and extracting those that are of type Role.
258     * @return the list of roles, sorted by name
259     */
260    public static String printRoles( WikiContext context )
261    {
262        Principal[] roles = context.getWikiSession().getRoles();
263        List<String> tempRoles = new ArrayList<String>();
264        ResourceBundle rb = Preferences.getBundle( context, InternationalizationManager.CORE_BUNDLE );
265        
266        for ( Principal role : roles )
267        {
268            if ( role instanceof Role )
269            {
270                tempRoles.add( role.getName() );
271            }
272        }
273        if ( tempRoles.size() == 0 )
274        {
275            return rb.getString( "userprofile.noroles" );
276        }
277
278        StringBuilder sb = new StringBuilder();
279        for ( int i = 0; i < tempRoles.size(); i++ )
280        {
281            String name = tempRoles.get( i );
282
283            sb.append( name );
284            if ( i < ( tempRoles.size() - 1 ) )
285            {
286                sb.append(',');
287                sb.append(' ');
288            }
289
290        }
291        return sb.toString();
292    }
293}