Package org.dspace.authenticate

Source Code of org.dspace.authenticate.ShibAuthentication

/*
* ShibAuthentication.java
*
* Version: $Revision: 4637 $
*
* Copyright (c) 2002-2009, The DSpace Foundation.  All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the DSpace Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/

package org.dspace.authenticate;

import java.sql.SQLException;
import javax.servlet.http.HttpServletRequest;
import java.util.Collection;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.dspace.authorize.AuthorizeException;

import org.dspace.core.Context;
import org.dspace.core.ConfigurationManager;
import org.dspace.core.LogManager;
import org.dspace.authenticate.AuthenticationManager;
import org.dspace.authenticate.AuthenticationMethod;
import org.dspace.eperson.EPerson;
import org.dspace.eperson.Group;

/**
* Shibboleth authentication for DSpace, tested on Shibboleth 1.3.x and
* Shibboleth 2.x. Read <a href=
* "https://mams.melcoe.mq.edu.au/zope/mams/pubs/Installation/dspace15/view"
* >Shib DSpace 1.5</a> for installation procedure. Read dspace.cfg for details
* on options available.
*
* @author <a href="mailto:bliong@melcoe.mq.edu.au">Bruc Liong, MELCOE</a>
* @author <a href="mailto:kli@melcoe.mq.edu.au">Xiang Kevin Li, MELCOE</a>
* @version $Revision: 4637 $
*/
public class ShibAuthentication implements AuthenticationMethod
{
    /** log4j category */
    private static Logger log = Logger.getLogger(ShibAuthentication.class);

    public int authenticate(Context context, String username, String password,
            String realm, HttpServletRequest request) throws SQLException
    {
        if (request == null)
        {
            return BAD_ARGS;
        }
        log.info("Shibboleth login started...");

        java.util.Enumeration names = request.getHeaderNames();
        String name;
        while (names.hasMoreElements())
            log.debug("header:" + (name = names.nextElement().toString()) + "="
                    + request.getHeader(name));

        boolean isUsingTomcatUser = ConfigurationManager
                .getBooleanProperty("authentication.shib.email-use-tomcat-remote-user");
        String emailHeader = ConfigurationManager
                .getProperty("authentication.shib.email-header");
        String fnameHeader = ConfigurationManager
                .getProperty("authentication.shib.firstname-header");
        String lnameHeader = ConfigurationManager
                .getProperty("authentication.shib.lastname-header");

        String email = null;
        String fname = null;
        String lname = null;

        if (emailHeader != null)
        {
            // try to grab email from the header
            email = request.getHeader(emailHeader);

            // fail, try lower case
            if (email == null)
                email = request.getHeader(emailHeader.toLowerCase());
        }

        // try to pull the "REMOTE_USER" info instead of the header
        if (email == null && isUsingTomcatUser)
        {
            email = request.getRemoteUser();
            log.info("RemoteUser identified as: " + email);
        }

        // No email address, perhaps the eperson has been setup, better check it
        if (email == null)
        {
            EPerson p = context.getCurrentUser();
            if (p != null)
                email = p.getEmail();
        }

        if (email == null)
        {
            log
                    .error("No email is given, you're denied access by Shib, please release email address");
            return AuthenticationMethod.BAD_ARGS;
        }

        email = email.toLowerCase();

        if (fnameHeader != null)
        {
            // try to grab name from the header
            fname = request.getHeader(fnameHeader);

            // fail, try lower case
            if (fname == null)
                fname = request.getHeader(fnameHeader.toLowerCase());
        }
        if (lnameHeader != null)
        {
            // try to grab name from the header
            lname = request.getHeader(lnameHeader);

            // fail, try lower case
            if (lname == null)
                lname = request.getHeader(lnameHeader.toLowerCase());
        }

        // future version can offer auto-update feature, this needs testing
        // before inclusion to core code

        EPerson eperson = null;
        try
        {
            eperson = EPerson.findByEmail(context, email);
            context.setCurrentUser(eperson);
        }
        catch (AuthorizeException e)
        {
            log.warn("Fail to locate user with email:" + email, e);
            eperson = null;
        }

        // auto create user if needed
        if (eperson == null
                && ConfigurationManager
                        .getBooleanProperty("authentication.shib.autoregister"))
        {
            log.info(LogManager.getHeader(context, "autoregister", "email="
                    + email));

            // TEMPORARILY turn off authorisation
            context.setIgnoreAuthorization(true);
            try
            {
                eperson = EPerson.create(context);
                eperson.setEmail(email);
                if (fname != null)
                    eperson.setFirstName(fname);
                if (lname != null)
                    eperson.setLastName(lname);
                eperson.setCanLogIn(true);
                AuthenticationManager.initEPerson(context, request, eperson);
                eperson.update();
                context.commit();
                context.setCurrentUser(eperson);
            }
            catch (AuthorizeException e)
            {
                log.warn("Fail to authorize user with email:" + email, e);
                eperson = null;
            }
            finally
            {
                context.setIgnoreAuthorization(false);
            }
        }

        if (eperson == null)
        {
            return AuthenticationMethod.NO_SUCH_USER;
        }
        else
        {
            // the person exists, just return ok
            context.setCurrentUser(eperson);
            request.getSession().setAttribute("shib.authenticated",
                    new Boolean("true"));
        }

        return AuthenticationMethod.SUCCESS;
    }

