Remove APIs from utils
authorBruno Sinou <bsinou@argeo.org>
Thu, 15 Sep 2016 14:56:20 +0000 (14:56 +0000)
committerBruno Sinou <bsinou@argeo.org>
Thu, 15 Sep 2016 14:56:20 +0000 (14:56 +0000)
git-svn-id: https://svn.argeo.org/commons/trunk@9165 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc

75 files changed:
org.argeo.cms.ui.workbench/META-INF/spring/keyring.xml
org.argeo.cms.ui.workbench/META-INF/spring/osgi.xml
org.argeo.cms.ui.workbench/src/org/argeo/eclipse/ui/workbench/commands/AddRemoteRepository.java
org.argeo.cms.ui.workbench/src/org/argeo/eclipse/ui/workbench/internal/jcr/NodeContentProvider.java
org.argeo.cms.ui.workbench/src/org/argeo/eclipse/ui/workbench/internal/jcr/model/RemoteRepositoryElem.java
org.argeo.cms.ui.workbench/src/org/argeo/eclipse/ui/workbench/internal/jcr/model/RepositoriesElem.java
org.argeo.cms.ui.workbench/src/org/argeo/eclipse/ui/workbench/jcr/JcrBrowserView.java
org.argeo.cms.ui.workbench/src/org/argeo/security/ui/admin/internal/parts/UserBatchUpdateWizard.java
org.argeo.cms.ui/src/org/argeo/cms/maintenance/AbstractOsgiComposite.java
org.argeo.cms.ui/src/org/argeo/cms/ui/internal/Activator.java
org.argeo.cms.ui/src/org/argeo/cms/util/CmsLink.java
org.argeo.cms.ui/src/org/argeo/cms/widgets/auth/CmsLoginShell.java
org.argeo.cms/ext/test/org/argeo/cms/security/PasswordBasedEncryptionTest.java [new file with mode: 0644]
org.argeo.cms/ext/test/org/argeo/cms/tabular/JcrTabularTest.java
org.argeo.cms/src/org/argeo/cms/auth/KeyringLoginModule.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/internal/kernel/Activator.java
org.argeo.cms/src/org/argeo/cms/internal/kernel/DeployConfig.java
org.argeo.cms/src/org/argeo/cms/internal/kernel/JcrKeyring.java [deleted file]
org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelUtils.java
org.argeo.cms/src/org/argeo/cms/security/AbstractKeyring.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/security/ChecksumFactory.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/security/JcrKeyring.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/security/PasswordBasedEncryption.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/tabular/CsvTabularWriter.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/tabular/JcrTabularRowIterator.java
org.argeo.cms/src/org/argeo/cms/tabular/JcrTabularWriter.java
org.argeo.eclipse.ui/bnd.bnd
org.argeo.enterprise/ext/test/org/argeo/osgi/useradmin/LdifParserTest.java
org.argeo.enterprise/ext/test/org/argeo/osgi/useradmin/LdifUserAdminTest.java
org.argeo.jcr/src/org/argeo/jackrabbit/JackrabbitDataModelMigration.java
org.argeo.jcr/src/org/argeo/jcr/JcrMonitor.java
org.argeo.jcr/src/org/argeo/jcr/JcrUtils.java
org.argeo.jcr/src/org/argeo/jcr/SimplePrincipal.java [new file with mode: 0644]
org.argeo.jcr/src/org/argeo/jcr/security/JcrAuthorizations.java
org.argeo.node.api/src/org/argeo/node/EnumOCD.java
org.argeo.node.api/src/org/argeo/node/security/CryptoKeyring.java [new file with mode: 0644]
org.argeo.node.api/src/org/argeo/node/security/Keyring.java [new file with mode: 0644]
org.argeo.node.api/src/org/argeo/node/security/PBEKeySpecCallback.java [new file with mode: 0644]
org.argeo.node.api/src/org/argeo/node/tabular/ArrayTabularRow.java [new file with mode: 0644]
org.argeo.node.api/src/org/argeo/node/tabular/TabularColumn.java [new file with mode: 0644]
org.argeo.node.api/src/org/argeo/node/tabular/TabularContent.java [new file with mode: 0644]
org.argeo.node.api/src/org/argeo/node/tabular/TabularRow.java [new file with mode: 0644]
org.argeo.node.api/src/org/argeo/node/tabular/TabularRowIterator.java [new file with mode: 0644]
org.argeo.node.api/src/org/argeo/node/tabular/TabularWriter.java [new file with mode: 0644]
org.argeo.osgi.boot/ext/test/org/argeo/osgi/boot/OsgiBootRuntimeTest.java
org.argeo.util/ext/test/org/argeo/util/security/PasswordBasedEncryptionTest.java [deleted file]
org.argeo.util/src/org/argeo/ArgeoException.java [deleted file]
org.argeo.util/src/org/argeo/ArgeoMonitor.java [deleted file]
org.argeo.util/src/org/argeo/OperatingSystem.java [deleted file]
org.argeo.util/src/org/argeo/util/CsvParser.java
org.argeo.util/src/org/argeo/util/CsvParserWithLinesAsMap.java
org.argeo.util/src/org/argeo/util/CsvWriter.java
org.argeo.util/src/org/argeo/util/DigestUtils.java [new file with mode: 0644]
org.argeo.util/src/org/argeo/util/StreamUtils.java [new file with mode: 0644]
org.argeo.util/src/org/argeo/util/Throughput.java
org.argeo.util/src/org/argeo/util/ThroughputEditor.java [deleted file]
org.argeo.util/src/org/argeo/util/UtilsException.java [new file with mode: 0644]
org.argeo.util/src/org/argeo/util/internal/StreamUtils.java [deleted file]
org.argeo.util/src/org/argeo/util/internal/UtilsException.java [deleted file]
org.argeo.util/src/org/argeo/util/security/AbstractKeyring.java [deleted file]
org.argeo.util/src/org/argeo/util/security/ChecksumFactory.java [deleted file]
org.argeo.util/src/org/argeo/util/security/CryptoKeyring.java [deleted file]
org.argeo.util/src/org/argeo/util/security/DigestUtils.java [deleted file]
org.argeo.util/src/org/argeo/util/security/Keyring.java [deleted file]
org.argeo.util/src/org/argeo/util/security/KeyringLoginModule.java [deleted file]
org.argeo.util/src/org/argeo/util/security/PBEKeySpecCallback.java [deleted file]
org.argeo.util/src/org/argeo/util/security/PasswordBasedEncryption.java [deleted file]
org.argeo.util/src/org/argeo/util/security/SimplePrincipal.java [deleted file]
org.argeo.util/src/org/argeo/util/tabular/ArrayTabularRow.java [deleted file]
org.argeo.util/src/org/argeo/util/tabular/CsvTabularWriter.java [deleted file]
org.argeo.util/src/org/argeo/util/tabular/TabularColumn.java [deleted file]
org.argeo.util/src/org/argeo/util/tabular/TabularContent.java [deleted file]
org.argeo.util/src/org/argeo/util/tabular/TabularRow.java [deleted file]
org.argeo.util/src/org/argeo/util/tabular/TabularRowIterator.java [deleted file]
org.argeo.util/src/org/argeo/util/tabular/TabularWriter.java [deleted file]

