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