From 9884b3225a86b831917b10376925eebcbf99e513 Mon Sep 17 00:00:00 2001 From: Mathieu Baudier Date: Thu, 11 Oct 2012 18:38:04 +0000 Subject: [PATCH] Refactor cryptography and keyring git-svn-id: https://svn.argeo.org/commons/trunk@5599 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- .../util/{crypto => security}/Keyring.java | 13 +- .../META-INF/jaas_default.txt | 2 +- .../META-INF/jaas_default.txt | 2 +- .../runtime/org.argeo.security.core/pom.xml | 8 +- .../security}/crypto/AbstractKeyring.java | 42 +++++- .../security}/crypto/KeyringLoginModule.java | 2 +- .../security}/crypto/PBEKeySpecCallback.java | 2 +- .../crypto/PasswordBasedEncryption.java | 20 ++- .../org/argeo/security/jcr}/JcrKeyring.java | 107 ++++++--------- .../security/crypto/ListBCCapabilities.java | 43 ++++++ .../crypto/PasswordBasedEncryptionTest.java | 3 +- .../META-INF/spring/commands.xml | 6 +- .../META-INF/spring/jcr.xml | 2 +- .../META-INF/spring/views.xml | 3 +- .../plugins/org.argeo.jcr.ui.explorer/pom.xml | 9 +- .../explorer/browser/NodeContentProvider.java | 21 +-- .../commands/AddRemoteRepository.java | 25 ++-- .../explorer/model/RemoteRepositoryNode.java | 29 ++-- .../ui/explorer/model/RepositoriesNode.java | 25 ++-- .../ui/explorer/views/GenericJcrBrowser.java | 64 ++++----- .../src/main/java/org/argeo/jcr/JcrUtils.java | 14 ++ .../argeo/jcr/security/SecurityJcrUtils.java | 125 ------------------ 22 files changed, 280 insertions(+), 287 deletions(-) rename base/runtime/org.argeo.util/src/main/java/org/argeo/util/{crypto => security}/Keyring.java (75%) rename {base/runtime/org.argeo.util/src/main/java/org/argeo/util => security/runtime/org.argeo.security.core/src/main/java/org/argeo/security}/crypto/AbstractKeyring.java (87%) rename {base/runtime/org.argeo.util/src/main/java/org/argeo/util => security/runtime/org.argeo.security.core/src/main/java/org/argeo/security}/crypto/KeyringLoginModule.java (98%) rename {base/runtime/org.argeo.util/src/main/java/org/argeo/util => security/runtime/org.argeo.security.core/src/main/java/org/argeo/security}/crypto/PBEKeySpecCallback.java (98%) rename {base/runtime/org.argeo.util/src/main/java/org/argeo/util => security/runtime/org.argeo.security.core/src/main/java/org/argeo/security}/crypto/PasswordBasedEncryption.java (91%) rename {server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/security => security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/jcr}/JcrKeyring.java (75%) create mode 100644 security/runtime/org.argeo.security.core/src/test/java/org/argeo/security/crypto/ListBCCapabilities.java rename {base/runtime/org.argeo.util/src/test/java/org/argeo/util => security/runtime/org.argeo.security.core/src/test/java/org/argeo/security}/crypto/PasswordBasedEncryptionTest.java (98%) delete mode 100644 server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/security/SecurityJcrUtils.java diff --git a/base/runtime/org.argeo.util/src/main/java/org/argeo/util/crypto/Keyring.java b/base/runtime/org.argeo.util/src/main/java/org/argeo/util/security/Keyring.java similarity index 75% rename from base/runtime/org.argeo.util/src/main/java/org/argeo/util/crypto/Keyring.java rename to base/runtime/org.argeo.util/src/main/java/org/argeo/util/security/Keyring.java index eb876df54..552d2ef23 100644 --- a/base/runtime/org.argeo.util/src/main/java/org/argeo/util/crypto/Keyring.java +++ b/base/runtime/org.argeo.util/src/main/java/org/argeo/util/security/Keyring.java @@ -13,19 +13,28 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.argeo.util.crypto; +package org.argeo.util.security; import java.io.InputStream; /** * Access to private (typically encrypted) data. The keyring is responsible for - * retrieving the necessary credentials. + * retrieving the necessary credentials. Experimental. This API may + * change. */ public interface Keyring { public void changePassword(char[] oldPassword, char[] newPassword); + /** + * Returns the confidential information as chars. Must ask for it if it is + * not stored. + */ public char[] getAsChars(String path); + /** + * Returns the confidential information as a stream. Must ask for it if it + * is not stored. + */ public InputStream getAsStream(String path); public void set(String path, char[] arr); diff --git a/security/plugins/org.argeo.security.ui.rap/META-INF/jaas_default.txt b/security/plugins/org.argeo.security.ui.rap/META-INF/jaas_default.txt index 3829f93bb..c74797b93 100644 --- a/security/plugins/org.argeo.security.ui.rap/META-INF/jaas_default.txt +++ b/security/plugins/org.argeo.security.ui.rap/META-INF/jaas_default.txt @@ -19,5 +19,5 @@ SPRING_SECURITY_CONTEXT { }; KEYRING { - org.argeo.util.crypto.KeyringLoginModule required; + org.argeo.security.crypto.KeyringLoginModule required; }; diff --git a/security/plugins/org.argeo.security.ui.rcp/META-INF/jaas_default.txt b/security/plugins/org.argeo.security.ui.rcp/META-INF/jaas_default.txt index 124d7ad9f..16d476daf 100644 --- a/security/plugins/org.argeo.security.ui.rcp/META-INF/jaas_default.txt +++ b/security/plugins/org.argeo.security.ui.rcp/META-INF/jaas_default.txt @@ -23,5 +23,5 @@ REMOTE { }; KEYRING { - org.argeo.util.crypto.KeyringLoginModule required; + org.argeo.security.crypto.KeyringLoginModule required; }; diff --git a/security/runtime/org.argeo.security.core/pom.xml b/security/runtime/org.argeo.security.core/pom.xml index abb559ad7..527d052fd 100644 --- a/security/runtime/org.argeo.security.core/pom.xml +++ b/security/runtime/org.argeo.security.core/pom.xml @@ -68,10 +68,10 @@ - - - - + + org.argeo.tp + bcprov + org.argeo.tp org.apache.commons.codec diff --git a/base/runtime/org.argeo.util/src/main/java/org/argeo/util/crypto/AbstractKeyring.java b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/crypto/AbstractKeyring.java similarity index 87% rename from base/runtime/org.argeo.util/src/main/java/org/argeo/util/crypto/AbstractKeyring.java rename to security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/crypto/AbstractKeyring.java index e42451325..b69fff95a 100644 --- a/base/runtime/org.argeo.util/src/main/java/org/argeo/util/crypto/AbstractKeyring.java +++ b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/crypto/AbstractKeyring.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.argeo.util.crypto; +package org.argeo.security.crypto; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -26,6 +26,8 @@ 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; @@ -41,9 +43,15 @@ import javax.security.auth.login.LoginException; import org.argeo.ArgeoException; import org.argeo.StreamUtils; +import org.argeo.util.security.Keyring; +import org.bouncycastle.jce.provider.BouncyCastleProvider; /** username / password based keyring. TODO internationalize */ public abstract class AbstractKeyring implements Keyring { + static { + Security.addProvider(new BouncyCastleProvider()); + } + public final static String DEFAULT_KEYRING_LOGIN_CONTEXT = "KEYRING"; private String loginContextName = DEFAULT_KEYRING_LOGIN_CONTEXT; @@ -51,6 +59,12 @@ public abstract class AbstractKeyring implements Keyring { 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 @@ -144,6 +158,10 @@ public abstract class AbstractKeyring implements Keyring { } } + protected Provider getSecurityProvider() { + return Security.getProvider(securityProviderName); + } + public void setLoginContextName(String loginContextName) { this.loginContextName = loginContextName; } @@ -156,6 +174,11 @@ public abstract class AbstractKeyring implements Keyring { 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; @@ -182,6 +205,23 @@ public abstract class AbstractKeyring implements Keyring { } + /** + * 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 ArgeoException("Cannot ask for a password", e); + } + + } + class KeyringCallbackHandler implements CallbackHandler { public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { diff --git a/base/runtime/org.argeo.util/src/main/java/org/argeo/util/crypto/KeyringLoginModule.java b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/crypto/KeyringLoginModule.java similarity index 98% rename from base/runtime/org.argeo.util/src/main/java/org/argeo/util/crypto/KeyringLoginModule.java rename to security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/crypto/KeyringLoginModule.java index e8b6928f8..24e0f1e9b 100644 --- a/base/runtime/org.argeo.util/src/main/java/org/argeo/util/crypto/KeyringLoginModule.java +++ b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/crypto/KeyringLoginModule.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.argeo.util.crypto; +package org.argeo.security.crypto; import java.security.AccessController; import java.util.Map; diff --git a/base/runtime/org.argeo.util/src/main/java/org/argeo/util/crypto/PBEKeySpecCallback.java b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/crypto/PBEKeySpecCallback.java similarity index 98% rename from base/runtime/org.argeo.util/src/main/java/org/argeo/util/crypto/PBEKeySpecCallback.java rename to security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/crypto/PBEKeySpecCallback.java index 676b9706f..111212387 100644 --- a/base/runtime/org.argeo.util/src/main/java/org/argeo/util/crypto/PBEKeySpecCallback.java +++ b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/crypto/PBEKeySpecCallback.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.argeo.util.crypto; +package org.argeo.security.crypto; import javax.crypto.spec.PBEKeySpec; import javax.security.auth.callback.Callback; diff --git a/base/runtime/org.argeo.util/src/main/java/org/argeo/util/crypto/PasswordBasedEncryption.java b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/crypto/PasswordBasedEncryption.java similarity index 91% rename from base/runtime/org.argeo.util/src/main/java/org/argeo/util/crypto/PasswordBasedEncryption.java rename to security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/crypto/PasswordBasedEncryption.java index 62cc2400b..63cdc6c0c 100644 --- a/base/runtime/org.argeo.util/src/main/java/org/argeo/util/crypto/PasswordBasedEncryption.java +++ b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/crypto/PasswordBasedEncryption.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.argeo.util.crypto; +package org.argeo.security.crypto; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -21,6 +21,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.security.Key; +import java.security.Security; import javax.crypto.Cipher; import javax.crypto.CipherInputStream; @@ -33,9 +34,14 @@ import javax.crypto.spec.SecretKeySpec; import org.argeo.ArgeoException; import org.argeo.StreamUtils; +import org.bouncycastle.jce.provider.BouncyCastleProvider; /** Simple password based encryption / decryption */ public class PasswordBasedEncryption { + static { + Security.addProvider(new BouncyCastleProvider()); + } + public final static Integer DEFAULT_ITERATION_COUNT = 1024; public final static Integer DEFAULT_KEY_LENGTH = 256; public final static String DEFAULT_SECRETE_KEY_FACTORY = "PBKDF2WithHmacSHA1"; @@ -55,6 +61,12 @@ public class PasswordBasedEncryption { private final Cipher ecipher; private final Cipher dcipher; + /** + * Default provider is bouncy castle, in order to have consistent behaviour + * across implementations + */ + private String securityProviderName = "BC"; + /** * This is up to the caller to clear the passed array. Neither copy of nor * reference to the passed array is kept @@ -91,7 +103,7 @@ public class PasswordBasedEncryption { } else { key = keyFac.generateSecret(keySpec); } - ecipher = Cipher.getInstance(getCipherName()); + ecipher = Cipher.getInstance(getCipherName(), securityProviderName); ecipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv)); // AlgorithmParameters params = ecipher.getParameters(); // byte[] iv = @@ -194,4 +206,8 @@ public class PasswordBasedEncryption { protected String getCipherName() { return DEFAULT_CIPHER; } + + public void setSecurityProviderName(String securityProviderName) { + this.securityProviderName = securityProviderName; + } } diff --git a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/security/JcrKeyring.java b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/jcr/JcrKeyring.java similarity index 75% rename from server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/security/JcrKeyring.java rename to security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/jcr/JcrKeyring.java index a35bbd272..04974bdd7 100644 --- a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/security/JcrKeyring.java +++ b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/jcr/JcrKeyring.java @@ -13,10 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.argeo.jcr.security; +package org.argeo.security.jcr; import java.io.ByteArrayInputStream; +import java.io.CharArrayReader; import java.io.InputStream; +import java.io.Reader; import java.security.SecureRandom; import javax.crypto.Cipher; @@ -35,8 +37,8 @@ import org.argeo.jcr.ArgeoNames; import org.argeo.jcr.ArgeoTypes; import org.argeo.jcr.JcrUtils; import org.argeo.jcr.UserJcrUtils; -import org.argeo.util.crypto.AbstractKeyring; -import org.argeo.util.crypto.PBEKeySpecCallback; +import org.argeo.security.crypto.AbstractKeyring; +import org.argeo.security.crypto.PBEKeySpecCallback; /** JCR based implementation of a keyring */ public class JcrKeyring extends AbstractKeyring implements ArgeoNames { @@ -150,7 +152,7 @@ public class JcrKeyring extends AbstractKeyring implements ArgeoNames { } } - /** The node must already exist at this path. Session is saved. */ + /** 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 @@ -158,42 +160,25 @@ public class JcrKeyring extends AbstractKeyring implements ArgeoNames { Binary binary = null; InputStream in = null; - // ByteArrayOutputStream out = null; - // OutputStream encrypted = null; - try { Cipher cipher = createCipher(); - if (!session.nodeExists(path)) - throw new ArgeoException("No node at " + path); - if (session.hasPendingChanges()) - session.save(); - Node node = session.getNode(path); + Node node; + if (!session.nodeExists(path)) { + String parentPath = JcrUtils.parentPath(path); + if (!session.nodeExists(parentPath)) + throw new ArgeoException("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)); - // AlgorithmParameters params = cipher.getParameters(); - // byte[] iv = - // params.getParameterSpec(IvParameterSpec.class).getIV(); - // if (iv != null) JcrUtils.setBinaryAsBytes(node, ARGEO_IV, iv); - // out = new ByteArrayOutputStream(); - // // encrypted = new CipherOutputStream(out, cipher); - // IOUtils.copy(unencrypted, out); - // byte[] unenc = out.toByteArray(); - // byte[] crypted = cipher.doFinal(unenc); - - // Cipher decipher = createCipher(); - // decipher.init(Cipher.DECRYPT_MODE, secretKey, new - // IvParameterSpec( - // iv)); - // byte[] decrypted = decipher.doFinal(crypted); - // System.out.println("Password :'" + new String(decrypted) + "'"); - - // JcrUtils.setBinaryAsBytes(node, Property.JCR_DATA, crypted); - in = new CipherInputStream(unencrypted, cipher); binary = session.getValueFactory().createBinary(in); node.setProperty(Property.JCR_DATA, binary); @@ -201,8 +186,6 @@ public class JcrKeyring extends AbstractKeyring implements ArgeoNames { } catch (Exception e) { throw new ArgeoException("Cannot encrypt", e); } finally { - // IOUtils.closeQuietly(out); - // IOUtils.closeQuietly(encrypted); IOUtils.closeQuietly(unencrypted); IOUtils.closeQuietly(in); JcrUtils.closeQuietly(binary); @@ -211,39 +194,39 @@ public class JcrKeyring extends AbstractKeyring implements ArgeoNames { @Override protected synchronized InputStream decrypt(String path) { - // should be called first for lazy initialization - SecretKey secretKey = getSecretKey(); - Binary binary = null; InputStream encrypted = null; - + Reader reader = null; try { - Cipher cipher = createCipher(); - if (!session.nodeExists(path)) - throw new ArgeoException("No node at " + path); - 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)); + if (!session.nodeExists(path)) { + char[] password = ask(); + reader = new CharArrayReader(password); + return new ByteArrayInputStream(IOUtils.toByteArray(reader)); } else { - cipher.init(Cipher.DECRYPT_MODE, secretKey); + // 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); } - - // byte[] arr = JcrUtils.getBinaryAsBytes(node - // .getProperty(Property.JCR_DATA)); - // byte[] arr2 = cipher.doFinal(arr); - // - // return new ByteArrayInputStream(arr2); - - binary = node.getProperty(Property.JCR_DATA).getBinary(); - encrypted = binary.getStream(); - return new CipherInputStream(encrypted, cipher); } catch (Exception e) { throw new ArgeoException("Cannot decrypt", e); } finally { IOUtils.closeQuietly(encrypted); + IOUtils.closeQuietly(reader); JcrUtils.closeQuietly(binary); } } @@ -255,7 +238,8 @@ public class JcrKeyring extends AbstractKeyring implements ArgeoNames { throw new ArgeoException("Keyring not setup"); Node keyring = userHome.getNode(ARGEO_KEYRING); Cipher cipher = Cipher.getInstance(keyring - .getProperty(ARGEO_CIPHER).getString()); + .getProperty(ARGEO_CIPHER).getString(), + getSecurityProvider()); return cipher; } catch (Exception e) { throw new ArgeoException("Cannot get cipher", e); @@ -267,12 +251,7 @@ public class JcrKeyring extends AbstractKeyring implements ArgeoNames { // TODO decrypt with old pw / encrypt with new pw all argeo:encrypted } - public synchronized Session getSession() { - return session; - } - public synchronized void setSession(Session session) { this.session = session; } - -} +} \ No newline at end of file diff --git a/security/runtime/org.argeo.security.core/src/test/java/org/argeo/security/crypto/ListBCCapabilities.java b/security/runtime/org.argeo.security.core/src/test/java/org/argeo/security/crypto/ListBCCapabilities.java new file mode 100644 index 000000000..a95fba274 --- /dev/null +++ b/security/runtime/org.argeo.security.core/src/test/java/org/argeo/security/crypto/ListBCCapabilities.java @@ -0,0 +1,43 @@ +package org.argeo.security.crypto; + +import java.security.Provider; +import java.security.Security; +import java.util.Iterator; + +import org.bouncycastle.jce.provider.BouncyCastleProvider; + +/** + * List the available capabilities for ciphers, key agreement, macs, message + * digests, signatures and other objects in the BC provider. + */ +public class ListBCCapabilities { + public static void main(String[] args) { + Security.addProvider(new BouncyCastleProvider()); + + Provider[] providers = Security.getProviders(); + for (Provider provider : providers) { + System.out.println(provider.getName()); + System.out.println(" " + provider.getVersion()); + System.out.println(" " + provider.getInfo()); + } + Provider provider = Security.getProvider("BC"); + // Provider provider = Security.getProvider(null); + + Iterator it = provider.keySet().iterator(); + + while (it.hasNext()) { + String entry = (String) it.next(); + + // this indicates the entry refers to another entry + + if (entry.startsWith("Alg.Alias.")) { + entry = entry.substring("Alg.Alias.".length()); + } + + String factoryClass = entry.substring(0, entry.indexOf('.')); + String name = entry.substring(factoryClass.length() + 1); + + System.out.println(factoryClass + ": " + name); + } + } +} diff --git a/base/runtime/org.argeo.util/src/test/java/org/argeo/util/crypto/PasswordBasedEncryptionTest.java b/security/runtime/org.argeo.security.core/src/test/java/org/argeo/security/crypto/PasswordBasedEncryptionTest.java similarity index 98% rename from base/runtime/org.argeo.util/src/test/java/org/argeo/util/crypto/PasswordBasedEncryptionTest.java rename to security/runtime/org.argeo.security.core/src/test/java/org/argeo/security/crypto/PasswordBasedEncryptionTest.java index a42444539..bea93188f 100644 --- a/base/runtime/org.argeo.util/src/test/java/org/argeo/util/crypto/PasswordBasedEncryptionTest.java +++ b/security/runtime/org.argeo.security.core/src/test/java/org/argeo/security/crypto/PasswordBasedEncryptionTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.argeo.util.crypto; +package org.argeo.security.crypto; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -33,6 +33,7 @@ import javax.xml.bind.DatatypeConverter; import junit.framework.TestCase; import org.argeo.StreamUtils; +import org.argeo.security.crypto.PasswordBasedEncryption; public class PasswordBasedEncryptionTest extends TestCase { public void testEncryptDecrypt() { diff --git a/server/plugins/org.argeo.jcr.ui.explorer/META-INF/spring/commands.xml b/server/plugins/org.argeo.jcr.ui.explorer/META-INF/spring/commands.xml index e3bad2892..5e4a185c7 100644 --- a/server/plugins/org.argeo.jcr.ui.explorer/META-INF/spring/commands.xml +++ b/server/plugins/org.argeo.jcr.ui.explorer/META-INF/spring/commands.xml @@ -22,10 +22,12 @@ - + + - + - + diff --git a/server/plugins/org.argeo.jcr.ui.explorer/META-INF/spring/views.xml b/server/plugins/org.argeo.jcr.ui.explorer/META-INF/spring/views.xml index 84520ef55..14f1943d7 100644 --- a/server/plugins/org.argeo.jcr.ui.explorer/META-INF/spring/views.xml +++ b/server/plugins/org.argeo.jcr.ui.explorer/META-INF/spring/views.xml @@ -7,8 +7,9 @@ - + + diff --git a/server/plugins/org.argeo.jcr.ui.explorer/pom.xml b/server/plugins/org.argeo.jcr.ui.explorer/pom.xml index 3f92ce1ab..4fdd06434 100644 --- a/server/plugins/org.argeo.jcr.ui.explorer/pom.xml +++ b/server/plugins/org.argeo.jcr.ui.explorer/pom.xml @@ -1,4 +1,5 @@ - + 4.0.0 org.argeo.commons.server @@ -25,7 +26,6 @@ *, org.argeo.eclipse.spring, - org.argeo.util.crypto, org.argeo.jcr.ui.explorer.* @@ -34,6 +34,11 @@ + + org.argeo.commons.base + org.argeo.util + 1.1.4-SNAPSHOT + org.argeo.commons.base org.argeo.eclipse.ui.jcr diff --git a/server/plugins/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/browser/NodeContentProvider.java b/server/plugins/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/browser/NodeContentProvider.java index 34466d301..c438463d8 100644 --- a/server/plugins/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/browser/NodeContentProvider.java +++ b/server/plugins/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/browser/NodeContentProvider.java @@ -27,10 +27,10 @@ import org.argeo.eclipse.ui.TreeParent; import org.argeo.jcr.ArgeoJcrConstants; import org.argeo.jcr.RepositoryRegister; import org.argeo.jcr.UserJcrUtils; -import org.argeo.jcr.security.JcrKeyring; import org.argeo.jcr.ui.explorer.model.RepositoriesNode; import org.argeo.jcr.ui.explorer.model.SingleJcrNode; import org.argeo.jcr.ui.explorer.utils.TreeObjectsComparator; +import org.argeo.util.security.Keyring; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.Viewer; @@ -40,14 +40,14 @@ import org.eclipse.jface.viewers.Viewer; * */ public class NodeContentProvider implements ITreeContentProvider { - // private final static Log log = - // LogFactory.getLog(NodeContentProvider.class); - - // Business Objects final private RepositoryRegister repositoryRegister; final private RepositoryFactory repositoryFactory; + /** + * A session of the logged in user on the default workspace of the node + * repository. + */ final private Session userSession; - final private JcrKeyring jcrKeyring; + final private Keyring keyring; final private boolean sortChildren; // reference for cleaning @@ -57,11 +57,11 @@ public class NodeContentProvider implements ITreeContentProvider { // Utils private TreeObjectsComparator itemComparator = new TreeObjectsComparator(); - public NodeContentProvider(JcrKeyring jcrKeyring, + public NodeContentProvider(Session userSession, Keyring keyring, RepositoryRegister repositoryRegister, RepositoryFactory repositoryFactory, Boolean sortChildren) { - this.userSession = jcrKeyring != null ? jcrKeyring.getSession() : null; - this.jcrKeyring = jcrKeyring; + this.userSession = userSession; + this.keyring = keyring; this.repositoryRegister = repositoryRegister; this.repositoryFactory = repositoryFactory; this.sortChildren = sortChildren; @@ -85,7 +85,8 @@ public class NodeContentProvider implements ITreeContentProvider { if (repositoriesNode != null) repositoriesNode.dispose(); repositoriesNode = new RepositoriesNode("Repositories", - repositoryRegister, repositoryFactory, null, jcrKeyring); + repositoryRegister, repositoryFactory, null, userSession, + keyring); } } diff --git a/server/plugins/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/commands/AddRemoteRepository.java b/server/plugins/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/commands/AddRemoteRepository.java index b7d4e030a..6187f40ee 100644 --- a/server/plugins/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/commands/AddRemoteRepository.java +++ b/server/plugins/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/commands/AddRemoteRepository.java @@ -31,8 +31,8 @@ import org.argeo.jcr.ArgeoNames; import org.argeo.jcr.ArgeoTypes; import org.argeo.jcr.JcrUtils; import org.argeo.jcr.UserJcrUtils; -import org.argeo.jcr.security.JcrKeyring; import org.argeo.jcr.ui.explorer.JcrExplorerConstants; +import org.argeo.util.security.Keyring; import org.eclipse.core.commands.AbstractHandler; import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.commands.ExecutionException; @@ -62,7 +62,8 @@ public class AddRemoteRepository extends AbstractHandler implements JcrExplorerConstants, ArgeoNames { private RepositoryFactory repositoryFactory; - private JcrKeyring keyring; + private Repository nodeRepository; + private Keyring keyring; public Object execute(ExecutionEvent event) throws ExecutionException { RemoteRepositoryLoginDialog dlg = new RemoteRepositoryLoginDialog( @@ -76,10 +77,14 @@ public class AddRemoteRepository extends AbstractHandler implements this.repositoryFactory = repositoryFactory; } - public void setKeyring(JcrKeyring keyring) { + public void setKeyring(Keyring keyring) { this.keyring = keyring; } + public void setNodeRepository(Repository nodeRepository) { + this.nodeRepository = nodeRepository; + } + class RemoteRepositoryLoginDialog extends TitleAreaDialog { private Text name; private Text uri; @@ -158,7 +163,7 @@ public class AddRemoteRepository extends AbstractHandler implements @Override protected void okPressed() { try { - Session nodeSession = keyring.getSession(); + Session nodeSession = nodeRepository.login(); Node home = UserJcrUtils.getUserHome(nodeSession); Node remote = home.hasNode(ARGEO_REMOTE) ? home @@ -171,11 +176,13 @@ public class AddRemoteRepository extends AbstractHandler implements ArgeoTypes.ARGEO_REMOTE_REPOSITORY); remoteRepository.setProperty(ARGEO_URI, uri.getText()); remoteRepository.setProperty(ARGEO_USER_ID, username.getText()); - Node pwd = remoteRepository.addNode(ARGEO_PASSWORD); - pwd.getSession().save(); - if (saveInKeyring.getSelection()) - keyring.set(pwd.getPath(), password.getText().toCharArray()); - keyring.getSession().save(); + nodeSession.save(); + if (saveInKeyring.getSelection()) { + String pwdPath = remoteRepository.getPath() + '/' + + ARGEO_PASSWORD; + keyring.set(pwdPath, password.getText().toCharArray()); + } + nodeSession.save(); MessageDialog.openInformation( getParentShell(), "Repository Added", diff --git a/server/plugins/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/model/RemoteRepositoryNode.java b/server/plugins/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/model/RemoteRepositoryNode.java index 8f71ace0a..19ca3990b 100644 --- a/server/plugins/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/model/RemoteRepositoryNode.java +++ b/server/plugins/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/model/RemoteRepositoryNode.java @@ -26,28 +26,37 @@ import javax.jcr.SimpleCredentials; import org.argeo.ArgeoException; import org.argeo.eclipse.ui.TreeParent; import org.argeo.jcr.ArgeoNames; -import org.argeo.jcr.security.JcrKeyring; +import org.argeo.util.security.Keyring; /** Root of a remote repository */ public class RemoteRepositoryNode extends RepositoryNode { - private JcrKeyring jcrKeyring; - private String remoteNodePath; + private final Keyring keyring; + /** + * A session of the logged in user on the default workspace of the node + * repository. + */ + private final Session userSession; + private final String remoteNodePath; public RemoteRepositoryNode(String alias, Repository repository, - TreeParent parent, JcrKeyring jcrKeyring, String remoteNodePath) { + TreeParent parent, Session userSession, Keyring keyring, + String remoteNodePath) { super(alias, repository, parent); - this.jcrKeyring = jcrKeyring; + this.keyring = keyring; + this.userSession = userSession; this.remoteNodePath = remoteNodePath; } @Override protected Session repositoryLogin(String workspaceName) throws RepositoryException { - Node remoteNode = jcrKeyring.getSession().getNode(remoteNodePath); - String userID = remoteNode.getProperty(ArgeoNames.ARGEO_USER_ID) + Node remoteRepository = userSession.getNode(remoteNodePath); + String userID = remoteRepository.getProperty(ArgeoNames.ARGEO_USER_ID) .getString(); - char[] password = jcrKeyring.getAsChars(remoteNodePath + "/" - + ArgeoNames.ARGEO_PASSWORD); + String pwdPath = remoteRepository.getPath() + '/' + + ArgeoNames.ARGEO_PASSWORD; + char[] password = keyring.getAsChars(pwdPath); + try { SimpleCredentials credentials = new SimpleCredentials(userID, password); @@ -59,7 +68,7 @@ public class RemoteRepositoryNode extends RepositoryNode { public void remove() { try { - Node remoteNode = jcrKeyring.getSession().getNode(remoteNodePath); + Node remoteNode = userSession.getNode(remoteNodePath); remoteNode.remove(); remoteNode.getSession().save(); } catch (RepositoryException e) { diff --git a/server/plugins/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/model/RepositoriesNode.java b/server/plugins/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/model/RepositoriesNode.java index 52ed4c2ef..fe8293235 100644 --- a/server/plugins/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/model/RepositoriesNode.java +++ b/server/plugins/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/model/RepositoriesNode.java @@ -32,7 +32,7 @@ import org.argeo.jcr.ArgeoJcrConstants; import org.argeo.jcr.ArgeoNames; import org.argeo.jcr.RepositoryRegister; import org.argeo.jcr.UserJcrUtils; -import org.argeo.jcr.security.JcrKeyring; +import org.argeo.util.security.Keyring; /** * UI Tree component. Implements the Argeo abstraction of a @@ -49,15 +49,21 @@ public class RepositoriesNode extends TreeParent implements ArgeoNames { private final RepositoryRegister repositoryRegister; private final RepositoryFactory repositoryFactory; - private final JcrKeyring jcrKeyring; + /** + * A session of the logged in user on the default workspace of the node + * repository. + */ + private final Session userSession; + private final Keyring keyring; public RepositoriesNode(String name, RepositoryRegister repositoryRegister, RepositoryFactory repositoryFactory, TreeParent parent, - JcrKeyring jcrKeyring) { + Session userSession, Keyring keyring) { super(name); this.repositoryRegister = repositoryRegister; this.repositoryFactory = repositoryFactory; - this.jcrKeyring = jcrKeyring; + this.userSession = userSession; + this.keyring = keyring; } /** @@ -78,9 +84,9 @@ public class RepositoriesNode extends TreeParent implements ArgeoNames { } // remote - if (jcrKeyring != null) { + if (keyring != null) { try { - addRemoteRepositories(jcrKeyring); + addRemoteRepositories(keyring); } catch (RepositoryException e) { throw new ArgeoException( "Cannot browse remote repositories", e); @@ -90,9 +96,8 @@ public class RepositoriesNode extends TreeParent implements ArgeoNames { } } - protected void addRemoteRepositories(JcrKeyring jcrKeyring) + protected void addRemoteRepositories(Keyring jcrKeyring) throws RepositoryException { - Session userSession = jcrKeyring.getSession(); Node userHome = UserJcrUtils.getUserHome(userSession); if (userHome != null && userHome.hasNode(ARGEO_REMOTE)) { NodeIterator it = userHome.getNode(ARGEO_REMOTE).getNodes(); @@ -107,8 +112,8 @@ public class RepositoriesNode extends TreeParent implements ArgeoNames { Repository repository = repositoryFactory .getRepository(params); RemoteRepositoryNode remoteRepositoryNode = new RemoteRepositoryNode( - remoteNode.getName(), repository, this, jcrKeyring, - remoteNode.getPath()); + remoteNode.getName(), repository, this, + userSession, jcrKeyring, remoteNode.getPath()); super.addChild(remoteRepositoryNode); } catch (Exception e) { ErrorFeedback.show("Cannot add remote repository " diff --git a/server/plugins/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/views/GenericJcrBrowser.java b/server/plugins/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/views/GenericJcrBrowser.java index 9ae1b0b63..5557d8109 100644 --- a/server/plugins/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/views/GenericJcrBrowser.java +++ b/server/plugins/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/views/GenericJcrBrowser.java @@ -19,22 +19,21 @@ import java.util.List; import javax.jcr.Property; import javax.jcr.PropertyType; +import javax.jcr.Repository; import javax.jcr.RepositoryException; import javax.jcr.RepositoryFactory; +import javax.jcr.Session; import javax.jcr.Value; import javax.jcr.observation.Event; import javax.jcr.observation.EventListener; import javax.jcr.observation.ObservationManager; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; import org.argeo.ArgeoException; import org.argeo.eclipse.ui.TreeParent; import org.argeo.eclipse.ui.jcr.AsyncUiEventListener; import org.argeo.eclipse.ui.jcr.utils.NodeViewerComparer; import org.argeo.eclipse.ui.jcr.views.AbstractJcrBrowser; import org.argeo.jcr.RepositoryRegister; -import org.argeo.jcr.security.JcrKeyring; import org.argeo.jcr.ui.explorer.JcrExplorerPlugin; import org.argeo.jcr.ui.explorer.browser.NodeContentProvider; import org.argeo.jcr.ui.explorer.browser.NodeLabelProvider; @@ -42,6 +41,7 @@ import org.argeo.jcr.ui.explorer.browser.PropertiesContentProvider; import org.argeo.jcr.ui.explorer.model.SingleJcrNode; import org.argeo.jcr.ui.explorer.utils.GenericNodeDoubleClickListener; import org.argeo.jcr.ui.explorer.utils.JcrUiUtils; +import org.argeo.util.security.Keyring; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.viewers.ColumnLabelProvider; import org.eclipse.jface.viewers.ISelectionChangedListener; @@ -65,16 +65,20 @@ import org.eclipse.swt.widgets.Menu; * Basic View to display a sash form to browse a JCR compliant multirepository * environment */ - public class GenericJcrBrowser extends AbstractJcrBrowser { - private final static Log log = LogFactory.getLog(GenericJcrBrowser.class); public final static String ID = JcrExplorerPlugin.ID + ".browserView"; private boolean sortChildNodes = false; /* DEPENDENCY INJECTION */ - private JcrKeyring jcrKeyring; + private Keyring keyring; private RepositoryRegister repositoryRegister; private RepositoryFactory repositoryFactory; + private Repository nodeRepository; + /** + * A session of the logged in user on the default workspace of the node + * repository. + */ + private Session userSession; // This page widgets private TreeViewer nodesViewer; @@ -82,35 +86,8 @@ public class GenericJcrBrowser extends AbstractJcrBrowser { private TableViewer propertiesViewer; private EventListener resultsObserver; - // Manage documents - // private JcrFileProvider jcrFileProvider; - // private FileHandler fileHandler; - @Override public void createPartControl(Composite parent) { - - // look for session - // Session nodeSession = jcrKeyring != null ? jcrKeyring.getSession() - // : null; - // if (nodeSession == null) { - // Repository nodeRepository = JcrUtils.getRepositoryByAlias( - // repositoryRegister, ArgeoJcrConstants.ALIAS_NODE); - // if (nodeRepository != null) - // try { - // nodeSession = nodeRepository.login(); - // // TODO : enhance that to enable multirepository listener. - // } catch (RepositoryException e1) { - // throw new ArgeoException("Cannot login to node repository"); - // } - // } - - // Instantiate the generic object that fits for - // both RCP & RAP - // Note that in RAP, it registers a service handler that provide the - // access to the files. - // jcrFileProvider = new JcrFileProvider(); - // fileHandler = new FileHandler(jcrFileProvider); - parent.setLayout(new FillLayout()); SashForm sashForm = new SashForm(parent, SWT.VERTICAL); sashForm.setSashWidth(4); @@ -121,7 +98,13 @@ public class GenericJcrBrowser extends AbstractJcrBrowser { GridLayout gl = new GridLayout(1, false); top.setLayout(gl); - nodeContentProvider = new NodeContentProvider(jcrKeyring, + try { + this.userSession = this.nodeRepository.login(); + } catch (RepositoryException e) { + throw new ArgeoException("Cannot open user session", e); + } + + nodeContentProvider = new NodeContentProvider(userSession, keyring, repositoryRegister, repositoryFactory, sortChildNodes); // nodes viewer @@ -181,10 +164,9 @@ public class GenericJcrBrowser extends AbstractJcrBrowser { }); resultsObserver = new TreeObserver(tmpNodeViewer.getTree().getDisplay()); - if (jcrKeyring != null) + if (keyring != null) try { - log.debug("userID=" + jcrKeyring.getSession().getUserID()); - ObservationManager observationManager = jcrKeyring.getSession() + ObservationManager observationManager = userSession .getWorkspace().getObservationManager(); observationManager.addEventListener(resultsObserver, Event.PROPERTY_ADDED | Event.PROPERTY_CHANGED, "/", @@ -335,12 +317,16 @@ public class GenericJcrBrowser extends AbstractJcrBrowser { this.repositoryRegister = repositoryRegister; } - public void setJcrKeyring(JcrKeyring jcrKeyring) { - this.jcrKeyring = jcrKeyring; + public void setKeyring(Keyring keyring) { + this.keyring = keyring; } public void setRepositoryFactory(RepositoryFactory repositoryFactory) { this.repositoryFactory = repositoryFactory; } + public void setNodeRepository(Repository nodeRepository) { + this.nodeRepository = nodeRepository; + } + } diff --git a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/JcrUtils.java b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/JcrUtils.java index 1ace83fcd..91eaceeb2 100644 --- a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/JcrUtils.java +++ b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/JcrUtils.java @@ -113,6 +113,20 @@ public class JcrUtils implements ArgeoJcrConstants { return node; } + /** Retrieves the node name from the provided path */ + public static String nodeNameFromPath(String path) { + if (path.equals("/")) + return ""; + if (path.charAt(0) != '/') + throw new ArgeoException("Path " + path + " must start with a '/'"); + String pathT = path; + if (pathT.charAt(pathT.length() - 1) == '/') + pathT = pathT.substring(0, pathT.length() - 2); + + int index = pathT.lastIndexOf('/'); + return pathT.substring(index + 1); + } + /** Retrieves the parent path of the provided path */ public static String parentPath(String path) { if (path.equals("/")) diff --git a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/security/SecurityJcrUtils.java b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/security/SecurityJcrUtils.java deleted file mode 100644 index 90a8d87bd..000000000 --- a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/security/SecurityJcrUtils.java +++ /dev/null @@ -1,125 +0,0 @@ -package org.argeo.jcr.security; - -import javax.jcr.Node; -import javax.jcr.RepositoryException; -import javax.jcr.Session; -import javax.jcr.version.VersionManager; - -import org.argeo.ArgeoException; -import org.argeo.jcr.ArgeoJcrConstants; -import org.argeo.jcr.ArgeoNames; -import org.argeo.jcr.ArgeoTypes; -import org.argeo.jcr.JcrUtils; -import org.argeo.jcr.UserJcrUtils; - -/** Utilities related to Argeo security model in JCR */ -@Deprecated -public class SecurityJcrUtils implements ArgeoJcrConstants { - /** - * Creates an Argeo user home, does nothing if it already exists. Session is - * NOT saved. - */ - static Node createUserHomeIfNeeded(Session session, String username) { - try { - String homePath = generateUserHomePath(username); - if (session.itemExists(homePath)) - return session.getNode(homePath); - else { - Node userHome = JcrUtils.mkdirs(session, homePath); - userHome.addMixin(ArgeoTypes.ARGEO_USER_HOME); - userHome.setProperty(ArgeoNames.ARGEO_USER_ID, username); - - // JcrUtils.addPrivilege(session, homePath, username, - // "jcr:all"); - return userHome; - } - } catch (RepositoryException e) { - JcrUtils.discardQuietly(session); - throw new ArgeoException("Cannot create home for " + username - + " in workspace " + session.getWorkspace().getName(), e); - } - } - - private static String generateUserHomePath(String username) { - String homeBasePath = UserJcrUtils.DEFAULT_HOME_BASE_PATH; - return homeBasePath + '/' + JcrUtils.firstCharsToPath(username, 2) - + '/' + username; - } - - /** - * Creates a user profile in the home of this user. Creates the home if - * needed, but throw an exception if a profile already exists. The session - * is not saved and the node is in a checkedOut state (that is, it requires - * a subsequent checkin after saving the session). - */ - static Node createUserProfile(Session session, String username) { - try { - Node userHome = createUserHomeIfNeeded(session, username); - if (userHome.hasNode(ArgeoNames.ARGEO_PROFILE)) - throw new ArgeoException( - "There is already a user profile under " + userHome); - Node userProfile = userHome.addNode(ArgeoNames.ARGEO_PROFILE); - userProfile.addMixin(ArgeoTypes.ARGEO_USER_PROFILE); - userProfile.setProperty(ArgeoNames.ARGEO_USER_ID, username); - userProfile.setProperty(ArgeoNames.ARGEO_ENABLED, true); - userProfile.setProperty(ArgeoNames.ARGEO_ACCOUNT_NON_EXPIRED, true); - userProfile.setProperty(ArgeoNames.ARGEO_ACCOUNT_NON_LOCKED, true); - userProfile.setProperty(ArgeoNames.ARGEO_CREDENTIALS_NON_EXPIRED, - true); - return userProfile; - } catch (RepositoryException e) { - JcrUtils.discardQuietly(session); - throw new ArgeoException("Cannot create user profile for " - + username + " in workspace " - + session.getWorkspace().getName(), e); - } - } - - /** - * Create user profile if needed, the session IS saved. - * - * @return the user profile - */ - static Node createUserProfileIfNeeded(Session securitySession, - String username) { - try { - Node userHome = createUserHomeIfNeeded(securitySession, username); - Node userProfile = userHome.hasNode(ArgeoNames.ARGEO_PROFILE) ? userHome - .getNode(ArgeoNames.ARGEO_PROFILE) : createUserProfile( - securitySession, username); - if (securitySession.hasPendingChanges()) - securitySession.save(); - VersionManager versionManager = securitySession.getWorkspace() - .getVersionManager(); - if (versionManager.isCheckedOut(userProfile.getPath())) - versionManager.checkin(userProfile.getPath()); - return userProfile; - } catch (RepositoryException e) { - JcrUtils.discardQuietly(securitySession); - throw new ArgeoException("Cannot create user profile for " - + username + " in workspace " - + securitySession.getWorkspace().getName(), e); - } - } - - /** - * @return null if not found * - */ - static Node getUserProfile(Session session, String username) { - try { - Node userHome = UserJcrUtils.getUserHome(session, username); - if (userHome == null) - return null; - if (userHome.hasNode(ArgeoNames.ARGEO_PROFILE)) - return userHome.getNode(ArgeoNames.ARGEO_PROFILE); - else - return null; - } catch (RepositoryException e) { - throw new ArgeoException( - "Cannot find profile for user " + username, e); - } - } - - private SecurityJcrUtils() { - } -} -- 2.30.2