package org.josso.tooling.gshell.install.installer; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.commons.vfs.FileObject; import org.apache.commons.vfs.FileSystemException; import org.apache.commons.vfs.FileType; import org.josso.tooling.gshell.install.JOSSOArtifact; import org.josso.tooling.gshell.install.TargetPlatform; import org.josso.tooling.gshell.install.util.XUpdateUtil; import org.w3c.dom.Document; import org.w3c.dom.DocumentType; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; import org.xmldb.common.xml.queries.XUpdateQuery; import org.xmldb.xupdate.lexus.XUpdateQueryImpl; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpression; import javax.xml.xpath.XPathFactory; import java.io.*; /** * @version $Id$ * @org.apache.xbean.XBean element="liferay5-installer" */ public class Liferay5Installer extends VFSInstaller { private static final Log log = LogFactory.getLog(Liferay5Installer.class); public Liferay5Installer(TargetPlatform targetPlatform) { super(targetPlatform); } public Liferay5Installer() { super(); } @Override public void validatePlatform() throws InstallException { try { boolean valid = true; if (targetConfDir.exists() && !targetConfDir.getType().getName().equals(FileType.FOLDER.getName()) && targetLibDir.exists() && !targetLibDir.getType().getName().equals(FileType.FOLDER.getName())) { valid = false; getPrinter().printErrStatus("LiferayHome", "Cannot find Liferay 5 webapp root."); } if (!valid) throw new InstallException("Target does not seem a " + getTargetPlatform().getDescription() + " install."); } catch (IOException e) { getPrinter().printErrStatus("Liferay 5 root", e.getMessage()); throw new InstallException(e.getMessage(), e); } getPrinter().printOkStatus("Liferay 5 root"); } @Override public void installComponent(JOSSOArtifact artifact, boolean replace) throws InstallException { try { FileObject srcFile = getFileSystemManager().resolveFile(artifact.getLocation()); // Install only the proper artifact for the target platform ... if (artifact.getBaseName().startsWith("josso-liferay5-agent")) { installFile(srcFile, this.targetLibDir, replace); } else if (artifact.getBaseName().startsWith("josso-agent-shared")) { installFile(srcFile, this.targetLibDir, replace); } else if (artifact.getBaseName().startsWith("josso-agents-bin") && artifact.getClassifier() != null && artifact.getClassifier().equals("axis")) { installFile(srcFile, this.targetJOSSOLibDir, replace); } else { log.debug("Artifact is not valid for selected platform : " + artifact); } } catch (IOException e) { throw new InstallException(e.getMessage(), e); } } @Override public void install3rdPartyComponent(JOSSOArtifact artifact, boolean replace) throws InstallException { // do nothing - don't install 3rd Party libs } @Override public boolean backupAgentConfigurations(boolean remove) { try { // backup portal-ext.properties FileObject portalConfFile = targetConfDir.resolveFile("portal-ext.properties"); if (portalConfFile.exists()) { // backup file in the same folder it is installed backupFile(portalConfFile, portalConfFile.getParent()); if (remove) { portalConfFile.delete(); } } } catch (Exception e) { getPrinter().printErrStatus("BackupAgentConfigurations", e.getMessage()); return false; } return true; } @Override public boolean removeOldComponents(boolean backup) { return true; } @Override public void installConfiguration(JOSSOArtifact artifact, boolean replace) throws InstallException { try { FileObject srcFile = getFileSystemManager().resolveFile(artifact.getLocation()); String name = srcFile.getName().getBaseName(); if (name.equals("portal-log4j-ext.xml") || name.equals("log4j.dtd")) { FileObject metaInfDir = targetConfDir.resolveFile("META-INF/"); if (!metaInfDir.exists()) metaInfDir.createFolder(); installFile(srcFile, metaInfDir, replace); } else { installFile(srcFile, this.targetConfDir, replace); } } catch (IOException e) { throw new InstallException(e.getMessage(), e); } } @Override public void configureAgent() throws InstallException { // Setup XUpdate : System.setProperty("org.xmldb.common.xml.queries.XPathQueryFactory", "org.xmldb.common.xml.queries.xalan2.XPathQueryFactoryImpl"); // For now, only web.xml to configure: configureWebXml(); configureJaasModule(); } protected void configureWebXml() throws InstallException { // -------------------------------------------------------------------- // Configure web.xml // -------------------------------------------------------------------- FileObject webXml = null; try { webXml = targetDir.resolveFile("WEB-INF/web.xml"); // Get a DOM document of the web.xml : Node webXmlNode = loadAsDom(webXml); boolean modified = false; // Perform specific configurations if (configureFilters(webXmlNode)) modified = true; if (modified) { // Backup Container configuration. If we cannot perform a backup, do nothing if (!backupFile(webXml, targetDir)) { getPrinter().printActionWarnStatus("Configure", targetDir.getName().getFriendlyURI() + "/WEB-INF/web.xml", "Must be done manually (Follow setup guide)"); return; } // Write modifications to file writeContentFromDom(webXmlNode, webXml); getPrinter().printActionOkStatus("Save", webXml.getName().getBaseName(), webXml.getName().getFriendlyURI()); } } catch (IOException e) { log.error(e.getMessage(), e); getPrinter().printErrStatus("Cannot configure container : ", e.getMessage()); } catch (SAXException e) { log.error(e.getMessage(), e); getPrinter().printErrStatus("Cannot configure container : ", e.getMessage()); } catch (Exception e) { log.error(e.getMessage(), e); getPrinter().printErrStatus("Cannot configure container : ", e.getMessage()); getPrinter().printActionWarnStatus("Configure", targetDir.getName().getFriendlyURI() + "/WEB-INF/web.xml", "Must be done manually (Follow setup guide)"); } } protected boolean configureFilters(Node xmlDom) throws Exception { XPath xpath = XPathFactory.newInstance().newXPath(); NodeList filtersNodes = (NodeList) xpath.evaluate("/web-app/filter", xmlDom, XPathConstants.NODESET); // Check if josso is already installed XPathExpression jossoFilterClassExp = xpath.compile("/web-app/filter[filter-class='org.josso.liferay5.agent.LiferaySSOAgentFilter']"); Node jossoFilterNode = (Node) jossoFilterClassExp.evaluate(xmlDom, XPathConstants.NODE); // Append josso filter after auto-login filter in web.xml if (jossoFilterNode != null) { getPrinter().printActionWarnStatus("Configure", "JOSSO SSO Filter", "Already configured : " + (jossoFilterNode != null ? jossoFilterNode.getNodeValue() : "<unknown>")); return false; } // Find auto-filter node in web.xml // Append josso filter after auto-login filter in web.xml if (filtersNodes != null && filtersNodes.getLength() > 0) { String xupdJossoFilter = "\n\t<xupdate:insert-after select=\"/web-app/filter[filter-class='com.liferay.portal.servlet.filters.autologin.AutoLoginFilter']\" >\n" + "\t\t<xupdate:element name=\"filter\"> \n" + "\t\t\t<xupdate:element name=\"filter-name\">SSO Josso Filter</xupdate:element>\n" + "\t\t\t<xupdate:element name=\"filter-class\">org.josso.liferay5.agent.LiferaySSOAgentFilter</xupdate:element>\n" + "\t\t</xupdate:element>\n" + "\t</xupdate:insert-after>\n\n" + "\t<xupdate:insert-before select=\"/web-app/filter-mapping[1]\" >\n" + "\t\t<xupdate:element name=\"filter-mapping\">\n" + "\t\t\t<filter-name>SSO Josso Filter</filter-name>\n" + "\t\t\t<url-pattern>/*</url-pattern>\n" + "\t\t</xupdate:element>\n" + "\t</xupdate:insert-before>"; String qry = XUpdateUtil.XUPDATE_START + xupdJossoFilter + XUpdateUtil.XUPDATE_END; log.debug("XUPDATE QUERY: \n" + qry); XUpdateQuery xq = new XUpdateQueryImpl(); xq.setQString(qry); xq.execute(xmlDom); getPrinter().printActionOkStatus("Added josso filter into web.xml", "JOSSO Liferay 5 Agent ", "WEB-INF/web.xml"); return true; } return false; } @Override public boolean updateAgentConfiguration(String idpHostName, String idpPort, String idpType) { boolean updated; updated = super.updateAgentConfiguration(idpHostName, idpPort, idpType); //To change body of overridden methods use File | Settings | File Templates. try { log.debug("targetJOSSOConfDir = " + targetJOSSOConfDir); FileObject agentConfigFile = targetJOSSOConfDir.resolveFile("josso-agent-config.xml"); if (agentConfigFile.exists()) { // Get a DOM document of the josso-agent-config.xml Node configXmlDom = readContentAsDom(agentConfigFile); String updateSchemaLocations = "<xupdate:update select=\"//@xsi:schemaLocation\">" + "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd " + " urn:org:josso:agent:liferay5 jar:" + targetLibDir + "/josso-liferay5-agent-" + getProperty("version") + ".jar!/josso-liferay5-agent.xsd" + " urn:org:josso:protocol:client jar:" + targetLibDir + "/josso-agents-bin-" + getProperty("version") + ".jar!/josso-protocol-client.xsd " + " urn:org:josso:agent:core jar:" + targetLibDir + "/josso-agents-bin-" + getProperty("version") + ".jar!/josso-agent.xsd" + "" + "</xupdate:update>"; String updateSchemaLocationQryStr = XUpdateUtil.XUPDATE_START + updateSchemaLocations + XUpdateUtil.XUPDATE_END; log.debug("XUPDATE QUERY: \n" +updateSchemaLocationQryStr); XUpdateQuery updateSchemaLocationQry = new XUpdateQueryImpl(); updateSchemaLocationQry.setQString(updateSchemaLocationQryStr); updateSchemaLocationQry.execute(configXmlDom); getPrinter().printActionOkStatus("Configure","Schema Locations", ""); // Write modifications to file writeContentFromDom(configXmlDom, agentConfigFile); getPrinter().printActionOkStatus("Save", agentConfigFile.getName().getBaseName(), agentConfigFile.getName().getFriendlyURI()); } } catch (Exception e) { log.error("Error injecting schema locations to agent configuration", e); getPrinter().printErrStatus("UpdateAgentConfiguration", e.getMessage()); updated = false; } return updated; } protected boolean configureJaasModule() { String tcInstallDir = getProperty("tomcatInstallDir"); String jbInstallDir = getProperty("jbossInstallDir"); final String JOSSO_TOMCAT_MODULE_DEFINITION = "\n\njosso {\n" + "org.josso.liferay5.agent.jaas.SSOGatewayLoginModule required debug=true;\n" + "};"; if (tcInstallDir != null) { log.debug("[configureJaasModule]: Tomcat install dir: " + tcInstallDir); try { FileObject tomcatInstallDir = getFileSystemManager().resolveFile(tcInstallDir); FileObject jaasConfigFile = tomcatInstallDir.resolveFile("conf/jaas.config"); if (jaasConfigFile != null) { BufferedWriter writerJaas = new BufferedWriter( new OutputStreamWriter(new FileOutputStream(jaasConfigFile.getURL().getFile(), true))); writerJaas.write(JOSSO_TOMCAT_MODULE_DEFINITION); writerJaas.flush(); writerJaas.close(); return true; } else { getPrinter().printActionErrStatus("Configure", "JOSSO SSO Filter", "jaas.conf doesn't exist on given path"); return false; } } catch (FileSystemException e) { getPrinter().printActionErrStatus("Configure", "JOSSO SSO Filter", "Tomcat install directory is wrong."); } catch (IOException e) { getPrinter().printActionErrStatus("Configure", "JOSSO SSO Filter", "Can not write to jaas.conf."); } } if (jbInstallDir != null) { log.debug("[configureJaasModule]: JBoss install dir: " + jbInstallDir); FileObject jbossInstallDir = null; try { jbossInstallDir = getFileSystemManager().resolveFile(jbInstallDir); FileObject loginConfig = jbossInstallDir.resolveFile("server/default/conf/login-config.xml"); Node xDom = readContentAsDom(loginConfig); if ( xDom == null ) { log.debug("[configureJaasModule]: XML is not loaded. " + loginConfig.getName().getFriendlyURI()); return false; } String xupdJossoModule = "\n\t<xupdate:append select=\"/policy\" >\n" + "\t\t<xupdate:element name=\"application-policy\">\n" + "\t\t\t<xupdate:attribute name=\"name\">josso</xupdate:attribute>\n" + "\t\t\t<authentication>\n" + "\t\t\t\t<login-module code=\"org.josso.liferay5.agent.jaas.SSOGatewayLoginModule\" flag=\"required\">\n" + "\t\t\t\t\t<module-option name=\"debug\">true</module-option>\n" + "\t\t\t\t</login-module>\n" + "\t\t\t</authentication>\n" + "\t\t</xupdate:element>\n" + "\t</xupdate:append>"; String qry = XUpdateUtil.XUPDATE_START + xupdJossoModule + XUpdateUtil.XUPDATE_END; log.debug("XUPDATE QUERY: \n" + qry); XUpdateQuery xq = new XUpdateQueryImpl(); xq.setQString(qry); xq.execute(xDom); writeContentFromDom(xDom, loginConfig); getPrinter().printActionOkStatus("Changed login-config.xml", "JOSSO Liferay 5 Agent ", "server/default/conf/login-config.xml"); return true; } catch (FileSystemException e) { getPrinter().printActionErrStatus("Configure", "JOSSO SSO Filter", "JBoss install directory is wrong."); } catch (Exception e) { e.printStackTrace(); } } return false; } private Document loadAsDom(FileObject inFile) throws Exception { InputStream is = null; try { is = inFile.getContent().getInputStream(); DocumentBuilderFactory parserFactory = DocumentBuilderFactory.newInstance(); parserFactory.setValidating(false); parserFactory.setNamespaceAware(false); // this is the only diference from readContentAsDom parserFactory.setIgnoringElementContentWhitespace(false); parserFactory.setIgnoringComments(false); DocumentBuilder builder = parserFactory.newDocumentBuilder(); boolean dtdNotFound = false; Document doc = null; try { doc = builder.parse(is); } catch (FileNotFoundException e) { dtdNotFound = true; } // if dtd doesn't exist parse the document again without trying to load dtd if (dtdNotFound) { is = inFile.getContent().getInputStream(); // disable dtd loading parserFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); builder = parserFactory.newDocumentBuilder(); doc = builder.parse(is); } DocumentType docType = doc.getDoctype(); return doc; } finally { if (is != null) try { is.close(); } catch (IOException e) { /**/} } } }