diff --git a/ccm-core/src/main/java/com/arsdigita/xml/Document.java b/ccm-core/src/main/java/com/arsdigita/xml/Document.java new file mode 100644 index 000000000..8c5fa29a9 --- /dev/null +++ b/ccm-core/src/main/java/com/arsdigita/xml/Document.java @@ -0,0 +1,356 @@ +/* + * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.xml; + +import java.io.ByteArrayOutputStream; +import java.io.StringReader; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamSource; +import javax.xml.transform.stream.StreamResult; +import org.apache.log4j.Logger; +import java.io.UnsupportedEncodingException; + +/** + * A wrapper class that implements some functionality of + * org.jdom.Document using org.w3c.dom.Document. + * + * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * pboy (Jan. 09) + * Class uses "DocumentBuilderFactory.newInstance()" to setup the parser + * (according to the javax.xml specification). This is a simple and + * straightforward, but rather thumb method. It requires a JVM wide acceptable + * configuration (using a system.property or a static JRE configuration file) and + * contrains all programms in a JVM (e.g. multiple CCM running in a container) + * to use the same configuration. + * + * Other methods are available but we have to dig deeper into the CCM code. + * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * + * @author Patrick McNeill + * @since ACS 4.5a + * @version $Id$ + */ +public class Document { + + private static final Logger s_log = + Logger.getLogger(Document.class.getName()); + /** + * this is the identity XSL stylesheet. We need to provide the + * identity transform as XSL explicitly because the default + * transformer (newTransformer()) strips XML namespace attributes. + * Also, this XSLT will strip the debugging info + * from the XML document if present. + */ + // XXX For some reason JD.XSLT doesn't copy xmlns: attributes + // to the output doc with + /* + private final static String identityXSL = + "\n" + + "\n" + + "\n" + + " " + + "\n\n" + + "\n" + + "\n" + + ""; + */ + // Explicitly create elements & attributes to avoid namespace + // problems + private final static String identityXSL = + "\n" + + "\n" + + "\n" + + " \n" + + "\n" + + "\n" + + " \n" + + "\n" + + "\n" + + " \n" + + "\n" + + "\n" + + "\n" + + ""; + /** + * A single DocumentBuilderFactory to use for + * creating Documents. + */ + protected static DocumentBuilderFactory s_builder = null; + /** + * A single DocumentBuilder to use for + * creating Documents. + */ + protected static ThreadLocal s_db = null; + + // ToDo (pboy): we should use + // DocumentBuilderFactory.newInstance(className cname, classLoader cloader) + // instead to achieve independence from a JVM wide configuration. + // Requires additional modifications in c.ad.util.xml.XML + static { + s_log.debug("Static initalizer starting..."); + s_builder = DocumentBuilderFactory.newInstance(); + s_builder.setNamespaceAware(true); + s_db = new ThreadLocal() { + + @Override + public Object initialValue() { + try { + return s_builder.newDocumentBuilder(); + } catch (ParserConfigurationException pce) { + return null; + } + } + }; + s_log.debug("Static initalized finished."); + } + + /* Used to build the DOM Documents that this class wraps */ + /** + * The internal DOM document being wrapped. + */ + protected org.w3c.dom.Document m_document; + + /** + * Creates a new Document class with no root element. + * + * @throws javax.xml.parsers.ParserConfigurationException + */ + public Document() throws ParserConfigurationException { + DocumentBuilder db = (DocumentBuilder) s_db.get(); + if (db == null) { + throw new ParserConfigurationException( + "Unable to create a DocumentBuilder"); + } + m_document = db.newDocument(); + } + + /** + * + * Creates a new Document class based on an org.w3c.dom.Document. + * + * @param doc the org.w3c.dom.Document + * + */ + public Document(org.w3c.dom.Document doc) { + m_document = doc; + } + + /** + * Creates a new Document class with the given root element. + * + * @param rootNode the element to use as the root node + * @throws javax.xml.parsers.ParserConfigurationException + */ + public Document(Element rootNode) throws ParserConfigurationException { + DocumentBuilder db = (DocumentBuilder) s_db.get(); + if (db == null) { + throw new ParserConfigurationException( + "Unable to create a DocumentBuilder"); + } + + m_document = db.newDocument(); + rootNode.importInto(m_document); + m_document.appendChild(rootNode.getInternalElement()); + } + + /** + * Creates a document from the passed in string that should + * be properly formatted XML + * + * @param xmlString + * @throws javax.xml.parsers.ParserConfigurationException + * @throws org.xml.sax.SAXException + */ + public Document(String xmlString) + throws ParserConfigurationException, org.xml.sax.SAXException { + this(new org.xml.sax.InputSource(new java.io.StringReader(xmlString))); + } + + public Document(byte[] xmlBytes) + throws ParserConfigurationException, org.xml.sax.SAXException { + this(new org.xml.sax.InputSource(new java.io.ByteArrayInputStream( + xmlBytes))); + } + + private Document(org.xml.sax.InputSource inputSource) + throws ParserConfigurationException, org.xml.sax.SAXException { + DocumentBuilder db = (DocumentBuilder) s_db.get(); + if (db == null) { + throw new ParserConfigurationException( + "Unable to create a DocumentBuilder"); + } + + org.w3c.dom.Document domDoc; + try { + domDoc = db.parse(inputSource); + } catch (java.io.IOException e) { + throw new com.arsdigita.util.UncheckedWrapperException(e); + } + m_document = domDoc; + } + + /** + * Sets the root element. + * + * @param rootNode the element to use as the root node + * @return this document. + */ + public Document setRootElement(Element rootNode) { + rootNode.importInto(m_document); + m_document.appendChild(rootNode.getInternalElement()); + + return this; + } + + /** + * Creates a new element and sets it as the root. + * Equivalent to + *
+     * Element root = new Element("name", NS);
+     * doc.setRootElement(root);
+     * 
+ * @param elt the element name + * @param ns the element's namespace URI + * @return The newly created root element. + */ + public Element createRootElement(String elt, String ns) { + org.w3c.dom.Element root = m_document.createElementNS(ns, elt); + m_document.appendChild(root); + Element wrapper = new Element(); + wrapper.m_element = root; + return wrapper; + } + + /** + * Creates a new element and sets it as the root. + * Equivalent to + *
+     * Element root = new Element("name", NS);
+     * doc.setRootElement(root);
+     * 
+ * @param elt the element name + * @return The newly created root element. + */ + public Element createRootElement(String elt) { + org.w3c.dom.Element root = m_document.createElement(elt); + m_document.appendChild(root); + Element wrapper = new Element(); + wrapper.m_element = root; + return wrapper; + } + + /** + * Returns the root element for the document. This is the top-level + * element (the "HTML" element in an HTML document). + * @return the document's root element. + */ + public Element getRootElement() { + Element root = new Element(); + root.m_element = m_document.getDocumentElement(); + return root; + } + + /** + * Not a part of org.jdom.Document, this function returns + * the internal DOM representation of this document. This method should + * only be used when passing the DOM to the translator. It will require + * changes once JDOM replaces this class. + * + * @return this document. + */ + public org.w3c.dom.Document getInternalDocument() { + return m_document; + } + + /** + * General toString() method for org.w3c.domDocument. + * Not really related to xml.Document, but needed here. + * Converts an XML in-memory DOM to String representation, using + * an XSLT identity transformation. + * + * @param document the org.w3c.dom.Document object + * to convert to a String representation + * @param indent if true, try to indent elements according to normal + * XML/SGML indentation conventions (may only work with certain + * XSLT engines) + * @return a String representation of document. + */ + public static String toString(org.w3c.dom.Document document, + boolean indent) { + Transformer identity; + ByteArrayOutputStream os = new ByteArrayOutputStream(); + try { + StreamSource identitySource = + new StreamSource(new StringReader(identityXSL)); + identity = TransformerFactory.newInstance().newTransformer( + identitySource); + identity.setOutputProperty("method", "xml"); + identity.setOutputProperty("indent", (indent ? "yes" : "no")); + identity.setOutputProperty("encoding", "UTF-8"); + identity.transform(new DOMSource(document), new StreamResult(os)); + } catch (javax.xml.transform.TransformerException e) { + s_log.error("error in toString", e); + return document.toString(); + } + + try { + return os.toString("UTF-8"); + } catch (UnsupportedEncodingException ex) { + s_log.error("UTF-8 encoding not supported!!!"); + return os.toString(); + } + } + + /** Convenience wrapper for static toString(Document, boolean), + * without additional indenting. + * @param document the org.w3c.dom.Document to output + * @return a String representation of document. + */ + public static String toString(org.w3c.dom.Document document) { + return toString(document, false); + } + + /** + * Generates an XML text representation of this document. + * @param indent if true, try to indent XML elements according + * to XML/SGML convention + * @return a String representation of this. + */ + public String toString(boolean indent) { + return toString(m_document, indent); + } + + /** Generates an XML text representation of this document, + * without additional indenting. + * @return a String representation of this. + */ + @Override + public String toString() { + return toString(m_document, false); + } +} diff --git a/ccm-core/src/main/java/org/libreccm/core/authentication/LocalLoginModule.java b/ccm-core/src/main/java/org/libreccm/core/authentication/LocalLoginModule.java index b5deeb740..3c1ff773a 100644 --- a/ccm-core/src/main/java/org/libreccm/core/authentication/LocalLoginModule.java +++ b/ccm-core/src/main/java/org/libreccm/core/authentication/LocalLoginModule.java @@ -21,6 +21,7 @@ package org.libreccm.core.authentication; import com.arsdigita.kernel.KernelConfig; import org.libreccm.core.User; +import org.libreccm.core.UserManager; import org.libreccm.core.UserRepository; import java.security.MessageDigest; @@ -46,6 +47,9 @@ public class LocalLoginModule extends PasswordLoginModule { */ @Inject private transient UserRepository userRepository; + + @Inject + private transient UserManager userManager; private transient Subject subject; @@ -106,31 +110,33 @@ public class LocalLoginModule extends PasswordLoginModule { "No user account identified by '%s' found.", username)); } + return userManager.verifyPasswordForUser(user, password); + // Verify the password. The algorithm used for hashing is stored in the // database so we need to retrieve the correct MessageDigest instance // first. - try { - final MessageDigest digest = MessageDigest.getInstance(user - .getHashAlgorithm()); - final String saltedPassword = String.format("%s%s", - password, - user.getSalt()); - final String passwordHash = new String(digest.digest( - saltedPassword.getBytes())); - - if (passwordHash.equals(user.getPassword())) { - subject.getPrincipals().add(new UserPrincipal(user)); - return true; - } else { - return false; - } - } catch (NoSuchAlgorithmException ex) { - throw new LoginException(String.format( - "Failed to validate password because the password stored for " - + "user '%s' in the database is hashed with algorithm '%s' " - + "which is not avialable.", - username, user.getHashAlgorithm())); - } +// try { +// final MessageDigest digest = MessageDigest.getInstance(user +// .getHashAlgorithm()); +// final String saltedPassword = String.format("%s%s", +// password, +// user.getSalt()); +// final String passwordHash = new String(digest.digest( +// saltedPassword.getBytes())); +// +// if (passwordHash.equals(user.getPassword())) { +// subject.getPrincipals().add(new UserPrincipal(user)); +// return true; +// } else { +// return false; +// } +// } catch (NoSuchAlgorithmException ex) { +// throw new LoginException(String.format( +// "Failed to validate password because the password stored for " +// + "user '%s' in the database is hashed with algorithm '%s' " +// + "which is not avialable.", +// username, user.getHashAlgorithm())); +// } } diff --git a/ccm-core/src/main/resources/ccm-core.config b/ccm-core/src/main/resources/ccm-core.config new file mode 100644 index 000000000..3afb5338f --- /dev/null +++ b/ccm-core/src/main/resources/ccm-core.config @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/ccm-core/src/test/java/com/arsdigita/kernel/KernelConfigTest.java b/ccm-core/src/test/java/com/arsdigita/kernel/KernelConfigTest.java new file mode 100644 index 000000000..861797f34 --- /dev/null +++ b/ccm-core/src/test/java/com/arsdigita/kernel/KernelConfigTest.java @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2015 LibreCCM Foundation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package com.arsdigita.kernel; + +import java.io.File; + +import static org.hamcrest.Matchers.*; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.asset.EmptyAsset; +import org.jboss.shrinkwrap.api.spec.WebArchive; +import org.jboss.shrinkwrap.resolver.api.maven.Maven; +import org.jboss.shrinkwrap.resolver.api.maven.PomEquippedResolveStage; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runner.RunWith; +import org.libreccm.tests.categories.IntegrationTest; + +import static org.junit.Assert.*; + +/** + * + * @author Jens Pelzetter + */ +@RunWith(Arquillian.class) +@Category(IntegrationTest.class) +public class KernelConfigTest { + + public KernelConfigTest() { + } + + @BeforeClass + public static void setUpClass() { + } + + @AfterClass + public static void tearDownClass() { + } + + @Before + public void setUp() { + } + + @After + public void tearDown() { + } + + @Deployment + public static WebArchive createDeployment() { + final PomEquippedResolveStage pom = Maven + .resolver() + .loadPomFromFile("pom.xml"); + final PomEquippedResolveStage dependencies = pom + .importCompileAndRuntimeDependencies(); + final File[] libs = dependencies.resolve().withTransitivity().asFile(); + + for (File lib : libs) { + System.err.printf("Adding file '%s' to test archive...%n", + lib.getName()); + } + + return ShrinkWrap + .create(WebArchive.class, + "LibreCCM-org.libreccm.core.KernelConfigTest.war") + //.addPackage(CcmObject.class.getPackage()) + .addPackage(com.arsdigita.kernel.KernelConfig.class.getPackage()) + .addPackage(com.arsdigita.runtime.AbstractConfig.class.getPackage()) + .addPackage(com.arsdigita.util.parameter.AbstractParameter.class. + getPackage()) + .addPackage(com.arsdigita.util.JavaPropertyReader.class. + getPackage()) + .addPackage(org.libreccm.tests.categories.IntegrationTest.class + .getPackage()) + .addAsLibraries(libs) + .addAsWebInfResource( + "configtests/com/arsdigita/kernel/KernelConfigTest/ccm-core.config", + "ccm-core.config") + .addAsWebInfResource( + "configtests/com/arsdigita/kernel/KernelConfigTest/registry.properties", + "conf/registry/registry.properties") + .addAsWebInfResource( + "configtests/com/arsdigita/kernel/KernelConfigTest/kernel.properties", + "conf/registry/ccm-core/kernel.properties") + .addAsResource( + "com/arsdigita/kernel/KernelConfig_parameter.properties", + "com/arsdigita/kernel/KernelConfig_parameter.properties") + .addAsWebInfResource(EmptyAsset.INSTANCE, "WEB-INF/beans.xml"); + } + + @Test + public void verifyKernelConfig() { + final KernelConfig kernelConfig = KernelConfig.getConfig(); + + assertThat(kernelConfig.isDebugEnabled(), + is(true)); + assertThat(kernelConfig.isDataPermissionCheckEnabled(), + is(false)); + assertThat(kernelConfig.getPrimaryUserIdentifier(), + is(equalTo("email"))); + assertThat(kernelConfig.isSSOenabled(), + is(false)); + assertThat(kernelConfig.isLoginRemembered(), + is(true)); + assertThat(kernelConfig.isSecureLoginRequired(), + is(false)); + assertThat(kernelConfig.getSupportedLanguages(), + is(equalTo("de,en"))); + assertThat(kernelConfig.languageIndependentItems(), + is(true)); + assertThat(kernelConfig.getLanguagesIndependentCode(), + is(equalTo("--"))); + } + +} diff --git a/ccm-core/src/test/resources/configtests/com/arsdigita/kernel/KernelConfigTest/ccm-core.config b/ccm-core/src/test/resources/configtests/com/arsdigita/kernel/KernelConfigTest/ccm-core.config new file mode 100644 index 000000000..491bfce26 --- /dev/null +++ b/ccm-core/src/test/resources/configtests/com/arsdigita/kernel/KernelConfigTest/ccm-core.config @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/ccm-core/src/test/resources/configtests/com/arsdigita/kernel/KernelConfigTest/kernel.properties b/ccm-core/src/test/resources/configtests/com/arsdigita/kernel/KernelConfigTest/kernel.properties new file mode 100644 index 000000000..56a27b731 --- /dev/null +++ b/ccm-core/src/test/resources/configtests/com/arsdigita/kernel/KernelConfigTest/kernel.properties @@ -0,0 +1,5 @@ +waf.kernel.supported_languages=de,en +waf.debug=true +waf.kernel.language_independent_items=true +waf.kernel.primary_user_identifier=email +waf.kernel.data_permission_check_enabled=false \ No newline at end of file diff --git a/ccm-core/src/test/resources/configtests/com/arsdigita/kernel/KernelConfigTest/registry.properties b/ccm-core/src/test/resources/configtests/com/arsdigita/kernel/KernelConfigTest/registry.properties new file mode 100644 index 000000000..e69de29bb