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.UnsupportedCallbackException;
025    import javax.security.auth.login.FailedLoginException;
026    import javax.security.auth.login.LoginException;
027    import javax.servlet.http.Cookie;
028    import javax.servlet.http.HttpServletRequest;
029    import javax.servlet.http.HttpServletResponse;
030    import javax.servlet.http.HttpSession;
031    
032    import org.apache.log4j.Logger;
033    import org.apache.wiki.auth.WikiPrincipal;
034    import org.apache.wiki.util.HttpUtil;
035    import org.apache.wiki.util.TextUtil;
036    
037    /**
038     * <p>
039     * Logs in a user based on assertion of a name supplied in a cookie. If the
040     * cookie is not found, authentication fails.
041     * </p>
042     * This module must be used with a CallbackHandler (such as
043     * {@link WebContainerCallbackHandler}) that supports the following Callback
044     * types:
045     * </p>
046     * <ol>
047     * <li>{@link HttpRequestCallback}- supplies the cookie, which should contain
048     * a user name.</li>
049     * </ol>
050     * <p>
051     * After authentication, a generic WikiPrincipal based on the username will be
052     * created and associated with the Subject.
053     * </p>
054     * @see javax.security.auth.spi.LoginModule#commit()
055     * @see CookieAuthenticationLoginModule
056     * @since 2.3
057     */
058    public class CookieAssertionLoginModule extends AbstractLoginModule
059    {
060    
061        /** The name of the cookie that gets stored to the user browser. */
062        public static final String PREFS_COOKIE_NAME = "JSPWikiAssertedName";
063    
064        /** Believed to be unused.
065         *  @deprecated */
066        public static final String PROMPT            = "User name";
067    
068        protected static final Logger    log         = Logger.getLogger( CookieAssertionLoginModule.class );
069    
070        /**
071         * Logs in the user by calling back to the registered CallbackHandler with
072         * an HttpRequestCallback. The CallbackHandler must supply the current
073         * servlet HTTP request as its response.
074         * @return the result of the login; if a cookie is
075         * found, this method returns <code>true</code>. If not found, this
076         * method throws a <code>FailedLoginException</code>.
077         * @see javax.security.auth.spi.LoginModule#login()
078         * @throws {@inheritDoc}
079         */
080        public boolean login() throws LoginException
081        {
082            // Otherwise, let's go and look for the cookie!
083            HttpRequestCallback hcb = new HttpRequestCallback();
084            Callback[] callbacks = new Callback[]
085            { hcb };
086            try
087            {
088                m_handler.handle( callbacks );
089                HttpServletRequest request = hcb.getRequest();
090                HttpSession session = ( request == null ) ? null : request.getSession( false );
091                String sid = ( session == null ) ? NULL : session.getId();
092                String name = (request != null) ? getUserCookie( request ) : null;
093                if ( name == null )
094                {
095                    if ( log.isDebugEnabled() )
096                    {
097                        log.debug( "No cookie " + PREFS_COOKIE_NAME + " present in session ID=:  " + sid );
098                    }
099                    throw new FailedLoginException( "The user cookie was not found." );
100                }
101    
102                if ( log.isDebugEnabled() )
103                {
104                    log.debug( "Logged in session ID=" + sid + "; asserted=" + name );
105                }
106                // If login succeeds, commit these principals/roles
107                m_principals.add( new WikiPrincipal( name, WikiPrincipal.FULL_NAME ) );
108                return true;
109            }
110            catch( IOException e )
111            {
112                log.error( "IOException: " + e.getMessage() );
113                return false;
114            }
115            catch( UnsupportedCallbackException e )
116            {
117                String message = "Unable to handle callback, disallowing login.";
118                log.error( message, e );
119                throw new LoginException( message );
120            }
121    
122        }
123    
124        /**
125         *  Returns the username cookie value.
126         *
127         *  @param request The Servlet request, as usual.
128         *  @return the username, as retrieved from the cookie
129         */
130        public static String getUserCookie( HttpServletRequest request )
131        {
132            String cookie = HttpUtil.retrieveCookieValue( request, PREFS_COOKIE_NAME );
133    
134            return TextUtil.urlDecodeUTF8(cookie);
135        }
136    
137        /**
138         *  Sets the username cookie.  The cookie value is URLEncoded in UTF-8.
139         *
140         *  @param response The Servlet response
141         *  @param name     The name to write into the cookie.
142         */
143        public static void setUserCookie( HttpServletResponse response, String name )
144        {
145            name = TextUtil.urlEncodeUTF8(name);
146            Cookie userId = new Cookie( PREFS_COOKIE_NAME, name );
147            userId.setMaxAge( 1001 * 24 * 60 * 60 ); // 1001 days is default.
148            response.addCookie( userId );
149        }
150    
151        /**
152         *  Removes the user cookie from the response.  This makes the user appear
153         *  again as an anonymous coward.
154         *
155         *  @param response The servlet response.
156         */
157        public static void clearUserCookie( HttpServletResponse response )
158        {
159            Cookie userId = new Cookie( PREFS_COOKIE_NAME, "" );
160            userId.setMaxAge( 0 );
161            response.addCookie( userId );
162        }
163    }