Thursday, August 11, 2011

Alfresco Webdav SSO Configuration

Hi,

I finally configured Oracle SSO with Alfresco Webdav. Below is how i achieved that.

I need to run Alfresco on tomcat deployed on other virtual machine, i created a class file as under

-- STEP 1



package my.custom;

import java.io.IOException; 
import java.util.List;
import java.util.Locale;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.transaction.UserTransaction;

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.web.app.Application;
import org.alfresco.web.app.servlet.AbstractAuthenticationFilter;
import org.alfresco.web.app.servlet.AuthenticationHelper;
import org.alfresco.web.bean.LoginBean;
import org.alfresco.web.bean.repository.User;
import org.alfresco.web.config.LanguagesConfigElement;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.extensions.config.ConfigService;
import org.springframework.extensions.surf.util.I18NUtil;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.alfresco.web.bean.repository.Repository;



public class WebDavAuthentication extends AbstractAuthenticationFilter implements Filter {
private static final String LOCALE = "locale";
public static final String MESSAGE_BUNDLE = "alfresco.messages.webclient";
private static Log logger = LogFactory.getLog(OSSOAuthenticationFilter.class);
private ServletContext context;
private String loginPage;
private AuthenticationComponent authComponent;
private AuthenticationService authService;
private TransactionService transactionService;
private PersonService personService;
private NodeService nodeService;
private List m_languages;

public OSSOAuthenticationFilter() {
super();
}

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 userName = null;
//Get headers setted by the oracle sigle sign one server
java.util.Enumeration reqMap = req.getHeaders("Osso-User-Dn");

if (reqMap == null) {
logger.error("No user logged in");
} else {
while (reqMap.hasMoreElements()){
//Get from the full dn the username
userName = ((String)reqMap.nextElement()).split(",")[0].trim().toString().split("=")[1].trim().toString();
//String tmp = value.split(",")[0].trim().toString();
//userName = tmp.split("=")[1].trim().toString();
}
}

if (logger.isDebugEnabled()) {
logger.debug("OSSO : User = " + userName);
}

// 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("OSSO : User " + user.getUserName() + " validate ticket");

if (user.getUserName().equals(userName)) {
UserTransaction tx1 = transactionService.getUserTransaction();
try {
tx1.begin();
authComponent.setCurrentUser(user.getUserName());
tx1.commit();
}catch(Exception ex){
logger.error("Failed due to transaction " + ex);
try {
tx1.rollback();
} catch (Exception ex2) {
logger.error("Failed to rollback transaction", ex2);
}

}
I18NUtil.setLocale(Application.getLanguage(httpSess));
chain.doFilter(sreq, sresp);
return;
} else {
// No match
//setAuthenticatedUser(req, httpSess, userName);
//below url is th oracle portal url
resp.sendRedirect("http://hostname:7778/alfresco");
return;
}
} catch (AuthenticationException ex) {
if (logger.isErrorEnabled())
logger.error("Failed to validate user " + user.getUserName(), ex);
}
}

setAuthenticatedUser(req, httpSess, userName);

// Redirect the login page as it is never seen as we always login by name
if (req.getRequestURI().endsWith(getLoginPage()) == true)
{
if (logger.isDebugEnabled())
logger.debug("Login page requested, chaining ...");

resp.sendRedirect(req.getContextPath() + "/faces/jsp/browse/browse.jsp");
return;
}
else
{
//below url is th oracle portal url
resp.sendRedirect("http://hostname:7778/alfresco");
//chain.doFilter(sreq, sresp);
return;
}

}

/**
* Set the authenticated user.
*
* It does not check that the user exists at the moment.
*
* @param req
* @param httpSess
* @param userName
*/
private void setAuthenticatedUser(HttpServletRequest req, HttpSession httpSess, String userName) {
if (userName != null){
UserTransaction tx1 = transactionService.getUserTransaction();
// Set the authentication
try {
tx1.begin();
authComponent.setCurrentUser(userName);
tx1.commit();
} catch (Throwable ex) {
logger.error(ex);
try {
tx1.rollback();
} catch (Exception ex2) {
logger.error("Failed to rollback transaction", ex2);
}
}

// Set up the user information
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);
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
httpSess.setAttribute(AuthenticationHelper.AUTHENTICATION_USER, user);
httpSess.setAttribute(LoginBean.LOGIN_EXTERNAL_AUTH, Boolean.TRUE);

// Set the current locale from the Accept-Lanaguage header if available
Locale userLocale = parseAcceptLanguageHeader(req, m_languages);

if (userLocale != null) {
httpSess.setAttribute(LOCALE, userLocale);
httpSess.removeAttribute(MESSAGE_BUNDLE);
}

// Set the locale using the session
I18NUtil.setLocale(Application.getLanguage(httpSess));
}
}

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");

// 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();
}

/**
* Return the login page address
*
* @return String
*/
private String getLoginPage() {
if (loginPage == null) {
loginPage = Application.getLoginPage(context);
}

return loginPage;
}
}



-- STEP 2 Place this class file under



C:\Alfresco\tomcat\webapps\alfresco\WEB-INF\classes\my\custom



-- STEP 3 Now you need to configure proxy pass in oc4j's httpd.conf file



$ORACLE_HOME/Apache/Apache/conf/httpd.conf, add the following entries:                                                                                    ProxyPass /alfresco/ http://host:8080/alfresco/

ProxyPass /alfresco http://host:8080/alfresco/


ProxyPassReverse /alfresco/ http://host:8080/alfresco/

