001/*
002// This software is subject to the terms of the Eclipse Public License v1.0
003// Agreement, available at the following URL:
004// http://www.eclipse.org/legal/epl-v10.html.
005// You must accept the terms of that agreement to use this software.
006//
007// Copyright (C) 2011-2011 Pentaho and others
008// All Rights Reserved.
009*/
010package mondrian.xmla.impl;
011
012import mondrian.xmla.*;
013
014import org.w3c.dom.Element;
015
016import java.util.Map;
017import javax.servlet.ServletConfig;
018import javax.servlet.ServletException;
019import javax.servlet.http.HttpServletRequest;
020import javax.servlet.http.HttpServletResponse;
021
022/**
023 * This is an abstract implementation of {@link XmlaRequestCallback}
024 * specialized in authenticating the requests coming in. Subclasses are
025 * only required to implement {@link #authenticate(String, String, String)}.
026 *
027 * <p>Once implemented, you only need to register your class using the XMLA
028 * servlet config, within your web.xml descriptor.
029 *
030 * @author LBoudreau
031 */
032public abstract class AuthenticatingXmlaRequestCallback
033    implements XmlaRequestCallback
034{
035    public String generateSessionId(Map<String, Object> context) {
036        // We don't want to override the session ID generation algorithm.
037        return null;
038    }
039
040    public void init(ServletConfig servletConfig) throws ServletException {
041        // Nothing to initialize here. Subclasses can override
042        // this if they wish.
043    }
044
045    public void postAction(
046        HttpServletRequest request,
047        HttpServletResponse response,
048        byte[][] responseSoapParts,
049        Map<String, Object> context)
050        throws Exception
051    {
052        return;
053    }
054
055    public void preAction(
056        HttpServletRequest request,
057        Element[] requestSoapParts,
058        Map<String, Object> context)
059        throws Exception
060    {
061        /*
062         * This is where the magic happens. At this stage, we have
063         * the username/password known. We will delegate the authentication
064         * process down to the subclass.
065         */
066        final String roleNames =
067            authenticate(
068                (String) context.get(XmlaConstants.CONTEXT_XMLA_USERNAME),
069                (String) context.get(XmlaConstants.CONTEXT_XMLA_PASSWORD),
070                (String) context.get(XmlaConstants.CONTEXT_XMLA_SESSION_ID));
071        context.put(
072            XmlaConstants.CONTEXT_ROLE_NAME,
073            roleNames);
074    }
075
076    /**
077     * This function is expected to do two things.
078     * <ul>
079     * <li>Validate the credentials.</li>
080     * <li>Return a comma separated list of role names associated to
081     * these credentials.</li>
082     * </ul>
083     * <p>Should there be any problems with the credentials, subclasses
084     * can invoke {@link #throwAuthenticationException(String)} to throw
085     * an authentication exception back to the client.
086     * @param username Username used for authentication, as specified
087     * in the SOAP security header. Might be null.
088     * @param password Password used for authentication, as specified
089     * in the SOAP security header. Might be null.
090     * @param sessionID A unique identifier for this client session.
091     * Session IDs should remain the same between different queries from
092     * a same client, although some clients do not implement the XMLA
093     * Session header properly, resulting in a new session ID for each
094     * request.
095     * @return A comma separated list of roles associated to this user,
096     * or <code>null</code> for root access.
097     */
098    public abstract String authenticate(
099        String username,
100        String password,
101        String sessionID);
102
103    /**
104     * Helper method to create and throw an authentication exception.
105     * @param reason A textual explanation of why the credentials are
106     * rejected.
107     */
108    protected void throwAuthenticationException(String reason) {
109        throw new XmlaException(
110            XmlaConstants.CLIENT_FAULT_FC,
111            XmlaConstants.CHH_AUTHORIZATION_CODE,
112            XmlaConstants.CHH_AUTHORIZATION_FAULT_FS,
113            new Exception(
114                "There was a problem with the credentials: "
115                + reason));
116    }
117
118    public boolean processHttpHeader(
119        HttpServletRequest request,
120        HttpServletResponse response,
121        Map<String, Object> context)
122        throws Exception
123    {
124        // We do not perform any special header treatment.
125        return true;
126    }
127}
128// End AuthenticatingXmlaRequestCallback.java