From: Bruno Sinou Date: Thu, 15 Sep 2016 14:56:20 +0000 (+0000) Subject: Remove APIs from utils X-Git-Tag: argeo-commons-2.1.46~19 X-Git-Url: https://git.argeo.org/?a=commitdiff_plain;h=77a5498dd5d10d2442127022efd6501a7dbddbae;p=lgpl%2Fargeo-commons.git Remove APIs from utils git-svn-id: https://svn.argeo.org/commons/trunk@9165 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- diff --git a/org.argeo.cms.ui.workbench/META-INF/spring/keyring.xml b/org.argeo.cms.ui.workbench/META-INF/spring/keyring.xml index 74c4ad6cf..59c7c544b 100644 --- a/org.argeo.cms.ui.workbench/META-INF/spring/keyring.xml +++ b/org.argeo.cms.ui.workbench/META-INF/spring/keyring.xml @@ -18,7 +18,7 @@ - + diff --git a/org.argeo.cms.ui.workbench/META-INF/spring/osgi.xml b/org.argeo.cms.ui.workbench/META-INF/spring/osgi.xml index df3322635..dc6e2707f 100644 --- a/org.argeo.cms.ui.workbench/META-INF/spring/osgi.xml +++ b/org.argeo.cms.ui.workbench/META-INF/spring/osgi.xml @@ -15,7 +15,7 @@ unbind-method="unregister" /> - + @@ -37,5 +37,5 @@ - + \ No newline at end of file diff --git a/org.argeo.cms.ui.workbench/src/org/argeo/eclipse/ui/workbench/commands/AddRemoteRepository.java b/org.argeo.cms.ui.workbench/src/org/argeo/eclipse/ui/workbench/commands/AddRemoteRepository.java index cf6a5b0f0..06b6fe4a8 100644 --- a/org.argeo.cms.ui.workbench/src/org/argeo/eclipse/ui/workbench/commands/AddRemoteRepository.java +++ b/org.argeo.cms.ui.workbench/src/org/argeo/eclipse/ui/workbench/commands/AddRemoteRepository.java @@ -33,7 +33,7 @@ import org.argeo.node.ArgeoNames; import org.argeo.node.ArgeoTypes; import org.argeo.node.NodeConstants; import org.argeo.node.NodeUtils; -import org.argeo.util.security.Keyring; +import org.argeo.node.security.Keyring; import org.eclipse.core.commands.AbstractHandler; import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.commands.ExecutionException; diff --git a/org.argeo.cms.ui.workbench/src/org/argeo/eclipse/ui/workbench/internal/jcr/NodeContentProvider.java b/org.argeo.cms.ui.workbench/src/org/argeo/eclipse/ui/workbench/internal/jcr/NodeContentProvider.java index 243d93265..be623871e 100644 --- a/org.argeo.cms.ui.workbench/src/org/argeo/eclipse/ui/workbench/internal/jcr/NodeContentProvider.java +++ b/org.argeo.cms.ui.workbench/src/org/argeo/eclipse/ui/workbench/internal/jcr/NodeContentProvider.java @@ -32,7 +32,7 @@ import org.argeo.eclipse.ui.workbench.internal.jcr.model.SingleJcrNodeElem; import org.argeo.jcr.RepositoryRegister; import org.argeo.node.NodeConstants; import org.argeo.node.NodeUtils; -import org.argeo.util.security.Keyring; +import org.argeo.node.security.Keyring; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.Viewer; diff --git a/org.argeo.cms.ui.workbench/src/org/argeo/eclipse/ui/workbench/internal/jcr/model/RemoteRepositoryElem.java b/org.argeo.cms.ui.workbench/src/org/argeo/eclipse/ui/workbench/internal/jcr/model/RemoteRepositoryElem.java index 90acc034e..edaf2396f 100644 --- a/org.argeo.cms.ui.workbench/src/org/argeo/eclipse/ui/workbench/internal/jcr/model/RemoteRepositoryElem.java +++ b/org.argeo.cms.ui.workbench/src/org/argeo/eclipse/ui/workbench/internal/jcr/model/RemoteRepositoryElem.java @@ -28,7 +28,7 @@ import org.argeo.eclipse.ui.EclipseUiException; import org.argeo.eclipse.ui.TreeParent; import org.argeo.node.ArgeoNames; import org.argeo.node.NodeUtils; -import org.argeo.util.security.Keyring; +import org.argeo.node.security.Keyring; /** Root of a remote repository */ public class RemoteRepositoryElem extends RepositoryElem { diff --git a/org.argeo.cms.ui.workbench/src/org/argeo/eclipse/ui/workbench/internal/jcr/model/RepositoriesElem.java b/org.argeo.cms.ui.workbench/src/org/argeo/eclipse/ui/workbench/internal/jcr/model/RepositoriesElem.java index 864048a76..294757acd 100644 --- a/org.argeo.cms.ui.workbench/src/org/argeo/eclipse/ui/workbench/internal/jcr/model/RepositoriesElem.java +++ b/org.argeo.cms.ui.workbench/src/org/argeo/eclipse/ui/workbench/internal/jcr/model/RepositoriesElem.java @@ -30,7 +30,7 @@ import org.argeo.eclipse.ui.dialogs.ErrorFeedback; import org.argeo.jcr.RepositoryRegister; import org.argeo.node.ArgeoNames; import org.argeo.node.NodeUtils; -import org.argeo.util.security.Keyring; +import org.argeo.node.security.Keyring; /** * UI Tree component that implements the Argeo abstraction of a diff --git a/org.argeo.cms.ui.workbench/src/org/argeo/eclipse/ui/workbench/jcr/JcrBrowserView.java b/org.argeo.cms.ui.workbench/src/org/argeo/eclipse/ui/workbench/jcr/JcrBrowserView.java index 92deb71a1..c30082765 100644 --- a/org.argeo.cms.ui.workbench/src/org/argeo/eclipse/ui/workbench/jcr/JcrBrowserView.java +++ b/org.argeo.cms.ui.workbench/src/org/argeo/eclipse/ui/workbench/jcr/JcrBrowserView.java @@ -40,7 +40,7 @@ import org.argeo.eclipse.ui.workbench.internal.jcr.NodeLabelProvider; import org.argeo.eclipse.ui.workbench.internal.jcr.PropertiesContentProvider; import org.argeo.eclipse.ui.workbench.internal.jcr.model.SingleJcrNodeElem; import org.argeo.jcr.RepositoryRegister; -import org.argeo.util.security.Keyring; +import org.argeo.node.security.Keyring; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.viewers.ColumnLabelProvider; import org.eclipse.jface.viewers.ISelectionChangedListener; diff --git a/org.argeo.cms.ui.workbench/src/org/argeo/security/ui/admin/internal/parts/UserBatchUpdateWizard.java b/org.argeo.cms.ui.workbench/src/org/argeo/security/ui/admin/internal/parts/UserBatchUpdateWizard.java index b3bff5943..b532ddef5 100644 --- a/org.argeo.cms.ui.workbench/src/org/argeo/security/ui/admin/internal/parts/UserBatchUpdateWizard.java +++ b/org.argeo.cms.ui.workbench/src/org/argeo/security/ui/admin/internal/parts/UserBatchUpdateWizard.java @@ -210,7 +210,7 @@ public class UserBatchUpdateWizard extends Wizard { // @Override // protected IStatus doRun(IProgressMonitor progressMonitor) { // try { - // ArgeoMonitor monitor = new EclipseArgeoMonitor(progressMonitor); + // JcrMonitor monitor = new EclipseJcrMonitor(progressMonitor); // int total = usersToUpdate.size(); // monitor.beginTask("Performing change", total); // userAdminWrapper.beginTransactionIfNeeded(); diff --git a/org.argeo.cms.ui/src/org/argeo/cms/maintenance/AbstractOsgiComposite.java b/org.argeo.cms.ui/src/org/argeo/cms/maintenance/AbstractOsgiComposite.java index 2494d90c3..8c893f2f3 100644 --- a/org.argeo.cms.ui/src/org/argeo/cms/maintenance/AbstractOsgiComposite.java +++ b/org.argeo.cms.ui/src/org/argeo/cms/maintenance/AbstractOsgiComposite.java @@ -7,7 +7,6 @@ import org.apache.commons.logging.LogFactory; import org.argeo.cms.util.CmsUtils; import org.eclipse.swt.SWT; import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.osgi.framework.BundleContext; import org.osgi.framework.FrameworkUtil; diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/internal/Activator.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/internal/Activator.java index 052762ec0..410498725 100644 --- a/org.argeo.cms.ui/src/org/argeo/cms/ui/internal/Activator.java +++ b/org.argeo.cms.ui/src/org/argeo/cms/ui/internal/Activator.java @@ -1,7 +1,6 @@ package org.argeo.cms.ui.internal; import org.argeo.cms.maintenance.MaintenanceUi; -import org.argeo.cms.ui.CmsStyles; import org.argeo.cms.ui.internal.rwt.UserUi; import org.argeo.node.NodeState; import org.argeo.util.LangUtils; diff --git a/org.argeo.cms.ui/src/org/argeo/cms/util/CmsLink.java b/org.argeo.cms.ui/src/org/argeo/cms/util/CmsLink.java index 3778515dc..865824c1a 100644 --- a/org.argeo.cms.ui/src/org/argeo/cms/util/CmsLink.java +++ b/org.argeo.cms.ui/src/org/argeo/cms/util/CmsLink.java @@ -22,7 +22,6 @@ import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Label; import org.osgi.framework.BundleContext; -import org.osgi.framework.FrameworkUtil; /** A link to an internal or external location. */ public class CmsLink implements CmsUiProvider { diff --git a/org.argeo.cms.ui/src/org/argeo/cms/widgets/auth/CmsLoginShell.java b/org.argeo.cms.ui/src/org/argeo/cms/widgets/auth/CmsLoginShell.java index 6afaa767c..c31ad9657 100644 --- a/org.argeo.cms.ui/src/org/argeo/cms/widgets/auth/CmsLoginShell.java +++ b/org.argeo.cms.ui/src/org/argeo/cms/widgets/auth/CmsLoginShell.java @@ -1,13 +1,11 @@ package org.argeo.cms.widgets.auth; import org.argeo.cms.ui.CmsView; -import org.argeo.eclipse.ui.dialogs.ErrorFeedback; import org.eclipse.rap.rwt.RWT; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; -import org.eclipse.swt.widgets.Widget; /** The site-related user menu */ public class CmsLoginShell extends CmsLogin { diff --git a/org.argeo.cms/ext/test/org/argeo/cms/security/PasswordBasedEncryptionTest.java b/org.argeo.cms/ext/test/org/argeo/cms/security/PasswordBasedEncryptionTest.java new file mode 100644 index 000000000..49319f15a --- /dev/null +++ b/org.argeo.cms/ext/test/org/argeo/cms/security/PasswordBasedEncryptionTest.java @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.cms.security; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; + +import javax.crypto.Cipher; +import javax.crypto.CipherInputStream; +import javax.crypto.CipherOutputStream; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.PBEKeySpec; +import javax.crypto.spec.PBEParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import javax.xml.bind.DatatypeConverter; + +import junit.framework.TestCase; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.cms.security.PasswordBasedEncryption; + +public class PasswordBasedEncryptionTest extends TestCase { + private final static Log log = LogFactory + .getLog(PasswordBasedEncryptionTest.class); + + public void testEncryptDecrypt() { + final String password = "test long password since they are safer"; + PasswordBasedEncryption pbeEnc = new PasswordBasedEncryption( + password.toCharArray()); + String message = "Hello World!"; + log.info("Password:\t'" + password + "'"); + log.info("Message:\t'" + message + "'"); + byte[] encrypted = pbeEnc.encryptString(message); + log.info("Encrypted:\t'" + + DatatypeConverter.printBase64Binary(encrypted) + "'"); + PasswordBasedEncryption pbeDec = new PasswordBasedEncryption( + password.toCharArray()); + InputStream in = null; + in = new ByteArrayInputStream(encrypted); + String decrypted = pbeDec.decryptAsString(in); + log.info("Decrypted:\t'" + decrypted + "'"); + IOUtils.closeQuietly(in); + assertEquals(message, decrypted); + } + + public void testPBEWithMD5AndDES() throws Exception { + String password = "test"; + String message = "Hello World!"; + + byte[] salt = { (byte) 0xc7, (byte) 0x73, (byte) 0x21, (byte) 0x8c, + (byte) 0x7e, (byte) 0xc8, (byte) 0xee, (byte) 0x99 }; + + int count = 1024; + + String cipherAlgorithm = "PBEWithMD5AndDES"; + String secretKeyAlgorithm = "PBEWithMD5AndDES"; + SecretKeyFactory keyFac = SecretKeyFactory + .getInstance(secretKeyAlgorithm); + PBEKeySpec pbeKeySpec = new PBEKeySpec(password.toCharArray()); + PBEParameterSpec pbeParamSpec = new PBEParameterSpec(salt, count); + SecretKey pbeKey = keyFac.generateSecret(pbeKeySpec); + Cipher ecipher = Cipher.getInstance(cipherAlgorithm); + ecipher.init(Cipher.ENCRYPT_MODE, pbeKey, pbeParamSpec); + Cipher dcipher = Cipher.getInstance(cipherAlgorithm); + dcipher.init(Cipher.DECRYPT_MODE, pbeKey, pbeParamSpec); + + byte[] encrypted = ecipher.doFinal(message.getBytes()); + byte[] decrypted = dcipher.doFinal(encrypted); + assertEquals(message, new String(decrypted)); + + } + + public void testPBEWithSHA1AndAES() throws Exception { + String password = "test"; + String message = "Hello World!"; + + byte[] salt = { (byte) 0xc7, (byte) 0x73, (byte) 0x21, (byte) 0x8c, + (byte) 0x7e, (byte) 0xc8, (byte) 0xee, (byte) 0x99 }; + byte[] iv = { (byte) 0xc7, (byte) 0x73, (byte) 0x21, (byte) 0x8c, + (byte) 0x7e, (byte) 0xc8, (byte) 0xee, (byte) 0x99, + (byte) 0xc7, (byte) 0x73, (byte) 0x21, (byte) 0x8c, + (byte) 0x7e, (byte) 0xc8, (byte) 0xee, (byte) 0x99 }; + + int count = 1024; + // int keyLength = 256; + int keyLength = 128; + + String cipherAlgorithm = "AES/CBC/PKCS5Padding"; + String secretKeyAlgorithm = "PBKDF2WithHmacSHA1"; + SecretKeyFactory keyFac = SecretKeyFactory + .getInstance(secretKeyAlgorithm); + PBEKeySpec pbeKeySpec = new PBEKeySpec(password.toCharArray(), salt, + count, keyLength); + SecretKey tmp = keyFac.generateSecret(pbeKeySpec); + SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES"); + Cipher ecipher = Cipher.getInstance(cipherAlgorithm); + ecipher.init(Cipher.ENCRYPT_MODE, secret, new IvParameterSpec(iv)); + + // decrypt + keyFac = SecretKeyFactory.getInstance(secretKeyAlgorithm); + pbeKeySpec = new PBEKeySpec(password.toCharArray(), salt, count, + keyLength); + tmp = keyFac.generateSecret(pbeKeySpec); + secret = new SecretKeySpec(tmp.getEncoded(), "AES"); + // AlgorithmParameters params = ecipher.getParameters(); + // byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV(); + Cipher dcipher = Cipher.getInstance(cipherAlgorithm); + dcipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv)); + + byte[] encrypted = ecipher.doFinal(message.getBytes()); + byte[] decrypted = dcipher.doFinal(encrypted); + assertEquals(message, new String(decrypted)); + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + CipherOutputStream cipherOut = new CipherOutputStream(out, ecipher); + cipherOut.write(message.getBytes()); + IOUtils.closeQuietly(cipherOut); + byte[] enc = out.toByteArray(); + + ByteArrayInputStream in = new ByteArrayInputStream(enc); + CipherInputStream cipherIn = new CipherInputStream(in, dcipher); + ByteArrayOutputStream dec = new ByteArrayOutputStream(); + IOUtils.copy(cipherIn, dec); + assertEquals(message, new String(dec.toByteArray())); + } +} diff --git a/org.argeo.cms/ext/test/org/argeo/cms/tabular/JcrTabularTest.java b/org.argeo.cms/ext/test/org/argeo/cms/tabular/JcrTabularTest.java index 0d8a8ce5f..b52ffe3c1 100644 --- a/org.argeo.cms/ext/test/org/argeo/cms/tabular/JcrTabularTest.java +++ b/org.argeo.cms/ext/test/org/argeo/cms/tabular/JcrTabularTest.java @@ -25,15 +25,13 @@ import javax.jcr.PropertyType; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.jackrabbit.commons.cnd.CndImporter; -import org.argeo.cms.tabular.JcrTabularRowIterator; -import org.argeo.cms.tabular.JcrTabularWriter; import org.argeo.jackrabbit.unit.AbstractJackrabbitTestCase; import org.argeo.node.ArgeoNames; import org.argeo.node.ArgeoTypes; -import org.argeo.util.tabular.TabularColumn; -import org.argeo.util.tabular.TabularRow; -import org.argeo.util.tabular.TabularRowIterator; -import org.argeo.util.tabular.TabularWriter; +import org.argeo.node.tabular.TabularColumn; +import org.argeo.node.tabular.TabularRow; +import org.argeo.node.tabular.TabularRowIterator; +import org.argeo.node.tabular.TabularWriter; public class JcrTabularTest extends AbstractJackrabbitTestCase { private final static Log log = LogFactory.getLog(JcrTabularTest.class); diff --git a/org.argeo.cms/src/org/argeo/cms/auth/KeyringLoginModule.java b/org.argeo.cms/src/org/argeo/cms/auth/KeyringLoginModule.java new file mode 100644 index 000000000..2c4958254 --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/auth/KeyringLoginModule.java @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.cms.auth; + +import java.security.AccessController; +import java.util.Map; +import java.util.Set; + +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.PBEKeySpec; +import javax.crypto.spec.SecretKeySpec; +import javax.security.auth.Subject; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.login.LoginException; +import javax.security.auth.spi.LoginModule; + +import org.argeo.cms.security.PasswordBasedEncryption; +import org.argeo.node.security.PBEKeySpecCallback; + +/** Adds a secret key to the private credentials */ +public class KeyringLoginModule implements LoginModule { + private Subject subject; + private CallbackHandler callbackHandler; + private SecretKey secretKey; + + public void initialize(Subject subject, CallbackHandler callbackHandler, + Map sharedState, Map options) { + this.subject = subject; + if (subject == null) { + subject = Subject.getSubject(AccessController.getContext()); + } + this.callbackHandler = callbackHandler; + } + + public boolean login() throws LoginException { + Set pbes = subject.getPrivateCredentials(SecretKey.class); + if (pbes.size() > 0) + return true; + PasswordCallback pc = new PasswordCallback("Master password", false); + PBEKeySpecCallback pbeCb = new PBEKeySpecCallback(); + Callback[] callbacks = { pc, pbeCb }; + try { + callbackHandler.handle(callbacks); + char[] password = pc.getPassword(); + + SecretKeyFactory keyFac = SecretKeyFactory.getInstance(pbeCb + .getSecretKeyFactory()); + PBEKeySpec keySpec; + if (pbeCb.getKeyLength() != null) + keySpec = new PBEKeySpec(password, pbeCb.getSalt(), + pbeCb.getIterationCount(), pbeCb.getKeyLength()); + else + keySpec = new PBEKeySpec(password, pbeCb.getSalt(), + pbeCb.getIterationCount()); + + String secKeyEncryption = pbeCb.getSecretKeyEncryption(); + if (secKeyEncryption != null) { + SecretKey tmp = keyFac.generateSecret(keySpec); + secretKey = new SecretKeySpec(tmp.getEncoded(), + secKeyEncryption); + } else { + secretKey = keyFac.generateSecret(keySpec); + } + } catch (Exception e) { + LoginException le = new LoginException("Cannot login keyring"); + le.initCause(e); + throw le; + } + return true; + } + + public boolean commit() throws LoginException { + if (secretKey != null) + subject.getPrivateCredentials().add(secretKey); + return true; + } + + public boolean abort() throws LoginException { + return true; + } + + public boolean logout() throws LoginException { + Set pbes = subject + .getPrivateCredentials(PasswordBasedEncryption.class); + pbes.clear(); + return true; + } + +} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/Activator.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/Activator.java index ecd36476f..99d5dbb3e 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/Activator.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/Activator.java @@ -8,8 +8,6 @@ import java.util.Dictionary; import java.util.List; import java.util.Locale; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; import org.argeo.cms.CmsException; import org.argeo.node.ArgeoLogger; import org.argeo.node.NodeConstants; @@ -21,7 +19,6 @@ import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; import org.osgi.framework.ServiceReference; -import org.osgi.service.condpermadmin.ConditionalPermissionAdmin; import org.osgi.service.log.LogReaderService; /** @@ -29,12 +26,9 @@ import org.osgi.service.log.LogReaderService; * access to kernel information for the rest of the bundle (and only it) */ public class Activator implements BundleActivator { - private final Log log = LogFactory.getLog(Activator.class); - private static Activator instance; private BundleContext bc; - private ConditionalPermissionAdmin permissionAdmin; private LogReaderService logReaderService; // private ConfigurationAdmin configurationAdmin; @@ -47,7 +41,6 @@ public class Activator implements BundleActivator { public void start(BundleContext bundleContext) throws Exception { instance = this; this.bc = bundleContext; - this.permissionAdmin = getService(ConditionalPermissionAdmin.class); this.logReaderService = getService(LogReaderService.class); // this.configurationAdmin = getService(ConfigurationAdmin.class); @@ -62,8 +55,10 @@ public class Activator implements BundleActivator { } private void initSecurity() { - URL url = getClass().getClassLoader().getResource(KernelConstants.JAAS_CONFIG); - System.setProperty("java.security.auth.login.config", url.toExternalForm()); + URL url = getClass().getClassLoader().getResource( + KernelConstants.JAAS_CONFIG); + System.setProperty("java.security.auth.login.config", + url.toExternalForm()); } private void initArgeoLogger() { @@ -82,24 +77,8 @@ public class Activator implements BundleActivator { Files.write(stateUuidPath, stateUuid.getBytes()); } nodeState = new CmsState(stateUuid); - // Object cn; - // Configuration nodeConf = - // configurationAdmin.getConfiguration(NodeConstants.NODE_STATE_PID); - // Dictionary props = nodeConf.getProperties(); - // if (props == null) { - // if (log.isDebugEnabled()) - // log.debug("Clean node state"); - // Dictionary envProps = new Hashtable<>(); - // // Use the UUID of the first framework run as state UUID - // cn = bc.getProperty(Constants.FRAMEWORK_UUID); - // envProps.put(NodeConstants.CN, cn); - // nodeConf.update(envProps); - // } else { - // cn = props.get(NodeConstants.CN); - // if (cn == null) - // throw new CmsException("No state UUID available"); - // } - Dictionary regProps = LangUtils.init(Constants.SERVICE_PID, NodeConstants.NODE_STATE_PID); + Dictionary regProps = LangUtils.init( + Constants.SERVICE_PID, NodeConstants.NODE_STATE_PID); regProps.put(NodeConstants.CN, stateUuid); bc.registerService(NodeState.class, nodeState, regProps); @@ -120,7 +99,6 @@ public class Activator implements BundleActivator { instance = null; this.bc = null; - this.permissionAdmin = null; this.logReaderService = null; // this.configurationAdmin = null; } diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/DeployConfig.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/DeployConfig.java index 042d1f634..9908e9772 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/DeployConfig.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/DeployConfig.java @@ -20,7 +20,6 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.argeo.cms.CmsException; import org.argeo.node.NodeConstants; -import org.argeo.osgi.useradmin.UserAdminConf; import org.argeo.util.naming.AttributesDictionary; import org.argeo.util.naming.LdifParser; import org.argeo.util.naming.LdifWriter; diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/JcrKeyring.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/JcrKeyring.java deleted file mode 100644 index 396093ff7..000000000 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/JcrKeyring.java +++ /dev/null @@ -1,295 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.cms.internal.kernel; - -import java.io.ByteArrayInputStream; -import java.io.CharArrayReader; -import java.io.InputStream; -import java.io.Reader; -import java.security.Provider; -import java.security.SecureRandom; - -import javax.crypto.Cipher; -import javax.crypto.CipherInputStream; -import javax.crypto.SecretKey; -import javax.crypto.spec.IvParameterSpec; -import javax.jcr.Binary; -import javax.jcr.Node; -import javax.jcr.Property; -import javax.jcr.RepositoryException; -import javax.jcr.Session; - -import org.apache.commons.io.IOUtils; -import org.argeo.jcr.ArgeoJcrException; -import org.argeo.jcr.JcrUtils; -import org.argeo.node.ArgeoNames; -import org.argeo.node.ArgeoTypes; -import org.argeo.node.NodeUtils; -import org.argeo.util.security.AbstractKeyring; -import org.argeo.util.security.PBEKeySpecCallback; - -/** JCR based implementation of a keyring */ -public class JcrKeyring extends AbstractKeyring implements ArgeoNames { - /** - * Stronger with 256, but causes problem with Oracle JVM, force 128 in this - * case - */ - public final static Long DEFAULT_SECRETE_KEY_LENGTH = 256l; - public final static String DEFAULT_SECRETE_KEY_FACTORY = "PBKDF2WithHmacSHA1"; - public final static String DEFAULT_SECRETE_KEY_ENCRYPTION = "AES"; - public final static String DEFAULT_CIPHER_NAME = "AES/CBC/PKCS5Padding"; - - private Integer iterationCountFactor = 200; - private Long secreteKeyLength = DEFAULT_SECRETE_KEY_LENGTH; - private String secreteKeyFactoryName = DEFAULT_SECRETE_KEY_FACTORY; - private String secreteKeyEncryption = DEFAULT_SECRETE_KEY_ENCRYPTION; - private String cipherName = DEFAULT_CIPHER_NAME; - - private Session session; - - /** - * When setup is called the session has not yet been saved and we don't want - * to save it since there maybe other data which would be inconsistent. So - * we keep a reference to this node which will then be used (an reset to - * null) when handling the PBE callback. We keep one per thread in case - * multiple users are accessing the same instance of a keyring. - */ - private ThreadLocal notYetSavedKeyring = new ThreadLocal() { - - @Override - protected Node initialValue() { - return null; - } - }; - - @Override - protected Boolean isSetup() { - try { - if (notYetSavedKeyring.get() != null) - return true; - - Node userHome = NodeUtils.getUserHome(session); - return userHome.hasNode(ARGEO_KEYRING); - } catch (RepositoryException e) { - throw new ArgeoJcrException("Cannot check whether keyring is setup", e); - } - } - - @Override - protected void setup(char[] password) { - Binary binary = null; - InputStream in = null; - try { - Node userHome = NodeUtils.getUserHome(session); - if (userHome.hasNode(ARGEO_KEYRING)) - throw new ArgeoJcrException("Keyring already setup"); - Node keyring = userHome.addNode(ARGEO_KEYRING); - keyring.addMixin(ArgeoTypes.ARGEO_PBE_SPEC); - - // deterministic salt and iteration count based on username - String username = session.getUserID(); - byte[] salt = new byte[8]; - byte[] usernameBytes = username.getBytes(); - for (int i = 0; i < salt.length; i++) { - if (i < usernameBytes.length) - salt[i] = usernameBytes[i]; - else - salt[i] = 0; - } - in = new ByteArrayInputStream(salt); - binary = session.getValueFactory().createBinary(in); - keyring.setProperty(ARGEO_SALT, binary); - - Integer iterationCount = username.length() * iterationCountFactor; - keyring.setProperty(ARGEO_ITERATION_COUNT, iterationCount); - - // default algo - // TODO check if algo and key length are available, use DES if not - keyring.setProperty(ARGEO_SECRET_KEY_FACTORY, secreteKeyFactoryName); - keyring.setProperty(ARGEO_KEY_LENGTH, secreteKeyLength); - keyring.setProperty(ARGEO_SECRET_KEY_ENCRYPTION, secreteKeyEncryption); - keyring.setProperty(ARGEO_CIPHER, cipherName); - - // keyring.getSession().save(); - - // encrypted password hash - // IOUtils.closeQuietly(in); - // JcrUtils.closeQuietly(binary); - // byte[] btPass = hash(password, salt, iterationCount); - // in = new ByteArrayInputStream(btPass); - // binary = session.getValueFactory().createBinary(in); - // keyring.setProperty(ARGEO_PASSWORD, binary); - - notYetSavedKeyring.set(keyring); - } catch (Exception e) { - throw new ArgeoJcrException("Cannot setup keyring", e); - } finally { - JcrUtils.closeQuietly(binary); - IOUtils.closeQuietly(in); - // JcrUtils.discardQuietly(session); - } - } - - @Override - protected void handleKeySpecCallback(PBEKeySpecCallback pbeCallback) { - try { - Node userHome = NodeUtils.getUserHome(session); - Node keyring; - if (userHome.hasNode(ARGEO_KEYRING)) - keyring = userHome.getNode(ARGEO_KEYRING); - else if (notYetSavedKeyring.get() != null) - keyring = notYetSavedKeyring.get(); - else - throw new ArgeoJcrException("Keyring not setup"); - - pbeCallback.set(keyring.getProperty(ARGEO_SECRET_KEY_FACTORY).getString(), - JcrUtils.getBinaryAsBytes(keyring.getProperty(ARGEO_SALT)), - (int) keyring.getProperty(ARGEO_ITERATION_COUNT).getLong(), - (int) keyring.getProperty(ARGEO_KEY_LENGTH).getLong(), - keyring.getProperty(ARGEO_SECRET_KEY_ENCRYPTION).getString()); - - if (notYetSavedKeyring.get() != null) - notYetSavedKeyring.remove(); - } catch (RepositoryException e) { - throw new ArgeoJcrException("Cannot handle key spec callback", e); - } - } - - /** The parent node must already exist at this path. */ - @Override - protected synchronized void encrypt(String path, InputStream unencrypted) { - // should be called first for lazy initialization - SecretKey secretKey = getSecretKey(); - - Binary binary = null; - InputStream in = null; - try { - Cipher cipher = createCipher(); - Node node; - if (!session.nodeExists(path)) { - String parentPath = JcrUtils.parentPath(path); - if (!session.nodeExists(parentPath)) - throw new ArgeoJcrException("No parent node of " + path); - Node parentNode = session.getNode(parentPath); - node = parentNode.addNode(JcrUtils.nodeNameFromPath(path)); - } else { - node = session.getNode(path); - } - node.addMixin(ArgeoTypes.ARGEO_ENCRYPTED); - SecureRandom random = new SecureRandom(); - byte[] iv = new byte[16]; - random.nextBytes(iv); - cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(iv)); - JcrUtils.setBinaryAsBytes(node, ARGEO_IV, iv); - - in = new CipherInputStream(unencrypted, cipher); - binary = session.getValueFactory().createBinary(in); - node.setProperty(Property.JCR_DATA, binary); - session.save(); - } catch (Exception e) { - throw new ArgeoJcrException("Cannot encrypt", e); - } finally { - IOUtils.closeQuietly(unencrypted); - IOUtils.closeQuietly(in); - JcrUtils.closeQuietly(binary); - } - } - - @Override - protected synchronized InputStream decrypt(String path) { - Binary binary = null; - InputStream encrypted = null; - Reader reader = null; - try { - if (!session.nodeExists(path)) { - char[] password = ask(); - reader = new CharArrayReader(password); - return new ByteArrayInputStream(IOUtils.toByteArray(reader)); - } else { - // should be called first for lazy initialisation - SecretKey secretKey = getSecretKey(); - - Cipher cipher = createCipher(); - - Node node = session.getNode(path); - if (node.hasProperty(ARGEO_IV)) { - byte[] iv = JcrUtils.getBinaryAsBytes(node.getProperty(ARGEO_IV)); - cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv)); - } else { - cipher.init(Cipher.DECRYPT_MODE, secretKey); - } - - binary = node.getProperty(Property.JCR_DATA).getBinary(); - encrypted = binary.getStream(); - return new CipherInputStream(encrypted, cipher); - } - } catch (Exception e) { - throw new ArgeoJcrException("Cannot decrypt", e); - } finally { - IOUtils.closeQuietly(encrypted); - IOUtils.closeQuietly(reader); - JcrUtils.closeQuietly(binary); - } - } - - protected Cipher createCipher() { - try { - Node userHome = NodeUtils.getUserHome(session); - if (!userHome.hasNode(ARGEO_KEYRING)) - throw new ArgeoJcrException("Keyring not setup"); - Node keyring = userHome.getNode(ARGEO_KEYRING); - String cipherName = keyring.getProperty(ARGEO_CIPHER).getString(); - Provider securityProvider = getSecurityProvider(); - Cipher cipher; - if (securityProvider == null)// TODO use BC? - cipher = Cipher.getInstance(cipherName); - else - cipher = Cipher.getInstance(cipherName, securityProvider); - return cipher; - } catch (Exception e) { - throw new ArgeoJcrException("Cannot get cipher", e); - } - } - - public synchronized void changePassword(char[] oldPassword, char[] newPassword) { - // TODO decrypt with old pw / encrypt with new pw all argeo:encrypted - } - - public synchronized void setSession(Session session) { - this.session = session; - } - - public void setIterationCountFactor(Integer iterationCountFactor) { - this.iterationCountFactor = iterationCountFactor; - } - - public void setSecreteKeyLength(Long keyLength) { - this.secreteKeyLength = keyLength; - } - - public void setSecreteKeyFactoryName(String secreteKeyFactoryName) { - this.secreteKeyFactoryName = secreteKeyFactoryName; - } - - public void setSecreteKeyEncryption(String secreteKeyEncryption) { - this.secreteKeyEncryption = secreteKeyEncryption; - } - - public void setCipherName(String cipherName) { - this.cipherName = cipherName; - } - -} \ No newline at end of file diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelUtils.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelUtils.java index 37c25d007..9c480647d 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelUtils.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelUtils.java @@ -1,8 +1,5 @@ package org.argeo.cms.internal.kernel; -import static org.argeo.cms.internal.kernel.KernelConstants.WEBDAV_PRIVATE; -import static org.argeo.cms.internal.kernel.KernelConstants.WEBDAV_PUBLIC; - import java.io.File; import java.io.IOException; import java.net.MalformedURLException; diff --git a/org.argeo.cms/src/org/argeo/cms/security/AbstractKeyring.java b/org.argeo.cms/src/org/argeo/cms/security/AbstractKeyring.java new file mode 100644 index 000000000..091de9e63 --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/security/AbstractKeyring.java @@ -0,0 +1,279 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.cms.security; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.CharArrayWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.io.Reader; +import java.io.Writer; +import java.security.AccessController; +import java.security.MessageDigest; +import java.security.Provider; +import java.security.Security; +import java.util.Arrays; +import java.util.Iterator; + +import javax.crypto.SecretKey; +import javax.security.auth.Subject; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.TextOutputCallback; +import javax.security.auth.callback.UnsupportedCallbackException; +import javax.security.auth.login.LoginContext; +import javax.security.auth.login.LoginException; + +import org.apache.commons.io.IOUtils; +import org.argeo.cms.CmsException; +import org.argeo.node.security.CryptoKeyring; +import org.argeo.node.security.Keyring; +import org.argeo.node.security.PBEKeySpecCallback; + +/** username / password based keyring. TODO internationalize */ +public abstract class AbstractKeyring implements Keyring, CryptoKeyring { + public final static String DEFAULT_KEYRING_LOGIN_CONTEXT = "KEYRING"; + + private String loginContextName = DEFAULT_KEYRING_LOGIN_CONTEXT; + private CallbackHandler defaultCallbackHandler; + + private String charset = "UTF-8"; + + /** + * Default provider is bouncy castle, in order to have consistent behaviour + * across implementations + */ + private String securityProviderName = "BC"; + + /** + * Whether the keyring has already been created in the past with a master + * password + */ + protected abstract Boolean isSetup(); + + /** + * Setup the keyring persistently, {@link #isSetup()} must return true + * afterwards + */ + protected abstract void setup(char[] password); + + /** Populates the key spec callback */ + protected abstract void handleKeySpecCallback(PBEKeySpecCallback pbeCallback); + + protected abstract void encrypt(String path, InputStream unencrypted); + + protected abstract InputStream decrypt(String path); + + /** Triggers lazy initialization */ + protected SecretKey getSecretKey() { + Subject subject = Subject.getSubject(AccessController.getContext()); + // we assume only one secrete key is available + Iterator iterator = subject.getPrivateCredentials( + SecretKey.class).iterator(); + if (!iterator.hasNext()) {// not initialized + CallbackHandler callbackHandler = new KeyringCallbackHandler(); + try { + LoginContext loginContext = new LoginContext(loginContextName, + subject, callbackHandler); + loginContext.login(); + // FIXME will login even if password is wrong + iterator = subject.getPrivateCredentials(SecretKey.class) + .iterator(); + return iterator.next(); + } catch (LoginException e) { + throw new CmsException("Keyring login failed", e); + } + + } else { + SecretKey secretKey = iterator.next(); + if (iterator.hasNext()) + throw new CmsException( + "More than one secret key in private credentials"); + return secretKey; + } + } + + public InputStream getAsStream(String path) { + return decrypt(path); + } + + public void set(String path, InputStream in) { + encrypt(path, in); + } + + public char[] getAsChars(String path) { + InputStream in = getAsStream(path); + CharArrayWriter writer = null; + Reader reader = null; + try { + writer = new CharArrayWriter(); + reader = new InputStreamReader(in, charset); + IOUtils.copy(reader, writer); + return writer.toCharArray(); + } catch (IOException e) { + throw new CmsException("Cannot decrypt to char array", e); + } finally { + IOUtils.closeQuietly(reader); + IOUtils.closeQuietly(in); + IOUtils.closeQuietly(writer); + } + } + + public void set(String path, char[] arr) { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + ByteArrayInputStream in = null; + Writer writer = null; + try { + writer = new OutputStreamWriter(out, charset); + writer.write(arr); + writer.flush(); + in = new ByteArrayInputStream(out.toByteArray()); + set(path, in); + } catch (IOException e) { + throw new CmsException("Cannot encrypt to char array", e); + } finally { + IOUtils.closeQuietly(writer); + IOUtils.closeQuietly(out); + IOUtils.closeQuietly(in); + } + } + + protected Provider getSecurityProvider() { + return Security.getProvider(securityProviderName); + } + + public void setLoginContextName(String loginContextName) { + this.loginContextName = loginContextName; + } + + public void setDefaultCallbackHandler(CallbackHandler defaultCallbackHandler) { + this.defaultCallbackHandler = defaultCallbackHandler; + } + + public void setCharset(String charset) { + this.charset = charset; + } + + public void setSecurityProviderName(String securityProviderName) { + this.securityProviderName = securityProviderName; + } + + @Deprecated + protected static byte[] hash(char[] password, byte[] salt, + Integer iterationCount) { + ByteArrayOutputStream out = null; + OutputStreamWriter writer = null; + try { + out = new ByteArrayOutputStream(); + writer = new OutputStreamWriter(out, "UTF-8"); + writer.write(password); + MessageDigest pwDigest = MessageDigest.getInstance("SHA-256"); + pwDigest.reset(); + pwDigest.update(salt); + byte[] btPass = pwDigest.digest(out.toByteArray()); + for (int i = 0; i < iterationCount; i++) { + pwDigest.reset(); + btPass = pwDigest.digest(btPass); + } + return btPass; + } catch (Exception e) { + throw new CmsException("Cannot hash", e); + } finally { + IOUtils.closeQuietly(out); + IOUtils.closeQuietly(writer); + } + + } + + /** + * Convenience method using the underlying callback to ask for a password + * (typically used when the password is not saved in the keyring) + */ + protected char[] ask() { + PasswordCallback passwordCb = new PasswordCallback("Password", false); + Callback[] dialogCbs = new Callback[] { passwordCb }; + try { + defaultCallbackHandler.handle(dialogCbs); + char[] password = passwordCb.getPassword(); + return password; + } catch (Exception e) { + throw new CmsException("Cannot ask for a password", e); + } + + } + + class KeyringCallbackHandler implements CallbackHandler { + public void handle(Callback[] callbacks) throws IOException, + UnsupportedCallbackException { + // checks + if (callbacks.length != 2) + throw new IllegalArgumentException( + "Keyring required 2 and only 2 callbacks: {PasswordCallback,PBEKeySpecCallback}"); + if (!(callbacks[0] instanceof PasswordCallback)) + throw new UnsupportedCallbackException(callbacks[0]); + if (!(callbacks[1] instanceof PBEKeySpecCallback)) + throw new UnsupportedCallbackException(callbacks[0]); + + PasswordCallback passwordCb = (PasswordCallback) callbacks[0]; + PBEKeySpecCallback pbeCb = (PBEKeySpecCallback) callbacks[1]; + + if (isSetup()) { + Callback[] dialogCbs = new Callback[] { passwordCb }; + defaultCallbackHandler.handle(dialogCbs); + } else {// setup keyring + TextOutputCallback textCb1 = new TextOutputCallback( + TextOutputCallback.INFORMATION, + "Enter a master password which will protect your private data"); + TextOutputCallback textCb2 = new TextOutputCallback( + TextOutputCallback.INFORMATION, + "(for example your credentials to third-party services)"); + TextOutputCallback textCb3 = new TextOutputCallback( + TextOutputCallback.INFORMATION, + "Don't forget this password since the data cannot be read without it"); + PasswordCallback confirmPasswordCb = new PasswordCallback( + "Confirm password", false); + // first try + Callback[] dialogCbs = new Callback[] { textCb1, textCb2, + textCb3, passwordCb, confirmPasswordCb }; + defaultCallbackHandler.handle(dialogCbs); + + // if passwords different, retry (except if cancelled) + while (passwordCb.getPassword() != null + && !Arrays.equals(passwordCb.getPassword(), + confirmPasswordCb.getPassword())) { + TextOutputCallback textCb = new TextOutputCallback( + TextOutputCallback.ERROR, + "The passwords do not match"); + dialogCbs = new Callback[] { textCb, passwordCb, + confirmPasswordCb }; + defaultCallbackHandler.handle(dialogCbs); + } + + if (passwordCb.getPassword() != null) {// not cancelled + setup(passwordCb.getPassword()); + } + } + + if (passwordCb.getPassword() != null) + handleKeySpecCallback(pbeCb); + } + + } +} diff --git a/org.argeo.cms/src/org/argeo/cms/security/ChecksumFactory.java b/org.argeo.cms/src/org/argeo/cms/security/ChecksumFactory.java new file mode 100644 index 000000000..c5b4e9ecc --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/security/ChecksumFactory.java @@ -0,0 +1,157 @@ +package org.argeo.cms.security; + +import static javax.xml.bind.DatatypeConverter.printBase64Binary; + +import java.io.IOException; +import java.math.BigInteger; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.security.MessageDigest; +import java.util.zip.Checksum; + +import org.argeo.cms.CmsException; + +/** Allows to fine tune how files are read. */ +public class ChecksumFactory { + private int regionSize = 10 * 1024 * 1024; + + public byte[] digest(Path path, final String algo) { + try { + final MessageDigest md = MessageDigest.getInstance(algo); + if (Files.isDirectory(path)) { + long begin = System.currentTimeMillis(); + Files.walkFileTree(path, new SimpleFileVisitor() { + + @Override + public FileVisitResult visitFile(Path file, + BasicFileAttributes attrs) throws IOException { + if (!Files.isDirectory(file)) { + byte[] digest = digest(file, algo); + md.update(digest); + } + return FileVisitResult.CONTINUE; + } + + }); + byte[] digest = md.digest(); + long duration = System.currentTimeMillis() - begin; + System.out.println(printBase64Binary(digest) + " " + path + + " (" + duration / 1000 + "s)"); + return digest; + } else { + long begin = System.nanoTime(); + long length = -1; + try (FileChannel channel = (FileChannel) Files + .newByteChannel(path);) { + length = channel.size(); + long cursor = 0; + while (cursor < length) { + long effectiveSize = Math.min(regionSize, length + - cursor); + MappedByteBuffer mb = channel.map( + FileChannel.MapMode.READ_ONLY, cursor, + effectiveSize); + // md.update(mb); + byte[] buffer = new byte[1024]; + while (mb.hasRemaining()){ + mb.get(buffer); + md.update(buffer); + } + + // sub digest + // mb.flip(); + // MessageDigest subMd = + // MessageDigest.getInstance(algo); + // subMd.update(mb); + // byte[] subDigest = subMd.digest(); + // System.out.println(" -> " + cursor); + // System.out.println(IOUtils.encodeHexString(subDigest)); + // System.out.println(new BigInteger(1, + // subDigest).toString(16)); + // System.out.println(new BigInteger(1, subDigest) + // .toString(Character.MAX_RADIX)); + // System.out.println(printBase64Binary(subDigest)); + + cursor = cursor + regionSize; + } + byte[] digest = md.digest(); + long duration = System.nanoTime() - begin; + System.out.println(printBase64Binary(digest) + " " + + path.getFileName() + " (" + duration / 1000000 + + "ms, " + (length / 1024) + "kB, " + + (length / (duration / 1000000)) * 1000 + / (1024 * 1024) + " MB/s)"); + return digest; + } + } + } catch (Exception e) { + throw new CmsException("Cannot digest " + path, e); + } + } + + /** Whether the file should be mapped. */ + protected boolean mapFile(FileChannel fileChannel) throws IOException { + long size = fileChannel.size(); + if (size > (regionSize / 10)) + return true; + return false; + } + + public long checksum(Path path, Checksum crc) { + final int bufferSize = 2 * 1024 * 1024; + long begin = System.currentTimeMillis(); + try (FileChannel channel = (FileChannel) Files.newByteChannel(path);) { + byte[] bytes = new byte[bufferSize]; + long length = channel.size(); + long cursor = 0; + while (cursor < length) { + long effectiveSize = Math.min(regionSize, length - cursor); + MappedByteBuffer mb = channel.map( + FileChannel.MapMode.READ_ONLY, cursor, effectiveSize); + int nGet; + while (mb.hasRemaining()) { + nGet = Math.min(mb.remaining(), bufferSize); + mb.get(bytes, 0, nGet); + crc.update(bytes, 0, nGet); + } + cursor = cursor + regionSize; + } + return crc.getValue(); + } catch (Exception e) { + throw new CmsException("Cannot checksum " + path, e); + } finally { + long duration = System.currentTimeMillis() - begin; + System.out.println(duration / 1000 + "s"); + } + } + + public static void main(String... args) { + ChecksumFactory cf = new ChecksumFactory(); + // Path path = + // Paths.get("/home/mbaudier/apache-maven-3.2.3-bin.tar.gz"); + Path path; + if (args.length > 0) { + path = Paths.get(args[0]); + } else { + path = Paths + .get("/home/mbaudier/Downloads/torrents/CentOS-7-x86_64-DVD-1503-01/" + + "CentOS-7-x86_64-DVD-1503-01.iso"); + } + // long adler = cf.checksum(path, new Adler32()); + // System.out.format("Adler=%d%n", adler); + // long crc = cf.checksum(path, new CRC32()); + // System.out.format("CRC=%d%n", crc); + String algo = "SHA1"; + byte[] digest = cf.digest(path, algo); + System.out.println(algo + " " + printBase64Binary(digest)); + System.out.println(algo + " " + new BigInteger(1, digest).toString(16)); + // String sha1 = printBase64Binary(cf.digest(path, "SHA1")); + // System.out.format("SHA1=%s%n", sha1); + } +} diff --git a/org.argeo.cms/src/org/argeo/cms/security/JcrKeyring.java b/org.argeo.cms/src/org/argeo/cms/security/JcrKeyring.java new file mode 100644 index 000000000..1ccb81731 --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/security/JcrKeyring.java @@ -0,0 +1,294 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.cms.security; + +import java.io.ByteArrayInputStream; +import java.io.CharArrayReader; +import java.io.InputStream; +import java.io.Reader; +import java.security.Provider; +import java.security.SecureRandom; + +import javax.crypto.Cipher; +import javax.crypto.CipherInputStream; +import javax.crypto.SecretKey; +import javax.crypto.spec.IvParameterSpec; +import javax.jcr.Binary; +import javax.jcr.Node; +import javax.jcr.Property; +import javax.jcr.RepositoryException; +import javax.jcr.Session; + +import org.apache.commons.io.IOUtils; +import org.argeo.jcr.ArgeoJcrException; +import org.argeo.jcr.JcrUtils; +import org.argeo.node.ArgeoNames; +import org.argeo.node.ArgeoTypes; +import org.argeo.node.NodeUtils; +import org.argeo.node.security.PBEKeySpecCallback; + +/** JCR based implementation of a keyring */ +public class JcrKeyring extends AbstractKeyring implements ArgeoNames { + /** + * Stronger with 256, but causes problem with Oracle JVM, force 128 in this + * case + */ + public final static Long DEFAULT_SECRETE_KEY_LENGTH = 256l; + public final static String DEFAULT_SECRETE_KEY_FACTORY = "PBKDF2WithHmacSHA1"; + public final static String DEFAULT_SECRETE_KEY_ENCRYPTION = "AES"; + public final static String DEFAULT_CIPHER_NAME = "AES/CBC/PKCS5Padding"; + + private Integer iterationCountFactor = 200; + private Long secreteKeyLength = DEFAULT_SECRETE_KEY_LENGTH; + private String secreteKeyFactoryName = DEFAULT_SECRETE_KEY_FACTORY; + private String secreteKeyEncryption = DEFAULT_SECRETE_KEY_ENCRYPTION; + private String cipherName = DEFAULT_CIPHER_NAME; + + private Session session; + + /** + * When setup is called the session has not yet been saved and we don't want + * to save it since there maybe other data which would be inconsistent. So + * we keep a reference to this node which will then be used (an reset to + * null) when handling the PBE callback. We keep one per thread in case + * multiple users are accessing the same instance of a keyring. + */ + private ThreadLocal notYetSavedKeyring = new ThreadLocal() { + + @Override + protected Node initialValue() { + return null; + } + }; + + @Override + protected Boolean isSetup() { + try { + if (notYetSavedKeyring.get() != null) + return true; + + Node userHome = NodeUtils.getUserHome(session); + return userHome.hasNode(ARGEO_KEYRING); + } catch (RepositoryException e) { + throw new ArgeoJcrException("Cannot check whether keyring is setup", e); + } + } + + @Override + protected void setup(char[] password) { + Binary binary = null; + InputStream in = null; + try { + Node userHome = NodeUtils.getUserHome(session); + if (userHome.hasNode(ARGEO_KEYRING)) + throw new ArgeoJcrException("Keyring already setup"); + Node keyring = userHome.addNode(ARGEO_KEYRING); + keyring.addMixin(ArgeoTypes.ARGEO_PBE_SPEC); + + // deterministic salt and iteration count based on username + String username = session.getUserID(); + byte[] salt = new byte[8]; + byte[] usernameBytes = username.getBytes(); + for (int i = 0; i < salt.length; i++) { + if (i < usernameBytes.length) + salt[i] = usernameBytes[i]; + else + salt[i] = 0; + } + in = new ByteArrayInputStream(salt); + binary = session.getValueFactory().createBinary(in); + keyring.setProperty(ARGEO_SALT, binary); + + Integer iterationCount = username.length() * iterationCountFactor; + keyring.setProperty(ARGEO_ITERATION_COUNT, iterationCount); + + // default algo + // TODO check if algo and key length are available, use DES if not + keyring.setProperty(ARGEO_SECRET_KEY_FACTORY, secreteKeyFactoryName); + keyring.setProperty(ARGEO_KEY_LENGTH, secreteKeyLength); + keyring.setProperty(ARGEO_SECRET_KEY_ENCRYPTION, secreteKeyEncryption); + keyring.setProperty(ARGEO_CIPHER, cipherName); + + // keyring.getSession().save(); + + // encrypted password hash + // IOUtils.closeQuietly(in); + // JcrUtils.closeQuietly(binary); + // byte[] btPass = hash(password, salt, iterationCount); + // in = new ByteArrayInputStream(btPass); + // binary = session.getValueFactory().createBinary(in); + // keyring.setProperty(ARGEO_PASSWORD, binary); + + notYetSavedKeyring.set(keyring); + } catch (Exception e) { + throw new ArgeoJcrException("Cannot setup keyring", e); + } finally { + JcrUtils.closeQuietly(binary); + IOUtils.closeQuietly(in); + // JcrUtils.discardQuietly(session); + } + } + + @Override + protected void handleKeySpecCallback(PBEKeySpecCallback pbeCallback) { + try { + Node userHome = NodeUtils.getUserHome(session); + Node keyring; + if (userHome.hasNode(ARGEO_KEYRING)) + keyring = userHome.getNode(ARGEO_KEYRING); + else if (notYetSavedKeyring.get() != null) + keyring = notYetSavedKeyring.get(); + else + throw new ArgeoJcrException("Keyring not setup"); + + pbeCallback.set(keyring.getProperty(ARGEO_SECRET_KEY_FACTORY).getString(), + JcrUtils.getBinaryAsBytes(keyring.getProperty(ARGEO_SALT)), + (int) keyring.getProperty(ARGEO_ITERATION_COUNT).getLong(), + (int) keyring.getProperty(ARGEO_KEY_LENGTH).getLong(), + keyring.getProperty(ARGEO_SECRET_KEY_ENCRYPTION).getString()); + + if (notYetSavedKeyring.get() != null) + notYetSavedKeyring.remove(); + } catch (RepositoryException e) { + throw new ArgeoJcrException("Cannot handle key spec callback", e); + } + } + + /** The parent node must already exist at this path. */ + @Override + protected synchronized void encrypt(String path, InputStream unencrypted) { + // should be called first for lazy initialization + SecretKey secretKey = getSecretKey(); + + Binary binary = null; + InputStream in = null; + try { + Cipher cipher = createCipher(); + Node node; + if (!session.nodeExists(path)) { + String parentPath = JcrUtils.parentPath(path); + if (!session.nodeExists(parentPath)) + throw new ArgeoJcrException("No parent node of " + path); + Node parentNode = session.getNode(parentPath); + node = parentNode.addNode(JcrUtils.nodeNameFromPath(path)); + } else { + node = session.getNode(path); + } + node.addMixin(ArgeoTypes.ARGEO_ENCRYPTED); + SecureRandom random = new SecureRandom(); + byte[] iv = new byte[16]; + random.nextBytes(iv); + cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(iv)); + JcrUtils.setBinaryAsBytes(node, ARGEO_IV, iv); + + in = new CipherInputStream(unencrypted, cipher); + binary = session.getValueFactory().createBinary(in); + node.setProperty(Property.JCR_DATA, binary); + session.save(); + } catch (Exception e) { + throw new ArgeoJcrException("Cannot encrypt", e); + } finally { + IOUtils.closeQuietly(unencrypted); + IOUtils.closeQuietly(in); + JcrUtils.closeQuietly(binary); + } + } + + @Override + protected synchronized InputStream decrypt(String path) { + Binary binary = null; + InputStream encrypted = null; + Reader reader = null; + try { + if (!session.nodeExists(path)) { + char[] password = ask(); + reader = new CharArrayReader(password); + return new ByteArrayInputStream(IOUtils.toByteArray(reader)); + } else { + // should be called first for lazy initialisation + SecretKey secretKey = getSecretKey(); + + Cipher cipher = createCipher(); + + Node node = session.getNode(path); + if (node.hasProperty(ARGEO_IV)) { + byte[] iv = JcrUtils.getBinaryAsBytes(node.getProperty(ARGEO_IV)); + cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv)); + } else { + cipher.init(Cipher.DECRYPT_MODE, secretKey); + } + + binary = node.getProperty(Property.JCR_DATA).getBinary(); + encrypted = binary.getStream(); + return new CipherInputStream(encrypted, cipher); + } + } catch (Exception e) { + throw new ArgeoJcrException("Cannot decrypt", e); + } finally { + IOUtils.closeQuietly(encrypted); + IOUtils.closeQuietly(reader); + JcrUtils.closeQuietly(binary); + } + } + + protected Cipher createCipher() { + try { + Node userHome = NodeUtils.getUserHome(session); + if (!userHome.hasNode(ARGEO_KEYRING)) + throw new ArgeoJcrException("Keyring not setup"); + Node keyring = userHome.getNode(ARGEO_KEYRING); + String cipherName = keyring.getProperty(ARGEO_CIPHER).getString(); + Provider securityProvider = getSecurityProvider(); + Cipher cipher; + if (securityProvider == null)// TODO use BC? + cipher = Cipher.getInstance(cipherName); + else + cipher = Cipher.getInstance(cipherName, securityProvider); + return cipher; + } catch (Exception e) { + throw new ArgeoJcrException("Cannot get cipher", e); + } + } + + public synchronized void changePassword(char[] oldPassword, char[] newPassword) { + // TODO decrypt with old pw / encrypt with new pw all argeo:encrypted + } + + public synchronized void setSession(Session session) { + this.session = session; + } + + public void setIterationCountFactor(Integer iterationCountFactor) { + this.iterationCountFactor = iterationCountFactor; + } + + public void setSecreteKeyLength(Long keyLength) { + this.secreteKeyLength = keyLength; + } + + public void setSecreteKeyFactoryName(String secreteKeyFactoryName) { + this.secreteKeyFactoryName = secreteKeyFactoryName; + } + + public void setSecreteKeyEncryption(String secreteKeyEncryption) { + this.secreteKeyEncryption = secreteKeyEncryption; + } + + public void setCipherName(String cipherName) { + this.cipherName = cipherName; + } + +} \ No newline at end of file diff --git a/org.argeo.cms/src/org/argeo/cms/security/PasswordBasedEncryption.java b/org.argeo.cms/src/org/argeo/cms/security/PasswordBasedEncryption.java new file mode 100644 index 000000000..a74cb592e --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/security/PasswordBasedEncryption.java @@ -0,0 +1,247 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.cms.security; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.GeneralSecurityException; +import java.security.InvalidKeyException; +import java.security.Key; + +import javax.crypto.Cipher; +import javax.crypto.CipherInputStream; +import javax.crypto.CipherOutputStream; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.PBEKeySpec; +import javax.crypto.spec.SecretKeySpec; + +import org.apache.commons.io.IOUtils; +import org.argeo.cms.CmsException; + +/** Simple password based encryption / decryption */ +public class PasswordBasedEncryption { + public final static Integer DEFAULT_ITERATION_COUNT = 1024; + /** Stronger with 256, but causes problem with Oracle JVM */ + public final static Integer DEFAULT_SECRETE_KEY_LENGTH = 256; + public final static Integer DEFAULT_SECRETE_KEY_LENGTH_RESTRICTED = 128; + public final static String DEFAULT_SECRETE_KEY_FACTORY = "PBKDF2WithHmacSHA1"; + public final static String DEFAULT_SECRETE_KEY_ENCRYPTION = "AES"; + public final static String DEFAULT_CIPHER_NAME = "AES/CBC/PKCS5Padding"; + public final static String DEFAULT_CHARSET = "UTF-8"; + + private Integer iterationCount = DEFAULT_ITERATION_COUNT; + private Integer secreteKeyLength = DEFAULT_SECRETE_KEY_LENGTH; + private String secreteKeyFactoryName = DEFAULT_SECRETE_KEY_FACTORY; + private String secreteKeyEncryption = DEFAULT_SECRETE_KEY_ENCRYPTION; + private String cipherName = DEFAULT_CIPHER_NAME; + + private static byte[] DEFAULT_SALT_8 = { (byte) 0xA9, (byte) 0x9B, + (byte) 0xC8, (byte) 0x32, (byte) 0x56, (byte) 0x35, (byte) 0xE3, + (byte) 0x03 }; + private static byte[] DEFAULT_IV_16 = { (byte) 0xA9, (byte) 0x9B, + (byte) 0xC8, (byte) 0x32, (byte) 0x56, (byte) 0x35, (byte) 0xE3, + (byte) 0x03, (byte) 0xA9, (byte) 0x9B, (byte) 0xC8, (byte) 0x32, + (byte) 0x56, (byte) 0x35, (byte) 0xE3, (byte) 0x03 }; + + private Key key; + private Cipher ecipher; + private Cipher dcipher; + + private String securityProviderName = null; + + /** + * This is up to the caller to clear the passed array. Neither copy of nor + * reference to the passed array is kept + */ + public PasswordBasedEncryption(char[] password) { + this(password, DEFAULT_SALT_8, DEFAULT_IV_16); + } + + /** + * This is up to the caller to clear the passed array. Neither copies of nor + * references to the passed arrays are kept + */ + public PasswordBasedEncryption(char[] password, byte[] passwordSalt, + byte[] initializationVector) { + try { + initKeyAndCiphers(password, passwordSalt, initializationVector); + } catch (InvalidKeyException e) { + Integer previousSecreteKeyLength = secreteKeyLength; + secreteKeyLength = DEFAULT_SECRETE_KEY_LENGTH_RESTRICTED; + System.err.println("'" + e.getMessage() + "', will use " + + secreteKeyLength + " secrete key length instead of " + + previousSecreteKeyLength); + try { + initKeyAndCiphers(password, passwordSalt, initializationVector); + } catch (Exception e1) { + throw new CmsException( + "Cannot get secret key (with restricted length)", e1); + } + } catch (Exception e) { + throw new CmsException("Cannot get secret key", e); + } + } + + protected void initKeyAndCiphers(char[] password, byte[] passwordSalt, + byte[] initializationVector) throws GeneralSecurityException { + byte[] salt = new byte[8]; + System.arraycopy(passwordSalt, 0, salt, 0, salt.length); + // for (int i = 0; i < password.length && i < salt.length; i++) + // salt[i] = (byte) password[i]; + byte[] iv = new byte[16]; + System.arraycopy(initializationVector, 0, iv, 0, iv.length); + + SecretKeyFactory keyFac = SecretKeyFactory + .getInstance(getSecretKeyFactoryName()); + PBEKeySpec keySpec = new PBEKeySpec(password, salt, + getIterationCount(), getKeyLength()); + String secKeyEncryption = getSecretKeyEncryption(); + if (secKeyEncryption != null) { + SecretKey tmp = keyFac.generateSecret(keySpec); + key = new SecretKeySpec(tmp.getEncoded(), getSecretKeyEncryption()); + } else { + key = keyFac.generateSecret(keySpec); + } + if (securityProviderName != null) + ecipher = Cipher.getInstance(getCipherName(), securityProviderName); + else + ecipher = Cipher.getInstance(getCipherName()); + ecipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv)); + dcipher = Cipher.getInstance(getCipherName()); + dcipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv)); + } + + public void encrypt(InputStream decryptedIn, OutputStream encryptedOut) + throws IOException { + try { + CipherOutputStream out = new CipherOutputStream(encryptedOut, + ecipher); + IOUtils.copy(decryptedIn, out); + IOUtils.closeQuietly(out); + } catch (IOException e) { + throw e; + } catch (Exception e) { + throw new CmsException("Cannot encrypt", e); + } finally { + IOUtils.closeQuietly(decryptedIn); + } + } + + public void decrypt(InputStream encryptedIn, OutputStream decryptedOut) + throws IOException { + try { + CipherInputStream decryptedIn = new CipherInputStream(encryptedIn, + dcipher); + IOUtils.copy(decryptedIn, decryptedOut); + } catch (IOException e) { + throw e; + } catch (Exception e) { + throw new CmsException("Cannot decrypt", e); + } finally { + IOUtils.closeQuietly(encryptedIn); + } + } + + public byte[] encryptString(String str) { + ByteArrayOutputStream out = null; + ByteArrayInputStream in = null; + try { + out = new ByteArrayOutputStream(); + in = new ByteArrayInputStream(str.getBytes(DEFAULT_CHARSET)); + encrypt(in, out); + return out.toByteArray(); + } catch (Exception e) { + throw new CmsException("Cannot encrypt", e); + } finally { + IOUtils.closeQuietly(out); + } + } + + /** Closes the input stream */ + public String decryptAsString(InputStream in) { + ByteArrayOutputStream out = null; + try { + out = new ByteArrayOutputStream(); + decrypt(in, out); + return new String(out.toByteArray(), DEFAULT_CHARSET); + } catch (Exception e) { + throw new CmsException("Cannot decrypt", e); + } finally { + IOUtils.closeQuietly(out); + } + } + + protected Key getKey() { + return key; + } + + protected Cipher getEcipher() { + return ecipher; + } + + protected Cipher getDcipher() { + return dcipher; + } + + protected Integer getIterationCount() { + return iterationCount; + } + + protected Integer getKeyLength() { + return secreteKeyLength; + } + + protected String getSecretKeyFactoryName() { + return secreteKeyFactoryName; + } + + protected String getSecretKeyEncryption() { + return secreteKeyEncryption; + } + + protected String getCipherName() { + return cipherName; + } + + public void setIterationCount(Integer iterationCount) { + this.iterationCount = iterationCount; + } + + public void setSecreteKeyLength(Integer keyLength) { + this.secreteKeyLength = keyLength; + } + + public void setSecreteKeyFactoryName(String secreteKeyFactoryName) { + this.secreteKeyFactoryName = secreteKeyFactoryName; + } + + public void setSecreteKeyEncryption(String secreteKeyEncryption) { + this.secreteKeyEncryption = secreteKeyEncryption; + } + + public void setCipherName(String cipherName) { + this.cipherName = cipherName; + } + + public void setSecurityProviderName(String securityProviderName) { + this.securityProviderName = securityProviderName; + } +} diff --git a/org.argeo.cms/src/org/argeo/cms/tabular/CsvTabularWriter.java b/org.argeo.cms/src/org/argeo/cms/tabular/CsvTabularWriter.java new file mode 100644 index 000000000..d22f44e73 --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/tabular/CsvTabularWriter.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.cms.tabular; + +import java.io.OutputStream; + +import org.argeo.node.tabular.TabularWriter; +import org.argeo.util.CsvWriter; + +/** Write tabular content in a stream as CSV. Wraps a {@link CsvWriter}. */ +public class CsvTabularWriter implements TabularWriter { + private CsvWriter csvWriter; + + public CsvTabularWriter(OutputStream out) { + this.csvWriter = new CsvWriter(out); + } + + public void appendRow(Object[] row) { + csvWriter.writeLine(row); + } + + public void close() { + } + +} diff --git a/org.argeo.cms/src/org/argeo/cms/tabular/JcrTabularRowIterator.java b/org.argeo.cms/src/org/argeo/cms/tabular/JcrTabularRowIterator.java index 931a2b565..5d380cfa5 100644 --- a/org.argeo.cms/src/org/argeo/cms/tabular/JcrTabularRowIterator.java +++ b/org.argeo.cms/src/org/argeo/cms/tabular/JcrTabularRowIterator.java @@ -30,11 +30,11 @@ import javax.jcr.RepositoryException; import org.apache.commons.io.IOUtils; import org.argeo.jcr.ArgeoJcrException; import org.argeo.node.ArgeoTypes; +import org.argeo.node.tabular.ArrayTabularRow; +import org.argeo.node.tabular.TabularColumn; +import org.argeo.node.tabular.TabularRow; +import org.argeo.node.tabular.TabularRowIterator; import org.argeo.util.CsvParser; -import org.argeo.util.tabular.ArrayTabularRow; -import org.argeo.util.tabular.TabularColumn; -import org.argeo.util.tabular.TabularRow; -import org.argeo.util.tabular.TabularRowIterator; /** Iterates over the rows of a {@link ArgeoTypes#ARGEO_TABLE} node. */ public class JcrTabularRowIterator implements TabularRowIterator { diff --git a/org.argeo.cms/src/org/argeo/cms/tabular/JcrTabularWriter.java b/org.argeo.cms/src/org/argeo/cms/tabular/JcrTabularWriter.java index 7249fd509..ac57d2ab7 100644 --- a/org.argeo.cms/src/org/argeo/cms/tabular/JcrTabularWriter.java +++ b/org.argeo.cms/src/org/argeo/cms/tabular/JcrTabularWriter.java @@ -30,9 +30,9 @@ import org.apache.commons.io.IOUtils; import org.argeo.jcr.ArgeoJcrException; import org.argeo.jcr.JcrUtils; import org.argeo.node.ArgeoTypes; +import org.argeo.node.tabular.TabularColumn; +import org.argeo.node.tabular.TabularWriter; import org.argeo.util.CsvWriter; -import org.argeo.util.tabular.TabularColumn; -import org.argeo.util.tabular.TabularWriter; /** Write / reference tabular content in a JCR repository. */ public class JcrTabularWriter implements TabularWriter { diff --git a/org.argeo.eclipse.ui/bnd.bnd b/org.argeo.eclipse.ui/bnd.bnd index 65e408ddf..b836fc0e9 100644 --- a/org.argeo.eclipse.ui/bnd.bnd +++ b/org.argeo.eclipse.ui/bnd.bnd @@ -2,5 +2,4 @@ Import-Package: javax.jcr.nodetype,\ org.eclipse.swt,\ org.eclipse.jface.window,\ org.eclipse.core.commands.common,\ - org.argeo,\ * diff --git a/org.argeo.enterprise/ext/test/org/argeo/osgi/useradmin/LdifParserTest.java b/org.argeo.enterprise/ext/test/org/argeo/osgi/useradmin/LdifParserTest.java index fecf5dd5a..e7c94609f 100644 --- a/org.argeo.enterprise/ext/test/org/argeo/osgi/useradmin/LdifParserTest.java +++ b/org.argeo.enterprise/ext/test/org/argeo/osgi/useradmin/LdifParserTest.java @@ -10,10 +10,10 @@ import javax.naming.directory.Attribute; import javax.naming.directory.Attributes; import javax.naming.ldap.LdapName; -import org.argeo.util.naming.LdifParser; - import junit.framework.TestCase; +import org.argeo.util.naming.LdifParser; + public class LdifParserTest extends TestCase implements BasicTestConstants { public void testBasicLdif() throws Exception { LdifParser ldifParser = new LdifParser(); diff --git a/org.argeo.enterprise/ext/test/org/argeo/osgi/useradmin/LdifUserAdminTest.java b/org.argeo.enterprise/ext/test/org/argeo/osgi/useradmin/LdifUserAdminTest.java index a8a7d226a..06f1e6d2e 100644 --- a/org.argeo.enterprise/ext/test/org/argeo/osgi/useradmin/LdifUserAdminTest.java +++ b/org.argeo.enterprise/ext/test/org/argeo/osgi/useradmin/LdifUserAdminTest.java @@ -16,6 +16,8 @@ import java.util.UUID; import javax.transaction.TransactionManager; +import junit.framework.TestCase; + import org.osgi.service.useradmin.Authorization; import org.osgi.service.useradmin.Group; import org.osgi.service.useradmin.Role; @@ -24,7 +26,6 @@ import org.osgi.service.useradmin.User; import bitronix.tm.BitronixTransactionManager; import bitronix.tm.TransactionManagerServices; import bitronix.tm.resource.ehcache.EhCacheXAResourceProducer; -import junit.framework.TestCase; public class LdifUserAdminTest extends TestCase implements BasicTestConstants { private BitronixTransactionManager tm; diff --git a/org.argeo.jcr/src/org/argeo/jackrabbit/JackrabbitDataModelMigration.java b/org.argeo.jcr/src/org/argeo/jackrabbit/JackrabbitDataModelMigration.java index e53ed5577..8fedcf521 100644 --- a/org.argeo.jcr/src/org/argeo/jackrabbit/JackrabbitDataModelMigration.java +++ b/org.argeo.jcr/src/org/argeo/jackrabbit/JackrabbitDataModelMigration.java @@ -18,7 +18,6 @@ package org.argeo.jackrabbit; import java.io.InputStreamReader; import java.io.Reader; -import javax.jcr.Node; import javax.jcr.Session; import org.apache.commons.io.IOUtils; @@ -60,7 +59,7 @@ public class JackrabbitDataModelMigration implements + " does not exist: nothing to migrate."); return false; } - Node dataModelNode = session.getNode(dataModelNodePath); +// Node dataModelNode = session.getNode(dataModelNodePath); // if (dataModelNode.hasProperty(ArgeoNames.ARGEO_DATA_MODEL_VERSION)) { // String currentVersion = dataModelNode.getProperty( // ArgeoNames.ARGEO_DATA_MODEL_VERSION).getString(); diff --git a/org.argeo.jcr/src/org/argeo/jcr/JcrMonitor.java b/org.argeo.jcr/src/org/argeo/jcr/JcrMonitor.java index f04be9aa5..71cf961e0 100644 --- a/org.argeo.jcr/src/org/argeo/jcr/JcrMonitor.java +++ b/org.argeo.jcr/src/org/argeo/jcr/JcrMonitor.java @@ -1,13 +1,11 @@ package org.argeo.jcr; -import org.argeo.ArgeoMonitor; /** * Simple monitor abstraction. Inspired by Eclipse IProgressMOnitor, but without * dependency to it. */ -@SuppressWarnings("deprecation") -public interface JcrMonitor extends ArgeoMonitor { +public interface JcrMonitor { /** * Constant indicating an unknown amount of work. */ diff --git a/org.argeo.jcr/src/org/argeo/jcr/JcrUtils.java b/org.argeo.jcr/src/org/argeo/jcr/JcrUtils.java index 313554041..8ccdfc73d 100644 --- a/org.argeo.jcr/src/org/argeo/jcr/JcrUtils.java +++ b/org.argeo.jcr/src/org/argeo/jcr/JcrUtils.java @@ -63,9 +63,7 @@ import javax.jcr.security.Privilege; import org.apache.commons.io.IOUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.argeo.ArgeoMonitor; -import org.argeo.util.security.DigestUtils; -import org.argeo.util.security.SimplePrincipal; +import org.argeo.util.DigestUtils; /** Utility methods to simplify common JCR operations. */ public class JcrUtils { @@ -1417,9 +1415,8 @@ public class JcrUtils { * files * @return how many files were copied */ - @SuppressWarnings("deprecation") public static Long copyFiles(Node fromNode, Node toNode, Boolean recursive, - ArgeoMonitor monitor) { + JcrMonitor monitor) { long count = 0l; Binary binary = null; diff --git a/org.argeo.jcr/src/org/argeo/jcr/SimplePrincipal.java b/org.argeo.jcr/src/org/argeo/jcr/SimplePrincipal.java new file mode 100644 index 000000000..804ce0725 --- /dev/null +++ b/org.argeo.jcr/src/org/argeo/jcr/SimplePrincipal.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.jcr; + +import java.security.Principal; + +/** Canonical implementation of a {@link Principal} */ +public class SimplePrincipal implements Principal { + private final String name; + + public SimplePrincipal(String name) { + if (name == null) + throw new IllegalArgumentException("Principal name cannot be null"); + this.name = name; + } + + public String getName() { + return name; + } + + @Override + public int hashCode() { + return name.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj == null) + return false; + if (obj instanceof Principal) + return name.equals((((Principal) obj).getName())); + return name.equals(obj.toString()); + } + + @Override + protected Object clone() throws CloneNotSupportedException { + return new SimplePrincipal(name); + } + + @Override + public String toString() { + return name; + } + +} diff --git a/org.argeo.jcr/src/org/argeo/jcr/security/JcrAuthorizations.java b/org.argeo.jcr/src/org/argeo/jcr/security/JcrAuthorizations.java index 9ad249252..3e8e3a2ff 100644 --- a/org.argeo.jcr/src/org/argeo/jcr/security/JcrAuthorizations.java +++ b/org.argeo.jcr/src/org/argeo/jcr/security/JcrAuthorizations.java @@ -29,7 +29,7 @@ import javax.jcr.security.Privilege; import org.argeo.jcr.ArgeoJcrException; import org.argeo.jcr.JcrUtils; -import org.argeo.util.security.SimplePrincipal; +import org.argeo.jcr.SimplePrincipal; /** Apply authorizations to a JCR repository. */ public class JcrAuthorizations implements Runnable { diff --git a/org.argeo.node.api/src/org/argeo/node/EnumOCD.java b/org.argeo.node.api/src/org/argeo/node/EnumOCD.java index daa2f540d..c5a191ee9 100644 --- a/org.argeo.node.api/src/org/argeo/node/EnumOCD.java +++ b/org.argeo.node.api/src/org/argeo/node/EnumOCD.java @@ -23,6 +23,10 @@ class EnumOCD> implements ObjectClassDefinition { return null; } + public String getLocale() { + return locale; + } + @Override public String getID() { return enumClass.getName(); diff --git a/org.argeo.node.api/src/org/argeo/node/security/CryptoKeyring.java b/org.argeo.node.api/src/org/argeo/node/security/CryptoKeyring.java new file mode 100644 index 000000000..72f9ff7a7 --- /dev/null +++ b/org.argeo.node.api/src/org/argeo/node/security/CryptoKeyring.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.node.security; + + + +/** + * Advanced keyring based on cryptography that can easily be centralized and + * coordinated with {@link KeyringLoginModule} (since they ar ein the same + * package) + */ +public interface CryptoKeyring extends Keyring { + +} diff --git a/org.argeo.node.api/src/org/argeo/node/security/Keyring.java b/org.argeo.node.api/src/org/argeo/node/security/Keyring.java new file mode 100644 index 000000000..467d9a8aa --- /dev/null +++ b/org.argeo.node.api/src/org/argeo/node/security/Keyring.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.node.security; + +import java.io.InputStream; + +/** + * Access to private (typically encrypted) data. The keyring is responsible for + * retrieving the necessary credentials. Experimental. This API may + * change. + */ +public interface Keyring { + public void changePassword(char[] oldPassword, char[] newPassword); + + /** + * Returns the confidential information as chars. Must ask for it if it is + * not stored. + */ + public char[] getAsChars(String path); + + /** + * Returns the confidential information as a stream. Must ask for it if it + * is not stored. + */ + public InputStream getAsStream(String path); + + public void set(String path, char[] arr); + + public void set(String path, InputStream in); +} diff --git a/org.argeo.node.api/src/org/argeo/node/security/PBEKeySpecCallback.java b/org.argeo.node.api/src/org/argeo/node/security/PBEKeySpecCallback.java new file mode 100644 index 000000000..f03ba9ddf --- /dev/null +++ b/org.argeo.node.api/src/org/argeo/node/security/PBEKeySpecCallback.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.node.security; + +import javax.crypto.spec.PBEKeySpec; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.PasswordCallback; + +/** + * All information required to set up a {@link PBEKeySpec} bar the password + * itself (use a {@link PasswordCallback}) + */ +public class PBEKeySpecCallback implements Callback { + private String secretKeyFactory; + private byte[] salt; + private Integer iterationCount; + /** Can be null for some algorithms */ + private Integer keyLength; + /** Can be null, will trigger secret key encryption if not */ + private String secretKeyEncryption; + + private String encryptedPasswordHashCipher; + private byte[] encryptedPasswordHash; + + public void set(String secretKeyFactory, byte[] salt, + Integer iterationCount, Integer keyLength, + String secretKeyEncryption) { + this.secretKeyFactory = secretKeyFactory; + this.salt = salt; + this.iterationCount = iterationCount; + this.keyLength = keyLength; + this.secretKeyEncryption = secretKeyEncryption; +// this.encryptedPasswordHashCipher = encryptedPasswordHashCipher; +// this.encryptedPasswordHash = encryptedPasswordHash; + } + + public String getSecretKeyFactory() { + return secretKeyFactory; + } + + public byte[] getSalt() { + return salt; + } + + public Integer getIterationCount() { + return iterationCount; + } + + public Integer getKeyLength() { + return keyLength; + } + + public String getSecretKeyEncryption() { + return secretKeyEncryption; + } + + public String getEncryptedPasswordHashCipher() { + return encryptedPasswordHashCipher; + } + + public byte[] getEncryptedPasswordHash() { + return encryptedPasswordHash; + } + +} diff --git a/org.argeo.node.api/src/org/argeo/node/tabular/ArrayTabularRow.java b/org.argeo.node.api/src/org/argeo/node/tabular/ArrayTabularRow.java new file mode 100644 index 000000000..97bf025dc --- /dev/null +++ b/org.argeo.node.api/src/org/argeo/node/tabular/ArrayTabularRow.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.node.tabular; + +import java.util.List; + +/** Minimal tabular row wrapping an {@link Object} array */ +public class ArrayTabularRow implements TabularRow { + private final Object[] arr; + + public ArrayTabularRow(List objs) { + this.arr = objs.toArray(); + } + + public Object get(Integer col) { + return arr[col]; + } + + public int size() { + return arr.length; + } + + public Object[] toArray() { + return arr; + } + +} diff --git a/org.argeo.node.api/src/org/argeo/node/tabular/TabularColumn.java b/org.argeo.node.api/src/org/argeo/node/tabular/TabularColumn.java new file mode 100644 index 000000000..5cd11d198 --- /dev/null +++ b/org.argeo.node.api/src/org/argeo/node/tabular/TabularColumn.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.node.tabular; + +/** The column in a tabular content */ +public class TabularColumn { + private String name; + /** + * JCR types, see + * http://www.day.com/maven/javax.jcr/javadocs/jcr-2.0/index.html + * ?javax/jcr/PropertyType.html + */ + private Integer type; + + /** column with default type */ + public TabularColumn(String name) { + super(); + this.name = name; + } + + public TabularColumn(String name, Integer type) { + super(); + this.name = name; + this.type = type; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + +} diff --git a/org.argeo.node.api/src/org/argeo/node/tabular/TabularContent.java b/org.argeo.node.api/src/org/argeo/node/tabular/TabularContent.java new file mode 100644 index 000000000..a5aa9f678 --- /dev/null +++ b/org.argeo.node.api/src/org/argeo/node/tabular/TabularContent.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.node.tabular; + +import java.util.List; + +/** + * Content organized as a table, possibly with headers. Only JCR types are + * supported even though there is not direct dependency on JCR. + */ +public interface TabularContent { + /** The headers of this table or null is none available. */ + public List getColumns(); + + public TabularRowIterator read(); +} diff --git a/org.argeo.node.api/src/org/argeo/node/tabular/TabularRow.java b/org.argeo.node.api/src/org/argeo/node/tabular/TabularRow.java new file mode 100644 index 000000000..f652df947 --- /dev/null +++ b/org.argeo.node.api/src/org/argeo/node/tabular/TabularRow.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.node.tabular; + +/** A row of tabular data */ +public interface TabularRow { + /** The value at this column index */ + public Object get(Integer col); + + /** The raw objects (direct references) */ + public Object[] toArray(); + + /** Number of columns */ + public int size(); +} diff --git a/org.argeo.node.api/src/org/argeo/node/tabular/TabularRowIterator.java b/org.argeo.node.api/src/org/argeo/node/tabular/TabularRowIterator.java new file mode 100644 index 000000000..98a04a65c --- /dev/null +++ b/org.argeo.node.api/src/org/argeo/node/tabular/TabularRowIterator.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.node.tabular; + +import java.util.Iterator; + +/** Navigation of rows */ +public interface TabularRowIterator extends Iterator { + /** + * Current row number, has to be incremented by each call to next() ; starts at 0, will + * therefore be 1 for the first row returned. + */ + public Long getCurrentRowNumber(); +} diff --git a/org.argeo.node.api/src/org/argeo/node/tabular/TabularWriter.java b/org.argeo.node.api/src/org/argeo/node/tabular/TabularWriter.java new file mode 100644 index 000000000..b7febee65 --- /dev/null +++ b/org.argeo.node.api/src/org/argeo/node/tabular/TabularWriter.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.node.tabular; + + +/** Write to a tabular content */ +public interface TabularWriter { + /** Append a new row of data */ + public void appendRow(Object[] row); + + /** Finish persisting data and release resources */ + public void close(); +} diff --git a/org.argeo.osgi.boot/ext/test/org/argeo/osgi/boot/OsgiBootRuntimeTest.java b/org.argeo.osgi.boot/ext/test/org/argeo/osgi/boot/OsgiBootRuntimeTest.java index a165c4ee5..b396c451a 100644 --- a/org.argeo.osgi.boot/ext/test/org/argeo/osgi/boot/OsgiBootRuntimeTest.java +++ b/org.argeo.osgi.boot/ext/test/org/argeo/osgi/boot/OsgiBootRuntimeTest.java @@ -15,10 +15,8 @@ */ package org.argeo.osgi.boot; -import java.util.HashMap; import java.util.Iterator; import java.util.Map; -import java.util.ServiceLoader; import java.util.TreeMap; import junit.framework.TestCase; @@ -26,8 +24,6 @@ import junit.framework.TestCase; import org.eclipse.core.runtime.adaptor.EclipseStarter; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; -import org.osgi.framework.launch.Framework; -import org.osgi.framework.launch.FrameworkFactory; /** Starts an Equinox runtime and provision it with OSGi boot. */ public class OsgiBootRuntimeTest extends TestCase { diff --git a/org.argeo.util/ext/test/org/argeo/util/security/PasswordBasedEncryptionTest.java b/org.argeo.util/ext/test/org/argeo/util/security/PasswordBasedEncryptionTest.java deleted file mode 100644 index 0895c6bbe..000000000 --- a/org.argeo.util/ext/test/org/argeo/util/security/PasswordBasedEncryptionTest.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.util.security; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.InputStream; - -import javax.crypto.Cipher; -import javax.crypto.CipherInputStream; -import javax.crypto.CipherOutputStream; -import javax.crypto.SecretKey; -import javax.crypto.SecretKeyFactory; -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.PBEKeySpec; -import javax.crypto.spec.PBEParameterSpec; -import javax.crypto.spec.SecretKeySpec; -import javax.xml.bind.DatatypeConverter; - -import junit.framework.TestCase; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.util.internal.StreamUtils; -import org.argeo.util.security.PasswordBasedEncryption; - -public class PasswordBasedEncryptionTest extends TestCase { - private final static Log log = LogFactory - .getLog(PasswordBasedEncryptionTest.class); - - public void testEncryptDecrypt() { - final String password = "test long password since they are safer"; - PasswordBasedEncryption pbeEnc = new PasswordBasedEncryption( - password.toCharArray()); - String message = "Hello World!"; - log.info("Password:\t'" + password + "'"); - log.info("Message:\t'" + message + "'"); - byte[] encrypted = pbeEnc.encryptString(message); - log.info("Encrypted:\t'" - + DatatypeConverter.printBase64Binary(encrypted) + "'"); - PasswordBasedEncryption pbeDec = new PasswordBasedEncryption( - password.toCharArray()); - InputStream in = null; - in = new ByteArrayInputStream(encrypted); - String decrypted = pbeDec.decryptAsString(in); - log.info("Decrypted:\t'" + decrypted + "'"); - StreamUtils.closeQuietly(in); - assertEquals(message, decrypted); - } - - public void testPBEWithMD5AndDES() throws Exception { - String password = "test"; - String message = "Hello World!"; - - byte[] salt = { (byte) 0xc7, (byte) 0x73, (byte) 0x21, (byte) 0x8c, - (byte) 0x7e, (byte) 0xc8, (byte) 0xee, (byte) 0x99 }; - - int count = 1024; - - String cipherAlgorithm = "PBEWithMD5AndDES"; - String secretKeyAlgorithm = "PBEWithMD5AndDES"; - SecretKeyFactory keyFac = SecretKeyFactory - .getInstance(secretKeyAlgorithm); - PBEKeySpec pbeKeySpec = new PBEKeySpec(password.toCharArray()); - PBEParameterSpec pbeParamSpec = new PBEParameterSpec(salt, count); - SecretKey pbeKey = keyFac.generateSecret(pbeKeySpec); - Cipher ecipher = Cipher.getInstance(cipherAlgorithm); - ecipher.init(Cipher.ENCRYPT_MODE, pbeKey, pbeParamSpec); - Cipher dcipher = Cipher.getInstance(cipherAlgorithm); - dcipher.init(Cipher.DECRYPT_MODE, pbeKey, pbeParamSpec); - - byte[] encrypted = ecipher.doFinal(message.getBytes()); - byte[] decrypted = dcipher.doFinal(encrypted); - assertEquals(message, new String(decrypted)); - - } - - public void testPBEWithSHA1AndAES() throws Exception { - String password = "test"; - String message = "Hello World!"; - - byte[] salt = { (byte) 0xc7, (byte) 0x73, (byte) 0x21, (byte) 0x8c, - (byte) 0x7e, (byte) 0xc8, (byte) 0xee, (byte) 0x99 }; - byte[] iv = { (byte) 0xc7, (byte) 0x73, (byte) 0x21, (byte) 0x8c, - (byte) 0x7e, (byte) 0xc8, (byte) 0xee, (byte) 0x99, - (byte) 0xc7, (byte) 0x73, (byte) 0x21, (byte) 0x8c, - (byte) 0x7e, (byte) 0xc8, (byte) 0xee, (byte) 0x99 }; - - int count = 1024; - // int keyLength = 256; - int keyLength = 128; - - String cipherAlgorithm = "AES/CBC/PKCS5Padding"; - String secretKeyAlgorithm = "PBKDF2WithHmacSHA1"; - SecretKeyFactory keyFac = SecretKeyFactory - .getInstance(secretKeyAlgorithm); - PBEKeySpec pbeKeySpec = new PBEKeySpec(password.toCharArray(), salt, - count, keyLength); - SecretKey tmp = keyFac.generateSecret(pbeKeySpec); - SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES"); - Cipher ecipher = Cipher.getInstance(cipherAlgorithm); - ecipher.init(Cipher.ENCRYPT_MODE, secret, new IvParameterSpec(iv)); - - // decrypt - keyFac = SecretKeyFactory.getInstance(secretKeyAlgorithm); - pbeKeySpec = new PBEKeySpec(password.toCharArray(), salt, count, - keyLength); - tmp = keyFac.generateSecret(pbeKeySpec); - secret = new SecretKeySpec(tmp.getEncoded(), "AES"); - // AlgorithmParameters params = ecipher.getParameters(); - // byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV(); - Cipher dcipher = Cipher.getInstance(cipherAlgorithm); - dcipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv)); - - byte[] encrypted = ecipher.doFinal(message.getBytes()); - byte[] decrypted = dcipher.doFinal(encrypted); - assertEquals(message, new String(decrypted)); - - ByteArrayOutputStream out = new ByteArrayOutputStream(); - CipherOutputStream cipherOut = new CipherOutputStream(out, ecipher); - cipherOut.write(message.getBytes()); - StreamUtils.closeQuietly(cipherOut); - byte[] enc = out.toByteArray(); - - ByteArrayInputStream in = new ByteArrayInputStream(enc); - CipherInputStream cipherIn = new CipherInputStream(in, dcipher); - ByteArrayOutputStream dec = new ByteArrayOutputStream(); - StreamUtils.copy(cipherIn, dec); - assertEquals(message, new String(dec.toByteArray())); - } -} diff --git a/org.argeo.util/src/org/argeo/ArgeoException.java b/org.argeo.util/src/org/argeo/ArgeoException.java deleted file mode 100644 index 4fa296afa..000000000 --- a/org.argeo.util/src/org/argeo/ArgeoException.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo; - -import javax.naming.OperationNotSupportedException; - -/** - * Argeo Commons specific exception. - * - * @deprecated Use project specific exceptions or standard ones like - * {@link OperationNotSupportedException}, - * {@link IllegalArgumentException}, etc. - */ -@Deprecated -public class ArgeoException extends RuntimeException { - private static final long serialVersionUID = 1L; - - /** Creates an exception with a message. */ - public ArgeoException(String message) { - super(message); - } - - /** Creates an exception with a message and a root cause. */ - public ArgeoException(String message, Throwable e) { - super(message, e); - } - -} diff --git a/org.argeo.util/src/org/argeo/ArgeoMonitor.java b/org.argeo.util/src/org/argeo/ArgeoMonitor.java deleted file mode 100644 index 307581ea7..000000000 --- a/org.argeo.util/src/org/argeo/ArgeoMonitor.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo; - -/** - * Simple monitor abstraction. Inspired by Eclipse IProgressMOnitor, but without - * dependency to it. - * - * @deprecated use org.argeo.jcr.JcrMonitor instead - */ -@Deprecated -public interface ArgeoMonitor { - /** - * Constant indicating an unknown amount of work. - */ - public final static int UNKNOWN = -1; - - /** - * Notifies that the main task is beginning. This must only be called once - * on a given progress monitor instance. - * - * @param name - * the name (or description) of the main task - * @param totalWork - * the total number of work units into which the main task is - * been subdivided. If the value is UNKNOWN the - * implementation is free to indicate progress in a way which - * doesn't require the total number of work units in advance. - */ - public void beginTask(String name, int totalWork); - - /** - * Notifies that the work is done; that is, either the main task is - * completed or the user canceled it. This method may be called more than - * once (implementations should be prepared to handle this case). - */ - public void done(); - - /** - * Returns whether cancelation of current operation has been requested. - * Long-running operations should poll to see if cancelation has been - * requested. - * - * @return true if cancellation has been requested, and - * false otherwise - * @see #setCanceled(boolean) - */ - public boolean isCanceled(); - - /** - * Sets the cancel state to the given value. - * - * @param value - * true indicates that cancelation has been - * requested (but not necessarily acknowledged); - * false clears this flag - * @see #isCanceled() - */ - public void setCanceled(boolean value); - - /** - * Sets the task name to the given value. This method is used to restore the - * task label after a nested operation was executed. Normally there is no - * need for clients to call this method. - * - * @param name - * the name (or description) of the main task - * @see #beginTask(java.lang.String, int) - */ - public void setTaskName(String name); - - /** - * Notifies that a subtask of the main task is beginning. Subtasks are - * optional; the main task might not have subtasks. - * - * @param name - * the name (or description) of the subtask - */ - public void subTask(String name); - - /** - * Notifies that a given number of work unit of the main task has been - * completed. Note that this amount represents an installment, as opposed to - * a cumulative amount of work done to date. - * - * @param work - * a non-negative number of work units just completed - */ - public void worked(int work); - -} diff --git a/org.argeo.util/src/org/argeo/OperatingSystem.java b/org.argeo.util/src/org/argeo/OperatingSystem.java deleted file mode 100644 index 697c86c51..000000000 --- a/org.argeo.util/src/org/argeo/OperatingSystem.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo; - -/** The current operating system. */ -public class OperatingSystem { - public final static int NIX = 1; - public final static int WINDOWS = 2; - public final static int SOLARIS = 3; - - public final static int os; - static { - String osName = System.getProperty("os.name"); - if (osName.startsWith("Win")) - os = WINDOWS; - else if (osName.startsWith("Solaris")) - os = SOLARIS; - else - os = NIX; - } - -} diff --git a/org.argeo.util/src/org/argeo/util/CsvParser.java b/org.argeo.util/src/org/argeo/util/CsvParser.java index 569f08c73..d133afdbc 100644 --- a/org.argeo.util/src/org/argeo/util/CsvParser.java +++ b/org.argeo.util/src/org/argeo/util/CsvParser.java @@ -23,9 +23,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -import org.argeo.util.internal.StreamUtils; -import org.argeo.util.internal.UtilsException; - /** * Parses a CSV file interpreting the first line as a header. The * {@link #parse(InputStream)} method and the setters are synchronized so that diff --git a/org.argeo.util/src/org/argeo/util/CsvParserWithLinesAsMap.java b/org.argeo.util/src/org/argeo/util/CsvParserWithLinesAsMap.java index fe1750a23..c84d994c2 100644 --- a/org.argeo.util/src/org/argeo/util/CsvParserWithLinesAsMap.java +++ b/org.argeo.util/src/org/argeo/util/CsvParserWithLinesAsMap.java @@ -19,8 +19,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import org.argeo.util.internal.UtilsException; - /** * CSV parser allowing to process lines as maps whose keys are the header * fields. diff --git a/org.argeo.util/src/org/argeo/util/CsvWriter.java b/org.argeo.util/src/org/argeo/util/CsvWriter.java index 1ebe1022d..4b9fea3fa 100644 --- a/org.argeo.util/src/org/argeo/util/CsvWriter.java +++ b/org.argeo.util/src/org/argeo/util/CsvWriter.java @@ -23,8 +23,6 @@ import java.io.Writer; import java.util.Iterator; import java.util.List; -import org.argeo.util.internal.UtilsException; - /** Write in CSV format. */ public class CsvWriter { private final Writer out; diff --git a/org.argeo.util/src/org/argeo/util/DigestUtils.java b/org.argeo.util/src/org/argeo/util/DigestUtils.java new file mode 100644 index 000000000..52cbc5d21 --- /dev/null +++ b/org.argeo.util/src/org/argeo/util/DigestUtils.java @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.util; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +/** Utilities around cryptographic digests */ +public class DigestUtils { + private static Boolean debug = true; + // TODO: make it writable + private final static Integer byteBufferCapacity = 100 * 1024;// 100 KB + + public static String digest(String algorithm, byte[] bytes) { + try { + MessageDigest digest = MessageDigest.getInstance(algorithm); + digest.update(bytes); + byte[] checksum = digest.digest(); + String res = encodeHexString(checksum); + return res; + } catch (Exception e) { + throw new UtilsException("Cannot digest with algorithm " + algorithm, e); + } + } + + public static String digest(String algorithm, InputStream in) { + try { + MessageDigest digest = MessageDigest.getInstance(algorithm); + // ReadableByteChannel channel = Channels.newChannel(in); + // ByteBuffer bb = ByteBuffer.allocateDirect(byteBufferCapacity); + // while (channel.read(bb) > 0) + // digest.update(bb); + byte[] buffer = new byte[byteBufferCapacity]; + int read = 0; + while ((read = in.read(buffer)) > 0) { + digest.update(buffer, 0, read); + } + + byte[] checksum = digest.digest(); + String res = encodeHexString(checksum); + return res; + } catch (Exception e) { + throw new UtilsException("Cannot digest with algorithm " + algorithm, e); + } finally { + StreamUtils.closeQuietly(in); + } + } + + public static String digest(String algorithm, File file) { + FileInputStream fis = null; + FileChannel fc = null; + try { + fis = new FileInputStream(file); + fc = fis.getChannel(); + + // Get the file's size and then map it into memory + int sz = (int) fc.size(); + ByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, sz); + return digest(algorithm, bb); + } catch (IOException e) { + throw new UtilsException("Cannot digest " + file + " with algorithm " + algorithm, e); + } finally { + StreamUtils.closeQuietly(fis); + if (fc.isOpen()) + try { + fc.close(); + } catch (IOException e) { + // silent + } + } + } + + protected static String digest(String algorithm, ByteBuffer bb) { + long begin = System.currentTimeMillis(); + try { + MessageDigest digest = MessageDigest.getInstance(algorithm); + digest.update(bb); + byte[] checksum = digest.digest(); + String res = encodeHexString(checksum); + long end = System.currentTimeMillis(); + if (debug) + System.out.println((end - begin) + " ms / " + ((end - begin) / 1000) + " s"); + return res; + } catch (NoSuchAlgorithmException e) { + throw new UtilsException("Cannot digest with algorithm " + algorithm, e); + } + } + + public static void main(String[] args) { + File file; + if (args.length > 0) + file = new File(args[0]); + else { + System.err.println("Usage: []" + " (see http://java.sun.com/j2se/1.5.0/" + + "docs/guide/security/CryptoSpec.html#AppA)"); + return; + } + + if (args.length > 1) { + String algorithm = args[1]; + System.out.println(digest(algorithm, file)); + } else { + String algorithm = "MD5"; + System.out.println(algorithm + ": " + digest(algorithm, file)); + algorithm = "SHA"; + System.out.println(algorithm + ": " + digest(algorithm, file)); + algorithm = "SHA-256"; + System.out.println(algorithm + ": " + digest(algorithm, file)); + algorithm = "SHA-512"; + System.out.println(algorithm + ": " + digest(algorithm, file)); + } + } + + final private static char[] hexArray = "0123456789ABCDEF".toCharArray(); + + /** + * From + * http://stackoverflow.com/questions/9655181/how-to-convert-a-byte-array-to + * -a-hex-string-in-java + */ + private static String encodeHexString(byte[] bytes) { + char[] hexChars = new char[bytes.length * 2]; + for (int j = 0; j < bytes.length; j++) { + int v = bytes[j] & 0xFF; + hexChars[j * 2] = hexArray[v >>> 4]; + hexChars[j * 2 + 1] = hexArray[v & 0x0F]; + } + return new String(hexChars); + } + +} diff --git a/org.argeo.util/src/org/argeo/util/StreamUtils.java b/org.argeo.util/src/org/argeo/util/StreamUtils.java new file mode 100644 index 000000000..1cfa5b220 --- /dev/null +++ b/org.argeo.util/src/org/argeo/util/StreamUtils.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.util; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Reader; +import java.io.Writer; + +/** Utilities to be used when APache COmmons IO is not available. */ +class StreamUtils { + private static final int DEFAULT_BUFFER_SIZE = 1024 * 4; + + /* + * APACHE COMMONS IO (inspired) + */ + + /** @return the number of bytes */ + public static Long copy(InputStream in, OutputStream out) + throws IOException { + Long count = 0l; + byte[] buf = new byte[DEFAULT_BUFFER_SIZE]; + while (true) { + int length = in.read(buf); + if (length < 0) + break; + out.write(buf, 0, length); + count = count + length; + } + return count; + } + + /** @return the number of chars */ + public static Long copy(Reader in, Writer out) throws IOException { + Long count = 0l; + char[] buf = new char[DEFAULT_BUFFER_SIZE]; + while (true) { + int length = in.read(buf); + if (length < 0) + break; + out.write(buf, 0, length); + count = count + length; + } + return count; + } + + public static void closeQuietly(InputStream in) { + if (in != null) + try { + in.close(); + } catch (Exception e) { + // + } + } + + public static void closeQuietly(OutputStream out) { + if (out != null) + try { + out.close(); + } catch (Exception e) { + // + } + } + + public static void closeQuietly(Reader in) { + if (in != null) + try { + in.close(); + } catch (Exception e) { + // + } + } + + public static void closeQuietly(Writer out) { + if (out != null) + try { + out.close(); + } catch (Exception e) { + // + } + } +} diff --git a/org.argeo.util/src/org/argeo/util/Throughput.java b/org.argeo.util/src/org/argeo/util/Throughput.java index fb928002e..e5bc96101 100644 --- a/org.argeo.util/src/org/argeo/util/Throughput.java +++ b/org.argeo.util/src/org/argeo/util/Throughput.java @@ -19,8 +19,6 @@ import java.text.NumberFormat; import java.text.ParseException; import java.util.Locale; -import org.argeo.util.internal.UtilsException; - public class Throughput { private final static NumberFormat usNumberFormat = NumberFormat .getInstance(Locale.US); diff --git a/org.argeo.util/src/org/argeo/util/ThroughputEditor.java b/org.argeo.util/src/org/argeo/util/ThroughputEditor.java deleted file mode 100644 index 4ebf26b81..000000000 --- a/org.argeo.util/src/org/argeo/util/ThroughputEditor.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.util; - -import java.beans.PropertyEditorSupport; - -public class ThroughputEditor extends PropertyEditorSupport { - - @Override - public String getAsText() { - return getValue().toString(); - } - - @Override - public void setAsText(String text) throws IllegalArgumentException { - setValue(new Throughput(text)); - } - -} diff --git a/org.argeo.util/src/org/argeo/util/UtilsException.java b/org.argeo.util/src/org/argeo/util/UtilsException.java new file mode 100644 index 000000000..b93233a76 --- /dev/null +++ b/org.argeo.util/src/org/argeo/util/UtilsException.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.util; + +/** Utils specific exception. */ +class UtilsException extends RuntimeException { + private static final long serialVersionUID = 1L; + + /** Creates an exception with a message. */ + public UtilsException(String message) { + super(message); + } + + /** Creates an exception with a message and a root cause. */ + public UtilsException(String message, Throwable e) { + super(message, e); + } + +} diff --git a/org.argeo.util/src/org/argeo/util/internal/StreamUtils.java b/org.argeo.util/src/org/argeo/util/internal/StreamUtils.java deleted file mode 100644 index cf6fc0c0e..000000000 --- a/org.argeo.util/src/org/argeo/util/internal/StreamUtils.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.util.internal; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.Reader; -import java.io.Writer; - -/** Utilities to be used when APache COmmons IO is not available. */ -public class StreamUtils { - private static final int DEFAULT_BUFFER_SIZE = 1024 * 4; - - /* - * APACHE COMMONS IO (inspired) - */ - - /** @return the number of bytes */ - public static Long copy(InputStream in, OutputStream out) - throws IOException { - Long count = 0l; - byte[] buf = new byte[DEFAULT_BUFFER_SIZE]; - while (true) { - int length = in.read(buf); - if (length < 0) - break; - out.write(buf, 0, length); - count = count + length; - } - return count; - } - - /** @return the number of chars */ - public static Long copy(Reader in, Writer out) throws IOException { - Long count = 0l; - char[] buf = new char[DEFAULT_BUFFER_SIZE]; - while (true) { - int length = in.read(buf); - if (length < 0) - break; - out.write(buf, 0, length); - count = count + length; - } - return count; - } - - public static void closeQuietly(InputStream in) { - if (in != null) - try { - in.close(); - } catch (Exception e) { - // - } - } - - public static void closeQuietly(OutputStream out) { - if (out != null) - try { - out.close(); - } catch (Exception e) { - // - } - } - - public static void closeQuietly(Reader in) { - if (in != null) - try { - in.close(); - } catch (Exception e) { - // - } - } - - public static void closeQuietly(Writer out) { - if (out != null) - try { - out.close(); - } catch (Exception e) { - // - } - } -} diff --git a/org.argeo.util/src/org/argeo/util/internal/UtilsException.java b/org.argeo.util/src/org/argeo/util/internal/UtilsException.java deleted file mode 100644 index d93851cdb..000000000 --- a/org.argeo.util/src/org/argeo/util/internal/UtilsException.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.util.internal; - -/** Utils specific exception. */ -public class UtilsException extends RuntimeException { - private static final long serialVersionUID = 1L; - - /** Creates an exception with a message. */ - public UtilsException(String message) { - super(message); - } - - /** Creates an exception with a message and a root cause. */ - public UtilsException(String message, Throwable e) { - super(message, e); - } - -} diff --git a/org.argeo.util/src/org/argeo/util/security/AbstractKeyring.java b/org.argeo.util/src/org/argeo/util/security/AbstractKeyring.java deleted file mode 100644 index 68ae1a20e..000000000 --- a/org.argeo.util/src/org/argeo/util/security/AbstractKeyring.java +++ /dev/null @@ -1,276 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.util.security; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.CharArrayWriter; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.io.Reader; -import java.io.Writer; -import java.security.AccessController; -import java.security.MessageDigest; -import java.security.Provider; -import java.security.Security; -import java.util.Arrays; -import java.util.Iterator; - -import javax.crypto.SecretKey; -import javax.security.auth.Subject; -import javax.security.auth.callback.Callback; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.callback.PasswordCallback; -import javax.security.auth.callback.TextOutputCallback; -import javax.security.auth.callback.UnsupportedCallbackException; -import javax.security.auth.login.LoginContext; -import javax.security.auth.login.LoginException; - -import org.argeo.util.internal.UtilsException; -import org.argeo.util.internal.StreamUtils; - -/** username / password based keyring. TODO internationalize */ -public abstract class AbstractKeyring implements Keyring, CryptoKeyring { - public final static String DEFAULT_KEYRING_LOGIN_CONTEXT = "KEYRING"; - - private String loginContextName = DEFAULT_KEYRING_LOGIN_CONTEXT; - private CallbackHandler defaultCallbackHandler; - - private String charset = "UTF-8"; - - /** - * Default provider is bouncy castle, in order to have consistent behaviour - * across implementations - */ - private String securityProviderName = "BC"; - - /** - * Whether the keyring has already been created in the past with a master - * password - */ - protected abstract Boolean isSetup(); - - /** - * Setup the keyring persistently, {@link #isSetup()} must return true - * afterwards - */ - protected abstract void setup(char[] password); - - /** Populates the key spec callback */ - protected abstract void handleKeySpecCallback(PBEKeySpecCallback pbeCallback); - - protected abstract void encrypt(String path, InputStream unencrypted); - - protected abstract InputStream decrypt(String path); - - /** Triggers lazy initialization */ - protected SecretKey getSecretKey() { - Subject subject = Subject.getSubject(AccessController.getContext()); - // we assume only one secrete key is available - Iterator iterator = subject.getPrivateCredentials( - SecretKey.class).iterator(); - if (!iterator.hasNext()) {// not initialized - CallbackHandler callbackHandler = new KeyringCallbackHandler(); - try { - LoginContext loginContext = new LoginContext(loginContextName, - subject, callbackHandler); - loginContext.login(); - // FIXME will login even if password is wrong - iterator = subject.getPrivateCredentials(SecretKey.class) - .iterator(); - return iterator.next(); - } catch (LoginException e) { - throw new UtilsException("Keyring login failed", e); - } - - } else { - SecretKey secretKey = iterator.next(); - if (iterator.hasNext()) - throw new UtilsException( - "More than one secret key in private credentials"); - return secretKey; - } - } - - public InputStream getAsStream(String path) { - return decrypt(path); - } - - public void set(String path, InputStream in) { - encrypt(path, in); - } - - public char[] getAsChars(String path) { - InputStream in = getAsStream(path); - CharArrayWriter writer = null; - Reader reader = null; - try { - writer = new CharArrayWriter(); - reader = new InputStreamReader(in, charset); - StreamUtils.copy(reader, writer); - return writer.toCharArray(); - } catch (IOException e) { - throw new UtilsException("Cannot decrypt to char array", e); - } finally { - StreamUtils.closeQuietly(reader); - StreamUtils.closeQuietly(in); - StreamUtils.closeQuietly(writer); - } - } - - public void set(String path, char[] arr) { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - ByteArrayInputStream in = null; - Writer writer = null; - try { - writer = new OutputStreamWriter(out, charset); - writer.write(arr); - writer.flush(); - in = new ByteArrayInputStream(out.toByteArray()); - set(path, in); - } catch (IOException e) { - throw new UtilsException("Cannot encrypt to char array", e); - } finally { - StreamUtils.closeQuietly(writer); - StreamUtils.closeQuietly(out); - StreamUtils.closeQuietly(in); - } - } - - protected Provider getSecurityProvider() { - return Security.getProvider(securityProviderName); - } - - public void setLoginContextName(String loginContextName) { - this.loginContextName = loginContextName; - } - - public void setDefaultCallbackHandler(CallbackHandler defaultCallbackHandler) { - this.defaultCallbackHandler = defaultCallbackHandler; - } - - public void setCharset(String charset) { - this.charset = charset; - } - - public void setSecurityProviderName(String securityProviderName) { - this.securityProviderName = securityProviderName; - } - - @Deprecated - protected static byte[] hash(char[] password, byte[] salt, - Integer iterationCount) { - ByteArrayOutputStream out = null; - OutputStreamWriter writer = null; - try { - out = new ByteArrayOutputStream(); - writer = new OutputStreamWriter(out, "UTF-8"); - writer.write(password); - MessageDigest pwDigest = MessageDigest.getInstance("SHA-256"); - pwDigest.reset(); - pwDigest.update(salt); - byte[] btPass = pwDigest.digest(out.toByteArray()); - for (int i = 0; i < iterationCount; i++) { - pwDigest.reset(); - btPass = pwDigest.digest(btPass); - } - return btPass; - } catch (Exception e) { - throw new UtilsException("Cannot hash", e); - } finally { - StreamUtils.closeQuietly(out); - StreamUtils.closeQuietly(writer); - } - - } - - /** - * Convenience method using the underlying callback to ask for a password - * (typically used when the password is not saved in the keyring) - */ - protected char[] ask() { - PasswordCallback passwordCb = new PasswordCallback("Password", false); - Callback[] dialogCbs = new Callback[] { passwordCb }; - try { - defaultCallbackHandler.handle(dialogCbs); - char[] password = passwordCb.getPassword(); - return password; - } catch (Exception e) { - throw new UtilsException("Cannot ask for a password", e); - } - - } - - class KeyringCallbackHandler implements CallbackHandler { - public void handle(Callback[] callbacks) throws IOException, - UnsupportedCallbackException { - // checks - if (callbacks.length != 2) - throw new IllegalArgumentException( - "Keyring required 2 and only 2 callbacks: {PasswordCallback,PBEKeySpecCallback}"); - if (!(callbacks[0] instanceof PasswordCallback)) - throw new UnsupportedCallbackException(callbacks[0]); - if (!(callbacks[1] instanceof PBEKeySpecCallback)) - throw new UnsupportedCallbackException(callbacks[0]); - - PasswordCallback passwordCb = (PasswordCallback) callbacks[0]; - PBEKeySpecCallback pbeCb = (PBEKeySpecCallback) callbacks[1]; - - if (isSetup()) { - Callback[] dialogCbs = new Callback[] { passwordCb }; - defaultCallbackHandler.handle(dialogCbs); - } else {// setup keyring - TextOutputCallback textCb1 = new TextOutputCallback( - TextOutputCallback.INFORMATION, - "Enter a master password which will protect your private data"); - TextOutputCallback textCb2 = new TextOutputCallback( - TextOutputCallback.INFORMATION, - "(for example your credentials to third-party services)"); - TextOutputCallback textCb3 = new TextOutputCallback( - TextOutputCallback.INFORMATION, - "Don't forget this password since the data cannot be read without it"); - PasswordCallback confirmPasswordCb = new PasswordCallback( - "Confirm password", false); - // first try - Callback[] dialogCbs = new Callback[] { textCb1, textCb2, - textCb3, passwordCb, confirmPasswordCb }; - defaultCallbackHandler.handle(dialogCbs); - - // if passwords different, retry (except if cancelled) - while (passwordCb.getPassword() != null - && !Arrays.equals(passwordCb.getPassword(), - confirmPasswordCb.getPassword())) { - TextOutputCallback textCb = new TextOutputCallback( - TextOutputCallback.ERROR, - "The passwords do not match"); - dialogCbs = new Callback[] { textCb, passwordCb, - confirmPasswordCb }; - defaultCallbackHandler.handle(dialogCbs); - } - - if (passwordCb.getPassword() != null) {// not cancelled - setup(passwordCb.getPassword()); - } - } - - if (passwordCb.getPassword() != null) - handleKeySpecCallback(pbeCb); - } - - } -} diff --git a/org.argeo.util/src/org/argeo/util/security/ChecksumFactory.java b/org.argeo.util/src/org/argeo/util/security/ChecksumFactory.java deleted file mode 100644 index b57db2c98..000000000 --- a/org.argeo.util/src/org/argeo/util/security/ChecksumFactory.java +++ /dev/null @@ -1,157 +0,0 @@ -package org.argeo.util.security; - -import static javax.xml.bind.DatatypeConverter.printBase64Binary; - -import java.io.IOException; -import java.math.BigInteger; -import java.nio.MappedByteBuffer; -import java.nio.channels.FileChannel; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.SimpleFileVisitor; -import java.nio.file.attribute.BasicFileAttributes; -import java.security.MessageDigest; -import java.util.zip.Checksum; - -import org.argeo.util.internal.UtilsException; - -/** Allows to fine tune how files are read. */ -public class ChecksumFactory { - private int regionSize = 10 * 1024 * 1024; - - public byte[] digest(Path path, final String algo) { - try { - final MessageDigest md = MessageDigest.getInstance(algo); - if (Files.isDirectory(path)) { - long begin = System.currentTimeMillis(); - Files.walkFileTree(path, new SimpleFileVisitor() { - - @Override - public FileVisitResult visitFile(Path file, - BasicFileAttributes attrs) throws IOException { - if (!Files.isDirectory(file)) { - byte[] digest = digest(file, algo); - md.update(digest); - } - return FileVisitResult.CONTINUE; - } - - }); - byte[] digest = md.digest(); - long duration = System.currentTimeMillis() - begin; - System.out.println(printBase64Binary(digest) + " " + path - + " (" + duration / 1000 + "s)"); - return digest; - } else { - long begin = System.nanoTime(); - long length = -1; - try (FileChannel channel = (FileChannel) Files - .newByteChannel(path);) { - length = channel.size(); - long cursor = 0; - while (cursor < length) { - long effectiveSize = Math.min(regionSize, length - - cursor); - MappedByteBuffer mb = channel.map( - FileChannel.MapMode.READ_ONLY, cursor, - effectiveSize); - // md.update(mb); - byte[] buffer = new byte[1024]; - while (mb.hasRemaining()){ - mb.get(buffer); - md.update(buffer); - } - - // sub digest - // mb.flip(); - // MessageDigest subMd = - // MessageDigest.getInstance(algo); - // subMd.update(mb); - // byte[] subDigest = subMd.digest(); - // System.out.println(" -> " + cursor); - // System.out.println(StreamUtils.encodeHexString(subDigest)); - // System.out.println(new BigInteger(1, - // subDigest).toString(16)); - // System.out.println(new BigInteger(1, subDigest) - // .toString(Character.MAX_RADIX)); - // System.out.println(printBase64Binary(subDigest)); - - cursor = cursor + regionSize; - } - byte[] digest = md.digest(); - long duration = System.nanoTime() - begin; - System.out.println(printBase64Binary(digest) + " " - + path.getFileName() + " (" + duration / 1000000 - + "ms, " + (length / 1024) + "kB, " - + (length / (duration / 1000000)) * 1000 - / (1024 * 1024) + " MB/s)"); - return digest; - } - } - } catch (Exception e) { - throw new UtilsException("Cannot digest " + path, e); - } - } - - /** Whether the file should be mapped. */ - protected boolean mapFile(FileChannel fileChannel) throws IOException { - long size = fileChannel.size(); - if (size > (regionSize / 10)) - return true; - return false; - } - - public long checksum(Path path, Checksum crc) { - final int bufferSize = 2 * 1024 * 1024; - long begin = System.currentTimeMillis(); - try (FileChannel channel = (FileChannel) Files.newByteChannel(path);) { - byte[] bytes = new byte[bufferSize]; - long length = channel.size(); - long cursor = 0; - while (cursor < length) { - long effectiveSize = Math.min(regionSize, length - cursor); - MappedByteBuffer mb = channel.map( - FileChannel.MapMode.READ_ONLY, cursor, effectiveSize); - int nGet; - while (mb.hasRemaining()) { - nGet = Math.min(mb.remaining(), bufferSize); - mb.get(bytes, 0, nGet); - crc.update(bytes, 0, nGet); - } - cursor = cursor + regionSize; - } - return crc.getValue(); - } catch (Exception e) { - throw new UtilsException("Cannot checksum " + path, e); - } finally { - long duration = System.currentTimeMillis() - begin; - System.out.println(duration / 1000 + "s"); - } - } - - public static void main(String... args) { - ChecksumFactory cf = new ChecksumFactory(); - // Path path = - // Paths.get("/home/mbaudier/apache-maven-3.2.3-bin.tar.gz"); - Path path; - if (args.length > 0) { - path = Paths.get(args[0]); - } else { - path = Paths - .get("/home/mbaudier/Downloads/torrents/CentOS-7-x86_64-DVD-1503-01/" - + "CentOS-7-x86_64-DVD-1503-01.iso"); - } - // long adler = cf.checksum(path, new Adler32()); - // System.out.format("Adler=%d%n", adler); - // long crc = cf.checksum(path, new CRC32()); - // System.out.format("CRC=%d%n", crc); - String algo = "SHA1"; - byte[] digest = cf.digest(path, algo); - System.out.println(algo + " " + printBase64Binary(digest)); - System.out.println(algo + " " + new BigInteger(1, digest).toString(16)); - // String sha1 = printBase64Binary(cf.digest(path, "SHA1")); - // System.out.format("SHA1=%s%n", sha1); - } -} diff --git a/org.argeo.util/src/org/argeo/util/security/CryptoKeyring.java b/org.argeo.util/src/org/argeo/util/security/CryptoKeyring.java deleted file mode 100644 index 53ce862f0..000000000 --- a/org.argeo.util/src/org/argeo/util/security/CryptoKeyring.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.util.security; - - -/** - * Advanced keyring based on cryptography that can easily be centralized and - * coordinated with {@link KeyringLoginModule} (since they ar ein the same - * package) - */ -public interface CryptoKeyring extends Keyring { - -} diff --git a/org.argeo.util/src/org/argeo/util/security/DigestUtils.java b/org.argeo.util/src/org/argeo/util/security/DigestUtils.java deleted file mode 100644 index 6d46c288f..000000000 --- a/org.argeo.util/src/org/argeo/util/security/DigestUtils.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.util.security; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.nio.ByteBuffer; -import java.nio.channels.FileChannel; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; - -import org.argeo.util.internal.UtilsException; -import org.argeo.util.internal.StreamUtils; - -/** Utilities around cryptographic digests */ -public class DigestUtils { - private static Boolean debug = true; - // TODO: make it writable - private final static Integer byteBufferCapacity = 100 * 1024;// 100 KB - - public static String digest(String algorithm, byte[] bytes) { - try { - MessageDigest digest = MessageDigest.getInstance(algorithm); - digest.update(bytes); - byte[] checksum = digest.digest(); - String res = encodeHexString(checksum); - return res; - } catch (Exception e) { - throw new UtilsException("Cannot digest with algorithm " + algorithm, e); - } - } - - public static String digest(String algorithm, InputStream in) { - try { - MessageDigest digest = MessageDigest.getInstance(algorithm); - // ReadableByteChannel channel = Channels.newChannel(in); - // ByteBuffer bb = ByteBuffer.allocateDirect(byteBufferCapacity); - // while (channel.read(bb) > 0) - // digest.update(bb); - byte[] buffer = new byte[byteBufferCapacity]; - int read = 0; - while ((read = in.read(buffer)) > 0) { - digest.update(buffer, 0, read); - } - - byte[] checksum = digest.digest(); - String res = encodeHexString(checksum); - return res; - } catch (Exception e) { - throw new UtilsException("Cannot digest with algorithm " + algorithm, e); - } finally { - StreamUtils.closeQuietly(in); - } - } - - public static String digest(String algorithm, File file) { - FileInputStream fis = null; - FileChannel fc = null; - try { - fis = new FileInputStream(file); - fc = fis.getChannel(); - - // Get the file's size and then map it into memory - int sz = (int) fc.size(); - ByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, sz); - return digest(algorithm, bb); - } catch (IOException e) { - throw new UtilsException("Cannot digest " + file + " with algorithm " + algorithm, e); - } finally { - StreamUtils.closeQuietly(fis); - if (fc.isOpen()) - try { - fc.close(); - } catch (IOException e) { - // silent - } - } - } - - protected static String digest(String algorithm, ByteBuffer bb) { - long begin = System.currentTimeMillis(); - try { - MessageDigest digest = MessageDigest.getInstance(algorithm); - digest.update(bb); - byte[] checksum = digest.digest(); - String res = encodeHexString(checksum); - long end = System.currentTimeMillis(); - if (debug) - System.out.println((end - begin) + " ms / " + ((end - begin) / 1000) + " s"); - return res; - } catch (NoSuchAlgorithmException e) { - throw new UtilsException("Cannot digest with algorithm " + algorithm, e); - } - } - - public static void main(String[] args) { - File file; - if (args.length > 0) - file = new File(args[0]); - else { - System.err.println("Usage: []" + " (see http://java.sun.com/j2se/1.5.0/" - + "docs/guide/security/CryptoSpec.html#AppA)"); - return; - } - - if (args.length > 1) { - String algorithm = args[1]; - System.out.println(digest(algorithm, file)); - } else { - String algorithm = "MD5"; - System.out.println(algorithm + ": " + digest(algorithm, file)); - algorithm = "SHA"; - System.out.println(algorithm + ": " + digest(algorithm, file)); - algorithm = "SHA-256"; - System.out.println(algorithm + ": " + digest(algorithm, file)); - algorithm = "SHA-512"; - System.out.println(algorithm + ": " + digest(algorithm, file)); - } - } - - final private static char[] hexArray = "0123456789ABCDEF".toCharArray(); - - /** - * From - * http://stackoverflow.com/questions/9655181/how-to-convert-a-byte-array-to - * -a-hex-string-in-java - */ - private static String encodeHexString(byte[] bytes) { - char[] hexChars = new char[bytes.length * 2]; - for (int j = 0; j < bytes.length; j++) { - int v = bytes[j] & 0xFF; - hexChars[j * 2] = hexArray[v >>> 4]; - hexChars[j * 2 + 1] = hexArray[v & 0x0F]; - } - return new String(hexChars); - } - -} diff --git a/org.argeo.util/src/org/argeo/util/security/Keyring.java b/org.argeo.util/src/org/argeo/util/security/Keyring.java deleted file mode 100644 index 10dbabd49..000000000 --- a/org.argeo.util/src/org/argeo/util/security/Keyring.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.util.security; - -import java.io.InputStream; - -/** - * Access to private (typically encrypted) data. The keyring is responsible for - * retrieving the necessary credentials. Experimental. This API may - * change. - */ -public interface Keyring { - public void changePassword(char[] oldPassword, char[] newPassword); - - /** - * Returns the confidential information as chars. Must ask for it if it is - * not stored. - */ - public char[] getAsChars(String path); - - /** - * Returns the confidential information as a stream. Must ask for it if it - * is not stored. - */ - public InputStream getAsStream(String path); - - public void set(String path, char[] arr); - - public void set(String path, InputStream in); -} diff --git a/org.argeo.util/src/org/argeo/util/security/KeyringLoginModule.java b/org.argeo.util/src/org/argeo/util/security/KeyringLoginModule.java deleted file mode 100644 index 11a834c25..000000000 --- a/org.argeo.util/src/org/argeo/util/security/KeyringLoginModule.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.util.security; - -import java.security.AccessController; -import java.util.Map; -import java.util.Set; - -import javax.crypto.SecretKey; -import javax.crypto.SecretKeyFactory; -import javax.crypto.spec.PBEKeySpec; -import javax.crypto.spec.SecretKeySpec; -import javax.security.auth.Subject; -import javax.security.auth.callback.Callback; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.callback.PasswordCallback; -import javax.security.auth.login.LoginException; -import javax.security.auth.spi.LoginModule; - -/** Adds a secret key to the private credentials */ -public class KeyringLoginModule implements LoginModule { - private Subject subject; - private CallbackHandler callbackHandler; - private SecretKey secretKey; - - public void initialize(Subject subject, CallbackHandler callbackHandler, - Map sharedState, Map options) { - this.subject = subject; - if (subject == null) { - subject = Subject.getSubject(AccessController.getContext()); - } - this.callbackHandler = callbackHandler; - } - - public boolean login() throws LoginException { - Set pbes = subject.getPrivateCredentials(SecretKey.class); - if (pbes.size() > 0) - return true; - PasswordCallback pc = new PasswordCallback("Master password", false); - PBEKeySpecCallback pbeCb = new PBEKeySpecCallback(); - Callback[] callbacks = { pc, pbeCb }; - try { - callbackHandler.handle(callbacks); - char[] password = pc.getPassword(); - - SecretKeyFactory keyFac = SecretKeyFactory.getInstance(pbeCb - .getSecretKeyFactory()); - PBEKeySpec keySpec; - if (pbeCb.getKeyLength() != null) - keySpec = new PBEKeySpec(password, pbeCb.getSalt(), - pbeCb.getIterationCount(), pbeCb.getKeyLength()); - else - keySpec = new PBEKeySpec(password, pbeCb.getSalt(), - pbeCb.getIterationCount()); - - String secKeyEncryption = pbeCb.getSecretKeyEncryption(); - if (secKeyEncryption != null) { - SecretKey tmp = keyFac.generateSecret(keySpec); - secretKey = new SecretKeySpec(tmp.getEncoded(), - secKeyEncryption); - } else { - secretKey = keyFac.generateSecret(keySpec); - } - } catch (Exception e) { - LoginException le = new LoginException("Cannot login keyring"); - le.initCause(e); - throw le; - } - return true; - } - - public boolean commit() throws LoginException { - if (secretKey != null) - subject.getPrivateCredentials().add(secretKey); - return true; - } - - public boolean abort() throws LoginException { - return true; - } - - public boolean logout() throws LoginException { - Set pbes = subject - .getPrivateCredentials(PasswordBasedEncryption.class); - pbes.clear(); - return true; - } - -} diff --git a/org.argeo.util/src/org/argeo/util/security/PBEKeySpecCallback.java b/org.argeo.util/src/org/argeo/util/security/PBEKeySpecCallback.java deleted file mode 100644 index 7b3a673bb..000000000 --- a/org.argeo.util/src/org/argeo/util/security/PBEKeySpecCallback.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.util.security; - -import javax.crypto.spec.PBEKeySpec; -import javax.security.auth.callback.Callback; -import javax.security.auth.callback.PasswordCallback; - -/** - * All information required to set up a {@link PBEKeySpec} bar the password - * itself (use a {@link PasswordCallback}) - */ -public class PBEKeySpecCallback implements Callback { - private String secretKeyFactory; - private byte[] salt; - private Integer iterationCount; - /** Can be null for some algorithms */ - private Integer keyLength; - /** Can be null, will trigger secret key encryption if not */ - private String secretKeyEncryption; - - private String encryptedPasswordHashCipher; - private byte[] encryptedPasswordHash; - - public void set(String secretKeyFactory, byte[] salt, - Integer iterationCount, Integer keyLength, - String secretKeyEncryption) { - this.secretKeyFactory = secretKeyFactory; - this.salt = salt; - this.iterationCount = iterationCount; - this.keyLength = keyLength; - this.secretKeyEncryption = secretKeyEncryption; -// this.encryptedPasswordHashCipher = encryptedPasswordHashCipher; -// this.encryptedPasswordHash = encryptedPasswordHash; - } - - public String getSecretKeyFactory() { - return secretKeyFactory; - } - - public byte[] getSalt() { - return salt; - } - - public Integer getIterationCount() { - return iterationCount; - } - - public Integer getKeyLength() { - return keyLength; - } - - public String getSecretKeyEncryption() { - return secretKeyEncryption; - } - - public String getEncryptedPasswordHashCipher() { - return encryptedPasswordHashCipher; - } - - public byte[] getEncryptedPasswordHash() { - return encryptedPasswordHash; - } - -} diff --git a/org.argeo.util/src/org/argeo/util/security/PasswordBasedEncryption.java b/org.argeo.util/src/org/argeo/util/security/PasswordBasedEncryption.java deleted file mode 100644 index fcc5f8319..000000000 --- a/org.argeo.util/src/org/argeo/util/security/PasswordBasedEncryption.java +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.util.security; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.security.GeneralSecurityException; -import java.security.InvalidKeyException; -import java.security.Key; - -import javax.crypto.Cipher; -import javax.crypto.CipherInputStream; -import javax.crypto.CipherOutputStream; -import javax.crypto.SecretKey; -import javax.crypto.SecretKeyFactory; -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.PBEKeySpec; -import javax.crypto.spec.SecretKeySpec; - -import org.argeo.util.internal.UtilsException; -import org.argeo.util.internal.StreamUtils; - -/** Simple password based encryption / decryption */ -public class PasswordBasedEncryption { - public final static Integer DEFAULT_ITERATION_COUNT = 1024; - /** Stronger with 256, but causes problem with Oracle JVM */ - public final static Integer DEFAULT_SECRETE_KEY_LENGTH = 256; - public final static Integer DEFAULT_SECRETE_KEY_LENGTH_RESTRICTED = 128; - public final static String DEFAULT_SECRETE_KEY_FACTORY = "PBKDF2WithHmacSHA1"; - public final static String DEFAULT_SECRETE_KEY_ENCRYPTION = "AES"; - public final static String DEFAULT_CIPHER_NAME = "AES/CBC/PKCS5Padding"; - public final static String DEFAULT_CHARSET = "UTF-8"; - - private Integer iterationCount = DEFAULT_ITERATION_COUNT; - private Integer secreteKeyLength = DEFAULT_SECRETE_KEY_LENGTH; - private String secreteKeyFactoryName = DEFAULT_SECRETE_KEY_FACTORY; - private String secreteKeyEncryption = DEFAULT_SECRETE_KEY_ENCRYPTION; - private String cipherName = DEFAULT_CIPHER_NAME; - - private static byte[] DEFAULT_SALT_8 = { (byte) 0xA9, (byte) 0x9B, - (byte) 0xC8, (byte) 0x32, (byte) 0x56, (byte) 0x35, (byte) 0xE3, - (byte) 0x03 }; - private static byte[] DEFAULT_IV_16 = { (byte) 0xA9, (byte) 0x9B, - (byte) 0xC8, (byte) 0x32, (byte) 0x56, (byte) 0x35, (byte) 0xE3, - (byte) 0x03, (byte) 0xA9, (byte) 0x9B, (byte) 0xC8, (byte) 0x32, - (byte) 0x56, (byte) 0x35, (byte) 0xE3, (byte) 0x03 }; - - private Key key; - private Cipher ecipher; - private Cipher dcipher; - - private String securityProviderName = null; - - /** - * This is up to the caller to clear the passed array. Neither copy of nor - * reference to the passed array is kept - */ - public PasswordBasedEncryption(char[] password) { - this(password, DEFAULT_SALT_8, DEFAULT_IV_16); - } - - /** - * This is up to the caller to clear the passed array. Neither copies of nor - * references to the passed arrays are kept - */ - public PasswordBasedEncryption(char[] password, byte[] passwordSalt, - byte[] initializationVector) { - try { - initKeyAndCiphers(password, passwordSalt, initializationVector); - } catch (InvalidKeyException e) { - Integer previousSecreteKeyLength = secreteKeyLength; - secreteKeyLength = DEFAULT_SECRETE_KEY_LENGTH_RESTRICTED; - System.err.println("'" + e.getMessage() + "', will use " - + secreteKeyLength + " secrete key length instead of " - + previousSecreteKeyLength); - try { - initKeyAndCiphers(password, passwordSalt, initializationVector); - } catch (Exception e1) { - throw new UtilsException( - "Cannot get secret key (with restricted length)", e1); - } - } catch (Exception e) { - throw new UtilsException("Cannot get secret key", e); - } - } - - protected void initKeyAndCiphers(char[] password, byte[] passwordSalt, - byte[] initializationVector) throws GeneralSecurityException { - byte[] salt = new byte[8]; - System.arraycopy(passwordSalt, 0, salt, 0, salt.length); - // for (int i = 0; i < password.length && i < salt.length; i++) - // salt[i] = (byte) password[i]; - byte[] iv = new byte[16]; - System.arraycopy(initializationVector, 0, iv, 0, iv.length); - - SecretKeyFactory keyFac = SecretKeyFactory - .getInstance(getSecretKeyFactoryName()); - PBEKeySpec keySpec = new PBEKeySpec(password, salt, - getIterationCount(), getKeyLength()); - String secKeyEncryption = getSecretKeyEncryption(); - if (secKeyEncryption != null) { - SecretKey tmp = keyFac.generateSecret(keySpec); - key = new SecretKeySpec(tmp.getEncoded(), getSecretKeyEncryption()); - } else { - key = keyFac.generateSecret(keySpec); - } - if (securityProviderName != null) - ecipher = Cipher.getInstance(getCipherName(), securityProviderName); - else - ecipher = Cipher.getInstance(getCipherName()); - ecipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv)); - dcipher = Cipher.getInstance(getCipherName()); - dcipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv)); - } - - public void encrypt(InputStream decryptedIn, OutputStream encryptedOut) - throws IOException { - try { - CipherOutputStream out = new CipherOutputStream(encryptedOut, - ecipher); - StreamUtils.copy(decryptedIn, out); - StreamUtils.closeQuietly(out); - } catch (IOException e) { - throw e; - } catch (Exception e) { - throw new UtilsException("Cannot encrypt", e); - } finally { - StreamUtils.closeQuietly(decryptedIn); - } - } - - public void decrypt(InputStream encryptedIn, OutputStream decryptedOut) - throws IOException { - try { - CipherInputStream decryptedIn = new CipherInputStream(encryptedIn, - dcipher); - StreamUtils.copy(decryptedIn, decryptedOut); - } catch (IOException e) { - throw e; - } catch (Exception e) { - throw new UtilsException("Cannot decrypt", e); - } finally { - StreamUtils.closeQuietly(encryptedIn); - } - } - - public byte[] encryptString(String str) { - ByteArrayOutputStream out = null; - ByteArrayInputStream in = null; - try { - out = new ByteArrayOutputStream(); - in = new ByteArrayInputStream(str.getBytes(DEFAULT_CHARSET)); - encrypt(in, out); - return out.toByteArray(); - } catch (Exception e) { - throw new UtilsException("Cannot encrypt", e); - } finally { - StreamUtils.closeQuietly(out); - } - } - - /** Closes the input stream */ - public String decryptAsString(InputStream in) { - ByteArrayOutputStream out = null; - try { - out = new ByteArrayOutputStream(); - decrypt(in, out); - return new String(out.toByteArray(), DEFAULT_CHARSET); - } catch (Exception e) { - throw new UtilsException("Cannot decrypt", e); - } finally { - StreamUtils.closeQuietly(out); - } - } - - protected Key getKey() { - return key; - } - - protected Cipher getEcipher() { - return ecipher; - } - - protected Cipher getDcipher() { - return dcipher; - } - - protected Integer getIterationCount() { - return iterationCount; - } - - protected Integer getKeyLength() { - return secreteKeyLength; - } - - protected String getSecretKeyFactoryName() { - return secreteKeyFactoryName; - } - - protected String getSecretKeyEncryption() { - return secreteKeyEncryption; - } - - protected String getCipherName() { - return cipherName; - } - - public void setIterationCount(Integer iterationCount) { - this.iterationCount = iterationCount; - } - - public void setSecreteKeyLength(Integer keyLength) { - this.secreteKeyLength = keyLength; - } - - public void setSecreteKeyFactoryName(String secreteKeyFactoryName) { - this.secreteKeyFactoryName = secreteKeyFactoryName; - } - - public void setSecreteKeyEncryption(String secreteKeyEncryption) { - this.secreteKeyEncryption = secreteKeyEncryption; - } - - public void setCipherName(String cipherName) { - this.cipherName = cipherName; - } - - public void setSecurityProviderName(String securityProviderName) { - this.securityProviderName = securityProviderName; - } -} diff --git a/org.argeo.util/src/org/argeo/util/security/SimplePrincipal.java b/org.argeo.util/src/org/argeo/util/security/SimplePrincipal.java deleted file mode 100644 index 29b8626e1..000000000 --- a/org.argeo.util/src/org/argeo/util/security/SimplePrincipal.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.util.security; - -import java.security.Principal; - -import org.argeo.util.internal.UtilsException; - -/** Canonical implementation of a {@link Principal} */ -public class SimplePrincipal implements Principal { - private final String name; - - public SimplePrincipal(String name) { - if (name == null) - throw new UtilsException("Principal name cannot be null"); - this.name = name; - } - - public String getName() { - return name; - } - - @Override - public int hashCode() { - return name.hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (obj == null) - return false; - if (obj instanceof Principal) - return name.equals((((Principal) obj).getName())); - return name.equals(obj.toString()); - } - - @Override - protected Object clone() throws CloneNotSupportedException { - return new SimplePrincipal(name); - } - - @Override - public String toString() { - return name; - } - -} diff --git a/org.argeo.util/src/org/argeo/util/tabular/ArrayTabularRow.java b/org.argeo.util/src/org/argeo/util/tabular/ArrayTabularRow.java deleted file mode 100644 index b1672e94c..000000000 --- a/org.argeo.util/src/org/argeo/util/tabular/ArrayTabularRow.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.util.tabular; - -import java.util.List; - -/** Minimal tabular row wrapping an {@link Object} array */ -public class ArrayTabularRow implements TabularRow { - private final Object[] arr; - - public ArrayTabularRow(List objs) { - this.arr = objs.toArray(); - } - - public Object get(Integer col) { - return arr[col]; - } - - public int size() { - return arr.length; - } - - public Object[] toArray() { - return arr; - } - -} diff --git a/org.argeo.util/src/org/argeo/util/tabular/CsvTabularWriter.java b/org.argeo.util/src/org/argeo/util/tabular/CsvTabularWriter.java deleted file mode 100644 index 8f5c52dca..000000000 --- a/org.argeo.util/src/org/argeo/util/tabular/CsvTabularWriter.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.util.tabular; - -import java.io.OutputStream; - -import org.argeo.util.CsvWriter; - -/** Write tabular content in a stream as CSV. Wraps a {@link CsvWriter}. */ -public class CsvTabularWriter implements TabularWriter { - private CsvWriter csvWriter; - - public CsvTabularWriter(OutputStream out) { - this.csvWriter = new CsvWriter(out); - } - - public void appendRow(Object[] row) { - csvWriter.writeLine(row); - } - - public void close() { - } - -} diff --git a/org.argeo.util/src/org/argeo/util/tabular/TabularColumn.java b/org.argeo.util/src/org/argeo/util/tabular/TabularColumn.java deleted file mode 100644 index a5ee32f27..000000000 --- a/org.argeo.util/src/org/argeo/util/tabular/TabularColumn.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.util.tabular; - -/** The column in a tabular content */ -public class TabularColumn { - private String name; - /** - * JCR types, see - * http://www.day.com/maven/javax.jcr/javadocs/jcr-2.0/index.html - * ?javax/jcr/PropertyType.html - */ - private Integer type; - - /** column with default type */ - public TabularColumn(String name) { - super(); - this.name = name; - } - - public TabularColumn(String name, Integer type) { - super(); - this.name = name; - this.type = type; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public Integer getType() { - return type; - } - - public void setType(Integer type) { - this.type = type; - } - -} diff --git a/org.argeo.util/src/org/argeo/util/tabular/TabularContent.java b/org.argeo.util/src/org/argeo/util/tabular/TabularContent.java deleted file mode 100644 index a2da86668..000000000 --- a/org.argeo.util/src/org/argeo/util/tabular/TabularContent.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.util.tabular; - -import java.util.List; - -/** - * Content organized as a table, possibly with headers. Only JCR types are - * supported even though there is not direct dependency on JCR. - */ -public interface TabularContent { - /** The headers of this table or null is none available. */ - public List getColumns(); - - public TabularRowIterator read(); -} diff --git a/org.argeo.util/src/org/argeo/util/tabular/TabularRow.java b/org.argeo.util/src/org/argeo/util/tabular/TabularRow.java deleted file mode 100644 index 05b8a40a9..000000000 --- a/org.argeo.util/src/org/argeo/util/tabular/TabularRow.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.util.tabular; - -/** A row of tabular data */ -public interface TabularRow { - /** The value at this column index */ - public Object get(Integer col); - - /** The raw objects (direct references) */ - public Object[] toArray(); - - /** Number of columns */ - public int size(); -} diff --git a/org.argeo.util/src/org/argeo/util/tabular/TabularRowIterator.java b/org.argeo.util/src/org/argeo/util/tabular/TabularRowIterator.java deleted file mode 100644 index 043463dd7..000000000 --- a/org.argeo.util/src/org/argeo/util/tabular/TabularRowIterator.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.util.tabular; - -import java.util.Iterator; - -/** Navigation of rows */ -public interface TabularRowIterator extends Iterator { - /** - * Current row number, has to be incremented by each call to next() ; starts at 0, will - * therefore be 1 for the first row returned. - */ - public Long getCurrentRowNumber(); -} diff --git a/org.argeo.util/src/org/argeo/util/tabular/TabularWriter.java b/org.argeo.util/src/org/argeo/util/tabular/TabularWriter.java deleted file mode 100644 index 20d6519fa..000000000 --- a/org.argeo.util/src/org/argeo/util/tabular/TabularWriter.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.util.tabular; - - -/** Write to a tabular content */ -public interface TabularWriter { - /** Append a new row of data */ - public void appendRow(Object[] row); - - /** Finish persisting data and release resources */ - public void close(); -}