index 74c4ad6cf459da86cd4ffcaa62346a369bcf9d37..59c7c544ba472e004d9a34a547d2064c337f3e9b 100644 (file)
@@ -18,7 +18,7 @@
                <property name="repository" ref="nodeRepository" />
        </bean>
 
-       <bean id="keyring" class="org.argeo.jcr.security.JcrKeyring">
+       <bean id="keyring" class="org.argeo.cms.security.JcrKeyring">
                <property name="session" ref="nodeSession" />
                <property name="defaultCallbackHandler" ref="defaultCallbackHandler" />
                <property name="secreteKeyLength" value="${argeo.keyring.secreteKeyLength}" />
index df3322635a261950797dcb668a442c4fa0cd8932..dc6e2707f8d3f080e9c845ef6aedef465e07a0b5 100644 (file)
@@ -15,7 +15,7 @@
                        unbind-method="unregister" />\r
        </list>\r
        <reference id="repositoryFactory" interface="javax.jcr.RepositoryFactory" />\r
-<!--   <reference id="keyring" interface="org.argeo.util.security.CryptoKeyring" /> -->\r
+<!--   <reference id="keyring" interface="org.argeo.node.security.CryptoKeyring" /> -->\r
 \r
        <!-- <reference id="nodeRepository" interface="javax.jcr.Repository" -->\r
        <!-- filter="(argeo.jcr.repository.alias=node)" /> -->\r
