<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}" />
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
\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
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;
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;
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 {
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
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;
// @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();
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;
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;
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 {
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 {
--- /dev/null
+/*
+ * 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()));
+ }
+}
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);
--- /dev/null
+/*
+ * 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;
+ }
+
+}
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;
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;
/**
* 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;
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);
}
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() {
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);
instance = null;
this.bc = null;
- this.permissionAdmin = null;
this.logReaderService = null;
// this.configurationAdmin = null;
}
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;
+++ /dev/null
-/*
- * 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
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;
--- /dev/null
+/*
+ * 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);
+ }
+
+ }
+}
--- /dev/null
+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);
+ }
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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() {
+ }
+
+}
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 {
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 {
org.eclipse.swt,\
org.eclipse.jface.window,\
org.eclipse.core.commands.common,\
- org.argeo,\
*
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();
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;
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;
import java.io.InputStreamReader;
import java.io.Reader;
-import javax.jcr.Node;
import javax.jcr.Session;
import org.apache.commons.io.IOUtils;
+ " 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();
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.
*/
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 {
* 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;
--- /dev/null
+/*
+ * 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;
+ }
+
+}
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 {
return null;
}
+ public String getLocale() {
+ return locale;
+ }
+
@Override
public String getID() {
return enumClass.getName();
--- /dev/null
+/*
+ * 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 {
+
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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;
+ }
+
+}
--- /dev/null
+/*
+ * 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;
+ }
+
+}
--- /dev/null
+/*
+ * 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;
+ }
+
+}
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+/*
+ * 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();
+}
*/
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;
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 {
+++ /dev/null
-/*
- * 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()));
- }
-}
+++ /dev/null
-/*
- * 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);
- }
-
-}
+++ /dev/null
-/*
- * 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);
-
-}
+++ /dev/null
-/*
- * 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;
- }
-
-}
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
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.
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;
--- /dev/null
+/*
+ * 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);
+ }
+
+}
--- /dev/null
+/*
+ * 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) {
+ //
+ }
+ }
+}
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);
+++ /dev/null
-/*
- * 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));
- }
-
-}
--- /dev/null
+/*
+ * 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);
+ }
+
+}
+++ /dev/null
-/*
- * 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) {
- //
- }
- }
-}
+++ /dev/null
-/*
- * 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);
- }
-
-}
+++ /dev/null
-/*
- * 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);
- }
-
- }
-}
+++ /dev/null
-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);
- }
-}
+++ /dev/null
-/*
- * 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 {
-
-}
+++ /dev/null
-/*
- * 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);
- }
-
-}
+++ /dev/null
-/*
- * 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);
-}
+++ /dev/null
-/*
- * 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;
- }
-
-}
+++ /dev/null
-/*
- * 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;
- }
-
-}
+++ /dev/null
-/*
- * 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;
- }
-}
+++ /dev/null
-/*
- * 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;
- }
-
-}
+++ /dev/null
-/*
- * 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;
- }
-
-}
+++ /dev/null
-/*
- * 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() {
- }
-
-}
+++ /dev/null
-/*
- * 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;
- }
-
-}
+++ /dev/null
-/*
- * 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();
-}
+++ /dev/null
-/*
- * 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();
-}
+++ /dev/null
-/*
- * 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();
-}
+++ /dev/null
-/*
- * 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();
-}