<?xml version="1.0" encoding="UTF-8"?>
<classpath>
- <classpathentry kind="src" output="target/classes" path="src/main/java"/>
- <classpathentry kind="src" output="target/classes" path="src/main/resources"/>
- <classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
- <classpathentry kind="src" output="target/test-classes" path="src/test/resources"/>
- <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>>>
- <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
- <classpathentry kind="output" path="bin"/>
+ <classpathentry kind="src" path="src" />
+ <classpathentry kind="src" path="ext/test" />
+ <classpathentry kind="con"
+ path="org.eclipse.pde.core.requiredPlugins" />
+ <classpathentry kind="con"
+ path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6" />
+ <classpathentry kind="output" path="bin" />
</classpath>
--- /dev/null
+Bundle-ActivationPolicy: lazy
+Import-Package:org.bouncycastle.*;resolution:=optional,\
+javax.jcr.security,\
+*
org.apache.log4j,\
slf4j.api,\
slf4j.org.apache.commons.logging
-source.. = src/main/java/,\
- src/main/resources/,\
- src/test/java/,\
- src/test/resources/
+source.. = src/,\
+ ext/test/
+bin.. = bin/
--- /dev/null
+log4j.rootLogger=WARN, console
+
+## Levels
+log4j.logger.org.argeo=DEBUG
+
+log4j.logger.org.hibernate=WARN
+
+log4j.logger.org.springframework=WARN
+#log4j.logger.org.springframework.web=DEBUG
+#log4j.logger.org.springframework.jms=WARN
+#log4j.logger.org.springframework.security=WARN
+
+log4j.logger.org.apache.activemq=WARN
+log4j.logger.org.apache.activemq.transport=WARN
+log4j.logger.org.apache.activemq.ActiveMQMessageConsumer=INFO
+log4j.logger.org.apache.activemq.ActiveMQMessageProducer=INFO
+
+log4j.logger.org.apache.catalina=INFO
+log4j.logger.org.apache.coyote=INFO
+log4j.logger.org.apache.tomcat=INFO
+
+## Appenders
+# console is set to be a ConsoleAppender.
+log4j.appender.console=org.apache.log4j.ConsoleAppender
+
+# console uses PatternLayout.
+log4j.appender.console.layout=org.apache.log4j.PatternLayout
+log4j.appender.console.layout.ConversionPattern= %-5p %d{ISO8601} %m - %c%n
--- /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.security;
+
+import org.apache.commons.codec.DecoderException;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.codec.binary.Hex;
+import org.springframework.security.providers.ldap.authenticator.LdapShaPasswordEncoder;
+
+public class PasswordSandbox {
+ public static void main(String[] args) {
+ try {
+ // Tested password
+ String pwdPlain = "demo";
+
+ // Check Java generated values
+ LdapShaPasswordEncoder lspe = new LdapShaPasswordEncoder();
+ String pwdLdapShaBase64 = lspe.encodePassword(pwdPlain, null);
+ System.out.println("pwdLdapShaBase64:\t\t" + pwdLdapShaBase64);
+
+ String pwdShaBase64 = pwdLdapShaBase64.substring("{SHA}".length());
+ System.out.println("pwdShaBase64:\t\t\t" + pwdShaBase64);
+
+ byte[] pwdShaArray = Base64.decodeBase64(pwdShaBase64.getBytes());
+ String pwdShaHex = new String(Hex.encodeHex(pwdShaArray));
+ System.out.println("pwdShaHex:\t\t\t" + pwdShaHex);
+
+ // Check that we can use JavaScript generated values in Hex
+ String jsShaHex = "89e495e7941cf9e40e6980d14a16bf023ccd4c91";
+ System.out.println("jsShaHex:\t\t\t" + pwdShaHex);
+ System.out.println("pwdShaHex==jsShaHex:\t\t"
+ + (pwdShaHex.equals(jsShaHex)));
+
+ byte[] jsShaArray = Hex.decodeHex(jsShaHex.toCharArray());
+ String jsShaBase64 = new String(Base64.encodeBase64(jsShaArray));
+ System.out.println("jsShaBase64:\t\t\t" + jsShaBase64);
+ System.out.println("pwdShaBase64==jsShaBase64:\t"
+ + (pwdShaBase64.equals(jsShaBase64)));
+ } catch (DecoderException e) {
+ e.printStackTrace();
+ }
+
+ }
+
+}
\ 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.security.crypto;
+
+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.StreamUtils;
+import org.argeo.security.crypto.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.security;
-
-import org.springframework.security.GrantedAuthority;
-import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
-
-/** Credentials required for the authentication to a node. */
-public class NodeAuthenticationToken extends
- UsernamePasswordAuthenticationToken {
- private static final long serialVersionUID = 1955222132884795213L;
- private final String url;
-
- /** Non authenticated local constructor */
- public NodeAuthenticationToken(Object principal, Object credentials) {
- super(principal, credentials);
- this.url = null;
- }
-
- /** Non authenticated remote constructor */
- public NodeAuthenticationToken(Object principal, Object credentials,
- String url) {
- super(principal, credentials);
- this.url = url;
- }
-
- /** Authenticated constructor */
- public NodeAuthenticationToken(NodeAuthenticationToken sat,
- GrantedAuthority[] authorities) {
- super(sat.getPrincipal(), sat.getCredentials(), authorities);
- this.url = sat.getUrl();
- }
-
- public String getUrl() {
- return url;
- }
-
- public Boolean isRemote() {
- return url != 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.security;
-
-import java.security.AccessController;
-import java.security.Principal;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Set;
-
-import javax.security.auth.Subject;
-
-import org.argeo.ArgeoException;
-import org.argeo.OperatingSystem;
-import org.springframework.security.Authentication;
-import org.springframework.security.GrantedAuthority;
-import org.springframework.security.GrantedAuthorityImpl;
-import org.springframework.security.userdetails.UserDetails;
-
-/** Abstracts principals provided by com.sun.security.auth.module login modules. */
-public class OsAuthenticationToken implements Authentication {
- private static final long serialVersionUID = -7544626794250917244L;
-
- final Class<? extends Principal> osUserPrincipalClass;
- final Class<? extends Principal> osUserIdPrincipalClass;
- final Class<? extends Principal> osGroupIdPrincipalClass;
-
- private List<GrantedAuthority> grantedAuthorities;
-
- private UserDetails details;
-
- /** Request */
- public OsAuthenticationToken(GrantedAuthority[] grantedAuthorities) {
- this.grantedAuthorities = grantedAuthorities != null ? Arrays
- .asList(grantedAuthorities) : null;
- ClassLoader cl = getClass().getClassLoader();
- switch (OperatingSystem.os) {
- case OperatingSystem.WINDOWS:
- osUserPrincipalClass = getPrincipalClass(cl,
- "com.sun.security.auth.NTUserPrincipal");
- osUserIdPrincipalClass = getPrincipalClass(cl,
- "com.sun.security.auth.NTSidUserPrincipal");
- osGroupIdPrincipalClass = getPrincipalClass(cl,
- "com.sun.security.auth.NTSidGroupPrincipal");
- break;
- case OperatingSystem.NIX:
- osUserPrincipalClass = getPrincipalClass(cl,
- "com.sun.security.auth.UnixPrincipal");
- osUserIdPrincipalClass = getPrincipalClass(cl,
- "com.sun.security.auth.UnixNumericUserPrincipal");
- osGroupIdPrincipalClass = getPrincipalClass(cl,
- "com.sun.security.auth.UnixNumericGroupPrincipal");
- break;
- case OperatingSystem.SOLARIS:
- osUserPrincipalClass = getPrincipalClass(cl,
- "com.sun.security.auth.SolarisPrincipal");
- osUserIdPrincipalClass = getPrincipalClass(cl,
- "com.sun.security.auth.SolarisNumericUserPrincipal");
- osGroupIdPrincipalClass = getPrincipalClass(cl,
- "com.sun.security.auth.SolarisNumericGroupPrincipal");
- break;
-
- default:
- throw new ArgeoException("Unsupported operating system "
- + OperatingSystem.os);
- }
-
- }
-
- /** Authenticated */
- public OsAuthenticationToken() {
- this(null);
- }
-
- /** @return the name, or null if not yet logged */
- public String getName() {
- Subject subject = Subject.getSubject(AccessController.getContext());
- if (subject == null)
- return null;
- return getUser().getName();
- }
-
- /**
- * Should not be called during authentication since group IDs are not yet
- * available {@link Subject} has been set
- */
- public GrantedAuthority[] getAuthorities() {
- // grantedAuthorities should not be null at this stage
- List<GrantedAuthority> gas = new ArrayList<GrantedAuthority>(
- grantedAuthorities);
- for (Principal groupPrincipal : getGroupsIds()) {
- gas.add(new GrantedAuthorityImpl("OSGROUP_"
- + groupPrincipal.getName()));
- }
- return gas.toArray(new GrantedAuthority[gas.size()]);
- }
-
- public UserDetails getDetails() {
- return details;
- }
-
- public void setDetails(UserDetails details) {
- this.details = details;
- }
-
- public boolean isAuthenticated() {
- return grantedAuthorities != null;
- }
-
- public void setAuthenticated(boolean isAuthenticated)
- throws IllegalArgumentException {
- if (grantedAuthorities != null)
- grantedAuthorities.clear();
- grantedAuthorities = null;
- }
-
- @SuppressWarnings("unchecked")
- protected static Class<? extends Principal> getPrincipalClass(
- ClassLoader cl, String className) {
- try {
- return (Class<? extends Principal>) cl.loadClass(className);
- } catch (ClassNotFoundException e) {
- throw new ArgeoException("Cannot load principal class", e);
- }
- }
-
- public Object getPrincipal() {
- return getUser();
- }
-
- public Principal getUser() {
- Subject subject = getSubject();
- Set<? extends Principal> userPrincipals = subject
- .getPrincipals(osUserPrincipalClass);
- if (userPrincipals == null || userPrincipals.size() == 0)
- throw new ArgeoException("No OS principal");
- if (userPrincipals.size() > 1)
- throw new ArgeoException("More than one OS principal");
- Principal user = userPrincipals.iterator().next();
- return user;
- }
-
- public Principal getUserId() {
- Subject subject = getSubject();
- Set<? extends Principal> userIdsPrincipals = subject
- .getPrincipals(osUserIdPrincipalClass);
- if (userIdsPrincipals == null || userIdsPrincipals.size() == 0)
- throw new ArgeoException("No user id principal");
- if (userIdsPrincipals.size() > 1)
- throw new ArgeoException("More than one user id principal");
- Principal userId = userIdsPrincipals.iterator().next();
- return userId;
- }
-
- public Set<? extends Principal> getGroupsIds() {
- Subject subject = getSubject();
- return (Set<? extends Principal>) subject
- .getPrincipals(osGroupIdPrincipalClass);
- }
-
- /** @return the subject always non null */
- protected Subject getSubject() {
- Subject subject = Subject.getSubject(AccessController.getContext());
- if (subject == null)
- throw new ArgeoException("No subject in JAAS context");
- return subject;
- }
-
- public Object getCredentials() {
- return "";
- }
-
-}
+++ /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.security;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-import org.springframework.security.Authentication;
-import org.springframework.security.GrantedAuthority;
-import org.springframework.security.context.SecurityContext;
-import org.springframework.security.context.SecurityContextHolder;
-import org.springframework.security.providers.anonymous.AnonymousAuthenticationToken;
-
-/** Static utilities */
-public class SecurityUtils {
-
- private SecurityUtils() {
- }
-
- /** Whether the current thread has the admin role */
- public static boolean hasCurrentThreadAuthority(String authority) {
- SecurityContext securityContext = SecurityContextHolder.getContext();
- if (securityContext != null) {
- Authentication authentication = securityContext.getAuthentication();
- if (authentication != null) {
- for (GrantedAuthority ga : authentication.getAuthorities())
- if (ga.getAuthority().equals(authority))
- return true;
- }
- }
- return false;
- }
-
- /**
- * @return the authenticated username or null if not authenticated /
- * anonymous
- */
- public static String getCurrentThreadUsername() {
- SecurityContext securityContext = SecurityContextHolder.getContext();
- if (securityContext != null) {
- Authentication authentication = securityContext.getAuthentication();
- if (authentication != null) {
- if (authentication instanceof AnonymousAuthenticationToken) {
- return null;
- }
- return authentication.getName();
- }
- }
- return null;
- }
-
- /**
- * Returns the display name of the user details (by calling toString() on
- * it)
- */
- public static String getUserDetailsDisplayName() {
- SecurityContext securityContext = SecurityContextHolder.getContext();
- if (securityContext != null) {
- Authentication authentication = securityContext.getAuthentication();
- if (authentication != null) {
- if (authentication instanceof AnonymousAuthenticationToken) {
- return null;
- }
- Object details = authentication.getDetails();
- if (details != null)
- return details.toString();
- return authentication.getName();
- }
- }
- return null;
- }
-
- /**
- * Converts an array of Spring Security {@link GrantedAuthority} to a
- * read-only list of strings, for portability and integration
- */
- public static List<String> authoritiesToStringList(
- GrantedAuthority[] authorities) {
- List<String> lst = new ArrayList<String>();
- for (GrantedAuthority ga : authorities)
- lst.add(ga.getAuthority());
- return Collections.unmodifiableList(lst);
- }
-}
+++ /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.security;
-
-/**
- * Marks a system authentication, that is which did not require a login process.
- */
-public interface SystemAuthentication {
-
-}
+++ /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.security;
-
-import java.util.concurrent.Callable;
-import java.util.concurrent.Executor;
-import java.util.concurrent.Future;
-
-/**
- * Allows to execute code authenticated as a system user (that is not a real
- * person). The {@link Executor} interface is not used directly in order to
- * allow future extension of this interface and to simplify its publication
- * (e.g. as an OSGi service) and interception.
- */
-public interface SystemExecutionService extends Executor {
- /**
- * Executes this {@link Runnable} within a system authenticated context.
- * Implementations should make sure that this method is properly secured via
- * Java permissions since it could access everything without credentials.
- */
- public void execute(Runnable runnable);
-
- /**
- * Executes this {@link Callable} within a system authenticated context.
- * Implementations should make sure that this method is properly secured via
- * Java permissions since it could access everything without credentials.
- */
- public <T> Future<T> submit(Callable<T> task);
-}
+++ /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.security;
-
-import java.util.Set;
-
-import org.springframework.security.userdetails.UserDetailsManager;
-
-/** Enrich {@link UserDetailsManager} in order to provide roles semantics. */
-public interface UserAdminService extends UserDetailsManager {
- /**
- * Usernames must match this regexp pattern ({@value #USERNAME_PATTERN}).
- * Thanks to <a href=
- * "http://www.mkyong.com/regular-expressions/how-to-validate-username-with-regular-expression/"
- * >this tip</a> (modified to add upper-case, add '@')
- */
- //public final static String USERNAME_PATTERN = "^[a-zA-Z0-9_-@]{3,64}$";
-
- /**
- * Email addresses must match this regexp pattern ({@value #EMAIL_PATTERN}.
- * Thanks to <a href=
- * "http://www.mkyong.com/regular-expressions/how-to-validate-email-address-with-regular-expression/"
- * >this tip</a>.
- */
- public final static String EMAIL_PATTERN = "^[_A-Za-z0-9-]+(\\.[_A-Za-z0-9-]+)*@[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$";
-
- /*
- * USERS
- */
- /** List all users. */
- public Set<String> listUsers();
-
- /** List users having this role (except the super user). */
- public Set<String> listUsersInRole(String role);
-
- /** Synchronize with the underlying DAO. */
- public void synchronize();
-
- /*
- * ROLES
- */
- public void newRole(String role);
-
- public Set<String> listEditableRoles();
-
- public void deleteRole(String role);
-}
+++ /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.security.core;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.ArgeoException;
-import org.argeo.security.SystemAuthentication;
-import org.springframework.security.Authentication;
-import org.springframework.security.AuthenticationManager;
-import org.springframework.security.context.SecurityContext;
-import org.springframework.security.context.SecurityContextHolder;
-
-/** Provides base method for executing code with system authorization. */
-public abstract class AbstractSystemExecution {
- static {
- // Forces Spring Security to use inheritable strategy
- // FIXME find a better place for forcing spring security mode
- // doesn't work for the time being
-// if (System.getProperty(SecurityContextHolder.SYSTEM_PROPERTY) == null)
-// SecurityContextHolder
-// .setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
- }
-
- private final static Log log = LogFactory
- .getLog(AbstractSystemExecution.class);
- private AuthenticationManager authenticationManager;
- private String systemAuthenticationKey;
-
- /** Whether the current thread was authenticated by this component. */
- private ThreadLocal<Boolean> authenticatedBySelf = new ThreadLocal<Boolean>() {
- protected Boolean initialValue() {
- return false;
- }
- };
-
- /**
- * Authenticate the calling thread to the underlying
- * {@link AuthenticationManager}
- */
- protected void authenticateAsSystem() {
- if (authenticatedBySelf.get())
- return;
- SecurityContext securityContext = SecurityContextHolder.getContext();
- Authentication currentAuth = securityContext.getAuthentication();
- if (currentAuth != null) {
- if (!(currentAuth instanceof SystemAuthentication))
- throw new ArgeoException(
- "System execution on an already authenticated thread: "
- + currentAuth + ", THREAD="
- + Thread.currentThread().getId());
- return;
- }
- // Subject subject = Subject.getSubject(AccessController.getContext());
- // if (subject != null
- // && !subject.getPrincipals(Authentication.class).isEmpty())
- // throw new ArgeoException(
- // "There is already an authenticated subject: " + subject);
-
- String key = systemAuthenticationKey != null ? systemAuthenticationKey
- : System.getProperty(
- InternalAuthentication.SYSTEM_KEY_PROPERTY,
- InternalAuthentication.SYSTEM_KEY_DEFAULT);
- if (key == null)
- throw new ArgeoException("No system key defined");
- Authentication auth = authenticationManager
- .authenticate(new InternalAuthentication(key));
- securityContext.setAuthentication(auth);
- authenticatedBySelf.set(true);
- if (log.isTraceEnabled())
- log.trace("System authenticated");
- }
-
- // /** Removes the authentication from the calling thread. */
- // protected void deauthenticateAsSystem() {
- // // remove the authentication
- // // SecurityContext securityContext = SecurityContextHolder.getContext();
- // // securityContext.setAuthentication(null);
- // // authenticatedBySelf.set(false);
- // if (log.isTraceEnabled()) {
- // log.trace("System deauthenticated");
- // // Thread.dumpStack();
- // }
- // }
-
- /**
- * Whether the current thread was authenticated by this component or a
- * parent thread.
- */
- protected Boolean isAuthenticatedBySelf() {
- return authenticatedBySelf.get();
- }
-
- public void setAuthenticationManager(
- AuthenticationManager authenticationManager) {
- this.authenticationManager = authenticationManager;
- }
-
- public void setSystemAuthenticationKey(String systemAuthenticationKey) {
- this.systemAuthenticationKey = systemAuthenticationKey;
- }
-
-}
+++ /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.security.core;
-
-import org.argeo.security.SystemExecutionService;
-import org.springframework.core.task.SimpleAsyncTaskExecutor;
-
-/**
- * Asynchronous Spring TaskExecutor (for use in JMS for example) wrapping a
- * {@link SystemExecutionService}.
- */
-public class AsyncSystemTaskExecutor extends SimpleAsyncTaskExecutor {
- private static final long serialVersionUID = -8035527542087963068L;
-
- private SystemExecutionService systemExecutionService;
-
- public AsyncSystemTaskExecutor() {
- super();
- }
-
- public AsyncSystemTaskExecutor(String threadNamePrefix) {
- super(threadNamePrefix);
- }
-
- @Override
- public Thread createThread(final Runnable runnable) {
- Runnable systemExecutionRunnable = new Runnable() {
-
- public void run() {
- systemExecutionService.execute(runnable);
-
- }
- };
- return super.createThread(systemExecutionRunnable);
- }
-
- public void setSystemExecutionService(
- SystemExecutionService systemExecutionService) {
- this.systemExecutionService = systemExecutionService;
- }
-
-}
+++ /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.security.core;
-
-import java.beans.PropertyDescriptor;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.springframework.beans.BeansException;
-import org.springframework.beans.PropertyValues;
-import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
-import org.springframework.context.ApplicationEvent;
-import org.springframework.context.ApplicationListener;
-import org.springframework.context.event.ContextRefreshedEvent;
-
-/**
- * Executes with a system authentication the instantiation and initialization
- * methods of the application context where it has been defined.
- */
-public class AuthenticatedApplicationContextInitialization extends
- AbstractSystemExecution implements InstantiationAwareBeanPostProcessor,
- ApplicationListener {
- // private Log log = LogFactory
- // .getLog(AuthenticatedApplicationContextInitialization.class);
- /** If non empty, restricts to these beans */
- private List<String> beanNames = new ArrayList<String>();
-
- @SuppressWarnings("rawtypes")
- public Object postProcessBeforeInstantiation(Class beanClass,
- String beanName) throws BeansException {
- // we authenticate when any bean is instantiated
- // we will deauthenticate only when the application context has been
- // refreshed in order to be able to deal with factory beans has well
- if (!isAuthenticatedBySelf()) {
- if (beanNames.size() == 0)
- authenticateAsSystem();
- else if (beanNames.contains(beanName))
- authenticateAsSystem();
- }
- return null;
- }
-
- public boolean postProcessAfterInstantiation(Object bean, String beanName)
- throws BeansException {
- return true;
- }
-
- public PropertyValues postProcessPropertyValues(PropertyValues pvs,
- PropertyDescriptor[] pds, Object bean, String beanName)
- throws BeansException {
- return pvs;
- }
-
- public Object postProcessBeforeInitialization(Object bean, String beanName)
- throws BeansException {
- // authenticateAsSystem();
- return bean;
- }
-
- public Object postProcessAfterInitialization(Object bean, String beanName)
- throws BeansException {
- // NOTE: in case there was an exception in on the initialization method
- // we expect the underlying thread to die and thus the system
- // authentication to be lost. We have currently no way to catch the
- // exception and perform the deauthentication by ourselves.
- // deauthenticateAsSystem();
- return bean;
- }
-
- public void onApplicationEvent(ApplicationEvent event) {
- if (event instanceof ContextRefreshedEvent) {
- // make sure that we have deauthenticated after the application
- // context was initialized/refreshed
- // deauthenticateAsSystem();
- }
- }
-
- public void setBeanNames(List<String> beanNames) {
- this.beanNames = beanNames;
- }
-
-}
+++ /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.security.core;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.springframework.beans.factory.InitializingBean;
-
-/**
- * Maintains a list of authentication providers injected in to a provider
- * manager, in order to avoid issues with OSGi services and use packages.
- */
-public class AuthenticationProvidersRegister implements InitializingBean {
- private Log log = LogFactory.getLog(AuthenticationProvidersRegister.class);
-
- private List<Object> providers = new ArrayList<Object>();
- private List<Object> defaultProviders = new ArrayList<Object>();
-
- public void register(Object authenticationProvider,
- Map<String, String> parameters) {
- providers.add(authenticationProvider);
- if (log.isTraceEnabled())
- log.trace("Registered authentication provider " + parameters);
- }
-
- public void unregister(Object authenticationProvider,
- Map<String, String> parameters) {
- providers.remove(authenticationProvider);
- if (log.isTraceEnabled())
- log.trace("Unregistered authentication provider " + parameters);
- }
-
- public List<Object> getProviders() {
- return providers;
- }
-
- public void setDefaultProviders(
- List<Object> defaultProviders) {
- this.defaultProviders = defaultProviders;
- }
-
- public void afterPropertiesSet() throws Exception {
- providers.addAll(defaultProviders);
- }
-
-}
+++ /dev/null
-package org.argeo.security.core;
-
-import java.io.Console;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.util.Arrays;
-import java.util.Locale;
-
-import javax.security.auth.callback.Callback;
-import javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.callback.NameCallback;
-import javax.security.auth.callback.PasswordCallback;
-import javax.security.auth.callback.TextOutputCallback;
-import javax.security.auth.callback.UnsupportedCallbackException;
-
-import org.argeo.ArgeoException;
-import org.argeo.util.LocaleCallback;
-
-/** Callback handler to be used with a command line UI. */
-public class ConsoleCallbackHandler implements CallbackHandler {
-
- @Override
- public void handle(Callback[] callbacks) throws IOException,
- UnsupportedCallbackException {
- Console console = System.console();
- if (console == null)
- throw new ArgeoException("No console available");
-
- PrintWriter writer = console.writer();
- for (int i = 0; i < callbacks.length; i++) {
- if (callbacks[i] instanceof TextOutputCallback) {
- TextOutputCallback callback = (TextOutputCallback) callbacks[i];
- writer.write(callback.getMessage());
- } else if (callbacks[i] instanceof NameCallback) {
- NameCallback callback = (NameCallback) callbacks[i];
- writer.write(callback.getPrompt());
- if (callback.getDefaultName() != null)
- writer.write(" (" + callback.getDefaultName() + ")");
- writer.write(" : ");
- String answer = console.readLine();
- if (callback.getDefaultName() != null
- && answer.trim().equals(""))
- callback.setName(callback.getDefaultName());
- else
- callback.setName(answer);
- } else if (callbacks[i] instanceof PasswordCallback) {
- PasswordCallback callback = (PasswordCallback) callbacks[i];
- writer.write(callback.getPrompt());
- char[] answer = console.readPassword();
- callback.setPassword(answer);
- Arrays.fill(answer, ' ');
- } else if (callbacks[i] instanceof LocaleCallback) {
- LocaleCallback callback = (LocaleCallback) callbacks[i];
- writer.write(callback.getPrompt());
- writer.write("\n");
- for (int j = 0; j < callback.getAvailableLocales().size(); j++) {
- Locale locale = callback.getAvailableLocales().get(j);
- writer.print(j + " : " + locale.getDisplayName() + "\n");
- }
- writer.write("(" + callback.getDefaultIndex() + ") : ");
- String answer = console.readLine();
- if (answer.trim().equals(""))
- callback.setSelectedIndex(callback.getDefaultIndex());
- else
- callback.setSelectedIndex(new Integer(answer.trim()));
- }
- }
- }
-
-}
+++ /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.security.core;
-
-import org.argeo.security.SystemAuthentication;
-import org.springframework.security.GrantedAuthority;
-import org.springframework.security.GrantedAuthorityImpl;
-import org.springframework.security.adapters.PrincipalSpringSecurityUserToken;
-
-/** A token base on a system key used to request a system authentication. */
-public class InternalAuthentication extends PrincipalSpringSecurityUserToken
- implements SystemAuthentication {
- private static final long serialVersionUID = -6783376375615949315L;
- /** 'admin' for consistency with JCR */
- public final static String DEFAULT_SYSTEM_USERNAME = "admin";
- public final static String DEFAULT_SYSTEM_ROLE = "ROLE_SYSTEM";
- public final static String SYSTEM_KEY_PROPERTY = "argeo.security.systemKey";
- public final static String SYSTEM_KEY_DEFAULT = "argeo";
-
- public InternalAuthentication(String key, String systemUsername,
- String systemRole) {
- super(
- key,
- systemUsername,
- key,
- new GrantedAuthority[] { new GrantedAuthorityImpl(systemRole) },
- systemUsername);
- }
-
- public InternalAuthentication(String key) {
- this(key, DEFAULT_SYSTEM_USERNAME, DEFAULT_SYSTEM_ROLE);
- }
-
-}
+++ /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.security.core;
-
-import java.util.concurrent.Callable;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-import java.util.concurrent.FutureTask;
-
-import org.argeo.ArgeoException;
-import org.argeo.security.SystemExecutionService;
-
-/**
- * Implementation of a {@link SystemExecutionService} using a key-based
- * {@link InternalAuthentication}
- */
-public class KeyBasedSystemExecutionService extends AbstractSystemExecution
- implements SystemExecutionService {
- public void execute(Runnable runnable) {
- try {
- wrapWithSystemAuthentication(Executors.callable(runnable)).call();
- } catch (RuntimeException e) {
- throw e;
- } catch (Exception e) {
- throw new ArgeoException(
- "Exception when running system authenticated task", e);
- }
- }
-
- public <T> Future<T> submit(Callable<T> task) {
- FutureTask<T> future = new FutureTask<T>(
- wrapWithSystemAuthentication(task));
- future.run();
- return future;
- }
-
- protected <T> Callable<T> wrapWithSystemAuthentication(
- final Callable<T> runnable) {
- return new Callable<T>() {
-
- public T call() throws Exception {
- authenticateAsSystem();
- try {
- return runnable.call();
- } finally {
-// deauthenticateAsSystem();
- }
- }
- };
- }
-}
+++ /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.security.core;
-
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Properties;
-
-import org.springframework.core.io.Resource;
-import org.springframework.security.AuthenticationException;
-import org.springframework.security.BadCredentialsException;
-import org.springframework.security.GrantedAuthority;
-import org.springframework.security.GrantedAuthorityImpl;
-import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
-import org.springframework.security.providers.dao.AbstractUserDetailsAuthenticationProvider;
-import org.springframework.security.userdetails.User;
-import org.springframework.security.userdetails.UserDetails;
-
-/** @deprecated */
-@Deprecated
-public class MatchingAuthenticationProvider extends
- AbstractUserDetailsAuthenticationProvider {
-
- private Resource mapping;
- private Properties properties;
-
- private List<String> defaultRoles = new ArrayList<String>();
-
- @Override
- protected void doAfterPropertiesSet() throws Exception {
- properties = new Properties();
- InputStream propIn = mapping.getInputStream();
- try {
- properties.load(propIn);
- } finally {
- propIn.close();
- }
- }
-
- @Override
- protected void additionalAuthenticationChecks(UserDetails userDetails,
- UsernamePasswordAuthenticationToken authentication)
- throws AuthenticationException {
- if (!userDetails.getPassword().equals(authentication.getCredentials()))
- throw new BadCredentialsException(
- "Invalid credentails provided by "
- + authentication.getName());
- }
-
- @Override
- protected UserDetails retrieveUser(String username,
- UsernamePasswordAuthenticationToken authentication)
- throws AuthenticationException {
- String value = properties.getProperty(username);
- if (value == null)
- throw new BadCredentialsException("User " + username
- + " is not registered");
- List<GrantedAuthority> grantedAuthorities = new ArrayList<GrantedAuthority>();
- for (String role : defaultRoles)
- grantedAuthorities.add(new GrantedAuthorityImpl(role));
- return new User(
- username,
- value,
- true,
- true,
- true,
- true,
- grantedAuthorities
- .toArray(new GrantedAuthority[grantedAuthorities.size()]));
- }
-
- public void setMapping(Resource mapping) {
- this.mapping = mapping;
- }
-
- public void setDefaultRoles(List<String> defaultRoles) {
- this.defaultRoles = defaultRoles;
- }
-
-}
+++ /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.security.core;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.argeo.security.OsAuthenticationToken;
-import org.springframework.security.Authentication;
-import org.springframework.security.AuthenticationException;
-import org.springframework.security.GrantedAuthority;
-import org.springframework.security.GrantedAuthorityImpl;
-import org.springframework.security.providers.AuthenticationProvider;
-
-/**
- * Validates an OS authentication. The id is that it will always be
- * authenticated since we are always runnign within an OS, but the fact that the
- * {@link Authentication} works properly depends on the proper OS login module
- * having been called as well. TODO make it more configurable (base roles, is
- * admin)
- */
-public class OsAuthenticationProvider implements AuthenticationProvider {
- final static String osUserRole = "ROLE_OS_USER";
- final static String userRole = "ROLE_USER";
- final static String adminRole = "ROLE_ADMIN";
-
- final static Boolean isAdmin = true;
-
- public Authentication authenticate(Authentication authentication)
- throws AuthenticationException {
- return new OsAuthenticationToken(getBaseAuthorities());
- }
-
- public static GrantedAuthority[] getBaseAuthorities() {
- List<GrantedAuthority> auths = new ArrayList<GrantedAuthority>();
- auths.add(new GrantedAuthorityImpl(osUserRole));
- auths.add(new GrantedAuthorityImpl(userRole));
- if (isAdmin)
- auths.add(new GrantedAuthorityImpl(adminRole));
- return auths.toArray(new GrantedAuthority[auths.size()]);
- }
-
- @SuppressWarnings("rawtypes")
- public boolean supports(Class authentication) {
- return OsAuthenticationToken.class.isAssignableFrom(authentication);
- }
-
-}
+++ /dev/null
-package org.argeo.security.core;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.Constants;
-
-/**
- * Logs the name and version of an OSGi bundle based on its
- * {@link BundleContext}.
- */
-public class OsgiModuleLabel {
- private final static Log log = LogFactory.getLog(OsgiModuleLabel.class);
-
- private Bundle bundle;
-
- public OsgiModuleLabel() {
- }
-
- /** Sets without logging. */
- public OsgiModuleLabel(Bundle bundle) {
- this.bundle = bundle;
- }
-
- /**
- * Retrieved bundle from a bundle context and logs it. Typically to be set
- * as a Spring bean.
- */
- public void setBundleContext(BundleContext bundleContext) {
- this.bundle = bundleContext.getBundle();
- log.info(msg());
- }
-
- public String msg() {
- String name = bundle.getHeaders().get(Constants.BUNDLE_NAME).toString();
- String symbolicName = bundle.getSymbolicName();
- String version = bundle.getVersion().toString();
- return name + " v" + version + " (" + symbolicName + ")";
- }
-}
+++ /dev/null
-package org.argeo.security.core;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.security.UserAdminService;
-
-/**
- * Register one or many roles via a user admin service. Does nothing if the role
- * is already registered.
- */
-public class SimpleRoleRegistration implements Runnable {
- private final static Log log = LogFactory
- .getLog(SimpleRoleRegistration.class);
-
- private String role;
- private List<String> roles = new ArrayList<String>();
- private UserAdminService userAdminService;
-
- @Override
- public void run() {
- Set<String> existingRoles = userAdminService.listEditableRoles();
- if (role != null && !existingRoles.contains(role))
- newRole(role);
- for (String r : roles) {
- if (!existingRoles.contains(r))
- newRole(r);
- }
- }
-
- protected void newRole(String r) {
- userAdminService.newRole(r);
- log.info("Added role " + r + " required by application.");
- }
-
- public void register(UserAdminService userAdminService, Map<?, ?> properties) {
- this.userAdminService = userAdminService;
- run();
- }
-
- public void setRole(String role) {
- this.role = role;
- }
-
- public void setRoles(List<String> roles) {
- this.roles = roles;
- }
-
- public void setUserAdminService(UserAdminService userAdminService) {
- this.userAdminService = userAdminService;
- }
-
-}
+++ /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.security.crypto;
-
-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.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, CryptoKeyring {
- static {
- Security.addProvider(new BouncyCastleProvider());
- }
-
- 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 ArgeoException("Keyring login failed", e);
- }
-
- } else {
- SecretKey secretKey = iterator.next();
- if (iterator.hasNext())
- throw new ArgeoException(
- "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 ArgeoException("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 ArgeoException("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 ArgeoException("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 ArgeoException("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
-/*
- * 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.security.crypto;
-
-import org.argeo.util.security.Keyring;
-
-/**
- * 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.security.crypto;
-
-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.security.crypto;
-
-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.security.crypto;
-
-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 java.security.Security;
-
-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.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.ArgeoException;
-import org.argeo.StreamUtils;
-import org.bouncycastle.jce.provider.BouncyCastleProvider;
-
-/** Simple password based encryption / decryption */
-public class PasswordBasedEncryption {
- private final static Log log = LogFactory
- .getLog(PasswordBasedEncryption.class);
-
- static {
- Security.addProvider(new BouncyCastleProvider());
- }
-
- 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;
-
- /**
- * 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
- */
- 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;
- log.warn("'" + e.getMessage() + "', will use " + secreteKeyLength
- + " secrete key length instead of "
- + previousSecreteKeyLength);
- try {
- initKeyAndCiphers(password, passwordSalt, initializationVector);
- } catch (Exception e1) {
- throw new ArgeoException(
- "Cannot get secret key (with restricted length)", e1);
- }
- } catch (Exception e) {
- throw new ArgeoException("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);
- }
- ecipher = Cipher.getInstance(getCipherName(), securityProviderName);
- 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 ArgeoException("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 ArgeoException("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 ArgeoException("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 ArgeoException("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.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;
-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.ArgeoException;
-import org.argeo.jcr.ArgeoNames;
-import org.argeo.jcr.ArgeoTypes;
-import org.argeo.jcr.JcrUtils;
-import org.argeo.jcr.UserJcrUtils;
-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 {
- /**
- * 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 = UserJcrUtils.getUserHome(session);
- return userHome.hasNode(ARGEO_KEYRING);
- } catch (RepositoryException e) {
- throw new ArgeoException("Cannot check whether keyring is setup", e);
- }
- }
-
- @Override
- protected void setup(char[] password) {
- Binary binary = null;
- InputStream in = null;
- try {
- Node userHome = UserJcrUtils.getUserHome(session);
- if (userHome.hasNode(ARGEO_KEYRING))
- throw new ArgeoException("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);
-
- // 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 ArgeoException("Cannot setup keyring", e);
- } finally {
- JcrUtils.closeQuietly(binary);
- IOUtils.closeQuietly(in);
- // JcrUtils.discardQuietly(session);
- }
- }
-
- @Override
- protected void handleKeySpecCallback(PBEKeySpecCallback pbeCallback) {
- try {
- Node userHome = UserJcrUtils.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 ArgeoException("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 ArgeoException("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 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));
- 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 ArgeoException("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 ArgeoException("Cannot decrypt", e);
- } finally {
- IOUtils.closeQuietly(encrypted);
- IOUtils.closeQuietly(reader);
- JcrUtils.closeQuietly(binary);
- }
- }
-
- protected Cipher createCipher() {
- try {
- Node userHome = UserJcrUtils.getUserHome(session);
- if (!userHome.hasNode(ARGEO_KEYRING))
- throw new ArgeoException("Keyring not setup");
- Node keyring = userHome.getNode(ARGEO_KEYRING);
- Cipher cipher = Cipher.getInstance(keyring
- .getProperty(ARGEO_CIPHER).getString(),
- getSecurityProvider());
- return cipher;
- } catch (Exception e) {
- throw new ArgeoException("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.security.jcr;
-
-import java.util.List;
-
-import javax.jcr.Node;
-import javax.jcr.Session;
-
-/**
- * Manages data expected by the Argeo security model, such as user home and
- * profile.
- */
-public interface JcrSecurityModel {
- /**
- * To be called before user details are loaded. Make sure than any logged in
- * user has a home directory with full access and a profile with information
- * about him (read access)
- *
- * @return the user profile (whose parent is the user home), never null
- */
- public Node sync(Session session, String username, List<String> roles);
-}
+++ /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.security.jcr;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.jcr.Node;
-import javax.jcr.Property;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-
-import org.argeo.jcr.ArgeoNames;
-import org.argeo.jcr.UserJcrUtils;
-import org.springframework.security.BadCredentialsException;
-import org.springframework.security.DisabledException;
-import org.springframework.security.GrantedAuthority;
-import org.springframework.security.GrantedAuthorityImpl;
-import org.springframework.security.LockedException;
-import org.springframework.security.userdetails.User;
-
-/** User details based on a user profile node. */
-public class JcrUserDetails extends User implements ArgeoNames {
- private static final long serialVersionUID = -8142764995842559646L;
- private final String homePath;
- private final String securityWorkspace;
-
- /** Human readable user name */
- private String displayName;
-
- protected JcrUserDetails(String securityWorkspace, String homePath,
- String username, String password, boolean enabled,
- boolean accountNonExpired, boolean credentialsNonExpired,
- boolean accountNonLocked, GrantedAuthority[] authorities)
- throws IllegalArgumentException {
- super(username, password, enabled, accountNonExpired,
- credentialsNonExpired, accountNonLocked, authorities);
- this.homePath = homePath;
- this.securityWorkspace = securityWorkspace;
- }
-
- public JcrUserDetails(Node userProfile, String password,
- GrantedAuthority[] authorities) throws RepositoryException {
- super(
- userProfile.getProperty(ARGEO_USER_ID).getString(),
- password,
- userProfile.getProperty(ARGEO_ENABLED).getBoolean(),
- userProfile.getProperty(ARGEO_ACCOUNT_NON_EXPIRED).getBoolean(),
- userProfile.getProperty(ARGEO_CREDENTIALS_NON_EXPIRED)
- .getBoolean(), userProfile.getProperty(
- ARGEO_ACCOUNT_NON_LOCKED).getBoolean(), authorities);
- // human readable name
- if (userProfile.hasProperty(Property.JCR_TITLE)) {
- displayName = userProfile.getProperty(Property.JCR_TITLE)
- .getString();
- if (displayName.trim().equals(""))
- displayName = null;
- }
- if (displayName == null)
- displayName = userProfile.getProperty(ARGEO_USER_ID).getString();
- // home is defined as the parent of the profile
- homePath = userProfile.getParent().getPath();
- securityWorkspace = userProfile.getSession().getWorkspace().getName();
- }
-
- /**
- * Convenience constructor
- *
- * @param session
- * the security session
- * @param username
- * the username
- * @param password
- * the password, can be null
- * @param authorities
- * the granted authorities
- */
- public JcrUserDetails(Session session, String username, String password,
- GrantedAuthority[] authorities) throws RepositoryException {
- this(UserJcrUtils.getUserProfile(session, username),
- password != null ? password : "", authorities);
- }
-
- /**
- * Check the account status in JCR, throwing the exceptions expected by
- * Spring security if needed.
- */
- public static void checkAccountStatus(Node userProfile) {
- try {
- if (!userProfile.getProperty(ARGEO_ENABLED).getBoolean())
- throw new DisabledException(userProfile.getPath()
- + " is disabled");
- if (!userProfile.getProperty(ARGEO_ACCOUNT_NON_LOCKED).getBoolean())
- throw new LockedException(userProfile.getPath() + " is locked");
- } catch (RepositoryException e) {
- throw new BadCredentialsException("Cannot check account status", e);
- }
- }
-
- /** Clone immutable with new roles */
- public JcrUserDetails cloneWithNewRoles(List<String> roles) {
- List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
- for (String role : roles) {
- authorities.add(new GrantedAuthorityImpl(role));
- }
- return new JcrUserDetails(securityWorkspace, homePath, getUsername(),
- getPassword(), isEnabled(), isAccountNonExpired(),
- isAccountNonExpired(), isAccountNonLocked(),
- authorities.toArray(new GrantedAuthority[authorities.size()]));
- }
-
- /** Clone immutable with new password */
- public JcrUserDetails cloneWithNewPassword(String password) {
- return new JcrUserDetails(securityWorkspace, homePath, getUsername(),
- password, isEnabled(), isAccountNonExpired(),
- isAccountNonExpired(), isAccountNonLocked(), getAuthorities());
- }
-
- public String getHomePath() {
- return homePath;
- }
-
- /** Not yet API */
- public String getSecurityWorkspace() {
- return securityWorkspace;
- }
-
- /** The human readable name of this user */
- public String getDisplayName() {
- return displayName;
- }
-
- @Override
- public String toString() {
- return getDisplayName();
- }
-
-}
+++ /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.security.jcr;
-
-import javax.jcr.Node;
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-
-import org.argeo.ArgeoException;
-import org.argeo.jcr.JcrUtils;
-import org.argeo.security.OsAuthenticationToken;
-import org.argeo.security.SecurityUtils;
-import org.argeo.security.core.OsAuthenticationProvider;
-import org.springframework.security.Authentication;
-import org.springframework.security.AuthenticationException;
-import org.springframework.security.BadCredentialsException;
-import org.springframework.security.GrantedAuthority;
-import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
-import org.springframework.security.userdetails.UserDetails;
-
-/** Relies on OS to authenticate and additionally setup JCR */
-public class OsJcrAuthenticationProvider extends OsAuthenticationProvider {
- private Repository repository;
- private Session nodeSession;
-
- private UserDetails userDetails;
- private JcrSecurityModel jcrSecurityModel = new SimpleJcrSecurityModel();
-
- private final static String JVM_OSUSER = System.getProperty("user.name");
-
- public void init() {
- try {
- nodeSession = repository.login();
- } catch (RepositoryException e) {
- throw new ArgeoException("Cannot initialize", e);
- }
- }
-
- public void destroy() {
- JcrUtils.logoutQuietly(nodeSession);
- }
-
- public Authentication authenticate(Authentication authentication)
- throws AuthenticationException {
- if (authentication instanceof UsernamePasswordAuthenticationToken) {
- // deal with remote access to internal server
- // FIXME very primitive and unsecure at this sSession adminSession
- // =tage
- // consider using the keyring for username / password authentication
- // or certificate
- UsernamePasswordAuthenticationToken upat = (UsernamePasswordAuthenticationToken) authentication;
- if (!upat.getPrincipal().toString().equals(JVM_OSUSER))
- throw new BadCredentialsException("Wrong credentials");
- UsernamePasswordAuthenticationToken authen = new UsernamePasswordAuthenticationToken(
- authentication.getPrincipal(),
- authentication.getCredentials(), getBaseAuthorities());
- authen.setDetails(userDetails);
- return authen;
- } else if (authentication instanceof OsAuthenticationToken) {
- OsAuthenticationToken authen = (OsAuthenticationToken) super
- .authenticate(authentication);
- try {
- // WARNING: at this stage we assume that the java properties
- // will have the same value
- GrantedAuthority[] authorities = getBaseAuthorities();
- String username = JVM_OSUSER;
- Node userProfile = jcrSecurityModel.sync(nodeSession, username,
- SecurityUtils.authoritiesToStringList(authorities));
- JcrUserDetails.checkAccountStatus(userProfile);
-
- userDetails = new JcrUserDetails(userProfile, authen
- .getCredentials().toString(), authorities);
- authen.setDetails(userDetails);
- return authen;
- } catch (RepositoryException e) {
- JcrUtils.discardQuietly(nodeSession);
- throw new ArgeoException(
- "Unexpected exception when synchronizing OS and JCR security ",
- e);
- }
- } else {
- throw new ArgeoException("Unsupported authentication "
- + authentication.getClass());
- }
- }
-
- public void setRepository(Repository repository) {
- this.repository = repository;
- }
-
- public void setJcrSecurityModel(JcrSecurityModel jcrSecurityModel) {
- this.jcrSecurityModel = jcrSecurityModel;
- }
-
- @SuppressWarnings("rawtypes")
- public boolean supports(Class authentication) {
- return OsAuthenticationToken.class.isAssignableFrom(authentication)
- || UsernamePasswordAuthenticationToken.class
- .isAssignableFrom(authentication);
- }
-}
\ 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.security.jcr;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import javax.jcr.Node;
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-
-import org.argeo.ArgeoException;
-import org.argeo.jcr.JcrUtils;
-import org.argeo.jcr.UserJcrUtils;
-import org.argeo.security.UserAdminService;
-import org.springframework.dao.DataAccessException;
-import org.springframework.security.userdetails.User;
-import org.springframework.security.userdetails.UserDetails;
-import org.springframework.security.userdetails.UsernameNotFoundException;
-
-/**
- * Dummy user service to be used when running as a single OS user (typically
- * desktop). TODO integrate with JCR user / groups
- */
-public class OsJcrUserAdminService implements UserAdminService {
- private Repository repository;
-
- /** In memory roles provided by applications. */
- private List<String> roles = new ArrayList<String>();
-
- // private Session adminSession;
-
- public void init() {
- // try {
- // adminSession = repository.login();
- // } catch (RepositoryException e) {
- // throw new ArgeoException("Cannot initialize", e);
- // }
- }
-
- public void destroy() {
- // JcrUtils.logoutQuietly(adminSession);
- }
-
- /** <b>Unsupported</b> */
- public void createUser(UserDetails user) {
- throw new UnsupportedOperationException();
- }
-
- /** Does nothing */
- public void updateUser(UserDetails user) {
-
- }
-
- /** <b>Unsupported</b> */
- public void deleteUser(String username) {
- throw new UnsupportedOperationException();
- }
-
- /** <b>Unsupported</b> */
- public void changePassword(String oldPassword, String newPassword) {
- throw new UnsupportedOperationException();
- }
-
- public boolean userExists(String username) {
- if (getSPropertyUsername().equals(username))
- return true;
- else
- return false;
- }
-
- public UserDetails loadUserByUsername(String username)
- throws UsernameNotFoundException, DataAccessException {
- if (getSPropertyUsername().equals(username)) {
- UserDetails userDetails;
- if (repository != null) {
- Session adminSession = null;
- try {
- adminSession = repository.login();
- Node userProfile = UserJcrUtils.getUserProfile(
- adminSession, username);
- userDetails = new JcrUserDetails(userProfile, "",
- OsJcrAuthenticationProvider.getBaseAuthorities());
- } catch (RepositoryException e) {
- throw new ArgeoException(
- "Cannot retrieve user profile for " + username, e);
- } finally {
- JcrUtils.logoutQuietly(adminSession);
- }
- } else {
- userDetails = new User(username, "", true, true, true, true,
- OsJcrAuthenticationProvider.getBaseAuthorities());
- }
- return userDetails;
- } else {
- throw new UnsupportedOperationException();
- }
- }
-
- protected final String getSPropertyUsername() {
- return System.getProperty("user.name");
- }
-
- public Set<String> listUsers() {
- Set<String> set = new HashSet<String>();
- set.add(getSPropertyUsername());
- return set;
- }
-
- public Set<String> listUsersInRole(String role) {
- Set<String> set = new HashSet<String>();
- set.add(getSPropertyUsername());
- return set;
- }
-
- /** Does nothing */
- public void synchronize() {
- }
-
- /** <b>Unsupported</b> */
- public void newRole(String role) {
- roles.add(role);
- }
-
- public Set<String> listEditableRoles() {
- return new HashSet<String>(roles);
- }
-
- /** <b>Unsupported</b> */
- public void deleteRole(String role) {
- roles.remove(role);
- }
-
- public void setRepository(Repository repository) {
- this.repository = repository;
- }
-}
+++ /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.security.jcr;
-
-import java.util.ArrayList;
-import java.util.Dictionary;
-import java.util.Hashtable;
-import java.util.List;
-
-import javax.jcr.Node;
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-import javax.jcr.RepositoryFactory;
-import javax.jcr.Session;
-import javax.jcr.SimpleCredentials;
-import javax.jcr.Value;
-
-import org.argeo.ArgeoException;
-import org.argeo.jcr.ArgeoJcrConstants;
-import org.argeo.jcr.ArgeoNames;
-import org.argeo.jcr.UserJcrUtils;
-import org.argeo.security.NodeAuthenticationToken;
-import org.osgi.framework.BundleContext;
-import org.springframework.security.Authentication;
-import org.springframework.security.AuthenticationException;
-import org.springframework.security.BadCredentialsException;
-import org.springframework.security.GrantedAuthority;
-import org.springframework.security.GrantedAuthorityImpl;
-import org.springframework.security.providers.AuthenticationProvider;
-
-/** Connects to a JCR repository and delegates authentication to it. */
-public class RemoteJcrAuthenticationProvider implements AuthenticationProvider,
- ArgeoNames {
- private RepositoryFactory repositoryFactory;
- private BundleContext bundleContext;
-
- public final static String ROLE_REMOTE = "ROLE_REMOTE";
-
- public Authentication authenticate(Authentication authentication)
- throws AuthenticationException {
- NodeAuthenticationToken siteAuth = (NodeAuthenticationToken) authentication;
- String url = siteAuth.getUrl();
- if (url == null)// TODO? login on own node
- throw new ArgeoException("No url set in " + siteAuth);
- Session session;
-
- Node userProfile;
- try {
- SimpleCredentials sp = new SimpleCredentials(siteAuth.getName(),
- siteAuth.getCredentials().toString().toCharArray());
- // get repository
- Repository repository = new RemoteJcrRepositoryWrapper(
- repositoryFactory, url, sp);
- if (bundleContext != null) {
- Dictionary<String, String> serviceProperties = new Hashtable<String, String>();
- serviceProperties.put(ArgeoJcrConstants.JCR_REPOSITORY_ALIAS,
- ArgeoJcrConstants.ALIAS_NODE);
- serviceProperties
- .put(ArgeoJcrConstants.JCR_REPOSITORY_URI, url);
- bundleContext.registerService(Repository.class.getName(),
- repository, serviceProperties);
- }
- // Repository repository = ArgeoJcrUtils.getRepositoryByUri(
- // repositoryFactory, url);
- // if (repository == null)
- // throw new ArgeoException("Cannot connect to " + url);
-
- session = repository.login(sp, null);
-
- userProfile = UserJcrUtils.getUserProfile(session, sp.getUserID());
- JcrUserDetails.checkAccountStatus(userProfile);
-
- // Node userHome = UserJcrUtils.getUserHome(session);
- // if (userHome == null ||
- // !userHome.hasNode(ArgeoNames.ARGEO_PROFILE))
- // throw new ArgeoException("No profile for user "
- // + siteAuth.getName() + " in security workspace "
- // + siteAuth.getSecurityWorkspace() + " of "
- // + siteAuth.getUrl());
- // userProfile = userHome.getNode(ArgeoNames.ARGEO_PROFILE);
- } catch (RepositoryException e) {
- throw new BadCredentialsException(
- "Cannot authenticate " + siteAuth, e);
- }
-
- try {
- // Node userHome = UserJcrUtils.getUserHome(session);
- // retrieve remote roles
- List<GrantedAuthority> authoritiesList = new ArrayList<GrantedAuthority>();
- if (userProfile != null
- && userProfile.hasProperty(ArgeoNames.ARGEO_REMOTE_ROLES)) {
- Value[] roles = userProfile.getProperty(
- ArgeoNames.ARGEO_REMOTE_ROLES).getValues();
- for (int i = 0; i < roles.length; i++)
- authoritiesList.add(new GrantedAuthorityImpl(roles[i]
- .getString()));
- }
- authoritiesList.add(new GrantedAuthorityImpl(ROLE_REMOTE));
-
- // create authenticated objects
- GrantedAuthority[] authorities = authoritiesList
- .toArray(new GrantedAuthority[authoritiesList.size()]);
- JcrUserDetails userDetails = new JcrUserDetails(userProfile,
- siteAuth.getCredentials().toString(), authorities);
- NodeAuthenticationToken authenticated = new NodeAuthenticationToken(
- siteAuth, authorities);
- authenticated.setDetails(userDetails);
- return authenticated;
- } catch (RepositoryException e) {
- throw new ArgeoException(
- "Unexpected exception when authenticating to " + url, e);
- }
- }
-
- @SuppressWarnings("rawtypes")
- public boolean supports(Class authentication) {
- return NodeAuthenticationToken.class.isAssignableFrom(authentication);
- }
-
- public void setRepositoryFactory(RepositoryFactory repositoryFactory) {
- this.repositoryFactory = repositoryFactory;
- }
-
- public void setBundleContext(BundleContext bundleContext) {
- this.bundleContext = bundleContext;
- }
-
-}
+++ /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.security.jcr;
-
-import javax.jcr.Credentials;
-import javax.jcr.LoginException;
-import javax.jcr.NoSuchWorkspaceException;
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-import javax.jcr.RepositoryFactory;
-import javax.jcr.Session;
-import javax.jcr.SimpleCredentials;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.ArgeoException;
-import org.argeo.jcr.ArgeoJcrUtils;
-import org.argeo.jcr.JcrRepositoryWrapper;
-import org.argeo.security.NodeAuthenticationToken;
-import org.argeo.security.SystemAuthentication;
-import org.springframework.security.Authentication;
-import org.springframework.security.context.SecurityContextHolder;
-import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
-
-/**
- * Wrapper around a remote Jackrabbit repository which allows to simplify
- * configuration and intercept some actions. It exposes itself as a
- * {@link Repository}.
- */
-public class RemoteJcrRepositoryWrapper extends JcrRepositoryWrapper {
- private final static Log log = LogFactory
- .getLog(RemoteJcrRepositoryWrapper.class);
-
- private String uri = null;
-
- private RepositoryFactory repositoryFactory;
-
- // remote
- private Credentials remoteSystemCredentials = null;
-
- /**
- * Empty constructor, {@link #init()} should be called after properties have
- * been set
- */
- public RemoteJcrRepositoryWrapper() {
- }
-
- /**
- * Embedded constructor, calling the {@link #init()} method.
- *
- * @param alias
- * if not null the repository will be published under this alias
- */
- public RemoteJcrRepositoryWrapper(RepositoryFactory repositoryFactory,
- String uri, Credentials remoteSystemCredentials) {
- this.repositoryFactory = repositoryFactory;
- this.uri = uri;
- this.remoteSystemCredentials = remoteSystemCredentials;
- init();
- }
-
- public void init() {
- Repository repository = createJackrabbitRepository();
- setRepository(repository);
- }
-
- /** Actually creates the new repository. */
- protected Repository createJackrabbitRepository() {
- long begin = System.currentTimeMillis();
- try {
- if (uri == null || uri.trim().equals(""))
- throw new ArgeoException("Remote URI not set");
-
- Repository repository = ArgeoJcrUtils.getRepositoryByUri(
- repositoryFactory, uri);
- if (repository == null)
- throw new ArgeoException("Remote JCR repository " + uri
- + " not found");
- double duration = ((double) (System.currentTimeMillis() - begin)) / 1000;
- log.info("Created remote JCR repository in " + duration
- + " s from URI " + uri);
- // we assume that the data model of the remote repository has
- // been properly initialized
- return repository;
- } catch (Exception e) {
- throw new ArgeoException("Cannot create remote JCR repository "
- + uri, e);
- }
- }
-
- /** Shutdown the repository */
- public void destroy() throws Exception {
- super.destroy();
- }
-
- /** Central login method */
- public Session login(Credentials credentials, String workspaceName)
- throws LoginException, NoSuchWorkspaceException,
- RepositoryException {
-
- // retrieve credentials for remote
- if (credentials == null) {
- Authentication authentication = SecurityContextHolder.getContext()
- .getAuthentication();
- if (authentication != null) {
- if (authentication instanceof UsernamePasswordAuthenticationToken) {
- UsernamePasswordAuthenticationToken upat = (UsernamePasswordAuthenticationToken) authentication;
- credentials = new SimpleCredentials(upat.getName(), upat
- .getCredentials().toString().toCharArray());
- } else if ((authentication instanceof SystemAuthentication)
- || (authentication instanceof NodeAuthenticationToken)) {
- credentials = remoteSystemCredentials;
- }
- }
- }
-
- return super.login(credentials, workspaceName);
- }
-
- public void setUri(String uri) {
- this.uri = uri;
- }
-
- public void setRepositoryFactory(RepositoryFactory repositoryFactory) {
- this.repositoryFactory = repositoryFactory;
- }
-
- public void setRemoteSystemCredentials(Credentials remoteSystemCredentials) {
- this.remoteSystemCredentials = remoteSystemCredentials;
- }
-
-}
+++ /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.security.jcr;
-
-import javax.jcr.Session;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.jcr.spring.ThreadBoundSession;
-import org.springframework.security.Authentication;
-import org.springframework.security.context.SecurityContextHolder;
-
-/**
- * Thread bounded JCR session factory which checks authentication and is
- * autoconfigured in Spring.
- */
-public class SecureThreadBoundSession extends ThreadBoundSession {
- private final static Log log = LogFactory
- .getLog(SecureThreadBoundSession.class);
-
- @Override
- protected Session preCall(Session session) {
- Authentication authentication = SecurityContextHolder.getContext()
- .getAuthentication();
- if (authentication != null) {
- String userID = session.getUserID();
- String currentUserName = authentication.getName();
- if (currentUserName != null) {
- if (!userID.equals(currentUserName)) {
- log.warn("Current session has user ID " + userID
- + " while logged is user is " + currentUserName
- + "(authentication=" + authentication + ")"
- + ". Re-login.");
- // TODO throw an exception
- return login();
- }
- }
- }
- return super.preCall(session);
- }
-
-}
+++ /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.security.jcr;
-
-import java.util.List;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.Value;
-import javax.jcr.security.Privilege;
-import javax.jcr.version.VersionManager;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-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;
-
-/**
- * Manages data expected by the Argeo security model, such as user home and
- * profile.
- */
-public class SimpleJcrSecurityModel implements JcrSecurityModel {
- private final static Log log = LogFactory
- .getLog(SimpleJcrSecurityModel.class);
- // ArgeoNames not implemented as interface in order to ease derivation by
- // Jackrabbit bundles
-
- /** The home base path. */
- private String homeBasePath = "/home";
-
- public synchronized Node sync(Session session, String username,
- List<String> roles) {
- // TODO check user name validity (e.g. should not start by ROLE_)
-
- try {
- Node userHome = UserJcrUtils.getUserHome(session, username);
- if (userHome == null) {
- String homePath = generateUserPath(homeBasePath, username);
- userHome = JcrUtils.mkdirs(session, homePath);
- // userHome = JcrUtils.mkfolders(session, homePath);
- userHome.addMixin(ArgeoTypes.ARGEO_USER_HOME);
- userHome.setProperty(ArgeoNames.ARGEO_USER_ID, username);
- session.save();
-
- JcrUtils.clearAccessControList(session, homePath, username);
- JcrUtils.addPrivilege(session, homePath, username,
- Privilege.JCR_ALL);
- } else {
- // for backward compatibility with pre 1.0 security model
- if (userHome.hasNode(ArgeoNames.ARGEO_PROFILE)) {
- userHome.getNode(ArgeoNames.ARGEO_PROFILE).remove();
- userHome.getSession().save();
- }
- }
-
- // Remote roles
- if (roles != null) {
- // writeRemoteRoles(userHome, roles);
- }
-
- Node userProfile = UserJcrUtils.getUserProfile(session, username);
- if (userProfile == null) {
- String personPath = generateUserPath(
- ArgeoJcrConstants.PEOPLE_BASE_PATH, username);
- Node personBase = JcrUtils.mkdirs(session, personPath);
- userProfile = personBase.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);
- session.save();
-
- JcrUtils.clearAccessControList(session, userProfile.getPath(),
- username);
- JcrUtils.addPrivilege(session, userProfile.getPath(), username,
- Privilege.JCR_READ);
-
- VersionManager versionManager = session.getWorkspace()
- .getVersionManager();
- if (versionManager.isCheckedOut(userProfile.getPath()))
- versionManager.checkin(userProfile.getPath());
-
- }
-
- // Remote roles
- if (roles != null) {
- writeRemoteRoles(userProfile, roles);
- }
- return userProfile;
- } catch (RepositoryException e) {
- JcrUtils.discardQuietly(session);
- throw new ArgeoException("Cannot sync node security model for "
- + username, e);
- }
- }
-
- /** Generate path for a new user home */
- protected String generateUserPath(String base, String username) {
- int atIndex = username.indexOf('@');
- if (atIndex > 0) {
- String domain = username.substring(0, atIndex);
- String name = username.substring(atIndex + 1);
- return base + '/' + JcrUtils.firstCharsToPath(domain, 2) + '/'
- + domain + '/' + JcrUtils.firstCharsToPath(name, 2) + '/'
- + name;
- } else if (atIndex == 0 || atIndex == (username.length() - 1)) {
- throw new ArgeoException("Unsupported username " + username);
- } else {
- return base + '/' + JcrUtils.firstCharsToPath(username, 2) + '/'
- + username;
- }
- }
-
- /** Write remote roles used by remote access in the home directory */
- protected void writeRemoteRoles(Node userHome, List<String> roles)
- throws RepositoryException {
- boolean writeRoles = false;
- if (userHome.hasProperty(ArgeoNames.ARGEO_REMOTE_ROLES)) {
- Value[] remoteRoles = userHome.getProperty(
- ArgeoNames.ARGEO_REMOTE_ROLES).getValues();
- if (remoteRoles.length != roles.size())
- writeRoles = true;
- else
- for (int i = 0; i < remoteRoles.length; i++)
- if (!remoteRoles[i].getString().equals(roles.get(i)))
- writeRoles = true;
- } else
- writeRoles = true;
-
- if (writeRoles) {
- userHome.getSession().getWorkspace().getVersionManager()
- .checkout(userHome.getPath());
- String[] roleIds = roles.toArray(new String[roles.size()]);
- userHome.setProperty(ArgeoNames.ARGEO_REMOTE_ROLES, roleIds);
- JcrUtils.updateLastModified(userHome);
- userHome.getSession().save();
- userHome.getSession().getWorkspace().getVersionManager()
- .checkin(userHome.getPath());
- if (log.isDebugEnabled())
- log.debug("Wrote remote roles " + roles + " for "
- + userHome.getProperty(ArgeoNames.ARGEO_USER_ID));
- }
-
- }
-
- public void setHomeBasePath(String homeBasePath) {
- this.homeBasePath = homeBasePath;
- }
-
-}
+++ /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.security.jcr.rememberme;
-
-import java.util.Date;
-
-import org.springframework.security.ui.rememberme.PersistentRememberMeToken;
-import org.springframework.security.ui.rememberme.PersistentTokenRepository;
-
-public class JcrPersistentTokenRepository implements PersistentTokenRepository {
-
- public void createNewToken(PersistentRememberMeToken token) {
- // TODO Auto-generated method stub
-
- }
-
- public void updateToken(String series, String tokenValue, Date lastUsed) {
- // TODO Auto-generated method stub
-
- }
-
- public PersistentRememberMeToken getTokenForSeries(String seriesId) {
- // TODO Auto-generated method stub
- return null;
- }
-
- public void removeUserTokens(String username) {
- // TODO Auto-generated method stub
-
- }
-
-}
+++ /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.security.log4j;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.ListIterator;
-import java.util.Map;
-import java.util.Properties;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.LinkedBlockingQueue;
-
-import org.apache.log4j.AppenderSkeleton;
-import org.apache.log4j.Level;
-import org.apache.log4j.LogManager;
-import org.apache.log4j.Logger;
-import org.apache.log4j.PropertyConfigurator;
-import org.apache.log4j.spi.LoggingEvent;
-import org.argeo.ArgeoException;
-import org.argeo.ArgeoLogListener;
-import org.argeo.ArgeoLogger;
-import org.argeo.security.SecurityUtils;
-
-/** Not meant to be used directly in standard log4j config */
-public class SecureLogger implements ArgeoLogger {
-
- private Boolean disabled = false;
-
- private String level = null;
-
- private Level log4jLevel = null;
- // private Layout layout;
-
- private Properties configuration;
-
- private AppenderImpl appender;
-
- private final List<ArgeoLogListener> everythingListeners = Collections
- .synchronizedList(new ArrayList<ArgeoLogListener>());
- private final List<ArgeoLogListener> allUsersListeners = Collections
- .synchronizedList(new ArrayList<ArgeoLogListener>());
- private final Map<String, List<ArgeoLogListener>> userListeners = Collections
- .synchronizedMap(new HashMap<String, List<ArgeoLogListener>>());
-
- private BlockingQueue<LogEvent> events;
- private LogDispatcherThread logDispatcherThread = new LogDispatcherThread();
-
- private Integer maxLastEventsCount = 10 * 1000;
-
- /** Marker to prevent stack overflow */
- private ThreadLocal<Boolean> dispatching = new ThreadLocal<Boolean>() {
-
- @Override
- protected Boolean initialValue() {
- return false;
- }
- };
-
- public void init() {
- try {
- events = new LinkedBlockingQueue<LogEvent>();
-
- // if (layout != null)
- // setLayout(layout);
- // else
- // setLayout(new PatternLayout(pattern));
- appender = new AppenderImpl();
- reloadConfiguration();
- Logger.getRootLogger().addAppender(appender);
-
- logDispatcherThread = new LogDispatcherThread();
- logDispatcherThread.start();
- } catch (Exception e) {
- throw new ArgeoException("Cannot initialize log4j");
- }
- }
-
- public void destroy() throws Exception {
- Logger.getRootLogger().removeAppender(appender);
- allUsersListeners.clear();
- for (List<ArgeoLogListener> lst : userListeners.values())
- lst.clear();
- userListeners.clear();
-
- events.clear();
- events = null;
- logDispatcherThread.interrupt();
- }
-
- // public void setLayout(Layout layout) {
- // this.layout = layout;
- // }
-
- public synchronized void register(ArgeoLogListener listener,
- Integer numberOfPreviousEvents) {
- String username = SecurityUtils.getCurrentThreadUsername();
- if (username == null)
- throw new ArgeoException(
- "Only authenticated users can register a log listener");
-
- if (!userListeners.containsKey(username)) {
- List<ArgeoLogListener> lst = Collections
- .synchronizedList(new ArrayList<ArgeoLogListener>());
- userListeners.put(username, lst);
- }
- userListeners.get(username).add(listener);
- List<LogEvent> lastEvents = logDispatcherThread.getLastEvents(username,
- numberOfPreviousEvents);
- for (LogEvent evt : lastEvents)
- dispatchEvent(listener, evt);
- }
-
- public synchronized void registerForAll(ArgeoLogListener listener,
- Integer numberOfPreviousEvents, boolean everything) {
- if (everything)
- everythingListeners.add(listener);
- else
- allUsersListeners.add(listener);
- List<LogEvent> lastEvents = logDispatcherThread.getLastEvents(null,
- numberOfPreviousEvents);
- for (LogEvent evt : lastEvents)
- if (everything || evt.getUsername() != null)
- dispatchEvent(listener, evt);
- }
-
- public synchronized void unregister(ArgeoLogListener listener) {
- String username = SecurityUtils.getCurrentThreadUsername();
- if (!userListeners.containsKey(username))
- throw new ArgeoException("No user listeners " + listener
- + " registered for user " + username);
- if (!userListeners.get(username).contains(listener))
- throw new ArgeoException("No user listeners " + listener
- + " registered for user " + username);
- userListeners.get(username).remove(listener);
- if (userListeners.get(username).isEmpty())
- userListeners.remove(username);
-
- }
-
- public synchronized void unregisterForAll(ArgeoLogListener listener) {
- everythingListeners.remove(listener);
- allUsersListeners.remove(listener);
- }
-
- /** For development purpose, since using regular logging is not easy here */
- static void stdOut(Object obj) {
- System.out.println(obj);
- }
-
- // public void setPattern(String pattern) {
- // this.pattern = pattern;
- // }
-
- public void setDisabled(Boolean disabled) {
- this.disabled = disabled;
- }
-
- public void setLevel(String level) {
- this.level = level;
- }
-
- public void setConfiguration(Properties configuration) {
- this.configuration = configuration;
- }
-
- public void updateConfiguration(Properties configuration) {
- setConfiguration(configuration);
- reloadConfiguration();
- }
-
- public Properties getConfiguration() {
- return configuration;
- }
-
- /** Reloads configuration (if the configuration {@link Properties} is set) */
- protected void reloadConfiguration() {
- if (configuration != null) {
- LogManager.resetConfiguration();
- PropertyConfigurator.configure(configuration);
- }
- }
-
- protected synchronized void processLoggingEvent(LogEvent event) {
- if (disabled)
- return;
-
- if (dispatching.get())
- return;
-
- if (level != null && !level.trim().equals("")) {
- if (log4jLevel == null || !log4jLevel.toString().equals(level))
- try {
- log4jLevel = Level.toLevel(level);
- } catch (Exception e) {
- System.err
- .println("Log4j level could not be set for level '"
- + level + "', resetting it to null.");
- e.printStackTrace();
- level = null;
- }
-
- if (log4jLevel != null
- && !event.getLoggingEvent().getLevel()
- .isGreaterOrEqual(log4jLevel)) {
- return;
- }
- }
-
- try {
- // admin listeners
- Iterator<ArgeoLogListener> everythingIt = everythingListeners
- .iterator();
- while (everythingIt.hasNext())
- dispatchEvent(everythingIt.next(), event);
-
- if (event.getUsername() != null) {
- Iterator<ArgeoLogListener> allUsersIt = allUsersListeners
- .iterator();
- while (allUsersIt.hasNext())
- dispatchEvent(allUsersIt.next(), event);
-
- if (userListeners.containsKey(event.getUsername())) {
- Iterator<ArgeoLogListener> userIt = userListeners.get(
- event.getUsername()).iterator();
- while (userIt.hasNext())
- dispatchEvent(userIt.next(), event);
- }
- }
- } catch (Exception e) {
- stdOut("Cannot process logging event");
- e.printStackTrace();
- }
- }
-
- protected void dispatchEvent(ArgeoLogListener logListener, LogEvent evt) {
- LoggingEvent event = evt.getLoggingEvent();
- logListener.appendLog(evt.getUsername(), event.getTimeStamp(), event
- .getLevel().toString(), event.getLoggerName(), event
- .getThreadName(), event.getMessage(), event
- .getThrowableStrRep());
- }
-
- private class AppenderImpl extends AppenderSkeleton {
- public boolean requiresLayout() {
- return false;
- }
-
- public void close() {
- }
-
- @Override
- protected void append(LoggingEvent event) {
- if (events != null) {
- try {
- String username = SecurityUtils.getCurrentThreadUsername();
- events.put(new LogEvent(username, event));
- } catch (InterruptedException e) {
- // silent
- }
- }
- }
-
- }
-
- private class LogDispatcherThread extends Thread {
- /** encapsulated in order to simplify concurrency management */
- private LinkedList<LogEvent> lastEvents = new LinkedList<LogEvent>();
-
- public LogDispatcherThread() {
- super("Argeo Logging Dispatcher Thread");
- }
-
- public void run() {
- while (events != null) {
- try {
- LogEvent loggingEvent = events.take();
- processLoggingEvent(loggingEvent);
- addLastEvent(loggingEvent);
- } catch (InterruptedException e) {
- if (events == null)
- return;
- }
- }
- }
-
- protected synchronized void addLastEvent(LogEvent loggingEvent) {
- if (lastEvents.size() >= maxLastEventsCount)
- lastEvents.poll();
- lastEvents.add(loggingEvent);
- }
-
- public synchronized List<LogEvent> getLastEvents(String username,
- Integer maxCount) {
- LinkedList<LogEvent> evts = new LinkedList<LogEvent>();
- ListIterator<LogEvent> it = lastEvents.listIterator(lastEvents
- .size());
- int count = 0;
- while (it.hasPrevious() && (count < maxCount)) {
- LogEvent evt = it.previous();
- if (username == null || username.equals(evt.getUsername())) {
- evts.push(evt);
- count++;
- }
- }
- return evts;
- }
- }
-
- private class LogEvent {
- private final String username;
- private final LoggingEvent loggingEvent;
-
- public LogEvent(String username, LoggingEvent loggingEvent) {
- super();
- this.username = username;
- this.loggingEvent = loggingEvent;
- }
-
- @Override
- public int hashCode() {
- return loggingEvent.hashCode();
- }
-
- @Override
- public boolean equals(Object obj) {
- return loggingEvent.equals(obj);
- }
-
- @Override
- public String toString() {
- return username + "@ " + loggingEvent.toString();
- }
-
- public String getUsername() {
- return username;
- }
-
- public LoggingEvent getLoggingEvent() {
- return loggingEvent;
- }
-
- }
-}
--- /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.security;
+
+import org.springframework.security.GrantedAuthority;
+import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
+
+/** Credentials required for the authentication to a node. */
+public class NodeAuthenticationToken extends
+ UsernamePasswordAuthenticationToken {
+ private static final long serialVersionUID = 1955222132884795213L;
+ private final String url;
+
+ /** Non authenticated local constructor */
+ public NodeAuthenticationToken(Object principal, Object credentials) {
+ super(principal, credentials);
+ this.url = null;
+ }
+
+ /** Non authenticated remote constructor */
+ public NodeAuthenticationToken(Object principal, Object credentials,
+ String url) {
+ super(principal, credentials);
+ this.url = url;
+ }
+
+ /** Authenticated constructor */
+ public NodeAuthenticationToken(NodeAuthenticationToken sat,
+ GrantedAuthority[] authorities) {
+ super(sat.getPrincipal(), sat.getCredentials(), authorities);
+ this.url = sat.getUrl();
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public Boolean isRemote() {
+ return url != 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.security;
+
+import java.security.AccessController;
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+
+import javax.security.auth.Subject;
+
+import org.argeo.ArgeoException;
+import org.argeo.OperatingSystem;
+import org.springframework.security.Authentication;
+import org.springframework.security.GrantedAuthority;
+import org.springframework.security.GrantedAuthorityImpl;
+import org.springframework.security.userdetails.UserDetails;
+
+/** Abstracts principals provided by com.sun.security.auth.module login modules. */
+public class OsAuthenticationToken implements Authentication {
+ private static final long serialVersionUID = -7544626794250917244L;
+
+ final Class<? extends Principal> osUserPrincipalClass;
+ final Class<? extends Principal> osUserIdPrincipalClass;
+ final Class<? extends Principal> osGroupIdPrincipalClass;
+
+ private List<GrantedAuthority> grantedAuthorities;
+
+ private UserDetails details;
+
+ /** Request */
+ public OsAuthenticationToken(GrantedAuthority[] grantedAuthorities) {
+ this.grantedAuthorities = grantedAuthorities != null ? Arrays
+ .asList(grantedAuthorities) : null;
+ ClassLoader cl = getClass().getClassLoader();
+ switch (OperatingSystem.os) {
+ case OperatingSystem.WINDOWS:
+ osUserPrincipalClass = getPrincipalClass(cl,
+ "com.sun.security.auth.NTUserPrincipal");
+ osUserIdPrincipalClass = getPrincipalClass(cl,
+ "com.sun.security.auth.NTSidUserPrincipal");
+ osGroupIdPrincipalClass = getPrincipalClass(cl,
+ "com.sun.security.auth.NTSidGroupPrincipal");
+ break;
+ case OperatingSystem.NIX:
+ osUserPrincipalClass = getPrincipalClass(cl,
+ "com.sun.security.auth.UnixPrincipal");
+ osUserIdPrincipalClass = getPrincipalClass(cl,
+ "com.sun.security.auth.UnixNumericUserPrincipal");
+ osGroupIdPrincipalClass = getPrincipalClass(cl,
+ "com.sun.security.auth.UnixNumericGroupPrincipal");
+ break;
+ case OperatingSystem.SOLARIS:
+ osUserPrincipalClass = getPrincipalClass(cl,
+ "com.sun.security.auth.SolarisPrincipal");
+ osUserIdPrincipalClass = getPrincipalClass(cl,
+ "com.sun.security.auth.SolarisNumericUserPrincipal");
+ osGroupIdPrincipalClass = getPrincipalClass(cl,
+ "com.sun.security.auth.SolarisNumericGroupPrincipal");
+ break;
+
+ default:
+ throw new ArgeoException("Unsupported operating system "
+ + OperatingSystem.os);
+ }
+
+ }
+
+ /** Authenticated */
+ public OsAuthenticationToken() {
+ this(null);
+ }
+
+ /** @return the name, or null if not yet logged */
+ public String getName() {
+ Subject subject = Subject.getSubject(AccessController.getContext());
+ if (subject == null)
+ return null;
+ return getUser().getName();
+ }
+
+ /**
+ * Should not be called during authentication since group IDs are not yet
+ * available {@link Subject} has been set
+ */
+ public GrantedAuthority[] getAuthorities() {
+ // grantedAuthorities should not be null at this stage
+ List<GrantedAuthority> gas = new ArrayList<GrantedAuthority>(
+ grantedAuthorities);
+ for (Principal groupPrincipal : getGroupsIds()) {
+ gas.add(new GrantedAuthorityImpl("OSGROUP_"
+ + groupPrincipal.getName()));
+ }
+ return gas.toArray(new GrantedAuthority[gas.size()]);
+ }
+
+ public UserDetails getDetails() {
+ return details;
+ }
+
+ public void setDetails(UserDetails details) {
+ this.details = details;
+ }
+
+ public boolean isAuthenticated() {
+ return grantedAuthorities != null;
+ }
+
+ public void setAuthenticated(boolean isAuthenticated)
+ throws IllegalArgumentException {
+ if (grantedAuthorities != null)
+ grantedAuthorities.clear();
+ grantedAuthorities = null;
+ }
+
+ @SuppressWarnings("unchecked")
+ protected static Class<? extends Principal> getPrincipalClass(
+ ClassLoader cl, String className) {
+ try {
+ return (Class<? extends Principal>) cl.loadClass(className);
+ } catch (ClassNotFoundException e) {
+ throw new ArgeoException("Cannot load principal class", e);
+ }
+ }
+
+ public Object getPrincipal() {
+ return getUser();
+ }
+
+ public Principal getUser() {
+ Subject subject = getSubject();
+ Set<? extends Principal> userPrincipals = subject
+ .getPrincipals(osUserPrincipalClass);
+ if (userPrincipals == null || userPrincipals.size() == 0)
+ throw new ArgeoException("No OS principal");
+ if (userPrincipals.size() > 1)
+ throw new ArgeoException("More than one OS principal");
+ Principal user = userPrincipals.iterator().next();
+ return user;
+ }
+
+ public Principal getUserId() {
+ Subject subject = getSubject();
+ Set<? extends Principal> userIdsPrincipals = subject
+ .getPrincipals(osUserIdPrincipalClass);
+ if (userIdsPrincipals == null || userIdsPrincipals.size() == 0)
+ throw new ArgeoException("No user id principal");
+ if (userIdsPrincipals.size() > 1)
+ throw new ArgeoException("More than one user id principal");
+ Principal userId = userIdsPrincipals.iterator().next();
+ return userId;
+ }
+
+ public Set<? extends Principal> getGroupsIds() {
+ Subject subject = getSubject();
+ return (Set<? extends Principal>) subject
+ .getPrincipals(osGroupIdPrincipalClass);
+ }
+
+ /** @return the subject always non null */
+ protected Subject getSubject() {
+ Subject subject = Subject.getSubject(AccessController.getContext());
+ if (subject == null)
+ throw new ArgeoException("No subject in JAAS context");
+ return subject;
+ }
+
+ public Object getCredentials() {
+ return "";
+ }
+
+}
--- /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.security;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.springframework.security.Authentication;
+import org.springframework.security.GrantedAuthority;
+import org.springframework.security.context.SecurityContext;
+import org.springframework.security.context.SecurityContextHolder;
+import org.springframework.security.providers.anonymous.AnonymousAuthenticationToken;
+
+/** Static utilities */
+public class SecurityUtils {
+
+ private SecurityUtils() {
+ }
+
+ /** Whether the current thread has the admin role */
+ public static boolean hasCurrentThreadAuthority(String authority) {
+ SecurityContext securityContext = SecurityContextHolder.getContext();
+ if (securityContext != null) {
+ Authentication authentication = securityContext.getAuthentication();
+ if (authentication != null) {
+ for (GrantedAuthority ga : authentication.getAuthorities())
+ if (ga.getAuthority().equals(authority))
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @return the authenticated username or null if not authenticated /
+ * anonymous
+ */
+ public static String getCurrentThreadUsername() {
+ SecurityContext securityContext = SecurityContextHolder.getContext();
+ if (securityContext != null) {
+ Authentication authentication = securityContext.getAuthentication();
+ if (authentication != null) {
+ if (authentication instanceof AnonymousAuthenticationToken) {
+ return null;
+ }
+ return authentication.getName();
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the display name of the user details (by calling toString() on
+ * it)
+ */
+ public static String getUserDetailsDisplayName() {
+ SecurityContext securityContext = SecurityContextHolder.getContext();
+ if (securityContext != null) {
+ Authentication authentication = securityContext.getAuthentication();
+ if (authentication != null) {
+ if (authentication instanceof AnonymousAuthenticationToken) {
+ return null;
+ }
+ Object details = authentication.getDetails();
+ if (details != null)
+ return details.toString();
+ return authentication.getName();
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Converts an array of Spring Security {@link GrantedAuthority} to a
+ * read-only list of strings, for portability and integration
+ */
+ public static List<String> authoritiesToStringList(
+ GrantedAuthority[] authorities) {
+ List<String> lst = new ArrayList<String>();
+ for (GrantedAuthority ga : authorities)
+ lst.add(ga.getAuthority());
+ return Collections.unmodifiableList(lst);
+ }
+}
--- /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.security;
+
+/**
+ * Marks a system authentication, that is which did not require a login process.
+ */
+public interface SystemAuthentication {
+
+}
--- /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.security;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Future;
+
+/**
+ * Allows to execute code authenticated as a system user (that is not a real
+ * person). The {@link Executor} interface is not used directly in order to
+ * allow future extension of this interface and to simplify its publication
+ * (e.g. as an OSGi service) and interception.
+ */
+public interface SystemExecutionService extends Executor {
+ /**
+ * Executes this {@link Runnable} within a system authenticated context.
+ * Implementations should make sure that this method is properly secured via
+ * Java permissions since it could access everything without credentials.
+ */
+ public void execute(Runnable runnable);
+
+ /**
+ * Executes this {@link Callable} within a system authenticated context.
+ * Implementations should make sure that this method is properly secured via
+ * Java permissions since it could access everything without credentials.
+ */
+ public <T> Future<T> submit(Callable<T> task);
+}
--- /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.security;
+
+import java.util.Set;
+
+import org.springframework.security.userdetails.UserDetailsManager;
+
+/** Enrich {@link UserDetailsManager} in order to provide roles semantics. */
+public interface UserAdminService extends UserDetailsManager {
+ /**
+ * Usernames must match this regexp pattern ({@value #USERNAME_PATTERN}).
+ * Thanks to <a href=
+ * "http://www.mkyong.com/regular-expressions/how-to-validate-username-with-regular-expression/"
+ * >this tip</a> (modified to add upper-case, add '@')
+ */
+ //public final static String USERNAME_PATTERN = "^[a-zA-Z0-9_-@]{3,64}$";
+
+ /**
+ * Email addresses must match this regexp pattern ({@value #EMAIL_PATTERN}.
+ * Thanks to <a href=
+ * "http://www.mkyong.com/regular-expressions/how-to-validate-email-address-with-regular-expression/"
+ * >this tip</a>.
+ */
+ public final static String EMAIL_PATTERN = "^[_A-Za-z0-9-]+(\\.[_A-Za-z0-9-]+)*@[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$";
+
+ /*
+ * USERS
+ */
+ /** List all users. */
+ public Set<String> listUsers();
+
+ /** List users having this role (except the super user). */
+ public Set<String> listUsersInRole(String role);
+
+ /** Synchronize with the underlying DAO. */
+ public void synchronize();
+
+ /*
+ * ROLES
+ */
+ public void newRole(String role);
+
+ public Set<String> listEditableRoles();
+
+ public void deleteRole(String role);
+}
--- /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.security.core;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.ArgeoException;
+import org.argeo.security.SystemAuthentication;
+import org.springframework.security.Authentication;
+import org.springframework.security.AuthenticationManager;
+import org.springframework.security.context.SecurityContext;
+import org.springframework.security.context.SecurityContextHolder;
+
+/** Provides base method for executing code with system authorization. */
+public abstract class AbstractSystemExecution {
+ static {
+ // Forces Spring Security to use inheritable strategy
+ // FIXME find a better place for forcing spring security mode
+ // doesn't work for the time being
+// if (System.getProperty(SecurityContextHolder.SYSTEM_PROPERTY) == null)
+// SecurityContextHolder
+// .setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
+ }
+
+ private final static Log log = LogFactory
+ .getLog(AbstractSystemExecution.class);
+ private AuthenticationManager authenticationManager;
+ private String systemAuthenticationKey;
+
+ /** Whether the current thread was authenticated by this component. */
+ private ThreadLocal<Boolean> authenticatedBySelf = new ThreadLocal<Boolean>() {
+ protected Boolean initialValue() {
+ return false;
+ }
+ };
+
+ /**
+ * Authenticate the calling thread to the underlying
+ * {@link AuthenticationManager}
+ */
+ protected void authenticateAsSystem() {
+ if (authenticatedBySelf.get())
+ return;
+ SecurityContext securityContext = SecurityContextHolder.getContext();
+ Authentication currentAuth = securityContext.getAuthentication();
+ if (currentAuth != null) {
+ if (!(currentAuth instanceof SystemAuthentication))
+ throw new ArgeoException(
+ "System execution on an already authenticated thread: "
+ + currentAuth + ", THREAD="
+ + Thread.currentThread().getId());
+ return;
+ }
+ // Subject subject = Subject.getSubject(AccessController.getContext());
+ // if (subject != null
+ // && !subject.getPrincipals(Authentication.class).isEmpty())
+ // throw new ArgeoException(
+ // "There is already an authenticated subject: " + subject);
+
+ String key = systemAuthenticationKey != null ? systemAuthenticationKey
+ : System.getProperty(
+ InternalAuthentication.SYSTEM_KEY_PROPERTY,
+ InternalAuthentication.SYSTEM_KEY_DEFAULT);
+ if (key == null)
+ throw new ArgeoException("No system key defined");
+ Authentication auth = authenticationManager
+ .authenticate(new InternalAuthentication(key));
+ securityContext.setAuthentication(auth);
+ authenticatedBySelf.set(true);
+ if (log.isTraceEnabled())
+ log.trace("System authenticated");
+ }
+
+ // /** Removes the authentication from the calling thread. */
+ // protected void deauthenticateAsSystem() {
+ // // remove the authentication
+ // // SecurityContext securityContext = SecurityContextHolder.getContext();
+ // // securityContext.setAuthentication(null);
+ // // authenticatedBySelf.set(false);
+ // if (log.isTraceEnabled()) {
+ // log.trace("System deauthenticated");
+ // // Thread.dumpStack();
+ // }
+ // }
+
+ /**
+ * Whether the current thread was authenticated by this component or a
+ * parent thread.
+ */
+ protected Boolean isAuthenticatedBySelf() {
+ return authenticatedBySelf.get();
+ }
+
+ public void setAuthenticationManager(
+ AuthenticationManager authenticationManager) {
+ this.authenticationManager = authenticationManager;
+ }
+
+ public void setSystemAuthenticationKey(String systemAuthenticationKey) {
+ this.systemAuthenticationKey = systemAuthenticationKey;
+ }
+
+}
--- /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.security.core;
+
+import org.argeo.security.SystemExecutionService;
+import org.springframework.core.task.SimpleAsyncTaskExecutor;
+
+/**
+ * Asynchronous Spring TaskExecutor (for use in JMS for example) wrapping a
+ * {@link SystemExecutionService}.
+ */
+public class AsyncSystemTaskExecutor extends SimpleAsyncTaskExecutor {
+ private static final long serialVersionUID = -8035527542087963068L;
+
+ private SystemExecutionService systemExecutionService;
+
+ public AsyncSystemTaskExecutor() {
+ super();
+ }
+
+ public AsyncSystemTaskExecutor(String threadNamePrefix) {
+ super(threadNamePrefix);
+ }
+
+ @Override
+ public Thread createThread(final Runnable runnable) {
+ Runnable systemExecutionRunnable = new Runnable() {
+
+ public void run() {
+ systemExecutionService.execute(runnable);
+
+ }
+ };
+ return super.createThread(systemExecutionRunnable);
+ }
+
+ public void setSystemExecutionService(
+ SystemExecutionService systemExecutionService) {
+ this.systemExecutionService = systemExecutionService;
+ }
+
+}
--- /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.security.core;
+
+import java.beans.PropertyDescriptor;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.springframework.beans.BeansException;
+import org.springframework.beans.PropertyValues;
+import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
+import org.springframework.context.ApplicationEvent;
+import org.springframework.context.ApplicationListener;
+import org.springframework.context.event.ContextRefreshedEvent;
+
+/**
+ * Executes with a system authentication the instantiation and initialization
+ * methods of the application context where it has been defined.
+ */
+public class AuthenticatedApplicationContextInitialization extends
+ AbstractSystemExecution implements InstantiationAwareBeanPostProcessor,
+ ApplicationListener {
+ // private Log log = LogFactory
+ // .getLog(AuthenticatedApplicationContextInitialization.class);
+ /** If non empty, restricts to these beans */
+ private List<String> beanNames = new ArrayList<String>();
+
+ @SuppressWarnings("rawtypes")
+ public Object postProcessBeforeInstantiation(Class beanClass,
+ String beanName) throws BeansException {
+ // we authenticate when any bean is instantiated
+ // we will deauthenticate only when the application context has been
+ // refreshed in order to be able to deal with factory beans has well
+ if (!isAuthenticatedBySelf()) {
+ if (beanNames.size() == 0)
+ authenticateAsSystem();
+ else if (beanNames.contains(beanName))
+ authenticateAsSystem();
+ }
+ return null;
+ }
+
+ public boolean postProcessAfterInstantiation(Object bean, String beanName)
+ throws BeansException {
+ return true;
+ }
+
+ public PropertyValues postProcessPropertyValues(PropertyValues pvs,
+ PropertyDescriptor[] pds, Object bean, String beanName)
+ throws BeansException {
+ return pvs;
+ }
+
+ public Object postProcessBeforeInitialization(Object bean, String beanName)
+ throws BeansException {
+ // authenticateAsSystem();
+ return bean;
+ }
+
+ public Object postProcessAfterInitialization(Object bean, String beanName)
+ throws BeansException {
+ // NOTE: in case there was an exception in on the initialization method
+ // we expect the underlying thread to die and thus the system
+ // authentication to be lost. We have currently no way to catch the
+ // exception and perform the deauthentication by ourselves.
+ // deauthenticateAsSystem();
+ return bean;
+ }
+
+ public void onApplicationEvent(ApplicationEvent event) {
+ if (event instanceof ContextRefreshedEvent) {
+ // make sure that we have deauthenticated after the application
+ // context was initialized/refreshed
+ // deauthenticateAsSystem();
+ }
+ }
+
+ public void setBeanNames(List<String> beanNames) {
+ this.beanNames = beanNames;
+ }
+
+}
--- /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.security.core;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.InitializingBean;
+
+/**
+ * Maintains a list of authentication providers injected in to a provider
+ * manager, in order to avoid issues with OSGi services and use packages.
+ */
+public class AuthenticationProvidersRegister implements InitializingBean {
+ private Log log = LogFactory.getLog(AuthenticationProvidersRegister.class);
+
+ private List<Object> providers = new ArrayList<Object>();
+ private List<Object> defaultProviders = new ArrayList<Object>();
+
+ public void register(Object authenticationProvider,
+ Map<String, String> parameters) {
+ providers.add(authenticationProvider);
+ if (log.isTraceEnabled())
+ log.trace("Registered authentication provider " + parameters);
+ }
+
+ public void unregister(Object authenticationProvider,
+ Map<String, String> parameters) {
+ providers.remove(authenticationProvider);
+ if (log.isTraceEnabled())
+ log.trace("Unregistered authentication provider " + parameters);
+ }
+
+ public List<Object> getProviders() {
+ return providers;
+ }
+
+ public void setDefaultProviders(
+ List<Object> defaultProviders) {
+ this.defaultProviders = defaultProviders;
+ }
+
+ public void afterPropertiesSet() throws Exception {
+ providers.addAll(defaultProviders);
+ }
+
+}
--- /dev/null
+package org.argeo.security.core;
+
+import java.io.Console;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.Locale;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.TextOutputCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+
+import org.argeo.ArgeoException;
+import org.argeo.util.LocaleCallback;
+
+/** Callback handler to be used with a command line UI. */
+public class ConsoleCallbackHandler implements CallbackHandler {
+
+ @Override
+ public void handle(Callback[] callbacks) throws IOException,
+ UnsupportedCallbackException {
+ Console console = System.console();
+ if (console == null)
+ throw new ArgeoException("No console available");
+
+ PrintWriter writer = console.writer();
+ for (int i = 0; i < callbacks.length; i++) {
+ if (callbacks[i] instanceof TextOutputCallback) {
+ TextOutputCallback callback = (TextOutputCallback) callbacks[i];
+ writer.write(callback.getMessage());
+ } else if (callbacks[i] instanceof NameCallback) {
+ NameCallback callback = (NameCallback) callbacks[i];
+ writer.write(callback.getPrompt());
+ if (callback.getDefaultName() != null)
+ writer.write(" (" + callback.getDefaultName() + ")");
+ writer.write(" : ");
+ String answer = console.readLine();
+ if (callback.getDefaultName() != null
+ && answer.trim().equals(""))
+ callback.setName(callback.getDefaultName());
+ else
+ callback.setName(answer);
+ } else if (callbacks[i] instanceof PasswordCallback) {
+ PasswordCallback callback = (PasswordCallback) callbacks[i];
+ writer.write(callback.getPrompt());
+ char[] answer = console.readPassword();
+ callback.setPassword(answer);
+ Arrays.fill(answer, ' ');
+ } else if (callbacks[i] instanceof LocaleCallback) {
+ LocaleCallback callback = (LocaleCallback) callbacks[i];
+ writer.write(callback.getPrompt());
+ writer.write("\n");
+ for (int j = 0; j < callback.getAvailableLocales().size(); j++) {
+ Locale locale = callback.getAvailableLocales().get(j);
+ writer.print(j + " : " + locale.getDisplayName() + "\n");
+ }
+ writer.write("(" + callback.getDefaultIndex() + ") : ");
+ String answer = console.readLine();
+ if (answer.trim().equals(""))
+ callback.setSelectedIndex(callback.getDefaultIndex());
+ else
+ callback.setSelectedIndex(new Integer(answer.trim()));
+ }
+ }
+ }
+
+}
--- /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.security.core;
+
+import org.argeo.security.SystemAuthentication;
+import org.springframework.security.GrantedAuthority;
+import org.springframework.security.GrantedAuthorityImpl;
+import org.springframework.security.adapters.PrincipalSpringSecurityUserToken;
+
+/** A token base on a system key used to request a system authentication. */
+public class InternalAuthentication extends PrincipalSpringSecurityUserToken
+ implements SystemAuthentication {
+ private static final long serialVersionUID = -6783376375615949315L;
+ /** 'admin' for consistency with JCR */
+ public final static String DEFAULT_SYSTEM_USERNAME = "admin";
+ public final static String DEFAULT_SYSTEM_ROLE = "ROLE_SYSTEM";
+ public final static String SYSTEM_KEY_PROPERTY = "argeo.security.systemKey";
+ public final static String SYSTEM_KEY_DEFAULT = "argeo";
+
+ public InternalAuthentication(String key, String systemUsername,
+ String systemRole) {
+ super(
+ key,
+ systemUsername,
+ key,
+ new GrantedAuthority[] { new GrantedAuthorityImpl(systemRole) },
+ systemUsername);
+ }
+
+ public InternalAuthentication(String key) {
+ this(key, DEFAULT_SYSTEM_USERNAME, DEFAULT_SYSTEM_ROLE);
+ }
+
+}
--- /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.security.core;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.FutureTask;
+
+import org.argeo.ArgeoException;
+import org.argeo.security.SystemExecutionService;
+
+/**
+ * Implementation of a {@link SystemExecutionService} using a key-based
+ * {@link InternalAuthentication}
+ */
+public class KeyBasedSystemExecutionService extends AbstractSystemExecution
+ implements SystemExecutionService {
+ public void execute(Runnable runnable) {
+ try {
+ wrapWithSystemAuthentication(Executors.callable(runnable)).call();
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new ArgeoException(
+ "Exception when running system authenticated task", e);
+ }
+ }
+
+ public <T> Future<T> submit(Callable<T> task) {
+ FutureTask<T> future = new FutureTask<T>(
+ wrapWithSystemAuthentication(task));
+ future.run();
+ return future;
+ }
+
+ protected <T> Callable<T> wrapWithSystemAuthentication(
+ final Callable<T> runnable) {
+ return new Callable<T>() {
+
+ public T call() throws Exception {
+ authenticateAsSystem();
+ try {
+ return runnable.call();
+ } finally {
+// deauthenticateAsSystem();
+ }
+ }
+ };
+ }
+}
--- /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.security.core;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import org.springframework.core.io.Resource;
+import org.springframework.security.AuthenticationException;
+import org.springframework.security.BadCredentialsException;
+import org.springframework.security.GrantedAuthority;
+import org.springframework.security.GrantedAuthorityImpl;
+import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
+import org.springframework.security.providers.dao.AbstractUserDetailsAuthenticationProvider;
+import org.springframework.security.userdetails.User;
+import org.springframework.security.userdetails.UserDetails;
+
+/** @deprecated */
+@Deprecated
+public class MatchingAuthenticationProvider extends
+ AbstractUserDetailsAuthenticationProvider {
+
+ private Resource mapping;
+ private Properties properties;
+
+ private List<String> defaultRoles = new ArrayList<String>();
+
+ @Override
+ protected void doAfterPropertiesSet() throws Exception {
+ properties = new Properties();
+ InputStream propIn = mapping.getInputStream();
+ try {
+ properties.load(propIn);
+ } finally {
+ propIn.close();
+ }
+ }
+
+ @Override
+ protected void additionalAuthenticationChecks(UserDetails userDetails,
+ UsernamePasswordAuthenticationToken authentication)
+ throws AuthenticationException {
+ if (!userDetails.getPassword().equals(authentication.getCredentials()))
+ throw new BadCredentialsException(
+ "Invalid credentails provided by "
+ + authentication.getName());
+ }
+
+ @Override
+ protected UserDetails retrieveUser(String username,
+ UsernamePasswordAuthenticationToken authentication)
+ throws AuthenticationException {
+ String value = properties.getProperty(username);
+ if (value == null)
+ throw new BadCredentialsException("User " + username
+ + " is not registered");
+ List<GrantedAuthority> grantedAuthorities = new ArrayList<GrantedAuthority>();
+ for (String role : defaultRoles)
+ grantedAuthorities.add(new GrantedAuthorityImpl(role));
+ return new User(
+ username,
+ value,
+ true,
+ true,
+ true,
+ true,
+ grantedAuthorities
+ .toArray(new GrantedAuthority[grantedAuthorities.size()]));
+ }
+
+ public void setMapping(Resource mapping) {
+ this.mapping = mapping;
+ }
+
+ public void setDefaultRoles(List<String> defaultRoles) {
+ this.defaultRoles = defaultRoles;
+ }
+
+}
--- /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.security.core;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.argeo.security.OsAuthenticationToken;
+import org.springframework.security.Authentication;
+import org.springframework.security.AuthenticationException;
+import org.springframework.security.GrantedAuthority;
+import org.springframework.security.GrantedAuthorityImpl;
+import org.springframework.security.providers.AuthenticationProvider;
+
+/**
+ * Validates an OS authentication. The id is that it will always be
+ * authenticated since we are always runnign within an OS, but the fact that the
+ * {@link Authentication} works properly depends on the proper OS login module
+ * having been called as well. TODO make it more configurable (base roles, is
+ * admin)
+ */
+public class OsAuthenticationProvider implements AuthenticationProvider {
+ final static String osUserRole = "ROLE_OS_USER";
+ final static String userRole = "ROLE_USER";
+ final static String adminRole = "ROLE_ADMIN";
+
+ final static Boolean isAdmin = true;
+
+ public Authentication authenticate(Authentication authentication)
+ throws AuthenticationException {
+ return new OsAuthenticationToken(getBaseAuthorities());
+ }
+
+ public static GrantedAuthority[] getBaseAuthorities() {
+ List<GrantedAuthority> auths = new ArrayList<GrantedAuthority>();
+ auths.add(new GrantedAuthorityImpl(osUserRole));
+ auths.add(new GrantedAuthorityImpl(userRole));
+ if (isAdmin)
+ auths.add(new GrantedAuthorityImpl(adminRole));
+ return auths.toArray(new GrantedAuthority[auths.size()]);
+ }
+
+ @SuppressWarnings("rawtypes")
+ public boolean supports(Class authentication) {
+ return OsAuthenticationToken.class.isAssignableFrom(authentication);
+ }
+
+}
--- /dev/null
+package org.argeo.security.core;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+
+/**
+ * Logs the name and version of an OSGi bundle based on its
+ * {@link BundleContext}.
+ */
+public class OsgiModuleLabel {
+ private final static Log log = LogFactory.getLog(OsgiModuleLabel.class);
+
+ private Bundle bundle;
+
+ public OsgiModuleLabel() {
+ }
+
+ /** Sets without logging. */
+ public OsgiModuleLabel(Bundle bundle) {
+ this.bundle = bundle;
+ }
+
+ /**
+ * Retrieved bundle from a bundle context and logs it. Typically to be set
+ * as a Spring bean.
+ */
+ public void setBundleContext(BundleContext bundleContext) {
+ this.bundle = bundleContext.getBundle();
+ log.info(msg());
+ }
+
+ public String msg() {
+ String name = bundle.getHeaders().get(Constants.BUNDLE_NAME).toString();
+ String symbolicName = bundle.getSymbolicName();
+ String version = bundle.getVersion().toString();
+ return name + " v" + version + " (" + symbolicName + ")";
+ }
+}
--- /dev/null
+package org.argeo.security.core;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.security.UserAdminService;
+
+/**
+ * Register one or many roles via a user admin service. Does nothing if the role
+ * is already registered.
+ */
+public class SimpleRoleRegistration implements Runnable {
+ private final static Log log = LogFactory
+ .getLog(SimpleRoleRegistration.class);
+
+ private String role;
+ private List<String> roles = new ArrayList<String>();
+ private UserAdminService userAdminService;
+
+ @Override
+ public void run() {
+ Set<String> existingRoles = userAdminService.listEditableRoles();
+ if (role != null && !existingRoles.contains(role))
+ newRole(role);
+ for (String r : roles) {
+ if (!existingRoles.contains(r))
+ newRole(r);
+ }
+ }
+
+ protected void newRole(String r) {
+ userAdminService.newRole(r);
+ log.info("Added role " + r + " required by application.");
+ }
+
+ public void register(UserAdminService userAdminService, Map<?, ?> properties) {
+ this.userAdminService = userAdminService;
+ run();
+ }
+
+ public void setRole(String role) {
+ this.role = role;
+ }
+
+ public void setRoles(List<String> roles) {
+ this.roles = roles;
+ }
+
+ public void setUserAdminService(UserAdminService userAdminService) {
+ this.userAdminService = userAdminService;
+ }
+
+}
--- /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.security.crypto;
+
+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.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, CryptoKeyring {
+ static {
+ Security.addProvider(new BouncyCastleProvider());
+ }
+
+ 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 ArgeoException("Keyring login failed", e);
+ }
+
+ } else {
+ SecretKey secretKey = iterator.next();
+ if (iterator.hasNext())
+ throw new ArgeoException(
+ "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 ArgeoException("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 ArgeoException("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 ArgeoException("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 ArgeoException("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
+/*
+ * 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.security.crypto;
+
+import org.argeo.util.security.Keyring;
+
+/**
+ * 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.security.crypto;
+
+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.security.crypto;
+
+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.security.crypto;
+
+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 java.security.Security;
+
+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.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.ArgeoException;
+import org.argeo.StreamUtils;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+
+/** Simple password based encryption / decryption */
+public class PasswordBasedEncryption {
+ private final static Log log = LogFactory
+ .getLog(PasswordBasedEncryption.class);
+
+ static {
+ Security.addProvider(new BouncyCastleProvider());
+ }
+
+ 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;
+
+ /**
+ * 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
+ */
+ 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;
+ log.warn("'" + e.getMessage() + "', will use " + secreteKeyLength
+ + " secrete key length instead of "
+ + previousSecreteKeyLength);
+ try {
+ initKeyAndCiphers(password, passwordSalt, initializationVector);
+ } catch (Exception e1) {
+ throw new ArgeoException(
+ "Cannot get secret key (with restricted length)", e1);
+ }
+ } catch (Exception e) {
+ throw new ArgeoException("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);
+ }
+ ecipher = Cipher.getInstance(getCipherName(), securityProviderName);
+ 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 ArgeoException("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 ArgeoException("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 ArgeoException("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 ArgeoException("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.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;
+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.ArgeoException;
+import org.argeo.jcr.ArgeoNames;
+import org.argeo.jcr.ArgeoTypes;
+import org.argeo.jcr.JcrUtils;
+import org.argeo.jcr.UserJcrUtils;
+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 {
+ /**
+ * 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 = UserJcrUtils.getUserHome(session);
+ return userHome.hasNode(ARGEO_KEYRING);
+ } catch (RepositoryException e) {
+ throw new ArgeoException("Cannot check whether keyring is setup", e);
+ }
+ }
+
+ @Override
+ protected void setup(char[] password) {
+ Binary binary = null;
+ InputStream in = null;
+ try {
+ Node userHome = UserJcrUtils.getUserHome(session);
+ if (userHome.hasNode(ARGEO_KEYRING))
+ throw new ArgeoException("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);
+
+ // 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 ArgeoException("Cannot setup keyring", e);
+ } finally {
+ JcrUtils.closeQuietly(binary);
+ IOUtils.closeQuietly(in);
+ // JcrUtils.discardQuietly(session);
+ }
+ }
+
+ @Override
+ protected void handleKeySpecCallback(PBEKeySpecCallback pbeCallback) {
+ try {
+ Node userHome = UserJcrUtils.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 ArgeoException("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 ArgeoException("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 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));
+ 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 ArgeoException("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 ArgeoException("Cannot decrypt", e);
+ } finally {
+ IOUtils.closeQuietly(encrypted);
+ IOUtils.closeQuietly(reader);
+ JcrUtils.closeQuietly(binary);
+ }
+ }
+
+ protected Cipher createCipher() {
+ try {
+ Node userHome = UserJcrUtils.getUserHome(session);
+ if (!userHome.hasNode(ARGEO_KEYRING))
+ throw new ArgeoException("Keyring not setup");
+ Node keyring = userHome.getNode(ARGEO_KEYRING);
+ Cipher cipher = Cipher.getInstance(keyring
+ .getProperty(ARGEO_CIPHER).getString(),
+ getSecurityProvider());
+ return cipher;
+ } catch (Exception e) {
+ throw new ArgeoException("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.security.jcr;
+
+import java.util.List;
+
+import javax.jcr.Node;
+import javax.jcr.Session;
+
+/**
+ * Manages data expected by the Argeo security model, such as user home and
+ * profile.
+ */
+public interface JcrSecurityModel {
+ /**
+ * To be called before user details are loaded. Make sure than any logged in
+ * user has a home directory with full access and a profile with information
+ * about him (read access)
+ *
+ * @return the user profile (whose parent is the user home), never null
+ */
+ public Node sync(Session session, String username, List<String> roles);
+}
--- /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.security.jcr;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jcr.Node;
+import javax.jcr.Property;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.argeo.jcr.ArgeoNames;
+import org.argeo.jcr.UserJcrUtils;
+import org.springframework.security.BadCredentialsException;
+import org.springframework.security.DisabledException;
+import org.springframework.security.GrantedAuthority;
+import org.springframework.security.GrantedAuthorityImpl;
+import org.springframework.security.LockedException;
+import org.springframework.security.userdetails.User;
+
+/** User details based on a user profile node. */
+public class JcrUserDetails extends User implements ArgeoNames {
+ private static final long serialVersionUID = -8142764995842559646L;
+ private final String homePath;
+ private final String securityWorkspace;
+
+ /** Human readable user name */
+ private String displayName;
+
+ protected JcrUserDetails(String securityWorkspace, String homePath,
+ String username, String password, boolean enabled,
+ boolean accountNonExpired, boolean credentialsNonExpired,
+ boolean accountNonLocked, GrantedAuthority[] authorities)
+ throws IllegalArgumentException {
+ super(username, password, enabled, accountNonExpired,
+ credentialsNonExpired, accountNonLocked, authorities);
+ this.homePath = homePath;
+ this.securityWorkspace = securityWorkspace;
+ }
+
+ public JcrUserDetails(Node userProfile, String password,
+ GrantedAuthority[] authorities) throws RepositoryException {
+ super(
+ userProfile.getProperty(ARGEO_USER_ID).getString(),
+ password,
+ userProfile.getProperty(ARGEO_ENABLED).getBoolean(),
+ userProfile.getProperty(ARGEO_ACCOUNT_NON_EXPIRED).getBoolean(),
+ userProfile.getProperty(ARGEO_CREDENTIALS_NON_EXPIRED)
+ .getBoolean(), userProfile.getProperty(
+ ARGEO_ACCOUNT_NON_LOCKED).getBoolean(), authorities);
+ // human readable name
+ if (userProfile.hasProperty(Property.JCR_TITLE)) {
+ displayName = userProfile.getProperty(Property.JCR_TITLE)
+ .getString();
+ if (displayName.trim().equals(""))
+ displayName = null;
+ }
+ if (displayName == null)
+ displayName = userProfile.getProperty(ARGEO_USER_ID).getString();
+ // home is defined as the parent of the profile
+ homePath = userProfile.getParent().getPath();
+ securityWorkspace = userProfile.getSession().getWorkspace().getName();
+ }
+
+ /**
+ * Convenience constructor
+ *
+ * @param session
+ * the security session
+ * @param username
+ * the username
+ * @param password
+ * the password, can be null
+ * @param authorities
+ * the granted authorities
+ */
+ public JcrUserDetails(Session session, String username, String password,
+ GrantedAuthority[] authorities) throws RepositoryException {
+ this(UserJcrUtils.getUserProfile(session, username),
+ password != null ? password : "", authorities);
+ }
+
+ /**
+ * Check the account status in JCR, throwing the exceptions expected by
+ * Spring security if needed.
+ */
+ public static void checkAccountStatus(Node userProfile) {
+ try {
+ if (!userProfile.getProperty(ARGEO_ENABLED).getBoolean())
+ throw new DisabledException(userProfile.getPath()
+ + " is disabled");
+ if (!userProfile.getProperty(ARGEO_ACCOUNT_NON_LOCKED).getBoolean())
+ throw new LockedException(userProfile.getPath() + " is locked");
+ } catch (RepositoryException e) {
+ throw new BadCredentialsException("Cannot check account status", e);
+ }
+ }
+
+ /** Clone immutable with new roles */
+ public JcrUserDetails cloneWithNewRoles(List<String> roles) {
+ List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
+ for (String role : roles) {
+ authorities.add(new GrantedAuthorityImpl(role));
+ }
+ return new JcrUserDetails(securityWorkspace, homePath, getUsername(),
+ getPassword(), isEnabled(), isAccountNonExpired(),
+ isAccountNonExpired(), isAccountNonLocked(),
+ authorities.toArray(new GrantedAuthority[authorities.size()]));
+ }
+
+ /** Clone immutable with new password */
+ public JcrUserDetails cloneWithNewPassword(String password) {
+ return new JcrUserDetails(securityWorkspace, homePath, getUsername(),
+ password, isEnabled(), isAccountNonExpired(),
+ isAccountNonExpired(), isAccountNonLocked(), getAuthorities());
+ }
+
+ public String getHomePath() {
+ return homePath;
+ }
+
+ /** Not yet API */
+ public String getSecurityWorkspace() {
+ return securityWorkspace;
+ }
+
+ /** The human readable name of this user */
+ public String getDisplayName() {
+ return displayName;
+ }
+
+ @Override
+ public String toString() {
+ return getDisplayName();
+ }
+
+}
--- /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.security.jcr;
+
+import javax.jcr.Node;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.argeo.ArgeoException;
+import org.argeo.jcr.JcrUtils;
+import org.argeo.security.OsAuthenticationToken;
+import org.argeo.security.SecurityUtils;
+import org.argeo.security.core.OsAuthenticationProvider;
+import org.springframework.security.Authentication;
+import org.springframework.security.AuthenticationException;
+import org.springframework.security.BadCredentialsException;
+import org.springframework.security.GrantedAuthority;
+import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
+import org.springframework.security.userdetails.UserDetails;
+
+/** Relies on OS to authenticate and additionally setup JCR */
+public class OsJcrAuthenticationProvider extends OsAuthenticationProvider {
+ private Repository repository;
+ private Session nodeSession;
+
+ private UserDetails userDetails;
+ private JcrSecurityModel jcrSecurityModel = new SimpleJcrSecurityModel();
+
+ private final static String JVM_OSUSER = System.getProperty("user.name");
+
+ public void init() {
+ try {
+ nodeSession = repository.login();
+ } catch (RepositoryException e) {
+ throw new ArgeoException("Cannot initialize", e);
+ }
+ }
+
+ public void destroy() {
+ JcrUtils.logoutQuietly(nodeSession);
+ }
+
+ public Authentication authenticate(Authentication authentication)
+ throws AuthenticationException {
+ if (authentication instanceof UsernamePasswordAuthenticationToken) {
+ // deal with remote access to internal server
+ // FIXME very primitive and unsecure at this sSession adminSession
+ // =tage
+ // consider using the keyring for username / password authentication
+ // or certificate
+ UsernamePasswordAuthenticationToken upat = (UsernamePasswordAuthenticationToken) authentication;
+ if (!upat.getPrincipal().toString().equals(JVM_OSUSER))
+ throw new BadCredentialsException("Wrong credentials");
+ UsernamePasswordAuthenticationToken authen = new UsernamePasswordAuthenticationToken(
+ authentication.getPrincipal(),
+ authentication.getCredentials(), getBaseAuthorities());
+ authen.setDetails(userDetails);
+ return authen;
+ } else if (authentication instanceof OsAuthenticationToken) {
+ OsAuthenticationToken authen = (OsAuthenticationToken) super
+ .authenticate(authentication);
+ try {
+ // WARNING: at this stage we assume that the java properties
+ // will have the same value
+ GrantedAuthority[] authorities = getBaseAuthorities();
+ String username = JVM_OSUSER;
+ Node userProfile = jcrSecurityModel.sync(nodeSession, username,
+ SecurityUtils.authoritiesToStringList(authorities));
+ JcrUserDetails.checkAccountStatus(userProfile);
+
+ userDetails = new JcrUserDetails(userProfile, authen
+ .getCredentials().toString(), authorities);
+ authen.setDetails(userDetails);
+ return authen;
+ } catch (RepositoryException e) {
+ JcrUtils.discardQuietly(nodeSession);
+ throw new ArgeoException(
+ "Unexpected exception when synchronizing OS and JCR security ",
+ e);
+ }
+ } else {
+ throw new ArgeoException("Unsupported authentication "
+ + authentication.getClass());
+ }
+ }
+
+ public void setRepository(Repository repository) {
+ this.repository = repository;
+ }
+
+ public void setJcrSecurityModel(JcrSecurityModel jcrSecurityModel) {
+ this.jcrSecurityModel = jcrSecurityModel;
+ }
+
+ @SuppressWarnings("rawtypes")
+ public boolean supports(Class authentication) {
+ return OsAuthenticationToken.class.isAssignableFrom(authentication)
+ || UsernamePasswordAuthenticationToken.class
+ .isAssignableFrom(authentication);
+ }
+}
\ 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.security.jcr;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.jcr.Node;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.argeo.ArgeoException;
+import org.argeo.jcr.JcrUtils;
+import org.argeo.jcr.UserJcrUtils;
+import org.argeo.security.UserAdminService;
+import org.springframework.dao.DataAccessException;
+import org.springframework.security.userdetails.User;
+import org.springframework.security.userdetails.UserDetails;
+import org.springframework.security.userdetails.UsernameNotFoundException;
+
+/**
+ * Dummy user service to be used when running as a single OS user (typically
+ * desktop). TODO integrate with JCR user / groups
+ */
+public class OsJcrUserAdminService implements UserAdminService {
+ private Repository repository;
+
+ /** In memory roles provided by applications. */
+ private List<String> roles = new ArrayList<String>();
+
+ // private Session adminSession;
+
+ public void init() {
+ // try {
+ // adminSession = repository.login();
+ // } catch (RepositoryException e) {
+ // throw new ArgeoException("Cannot initialize", e);
+ // }
+ }
+
+ public void destroy() {
+ // JcrUtils.logoutQuietly(adminSession);
+ }
+
+ /** <b>Unsupported</b> */
+ public void createUser(UserDetails user) {
+ throw new UnsupportedOperationException();
+ }
+
+ /** Does nothing */
+ public void updateUser(UserDetails user) {
+
+ }
+
+ /** <b>Unsupported</b> */
+ public void deleteUser(String username) {
+ throw new UnsupportedOperationException();
+ }
+
+ /** <b>Unsupported</b> */
+ public void changePassword(String oldPassword, String newPassword) {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean userExists(String username) {
+ if (getSPropertyUsername().equals(username))
+ return true;
+ else
+ return false;
+ }
+
+ public UserDetails loadUserByUsername(String username)
+ throws UsernameNotFoundException, DataAccessException {
+ if (getSPropertyUsername().equals(username)) {
+ UserDetails userDetails;
+ if (repository != null) {
+ Session adminSession = null;
+ try {
+ adminSession = repository.login();
+ Node userProfile = UserJcrUtils.getUserProfile(
+ adminSession, username);
+ userDetails = new JcrUserDetails(userProfile, "",
+ OsJcrAuthenticationProvider.getBaseAuthorities());
+ } catch (RepositoryException e) {
+ throw new ArgeoException(
+ "Cannot retrieve user profile for " + username, e);
+ } finally {
+ JcrUtils.logoutQuietly(adminSession);
+ }
+ } else {
+ userDetails = new User(username, "", true, true, true, true,
+ OsJcrAuthenticationProvider.getBaseAuthorities());
+ }
+ return userDetails;
+ } else {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ protected final String getSPropertyUsername() {
+ return System.getProperty("user.name");
+ }
+
+ public Set<String> listUsers() {
+ Set<String> set = new HashSet<String>();
+ set.add(getSPropertyUsername());
+ return set;
+ }
+
+ public Set<String> listUsersInRole(String role) {
+ Set<String> set = new HashSet<String>();
+ set.add(getSPropertyUsername());
+ return set;
+ }
+
+ /** Does nothing */
+ public void synchronize() {
+ }
+
+ /** <b>Unsupported</b> */
+ public void newRole(String role) {
+ roles.add(role);
+ }
+
+ public Set<String> listEditableRoles() {
+ return new HashSet<String>(roles);
+ }
+
+ /** <b>Unsupported</b> */
+ public void deleteRole(String role) {
+ roles.remove(role);
+ }
+
+ public void setRepository(Repository repository) {
+ this.repository = repository;
+ }
+}
--- /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.security.jcr;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.List;
+
+import javax.jcr.Node;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.RepositoryFactory;
+import javax.jcr.Session;
+import javax.jcr.SimpleCredentials;
+import javax.jcr.Value;
+
+import org.argeo.ArgeoException;
+import org.argeo.jcr.ArgeoJcrConstants;
+import org.argeo.jcr.ArgeoNames;
+import org.argeo.jcr.UserJcrUtils;
+import org.argeo.security.NodeAuthenticationToken;
+import org.osgi.framework.BundleContext;
+import org.springframework.security.Authentication;
+import org.springframework.security.AuthenticationException;
+import org.springframework.security.BadCredentialsException;
+import org.springframework.security.GrantedAuthority;
+import org.springframework.security.GrantedAuthorityImpl;
+import org.springframework.security.providers.AuthenticationProvider;
+
+/** Connects to a JCR repository and delegates authentication to it. */
+public class RemoteJcrAuthenticationProvider implements AuthenticationProvider,
+ ArgeoNames {
+ private RepositoryFactory repositoryFactory;
+ private BundleContext bundleContext;
+
+ public final static String ROLE_REMOTE = "ROLE_REMOTE";
+
+ public Authentication authenticate(Authentication authentication)
+ throws AuthenticationException {
+ NodeAuthenticationToken siteAuth = (NodeAuthenticationToken) authentication;
+ String url = siteAuth.getUrl();
+ if (url == null)// TODO? login on own node
+ throw new ArgeoException("No url set in " + siteAuth);
+ Session session;
+
+ Node userProfile;
+ try {
+ SimpleCredentials sp = new SimpleCredentials(siteAuth.getName(),
+ siteAuth.getCredentials().toString().toCharArray());
+ // get repository
+ Repository repository = new RemoteJcrRepositoryWrapper(
+ repositoryFactory, url, sp);
+ if (bundleContext != null) {
+ Dictionary<String, String> serviceProperties = new Hashtable<String, String>();
+ serviceProperties.put(ArgeoJcrConstants.JCR_REPOSITORY_ALIAS,
+ ArgeoJcrConstants.ALIAS_NODE);
+ serviceProperties
+ .put(ArgeoJcrConstants.JCR_REPOSITORY_URI, url);
+ bundleContext.registerService(Repository.class.getName(),
+ repository, serviceProperties);
+ }
+ // Repository repository = ArgeoJcrUtils.getRepositoryByUri(
+ // repositoryFactory, url);
+ // if (repository == null)
+ // throw new ArgeoException("Cannot connect to " + url);
+
+ session = repository.login(sp, null);
+
+ userProfile = UserJcrUtils.getUserProfile(session, sp.getUserID());
+ JcrUserDetails.checkAccountStatus(userProfile);
+
+ // Node userHome = UserJcrUtils.getUserHome(session);
+ // if (userHome == null ||
+ // !userHome.hasNode(ArgeoNames.ARGEO_PROFILE))
+ // throw new ArgeoException("No profile for user "
+ // + siteAuth.getName() + " in security workspace "
+ // + siteAuth.getSecurityWorkspace() + " of "
+ // + siteAuth.getUrl());
+ // userProfile = userHome.getNode(ArgeoNames.ARGEO_PROFILE);
+ } catch (RepositoryException e) {
+ throw new BadCredentialsException(
+ "Cannot authenticate " + siteAuth, e);
+ }
+
+ try {
+ // Node userHome = UserJcrUtils.getUserHome(session);
+ // retrieve remote roles
+ List<GrantedAuthority> authoritiesList = new ArrayList<GrantedAuthority>();
+ if (userProfile != null
+ && userProfile.hasProperty(ArgeoNames.ARGEO_REMOTE_ROLES)) {
+ Value[] roles = userProfile.getProperty(
+ ArgeoNames.ARGEO_REMOTE_ROLES).getValues();
+ for (int i = 0; i < roles.length; i++)
+ authoritiesList.add(new GrantedAuthorityImpl(roles[i]
+ .getString()));
+ }
+ authoritiesList.add(new GrantedAuthorityImpl(ROLE_REMOTE));
+
+ // create authenticated objects
+ GrantedAuthority[] authorities = authoritiesList
+ .toArray(new GrantedAuthority[authoritiesList.size()]);
+ JcrUserDetails userDetails = new JcrUserDetails(userProfile,
+ siteAuth.getCredentials().toString(), authorities);
+ NodeAuthenticationToken authenticated = new NodeAuthenticationToken(
+ siteAuth, authorities);
+ authenticated.setDetails(userDetails);
+ return authenticated;
+ } catch (RepositoryException e) {
+ throw new ArgeoException(
+ "Unexpected exception when authenticating to " + url, e);
+ }
+ }
+
+ @SuppressWarnings("rawtypes")
+ public boolean supports(Class authentication) {
+ return NodeAuthenticationToken.class.isAssignableFrom(authentication);
+ }
+
+ public void setRepositoryFactory(RepositoryFactory repositoryFactory) {
+ this.repositoryFactory = repositoryFactory;
+ }
+
+ public void setBundleContext(BundleContext bundleContext) {
+ this.bundleContext = bundleContext;
+ }
+
+}
--- /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.security.jcr;
+
+import javax.jcr.Credentials;
+import javax.jcr.LoginException;
+import javax.jcr.NoSuchWorkspaceException;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.RepositoryFactory;
+import javax.jcr.Session;
+import javax.jcr.SimpleCredentials;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.ArgeoException;
+import org.argeo.jcr.ArgeoJcrUtils;
+import org.argeo.jcr.JcrRepositoryWrapper;
+import org.argeo.security.NodeAuthenticationToken;
+import org.argeo.security.SystemAuthentication;
+import org.springframework.security.Authentication;
+import org.springframework.security.context.SecurityContextHolder;
+import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
+
+/**
+ * Wrapper around a remote Jackrabbit repository which allows to simplify
+ * configuration and intercept some actions. It exposes itself as a
+ * {@link Repository}.
+ */
+public class RemoteJcrRepositoryWrapper extends JcrRepositoryWrapper {
+ private final static Log log = LogFactory
+ .getLog(RemoteJcrRepositoryWrapper.class);
+
+ private String uri = null;
+
+ private RepositoryFactory repositoryFactory;
+
+ // remote
+ private Credentials remoteSystemCredentials = null;
+
+ /**
+ * Empty constructor, {@link #init()} should be called after properties have
+ * been set
+ */
+ public RemoteJcrRepositoryWrapper() {
+ }
+
+ /**
+ * Embedded constructor, calling the {@link #init()} method.
+ *
+ * @param alias
+ * if not null the repository will be published under this alias
+ */
+ public RemoteJcrRepositoryWrapper(RepositoryFactory repositoryFactory,
+ String uri, Credentials remoteSystemCredentials) {
+ this.repositoryFactory = repositoryFactory;
+ this.uri = uri;
+ this.remoteSystemCredentials = remoteSystemCredentials;
+ init();
+ }
+
+ public void init() {
+ Repository repository = createJackrabbitRepository();
+ setRepository(repository);
+ }
+
+ /** Actually creates the new repository. */
+ protected Repository createJackrabbitRepository() {
+ long begin = System.currentTimeMillis();
+ try {
+ if (uri == null || uri.trim().equals(""))
+ throw new ArgeoException("Remote URI not set");
+
+ Repository repository = ArgeoJcrUtils.getRepositoryByUri(
+ repositoryFactory, uri);
+ if (repository == null)
+ throw new ArgeoException("Remote JCR repository " + uri
+ + " not found");
+ double duration = ((double) (System.currentTimeMillis() - begin)) / 1000;
+ log.info("Created remote JCR repository in " + duration
+ + " s from URI " + uri);
+ // we assume that the data model of the remote repository has
+ // been properly initialized
+ return repository;
+ } catch (Exception e) {
+ throw new ArgeoException("Cannot create remote JCR repository "
+ + uri, e);
+ }
+ }
+
+ /** Shutdown the repository */
+ public void destroy() throws Exception {
+ super.destroy();
+ }
+
+ /** Central login method */
+ public Session login(Credentials credentials, String workspaceName)
+ throws LoginException, NoSuchWorkspaceException,
+ RepositoryException {
+
+ // retrieve credentials for remote
+ if (credentials == null) {
+ Authentication authentication = SecurityContextHolder.getContext()
+ .getAuthentication();
+ if (authentication != null) {
+ if (authentication instanceof UsernamePasswordAuthenticationToken) {
+ UsernamePasswordAuthenticationToken upat = (UsernamePasswordAuthenticationToken) authentication;
+ credentials = new SimpleCredentials(upat.getName(), upat
+ .getCredentials().toString().toCharArray());
+ } else if ((authentication instanceof SystemAuthentication)
+ || (authentication instanceof NodeAuthenticationToken)) {
+ credentials = remoteSystemCredentials;
+ }
+ }
+ }
+
+ return super.login(credentials, workspaceName);
+ }
+
+ public void setUri(String uri) {
+ this.uri = uri;
+ }
+
+ public void setRepositoryFactory(RepositoryFactory repositoryFactory) {
+ this.repositoryFactory = repositoryFactory;
+ }
+
+ public void setRemoteSystemCredentials(Credentials remoteSystemCredentials) {
+ this.remoteSystemCredentials = remoteSystemCredentials;
+ }
+
+}
--- /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.security.jcr;
+
+import javax.jcr.Session;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.jcr.spring.ThreadBoundSession;
+import org.springframework.security.Authentication;
+import org.springframework.security.context.SecurityContextHolder;
+
+/**
+ * Thread bounded JCR session factory which checks authentication and is
+ * autoconfigured in Spring.
+ */
+public class SecureThreadBoundSession extends ThreadBoundSession {
+ private final static Log log = LogFactory
+ .getLog(SecureThreadBoundSession.class);
+
+ @Override
+ protected Session preCall(Session session) {
+ Authentication authentication = SecurityContextHolder.getContext()
+ .getAuthentication();
+ if (authentication != null) {
+ String userID = session.getUserID();
+ String currentUserName = authentication.getName();
+ if (currentUserName != null) {
+ if (!userID.equals(currentUserName)) {
+ log.warn("Current session has user ID " + userID
+ + " while logged is user is " + currentUserName
+ + "(authentication=" + authentication + ")"
+ + ". Re-login.");
+ // TODO throw an exception
+ return login();
+ }
+ }
+ }
+ return super.preCall(session);
+ }
+
+}
--- /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.security.jcr;
+
+import java.util.List;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.Value;
+import javax.jcr.security.Privilege;
+import javax.jcr.version.VersionManager;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+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;
+
+/**
+ * Manages data expected by the Argeo security model, such as user home and
+ * profile.
+ */
+public class SimpleJcrSecurityModel implements JcrSecurityModel {
+ private final static Log log = LogFactory
+ .getLog(SimpleJcrSecurityModel.class);
+ // ArgeoNames not implemented as interface in order to ease derivation by
+ // Jackrabbit bundles
+
+ /** The home base path. */
+ private String homeBasePath = "/home";
+
+ public synchronized Node sync(Session session, String username,
+ List<String> roles) {
+ // TODO check user name validity (e.g. should not start by ROLE_)
+
+ try {
+ Node userHome = UserJcrUtils.getUserHome(session, username);
+ if (userHome == null) {
+ String homePath = generateUserPath(homeBasePath, username);
+ userHome = JcrUtils.mkdirs(session, homePath);
+ // userHome = JcrUtils.mkfolders(session, homePath);
+ userHome.addMixin(ArgeoTypes.ARGEO_USER_HOME);
+ userHome.setProperty(ArgeoNames.ARGEO_USER_ID, username);
+ session.save();
+
+ JcrUtils.clearAccessControList(session, homePath, username);
+ JcrUtils.addPrivilege(session, homePath, username,
+ Privilege.JCR_ALL);
+ } else {
+ // for backward compatibility with pre 1.0 security model
+ if (userHome.hasNode(ArgeoNames.ARGEO_PROFILE)) {
+ userHome.getNode(ArgeoNames.ARGEO_PROFILE).remove();
+ userHome.getSession().save();
+ }
+ }
+
+ // Remote roles
+ if (roles != null) {
+ // writeRemoteRoles(userHome, roles);
+ }
+
+ Node userProfile = UserJcrUtils.getUserProfile(session, username);
+ if (userProfile == null) {
+ String personPath = generateUserPath(
+ ArgeoJcrConstants.PEOPLE_BASE_PATH, username);
+ Node personBase = JcrUtils.mkdirs(session, personPath);
+ userProfile = personBase.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);
+ session.save();
+
+ JcrUtils.clearAccessControList(session, userProfile.getPath(),
+ username);
+ JcrUtils.addPrivilege(session, userProfile.getPath(), username,
+ Privilege.JCR_READ);
+
+ VersionManager versionManager = session.getWorkspace()
+ .getVersionManager();
+ if (versionManager.isCheckedOut(userProfile.getPath()))
+ versionManager.checkin(userProfile.getPath());
+
+ }
+
+ // Remote roles
+ if (roles != null) {
+ writeRemoteRoles(userProfile, roles);
+ }
+ return userProfile;
+ } catch (RepositoryException e) {
+ JcrUtils.discardQuietly(session);
+ throw new ArgeoException("Cannot sync node security model for "
+ + username, e);
+ }
+ }
+
+ /** Generate path for a new user home */
+ protected String generateUserPath(String base, String username) {
+ int atIndex = username.indexOf('@');
+ if (atIndex > 0) {
+ String domain = username.substring(0, atIndex);
+ String name = username.substring(atIndex + 1);
+ return base + '/' + JcrUtils.firstCharsToPath(domain, 2) + '/'
+ + domain + '/' + JcrUtils.firstCharsToPath(name, 2) + '/'
+ + name;
+ } else if (atIndex == 0 || atIndex == (username.length() - 1)) {
+ throw new ArgeoException("Unsupported username " + username);
+ } else {
+ return base + '/' + JcrUtils.firstCharsToPath(username, 2) + '/'
+ + username;
+ }
+ }
+
+ /** Write remote roles used by remote access in the home directory */
+ protected void writeRemoteRoles(Node userHome, List<String> roles)
+ throws RepositoryException {
+ boolean writeRoles = false;
+ if (userHome.hasProperty(ArgeoNames.ARGEO_REMOTE_ROLES)) {
+ Value[] remoteRoles = userHome.getProperty(
+ ArgeoNames.ARGEO_REMOTE_ROLES).getValues();
+ if (remoteRoles.length != roles.size())
+ writeRoles = true;
+ else
+ for (int i = 0; i < remoteRoles.length; i++)
+ if (!remoteRoles[i].getString().equals(roles.get(i)))
+ writeRoles = true;
+ } else
+ writeRoles = true;
+
+ if (writeRoles) {
+ userHome.getSession().getWorkspace().getVersionManager()
+ .checkout(userHome.getPath());
+ String[] roleIds = roles.toArray(new String[roles.size()]);
+ userHome.setProperty(ArgeoNames.ARGEO_REMOTE_ROLES, roleIds);
+ JcrUtils.updateLastModified(userHome);
+ userHome.getSession().save();
+ userHome.getSession().getWorkspace().getVersionManager()
+ .checkin(userHome.getPath());
+ if (log.isDebugEnabled())
+ log.debug("Wrote remote roles " + roles + " for "
+ + userHome.getProperty(ArgeoNames.ARGEO_USER_ID));
+ }
+
+ }
+
+ public void setHomeBasePath(String homeBasePath) {
+ this.homeBasePath = homeBasePath;
+ }
+
+}
--- /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.security.jcr.rememberme;
+
+import java.util.Date;
+
+import org.springframework.security.ui.rememberme.PersistentRememberMeToken;
+import org.springframework.security.ui.rememberme.PersistentTokenRepository;
+
+public class JcrPersistentTokenRepository implements PersistentTokenRepository {
+
+ public void createNewToken(PersistentRememberMeToken token) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void updateToken(String series, String tokenValue, Date lastUsed) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public PersistentRememberMeToken getTokenForSeries(String seriesId) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public void removeUserTokens(String username) {
+ // TODO Auto-generated method stub
+
+ }
+
+}
--- /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.security.log4j;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.Properties;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import org.apache.log4j.AppenderSkeleton;
+import org.apache.log4j.Level;
+import org.apache.log4j.LogManager;
+import org.apache.log4j.Logger;
+import org.apache.log4j.PropertyConfigurator;
+import org.apache.log4j.spi.LoggingEvent;
+import org.argeo.ArgeoException;
+import org.argeo.ArgeoLogListener;
+import org.argeo.ArgeoLogger;
+import org.argeo.security.SecurityUtils;
+
+/** Not meant to be used directly in standard log4j config */
+public class SecureLogger implements ArgeoLogger {
+
+ private Boolean disabled = false;
+
+ private String level = null;
+
+ private Level log4jLevel = null;
+ // private Layout layout;
+
+ private Properties configuration;
+
+ private AppenderImpl appender;
+
+ private final List<ArgeoLogListener> everythingListeners = Collections
+ .synchronizedList(new ArrayList<ArgeoLogListener>());
+ private final List<ArgeoLogListener> allUsersListeners = Collections
+ .synchronizedList(new ArrayList<ArgeoLogListener>());
+ private final Map<String, List<ArgeoLogListener>> userListeners = Collections
+ .synchronizedMap(new HashMap<String, List<ArgeoLogListener>>());
+
+ private BlockingQueue<LogEvent> events;
+ private LogDispatcherThread logDispatcherThread = new LogDispatcherThread();
+
+ private Integer maxLastEventsCount = 10 * 1000;
+
+ /** Marker to prevent stack overflow */
+ private ThreadLocal<Boolean> dispatching = new ThreadLocal<Boolean>() {
+
+ @Override
+ protected Boolean initialValue() {
+ return false;
+ }
+ };
+
+ public void init() {
+ try {
+ events = new LinkedBlockingQueue<LogEvent>();
+
+ // if (layout != null)
+ // setLayout(layout);
+ // else
+ // setLayout(new PatternLayout(pattern));
+ appender = new AppenderImpl();
+ reloadConfiguration();
+ Logger.getRootLogger().addAppender(appender);
+
+ logDispatcherThread = new LogDispatcherThread();
+ logDispatcherThread.start();
+ } catch (Exception e) {
+ throw new ArgeoException("Cannot initialize log4j");
+ }
+ }
+
+ public void destroy() throws Exception {
+ Logger.getRootLogger().removeAppender(appender);
+ allUsersListeners.clear();
+ for (List<ArgeoLogListener> lst : userListeners.values())
+ lst.clear();
+ userListeners.clear();
+
+ events.clear();
+ events = null;
+ logDispatcherThread.interrupt();
+ }
+
+ // public void setLayout(Layout layout) {
+ // this.layout = layout;
+ // }
+
+ public synchronized void register(ArgeoLogListener listener,
+ Integer numberOfPreviousEvents) {
+ String username = SecurityUtils.getCurrentThreadUsername();
+ if (username == null)
+ throw new ArgeoException(
+ "Only authenticated users can register a log listener");
+
+ if (!userListeners.containsKey(username)) {
+ List<ArgeoLogListener> lst = Collections
+ .synchronizedList(new ArrayList<ArgeoLogListener>());
+ userListeners.put(username, lst);
+ }
+ userListeners.get(username).add(listener);
+ List<LogEvent> lastEvents = logDispatcherThread.getLastEvents(username,
+ numberOfPreviousEvents);
+ for (LogEvent evt : lastEvents)
+ dispatchEvent(listener, evt);
+ }
+
+ public synchronized void registerForAll(ArgeoLogListener listener,
+ Integer numberOfPreviousEvents, boolean everything) {
+ if (everything)
+ everythingListeners.add(listener);
+ else
+ allUsersListeners.add(listener);
+ List<LogEvent> lastEvents = logDispatcherThread.getLastEvents(null,
+ numberOfPreviousEvents);
+ for (LogEvent evt : lastEvents)
+ if (everything || evt.getUsername() != null)
+ dispatchEvent(listener, evt);
+ }
+
+ public synchronized void unregister(ArgeoLogListener listener) {
+ String username = SecurityUtils.getCurrentThreadUsername();
+ if (!userListeners.containsKey(username))
+ throw new ArgeoException("No user listeners " + listener
+ + " registered for user " + username);
+ if (!userListeners.get(username).contains(listener))
+ throw new ArgeoException("No user listeners " + listener
+ + " registered for user " + username);
+ userListeners.get(username).remove(listener);
+ if (userListeners.get(username).isEmpty())
+ userListeners.remove(username);
+
+ }
+
+ public synchronized void unregisterForAll(ArgeoLogListener listener) {
+ everythingListeners.remove(listener);
+ allUsersListeners.remove(listener);
+ }
+
+ /** For development purpose, since using regular logging is not easy here */
+ static void stdOut(Object obj) {
+ System.out.println(obj);
+ }
+
+ // public void setPattern(String pattern) {
+ // this.pattern = pattern;
+ // }
+
+ public void setDisabled(Boolean disabled) {
+ this.disabled = disabled;
+ }
+
+ public void setLevel(String level) {
+ this.level = level;
+ }
+
+ public void setConfiguration(Properties configuration) {
+ this.configuration = configuration;
+ }
+
+ public void updateConfiguration(Properties configuration) {
+ setConfiguration(configuration);
+ reloadConfiguration();
+ }
+
+ public Properties getConfiguration() {
+ return configuration;
+ }
+
+ /** Reloads configuration (if the configuration {@link Properties} is set) */
+ protected void reloadConfiguration() {
+ if (configuration != null) {
+ LogManager.resetConfiguration();
+ PropertyConfigurator.configure(configuration);
+ }
+ }
+
+ protected synchronized void processLoggingEvent(LogEvent event) {
+ if (disabled)
+ return;
+
+ if (dispatching.get())
+ return;
+
+ if (level != null && !level.trim().equals("")) {
+ if (log4jLevel == null || !log4jLevel.toString().equals(level))
+ try {
+ log4jLevel = Level.toLevel(level);
+ } catch (Exception e) {
+ System.err
+ .println("Log4j level could not be set for level '"
+ + level + "', resetting it to null.");
+ e.printStackTrace();
+ level = null;
+ }
+
+ if (log4jLevel != null
+ && !event.getLoggingEvent().getLevel()
+ .isGreaterOrEqual(log4jLevel)) {
+ return;
+ }
+ }
+
+ try {
+ // admin listeners
+ Iterator<ArgeoLogListener> everythingIt = everythingListeners
+ .iterator();
+ while (everythingIt.hasNext())
+ dispatchEvent(everythingIt.next(), event);
+
+ if (event.getUsername() != null) {
+ Iterator<ArgeoLogListener> allUsersIt = allUsersListeners
+ .iterator();
+ while (allUsersIt.hasNext())
+ dispatchEvent(allUsersIt.next(), event);
+
+ if (userListeners.containsKey(event.getUsername())) {
+ Iterator<ArgeoLogListener> userIt = userListeners.get(
+ event.getUsername()).iterator();
+ while (userIt.hasNext())
+ dispatchEvent(userIt.next(), event);
+ }
+ }
+ } catch (Exception e) {
+ stdOut("Cannot process logging event");
+ e.printStackTrace();
+ }
+ }
+
+ protected void dispatchEvent(ArgeoLogListener logListener, LogEvent evt) {
+ LoggingEvent event = evt.getLoggingEvent();
+ logListener.appendLog(evt.getUsername(), event.getTimeStamp(), event
+ .getLevel().toString(), event.getLoggerName(), event
+ .getThreadName(), event.getMessage(), event
+ .getThrowableStrRep());
+ }
+
+ private class AppenderImpl extends AppenderSkeleton {
+ public boolean requiresLayout() {
+ return false;
+ }
+
+ public void close() {
+ }
+
+ @Override
+ protected void append(LoggingEvent event) {
+ if (events != null) {
+ try {
+ String username = SecurityUtils.getCurrentThreadUsername();
+ events.put(new LogEvent(username, event));
+ } catch (InterruptedException e) {
+ // silent
+ }
+ }
+ }
+
+ }
+
+ private class LogDispatcherThread extends Thread {
+ /** encapsulated in order to simplify concurrency management */
+ private LinkedList<LogEvent> lastEvents = new LinkedList<LogEvent>();
+
+ public LogDispatcherThread() {
+ super("Argeo Logging Dispatcher Thread");
+ }
+
+ public void run() {
+ while (events != null) {
+ try {
+ LogEvent loggingEvent = events.take();
+ processLoggingEvent(loggingEvent);
+ addLastEvent(loggingEvent);
+ } catch (InterruptedException e) {
+ if (events == null)
+ return;
+ }
+ }
+ }
+
+ protected synchronized void addLastEvent(LogEvent loggingEvent) {
+ if (lastEvents.size() >= maxLastEventsCount)
+ lastEvents.poll();
+ lastEvents.add(loggingEvent);
+ }
+
+ public synchronized List<LogEvent> getLastEvents(String username,
+ Integer maxCount) {
+ LinkedList<LogEvent> evts = new LinkedList<LogEvent>();
+ ListIterator<LogEvent> it = lastEvents.listIterator(lastEvents
+ .size());
+ int count = 0;
+ while (it.hasPrevious() && (count < maxCount)) {
+ LogEvent evt = it.previous();
+ if (username == null || username.equals(evt.getUsername())) {
+ evts.push(evt);
+ count++;
+ }
+ }
+ return evts;
+ }
+ }
+
+ private class LogEvent {
+ private final String username;
+ private final LoggingEvent loggingEvent;
+
+ public LogEvent(String username, LoggingEvent loggingEvent) {
+ super();
+ this.username = username;
+ this.loggingEvent = loggingEvent;
+ }
+
+ @Override
+ public int hashCode() {
+ return loggingEvent.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return loggingEvent.equals(obj);
+ }
+
+ @Override
+ public String toString() {
+ return username + "@ " + loggingEvent.toString();
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public LoggingEvent getLoggingEvent() {
+ return loggingEvent;
+ }
+
+ }
+}
+++ /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.security;
-
-import org.apache.commons.codec.DecoderException;
-import org.apache.commons.codec.binary.Base64;
-import org.apache.commons.codec.binary.Hex;
-import org.springframework.security.providers.ldap.authenticator.LdapShaPasswordEncoder;
-
-public class PasswordSandbox {
- public static void main(String[] args) {
- try {
- // Tested password
- String pwdPlain = "demo";
-
- // Check Java generated values
- LdapShaPasswordEncoder lspe = new LdapShaPasswordEncoder();
- String pwdLdapShaBase64 = lspe.encodePassword(pwdPlain, null);
- System.out.println("pwdLdapShaBase64:\t\t" + pwdLdapShaBase64);
-
- String pwdShaBase64 = pwdLdapShaBase64.substring("{SHA}".length());
- System.out.println("pwdShaBase64:\t\t\t" + pwdShaBase64);
-
- byte[] pwdShaArray = Base64.decodeBase64(pwdShaBase64.getBytes());
- String pwdShaHex = new String(Hex.encodeHex(pwdShaArray));
- System.out.println("pwdShaHex:\t\t\t" + pwdShaHex);
-
- // Check that we can use JavaScript generated values in Hex
- String jsShaHex = "89e495e7941cf9e40e6980d14a16bf023ccd4c91";
- System.out.println("jsShaHex:\t\t\t" + pwdShaHex);
- System.out.println("pwdShaHex==jsShaHex:\t\t"
- + (pwdShaHex.equals(jsShaHex)));
-
- byte[] jsShaArray = Hex.decodeHex(jsShaHex.toCharArray());
- String jsShaBase64 = new String(Base64.encodeBase64(jsShaArray));
- System.out.println("jsShaBase64:\t\t\t" + jsShaBase64);
- System.out.println("pwdShaBase64==jsShaBase64:\t"
- + (pwdShaBase64.equals(jsShaBase64)));
- } catch (DecoderException e) {
- e.printStackTrace();
- }
-
- }
-
-}
\ 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.security.crypto;
-
-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.StreamUtils;
-import org.argeo.security.crypto.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
-log4j.rootLogger=WARN, console
-
-## Levels
-log4j.logger.org.argeo=DEBUG
-
-log4j.logger.org.hibernate=WARN
-
-log4j.logger.org.springframework=WARN
-#log4j.logger.org.springframework.web=DEBUG
-#log4j.logger.org.springframework.jms=WARN
-#log4j.logger.org.springframework.security=WARN
-
-log4j.logger.org.apache.activemq=WARN
-log4j.logger.org.apache.activemq.transport=WARN
-log4j.logger.org.apache.activemq.ActiveMQMessageConsumer=INFO
-log4j.logger.org.apache.activemq.ActiveMQMessageProducer=INFO
-
-log4j.logger.org.apache.catalina=INFO
-log4j.logger.org.apache.coyote=INFO
-log4j.logger.org.apache.tomcat=INFO
-
-## Appenders
-# console is set to be a ConsoleAppender.
-log4j.appender.console=org.apache.log4j.ConsoleAppender
-
-# console uses PatternLayout.
-log4j.appender.console.layout=org.apache.log4j.PatternLayout
-log4j.appender.console.layout.ConversionPattern= %-5p %d{ISO8601} %m - %c%n
+++ /dev/null
-{"roles":["ROLE_ADMIN","ROLE_USER"],"userNatures":[{"description":"Superuser","email":"admin@localhost","firstName":"Gandalf","lastName":"User","type":"org.argeo.security.nature.SimpleUserNature"},{"mobile":null,"telephoneNumber":null,"type":"org.argeo.security.nature.CoworkerNature"}],"username":"gandalf2","enabled":true,"password":"{SHA}ieSV55Qc+eQOaYDRSha/AjzNTJE=","authorities":[{"authority":"ROLE_ADMIN"},{"authority":"ROLE_USER"}],"accountNonExpired":true,"accountNonLocked":true,"credentialsNonExpired":true}
\ No newline at end of file