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     */
019    package org.apache.wiki.auth.login;
020    
021    import java.io.IOException;
022    
023    import javax.security.auth.callback.Callback;
024    import javax.security.auth.callback.NameCallback;
025    import javax.security.auth.callback.PasswordCallback;
026    import javax.security.auth.callback.UnsupportedCallbackException;
027    import javax.security.auth.login.FailedLoginException;
028    import javax.security.auth.login.LoginException;
029    
030    import org.apache.log4j.Logger;
031    
032    import org.apache.wiki.auth.NoSuchPrincipalException;
033    import org.apache.wiki.auth.WikiPrincipal;
034    import org.apache.wiki.auth.user.UserDatabase;
035    import org.apache.wiki.auth.user.UserProfile;
036    
037    /**
038     * <p>
039     * Logs in a user based on a username, password, and static password file
040     * location. This module must be used with a CallbackHandler (such as
041     * {@link WikiCallbackHandler}) that supports the following Callback types:
042     * </p>
043     * <ol>
044     * <li>{@link javax.security.auth.callback.NameCallback}- supplies the
045     * username</li>
046     * <li>{@link javax.security.auth.callback.PasswordCallback}- supplies the
047     * password</li>
048     * <li>{@link org.apache.wiki.auth.login.UserDatabaseCallback}- supplies the
049     * {@link org.apache.wiki.auth.user.UserDatabase}</li>
050     * </ol>
051     * <p>
052     * After authentication, a Principals based on the login name will be created
053     * and associated with the Subject.
054     * </p>
055     * @since 2.3
056     */
057    public class UserDatabaseLoginModule extends AbstractLoginModule
058    {
059    
060        private static final Logger log = Logger.getLogger( UserDatabaseLoginModule.class );
061    
062        /**
063         * @see javax.security.auth.spi.LoginModule#login()
064         * 
065         * {@inheritDoc}
066         */
067        public boolean login() throws LoginException
068        {
069            UserDatabaseCallback ucb = new UserDatabaseCallback();
070            NameCallback ncb = new NameCallback( "User name" );
071            PasswordCallback pcb = new PasswordCallback( "Password", false );
072            Callback[] callbacks = new Callback[]
073            { ucb, ncb, pcb };
074            try
075            {
076                m_handler.handle( callbacks );
077                UserDatabase db = ucb.getUserDatabase();
078                String username = ncb.getName();
079                String password = new String( pcb.getPassword() );
080    
081                // Look up the user and compare the password hash
082                if ( db == null )
083                {
084                    throw new FailedLoginException( "No user database: check the callback handler code!" );
085                }
086                UserProfile profile = db.findByLoginName( username );
087                String storedPassword = profile.getPassword();
088                if ( storedPassword != null && db.validatePassword( username, password ) )
089                {
090                    if ( log.isDebugEnabled() )
091                    {
092                        log.debug( "Logged in user database user " + username );
093                    }
094    
095                    // If login succeeds, commit these principals/roles
096                    m_principals.add( new WikiPrincipal( username,  WikiPrincipal.LOGIN_NAME ) );
097    
098                    return true;
099                }
100                throw new FailedLoginException( "The username or password is incorrect." );
101            }
102            catch( IOException e )
103            {
104                String message = "IO exception; disallowing login.";
105                log.error( message, e );
106                throw new LoginException( message );
107            }
108            catch( UnsupportedCallbackException e )
109            {
110                String message = "Unable to handle callback; disallowing login.";
111                log.error( message, e );
112                throw new LoginException( message );
113            }
114            catch( NoSuchPrincipalException e )
115            {
116                throw new FailedLoginException( "The username or password is incorrect." );
117            }
118        }
119    
120    }