@@ -37,5 +37,5 @@
 \r
 \r
        <!-- SERVICES -->\r
-       <service interface="org.argeo.util.security.CryptoKeyring" ref="keyring" />\r
+       <service interface="org.argeo.node.security.CryptoKeyring" ref="keyring" />\r
 </beans:beans>
\ No newline at end of file
index cf6a5b0f006472946c2dd15f3eaa31ff1b4617d2..06b6fe4a836579c124eb43e660f0f78f6f656065 100644 (file)
@@ -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;
index 243d932653a4288264bd4756491183280995d9f6..be623871e0269f99665e1c7b5462c99506aa48f8 100644 (file)
@@ -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;
 
index 90acc034e9dc93d1de17f9ce213088c1a47ef54b..edaf2396ff1ae702728996ba2497f382a4499d60 100644 (file)
@@ -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 {
index 864048a76127855a5510ecb6889fbbdf3ac28c5b..294757acd257af9e7d7ad61f65c8a050a008a5b2 100644 (file)
@@ -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
index 92deb71a110cd56714c27bf2c28bdf5107a5e508..c30082765ad26e02a12a65297de16c52d7cf67be 100644 (file)
@@ -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;
index b3bff5943d46ea018fa4559f0f6c8e739f4522b7..b532ddef52948d53e7211a13dbaa5ca22a5a7af7 100644 (file)
@@ -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();
index 2494d90c3c033a47bfffefba18c4b60077d13f78..8c893f2f397d411048ed6ecadcf0ead13f6ec248 100644 (file)
@@ -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;
index 052762ec0e76b2f1a6d9cc972270d8d81b948ced..410498725a2a78ac304abba03412543b752eb9ff 100644 (file)
@@ -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;
index 3778515dcc70c56a338ef271db0a69df304b8e5a..865824c1a90b09890db356db0feaa0d9a78fd48f 100644 (file)
@@ -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 {
index 6afaa767c7b3506b9a4d63e80d4d78ee36739796..c31ad96579d08853f1c95e6fd6cd6569c56ae5ef 100644 (file)
@@ -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 (file)
index 0000000..49319f1
--- /dev/null
@@ -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()));
+       }
+}
index 0d8a8ce5f9530b0adef00cb4f72329a03673df1c..b52ffe3c16b0365c8622a27881a065d26c3a8f71 100644 (file)
@@ -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 (file)
index 0000000..2c49582
--- /dev/null
@@ -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<String, ?> sharedState, Map<String, ?> options) {
+               this.subject = subject;
+               if (subject == null) {
+                       subject = Subject.getSubject(AccessController.getContext());
+               }
+               this.callbackHandler = callbackHandler;
+       }
+
+       public boolean login() throws LoginException {
+               Set<SecretKey> 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<PasswordBasedEncryption> pbes = subject
+                               .getPrivateCredentials(PasswordBasedEncryption.class);
+               pbes.clear();
+               return true;
+       }
+
+}
index ecd36476facdd5cbc7e187cb87dd0c01d84b840e..99d5dbb3e73294bb14c824f75a92dc2c76ab56f7 100644 (file)
@@ -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<String, Object> props = nodeConf.getProperties();
-               // if (props == null) {
-               // if (log.isDebugEnabled())
-               // log.debug("Clean node state");
-               // Dictionary<String, Object> 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<String, Object> regProps = LangUtils.init(Constants.SERVICE_PID, NodeConstants.NODE_STATE_PID);
+               Dictionary<String, Object> 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;
        }
