I have been trying to integrate a Spring based web application with alfresco and some other applications. For that I am using CAS Single Sign On mechanism. With all the tutorials and blogs I thought I have successfully done so. But now I am facing few hurdles —
Steps I have followed :
1) mywebapp is running on tomcat server 8090 localhost:8090/mywebapp (using mywebappDB oracle)
2) CAS and Alfresco runing on different server 8080 (8443 for https)
imdad:8443/cas/login (using mywebappDB oracle) (on https)
localhost:8080/alfresco (using alfresco – postgress)
Now, When my browser hits localhost:8090/mywebapp URL, it gets redirectecd to CAS
imdad:8443/cas/login?service=http%3A%2F%2Flocalhost%3A8090%2Fmywebapp%2Fpages%2Fhome.jsf
The user name and password is given and authenticated (this user exist in CAS as well as mywebapp) , Even if I keep a different DB for CAS, it will accept the username and password from that DB only, and after authentication it re-directs me to mywebapp. so I get logged in with the same username (This username is also present in mywebapp DB). Now what i know is The username that CAS authenticates sould also be present for the other application so that after authentication, it should know which user is logged in.Since CAS validates with the ticket granting system, password for the other webapp is irrelevelant(i.e. even if the password in the application DB is different, if the user name exist and is authenticated, it will successfully login to the application)
Now the problem I am facing is :
I have put alfresco within IFRAME in the mywebapp application, so when SSO is successfull, I can access mywebapp and the alfresco. But when username is authenticated through CAS and logs into mywebapp and if that user does not exist in Alfresco, it throughs Null pointer exception and alfresco crashes untill Single sign out is done by explicitly executing —
imdad:8443/cas/logout (on https)
heres the tacktrace : (unable to post the image for being new user)
java.lang.NullPointerException at info.intix.alfresco.CasAuthenticationFilter.doFilter(CasAuthenticationFilter.java:73) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.jasig.cas.client.validation.AbstractTicketValidationFilter.doFilter(AbstractTicketValidationFilter.java:201) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.jasig.cas.client.authentication.AuthenticationFilter.doFilter(AuthenticationFilter.java:107) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:470) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298) at org.apache.coyote.http11.Http11AprProcessor.process(Http11AprProcessor.java:861) at org.apache.coyote.http11.Http11AprProtocol$Http11ConnectionHandler.process(Http11AprProtocol.java:579) at org.apache.tomcat.util.net.AprEndpoint$Worker.run(AprEndpoint.java:1584) at java.lang.Thread.run(Thread.java:662)
and here is my filter program
package info.intix.alfresco;
import java.io.IOException;
import java.util.List;
import java.util.Locale;
import javax.servlet.*;
import javax.servlet.http.*;
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.bean.repository.Repository;
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.jasig.cas.client.authentication.AttributePrincipal;
import org.jasig.cas.client.validation.Assertion;
//import org.springframework.extensions.config.Config;
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;
public class CasAuthenticationFilter extends AbstractAuthenticationFilter
implements Filter
{
public CasAuthenticationFilter()
{
}
public void destroy()
{
}
public void doFilter(ServletRequest sreq, ServletResponse sresp, FilterChain chain)
throws IOException, ServletException
{
HttpServletRequest req = (HttpServletRequest)sreq;
HttpServletResponse resp = (HttpServletResponse)sresp;
HttpSession httpSess = req.getSession(true);
Assertion assertion = (Assertion)httpSess.getAttribute("_const_cas_assertion_");
String username = assertion.getPrincipal().getName();
User user = (User)httpSess.getAttribute("_alfAuthTicket");
if(user != null && user.getUserName().equals(username))
{
authComponent.setCurrentUser(user.getUserName());
I18NUtil.setLocale(req.getLocale());
chain.doFilter(sreq, sresp);
return;
}
try
{
setAuthenticatedUser(req, httpSess, username);
}
catch(AuthenticationException ex)
{
if(logger.isErrorEnabled())
logger.error((new StringBuilder(" => Failed to validate user ")).append(user.getUserName()).toString(), ex);
}
setAuthenticatedUser(req, httpSess, username);
if(req.getRequestURI().endsWith(getLoginPage()))
{
if(logger.isDebugEnabled())
logger.debug(" => Login page requested, chaining ...");
resp.sendRedirect((new StringBuilder(String.valueOf(req.getContextPath()))).append("/faces/jsp/browse/browse.jsp").toString());
return;
} else
{
chain.doFilter(sreq, sresp);
return;
}
}
private void setAuthenticatedUser(HttpServletRequest req, HttpSession httpSess, String userName)
{
authComponent.setCurrentUser(userName);
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((new StringBuilder(" => Home Folder is null for user '")).append(userName).append("', using company_home.").toString());
homeSpaceRef = 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);
}
httpSess.setAttribute("_alfAuthTicket", user);
httpSess.setAttribute("_alfExternalAuth", Boolean.TRUE);
Locale userLocale = parseAcceptLanguageHeader(req, m_languages);
if(userLocale != null)
{
httpSess.setAttribute("locale", userLocale);
httpSess.removeAttribute("alfresco.messages.webclient");
}
I18NUtil.setLocale(req.getLocale());
}
public void init(FilterConfig config)
throws ServletException
{
context = config.getServletContext();
WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(context);
ServiceRegistry serviceRegistry = (ServiceRegistry)ctx.getBean("ServiceRegistry");
transactionService = serviceRegistry.getTransactionService();
nodeService = serviceRegistry.getNodeService();
authComponent = (AuthenticationComponent)ctx.getBean("authenticationComponent");
authService = (AuthenticationService)ctx.getBean("authenticationService");
personService = (PersonService)ctx.getBean("personService");
ConfigService configServiceService = (ConfigService)ctx.getBean("webClientConfigService");
LanguagesConfigElement configElement = (LanguagesConfigElement)configServiceService.getConfig("Languages").getConfigElement("languages");
m_languages = configElement.getLanguages();
}
private String getLoginPage()
{
if(loginPage == null)
loginPage = Application.getLoginPage(context);
return loginPage;
}
private static final String LOCALE = "locale";
public static final String MESSAGE_BUNDLE = "alfresco.messages.webclient";
private static Log logger = LogFactory.getLog("info/intix/alfresco/CasAuthenticationFilter");
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;
}
What I intend to do :
If such event occurs, then I want to show a custom warning message saying : “User doesnt have the priviledge to alfresco, Contact the Admin” instead of that null pointer exception.
other questions:
Does the CAS DB has to be Centralised i.e. it should have all the usernames present in all the applications?
How does the user management done using database? The CAS authenticated user, if not present in the Alfresco database, should get added (gets its profile automatically created) to Alfresco. (how can LDAP be used?)
(Take in consideration – I am all very new to this)