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