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.auth.user; 020 021import org.apache.commons.lang3.StringUtils; 022 023import jakarta.servlet.http.HttpServletRequest; 024import java.io.Serializable; 025import java.util.ArrayList; 026import java.util.Date; 027import java.util.HashMap; 028import java.util.List; 029import java.util.Map; 030 031 032/** 033 * Default implementation for representing wiki user information, such as the login name, full name, wiki name, and e-mail address. 034 * 035 * @since 2.3 036 */ 037public final class DefaultUserProfile implements UserProfile { 038 039 private static final long serialVersionUID = -5600466893735300647L; 040 private static final String EMPTY_STRING = ""; 041 private static final String WHITESPACE = "\\s"; 042 043 private final Map< String, Serializable > attributes = new HashMap<>(); 044 private Date created; 045 private String email; 046 private String fullname; 047 private Date lockExpiry; 048 private String loginName; 049 private Date modified; 050 private String password; 051 private String uid; 052 private String wikiname; 053 //oldest should be in position zero, size bounded via configuration 054 private List<String> previousHashedCredentials = new ArrayList<>(); 055 056 public List<String> getPreviousHashedCredentials() { 057 return previousHashedCredentials; 058 } 059 060 /** 061 * Package constructor to allow direct instantiation only from package related classes (i.e., AbstractUserDatabase). 062 */ 063 DefaultUserProfile() {} 064 065 /** 066 * {@inheritDoc} 067 */ 068 @Override 069 public boolean equals( final Object o ) { 070 if ( o instanceof UserProfile ) { 071 final DefaultUserProfile u = ( DefaultUserProfile )o; 072 return same( fullname, u.fullname ) && 073 //same( password, u.password ) && 074 //Note: this used to compare the password for some reason, but that was causing 075 //issues when the user wanted to change their password. since this is called 076 //from DefaultUserManager#setProfile 077 same( loginName, u.loginName ) && 078 same( StringUtils.lowerCase( email ), StringUtils.lowerCase( u.email ) ) && 079 same( wikiname, u.wikiname ); 080 } 081 082 return false; 083 } 084 085 @Override 086 public int hashCode() { 087 return ( fullname != null ? fullname.hashCode() : 0 ) ^ 088 ( password != null ? password.hashCode() : 0 ) ^ 089 ( loginName != null ? loginName.hashCode() : 0 ) ^ 090 ( wikiname != null ? wikiname.hashCode() : 0 ) ^ 091 ( email != null ? StringUtils.lowerCase( email ).hashCode() : 0 ); 092 } 093 094 /** 095 * Returns the creation date 096 * 097 * @return the creation date 098 * @see org.apache.wiki.auth.user.UserProfile#getCreated() 099 */ 100 @Override 101 public Date getCreated() 102 { 103 return created; 104 } 105 106 /** 107 * Returns the user's e-mail address. 108 * 109 * @return the e-mail address 110 */ 111 @Override 112 public String getEmail() 113 { 114 return email; 115 } 116 117 /** 118 * Returns the user's full name. 119 * 120 * @return the full name 121 */ 122 @Override 123 public String getFullname() 124 { 125 return fullname; 126 } 127 128 /** 129 * Returns the last-modified date. 130 * 131 * @return the last-modified date 132 * @see org.apache.wiki.auth.user.UserProfile#getLastModified() 133 */ 134 @Override 135 public Date getLastModified() 136 { 137 return modified; 138 } 139 140 /** 141 * Returns the user's login name. 142 * @return the login name 143 */ 144 @Override 145 public String getLoginName() 146 { 147 return loginName; 148 } 149 150 /** 151 * Returns the user password for use with custom authentication. Note that the password field is not meaningful for container 152 * authentication; the user's private credentials are generally stored elsewhere. While it depends on the {@link UserDatabase} 153 * implementation, in most cases the value returned by this method will be a password hash, not the password itself. 154 * 155 * @return the password 156 */ 157 @Override 158 public String getPassword() 159 { 160 return password; 161 } 162 163 /** 164 * Returns the user's wiki name. 165 * 166 * @return the wiki name. 167 */ 168 @Override 169 public String getWikiName() 170 { 171 return wikiname; 172 } 173 174 /** 175 * Returns <code>true</code> if the user profile is new. This implementation checks whether {@link #getLastModified()} returns 176 * <code>null</code> to determine the status. 177 * 178 * @see org.apache.wiki.auth.user.UserProfile#isNew() 179 */ 180 @Override 181 public boolean isNew() 182 { 183 return modified == null; 184 } 185 186 /** 187 * @param date the creation date 188 * @see org.apache.wiki.auth.user.UserProfile#setCreated(java.util.Date) 189 */ 190 @Override 191 public void setCreated( final Date date ) 192 { 193 created = date; 194 } 195 196 /** 197 * Sets the user's e-mail address. 198 * 199 * @param email the e-mail address 200 */ 201 @Override 202 public void setEmail( final String email ) 203 { 204 this.email = email; 205 } 206 207 /** 208 * Sets the user's full name. For example, "Janne Jalkanen." 209 * 210 * @param arg the full name 211 */ 212 @Override 213 public void setFullname( final String arg ) { 214 fullname = arg; 215 216 // Compute wiki name 217 if ( fullname != null ) { 218 wikiname = fullname.replaceAll( WHITESPACE, EMPTY_STRING ); 219 } 220 } 221 222 /** 223 * Sets the last-modified date. 224 * 225 * @param date the last-modified date 226 * @see org.apache.wiki.auth.user.UserProfile#setLastModified(java.util.Date) 227 */ 228 @Override 229 public void setLastModified( final Date date ) 230 { 231 modified = date; 232 } 233 234 /** 235 * Sets the name by which the user logs in. The login name is used as the username for custom authentication (see 236 * {@link org.apache.wiki.auth.AuthenticationManager#login(org.apache.wiki.api.core.Session,HttpServletRequest, String, String)}). 237 * The login name is typically a short name ("jannej"). In contrast, the wiki name is typically of type 238 * FirstnameLastName ("JanneJalkanen"). 239 * 240 * @param name the login name 241 */ 242 @Override 243 public void setLoginName( final String name ) 244 { 245 loginName = name; 246 } 247 248 /** 249 * Sets the user's password for use with custom authentication. It is <em>not</em> the responsibility of implementing classes to hash 250 * the password; that responsibility is borne by the UserDatabase implementation during save operations (see 251 * {@link UserDatabase#save(UserProfile)}). Note that the password field is not meaningful for container authentication; the user's 252 * private credentials are generally stored elsewhere. 253 * 254 * @param arg the password 255 */ 256 @Override 257 public void setPassword( final String arg ) 258 { 259 password = arg; 260 } 261 262 /** 263 * Returns a string representation of this user profile. 264 * 265 * @return the string 266 */ 267 @Override 268 public String toString() 269 { 270 return "[DefaultUserProfile: '" + getFullname() + "']"; 271 } 272 273 /** 274 * Private method that compares two objects and determines whether they are equal. Two nulls are considered equal. 275 * 276 * @param arg1 the first object 277 * @param arg2 the second object 278 * @return the result of the comparison 279 */ 280 private boolean same( final Object arg1, final Object arg2 ) { 281 if( arg1 == null && arg2 == null ) { 282 return true; 283 } 284 if( arg1 == null || arg2 == null ) { 285 return false; 286 } 287 return arg1.equals( arg2 ); 288 } 289 290 //--------------------------- Attribute and lock interface implementations --------------------------- 291 292 /** 293 * {@inheritDoc} 294 */ 295 @Override 296 public Map< String, Serializable > getAttributes() 297 { 298 return attributes; 299 } 300 301 /** 302 * {@inheritDoc} 303 */ 304 @Override 305 public Date getLockExpiry() 306 { 307 return isLocked() ? lockExpiry : null; 308 } 309 310 /** 311 * {@inheritDoc} 312 */ 313 @Override 314 public String getUid() 315 { 316 return uid; 317 } 318 319 /** 320 * {@inheritDoc} 321 */ 322 @Override 323 public boolean isLocked() { 324 final boolean locked = lockExpiry != null && System.currentTimeMillis() < lockExpiry.getTime(); 325 // Clear the lock if it's expired already 326 if( !locked && lockExpiry != null ) { 327 lockExpiry = null; 328 } 329 return locked; 330 331 } 332 333 /** 334 * {@inheritDoc} 335 */ 336 @Override 337 public void setLockExpiry( final Date expiry ) 338 { 339 this.lockExpiry = expiry; 340 } 341 342 /** 343 * {@inheritDoc} 344 */ 345 @Override 346 public void setUid( final String uid ) 347 { 348 this.uid = uid; 349 } 350 351}