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