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    import java.security.Principal;
023    
024    import javax.security.auth.callback.Callback;
025    import javax.security.auth.callback.UnsupportedCallbackException;
026    import javax.security.auth.login.FailedLoginException;
027    import javax.security.auth.login.LoginException;
028    import javax.servlet.http.HttpServletRequest;
029    import javax.servlet.http.HttpSession;
030    
031    import org.apache.log4j.Logger;
032    
033    import org.apache.wiki.auth.WikiPrincipal;
034    
035    /**
036     * <p>
037     * Logs in a user by extracting authentication data from an Http servlet
038     * session. First, the module tries to extract a Principal object out of the
039     * request directly using the servlet requests's <code>getUserPrincipal()</code>
040     * method. If one is found, authentication succeeds. If there is no
041     * Principal in the request, try calling <code>getRemoteUser()</code>. If
042     * the <code>remoteUser</code> exists but the UserDatabase can't find a matching
043     * profile, a generic WikiPrincipal is created with this value. If neither
044     * <code>userPrincipal</code> nor <code>remoteUser</code> exist in the request, the login fails.
045     * </p>
046     * <p>
047     * This module must be used with a CallbackHandler that supports the following
048     * Callback types:
049     * </p>
050     * <ol>
051     * <li>{@link HttpRequestCallback} - supplies the Http request object, from
052     * which the getRemoteUser and getUserPrincipal are extracted</li>
053     * <li>{@link UserDatabaseCallback} - supplies the user database for looking up
054     * the value of getRemoteUser</li>
055     * </ol>
056     * <p>
057     * After authentication, the Subject will contain the Principal that
058     * represents the logged-in user.</p>
059     *
060     * @since 2.3
061     */
062    public class WebContainerLoginModule extends AbstractLoginModule
063    {
064    
065        protected static final Logger log      = Logger.getLogger( WebContainerLoginModule.class );
066    
067        /**
068         * Logs in the user.
069         * @see javax.security.auth.spi.LoginModule#login()
070         * 
071         * @return {@inheritDoc}
072         * @throws {@inheritDoc}
073         */
074        public boolean login() throws LoginException
075        {
076            HttpRequestCallback rcb = new HttpRequestCallback();
077            Callback[] callbacks = new Callback[] { rcb };
078            String userId = null;
079    
080            try
081            {
082                // First, try to extract a Principal object out of the request
083                // directly. If we find one, we're done.
084                m_handler.handle( callbacks );
085                HttpServletRequest request = rcb.getRequest();
086                if ( request == null )
087                {
088                    throw new LoginException( "No Http request supplied." );
089                }
090                HttpSession session = request.getSession(false);
091                String sid = (session == null) ? NULL : session.getId();
092                Principal principal = request.getUserPrincipal();
093                if ( principal == null )
094                {
095                    // If no Principal in request, try the remoteUser
096                    if ( log.isDebugEnabled() )
097                    {
098                        log.debug( "No userPrincipal found for session ID=" + sid);
099                    }
100                    userId = request.getRemoteUser();
101                    if ( userId == null )
102                    {
103                        if ( log.isDebugEnabled() )
104                        {
105                            log.debug( "No remoteUser found for session ID=" + sid);
106                        }
107                        throw new FailedLoginException( "No remote user found" );
108                    }
109                    principal = new WikiPrincipal( userId, WikiPrincipal.LOGIN_NAME );
110                }
111                if ( log.isDebugEnabled() )
112                {
113                    log.debug("Logged in container principal " + principal.getName() + "." );
114                }
115                m_principals.add( principal );
116    
117                return true;
118            }
119            catch( IOException e )
120            {
121                log.error( "IOException: " + e.getMessage() );
122                return false;
123            }
124            catch( UnsupportedCallbackException e )
125            {
126                log.error( "UnsupportedCallbackException: " + e.getMessage() );
127                return false;
128            }
129        }
130    }