    /**
     * Grab the special groups to be automatically provisioned for the current
     * user. Currently the mapping for the groups is done one-to-one, future
     * version can consider the usage of regex for such mapping.
     */
    public int[] getSpecialGroups(Context context, HttpServletRequest request)
    {
        // no user logged in or user not logged from shibboleth
        if (request == null || context.getCurrentUser() == null
                || request.getSession().getAttribute("shib.authenticated") == null)
        {
            return new int[0];
        }
               
        if (request.getSession().getAttribute("shib.specialgroup") != null)
        {
            return (int[]) request.getSession().getAttribute(
                    "shib.specialgroup");
        }

        java.util.Set groups = new java.util.HashSet();
        String roleHeader = ConfigurationManager
                .getProperty("authentication.shib.role-header");
        boolean roleHeader_ignoreScope = ConfigurationManager
                .getBooleanProperty("authentication.shib.role-header.ignore-scope");
        if (roleHeader == null || roleHeader.trim().length() == 0)
            roleHeader = "Shib-EP-UnscopedAffiliation"; // fall back to default
        String affiliations = request.getHeader(roleHeader);

        // try again with all lower case...maybe has better luck
        if (affiliations == null)
            affiliations = request.getHeader(roleHeader.toLowerCase());

        // default role when fully authN but not releasing any roles?
        String defaultRoles = ConfigurationManager
                .getProperty("authentication.shib.default-roles");
        if (affiliations == null && defaultRoles != null)
        {
            affiliations = defaultRoles;
        }

        if (affiliations != null)
        {
            java.util.StringTokenizer st = new java.util.StringTokenizer(
                    affiliations, ";,");
            // do the mapping here
            while (st.hasMoreTokens())
            {
                String affiliation = st.nextToken().trim();

                // strip scope if present and roleHeader_ignoreScope
                if (roleHeader_ignoreScope)
                {
                        int index = affiliation.indexOf("@");
                        if (index != -1) affiliation = affiliation.substring(0,index);
                }

                // perform mapping here if necessary
                String groupLabels = ConfigurationManager
                        .getProperty("authentication.shib.role." + affiliation);
                if (groupLabels == null || groupLabels.trim().length() == 0)
                    groupLabels = ConfigurationManager
                            .getProperty("authentication.shib.role."
                                    + affiliation.toLowerCase());

                // revert back to original entry when no mapping is provided
                if (groupLabels == null)
                    groupLabels = affiliation;

                String[] labels = groupLabels.split(",");
                for (int i = 0; i < labels.length; i++)
                    addGroup(groups, context, labels[i].trim());
            }
        }

        int ids[] = new int[groups.size()];
        java.util.Iterator it = groups.iterator();
        for (int i = 0; it.hasNext(); i++)
            ids[i] = ((Integer) it.next()).intValue();

        // store the special group, if already transformed from headers
        // since subsequent header may not have the values anymore
        if (ids.length != 0)
        {
            request.getSession().setAttribute("shib.specialgroup", ids);
        }

        return ids;
    }

