04-30-2007 06:18 PM
05-09-2007 06:46 AM
07-23-2007 08:10 AM
07-24-2007 06:47 AM
03-19-2008 07:39 AM
05-16-2008 07:18 AM
Hi, we are also interested in the use of Shibboleth with Alfresco.Hi Denis,
Have you made some progress on this ?
Denis
package org.alfresco.web.app.servlet;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.repo.security.authentication.AuthenticationException;
import org.alfresco.repo.security.authentication.MutableAuthenticationDao;
import org.alfresco.repo.webservice.administration.NewUserDetails;
import org.alfresco.repo.webservice.types.NamedValue;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.security.AuthenticationService;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.cmr.search.ResultSet;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.web.bean.LoginBean;
import org.alfresco.web.bean.repository.User;
import org.alfresco.web.app.Application;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.transaction.UserTransaction;
import javax.transaction.SystemException;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.util.*;
/**
*
*
* @author Kimmo Ilppola
*/
public class ShibbolethHTTPRequestAuthenticationFilter extends AbstractAuthenticationFilter implements Filter
{
/** Location of configuration file on classpath */
private final static String PROPERTY_FILE = "/shibbolethAttributes.properties";
private static Properties CONFIG_PROPERTIES;
/* Name of header properties */
private final static String SHIB_USER = "header.username";
private final static String FIRSTNAME_HEADER_NAME_PROPERTY = "header.firstname";
private final static String LASTNAME_HEADER_NAME_PROPERTY = "header.lastname";
private final static String ORGID_HEADER_NAME_PROPERTY = "header.orgId";
private final static String EMAIL_HEADER_NAME_PROPERTY = "header.email";
private final static String LOGOUT_URL_HEADER_NAME_PROPERTY = "header.logout-url";
private static String shibUserNameHeaderName = "Shib-InetOrgPerson-uid";
private static String firstNameHeaderName = "Shib-InetOrgPerson-givenName";
private static String lastNameHeaderName = "Shib-InetOrgPerson-cn";
private static String emailHeaderName = "Shib-InetOrgPerson-mail";
private static String orgIdNumHeaderName = "Shib-InetOrgPerson-ou";
private static String logoutUrlHeaderName = "logout-url";
private static Log logger = LogFactory.getLog(ShibbolethHTTPRequestAuthenticationFilter.class);
private ServletContext context;
private AuthenticationComponent authComponent;
private AuthenticationService authService;
private TransactionService transactionService;
private PersonService personService;
private NodeService nodeService;
private MutableAuthenticationDao authenticationDao;
private SearchService searchService;
private String loginPage = null;
public ShibbolethHTTPRequestAuthenticationFilter()
{
super();
if (logger.isDebugEnabled()) {
logger.debug("Initializing shibboleth authenticator using property file " + PROPERTY_FILE);
}
InputStream propsIn = ShibbolethHTTPRequestAuthenticationFilter.class.getResourceAsStream(PROPERTY_FILE);
CONFIG_PROPERTIES = new Properties();
try {
CONFIG_PROPERTIES.load(propsIn);
shibUserNameHeaderName = CONFIG_PROPERTIES.getProperty(SHIB_USER);
firstNameHeaderName = CONFIG_PROPERTIES.getProperty(FIRSTNAME_HEADER_NAME_PROPERTY);
lastNameHeaderName = CONFIG_PROPERTIES.getProperty(LASTNAME_HEADER_NAME_PROPERTY);
emailHeaderName = CONFIG_PROPERTIES.getProperty(EMAIL_HEADER_NAME_PROPERTY);
orgIdNumHeaderName = CONFIG_PROPERTIES.getProperty(ORGID_HEADER_NAME_PROPERTY);
logoutUrlHeaderName = CONFIG_PROPERTIES.getProperty(LOGOUT_URL_HEADER_NAME_PROPERTY);
} catch (IOException e) {
logger.warn("ShibbolethHTTPRequestAuthenticationFilter is unable to read properties file, using default properties", e);
}
}
public void destroy()
{
// Nothing to do
}
/**
* Run the filter
*
* @param sreq
* ServletRequest
* @param sresp
* ServletResponse
* @param chain
* FilterChain
* @exception IOException
* @exception ServletException
*/
public void doFilter(ServletRequest sreq, ServletResponse sresp, FilterChain chain) throws IOException,
ServletException
{
// Get the HTTP request/response/session
HttpServletRequest req = (HttpServletRequest) sreq;
HttpServletResponse resp = (HttpServletResponse) sresp;
HttpSession httpSess = req.getSession(true);
String authHdr = req.getHeader( shibUserNameHeaderName );
if(logger.isDebugEnabled()) {
logger.debug("ShibbolethHTTPRequestAuthenticationFilter uri: "+req.getRequestURI()+", authHdr: "+authHdr);
}
// Throw an error if we have an unknown authentication
if ((authHdr == null) || (authHdr.length() < 1))
{
resp.sendRedirect(req.getContextPath() + "/jsp/noaccess.jsp");
BaseServlet.redirectToLoginPage((HttpServletRequest)sreq, (HttpServletResponse)sresp, context);
chain.doFilter(sreq, sresp);
return;
}
// redirect login/logout to shibboleth logout url
// todo: this doesn't work yet
if (req.getRequestURI().endsWith(getLoginPage())) {
resp.sendRedirect( req.getHeader(logoutUrlHeaderName) );
return;
}
// See if there is a user in the session and test if it matches
User user = (User) httpSess.getAttribute(AuthenticationHelper.AUTHENTICATION_USER);
if (user != null)
{
try
{
// Debug
if (logger.isDebugEnabled())
logger.debug("User " + user.getUserName() + " validate ticket");
// Validate the user. Shibboleth allready validates the ticket so we just need to check the userName
// todo : is this validation reduntant?
if (user.getUserName().equals(authHdr))
{
authComponent.setCurrentUser(user.getUserName());
chain.doFilter(sreq, sresp);
return;
}
else
{
// No match
setAuthenticatedUser(req, httpSess, authHdr);
}
}
catch (Throwable ex)
{
if (logger.isErrorEnabled())
logger.error("Failed to validate user " + user.getUserName(), ex);
}
}
setAuthenticatedUser(req, httpSess, authHdr);
chain.doFilter(sreq, sresp);
return;
}
/**
* Set the authenticated user.
*
* @param req
* @param httpSess
* @param userName
*/
private void setAuthenticatedUser(HttpServletRequest req, HttpSession httpSess, String userName)
{
// shibboleth does not provide any other means to import users
addShibUser(req,httpSess);
UserTransaction atx = transactionService.getUserTransaction();
try {
atx.begin();
// Set the authentication
authComponent.setCurrentUser(userName);
atx.commit();
} catch (Throwable e) {
logger.error(e);
try {
atx.rollback();
} catch (SystemException e1) {
logger.error("Failed to rollback transaction", e);
}
}
// Set up the user information
// Note that we have to create users here as we have no other way of retrieving user-attributes
UserTransaction tx = transactionService.getUserTransaction();
NodeRef homeSpaceRef = null;
User user;
try
{
tx.begin();
user = new User(userName, authService.getCurrentTicket(), personService.getPerson(userName));
homeSpaceRef = (NodeRef) nodeService.getProperty(personService.getPerson(userName),
ContentModel.PROP_HOMEFOLDER);
user.setHomeSpaceId(homeSpaceRef.getId());
tx.commit();
}
catch (Throwable ex)
{
logger.error(ex);
try
{
tx.rollback();
}
catch (Exception ex2)
{
logger.error("Failed to rollback transaction", ex2);
}
if(ex instanceof RuntimeException)
{
throw (RuntimeException)ex;
}
else
{
throw new RuntimeException("Failed to set authenticated user", ex);
}
}
// Store the user
httpSess.setAttribute(AuthenticationHelper.AUTHENTICATION_USER, user);
httpSess.setAttribute(LoginBean.LOGIN_EXTERNAL_AUTH, Boolean.TRUE);
}
protected NodeRef getCompanyHome()
{
StoreRef storeRef = new StoreRef(StoreRef.PROTOCOL_WORKSPACE, "SpacesStore");
ResultSet resultSet = searchService.query(storeRef, SearchService.LANGUAGE_LUCENE, "PATH:\"/app:company_home\"");
return resultSet.getNodeRef(0);
}
/**
* @return The login page url
*/
private String getLoginPage()
{
if (this.loginPage == null)
{
this.loginPage = Application.getLoginPage(this.context);
}
return this.loginPage;
}
private boolean addShibUser(HttpServletRequest req, HttpSession httpSess) {
// get all properties from header
String userName = req.getHeader( shibUserNameHeaderName );
String orgId = req.getHeader(orgIdNumHeaderName);
String firstName = req.getHeader(firstNameHeaderName);
String lastName = req.getHeader(lastNameHeaderName);
String email = req.getHeader( emailHeaderName );
// Create a new authentication
try {
// todo: passwords should not be stored!
authService.createAuthentication(userName, "90wy3vgyn0w394vf".toCharArray());
} catch (AuthenticationException e) {
logger.info( "User allready exists, authenticating..");
return false;
} finally {
UserTransaction atx = transactionService.getUserTransaction();
try {
atx.begin();
// Set the authentication
// todo: can we do this otherwise? we are not yet authenticated
authComponent.setCurrentUser("admin");
atx.commit();
} catch (Throwable e) {
logger.error(e);
try {
atx.rollback();
} catch (SystemException e1) {
logger.error("Failed to rollback transaction", e);
}
}
// todo: use homeFolderProvider
String homeFolder = "workspace://SpacesStore/"+getCompanyHome().getId();
// create new userDetails object
NewUserDetails newUser = new NewUserDetails();
logger.info("newuser.setUserName :"+userName);
newUser.setUserName(userName);
newUser.setPassword("shibboleth");
newUser.setProperties(
createPersonProperties( homeFolder , firstName, "", lastName, email, orgId)
);
if(!personService.personExists(newUser.getUserName()))
{
atx = transactionService.getUserTransaction();
try {
atx.begin();
// Create a new user
authenticationDao.createUser(newUser.getUserName(),"shibboleth".toCharArray());
// Create a new person
Map<QName, Serializable> properties = new HashMap<QName, Serializable>(7);
logger.info("properties.put username : "+newUser.getUserName());
properties.put(ContentModel.PROP_USERNAME, newUser.getUserName());
for (NamedValue namedValue : newUser.getProperties())
{
logger.info("properties.put "+namedValue.getName()+" : "+namedValue.getValue());
properties.put(QName.createQName(namedValue.getName()), namedValue.getValue());
}
NodeRef personNodeRef = personService.createPerson(properties);
atx.commit();
} catch (Throwable e) {
logger.error(e);
try {
atx.rollback();
} catch (SystemException e1) {
logger.error("Failed to rollback transaction", e);
}
}
} else {
logger.info("User "+userName+" exists, updating..");
atx = transactionService.getUserTransaction();
try {
atx.begin();
Map<QName, Serializable> properties = new HashMap<QName, Serializable>(7);
logger.info("properties.put username : "+newUser.getUserName());
properties.put(ContentModel.PROP_USERNAME, newUser.getUserName());
for (NamedValue namedValue : newUser.getProperties())
{
logger.info("properties.put "+namedValue.getName()+" : "+namedValue.getValue());
properties.put(QName.createQName(namedValue.getName()), namedValue.getValue());
}
personService.setPersonProperties(userName,properties);
atx.commit();
} catch (Throwable e) {
logger.error(e);
try {
atx.rollback();
} catch (SystemException e1) {
logger.error("Failed to rollback transaction", e);
}
}
}
authService.clearCurrentSecurityContext();
return true;
}
}
private NamedValue[] createPersonProperties(
String homeFolder,
String firstName,
String middleName,
String lastName,
String email,
String orgId)
{
// Create the new user objects
return new NamedValue[] {
new NamedValue("{http://www.alfresco.org/model/content/1.0}homeFolder", false, homeFolder, null),
new NamedValue("{http://www.alfresco.org/model/content/1.0}firstName", false, firstName, null),
new NamedValue("{http://www.alfresco.org/model/content/1.0}middleName", false, middleName, null),
new NamedValue("{http://www.alfresco.org/model/content/1.0}lastName", false, lastName, null),
new NamedValue("{http://www.alfresco.org/model/content/1.0}email", false, email, null),
new NamedValue("{http://www.alfresco.org/model/content/1.0}organizationId", false, orgId, null) };
}
public void init(FilterConfig config) throws ServletException
{
this.context = config.getServletContext();
WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(context);
ServiceRegistry serviceRegistry = (ServiceRegistry) ctx.getBean(ServiceRegistry.SERVICE_REGISTRY);
transactionService = serviceRegistry.getTransactionService();
nodeService = serviceRegistry.getNodeService();
authComponent = (AuthenticationComponent) ctx.getBean("AuthenticationComponent");
authService = (AuthenticationService) ctx.getBean("AuthenticationService");
personService = (PersonService) ctx.getBean("PersonService");
authenticationDao = (MutableAuthenticationDao) ctx.getBean("authenticationDao");
searchService = (SearchService) ctx.getBean("SearchService");
}
}
shibbolethAttributes.properties# Take note how you want shibboleth attributess mapped to alfresco
# These need to match parameters defined in AAP.xml (attribute acceptance policy)
# logout-url is the page that should be displayed upon logout (invalidating shibd-session is not yet implemented)
header.username = Shib-InetOrgPerson-uid
header.firstname = Shib-InetOrgPerson-givenName
header.lastname = Shib-InetOrgPerson-cn
header.email = Shib-InetOrgPerson-mail
header.orgId = Shib-InetOrgPerson-ou
header.logout-url = logout-url
05-16-2008 10:51 AM
04-21-2009 09:28 AM
06-16-2009 10:44 AM
06-26-2009 09:17 AM
Tags
Find what you came for
We want to make your experience in Hyland Connect as valuable as possible, so we put together some helpful links.