ProxyPassReverse /alfresco http://host:8080/alfresco/

-- STEP 4 Now you need to enable sso on oracle portal



edit $ORACLE_HOME/Apache/Apache/conf/mod_osso.conf, add the following lines just before the :
require valid-user
AuthType Basic


require valid-user
AuthType Basic

Please restart apache after you have made this configuration 

-- STEP 5 Edit web xml file under

C:\Alfresco\tomcat\webapps\alfresco\WEB-INF

paste below lines before Authentication Filter 

<filter>
<filter-name>Osso Filter</filter-name>
<filter-class>my.custom.OSSOAuthenticationFilter</filter-class>
</filter>

<filter-mapping>
<filter-name>Osso Filter</filter-name>
<url-pattern>/faces/jsp/browse/browse.jsp</url-pattern>
</filter-mapping>

<filter>
<filter-name>Osso Filter</filter-name>
<filter-class>my.custom.OSSOAuthenticationFilter</filter-class>
</filter>

<filter-mapping>
<filter-name>Osso Filter</filter-name>
<url-pattern>/alfresco</url-pattern>
</filter-mapping> 

-- STEP 6 If alfresco is already running then stop and start alfresco
service from start menu under start -> alfresco -> stop alfreco
virtual server



Thats it, now oracle sso is configured successfully for Alfreco



Try opening http://oc4jserverhost/alfresco, it will redirect to oracle
portal sso login page, enter credentials, it will then redirect you to
alfresco home page on successful login.

Any issues implementing this, feel free to contact me..

Cheers,

Ujjwal Soni

Tuesday, August 2, 2011

Conflicting standard.jar with OC4J server

Today i was working on an application that was to be deployed on LIVE oc4j application server. The deployment went successful but when the application was being tested there were many errors as below related to standard. jar that was in OC4J lib and in my application's classpath.

The errors i got are as under ::


11/08/02 13:31:07 vqwiki.WikiException: org.apache.taglibs.standard.tag.common.core.Util.escapeXml(Ljava/lang/String;)Ljava/lang/String;
11/08/02 13:31:07       at vqwiki.servlets.SaveTopicServlet.doPost(SaveTopicServlet.java:150)
11/08/02 13:31:07       at javax.servlet.http.HttpServlet.service(HttpServlet.java:760)
11/08/02 13:31:07       at javax.servlet.http.HttpServlet.service(HttpServlet.java:853)
11/08/02 13:31:07       at com.evermind.server.http.ServletRequestDispatcher.invoke(ServletRequestDispatcher.java:835)
11/08/02 13:31:07       at com.evermind.server.http.ServletRequestDispatcher.forwardInternal(ServletRequestDispatcher.java:341)
11/08/02 13:31:07       at com.evermind.server.http.ServletRequestDispatcher.forward(ServletRequestDispatcher.java:230)
11/08/02 13:31:07       at vqwiki.servlets.VQWikiServlet.dispatch(VQWikiServlet.java:107)
11/08/02 13:31:07       at vqwiki.servlets.WikiServlet.doPost(WikiServlet.java:733)
11/08/02 13:31:07       at javax.servlet.http.HttpServlet.service(HttpServlet.java:760)
11/08/02 13:31:07       at javax.servlet.http.HttpServlet.service(HttpServlet.java:853)
11/08/02 13:31:07       at com.evermind.server.http.ServletRequestDispatcher.invoke(ServletRequestDispatcher.java:835)
11/08/02 13:31:07       at com.evermind.server.http.ServletRequestDispatcher.forwardInternal(ServletRequestDispatcher.java:341)
11/08/02 13:31:07       at com.evermind.server.http.ServletRequestDispatcher.forward(ServletRequestDispatcher.java:230)
11/08/02 13:31:07       at vqwiki.servlets.FrontControllerFilter.doFilter(FrontControllerFilter.java:91)
11/08/02 13:31:07       at com.evermind.server.http.EvermindFilterChain.doFilter(EvermindFilterChain.java:16)
11/08/02 13:31:07       at vqwiki.servlets.SetCharacterEncodingFilter.doFilter(SetCharacterEncodingFilter.java:74)
11/08/02 13:31:07       at com.evermind.server.http.ServletRequestDispatcher.invoke(ServletRequestDispatcher.java:670)
11/08/02 13:31:07       at com.evermind.server.http.ServletRequestDispatcher.forwardInternal(ServletRequestDispatcher.java:341)
11/08/02 13:31:07       at com.evermind.server.http.HttpRequestHandler.handleNotFound(HttpRequestHandler.java:1038)
11/08/02 13:31:07       at com.evermind.server.http.HttpRequestHandler.processRequest(HttpRequestHandler.java:853)
11/08/02 13:31:07       at com.evermind.server.http.AJPRequestHandler.run(AJPRequestHandler.java:231)
11/08/02 13:31:07       at com.evermind.server.http.AJPRequestHandler.run(AJPRequestHandler.java:136)
11/08/02 13:31:07       at com.evermind.util.ReleasableResourcePooledExecutor$MyWorker.run(ReleasableResourcePooledExecutor.java:192)
11/08/02 13:31:07       at java.lang.Thread.run(Thread.java:534)


I resolved this error by editing my web application's orion-web.xml

I un-commented below line from the file :


 <!-- Uncomment this element to control web application class loader behavior. -->
        <web-app-class-loader search-local-classes-first="true"  include-war-manifest-class-path="true" /> 

Regards,

Ujjwal Soni