org.apache.jetspeed.modules.actions.NTLMSessionValidator.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.jetspeed.modules.actions.NTLMSessionValidator.java

Source

/*
 * Copyright 2000-2004 The Apache Software Foundation.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.jetspeed.modules.actions;

// JDK stuff
import java.util.Locale;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.codec.binary.Base64;
import org.apache.jetspeed.om.security.JetspeedUser;
import org.apache.jetspeed.services.JetspeedSecurity;
import org.apache.jetspeed.services.customlocalization.CustomLocalizationService;
import org.apache.jetspeed.services.logging.JetspeedLogFactoryService;
import org.apache.jetspeed.services.logging.JetspeedLogger;
import org.apache.jetspeed.services.rundata.JetspeedRunData;
import org.apache.jetspeed.services.security.JetspeedSecurityCache;
import org.apache.jetspeed.services.security.LoginException;
import org.apache.jetspeed.services.security.UnknownUserException;
import org.apache.jetspeed.util.ServiceUtil;
import org.apache.turbine.services.localization.LocalizationService;
import org.apache.turbine.services.resources.TurbineResources;
import org.apache.turbine.util.RunData;

/**
 * Just like org.apache.turbine.modules.actions.sessionvalidator.
 * TemplateSessionValidator except:
 * <ul>
 * <li>it doesn't check the session_access_counter
 * <li>it automatically logs the user in based on currently authenticated nt
 * user
 * <li>expects a JetspeedRunData object and put there the additionnal jetspeed
 * properties
 * </ul>
 * <B>Usage of this session validator is limited to Windows NT/2000 and MS
 * Internet Explorer.</B>
 * <P>
 * To activate this session validator, set <CODE>action.sessionvalidator</CODE>
 * in tr.props to <code>NTLMSessionValidator</code>.
 * </P>
 * <P>
 * When this session validator is active, the following algorithm is used to
 * display appropriate psml:
 * 
 * <pre>
 * Check authentication status
 * If user is not authenticated to machine running the portal
 *      Pop the standard login box
 *      If user passes authentication
 *           Attempt to retrieve matching user profile
 *           If matching profile found
 *                Render the profile
 *           Else
 *                Retrieve and render anonymous profile
 *           End
 *      Else If authentication fails
 *           Keep prompting for login information
 *      Else If the user cancels the login box
 *           Retrieve and render anonymous profile
 *      End
 * Else
 *      Attempt to retrieve matching user profile
 *      If matching profile found
 *           Render the profile
 *      Else
 *           Retrieve and render anonymous profile
 *      End
 * End
 * </pre>
 * 
 * </P>
 * <P>
 * Optionally, certain characters may be removed from the username before it's
 * passed to the JetspeedSecurity. These characters may be specified by setting
 * <CODE>NTLMSessionValidator.chars.to.remove</CODE> property. For example, if
 * invalid characters list is '#@$', username '#user1' will be returned as
 * 'user1'.
 * </P>
 * 
 * @author <a href="mailto:morciuch@apache.org">Mark Orciuch</a>
 * @version $Id: NTLMSessionValidator.java,v 1.6 2004/02/23 02:59:06 jford Exp $
 * @see org.apache.turbine.modules.actions.sessionvalidator.TemplateSessionValidator
 * @see http://www.innovation.ch/java/ntlm.html
 * @since 1.4b5
 */
public class NTLMSessionValidator extends TemplateSessionValidator {

    private static final String INVALID_CHARS_KEY = "NTLMSessionValidator.chars.to.remove";

    private final String invalidChars = org.apache.jetspeed.services.resources.JetspeedResources
            .getString(INVALID_CHARS_KEY, null);

    private static final byte z = 0;

    private static final byte[] msg1 = { (byte) 'N', (byte) 'T', (byte) 'L', (byte) 'M', (byte) 'S', (byte) 'S',
            (byte) 'P', z, (byte) 2, z, z, z, z, z, z, z, (byte) 40, z, z, z, (byte) 1, (byte) 130, z, z, z,
            (byte) 2, (byte) 2, (byte) 2, z, z, z, z, z, z, z, z, z, z, z, z };

    private static final String encodedMsg1 = "NTLM " + new String(Base64.encodeBase64(msg1));

    /**
     * Static initialization of the logger for this class
     */
    private static final JetspeedLogger logger = JetspeedLogFactoryService
            .getLogger(NTLMSessionValidator.class.getName());