index 042d1f6349d3ad9ae6bb594d178c29397e322354..9908e97726f04882f166f37e87f1dc5f53848946 100644 (file)
@@ -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 (file)
index 396093f..0000000
+++ /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<Node> notYetSavedKeyring = new ThreadLocal<Node>() {
-
-               @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
index 37c25d007830450185c4c4c94454d1fe23498a59..9c480647dd76830f0764941525bac68de3df7fad 100644 (file)
@@ -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 (file)
index 0000000..091de9e
--- /dev/null
@@ -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<SecretKey> 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 (file)
index 0000000..c5b4e9e
--- /dev/null
@@ -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<Path>() {
+
+                                       @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 (file)
index 0000000..1ccb817
--- /dev/null
@@ -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<Node> notYetSavedKeyring = new ThreadLocal<Node>() {
+
+               @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 (file)
index 0000000..a74cb59
--- /dev/null
@@ -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 (file)
index 0000000..d22f44e
--- /dev/null
@@ -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() {
+       }
+
+}
index 931a2b565a1e2530321c00525ffdd85117465b71..5d380cfa5f9ce78effb18c8e8e568582a24f11de 100644 (file)
@@ -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 {
index 7249fd509fa4bf65593e5aa6c472c18053b659a3..ac57d2ab7156d4c8acb6ebbe9d43141b5b541e14 100644 (file)
@@ -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 {
index 65e408ddf71c592d371253804c22cb290e144bed..b836fc0e90659066d63787e393d69a12d8b769fa 100644 (file)
@@ -2,5 +2,4 @@ Import-Package: javax.jcr.nodetype,\
                                org.eclipse.swt,\
                                org.eclipse.jface.window,\
                                org.eclipse.core.commands.common,\
-                               org.argeo,\
                                *
index fecf5dd5a199a7e5cfbe3012b8481e1729ab26fa..e7c94609f1c724ee14ea20caf2e82c29989594a6 100644 (file)
@@ -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();
index a8a7d226a1aa124c135d038882782af8e93bf291..06f1e6d2e19f5e9b1a5364b6d5edd5dad12f2e7f 100644 (file)
@@ -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;
index e53ed557774bfeae9e70b06c546caa3eb1c3040e..8fedcf5217c886acb09ddbb3c70fc86d92e48ed8 100644 (file)
@@ -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();
index f04be9aa59cc5ab6d62c084564e070efdbaab3ab..71cf961e0b153a3df1fb8d4bf57261031cfd39bc 100644 (file)
@@ -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.
         */
index 313554041669f1ce89e285b2d4dbb47599a74956..8ccdfc73d2285bb69f8f994dbb8f232a83b95fc1 100644 (file)
@@ -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 (file)
index 0000000..804ce07
--- /dev/null
@@ -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;
+       }
+
+}
index 9ad249252e768f9e7f12f1ee8a0ebe7bf6f8d4d3..3e8e3a2ff6216f1968ae4cd862cae686bcaf6556 100644 (file)
@@ -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 {
index daa2f540d56127b174198ac13b29aa9d20cf96b4..c5a191ee9b0a93b97e1687779a6154370fd351fe 100644 (file)
@@ -23,6 +23,10 @@ class EnumOCD<T extends Enum<T>> 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 (file)
index 0000000..72f9ff7
--- /dev/null
@@ -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 (file)
index 0000000..467d9a8
--- /dev/null
@@ -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. <b>Experimental. This API may
+ * change.</b>
+ */
+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 (file)
index 0000000..f03ba9d
--- /dev/null
@@ -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 (file)
index 0000000..97bf025
--- /dev/null
@@ -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 (file)
index 0000000..5cd11d1
--- /dev/null
@@ -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 (file)
index 0000000..a5aa9f6
--- /dev/null
@@ -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 <code>null</code> is none available. */
+       public List<TabularColumn> 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 (file)
index 0000000..f652df9
--- /dev/null
@@ -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 (file)
index 0000000..98a04a6
--- /dev/null
@@ -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<TabularRow> {
+       /**
+        * 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 (file)
index 0000000..b7febee
--- /dev/null
@@ -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();
+}
index a165c4ee5ea42866c63a288a4b80a2dc8d0e7dbf..b396c451a200e604e8c4dadc8df494c53e7399a6 100644 (file)
  */
 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 (file)
index 0895c6b..0000000
+++ /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 (file)
index 4fa296a..0000000
+++ /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 (file)
index 307581e..0000000
+++ /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 <code>UNKNOWN</code> 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 <code>true</code> if cancellation has been requested, and
-        *         <code>false</code> otherwise
-        * @see #setCanceled(boolean)
-        */
-       public boolean isCanceled();
-
-       /**
-        * Sets the cancel state to the given value.
-        * 
-        * @param value
-        *            <code>true</code> indicates that cancelation has been
-        *            requested (but not necessarily acknowledged);
-        *            <code>false</code> 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 (file)
index 697c86c..0000000
+++ /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;
-       }
-
-}
index 569f08c731092acd8f76790a42af2b54d620e150..d133afdbc41f1d6d35fed0d1019aae5e9a31c289 100644 (file)
@@ -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
index fe1750a233f54fd1ddb6c5040de2f9faaccf8816..c84d994c27032da8bbefd540363c8c2f51169be4 100644 (file)
@@ -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.
index 1ebe1022dd48aff118a97d983a0d7e02d251b561..4b9fea3faa093ca99e4e47d42c7c3715c359afaa 100644 (file)
@@ -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 (file)
index 0000000..52cbc5d
--- /dev/null
@@ -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: <file> [<algorithm>]" + " (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 (file)
index 0000000..1cfa5b2
--- /dev/null
@@ -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) {
+                               //
+                       }
+       }
+}
index fb928002e782aece5c5d33c4cee81bd1e9f31b0c..e5bc96101582c6a739a395b501d1a0a186ebaf6b 100644 (file)
@@ -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 (file)
index 4ebf26b..0000000
+++ /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 (file)
index 0000000..b93233a
--- /dev/null
@@ -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 (file)
index cf6fc0c..0000000
+++ /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 (file)
index d93851c..0000000
+++ /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 (file)
index 68ae1a2..0000000
+++ /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<SecretKey> 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 (file)
index b57db2c..0000000
+++ /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<Path>() {
-
-                                       @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 (file)
index 53ce862..0000000
+++ /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 (file)
index 6d46c28..0000000
+++ /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: <file> [<algorithm>]" + " (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 (file)
index 10dbabd..0000000
+++ /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. <b>Experimental. This API may
- * change.</b>
- */
-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 (file)
index 11a834c..0000000
+++ /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<String, ?> sharedState, Map<String, ?> options) {
-               this.subject = subject;
-               if (subject == null) {
-                       subject = Subject.getSubject(AccessController.getContext());
-               }
-               this.callbackHandler = callbackHandler;
-       }
-
-       public boolean login() throws LoginException {
-               Set<SecretKey> 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<PasswordBasedEncryption> 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 (file)
index 7b3a673..0000000
+++ /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 (file)
index fcc5f83..0000000
+++ /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 (file)
index 29b8626..0000000
+++ /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 (file)
index b1672e9..0000000
+++ /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 (file)
index 8f5c52d..0000000
+++ /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 (file)
index a5ee32f..0000000
+++ /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 (file)
index a2da866..0000000
+++ /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 <code>null</code> is none available. */
-       public List<TabularColumn> 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 (file)
index 05b8a40..0000000
+++ /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 (file)
index 043463d..0000000
+++ /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<TabularRow> {
-       /**
-        * 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 (file)
index 20d6519..0000000
+++ /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();
-}