[DS-48] shibboleth+dspace1.5.1 patch - ID: 2412723

git-svn-id: http://scm.dspace.org/svn/repo/branches/dspace-1_5_x@3642 9c30dcfa-912a-0410-8fc2-9e0234be79fd
This commit is contained in:
Mark Diggory
2009-03-27 04:53:11 +00:00
parent 6c412317f7
commit b0bf22d495
11 changed files with 935 additions and 4 deletions

View File

@@ -0,0 +1,423 @@
/*
* ShibAuthentication.java
*
* Version: $Revision$
*
* Copyright (c) 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 Hewlett-Packard Company nor the name of the
* Massachusetts Institute of Technology nor the names of their
* 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$
*/
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
{
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);
}
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)
{
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");
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();
// 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";
}
}

View File

@@ -1354,6 +1354,7 @@ org.dspace.content.Community.untitled
org.dspace.eperson.LDAPAuthentication.title = Enter LDAP Netid and Password
org.dspace.eperson.PasswordAuthentication.title = Enter DSpace Username and Password
org.dspace.eperson.X509Authentication.title = Enter DSpace using Web Certificate
org.dspace.authenticate.ShibAuthentication.title = Login via Shibboleth
org.dspace.eperson.Subscribe.authors = Authors:
org.dspace.eperson.Subscribe.id = ID:
org.dspace.eperson.Subscribe.new-items = New Items:

View File

@@ -0,0 +1,129 @@
/*
* ShibbolethFilter.java
*
* Version: $Revision$
*
* Copyright (c) 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 Hewlett-Packard Company nor the name of the
* Massachusetts Institute of Technology nor the names of their
* 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.app.webui.filter;
import java.io.IOException;
import java.sql.SQLException;
import javax.servlet.ServletException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.apache.log4j.Logger;
import org.dspace.app.webui.util.Authenticate;
import org.dspace.app.webui.util.JSPManager;
import org.dspace.app.webui.util.UIUtil;
import org.dspace.core.Context;
import org.dspace.core.LogManager;
/**
* DSpace filter that only allows requests from authenticated shib users
* to proceed. Anonymous requests prompt the authentication procedure.
*
* @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$
*/
public class ShibbolethFilter implements Filter
{
/** log4j category */
private static Logger log = Logger.getLogger(ShibbolethFilter.class);
public void init(FilterConfig config)
{
// Do nothing
}
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain)
throws ServletException, IOException
{
Context context = null;
// We need HTTP request objects
HttpServletRequest hrequest = (HttpServletRequest) request;
HttpServletResponse hresponse = (HttpServletResponse) response;
try
{
// Obtain a context
context = UIUtil.obtainContext(hrequest);
if (context.getCurrentUser() == null)
{
java.util.Enumeration names = ((HttpServletRequest) request).getHeaderNames();
String name;
while(names.hasMoreElements()) log.debug("header:"+(name = names.nextElement().toString())+"="+((HttpServletRequest)request).getHeader(name));
// No current user, prompt authentication
Authenticate.startAuthentication(context, hrequest, hresponse);
}else{
chain.doFilter(hrequest, hresponse);
return;
}
}
catch (SQLException se)
{
log.warn(LogManager.getHeader(context,
"database_error",
se.toString()), se);
JSPManager.showInternalError(hrequest, hresponse);
}
// Abort the context if it's still valid
if (context != null && context.isValid())
{
context.abort();
}
}
public void destroy()
{
// Nothing
}
}

View File

