CAS, Liferay和Alfresco portlet三者的整合

CAS 和Liferay的整合网上到处都有,我在此也不再鳌述。CAS和Alfresco的整合推荐一篇blog,你看了之后也就知道怎么做了:
http://athenalogics.blogspot.com/2008/07/how-to-casify-alfresco-cms_567.html

本文所要讲的是在CAS和Liferay已经整合好的前提下, 把Alfresco部署成Liferay的portlet并且和CAS整合。
我试了网上有一些别的方法无一成功,也有人说存在bug无法整合。至少根据我前面的blog讲share liferay session的方法给alfresco portlet是不可行的。alfresco的用户认证这里确实有bug。

当然,首先你需要把Alfresco部署成portlet,我这里用到的是Alfresco community version 2.1, Liferay 5.1.0
部署Liferay portlet 通常的做法是 Hotdeploy. 也就是把alfresco.war放到$user_home/liferay/deploy

之后会在Webapp下面产生一个新的alfresco的app, 到它的lib下面把portlet-api删掉,因为这个和liferay的相冲突。然再把附件中的liferay portlet描述文件copy到alfresco/WEB-INF下面. 注意,附件里的web.xml中用到的portlet-class是我自己修改过的。
这样你的alfresco就可以被添加到liferay里面了.

当然,如果你不想使用hotdeploy(通常写自动产生server的script的人最讨厌这个), 那么可以参考这个script的相应部分: http://tempo.intalio.org/tempo/trunk/rsc/scripts/create_tomcat.rb


接下来,Alfresco portlet的用户管理的基本思路是在PortletSession里是否存在'AuthenticationHelper.AUTHENTICATION_USER'这个属性,如果存在的话就取出里面的User去做验证。通过的话就可以访问。基于这个原理,我在原有的portlet-class上做了一些改动,下面的portlet class的全文:


