    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;
    020
    021import org.apache.wiki.api.core.Context;
    022import org.apache.wiki.api.core.Session;
    023import org.apache.wiki.api.engine.Initializable;
    024import org.apache.wiki.api.exceptions.WikiException;
    025import org.apache.wiki.auth.user.DuplicateUserException;
    026import org.apache.wiki.auth.user.UserDatabase;
    027import org.apache.wiki.auth.user.UserProfile;
    028import org.apache.wiki.event.WikiEventListener;
    029import org.apache.wiki.event.WikiEventManager;
    030import org.apache.wiki.event.WikiSecurityEvent;
    031
    032import java.security.Principal;
    033import org.apache.wiki.security.EventUtil;
    034
    035
    036/**
    037 * Provides a facade for obtaining user information.
    038 *
    039 * @since 2.3
    040 */
    041public interface UserManager extends Initializable {
    042
    043    /** Message key for the "save profile" message. */
    044    String PROP_DATABASE = "jspwiki.userdatabase";
    045
    046    String JSON_USERS = "users";
    047
    048    /**
    049     * Returns the UserDatabase employed by this Engine. The UserDatabase is lazily initialized by this method, if it does
    050     * not exist yet. If the initialization fails, this method will use the inner class DummyUserDatabase as a default (which
    051     * is enough to get JSPWiki running).
    052     *
    053     * @return the dummy user database
    054     * @since 2.3
    055     */
    056    UserDatabase getUserDatabase();
    057
    058    /**
    059     * <p>Retrieves the {@link org.apache.wiki.auth.user.UserProfile} for the user in a session. If the user is authenticated, the
    060     * UserProfile returned will be the one stored in the user database; if one does not exist, a new one will be initialized and returned.
    061     * If the user is anonymous or asserted, the UserProfile will <i>always</i> be newly initialized to prevent spoofing of identities.
    062     * If a UserProfile needs to be initialized, its {@link org.apache.wiki.auth.user.UserProfile#isNew()} method will return
    063     * <code>true</code>, and its login name will will be set automatically if the user is authenticated. Note that this method does
    064     * not modify the retrieved (or newly created) profile otherwise; other fields in the user profile may be <code>null</code>.</p>
    065     * <p>If a new UserProfile was created, but its {@link org.apache.wiki.auth.user.UserProfile#isNew()} method returns
    066     * <code>false</code>, this method throws an {@link IllegalStateException}. This is meant as a quality check for UserDatabase providers;
    067     * it should only be thrown if the implementation is faulty.</p>
    068     *
    069     * @param session the session, which may not be <code>null</code>
    070     * @return the user's profile, which will be newly initialized if the user is anonymous or asserted, or if the user cannot be found in
    071     *         the user database
    072     */
    073    UserProfile getUserProfile( Session session );
    074
    075    /**
    076     * <p>
    077     * Saves the {@link org.apache.wiki.auth.user.UserProfile} for the user in a wiki session.This method verifies that a user profile to
    078 be saved doesn't collide with existing profiles; that is, the login name or full name is already used by another profile. If the
    079 profile collides, a <code>DuplicateUserException</code> is thrown. After saving the profile, the user database changes are committed,
    080     * and the user's credential set is refreshed; if custom authentication is used, this means the user will be automatically be logged in.
    081     * </p>
    082     * <p>
    083     * When the user's profile is saved successfully, this method fires a {@link WikiSecurityEvent#PROFILE_SAVE} event with the Session
    084     * as the source and the UserProfile as target. For existing profiles, if the user's full name changes, this method also fires a
    085     * "name changed" event ({@link WikiSecurityEvent#PROFILE_NAME_CHANGED}) with the Session as the source and an array containing
    086     * the old and new UserProfiles, respectively. The <code>NAME_CHANGED</code> event allows the GroupManager and PageManager can change
    087     * group memberships and ACLs if needed.
    088     * </p>
    089     * <p>
    090     * Note that Sessions normally attach event listeners to the UserManager, so changes to the profile will automatically cause the
    091     * correct Principals to be reloaded into the current Session's Subject.
    092     * </p>
    093     *
    094     * @param context the wiki context, which may not be <code>null</code>
    095     * @param profile the user profile, which may not be <code>null</code>
    096     * @throws DuplicateUserException if the proposed profile's login name or full name collides with another
    097     * @throws WikiException if the save fails for some reason. If the current user does not have
    098     * permission to save the profile, this will be a {@link org.apache.wiki.auth.WikiSecurityException};
    099     * if if the user profile must be approved before it can be saved, it will be a
    100     * {@link org.apache.wiki.workflow.DecisionRequiredException}. All other WikiException
    101     * indicate a condition that is not normal is probably due to mis-configuration
    102     */
    103    void setUserProfile( Context context, UserProfile profile ) throws DuplicateUserException, WikiException;
    104
    105    void startUserProfileCreationWorkflow( Context context, UserProfile profile ) throws WikiException;
    106
    107    /**
    108     * <p> Extracts user profile parameters from the HTTP request and populates a UserProfile with them. The UserProfile will either be a
    109     * copy of the user's existing profile (if one can be found), or a new profile (if not). The rules for populating the profile as as
    110     * follows: </p>
    111     * <ul>
    112     * <li>If the <code>email</code> or <code>password</code> parameter values differ from those in the existing profile, the passed
    113     * parameters override the old values.</li>
    114     * <li>For new profiles, the user-supplied <code>fullname</code> parameter is always used; for existing profiles the existing value is
    115     * used, and whatever value the user supplied is discarded. The wiki name is automatically computed by taking the full name and
    116     * extracting all whitespace.</li>
    117     * <li>In all cases, the created/last modified timestamps of the user's existing or new profile always override whatever values the user
    118     * supplied.</li>
    119     * <li>If container authentication is used, the login name property of the profile is set to the name of
    120     * {@link org.apache.wiki.api.core.Session#getLoginPrincipal()}. Otherwise, the value of the <code>loginname</code> parameter is used.</li>
    121     * </ul>
    122     *
    123     * @param context the current wiki context
    124     * @return a new, populated user profile
    125     */
    126    UserProfile parseProfile( Context context );
    127
    128    /**
    129     * Validates a user profile, and appends any errors to the session errors list. If the profile is new, the password will be checked to
    130     * make sure it isn't null. Otherwise, the password is checked for length and that it matches the value of the 'password2' HTTP
    131     * parameter. Note that we have a special case when container-managed authentication is used and the user is not authenticated;
    132     * this will always cause validation to fail. Any validation errors are added to the wiki session's messages collection
    133     * (see {@link org.apache.wiki.api.core.Session#getMessages()}.
    134     *
    135     * @param context the current wiki context
    136     * @param profile the supplied UserProfile
    137     */
    138    void validateProfile( Context context, UserProfile profile );
    139
    140    /**
    141     *  A helper method for returning all of the known WikiNames in this system.
    142     *
    143     *  @return An Array of Principals
    144     *  @throws WikiSecurityException If for reason the names cannot be fetched
    145     */
    146    Principal[] listWikiNames() throws WikiSecurityException;
    147
    148    // events processing .......................................................
    149
    150    /**
    151     * Registers a WikiEventListener with this instance. This is a convenience method.
    152     *
    153     * @param listener the event listener
    154     */
    155    void addWikiEventListener( WikiEventListener listener );
    156
    157    /**
    158     * Un-registers a WikiEventListener with this instance. This is a convenience method.
    159     *
    160     * @param listener the event listener
    161     */
    162    void removeWikiEventListener( WikiEventListener listener );
    163
    164    /**
    165     *  Fires a WikiSecurityEvent of the provided type, Principal and target Object to all registered listeners.
    166     *
    167     * @see org.apache.wiki.event.WikiSecurityEvent
    168     * @param type       the event type to be fired
    169     * @param session    the wiki session supporting the event
    170     * @param profile    the user profile (or array of user profiles), which may be <code>null</code>
    171     */
    172    default void fireEvent( final int type, final Session session, final Object profile ) {
    173        if( WikiEventManager.isListening( this ) ) {
    174            WikiEventManager.fireEvent( this,
    175                    EventUtil.applyFrom(new WikiSecurityEvent( session, type, profile )) );
    176        }
    177    }
    178
    179}