@@ -0,0 +1,119 @@
/*
* ShibbolethServlet.java
*
* Version: $Revision$
*
* Copyright (c) 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 Hewlett-Packard Company nor the name of the
* Massachusetts Institute of Technology nor the names of their
* 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.app.webui.servlet;
import java.io.IOException;
import java.sql.SQLException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import org.dspace.app.webui.util.Authenticate;
import org.dspace.app.webui.util.JSPManager;
import org.dspace.authorize.AuthorizeException;
import org.dspace.core.Context;
import org.dspace.core.LogManager;
import org.dspace.eperson.EPerson;
import org.dspace.app.webui.servlet.DSpaceServlet;
import org.dspace.authenticate.AuthenticationManager;
import org.dspace.authenticate.AuthenticationMethod;
import org.dspace.eperson.Group;
/**
* Shibbolize dspace. Follow instruction at
* http://mams.melcoe.mq.edu.au/zope/mams/pubs/Installation/dspace15
*
* Pull information from the header as released by Shibboleth target.
* The header required are:
* <ol><li>user email</li>
* <li>first name (optional)</li>
* <li>last name (optional)</li>
* <li>user roles</li>
* </ol>.
*
* All these info are configurable from the configuration file (dspace.cfg).
*
* @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$
*/
public class ShibbolethServlet extends DSpaceServlet {
/** log4j logger */
private static Logger log = Logger.getLogger(ShibbolethServlet.class);
protected void doDSGet(Context context,
HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException, SQLException, AuthorizeException {
//debugging, show all headers
java.util.Enumeration names = request.getHeaderNames();
String name;
while(names.hasMoreElements()) log.info("header:"+(name=names.nextElement().toString())+"="+request.getHeader(name));
String jsp = null;
// Locate the eperson
int status = AuthenticationManager.authenticate(context, null, null, null, request);
if (status == AuthenticationMethod.SUCCESS){
// Logged in OK.
Authenticate.loggedIn(context, request, context.getCurrentUser());
log.info(LogManager.getHeader(context, "login", "type=shibboleth"));
// resume previous request
Authenticate.resumeInterruptedRequest(request, response);
return;
}else if (status == AuthenticationMethod.CERT_REQUIRED){
jsp = "/error/require-certificate.jsp";
}else if(status == AuthenticationMethod.NO_SUCH_USER){
jsp = "/login/no-single-sign-out.jsp";
}else if(status == AuthenticationMethod.BAD_ARGS){
jsp = "/login/no-email.jsp";
}
// If we reach here, supplied email/password was duff.
log.info(LogManager.getHeader(context, "failed_login","result="+String.valueOf(status)));
JSPManager.showJSP(request, response, jsp);
return;
}
}

View File

@@ -397,6 +397,18 @@
</servlet>
<!-- shibbolized dspace -->
<servlet>
<servlet-name>shibboleth-login</servlet-name>
<servlet-class>org.dspace.app.webui.servlet.ShibbolethServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>shibboleth-login</servlet-name>
<url-pattern>/shibboleth-login</url-pattern>
</servlet-mapping>
<!-- Servlet Mappings -->
<servlet-mapping>

View File

@@ -0,0 +1,18 @@
<%--
- should be put under $DSPACE_SRC_HOME/dspace-jspui/dspace-jspui-webapp/src/main/webapp/login
- no-email.jsp
--%>
<%--
- Display message indicating that the Shibboleth target is not configured properly to release the "user" information
--%>
<%@ page contentType="text/html;charset=UTF-8" %>
<%@ taglib uri="http://www.dspace.org/dspace-tags.tld" prefix="dspace" %>
<dspace:layout title="No User email is provided">
<h1>User Email is required</h1>
<P>Your SSO system is not configured properly to release user email info</P>
</dspace:layout>

View File

@@ -0,0 +1,18 @@
<%--
- should be put under $DSPACE_SRC_HOME/dspace-jspui/dspace-jspui-webapp/src/main/webapp/login
- no-single-sign-out.jsp
--%>
<%--
- Display message indicating that the Shibboleth does not support single sign out yet
--%>
<%@ page contentType="text/html;charset=UTF-8" %>
<%@ taglib uri="http://www.dspace.org/dspace-tags.tld" prefix="dspace" %>
<dspace:layout title="Single Sign Out feature is not implemented">
<h1>Single Sign Out feature is not implemented</h1>
<P>The protection provided by Shibboleth does not have single sign out feature implemented yet. Please simply close the browser and re-open it to clear cookie</P>
</dspace:layout>

View File

@@ -0,0 +1,143 @@
/*
* ShibbolethAction.java
*
* Version: $Revision$
*
* Date: $Date$
*
* Copyright (c) 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 their
* 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.app.xmlui.aspect.eperson;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.cocoon.acting.AbstractAction;
import org.apache.cocoon.environment.ObjectModelHelper;
import org.apache.cocoon.environment.Redirector;
import org.apache.cocoon.environment.Request;
import org.apache.cocoon.environment.SourceResolver;
import org.apache.cocoon.environment.http.HttpEnvironment;
import org.apache.cocoon.sitemap.PatternException;
import org.dspace.app.xmlui.utils.AuthenticationUtil;
import org.dspace.core.ConfigurationManager;
import org.dspace.core.Context;
import org.dspace.eperson.EPerson;
/**
* Attempt to authenticate the user based upon their presented shibboleth credentials.
* This action uses the http parameters as supplied by Shibboleth SP.
* Read dspace.cfg for configuration detail.
*
* If the authentication attempt is successfull then an HTTP redirect will be
* sent to the browser redirecting them to their original location in the
* system before authenticated or if none is supplied back to the DSpace
* homepage. The action will also return true, thus contents of the action will
* be excuted.
*
* If the authentication attempt fails, the action returns false.
*
* Example use:
*
* <map:act name="Shibboleth">
* <map:serialize type="xml"/>
* </map:act>
* <map:transform type="try-to-login-again-transformer">
*
* @author <a href="mailto:bliong@melcoe.mq.edu.au">Bruc Liong, MELCOE</a>
*/
public class ShibbolethAction extends AbstractAction
{
/**
* Attempt to authenticate the user.
*/
public Map act(Redirector redirector, SourceResolver resolver, Map objectModel,
String source, Parameters parameters) throws Exception
{
try
{
//rely on implicit authN of Shib
Context context = AuthenticationUtil.Authenticate(objectModel, null, null, null);
EPerson eperson = null;
if(context != null) eperson = context.getCurrentUser();
if (eperson != null)
{
Request request = ObjectModelHelper.getRequest(objectModel);
// The user has successfully logged in
String redirectURL = request.getContextPath();
if (AuthenticationUtil.isInterupptedRequest(objectModel))
{
// Resume the request and set the redirect target URL to
// that of the originaly interrupted request.
redirectURL += AuthenticationUtil.resumeInterruptedRequest(objectModel);
}
else
{
// Otherwise direct the user to the login page
String loginRedirect = ConfigurationManager.getProperty("xmlui.user.loginredirect");
redirectURL += (loginRedirect != null) ? loginRedirect.trim() : "";
}
// Authentication successfull send a redirect.
final HttpServletResponse httpResponse = (HttpServletResponse) objectModel.get(HttpEnvironment.HTTP_RESPONSE_OBJECT);
httpResponse.sendRedirect(redirectURL);
// log the user out for the rest of this current request, however they will be reauthenticated
// fully when they come back from the redirect. This prevents caching problems where part of the
// request is preformed for the user was authenticated and the other half after it succedded. This
// way the user is fully authenticated from the start of the request.
//
// TODO: have no idea what this is, but leave it as it is, could be broken
context.setCurrentUser(null);
return new HashMap();
}
}
catch (SQLException sqle)
{
throw new PatternException("Unable to preform Shibboleth authentication",
sqle);
}
return null;
}
}

View File

@@ -70,6 +70,7 @@ registration, forgotten passwords, editing profiles, and changing passwords.
<map:actions>
<map:action name="AuthenticateAction" src="org.dspace.app.xmlui.aspect.eperson.AuthenticateAction"/>
<map:action name="ShibbolethAction" src="org.dspace.app.xmlui.aspect.eperson.ShibbolethAction"/>
<map:action name="LDAPAuthenticateAction" src="org.dspace.app.xmlui.aspect.eperson.LDAPAuthenticateAction"/>
<map:action name="UnAuthenticateAction" src="org.dspace.app.xmlui.aspect.eperson.UnAuthenticateAction"/>
<map:action name="LoginRedirect" src="org.dspace.app.xmlui.aspect.eperson.LoginRedirect" />
@@ -193,7 +194,7 @@ registration, forgotten passwords, editing profiles, and changing passwords.
</map:match>
<map:match pattern="shibboleth-login">
<map:act type="AuthenticateAction">
<map:act type="ShibbolethAction">
<!-- Loggin succeeded, request will be forwarded. -->
<map:serialize type="xml"/>
</map:act>

View File

@@ -428,7 +428,7 @@
<message key="xmlui.EPerson.LoginChooser.trail">Choose Login</message>
<message key="xmlui.EPerson.LoginChooser.head1">Choose a Login Method</message>
<message key="xmlui.EPerson.LoginChooser.para1">Log in via:</message>
<message key="au.edu.mq.melcoe.mams.dspace.eperson.ShibAuthentication.title">Shibboleth Authentication</message>
<message key="org.dspace.authenticate.ShibAuthentication.title">Shibboleth Authentication</message>
<message key="org.dspace.eperson.LDAPAuthentication.title">LDAP Authentication</message>
<message key="org.dspace.eperson.PasswordAuthentication.title">Password Authentication</message>
<message key="org.dspace.eperson.X509Authentication.title">Web Certificate Authentication</message>

View File

@@ -279,9 +279,76 @@ handle.dir = ${dspace.dir}/handle-server
# Stack of authentication methods
# (See org.dspace.authenticate.AuthenticationManager)
# Example:
# plugin.sequence.org.dspace.authenticate.AuthenticationMethod = \
# org.dspace.authenticate.ShibAuthentication, \
# org.dspace.authenticate.PasswordAuthentication
plugin.sequence.org.dspace.authenticate.AuthenticationMethod = \
org.dspace.authenticate.PasswordAuthentication
#### Shibboleth Authentication Configuration Settings ####
# Check https://mams.melcoe.mq.edu.au/zope/mams/pubs/Installation/dspace15/view
# for installation detail.
#
# DSpace requires email as user's credential. There are 2 ways of providing
# email to DSpace:
# 1) by explicitly specifying to the user which attribute (header)
# carries the email address.
# 2) by turning on the user-email-using-tomcat=true which means
# the software will try to acquire the user's email from Tomcat
# The first option takes PRECEDENCE when specified. Both options can
# be enabled to allow fallback.
# this option below specifies that the email comes from the mentioned header.
# The value is CASE-Sensitive.
authentication.shib.email-header = MAIL
# optional. Specify the header that carries user's first name
# this is going to be used for creation of new-user
authentication.shib.firstname-header = SHIB-EP-GIVENNAME
# optional. Specify the header that carries user's last name
# this is used for creation of new user
authentication.shib.lastname-header = SHIB-EP-SURNAME
# this option below forces the software to acquire the email from Tomcat.
authentication.shib.email-use-tomcat-remote-user = true
# should we allow new users to be registered automtically
# if the IdP provides sufficient info (and user not exists in DSpace)
authentication.shib.autoregister = true
# this header here specifies which attribute that is responsible
# for providing user's roles to DSpace. When not specified, it is
# defaulted to 'Shib-EP-UnscopedAffiliation'. The value is specified
# in AAP.xml (Shib 1.3.x) or attribute-filter.xml (Shib 2.x).
# The value is CASE-Sensitive. The values provided in this
# header are separated by semi-colon or comma.
# authentication.shib.role-header = Shib-EP-UnscopedAffiliation
# when user is fully authN on IdP but would not like to release
# his/her roles to DSpace (for privacy reason?), what should be
# the default roles be given to such users?
# The values are separated by semi-colon or comma
# authentication.shib.default-roles = Staff, Walk-ins
# The following mappings specify role mapping between IdP and Dspace.
# the left side of the entry is IdP's role (prefixed with
# "authentication.shib.role.") which will be mapped to
# the right entry from DSpace. DSpace's group as indicated on the
# right entry has to EXIST in DSpace, otherwise user will be identified
# as 'anonymous'. Multiple values on the right entry should be separated
# by comma. The values are CASE-Sensitive. Heuristic one-to-one mapping
# will be done when the IdP groups entry are not listed below (i.e.
# if "X" group in IdP is not specified here, then it will be mapped
# to "X" group in DSpace if it exists, otherwise it will be mapped
# to simply 'anonymous')
#
# Given sufficient demand, future release could support regex for the mapping
# special characters need to be escaped by \
authentication.shib.role.Senior\ Researcher = Researcher, Staff
authentication.shib.role.Librarian = Administrator
#### PasswordAuthentication options ####
# Only emails ending in the following domains are allowed to self-register