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 java.security.Principal; 022import java.util.Properties; 023 024import org.apache.wiki.WikiEngine; 025import org.apache.wiki.api.exceptions.NoRequiredPropertyException; 026import org.apache.wiki.auth.NoSuchPrincipalException; 027import org.apache.wiki.auth.WikiSecurityException; 028 029/** 030 * Defines an interface for loading, persisting and storing users. 031 * @since 2.3 032 */ 033public interface UserDatabase 034{ 035 036 /** 037 * No-op method that in previous versions of JSPWiki was intended to 038 * atomically commit changes to the user database. Now, the {@link #rename(String, String)}, 039 * {@link #save(UserProfile)} and {@link #deleteByLoginName(String)} methods 040 * are atomic themselves. 041 * @throws WikiSecurityException 042 * @deprecated there is no need to call this method because the save, rename and 043 * delete methods contain their own commit logic 044 */ 045 void commit() throws WikiSecurityException; 046 047 /** 048 * Looks up and deletes the first {@link UserProfile} in the user database 049 * that matches a profile having a given login name. If the user database 050 * does not contain a user with a matching attribute, throws a 051 * {@link NoSuchPrincipalException}. This method is intended to be atomic; 052 * results cannot be partially committed. If the commit fails, it should 053 * roll back its state appropriately. Implementing classes that persist 054 * to the file system may wish to make this method <code>synchronized</code>. 055 * @param loginName the login name of the user profile that shall be deleted 056 */ 057 void deleteByLoginName( String loginName ) throws NoSuchPrincipalException, WikiSecurityException; 058 059 /** 060 * <p> 061 * Looks up the Principals representing a user from the user database. These 062 * are defined as a set of Principals manufactured from the login name, full 063 * name, and wiki name. The order of the Principals returned is not 064 * significant. If the user database does not contain a user with the 065 * supplied identifier, throws a {@link NoSuchPrincipalException}. 066 * </p> 067 * <p> 068 * Note that if an implememtation wishes to mark one of the returned 069 * Principals as representing the user's common name, it should instantiate 070 * this Principal using 071 * {@link org.apache.wiki.auth.WikiPrincipal#WikiPrincipal(String, String)} 072 * with the <code>type</code> parameter set to 073 * {@link org.apache.wiki.auth.WikiPrincipal#WIKI_NAME}. The method 074 * {@link org.apache.wiki.WikiSession#getUserPrincipal()} will return this 075 * principal as the "primary" principal. Note that this method can also be 076 * used to mark a WikiPrincipal as a login name or a wiki name. 077 * </p> 078 * @param identifier the name of the user to retrieve; this corresponds to 079 * value returned by the user profile's 080 * {@link UserProfile#getLoginName()} method. 081 * @return the array of Principals representing the user's identities 082 */ 083 Principal[] getPrincipals( String identifier ) throws NoSuchPrincipalException; 084 085 /** 086 * Returns all WikiNames that are stored in the UserDatabase 087 * as an array of Principal objects. If the database does not 088 * contain any profiles, this method will return a zero-length 089 * array. 090 * @return the WikiNames 091 */ 092 Principal[] getWikiNames() throws WikiSecurityException; 093 094 /** 095 * Looks up and returns the first {@link UserProfile} in the user database 096 * that whose login name, full name, or wiki name matches the supplied 097 * string. This method provides a "forgiving" search algorithm for resolving 098 * Principal names when the exact profile attribute that supplied the name 099 * is unknown. 100 * @param index the login name, full name, or wiki name 101 */ 102 UserProfile find( String index ) throws NoSuchPrincipalException; 103 104 /** 105 * Looks up and returns the first {@link UserProfile} in the user database 106 * that matches a profile having a given e-mail address. If the user 107 * database does not contain a user with a matching attribute, throws a 108 * {@link NoSuchPrincipalException}. 109 * @param index the e-mail address of the desired user profile 110 * @return the user profile 111 */ 112 UserProfile findByEmail( String index ) throws NoSuchPrincipalException; 113 114 /** 115 * Looks up and returns the first {@link UserProfile} in the user database 116 * that matches a profile having a given login name. If the user database 117 * does not contain a user with a matching attribute, throws a 118 * {@link NoSuchPrincipalException}. 119 * @param index the login name of the desired user profile 120 * @return the user profile 121 */ 122 UserProfile findByLoginName( String index ) throws NoSuchPrincipalException; 123 124 /** 125 * Looks up and returns the first {@link UserProfile} in the user database 126 * that matches a profile having a given unique ID (uid). If the user database 127 * does not contain a user with a unique ID, it throws a 128 * {@link NoSuchPrincipalException}. 129 * @param uid the unique identifier of the desired user profile 130 * @return the user profile 131 * @since 2.8 132 */ 133 UserProfile findByUid( String uid ) throws NoSuchPrincipalException; 134 135 /** 136 * Looks up and returns the first {@link UserProfile} in the user database 137 * that matches a profile having a given wiki name. If the user database 138 * does not contain a user with a matching attribute, throws a 139 * {@link NoSuchPrincipalException}. 140 * @param index the wiki name of the desired user profile 141 * @return the user profile 142 */ 143 UserProfile findByWikiName( String index ) throws NoSuchPrincipalException; 144 145 /** 146 * Looks up and returns the first {@link UserProfile} in the user database 147 * that matches a profile having a given full name. If the user database 148 * does not contain a user with a matching attribute, throws a 149 * {@link NoSuchPrincipalException}. 150 * @param index the fill name of the desired user profile 151 * @return the user profile 152 */ 153 UserProfile findByFullName( String index ) throws NoSuchPrincipalException; 154 155 /** 156 * Initializes the user database based on values from a Properties object. 157 */ 158 void initialize( WikiEngine engine, Properties props ) throws NoRequiredPropertyException, WikiSecurityException; 159 160 /** 161 * Factory method that instantiates a new user profile. 162 * The {@link UserProfile#isNew()} method of profiles created using 163 * this method should return <code>true</code>. 164 */ 165 UserProfile newProfile(); 166 167 /** 168 * <p>Renames a {@link UserProfile} in the user database by changing 169 * the profile's login name. Because the login name is the profile's unique 170 * identifier, implementations should verify that the identifier is 171 * "safe" to change before actually changing it. Specifically: the profile 172 * with the supplied login name must already exist, and the proposed new 173 * name must not be in use by another profile.</p> 174 * <p>This method is intended to be atomic; results cannot be partially committed. 175 * If the commit fails, it should roll back its state appropriately. 176 * Implementing classes that persist to the file system may wish to make 177 * this method <code>synchronized</code>.</p> 178 * @param loginName the existing login name for the profile 179 * @param newName the proposed new login name 180 * @throws NoSuchPrincipalException if the user profile identified by 181 * <code>loginName</code> does not exist 182 * @throws DuplicateUserException if another user profile with the 183 * proposed new login name already exists 184 * @throws WikiSecurityException if the profile cannot be renamed for 185 * any reason, such as an I/O error, database connection failure 186 * or lack of support for renames. 187 */ 188 void rename( String loginName, String newName ) throws NoSuchPrincipalException, DuplicateUserException, WikiSecurityException; 189 190 /** 191 * <p> 192 * Saves a {@link UserProfile}to the user database, overwriting the 193 * existing profile if it exists. The user name under which the profile 194 * should be saved is returned by the supplied profile's 195 * {@link UserProfile#getLoginName()} method. 196 * </p> 197 * <p> 198 * The database implementation is responsible for detecting potential 199 * duplicate user profiles; specifically, the login name, wiki name, and 200 * full name must be unique. The implementation is not required to check for 201 * validity of passwords or e-mail addresses. Special case: if the profile 202 * already exists and the password is null, it should retain its previous 203 * value, rather than being set to null. 204 * </p> 205 * <p>Implementations are <em>required</em> to time-stamp the creation 206 * or modification fields of the UserProfile./p> 207 * <p>This method is intended to be atomic; results cannot be partially committed. 208 * If the commit fails, it should roll back its state appropriately. 209 * Implementing classes that persist to the file system may wish to make 210 * this method <code>synchronized</code>.</p> 211 * @param profile the user profile to save 212 * @throws WikiSecurityException if the profile cannot be saved 213 */ 214 void save( UserProfile profile ) throws WikiSecurityException; 215 216 /** 217 * Determines whether a supplied user password is valid, given a login name 218 * and password. It is up to the implementing class to determine how the 219 * comparison should be made. For example, the password might be hashed 220 * before comparing it to the value persisted in the back-end data store. 221 * @param loginName the login name 222 * @param password the password 223 * @return <code>true</code> if the password is valid, <code>false</code> 224 * otherwise 225 */ 226 boolean validatePassword( String loginName, String password ); 227 228}