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