From: Mathieu Baudier Date: Thu, 15 Oct 2015 13:06:43 +0000 (+0000) Subject: Improve login and HTTPS config. X-Git-Tag: argeo-commons-2.1.30~88 X-Git-Url: https://git.argeo.org/?a=commitdiff_plain;h=739faf3400e7f2f1b2bf06bd1ccf9da042c78f5b;p=lgpl%2Fargeo-commons.git Improve login and HTTPS config. git-svn-id: https://svn.argeo.org/commons/trunk@8489 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- diff --git a/demo/argeo_node_cms.properties b/demo/argeo_node_cms.properties index 9578df237..4d336710d 100644 --- a/demo/argeo_node_cms.properties +++ b/demo/argeo_node_cms.properties @@ -1,12 +1,12 @@ argeo.osgi.start.2.node=\ org.eclipse.equinox.http.servlet,\ org.eclipse.equinox.http.jetty,\ -org.eclipse.rap.rwt.osgi argeo.osgi.start.3.node=\ org.argeo.cms,\ argeo.osgi.start.4.node=\ +org.eclipse.rap.rwt.osgi,\ org.eclipse.gemini.blueprint.extender argeo.osgi.start.4.cms=\ @@ -19,6 +19,7 @@ argeo.osgi.start.5.cms=\ org.argeo.cms.demo org.osgi.service.http.port=7070 +org.osgi.service.http.port.secure=7073 org.eclipse.equinox.http.jetty.log.stderr.threshold=info org.osgi.framework.security=osgi diff --git a/demo/argeo_node_rap.properties b/demo/argeo_node_rap.properties index c7f0d77e1..6ca4735ec 100644 --- a/demo/argeo_node_rap.properties +++ b/demo/argeo_node_rap.properties @@ -1,10 +1,10 @@ argeo.osgi.start.2.node=\ -org.argeo.cms - -argeo.osgi.start.3.http=\ org.eclipse.equinox.http.servlet,\ org.eclipse.equinox.http.jetty +argeo.osgi.start.3.node=\ +org.argeo.cms + argeo.osgi.start.4.apps=\ org.eclipse.rap.rwt.osgi,\ org.eclipse.gemini.blueprint.extender @@ -28,12 +28,14 @@ java.security.policy=file:../../all.policy # HTTP org.osgi.service.http.port=7070 -org.eclipse.equinox.http.jetty.log.stderr.threshold=info +#org.eclipse.equinox.http.jetty.log.stderr.threshold=info # HTTPS -#org.osgi.service.http.port.secure=7073 +org.osgi.service.http.port.secure=7073 #org.eclipse.equinox.http.jetty.https.enabled=true #org.eclipse.equinox.http.jetty.ssl.keystore=../../ssl/server.jks +#org.eclipse.equinox.http.jetty.ssl.keystore=data/node.p12 +#org.eclipse.equinox.http.jetty.ssl.keystoretype=PKCS12 #org.eclipse.equinox.http.jetty.ssl.password=changeit #org.eclipse.equinox.http.jetty.ssl.wantclientauth=true @@ -61,4 +63,5 @@ log4j.configuration=file:../../log4j.properties #argeo.node.repo.maxVolatileIndexSize=1048576 # DON'T CHANGE BELOW -org.eclipse.rap.workbenchAutostart=false \ No newline at end of file +org.eclipse.rap.workbenchAutostart=false +org.eclipse.equinox.http.jetty.autostart=false \ No newline at end of file diff --git a/org.argeo.cms/src/org/argeo/cms/auth/ThreadDeathLoginException.java b/org.argeo.cms/src/org/argeo/cms/auth/ThreadDeathLoginException.java new file mode 100644 index 000000000..fb49dc2be --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/auth/ThreadDeathLoginException.java @@ -0,0 +1,17 @@ +package org.argeo.cms.auth; + +import javax.security.auth.login.LoginException; + +public class ThreadDeathLoginException extends LoginException { + private static final long serialVersionUID = 4359130889332276894L; + + private final ThreadDeath threadDeath; + + public ThreadDeathLoginException(String msg, ThreadDeath cause) { + this.threadDeath = cause; + } + + public ThreadDeath getThreadDeath() { + return threadDeath; + } +} \ No newline at end of file diff --git a/org.argeo.cms/src/org/argeo/cms/auth/UserAdminLoginModule.java b/org.argeo.cms/src/org/argeo/cms/auth/UserAdminLoginModule.java index 53e48e8c1..53b4242ef 100644 --- a/org.argeo.cms/src/org/argeo/cms/auth/UserAdminLoginModule.java +++ b/org.argeo.cms/src/org/argeo/cms/auth/UserAdminLoginModule.java @@ -70,6 +70,9 @@ public class UserAdminLoginModule implements LoginModule, AuthConstants { } catch (IOException e) { throw new LoginException("Cannot handle http callback: " + e.getMessage()); + } catch (ThreadDeath e) { + throw new ThreadDeathLoginException( + "Callbackhandler thread died", e); } catch (UnsupportedCallbackException e) { return false; } diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/Kernel.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/Kernel.java index d4092371a..871163fc0 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/Kernel.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/Kernel.java @@ -3,16 +3,15 @@ package org.argeo.cms.internal.kernel; import static bitronix.tm.TransactionManagerServices.getTransactionManager; import static bitronix.tm.TransactionManagerServices.getTransactionSynchronizationRegistry; import static java.util.Locale.ENGLISH; -import static org.apache.commons.io.FileUtils.copyDirectory; import static org.argeo.cms.internal.kernel.KernelUtils.getFrameworkProp; import static org.argeo.cms.internal.kernel.KernelUtils.getOsgiInstanceDir; -import static org.argeo.cms.internal.kernel.KernelUtils.getOsgiInstancePath; import static org.argeo.jcr.ArgeoJcrConstants.ALIAS_NODE; import static org.argeo.jcr.ArgeoJcrConstants.JCR_REPOSITORY_ALIAS; import static org.argeo.util.LocaleChoice.asLocaleList; import static org.osgi.framework.Constants.FRAMEWORK_UUID; import java.io.File; +import java.io.FileFilter; import java.io.IOException; import java.lang.management.ManagementFactory; import java.security.PrivilegedAction; @@ -29,6 +28,7 @@ import javax.transaction.TransactionManager; import javax.transaction.TransactionSynchronizationRegistry; import javax.transaction.UserTransaction; +import org.apache.commons.io.FileUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.jackrabbit.util.TransientFileFactory; @@ -37,17 +37,20 @@ import org.argeo.ArgeoLogger; import org.argeo.cms.CmsException; import org.argeo.jackrabbit.OsgiJackrabbitRepositoryFactory; import org.argeo.jcr.ArgeoJcrConstants; +import org.eclipse.equinox.http.jetty.JettyConfigurator; +import org.eclipse.equinox.http.jetty.JettyConstants; import org.eclipse.equinox.http.servlet.ExtendedHttpService; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceEvent; import org.osgi.framework.ServiceListener; import org.osgi.framework.ServiceReference; import org.osgi.framework.ServiceRegistration; +import org.osgi.service.cm.Configuration; +import org.osgi.service.cm.ConfigurationAdmin; import org.osgi.service.useradmin.UserAdmin; import bitronix.tm.BitronixTransactionManager; import bitronix.tm.BitronixTransactionSynchronizationRegistry; -import bitronix.tm.Configuration; import bitronix.tm.TransactionManagerServices; /** @@ -62,6 +65,10 @@ import bitronix.tm.TransactionManagerServices; * */ final class Kernel implements KernelHeader, KernelConstants, ServiceListener { + /* + * SERVICE REFERENCES + */ + private ServiceReference configurationAdmin; /* * REGISTERED SERVICES */ @@ -96,6 +103,8 @@ final class Kernel implements KernelHeader, KernelConstants, ServiceListener { public Kernel() { nodeSecurity = new NodeSecurity(); + // log.debug(bc.getDataFile("")); + // log.debug(bc.getDataFile("test")); } final void init() { @@ -111,7 +120,7 @@ final class Kernel implements KernelHeader, KernelConstants, ServiceListener { private void doInit() { long begin = System.currentTimeMillis(); - + ConfigurationAdmin conf = findConfigurationAdmin(); // Use CMS bundle classloader ClassLoader currentContextCl = Thread.currentThread() .getContextClassLoader(); @@ -133,6 +142,7 @@ final class Kernel implements KernelHeader, KernelConstants, ServiceListener { userAdmin = new NodeUserAdmin(transactionManager, repository); // HTTP + initWebServer(conf); ServiceReference sr = bc .getServiceReference(ExtendedHttpService.class); if (sr != null) @@ -168,19 +178,40 @@ final class Kernel implements KernelHeader, KernelConstants, ServiceListener { // TODO also uncompress archives if (initDir.exists()) try { - copyDirectory(initDir, getOsgiInstanceDir()); + FileUtils.copyDirectory(initDir, getOsgiInstanceDir(), + new FileFilter() { + + @Override + public boolean accept(File pathname) { + if (pathname.getName().equals(".svn") + || pathname.getName().equals(".git")) + return false; + return true; + } + }); log.info("CMS initialized from " + initDir.getCanonicalPath()); } catch (IOException e) { throw new CmsException("Cannot initialize from " + initDir, e); } } + /** Can be null */ + private ConfigurationAdmin findConfigurationAdmin() { + configurationAdmin = bc.getServiceReference(ConfigurationAdmin.class); + if (configurationAdmin == null) { + return null; + } + return bc.getService(configurationAdmin); + } + private void initTransactionManager() { - Configuration tmConf = TransactionManagerServices.getConfiguration(); + bitronix.tm.Configuration tmConf = TransactionManagerServices + .getConfiguration(); tmConf.setServerId(getFrameworkProp(FRAMEWORK_UUID)); - File tmBaseDir = new File(getFrameworkProp(TRANSACTIONS_HOME, - getOsgiInstancePath(DIR_TRANSACTIONS))); + // File tmBaseDir = new File(getFrameworkProp(TRANSACTIONS_HOME, + // getOsgiInstancePath(DIR_TRANSACTIONS))); + File tmBaseDir = bc.getDataFile(DIR_TRANSACTIONS); File tmDir1 = new File(tmBaseDir, "btm1"); tmDir1.mkdirs(); tmConf.setLogPart1Filename(new File(tmDir1, tmDir1.getName() + ".tlog") @@ -193,6 +224,44 @@ final class Kernel implements KernelHeader, KernelConstants, ServiceListener { transactionSynchronizationRegistry = getTransactionSynchronizationRegistry(); } + private void initWebServer(ConfigurationAdmin conf) { + String httpPort = getFrameworkProp("org.osgi.service.http.port"); + String httpsPort = getFrameworkProp("org.osgi.service.http.port.secure"); + try { + if (httpPort != null || httpsPort != null) { + Hashtable jettyProps = new Hashtable(); + if (httpPort != null) { + jettyProps.put(JettyConstants.HTTP_PORT, httpPort); + jettyProps.put(JettyConstants.HTTP_ENABLED, true); + } + if (httpsPort != null) { + jettyProps.put(JettyConstants.HTTPS_PORT, httpsPort); + jettyProps.put(JettyConstants.HTTPS_ENABLED, true); + jettyProps.put(JettyConstants.SSL_KEYSTORETYPE, "PKCS12"); + jettyProps.put(JettyConstants.SSL_KEYSTORE, nodeSecurity + .getHttpServerKeyStore().getCanonicalPath()); + jettyProps.put(JettyConstants.SSL_PASSWORD, "changeit"); + jettyProps.put(JettyConstants.SSL_WANTCLIENTAUTH, true); + } + if (conf != null) { + // TODO make filter more generic + String filter = "(" + JettyConstants.HTTP_PORT + "=" + + httpPort + ")"; + if (conf.listConfigurations(filter) != null) + return; + Configuration jettyConf = conf.createFactoryConfiguration( + JETTY_FACTORY_PID, null); + jettyConf.update(jettyProps); + } else { + JettyConfigurator.startServer("default", jettyProps); + } + } + } catch (Exception e) { + throw new CmsException("Cannot initialize web server on " + + httpPortsMsg(httpPort, httpsPort), e); + } + } + private void publish() { // Listen to service publication (also ours) bc.addServiceListener(Kernel.this); @@ -303,8 +372,12 @@ final class Kernel implements KernelHeader, KernelConstants, ServiceListener { Object httpsPort = sr.getProperty("https.port"); dataHttp = new DataHttp(httpService, repository); if (log.isDebugEnabled()) - log.debug("HTTP " + httpPort - + (httpsPort != null ? " - HTTPS " + httpsPort : "")); + log.debug(httpPortsMsg(httpPort, httpsPort)); + } + + private String httpPortsMsg(Object httpPort, Object httpsPort) { + return "HTTP " + httpPort + + (httpsPort != null ? " - HTTPS " + httpsPort : ""); } @Override diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelConstants.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelConstants.java index afb6b29e9..f7feb3106 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelConstants.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelConstants.java @@ -18,8 +18,6 @@ public interface KernelConstants { final static String REPO_SEARCH_CACHE_SIZE = "argeo.node.repo.searchCacheSize"; final static String REPO_MAX_VOLATILE_INDEX_SIZE = "argeo.node.repo.maxVolatileIndexSize"; - final static String DIR_NODE = "node"; - final static String DIR_TRANSACTIONS = "transactions"; final static String TRANSACTIONS_HOME = "argeo.node.transactions.home"; final static String I18N_DEFAULT_LOCALE = "argeo.i18n.defaultLocale"; @@ -32,6 +30,12 @@ public interface KernelConstants { final static String[] DEFAULT_CNDS = { "/org/argeo/jcr/argeo.cnd", "/org/argeo/cms/cms.cnd" }; + // Directories + final static String DIR_NODE = "node"; + final static String DIR_TRANSACTIONS = "transactions"; + final static String DIR_PKI = "pki"; + final static String DIR_PKI_PRIVATE = DIR_PKI + "/private"; + // Security final static String DEFAULT_SECURITY_KEY = "argeo"; final static String JAAS_CONFIG = "/org/argeo/cms/internal/kernel/jaas.cfg"; @@ -49,4 +53,6 @@ public interface KernelConstants { final static String PATH_WORKBENCH = "/ui"; final static String PATH_WORKBENCH_PUBLIC = PATH_WORKBENCH + "/public"; + final static String JETTY_FACTORY_PID = "org.eclipse.equinox.http.jetty.config"; //$NON-NLS-1$ + } diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeSecurity.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeSecurity.java index 6714bd6e7..eeb2b18b4 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeSecurity.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeSecurity.java @@ -32,37 +32,28 @@ class NodeSecurity implements KernelConstants { public final static int STAGING = 2; public final static int DEV = 1; - final static String SECURITY_PROVIDER = "BC";// Bouncy Castle - private final boolean firstInit; - private final static Log log; - static { - log = LogFactory.getLog(NodeSecurity.class); - // Make Bouncy Castle the default provider - Provider provider = new BouncyCastleProvider(); - int position = Security.insertProviderAt(provider, 1); - if (position == -1) - log.error("Provider " + provider.getName() - + " already installed and could not be set as default"); - Provider defaultProvider = Security.getProviders()[0]; - if (!defaultProvider.getName().equals(SECURITY_PROVIDER)) - log.error("Provider name is " + defaultProvider.getName() - + " but it should be " + SECURITY_PROVIDER); - } - private final Subject kernelSubject; private int securityLevel = STAGING; + private final File keyStoreFile; + public NodeSecurity() { // Configure JAAS first URL url = getClass().getClassLoader().getResource( KernelConstants.JAAS_CONFIG); System.setProperty("java.security.auth.login.config", url.toExternalForm()); + // log.debug("JASS config: " + url.toExternalForm()); + // disable Jetty autostart + // System.setProperty("org.eclipse.equinox.http.jetty.autostart", + // "false"); firstInit = !new File(getOsgiInstanceDir(), DIR_NODE).exists(); + this.keyStoreFile = new File(KernelUtils.getOsgiInstanceDir(), + "node.p12"); this.kernelSubject = logInKernel(); } @@ -136,8 +127,6 @@ class NodeSecurity implements KernelConstants { private void createKeyStoreIfNeeded() { char[] ksPwd = "changeit".toCharArray(); char[] keyPwd = Arrays.copyOf(ksPwd, ksPwd.length); - File keyStoreFile = new File(KernelUtils.getOsgiInstanceDir(), - "node.p12"); if (!keyStoreFile.exists()) { try { keyStoreFile.getParentFile().mkdirs(); @@ -151,4 +140,24 @@ class NodeSecurity implements KernelConstants { } } } + + File getHttpServerKeyStore() { + return keyStoreFile; + } + + private final static String SECURITY_PROVIDER = "BC";// Bouncy Castle + private final static Log log; + static { + log = LogFactory.getLog(NodeSecurity.class); + // Make Bouncy Castle the default provider + Provider provider = new BouncyCastleProvider(); + int position = Security.insertProviderAt(provider, 1); + if (position == -1) + log.error("Provider " + provider.getName() + + " already installed and could not be set as default"); + Provider defaultProvider = Security.getProviders()[0]; + if (!defaultProvider.getName().equals(SECURITY_PROVIDER)) + log.error("Provider name is " + defaultProvider.getName() + + " but it should be " + SECURITY_PROVIDER); + } } diff --git a/org.argeo.security.jackrabbit/build.properties b/org.argeo.security.jackrabbit/build.properties index 8103225a3..0cc2cd06c 100644 --- a/org.argeo.security.jackrabbit/build.properties +++ b/org.argeo.security.jackrabbit/build.properties @@ -17,7 +17,6 @@ additional.bundles = org.junit,\ EDU.oswego.cs.dl.util.concurrent,\ org.apache.lucene,\ org.apache.tika.core,\ - org.apache.tika.parsers,\ org.apache.commons.dbcp,\ org.apache.commons.pool,\ org.argeo.server.jcr diff --git a/org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/RapWorkbenchLogin.java b/org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/RapWorkbenchLogin.java index 1f4914ace..8c380bd3e 100644 --- a/org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/RapWorkbenchLogin.java +++ b/org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/RapWorkbenchLogin.java @@ -6,6 +6,8 @@ import org.eclipse.swt.widgets.Display; import org.eclipse.ui.PlatformUI; public class RapWorkbenchLogin extends WorkbenchLogin { + // private final static Log log = + // LogFactory.getLog(RapWorkbenchLogin.class); @Override protected int createAndRunWorkbench(Display display, String username) { @@ -22,8 +24,13 @@ public class RapWorkbenchLogin extends WorkbenchLogin { public int createUI() { JavaScriptExecutor jsExecutor = RWT.getClient().getService( JavaScriptExecutor.class); - int returnCode = super.createUI(); - jsExecutor.execute("location.reload()"); + int returnCode; + try { + returnCode = super.createUI(); + } finally { + // always reload + jsExecutor.execute("location.reload()"); + } return returnCode; } diff --git a/org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/SecureEntryPoint.java b/org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/SecureEntryPoint.java index 5ff76a9ea..a42fc2a8f 100644 --- a/org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/SecureEntryPoint.java +++ b/org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/SecureEntryPoint.java @@ -20,7 +20,7 @@ import java.security.AccessController; import java.security.PrivilegedAction; import javax.security.auth.Subject; -import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.login.CredentialNotFoundException; import javax.security.auth.login.FailedLoginException; import javax.security.auth.login.LoginContext; import javax.security.auth.login.LoginException; @@ -32,6 +32,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.argeo.ArgeoException; import org.argeo.cms.auth.AuthConstants; +import org.argeo.cms.auth.ThreadDeathLoginException; import org.argeo.cms.widgets.auth.DefaultLoginDialog; import org.argeo.eclipse.ui.dialogs.ErrorFeedback; import org.eclipse.jface.dialogs.MessageDialog; @@ -86,8 +87,9 @@ public class SecureEntryPoint implements EntryPoint { subject = new Subject(); final LoginContext loginContext; + DefaultLoginDialog callbackHandler; try { - CallbackHandler callbackHandler = new DefaultLoginDialog( + callbackHandler = new DefaultLoginDialog( display.getActiveShell()); loginContext = new LoginContext( AuthConstants.LOGIN_CONTEXT_USER, subject, @@ -118,7 +120,13 @@ public class SecureEntryPoint implements EntryPoint { "Bad Credentials", e.getMessage()); // retry login continue tryLogin; + } catch (CredentialNotFoundException e) { + MessageDialog.openInformation(display.getActiveShell(), + "No Credentials", e.getMessage()); + // retry login + continue tryLogin; } catch (LoginException e) { + callbackHandler.getShell().dispose(); return processLoginDeath(display, e); } } @@ -166,7 +174,7 @@ public class SecureEntryPoint implements EntryPoint { return returnCode; } - private Integer processLoginDeath(Display display, LoginException e) { + private Integer processLoginDeath(Display display, Throwable e) { // check thread death ThreadDeath td = wasCausedByThreadDeath(e); if (td != null) { @@ -193,7 +201,8 @@ public class SecureEntryPoint implements EntryPoint { protected ThreadDeath wasCausedByThreadDeath(Throwable t) { if (t instanceof ThreadDeath) return (ThreadDeath) t; - + if (t instanceof ThreadDeathLoginException) + return ((ThreadDeathLoginException) t).getThreadDeath(); if (t.getCause() != null) return wasCausedByThreadDeath(t.getCause()); else diff --git a/org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/WorkbenchLogin.java b/org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/WorkbenchLogin.java index e7a5c0c35..2a98c6c9f 100644 --- a/org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/WorkbenchLogin.java +++ b/org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/WorkbenchLogin.java @@ -17,6 +17,7 @@ import org.argeo.cms.auth.CurrentUser; import org.argeo.cms.auth.HttpRequestCallbackHandler; import org.argeo.cms.widgets.auth.CmsLogin; import org.argeo.cms.widgets.auth.CmsLoginShell; +import org.argeo.eclipse.ui.dialogs.ErrorFeedback; import org.argeo.eclipse.ui.specific.UiContext; import org.eclipse.rap.rwt.RWT; import org.eclipse.rap.rwt.application.EntryPoint; @@ -42,8 +43,17 @@ abstract class WorkbenchLogin implements EntryPoint, CmsView { CmsLoginShell loginShell = createCmsLoginShell(); loginShell.open(); while (!loginShell.getShell().isDisposed()) { - if (!display.readAndDispatch()) { - display.sleep(); + try { + if (!display.readAndDispatch()) + display.sleep(); + } catch (Exception e1) { + try { + Thread.sleep(3000); + } catch (InterruptedException e2) { + // silent + } + ErrorFeedback.show("Login failed", e1); + return -1; } } } catch (LoginException e) { diff --git a/org.argeo.server.jcr/build.properties b/org.argeo.server.jcr/build.properties index 943d48efe..f4baf37e8 100644 --- a/org.argeo.server.jcr/build.properties +++ b/org.argeo.server.jcr/build.properties @@ -19,6 +19,5 @@ additional.bundles = org.junit,\ EDU.oswego.cs.dl.util.concurrent,\ org.apache.lucene,\ org.apache.tika.core,\ - org.apache.tika.parsers,\ org.apache.commons.dbcp,\ org.apache.commons.pool