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