    /**
     * Execute the action.
     * 
     * @param data
     *          Turbine information.
     * @exception Exception
     *              , a generic exception.
     */
    @Override
    public void doPerform(RunData data) throws Exception {
        // first, invoke our superclass action to make sure
        // we follow Turbine evolutions
        // FIXME: if the user is not found (this can happen, for instance,
        // if the anonymous user is not in the DB), it throws a terrible exception
        // in the user's face
        super.doPerform(data);

        JetspeedUser user = (JetspeedUser) data.getUser();

        // get remote user from ntlm
        String userName = this.getRemoteUser(data);

        if ((user == null || !user.hasLoggedIn())) {
            if (userName != null && userName.length() > 0) {
                byte[] temp = userName.getBytes();
                StringBuffer buffer = new StringBuffer();
                for (int i = 0; i < temp.length; i++) {
                    if (temp[i] != 0) {
                        if (invalidChars == null || invalidChars.indexOf(temp[i]) < 0) {
                            buffer.append((char) temp[i]);
                        }
                    }
                }
                userName = buffer.toString();
                try {
                    user = JetspeedSecurity.getUser(userName);
                    data.setUser(user);
                    user.setHasLoggedIn(new Boolean(true));
                    user.updateLastLogin();
                    data.save();
                    if (JetspeedSecurityCache.getAcl(userName) == null) {
                        JetspeedSecurityCache.load(userName);
                    }
                    logger.info("NTLMSessionValidator: automatic login using [" + userName + "]");
                } catch (LoginException noSuchUser) {
                    // user not found - ignore it - they will not be logged in
                    // automatically
                } catch (UnknownUserException unknownUser) {
                    // user not found - ignore it - they will not be logged in
                    // automatically
                    if (logger.isWarnEnabled()) {
                        logger.warn("NTLMSessionValidator: username [" + userName
                                + "] does not exist or authentication failed, " + "redirecting to anon profile");
                    }
                }
            }
        }

        // now, define Jetspeed specific properties, using the customized
        // RunData properties
        JetspeedRunData jdata = null;

        try {
            jdata = (JetspeedRunData) data;
        } catch (ClassCastException e) {
            logger.error("The RunData object does not implement the expected interface, "
                    + "please verify the RunData factory settings");
            return;
        }
        String language = data.getRequest().getParameter("js_language");

        if (null != language) {
            user.setPerm("language", language);
        }

        // Get the locale store it in the user object
        CustomLocalizationService locService = (CustomLocalizationService) ServiceUtil
                .getServiceByName(LocalizationService.SERVICE_NAME);
        Locale locale = locService.getLocale(data);
        if (locale == null) {
            locale = new Locale(TurbineResources.getString("locale.default.language", "en"),
                    TurbineResources.getString("locale.default.country", "US"));
        }

        data.getUser().setTemp("locale", locale);

        // if a portlet is referenced in the parameters request, store it
        // in the RunData object
        String paramPortlet = jdata.getParameters().getString("js_peid");
        if (paramPortlet != null && paramPortlet.length() > 0) {
            jdata.setJs_peid(paramPortlet);
        }

    }

    /**
     * This session validator does not require a new session for each request
     * 
     * @param data
     * @return
     */
    @Override
    public boolean requiresNewSession(RunData data) {
        return false;
    }

    /**
     * Extracts user name from http headers
     * 
     * @param data
     * @return
     * @exception Exception
     */
    private String getRemoteUser(RunData data) throws Exception {
        HttpServletRequest request = data.getRequest();
        HttpServletResponse response = data.getResponse();

        if (data.getUser().hasLoggedIn() && request.getMethod().equalsIgnoreCase("get")) {
            return data.getUser().getUserName();
        }

        String auth = request.getHeader("Authorization");
        if (auth == null) {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.setHeader("WWW-Authenticate", "NTLM");
            response.flushBuffer();

            return null;
        }
        if (auth.startsWith("NTLM ")) {

            byte[] msg = Base64.decodeBase64(auth.substring(5).getBytes());
            int off = 0, length, offset;

            if (msg[8] == 1) {
                response.setHeader("WWW-Authenticate", encodedMsg1);
                response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);

                return null;
            } else if (msg[8] == 3) {
                if (data.getUser().hasLoggedIn()) {
                    return data.getUser().getUserName();
                }

                off = 30;

                // length = msg[off + 17] * 256 + msg[off + 16];
                // offset = msg[off + 19] * 256 + msg[off + 18];
                // String remoteHost = new String(msg, offset, length);

                // length = msg[off + 1] * 256 + msg[off];
                // offset = msg[off + 3] * 256 + msg[off + 2];
                // String domain = new String(msg, offset, length);

                length = msg[off + 9] * 256 + msg[off + 8];
                offset = msg[off + 11] * 256 + msg[off + 10];
                String username = new String(msg, offset, length);

                return username;
            }

        }

        return null;
    }
}