/*
* Copyright (C) 2005-2007 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.

* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.

* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.intalio.tempo.web;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.List;

import javax.faces.application.ViewHandler;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.PortletException;
import javax.portlet.PortletRequest;
import javax.portlet.PortletRequestDispatcher;
import javax.portlet.PortletSession;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import javax.portlet.UnavailableException;
import javax.servlet.http.HttpServletRequest;
import javax.transaction.UserTransaction;

import org.alfresco.config.ConfigService;
import org.alfresco.i18n.I18NUtil;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.repo.security.authentication.AuthenticationException;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.security.AuthenticationService;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.TempFileProvider;
import org.alfresco.web.app.Application;
import org.alfresco.web.app.portlet.AlfrescoDefaultViewSelector;
import org.alfresco.web.app.servlet.AuthenticationHelper;
import org.alfresco.web.app.servlet.AuthenticationStatus;
import org.alfresco.web.bean.ErrorBean;
import org.alfresco.web.bean.FileUploadBean;
import org.alfresco.web.bean.LoginBean;
import org.alfresco.web.bean.NavigationBean;
import org.alfresco.web.bean.repository.Repository;
import org.alfresco.web.bean.repository.User;
import org.alfresco.web.config.ClientConfigElement;
import org.alfresco.web.config.LanguagesConfigElement;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.portlet.PortletFileUpload;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.myfaces.portlet.MyFacesGenericPortlet;
import org.apache.myfaces.portlet.PortletUtil;
import org.springframework.web.context.WebApplicationContext;

import com.liferay.portal.service.UserServiceUtil;

/**
* Class to extend the MyFacesGenericPortlet to provide behaviour specific to
* Alfresco web client. Handles upload of multi-part forms through a JSR-168
* Portlet, generic error handling and session login authentication.
*
* @author Gavin Cornwell, Kevin Roast
*/
public class AlfrescoFacesPortlet extends MyFacesGenericPortlet {
private static final String PREF_ALF_USERNAME = "_alfUserName";
private static final String SESSION_LAST_VIEW_ID = "_alfLastViewId";

private static final String ERROR_PAGE_PARAM = "error-page";
private static final String ERROR_OCCURRED = "error-occurred";
private List<String> m_languages;
private static Log logger = LogFactory.getLog(AlfrescoFacesPortlet.class);

private String loginPage = null;
private String errorPage = null;

/**
* Called by the portlet container to allow the portlet to process an action
* request.
*/
public void processAction(ActionRequest request, ActionResponse response) throws PortletException, IOException {
Application.setInPortalServer(true);

// Set the current locale
I18NUtil.setLocale(Application.getLanguage(request.getPortletSession()));

boolean isMultipart = PortletFileUpload.isMultipartContent(request);

try {
// NOTE: Due to filters not being called within portlets we can not
// make use
// of the MyFaces file upload support, therefore we are using a pure
// portlet request/action to handle file uploads until there is a
// solution.

if (isMultipart) {
if (logger.isDebugEnabled())
logger.debug("Handling multipart request...");

PortletSession session = request.getPortletSession();

// get the file from the request and put it in the session
DiskFileItemFactory factory = new DiskFileItemFactory();
PortletFileUpload upload = new PortletFileUpload(factory);
List<FileItem> fileItems = upload.parseRequest(request);
Iterator<FileItem> iter = fileItems.iterator();
FileUploadBean bean = new FileUploadBean();
while (iter.hasNext()) {
FileItem item = iter.next();
String filename = item.getName();
if (item.isFormField() == false) {
if (logger.isDebugEnabled())
logger.debug("Processing uploaded file: " + filename);

// workaround a bug in IE where the full path is
// returned
// IE is only available for Windows so only check for
// the Windows path separator
int idx = filename.lastIndexOf('\\');

if (idx == -1) {
// if there is no windows path separator check for
// *nix
idx = filename.lastIndexOf('/');
}

if (idx != -1) {
filename = filename.substring(idx + File.separator.length());
}

File tempFile = TempFileProvider.createTempFile("alfresco", ".upload");
item.write(tempFile);
bean.setFile(tempFile);
bean.setFileName(filename);
bean.setFilePath(tempFile.getAbsolutePath());
session.setAttribute(FileUploadBean.FILE_UPLOAD_BEAN_NAME, bean, PortletSession.PORTLET_SCOPE);
}
}

// Set the VIEW_ID parameter to tell the faces portlet bridge to
// treat the request
// as a JSF request, this will send us back to the previous page
// we came from.
String lastViewId = (String) request.getPortletSession().getAttribute(SESSION_LAST_VIEW_ID);
if (lastViewId != null) {
response.setRenderParameter(VIEW_ID, lastViewId);
}
} else {
User user = (User) request.getPortletSession().getAttribute(AuthenticationHelper.AUTHENTICATION_USER);
if (user != null) {
// setup the authentication context
try {
WebApplicationContext ctx = (WebApplicationContext) getPortletContext().getAttribute(
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
AuthenticationService auth = (AuthenticationService) ctx.getBean("AuthenticationService");
auth.validate(user.getTicket());

// save last username into portlet preferences, get from
// LoginBean state
LoginBean loginBean = (LoginBean) request.getPortletSession().getAttribute(AuthenticationHelper.LOGIN_BEAN);
if (loginBean != null) {
// TODO: Need to login to the Portal to get a user
// here to store prefs against
// so not really a suitable solution as they get
// thrown away at present!
// Also would need to store prefs PER user - so auto
// login for each...?
String oldValue = request.getPreferences().getValue(PREF_ALF_USERNAME, null);
if (oldValue == null || oldValue.equals(loginBean.getUsernameInternal()) == false) {
if (request.getPreferences().isReadOnly(PREF_ALF_USERNAME) == false) {
request.getPreferences().setValue(PREF_ALF_USERNAME, loginBean.getUsernameInternal());
request.getPreferences().store();
}
}
}

// do the normal JSF processing
super.processAction(request, response);
} catch (AuthenticationException authErr) {
// remove User object as it's now useless
request.getPortletSession().removeAttribute(AuthenticationHelper.AUTHENTICATION_USER);
}
} else {
// do the normal JSF processing as we may be on the login
// page
super.processAction(request, response);
}
}
} catch (Throwable e) {
if (getErrorPage() != null) {
handleError(request, response, e);
} else {
logger.warn("No error page configured, re-throwing exception");

if (e instanceof PortletException) {
throw (PortletException) e;
} else if (e instanceof IOException) {
throw (IOException) e;
} else {
throw new PortletException(e);
}
}
}
}

/**
* @see org.apache.myfaces.portlet.MyFacesGenericPortlet#facesRender(javax.portlet.RenderRequest,
* javax.portlet.RenderResponse)
*/
protected void facesRender(RenderRequest request, RenderResponse response) throws PortletException, IOException {

try {
User user = (User) request.getPortletSession().getAttribute(AuthenticationHelper.AUTHENTICATION_USER);
if (user == null) {
Method getHttpServletRequest = request.getClass().getMethod("getHttpServletRequest");
HttpServletRequest hsr = (HttpServletRequest) getHttpServletRequest.invoke(request);
Long userID = (Long) hsr.getSession().getAttribute("USER_ID");
com.liferay.portal.model.User liferayUser = UserServiceUtil.getUserById(userID);
String userName = liferayUser.getScreenName();
logger.debug("user name for alfresco is:" + userName);
getPortletContext().removeAttribute("loggedin");
setAuthenticatedUser(request, userName);
}
} catch (Throwable e) {
// do nothing
}

Application.setInPortalServer(true);

// Set the current locale
I18NUtil.setLocale(Application.getLanguage(request.getPortletSession()));

if (request.getParameter(ERROR_OCCURRED) != null) {
String errorPage = Application.getErrorPage(getPortletContext());

if (logger.isDebugEnabled())
logger.debug("An error has occurred, redirecting to error page: " + errorPage);

response.setContentType("text/html");
PortletRequestDispatcher dispatcher = getPortletContext().getRequestDispatcher(errorPage);
dispatcher.include(request, response);
} else {
WebApplicationContext ctx = (WebApplicationContext) getPortletContext().getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
AuthenticationService auth = (AuthenticationService) ctx.getBean("AuthenticationService");

// if we have no User object in the session then an HTTP Session
// timeout must have occured
// use the viewId to check that we are not already on the login page
PortletSession session = request.getPortletSession();
String viewId = request.getParameter(VIEW_ID);
// keep track of last view id so we can use it as return page from
// multi-part requests
request.getPortletSession().setAttribute(SESSION_LAST_VIEW_ID, viewId);
User user = (User) request.getPortletSession().getAttribute(AuthenticationHelper.AUTHENTICATION_USER);
if (user == null && (viewId == null || viewId.equals(getLoginPage()) == false)) {
if (AuthenticationHelper.portalGuestAuthenticate(ctx, session, auth) == AuthenticationStatus.Guest) {
if (logger.isDebugEnabled())
logger.debug("Guest access successful.");

// perform the forward to the page processed by the Faces
// servlet
response.setContentType("text/html");
request.getPortletSession().setAttribute(PortletUtil.PORTLET_REQUEST_FLAG, "true");

// get the start location as configured by the web-client
// config
ConfigService configService = (ConfigService) ctx.getBean("webClientConfigService");
ClientConfigElement configElement = (ClientConfigElement) configService.getGlobalConfig().getConfigElement("client");
if (NavigationBean.LOCATION_MYALFRESCO.equals(configElement.getInitialLocation())) {
nonFacesRequest(request, response, "/jsp/dashboards/container.jsp");
} else {
nonFacesRequest(request, response, "/jsp/browse/browse.jsp");
}
} else {
if (logger.isDebugEnabled())
logger.debug("No valid User login, requesting login page. ViewId: " + viewId);

// set last used username as special session value used by
// the LoginBean
session.setAttribute(AuthenticationHelper.SESSION_USERNAME, request.getPreferences().getValue(PREF_ALF_USERNAME, null));

// login page is the default portal page
response.setContentType("text/html");
request.getPortletSession().setAttribute(PortletUtil.PORTLET_REQUEST_FLAG, "true");
nonFacesRequest(request, response);
}
} else {
if (session.getAttribute(AuthenticationHelper.SESSION_INVALIDATED) != null) {
// remove the username preference value as explicit logout
// was requested by the user
if (request.getPreferences().isReadOnly(PREF_ALF_USERNAME) == false) {
request.getPreferences().reset(PREF_ALF_USERNAME);
}
session.removeAttribute(AuthenticationHelper.SESSION_INVALIDATED);
}

try {
if (user != null) {
if (logger.isDebugEnabled())
logger.debug("Validating ticket: " + user.getTicket());

// setup the authentication context
auth.validate(user.getTicket());
}

// do the normal JSF processing
String loggedin = (String) getPortletContext().getAttribute("loggedin");
logger.debug("logged in?:" + loggedin);
if (loggedin != null && loggedin.equalsIgnoreCase("true")) {
super.facesRender(request, response);
} else {
getPortletContext().setAttribute("loggedin", "true");
response.setContentType("text/html");
request.getPortletSession().setAttribute(PortletUtil.PORTLET_REQUEST_FLAG, "true");
nonFacesRequest(request, response, "/jsp/browse/browse.jsp");
}
} catch (AuthenticationException authErr) {
// ticket is no longer valid!
if (logger.isDebugEnabled())
logger.debug("Invalid ticket, requesting login page.");

// remove User object as it's now useless
request.getPortletSession().removeAttribute(AuthenticationHelper.AUTHENTICATION_USER);

// login page is the default portal page
response.setContentType("text/html");
request.getPortletSession().setAttribute(PortletUtil.PORTLET_REQUEST_FLAG, "true");
nonFacesRequest(request, response);
} catch (Throwable e) {
if (getErrorPage() != null) {
handleError(request, response, e);
} else {
logger.warn("No error page configured, re-throwing exception");

if (e instanceof PortletException) {
throw (PortletException) e;
} else if (e instanceof IOException) {
throw (IOException) e;
} else {
throw new PortletException(e);
}
}
}
}
}
}

/**
* Handles errors that occur during a process action request
*/
private void handleError(ActionRequest request, ActionResponse response, Throwable error) throws PortletException, IOException {
// get the error bean from the session and set the error that occurred.
PortletSession session = request.getPortletSession();
ErrorBean errorBean = (ErrorBean) session.getAttribute(ErrorBean.ERROR_BEAN_NAME, PortletSession.PORTLET_SCOPE);
if (errorBean == null) {
errorBean = new ErrorBean();
session.setAttribute(ErrorBean.ERROR_BEAN_NAME, errorBean, PortletSession.PORTLET_SCOPE);
}
errorBean.setLastError(error);

response.setRenderParameter(ERROR_OCCURRED, "true");
}

/**
* Handles errors that occur during a render request
*/
private void handleError(RenderRequest request, RenderResponse response, Throwable error) throws PortletException, IOException {
// get the error bean from the session and set the error that occurred.
PortletSession session = request.getPortletSession();
ErrorBean errorBean = (ErrorBean) session.getAttribute(ErrorBean.ERROR_BEAN_NAME, PortletSession.PORTLET_SCOPE);
if (errorBean == null) {
errorBean = new ErrorBean();
session.setAttribute(ErrorBean.ERROR_BEAN_NAME, errorBean, PortletSession.PORTLET_SCOPE);
}
errorBean.setLastError(error);

// if the faces context is available set the current view to the browse
// page
// so that the error page goes back to the application (rather than
// going back
// to the same page which just throws the error again meaning we can
// never leave
// the error page)
FacesContext context = FacesContext.getCurrentInstance();
if (context != null) {
ViewHandler viewHandler = context.getApplication().getViewHandler();
// TODO: configure the portlet error return page
UIViewRoot view = viewHandler.createView(context, "/jsp/browse/browse.jsp");
context.setViewRoot(view);
}

// get the error page and include that instead
String errorPage = getErrorPage();

if (logger.isDebugEnabled())
logger.debug("An error has occurred, redirecting to error page: " + errorPage);

response.setContentType("text/html");
PortletRequestDispatcher dispatcher = getPortletContext().getRequestDispatcher(errorPage);
dispatcher.include(request, response);
}

/**
* @see org.apache.myfaces.portlet.MyFacesGenericPortlet#setDefaultViewSelector()
*/
protected void setDefaultViewSelector() throws UnavailableException {
super.setDefaultViewSelector();
if (this.defaultViewSelector == null) {
this.defaultViewSelector = new AlfrescoDefaultViewSelector();
}
}

/**
* @return Retrieves the configured login page
*/
private String getLoginPage() {
if (this.loginPage == null) {
this.loginPage = Application.getLoginPage(getPortletContext());
}

return this.loginPage;
}

/**
* @return Retrieves the configured error page
*/
private String getErrorPage() {
if (this.errorPage == null) {
this.errorPage = Application.getErrorPage(getPortletContext());
}

return this.errorPage;
}

private void setAuthenticatedUser(PortletRequest req, String userName) {

WebApplicationContext ctx = (WebApplicationContext) getPortletContext().getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
ServiceRegistry serviceRegistry = (ServiceRegistry) ctx.getBean(ServiceRegistry.SERVICE_REGISTRY);
TransactionService transactionService = serviceRegistry.getTransactionService();
NodeService nodeService = serviceRegistry.getNodeService();

AuthenticationComponent authComponent = (AuthenticationComponent) ctx.getBean("authenticationComponent");
AuthenticationService authService = (AuthenticationService) ctx.getBean("authenticationService");
PersonService personService = (PersonService) ctx.getBean("personService");

// Get a list of the available locales
ConfigService configServiceService = (ConfigService) ctx.getBean("webClientConfigService");
LanguagesConfigElement configElement = (LanguagesConfigElement) configServiceService.getConfig("Languages").getConfigElement(
LanguagesConfigElement.CONFIG_ELEMENT_ID);

m_languages = configElement.getLanguages();

// Set up the user information
UserTransaction tx = transactionService.getUserTransaction();
NodeRef homeSpaceRef = null;
User user;
try {
tx.begin();
// Set the authentication
authComponent.setCurrentUser(userName);
user = new User(userName, authService.getCurrentTicket(), personService.getPerson(userName));
homeSpaceRef = (NodeRef) nodeService.getProperty(personService.getPerson(userName), ContentModel.PROP_HOMEFOLDER);
if (homeSpaceRef == null) {
logger.warn("Home Folder is null for user '" + userName + "', using company_home.");
homeSpaceRef = (NodeRef) nodeService.getRootNode(Repository.getStoreRef());
}
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
req.getPortletSession().setAttribute(AuthenticationHelper.AUTHENTICATION_USER, user);
req.getPortletSession().setAttribute(LoginBean.LOGIN_EXTERNAL_AUTH, Boolean.TRUE);

logger.debug("...authenticated user is: " + user.getUserName() + user.getTicket());
}

}



从上面的代码可以看出,拿去认证的用户是从Liferay的Session里拿到的当前登陆的用户,我们认为这个用户如果在alfresco里存在的话,那么也是可以访问alfresco的。这里我并没有完全整合用户认证,而是做了一个各个系统之间用户的对应关系。比如CAS的用户名和Liferay的Screen Name必须是一样的。那么从上面的代码中我们可以看到Liferay的用户的First Name必须和Alfresco的用户名一样。

更完善的三者整合是在这里: http://liferay.cignex.com/ 当然他们的方法就是中央管理了用户(LDAP)而不需要user mapping了

接下来,你只要在你的mysql里面创建一个名为alfresco的数据库,然后创建相应的用户。再start server就好了。

create database alfresco;
grant all on alfresco.* to 'alfresco'@'localhost' identified by 'alfresco' with grant option;
grant all on alfresco.* to 'alfresco'@'localhost.localdomain' identified by 'alfresco' with grant option;


所有的portlet描述文件和这个portlet-class都在附件的包里. enjoy~
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值