    /** Find dspaceGroup in DSpace database, if found, include it into groups */
    private void addGroup(Collection groups, Context context, String dspaceGroup)
    {
        try
        {
            Group g = Group.findByName(context, dspaceGroup);
            if (g == null)
            {
                // oops - no group defined
                log.warn(LogManager.getHeader(context, dspaceGroup
                        + " group is not found!! Admin needs to create one!",
                        "requiredGroup=" + dspaceGroup));
                groups.add(new Integer(0));
            }
            else
            {
                groups.add(new Integer(g.getID()));
            }
            log.info("Mapping group: " + dspaceGroup + " to groupID: "
                    + (g == null ? 0 : g.getID()));
        }
        catch (SQLException e)
        {
            log.error("Mapping group:" + dspaceGroup + " failed with error", e);
        }
    }

    /**
     * Indicate whether or not a particular self-registering user can set
     * themselves a password in the profile info form.
     *
     * @param context
     *            DSpace context
     * @param request
     *            HTTP request, in case anything in that is used to decide
     * @param email
     *            e-mail address of user attempting to register
     *
     */
    public boolean allowSetPassword(Context context,
            HttpServletRequest request, String email) throws SQLException
    {
        // don't use password at all
        return false;
    }

    /**
     * Predicate, is this an implicit authentication method. An implicit method
     * gets credentials from the environment (such as an HTTP request or even
     * Java system properties) rather than the explicit username and password.
     * For example, a method that reads the X.509 certificates in an HTTPS
     * request is implicit.
     *
     * @return true if this method uses implicit authentication.
     */
    public boolean isImplicit()
    {
        return true;
    }

    /**
     * Indicate whether or not a particular user can self-register, based on
     * e-mail address.
     *
     * @param context
     *            DSpace context
     * @param request
     *            HTTP request, in case anything in that is used to decide
     * @param email
     *            e-mail address of user attempting to register
     *
     */
    public boolean canSelfRegister(Context context, HttpServletRequest request,
            String username) throws SQLException
    {
        return true;
    }

    /**
     * Initialise a new e-person record for a self-registered new user.
     *
     * @param context
     *            DSpace context
     * @param request
     *            HTTP request, in case it's needed
     * @param eperson
     *            newly created EPerson record - email + information from the
     *            registration form will have been filled out.
     *
     */
    public void initEPerson(Context context, HttpServletRequest request,
            EPerson eperson) throws SQLException
    {

    }

    /**
     * Get login page to which to redirect. Returns URL (as string) to which to
     * redirect to obtain credentials (either password prompt or e.g. HTTPS port
     * for client cert.); null means no redirect.
     *
     * @param context
     *            DSpace context, will be modified (ePerson set) upon success.
     *
     * @param request
     *            The HTTP request that started this operation, or null if not
     *            applicable.
     *
     * @param response
     *            The HTTP response from the servlet method.
     *
     * @return fully-qualified URL or null
     */
    public String loginPageURL(Context context, HttpServletRequest request,
            HttpServletResponse response)
    {
        return response.encodeRedirectURL(request.getContextPath()
                + "/shibboleth-login");
    }

    /**
     * Get title of login page to which to redirect. Returns a <i>message
     * key</i> that gets translated into the title or label for "login page" (or
     * null, if not implemented) This title may be used to identify the link to
     * the login page in a selection menu, when there are multiple ways to
     * login.
     *
     * @param context
     *            DSpace context, will be modified (ePerson set) upon success.
     *
     * @return title text.
     */
    public String loginPageTitle(Context context)
    {
        return "org.dspace.authenticate.ShibAuthentication.title";
    }
}
TOP

Related Classes of org.dspace.authenticate.ShibAuthentication

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.