Jackrabbit security improved
authorMathieu Baudier <mbaudier@argeo.org>
Wed, 16 Mar 2011 15:21:11 +0000 (15:21 +0000)
committerMathieu Baudier <mbaudier@argeo.org>
Wed, 16 Mar 2011 15:21:11 +0000 (15:21 +0000)
Remote logging on a DAVEX server
(not everything working)

git-svn-id: https://svn.argeo.org/commons/trunk@4296 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc

35 files changed:
security/modules/org.argeo.security.services/META-INF/MANIFEST.MF
security/modules/org.argeo.security.services/META-INF/spring/osgi.xml
security/modules/org.argeo.security.services/META-INF/spring/services.xml
security/plugins/org.argeo.security.equinox/pom.xml
security/plugins/org.argeo.security.equinox/src/main/java/org/argeo/security/equinox/SpringLoginModule.java
security/plugins/org.argeo.security.ui.application/org.argeo.security.ui.application.product
security/plugins/org.argeo.security.ui.application/src/main/java/org/argeo/security/ui/application/AbstractSecureApplication.java
security/plugins/org.argeo.security.ui/src/main/java/org/argeo/security/ui/dialogs/DefaultLoginDialog.java
security/runtime/org.argeo.security.core/pom.xml
security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/SiteAuthenticationToken.java [new file with mode: 0644]
security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/ArgeoAuthenticationManager.java [new file with mode: 0644]
security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/jcr/JcrAuthenticationProvider.java [new file with mode: 0644]
security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/jcr/JcrAuthenticationToken.java [new file with mode: 0644]
security/runtime/org.argeo.security.jackrabbit/src/main/java/org/argeo/security/jackrabbit/ArgeoAccessManager.java [new file with mode: 0644]
security/runtime/org.argeo.security.jackrabbit/src/main/java/org/argeo/security/jackrabbit/ArgeoLoginModule.java [new file with mode: 0644]
security/runtime/org.argeo.security.jackrabbit/src/main/java/org/argeo/security/jackrabbit/ArgeoSecurityManager.java [new file with mode: 0644]
security/runtime/org.argeo.security.jackrabbit/src/main/java/org/argeo/security/jackrabbit/GrantedAuthorityPrincipal.java [new file with mode: 0644]
security/runtime/org.argeo.security.jackrabbit/src/main/java/org/argeo/security/jackrabbit/providers/JackrabbitAuthenticationProvider.java [new file with mode: 0644]
security/runtime/org.argeo.security.jackrabbit/src/main/java/org/argeo/security/jackrabbit/spring/GrantedAuthorityPrincipal.java [deleted file]
security/runtime/org.argeo.security.jackrabbit/src/main/java/org/argeo/security/jackrabbit/spring/SpringLoginModule.java [deleted file]
server/modules/org.argeo.jackrabbit.webapp/META-INF/MANIFEST.MF
server/modules/org.argeo.jackrabbit.webapp/WEB-INF/applicationContext.xml
server/modules/org.argeo.jackrabbit.webapp/WEB-INF/osgi.xml
server/modules/org.argeo.jackrabbit.webapp/WEB-INF/security-filters.xml [new file with mode: 0644]
server/modules/org.argeo.jackrabbit.webapp/WEB-INF/security.xml
server/modules/org.argeo.node.repo.jackrabbit/META-INF/MANIFEST.MF
server/modules/org.argeo.node.repo.jackrabbit/META-INF/spring/noderepo-osgi.xml
server/modules/org.argeo.node.repo.jackrabbit/META-INF/spring/noderepo.xml
server/modules/org.argeo.node.repo.jackrabbit/repository-h2.xml
server/modules/org.argeo.node.repo.jackrabbit/repository-postgresql.xml
server/modules/org.argeo.server.ads.server/META-INF/spring/server.xml
server/plugins/org.argeo.jcr.ui.explorer/org.argeo.jcr.ui.explorer.product
server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/JackrabbitRepositoryFactory.java
server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/SimpleSessionProvider.java
server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/DefaultRepositoryFactory.java [new file with mode: 0644]

index 3d22df281a9d82c96a7fe7c6884d209a78f8406b..8658c2bdca61457bfca44f463d947235e2652e9f 100644 (file)
@@ -6,6 +6,7 @@ Import-Package: org.argeo.security,
  org.springframework.security;specification-version="2.0.4.A",
  org.springframework.security.adapters;specification-version="2.0.6.RELEASE",
  org.springframework.security.providers;specification-version="2.0.6.RELEASE",
+ org.springframework.security.providers.anonymous;specification-version="2.0.6.RELEASE",
  org.springframework.security.providers.encoding;specification-version="2.0.6.RELEASE",
  org.springframework.security.providers.rememberme;specification-version="2.0.6.RELEASE"
 Bundle-Name: Security Services
index 62872b1c0ac2335d679e3bf23ffc5eccf879840a..92b4129fd8ba6f8800c94b19ce3fd369791feed6 100644 (file)
 \r
        <reference id="securityDao" interface="org.argeo.security.ArgeoSecurityDao" />\r
 \r
-       <reference id="authenticationProvider"\r
-               interface="org.springframework.security.providers.AuthenticationProvider" />\r
+       <!-- <reference id="authenticationProvider" -->\r
+       <!-- interface="org.springframework.security.providers.AuthenticationProvider" \r
+               /> -->\r
+       <list id="authenticationProviders"\r
+               interface="org.springframework.security.providers.AuthenticationProvider"\r
+               cardinality="0..N">\r
+               <listener ref="authenticationManager" bind-method="register"\r
+                       unbind-method="unregister" />\r
+       </list>\r
 \r
        <!-- SERVICES -->\r
        <service ref="securityService" interface="org.argeo.security.ArgeoSecurityService" />\r
index bb79de26555d897065b83007998ea4afc2a8938e..c602a6bc53f53dd7d96bb02a74a83f815ea72aca 100644 (file)
                <property name="systemAuthenticationKey" value="${argeo.security.systemKey}" />
        </bean>
 
-       <bean id="authenticationManager" class="org.springframework.security.providers.ProviderManager">
+       <bean id="authenticationManager" class="org.argeo.security.core.ArgeoAuthenticationManager">
                <property name="providers">
                        <list>
                                <bean class="org.springframework.security.adapters.AuthByAdapterProvider">
                                        <property name="key" value="${argeo.security.systemKey}" />
                                </bean>
                                <bean
-                                       class="org.springframework.security.providers.rememberme.RememberMeAuthenticationProvider">
+                                       class="org.springframework.security.providers.anonymous.AnonymousAuthenticationProvider">
                                        <property name="key" value="${argeo.security.systemKey}" />
                                </bean>
-                               <ref bean="authenticationProvider" />
                        </list>
                </property>
        </bean>
+
+
+       <!-- <bean id="rememberMeAuthenticationProvider" -->
+       <!-- class="org.springframework.security.providers.rememberme.RememberMeAuthenticationProvider"> -->
+       <!-- <property name="key" value="${argeo.security.systemKey}" /> -->
+       <!-- </bean> -->
+
 </beans>
\ No newline at end of file
index 944a6e0df42bb362fc4443ed145e26175a2ca7cb..9e0299f443d74f0b4fd9ab3e96a8ef69225e6159 100644 (file)
                        <artifactId>org.argeo.basic.nodeps</artifactId>
                        <version>0.2.3-SNAPSHOT</version>
                </dependency>
+               <dependency>
+                       <groupId>org.argeo.commons.security</groupId>
+                       <artifactId>org.argeo.security.core</artifactId>
+                       <version>0.2.3-SNAPSHOT</version>
+               </dependency>
 
                <!-- Spring -->
                <dependency>
index 2222faeccf35620734bfebf9d1a4cd6a15fcc020..c357a9ea7f1ae44e0e756bacfd2f15125486748e 100644 (file)
@@ -10,11 +10,11 @@ import javax.security.auth.callback.PasswordCallback;
 import javax.security.auth.callback.TextOutputCallback;
 import javax.security.auth.login.LoginException;
 
+import org.argeo.security.SiteAuthenticationToken;
 import org.springframework.security.Authentication;
 import org.springframework.security.AuthenticationManager;
 import org.springframework.security.BadCredentialsException;
 import org.springframework.security.context.SecurityContextHolder;
-import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
 import org.springframework.security.providers.jaas.SecurityContextLoginModule;
 
 /** Login module which caches one subject per thread. */
@@ -56,6 +56,7 @@ public class SpringLoginModule extends SecurityContextLoginModule {
                NameCallback nameCallback = new NameCallback("User");
                PasswordCallback passwordCallback = new PasswordCallback("Password",
                                false);
+               NameCallback urlCallback = new NameCallback("Site URL");
 
                if (callbackHandler == null) {
                        throw new LoginException("No call back handler available");
@@ -63,7 +64,7 @@ public class SpringLoginModule extends SecurityContextLoginModule {
                }
                try {
                        callbackHandler.handle(new Callback[] { label, nameCallback,
-                                       passwordCallback });
+                                       passwordCallback, urlCallback });
                } catch (Exception e) {
                        LoginException le = new LoginException("Callback handling failed");
                        le.initCause(e);
@@ -76,8 +77,15 @@ public class SpringLoginModule extends SecurityContextLoginModule {
                if (passwordCallback.getPassword() != null) {
                        password = String.valueOf(passwordCallback.getPassword());
                }
-               UsernamePasswordAuthenticationToken credentials = new UsernamePasswordAuthenticationToken(
-                               username, password);
+               String url = urlCallback.getName();
+               // TODO: set it via system properties
+               String workspace = null;
+
+               // UsernamePasswordAuthenticationToken credentials = new
+               // UsernamePasswordAuthenticationToken(
+               // username, password);
+               SiteAuthenticationToken credentials = new SiteAuthenticationToken(
+                               username, password, url, workspace);
 
                try {
                        Authentication authentication = authenticationManager
index c410c4ed52928185bdb40691ef034f28a191fd51..3fabf3a1908b9ab19b94ad098e31812b54a3dfc8 100644 (file)
    <plugins>
       <plugin id="com.ibm.icu"/>
       <plugin id="com.springsource.antlr"/>
+      <plugin id="com.springsource.com.sun.syndication"/>
       <plugin id="com.springsource.edu.emory.mathcs.backport"/>
+      <plugin id="com.springsource.edu.oswego.cs.dl.util.concurrent"/>
+      <plugin id="com.springsource.javax.mail"/>
       <plugin id="com.springsource.javax.servlet"/>
       <plugin id="com.springsource.javax.xml.stream"/>
       <plugin id="com.springsource.jdbm"/>
       <plugin id="com.springsource.org.aopalliance"/>
       <plugin id="com.springsource.org.apache.commons.codec"/>
       <plugin id="com.springsource.org.apache.commons.collections"/>
+      <plugin id="com.springsource.org.apache.commons.compress"/>
+      <plugin id="com.springsource.org.apache.commons.dbcp"/>
+      <plugin id="com.springsource.org.apache.commons.fileupload"/>
+      <plugin id="com.springsource.org.apache.commons.httpclient"/>
       <plugin id="com.springsource.org.apache.commons.io"/>
       <plugin id="com.springsource.org.apache.commons.lang"/>
       <plugin id="com.springsource.org.apache.commons.pool"/>
       <plugin id="com.springsource.org.apache.directory.shared.asn1"/>
       <plugin id="com.springsource.org.apache.directory.shared.ldap"/>
       <plugin id="com.springsource.org.apache.log4j"/>
+      <plugin id="com.springsource.org.apache.lucene"/>
       <plugin id="com.springsource.org.apache.mina"/>
       <plugin id="com.springsource.org.apache.ws.commons.schema"/>
+      <plugin id="com.springsource.org.apache.xalan"/>
+      <plugin id="com.springsource.org.apache.xerces" fragment="true"/>
+      <plugin id="com.springsource.org.apache.xml.resolver"/>
+      <plugin id="com.springsource.org.apache.xml.serializer"/>
+      <plugin id="com.springsource.org.apache.xmlbeans"/>
+      <plugin id="com.springsource.org.apache.xmlcommons"/>
       <plugin id="com.springsource.org.codehaus.jackson"/>
       <plugin id="com.springsource.org.codehaus.jackson.mapper"/>
+      <plugin id="com.springsource.org.cyberneko.html"/>
+      <plugin id="com.springsource.org.dom4j"/>
+      <plugin id="com.springsource.org.h2"/>
+      <plugin id="com.springsource.org.jdom"/>
+      <plugin id="com.springsource.org.objectweb.asm"/>
+      <plugin id="com.springsource.org.postgresql.jdbc3"/>
       <plugin id="com.springsource.slf4j.api"/>
       <plugin id="com.springsource.slf4j.log4j" fragment="true"/>
       <plugin id="com.springsource.slf4j.org.apache.commons.logging"/>
       <plugin id="org.argeo.basic.nodeps"/>
+      <plugin id="org.argeo.dep.osgi.boilerpipe"/>
+      <plugin id="org.argeo.dep.osgi.bouncycastle.jdk15"/>
       <plugin id="org.argeo.dep.osgi.directory.shared.asn.codec" fragment="true"/>
+      <plugin id="org.argeo.dep.osgi.drewnoakes.metadata_extractor"/>
+      <plugin id="org.argeo.dep.osgi.jackrabbit"/>
+      <plugin id="org.argeo.dep.osgi.jcr"/>
       <plugin id="org.argeo.dep.osgi.mina.filter.ssl" fragment="true"/>
+      <plugin id="org.argeo.dep.osgi.netcdf"/>
+      <plugin id="org.argeo.dep.osgi.pdfbox"/>
+      <plugin id="org.argeo.dep.osgi.poi"/>
       <plugin id="org.argeo.dep.osgi.springframework.ldap"/>
+      <plugin id="org.argeo.dep.osgi.tagsoup"/>
+      <plugin id="org.argeo.dep.osgi.tika"/>
       <plugin id="org.argeo.eclipse.ui"/>
       <plugin id="org.argeo.infra.core"/>
       <plugin id="org.argeo.infra.security.services" fragment="true"/>
+      <plugin id="org.argeo.node.repo.jackrabbit"/>
       <plugin id="org.argeo.security.core"/>
       <plugin id="org.argeo.security.equinox"/>
+      <plugin id="org.argeo.security.jackrabbit" fragment="true"/>
       <plugin id="org.argeo.security.ldap"/>
       <plugin id="org.argeo.security.manager.ldap"/>
       <plugin id="org.argeo.security.services"/>
       <plugin id="org.argeo.server.ads"/>
       <plugin id="org.argeo.server.ads.server"/>
       <plugin id="org.argeo.server.core"/>
+      <plugin id="org.argeo.server.ext.jackrabbit" fragment="true"/>
+      <plugin id="org.argeo.server.jackrabbit"/>
+      <plugin id="org.argeo.server.jcr"/>
+      <plugin id="org.argeo.server.jcr.mvc"/>
       <plugin id="org.argeo.server.json"/>
+      <plugin id="org.argeo.server.tika.jackrabbit" fragment="true"/>
+      <plugin id="org.argeo.slc.agent.ext.xalan" fragment="true"/>
       <plugin id="org.argeo.slc.demo.log4j" fragment="true"/>
+      <plugin id="org.argeo.slc.gis.ext.dbcp" fragment="true"/>
       <plugin id="org.eclipse.core.commands"/>
       <plugin id="org.eclipse.core.contenttype"/>
       <plugin id="org.eclipse.core.databinding"/>
       <plugin id="org.springframework.osgi.extender"/>
       <plugin id="org.springframework.osgi.io"/>
       <plugin id="org.springframework.oxm"/>
+      <plugin id="org.springframework.security.acls" fragment="true"/>
       <plugin id="org.springframework.security.core"/>
       <plugin id="org.springframework.transaction"/>
+      <plugin id="org.springframework.web"/>
       <plugin id="org.springframework.web.servlet"/>
       <plugin id="org.springframework.xml"/>
    </plugins>
 
    <configurations>
+      <plugin id="org.argeo.node.repo.jackrabbit" autoStart="true" startLevel="0" />
       <plugin id="org.argeo.security.manager.ldap" autoStart="true" startLevel="0" />
       <plugin id="org.argeo.security.services" autoStart="true" startLevel="0" />
       <plugin id="org.argeo.server.ads.server" autoStart="true" startLevel="0" />
index 9550660004fbb22a4c9376c3ca42ae3c4073195d..d866cb69ce77bcf18bb1de655444b6f765f03d22 100644 (file)
@@ -3,9 +3,11 @@ package org.argeo.security.ui.application;
 import java.security.PrivilegedAction;
 
 import javax.security.auth.Subject;
+import javax.security.auth.login.LoginException;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.argeo.eclipse.ui.dialogs.Error;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Status;
 import org.eclipse.equinox.app.IApplication;
@@ -17,8 +19,8 @@ import org.eclipse.ui.PlatformUI;
 import org.eclipse.ui.application.WorkbenchAdvisor;
 
 /**
- * Common base class for authenticated access to the Eclipse UI framework (RAP and
- * RCP)
+ * Common base class for authenticated access to the Eclipse UI framework (RAP
+ * and RCP)
  */
 public abstract class AbstractSecureApplication implements IApplication {
        private static final Log log = LogFactory
@@ -30,34 +32,42 @@ public abstract class AbstractSecureApplication implements IApplication {
 
                Integer returnCode = null;
                Display display = PlatformUI.createDisplay();
-
-               // Force login
-
                try {
-                       String username = null;
-                       Exception loginException = null;
                        Subject subject = null;
-                       try {
-                               SecureApplicationActivator.getLoginContext().login();
-                               subject = SecureApplicationActivator.getLoginContext()
-                                               .getSubject();
-
-                               // username = CurrentUser.getUsername();
-                       } catch (Exception e) {
-                               loginException = e;
-                               e.printStackTrace();
+                       Boolean retry = true;
+                       while (retry) {
+                               try {
+                                       SecureApplicationActivator.getLoginContext().login();
+                                       subject = SecureApplicationActivator.getLoginContext()
+                                                       .getSubject();
+                                       retry = false;
+                               } catch (LoginException e) {
+                                       Error.show("Cannot login", e);
+                                       retry = true;
+                               } catch (Exception e) {
+                                       Error.show("Unexpected exception while trying to login", e);
+                                       retry = false;
+                               }
                        }
+
                        if (subject == null) {
-                               IStatus status = new Status(IStatus.ERROR,
-                                               "org.argeo.security.application", "Login is mandatory",
-                                               loginException);
-                               ErrorDialog.openError(null, "Error", "Shutdown...", status);
-                               return status.getSeverity();
+                               // IStatus status = new Status(IStatus.ERROR,
+                               // "org.argeo.security.application", "Login is mandatory",
+                               // loginException);
+                               // ErrorDialog.openError(null, "Error", "Shutdown...", status);
+                               // return status.getSeverity();
+
+                               // TODO: log as anonymous
                        }
 
-                       returnCode = (Integer) Subject.doAs(subject, getRunAction(display));
-                       SecureApplicationActivator.getLoginContext().logout();
-                       return processReturnCode(returnCode);
+                       if (subject != null) {
+                               returnCode = (Integer) Subject.doAs(subject,
+                                               getRunAction(display));
+                               SecureApplicationActivator.getLoginContext().logout();
+                               return processReturnCode(returnCode);
+                       } else {
+                               return -1;
+                       }
                } catch (Exception e) {
                        // e.printStackTrace();
                        IStatus status = new Status(IStatus.ERROR,
index d00e961fb3acd4a221c3071e13f26cbd3ad40638..7a846f7b54564b66ecc9d4cd49a85a5fe81fc8d0 100644 (file)
@@ -30,7 +30,7 @@ public class DefaultLoginDialog extends AbstractLoginDialog {
        }
 
        protected Point getInitialSize() {
-               return new Point(300, 250);
+               return new Point(300, 350);
        }
 
        protected Control createDialogArea(Composite parent) {
index 5c9a1f9eb05c204891d5e4908e5e20b702782ba6..e9eca020c13a2b9b2554a876ebe5b8726a86ad80 100644 (file)
                        <artifactId>org.argeo.basic.nodeps</artifactId>
                        <version>0.2.3-SNAPSHOT</version>
                </dependency>
+               <dependency>
+                       <groupId>org.argeo.commons.server</groupId>
+                       <artifactId>org.argeo.server.jcr</artifactId>
+                       <version>0.2.3-SNAPSHOT</version>
+               </dependency>
 
                <!-- Spring -->
                <dependency>
diff --git a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/SiteAuthenticationToken.java b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/SiteAuthenticationToken.java
new file mode 100644 (file)
index 0000000..d836b6f
--- /dev/null
@@ -0,0 +1,34 @@
+package org.argeo.security;
+
+import org.springframework.security.GrantedAuthority;
+import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
+
+public class SiteAuthenticationToken extends
+               UsernamePasswordAuthenticationToken {
+       private static final long serialVersionUID = 1955222132884795213L;
+       private final String url;
+       private final String workspace;
+
+       public SiteAuthenticationToken(Object principal, Object credentials,
+                       String url, String workspace) {
+               super(principal, credentials);
+               this.url = url;
+               this.workspace = workspace;
+       }
+
+       public SiteAuthenticationToken(Object principal, Object credentials,
+                       GrantedAuthority[] authorities, String url, String workspace) {
+               super(principal, credentials, authorities);
+               this.url = url;
+               this.workspace = workspace;
+       }
+
+       public String getUrl() {
+               return url;
+       }
+
+       public String getWorkspace() {
+               return workspace;
+       }
+
+}
diff --git a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/ArgeoAuthenticationManager.java b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/ArgeoAuthenticationManager.java
new file mode 100644 (file)
index 0000000..de60bad
--- /dev/null
@@ -0,0 +1,28 @@
+package org.argeo.security.core;
+
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.security.providers.AuthenticationProvider;
+import org.springframework.security.providers.ProviderManager;
+
+public class ArgeoAuthenticationManager extends ProviderManager {
+       private Log log = LogFactory.getLog(ArgeoAuthenticationManager.class);
+
+       @SuppressWarnings("unchecked")
+       public void register(AuthenticationProvider authenticationProvider,
+                       Map<String, String> parameters) {
+               getProviders().add(authenticationProvider);
+               if (log.isDebugEnabled())
+                       log.debug("Registered authentication provider " + parameters);
+       }
+
+       public void unregister(AuthenticationProvider authenticationProvider,
+                       Map<String, String> parameters) {
+               getProviders().remove(authenticationProvider);
+               if (log.isDebugEnabled())
+                       log.debug("Unregistered authentication provider " + parameters);
+       }
+
+}
diff --git a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/jcr/JcrAuthenticationProvider.java b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/jcr/JcrAuthenticationProvider.java
new file mode 100644 (file)
index 0000000..844984a
--- /dev/null
@@ -0,0 +1,136 @@
+package org.argeo.security.jcr;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+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 org.argeo.ArgeoException;
+import org.argeo.jcr.ArgeoJcrConstants;
+import org.argeo.jcr.ArgeoNames;
+import org.argeo.jcr.ArgeoTypes;
+import org.argeo.security.SiteAuthenticationToken;
+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;
+
+/** Connects to a JCR repository and delegate authentication to it. */
+public class JcrAuthenticationProvider implements AuthenticationProvider {
+       private List<RepositoryFactory> repositoryFactories = new ArrayList<RepositoryFactory>();
+       private final String defaultHome;
+       private final String userRole;
+
+       public JcrAuthenticationProvider() {
+               this("ROLE_USER", "home");
+       }
+
+       public JcrAuthenticationProvider(String userRole) {
+               this(userRole, "home");
+       }
+
+       public JcrAuthenticationProvider(String defaultHome, String userRole) {
+               super();
+               this.defaultHome = defaultHome;
+               this.userRole = userRole;
+       }
+
+       public Authentication authenticate(Authentication authentication)
+                       throws AuthenticationException {
+               if (!(authentication instanceof SiteAuthenticationToken))
+                       return null;
+               SiteAuthenticationToken siteAuth = (SiteAuthenticationToken) authentication;
+               String url = siteAuth.getUrl();
+               if (url == null)
+                       return null;
+
+               try {
+                       Map<String, String> parameters = new HashMap<String, String>();
+                       parameters.put(ArgeoJcrConstants.JCR_REPOSITORY_URI, url);
+
+                       Repository repository = null;
+                       for (Iterator<RepositoryFactory> it = repositoryFactories
+                                       .iterator(); it.hasNext();) {
+                               repository = it.next().getRepository(parameters);
+                       }
+                       if (repository == null)
+                               return null;
+
+                       SimpleCredentials sp = new SimpleCredentials(siteAuth.getName(),
+                                       siteAuth.getCredentials().toString().toCharArray());
+                       String workspace = siteAuth.getWorkspace();
+                       Session session;
+                       if (workspace == null || workspace.trim().equals(""))
+                               session = repository.login(sp);
+                       else
+                               session = repository.login(sp, workspace);
+                       Node userHome = getUserHome(session);
+                       GrantedAuthority[] authorities = {};
+                       return new JcrAuthenticationToken(siteAuth.getPrincipal(),
+                                       siteAuth.getCredentials(), authorities, url, userHome);
+               } catch (RepositoryException e) {
+                       throw new ArgeoException(
+                                       "Unexpected exception when authenticating to " + url, e);
+               }
+       }
+
+       protected GrantedAuthority[] getGrantedAuthorities(Session session) {
+               return new GrantedAuthority[] { new GrantedAuthorityImpl(userRole) };
+       }
+
+       @SuppressWarnings("rawtypes")
+       public boolean supports(Class authentication) {
+               return SiteAuthenticationToken.class.isAssignableFrom(authentication);
+       }
+
+       protected Node getUserHome(Session session) {
+               String userID = "<not yet logged in>";
+               try {
+                       userID = session.getUserID();
+                       Node rootNode = session.getRootNode();
+                       Node homeNode;
+                       if (!rootNode.hasNode(defaultHome)) {
+                               homeNode = rootNode.addNode(defaultHome, ArgeoTypes.ARGEO_HOME);
+                       } else {
+                               homeNode = rootNode.getNode(defaultHome);
+                       }
+
+                       Node userHome;
+                       if (!homeNode.hasNode(userID)) {
+                               userHome = homeNode.addNode(userID);
+                               userHome.addMixin(ArgeoTypes.ARGEO_USER_HOME);
+                               userHome.setProperty(ArgeoNames.ARGEO_USER_ID, userID);
+                       } else {
+                               userHome = homeNode.getNode(userID);
+                       }
+                       session.save();
+                       return userHome;
+               } catch (Exception e) {
+                       throw new ArgeoException("Cannot initialize home for user '"
+                                       + userID + "'", e);
+               }
+       }
+
+       public void setRepositoryFactories(
+                       List<RepositoryFactory> repositoryFactories) {
+               this.repositoryFactories = repositoryFactories;
+       }
+
+       public String getDefaultHome() {
+               return defaultHome;
+       }
+
+       public String getUserRole() {
+               return userRole;
+       }
+
+}
diff --git a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/jcr/JcrAuthenticationToken.java b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/jcr/JcrAuthenticationToken.java
new file mode 100644 (file)
index 0000000..8655083
--- /dev/null
@@ -0,0 +1,34 @@
+package org.argeo.security.jcr;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.ArgeoException;
+import org.argeo.security.SiteAuthenticationToken;
+import org.springframework.security.GrantedAuthority;
+
+public class JcrAuthenticationToken extends SiteAuthenticationToken {
+       private static final long serialVersionUID = -2736830165315486169L;
+       private final transient Node userHome;
+
+       public JcrAuthenticationToken(Object principal, Object credentials,
+                       GrantedAuthority[] authorities, String url, Node userHome) {
+               super(principal, credentials, authorities, url,
+                               extractWorkspace(userHome));
+               this.userHome = userHome;
+       }
+
+       private static String extractWorkspace(Node userHome) {
+               try {
+                       return userHome.getSession().getWorkspace().getName();
+               } catch (RepositoryException e) {
+                       throw new ArgeoException("Cannot extract workspace of " + userHome,
+                                       e);
+               }
+       }
+
+       public Node getUserHome() {
+               return userHome;
+       }
+
+}
diff --git a/security/runtime/org.argeo.security.jackrabbit/src/main/java/org/argeo/security/jackrabbit/ArgeoAccessManager.java b/security/runtime/org.argeo.security.jackrabbit/src/main/java/org/argeo/security/jackrabbit/ArgeoAccessManager.java
new file mode 100644 (file)
index 0000000..4403def
--- /dev/null
@@ -0,0 +1,8 @@
+package org.argeo.security.jackrabbit;
+
+import org.apache.jackrabbit.core.security.DefaultAccessManager;
+
+/** Intermediary class in order to have a consistent naming in config files. */
+public class ArgeoAccessManager extends DefaultAccessManager {
+
+}
diff --git a/security/runtime/org.argeo.security.jackrabbit/src/main/java/org/argeo/security/jackrabbit/ArgeoLoginModule.java b/security/runtime/org.argeo.security.jackrabbit/src/main/java/org/argeo/security/jackrabbit/ArgeoLoginModule.java
new file mode 100644 (file)
index 0000000..d05cdf9
--- /dev/null
@@ -0,0 +1,94 @@
+package org.argeo.security.jackrabbit;
+
+import java.security.Principal;
+import java.security.acl.Group;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+
+import javax.jcr.Credentials;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.SimpleCredentials;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.login.LoginException;
+
+import org.apache.jackrabbit.core.security.AnonymousPrincipal;
+import org.apache.jackrabbit.core.security.authentication.AbstractLoginModule;
+import org.apache.jackrabbit.core.security.authentication.Authentication;
+import org.apache.jackrabbit.core.security.principal.AdminPrincipal;
+import org.argeo.security.SystemAuthentication;
+import org.springframework.security.GrantedAuthority;
+import org.springframework.security.context.SecurityContextHolder;
+import org.springframework.security.providers.anonymous.AnonymousAuthenticationToken;
+
+public class ArgeoLoginModule extends AbstractLoginModule {
+       private String adminRole = "ROLE_ADMIN";
+
+       /**
+        * Returns the Spring {@link org.springframework.security.Authentication}
+        * (which can be null)
+        */
+       @Override
+       protected Principal getPrincipal(Credentials credentials) {
+               return SecurityContextHolder.getContext().getAuthentication();
+       }
+
+       protected Set<Principal> getPrincipals() {
+               // use linked HashSet instead of HashSet in order to maintain the order
+               // of principals (as in the Subject).
+               Set<Principal> principals = new LinkedHashSet<Principal>();
+               principals.add(principal);
+
+               org.springframework.security.Authentication authen = (org.springframework.security.Authentication) principal;
+
+               if (authen instanceof SystemAuthentication)
+                       principals.add(new AdminPrincipal(authen.getName()));
+               else if (authen instanceof AnonymousAuthenticationToken)
+                       principals.add(new AnonymousPrincipal());
+               else
+                       for (GrantedAuthority ga : authen.getAuthorities()) {
+                               if (adminRole.equals(ga.getAuthority()))
+                                       principals.add(new AdminPrincipal(authen.getName()));
+                       }
+
+               // override credentials since we did not used the one passed to us
+               credentials = new SimpleCredentials(authen.getName(), authen
+                               .getCredentials().toString().toCharArray());
+
+               return principals;
+       }
+
+       @SuppressWarnings("rawtypes")
+       @Override
+       protected void doInit(CallbackHandler callbackHandler, Session session,
+                       Map options) throws LoginException {
+       }
+
+       @Override
+       protected boolean impersonate(Principal principal, Credentials credentials)
+                       throws RepositoryException, LoginException {
+               throw new UnsupportedOperationException(
+                               "Impersonation is not yet supported");
+       }
+
+       @Override
+       protected Authentication getAuthentication(final Principal principal,
+                       Credentials creds) throws RepositoryException {
+               if (principal instanceof Group) {
+                       return null;
+               }
+               return new Authentication() {
+                       public boolean canHandle(Credentials credentials) {
+                               return principal instanceof org.springframework.security.Authentication;
+                       }
+
+                       public boolean authenticate(Credentials credentials)
+                                       throws RepositoryException {
+                               return ((org.springframework.security.Authentication) principal)
+                                               .isAuthenticated();
+                       }
+               };
+       }
+
+}
diff --git a/security/runtime/org.argeo.security.jackrabbit/src/main/java/org/argeo/security/jackrabbit/ArgeoSecurityManager.java b/security/runtime/org.argeo.security.jackrabbit/src/main/java/org/argeo/security/jackrabbit/ArgeoSecurityManager.java
new file mode 100644 (file)
index 0000000..a3a6d42
--- /dev/null
@@ -0,0 +1,80 @@
+package org.argeo.security.jackrabbit;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import javax.jcr.RepositoryException;
+import javax.security.auth.Subject;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.jackrabbit.api.security.user.Group;
+import org.apache.jackrabbit.api.security.user.User;
+import org.apache.jackrabbit.api.security.user.UserManager;
+import org.apache.jackrabbit.core.DefaultSecurityManager;
+import org.apache.jackrabbit.core.security.SystemPrincipal;
+import org.argeo.ArgeoException;
+import org.springframework.security.Authentication;
+import org.springframework.security.GrantedAuthority;
+
+/** Intermediary class in order to have a consistent naming in config files. */
+public class ArgeoSecurityManager extends DefaultSecurityManager {
+       private Log log = LogFactory.getLog(ArgeoSecurityManager.class);
+
+       @Override
+       /** Since this is called once when the session is created, we take the opportunity to synchronize Spring and Jackrabbit users and groups.*/
+       public String getUserID(Subject subject, String workspaceName)
+                       throws RepositoryException {
+               long begin = System.currentTimeMillis();
+
+               if (!subject.getPrincipals(SystemPrincipal.class).isEmpty())
+                       return super.getUserID(subject, workspaceName);
+
+               Authentication authen;
+               Set<Authentication> authens = subject
+                               .getPrincipals(Authentication.class);
+               if (authens.size() == 0)
+                       throw new ArgeoException("No Spring authentication found in "
+                                       + subject);
+               else
+                       authen = authens.iterator().next();
+
+               UserManager systemUm = getSystemUserManager(workspaceName);
+
+               String userId = authen.getName();
+               User user = (User) systemUm.getAuthorizable(userId);
+               if (user == null) {
+                       user = systemUm.createUser(userId, authen.getCredentials()
+                                       .toString(), authen, null);
+                       log.info(userId + " added as " + user);
+               }
+
+               List<String> userGroupIds = new ArrayList<String>();
+               for (GrantedAuthority ga : authen.getAuthorities()) {
+                       Group group = (Group) systemUm.getAuthorizable(ga.getAuthority());
+                       if (group == null) {
+                               group = systemUm.createGroup(ga.getAuthority(),
+                                               new GrantedAuthorityPrincipal(ga), null);
+                               log.info(ga.getAuthority() + " added as " + group);
+                       }
+                       if (!group.isMember(user))
+                               group.addMember(user);
+                       userGroupIds.add(ga.getAuthority());
+               }
+
+               // check if user has not been removed from some groups
+               for (Iterator<Group> it = user.declaredMemberOf(); it.hasNext();) {
+                       Group group = it.next();
+                       if (!userGroupIds.contains(group.getID()))
+                               group.removeMember(user);
+               }
+
+               if (log.isDebugEnabled())
+                       log.debug("Spring and Jackrabbit Security synchronized for user "
+                                       + userId + " in " + (System.currentTimeMillis() - begin)
+                                       + " ms");
+               return userId;
+       }
+}
diff --git a/security/runtime/org.argeo.security.jackrabbit/src/main/java/org/argeo/security/jackrabbit/GrantedAuthorityPrincipal.java b/security/runtime/org.argeo.security.jackrabbit/src/main/java/org/argeo/security/jackrabbit/GrantedAuthorityPrincipal.java
new file mode 100644 (file)
index 0000000..ffd8d6f
--- /dev/null
@@ -0,0 +1,20 @@
+package org.argeo.security.jackrabbit;
+
+import java.security.Principal;
+
+import org.springframework.security.GrantedAuthority;
+
+/** Wraps a {@link GrantedAuthority} as a prin,cipal. */
+class GrantedAuthorityPrincipal implements Principal {
+       private final GrantedAuthority grantedAuthority;
+
+       public GrantedAuthorityPrincipal(GrantedAuthority grantedAuthority) {
+               super();
+               this.grantedAuthority = grantedAuthority;
+       }
+
+       public String getName() {
+               return grantedAuthority.getAuthority();
+       }
+
+}
diff --git a/security/runtime/org.argeo.security.jackrabbit/src/main/java/org/argeo/security/jackrabbit/providers/JackrabbitAuthenticationProvider.java b/security/runtime/org.argeo.security.jackrabbit/src/main/java/org/argeo/security/jackrabbit/providers/JackrabbitAuthenticationProvider.java
new file mode 100644 (file)
index 0000000..b7dedad
--- /dev/null
@@ -0,0 +1,38 @@
+package org.argeo.security.jackrabbit.providers;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.apache.jackrabbit.api.JackrabbitSession;
+import org.apache.jackrabbit.api.security.user.Group;
+import org.apache.jackrabbit.api.security.user.User;
+import org.apache.jackrabbit.api.security.user.UserManager;
+import org.argeo.ArgeoException;
+import org.argeo.security.jcr.JcrAuthenticationProvider;
+import org.springframework.security.GrantedAuthority;
+import org.springframework.security.GrantedAuthorityImpl;
+
+public class JackrabbitAuthenticationProvider extends JcrAuthenticationProvider {
+
+       @Override
+       protected GrantedAuthority[] getGrantedAuthorities(Session session) {
+               try {
+                       JackrabbitSession jackrabbitSession = (JackrabbitSession) session;
+                       UserManager userManager = jackrabbitSession.getUserManager();
+                       User user = (User) userManager.getAuthorizable(session.getUserID());
+                       List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
+                       for (Iterator<Group> it = user.memberOf(); it.hasNext();)
+                               authorities.add(new GrantedAuthorityImpl(it.next().getID()));
+                       return authorities
+                                       .toArray(new GrantedAuthority[authorities.size()]);
+               } catch (RepositoryException e) {
+                       throw new ArgeoException("Cannot retrieve authorities for "
+                                       + session.getUserID(), e);
+               }
+       }
+
+}
diff --git a/security/runtime/org.argeo.security.jackrabbit/src/main/java/org/argeo/security/jackrabbit/spring/GrantedAuthorityPrincipal.java b/security/runtime/org.argeo.security.jackrabbit/src/main/java/org/argeo/security/jackrabbit/spring/GrantedAuthorityPrincipal.java
deleted file mode 100644 (file)
index ec6152e..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-package org.argeo.security.jackrabbit.spring;
-
-import java.security.Principal;
-
-import org.springframework.security.GrantedAuthority;
-
-/** Wraps a {@link GrantedAuthority} as a prin,cipal. */
-public class GrantedAuthorityPrincipal implements Principal {
-       private final GrantedAuthority grantedAuthority;
-
-       public GrantedAuthorityPrincipal(GrantedAuthority grantedAuthority) {
-               super();
-               this.grantedAuthority = grantedAuthority;
-       }
-
-       public String getName() {
-               return grantedAuthority.getAuthority();
-       }
-
-}
diff --git a/security/runtime/org.argeo.security.jackrabbit/src/main/java/org/argeo/security/jackrabbit/spring/SpringLoginModule.java b/security/runtime/org.argeo.security.jackrabbit/src/main/java/org/argeo/security/jackrabbit/spring/SpringLoginModule.java
deleted file mode 100644 (file)
index c6b456d..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-package org.argeo.security.jackrabbit.spring;
-
-import java.security.Principal;
-import java.security.acl.Group;
-import java.util.LinkedHashSet;
-import java.util.Map;
-import java.util.Set;
-
-import javax.jcr.Credentials;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.login.LoginException;
-
-import org.apache.jackrabbit.core.security.AnonymousPrincipal;
-import org.apache.jackrabbit.core.security.authentication.AbstractLoginModule;
-import org.apache.jackrabbit.core.security.authentication.Authentication;
-import org.apache.jackrabbit.core.security.principal.AdminPrincipal;
-import org.argeo.security.SystemAuthentication;
-import org.springframework.security.GrantedAuthority;
-import org.springframework.security.context.SecurityContextHolder;
-import org.springframework.security.providers.anonymous.AnonymousAuthenticationToken;
-
-public class SpringLoginModule extends AbstractLoginModule {
-
-       /**
-        * Returns the Spring {@link org.springframework.security.Authentication}
-        * (which can be null)
-        */
-       @Override
-       protected Principal getPrincipal(Credentials credentials) {
-               return SecurityContextHolder.getContext().getAuthentication();
-       }
-
-       protected Set<Principal> getPrincipals() {
-               // use linked HashSet instead of HashSet in order to maintain the order
-               // of principals (as in the Subject).
-               Set<Principal> principals = new LinkedHashSet<Principal>();
-               principals.add(principal);
-
-               org.springframework.security.Authentication authen = (org.springframework.security.Authentication) principal;
-
-               if (authen instanceof AnonymousAuthenticationToken)
-                       principals.add(new AnonymousPrincipal());
-               if (authen instanceof SystemAuthentication)
-                       principals.add(new AdminPrincipal(authen.getName()));
-
-               for (GrantedAuthority authority : authen.getAuthorities())
-                       principals.add(new GrantedAuthorityPrincipal(authority));
-
-               return principals;
-       }
-
-       @SuppressWarnings("rawtypes")
-       @Override
-       protected void doInit(CallbackHandler callbackHandler, Session session,
-                       Map options) throws LoginException {
-       }
-
-       @Override
-       protected boolean impersonate(Principal principal, Credentials credentials)
-                       throws RepositoryException, LoginException {
-               throw new UnsupportedOperationException(
-                               "Impersonation is not yet supported");
-       }
-
-       @Override
-       protected Authentication getAuthentication(Principal principal,
-                       Credentials creds) throws RepositoryException {
-               if (principal instanceof Group) {
-                       return null;
-               }
-               return new Authentication() {
-                       public boolean canHandle(Credentials credentials) {
-                               return true;
-                       }
-
-                       public boolean authenticate(Credentials credentials)
-                                       throws RepositoryException {
-                               return true;
-                       }
-               };
-       }
-
-}
index 0e6854f7994a3609ac821bbf793892548e2328b4..17709f27a08de4d8df322706e5abdc59c6d28a38 100644 (file)
@@ -21,6 +21,7 @@ Import-Package: javax.jcr,
  org.springframework.aop.scope;version="2.5.6.SEC01",
  org.springframework.osgi.web.context.support;version="1.2.1",
  org.springframework.security;version="2.0.6.RELEASE",
+ org.springframework.security.providers.anonymous;version="2.0.6.RELEASE",
  org.springframework.security.ui.webapp;version="2.0.6.RELEASE",
  org.springframework.web.context;version="2.5.6.SEC01",
  org.springframework.web.filter;version="2.5.6.SEC01",
index 5898b1952fa5816c1b56a22cf36f917acfce4c5d..42db5686a5808d4693f55c80a271fa32c6e8831c 100644 (file)
@@ -10,8 +10,8 @@
 
        <bean id="repositoryRegister" class="org.argeo.jcr.DefaultRepositoryRegister" />
 
-       <bean id="sessionProvider" scope="session" destroy-method="dispose"
-               class="org.argeo.jackrabbit.remote.SimpleSessionProvider">
+       <bean id="sessionProvider" scope="session" init-method="init"
+               destroy-method="dispose" class="org.argeo.jackrabbit.remote.SimpleSessionProvider">
                <aop:scoped-proxy proxy-target-class="false" />
        </bean>
 
index 80b804ef6cbdb92017d4f7ea517a7669ec4fc4cd..34fe6ad8124244fa189dd0ca9a4eb9f343a21d07 100644 (file)
@@ -13,6 +13,6 @@
                        unbind-method="unregister" />\r
        </set>\r
 \r
-       <reference id="_authenticationManager"\r
-               interface="org.springframework.security.AuthenticationManager" />\r
+<!--   <reference id="authenticationManager"-->\r
+<!--           interface="org.springframework.security.AuthenticationManager" />-->\r
 </beans:beans>
\ No newline at end of file
diff --git a/server/modules/org.argeo.jackrabbit.webapp/WEB-INF/security-filters.xml b/server/modules/org.argeo.jackrabbit.webapp/WEB-INF/security-filters.xml
new file mode 100644 (file)
index 0000000..c969b4d
--- /dev/null
@@ -0,0 +1,114 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:sec="http://www.springframework.org/schema/security" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:aop="http://www.springframework.org/schema/aop"
+       xsi:schemaLocation="
+       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
+       http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.4.xsd">
+
+
+       <!-- Filter chain -->
+       <alias name="filterChainProxy" alias="springSecurityFilterChain" />
+
+       <bean id="filterChainProxy" class="org.springframework.security.util.FilterChainProxy">
+               <sec:filter-chain-map path-type="ant">
+                       <sec:filter-chain pattern="/images/*" filters="none" />
+                       <sec:filter-chain pattern="/**"
+                               filters="securityContextFilter, logoutFilter, requestCacheFilter,
+                 servletApiFilter, anonFilter, sessionMgmtFilter, exceptionTranslator, filterSecurityInterceptor" />
+               </sec:filter-chain-map>
+       </bean>
+
+       <!-- Filters -->
+       <bean id="securityContextFilter"
+               class="org.springframework.security.web.context.SecurityContextPersistenceFilter">
+               <property name="securityContextRepository" ref="securityContextRepository" />
+       </bean>
+
+       <bean id="securityContextRepository"
+               class="org.springframework.security.web.context.HttpSessionSecurityContextRepository" />
+
+       <bean id="logoutFilter"
+               class="org.springframework.security.web.authentication.logout.LogoutFilter">
+               <constructor-arg value="/logged_out.htm" />
+               <constructor-arg>
+                       <list>
+                               <bean
+                                       class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler" />
+                       </list>
+               </constructor-arg>
+       </bean>
+
+       <!-- <bean id="formLoginFilter" -->
+       <!-- class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter"> -->
+       <!-- <property name="authenticationManager" ref="authenticationManager" 
+               /> -->
+       <!-- <property name="authenticationSuccessHandler"> -->
+       <!-- <bean -->
+       <!-- class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler"> -->
+       <!-- <property name="defaultTargetUrl" value="/index.jsp" /> -->
+       <!-- </bean> -->
+       <!-- </property> -->
+       <!-- <property name="sessionAuthenticationStrategy"> -->
+       <!-- <bean -->
+       <!-- class="org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy" 
+               /> -->
+       <!-- </property> -->
+       <!-- </bean> -->
+
+       <bean id="requestCacheFilter"
+               class="org.springframework.security.web.savedrequest.RequestCacheAwareFilter" />
+
+       <bean id="servletApiFilter"
+               class="org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter" />
+
+       <bean id="anonFilter"
+               class="org.springframework.security.web.authentication.AnonymousAuthenticationFilter">
+               <property name="key" value="SomeUniqueKeyForThisApplication" />
+               <property name="userAttribute" value="anonymousUser,ROLE_ANONYMOUS" />
+       </bean>
+
+       <bean id="sessionMgmtFilter"
+               class="org.springframework.security.web.session.SessionManagementFilter">
+               <constructor-arg ref="securityContextRepository" />
+       </bean>
+
+       <bean id="exceptionTranslator"
+               class="org.springframework.security.web.access.ExceptionTranslationFilter">
+               <property name="authenticationEntryPoint">
+                       <bean
+                               class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
+                               <property name="loginFormUrl" value="/login.htm" />
+                       </bean>
+               </property>
+       </bean>
+
+       <bean id="filterSecurityInterceptor"
+               class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
+               <!-- <property name="securityMetadataSource"> -->
+               <!-- <sec:filter-security-metadata-source> -->
+               <!-- <sec:intercept-url pattern="/secure/extreme/*" -->
+               <!-- access="ROLE_SUPERVISOR" /> -->
+               <!-- <sec:intercept-url pattern="/secure/**" -->
+               <!-- access="IS_AUTHENTICATED_FULLY" /> -->
+               <!-- <sec:intercept-url pattern="/login.htm" -->
+               <!-- access="IS_AUTHENTICATED_ANONYMOUSLY" /> -->
+               <!-- <sec:intercept-url pattern="/**" access="ROLE_USER" /> -->
+               <!-- </sec:filter-security-metadata-source> -->
+               <!-- </property> -->
+               <property name="authenticationManager" ref="authenticationManager" />
+               <property name="accessDecisionManager" ref="accessDecisionManager" />
+       </bean>
+
+       <!-- Access decision manager -->
+       <bean id="accessDecisionManager"
+               class="org.springframework.security.access.vote.AffirmativeBased">
+               <property name="decisionVoters">
+                       <list>
+                               <bean class="org.springframework.security.access.vote.RoleVoter" />
+                               <bean class="org.springframework.security.access.vote.AuthenticatedVoter" />
+                       </list>
+               </property>
+       </bean>
+
+</beans>
\ No newline at end of file
index 2e08bfdb067368e932dbedef1ae21d8b79c9fa67..caba1aa9f72a61392c3f11f4a05f642f05bb4ace 100644 (file)
@@ -7,8 +7,26 @@
        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.4.xsd">
 
        <security:http>
-               <security:http-basic />
+               <security:intercept-url pattern="/remoting/*"
+                       access="ROLE_USER,ROLE_ADMIN,ROLE_ANONYMOUS" />
+               <security:intercept-url pattern="/*/node/*/**"
+                       access="ROLE_USER,ROLE_ADMIN" />
                <security:intercept-url pattern="/**"
                        access="ROLE_USER,ROLE_ADMIN,ROLE_ANONYMOUS" />
+               <security:http-basic />
+               <security:anonymous />
        </security:http>
+
+       <!-- LDAP -->
+       <security:ldap-authentication-provider
+               user-dn-pattern="uid={0},ou=People" group-search-base="ou=Roles"
+               group-search-filter="(member={0})" user-details-class="inetOrgPerson" />
+       <!-- <security:password-compare> -->
+       <!-- <security:password-encoder hash="{ssha}" > -->
+       <!-- <security:salt-source system-wide="test"/> -->
+       <!-- </security:password-encoder> -->
+       <!-- </security:password-compare> -->
+       <!-- </security:ldap-authentication-provider> -->
+       <security:ldap-server url="ldap://localhost:10389/dc=demo,dc=argeo,dc=org" />
+
 </beans>
\ No newline at end of file
index fbabbb2a207bd78ae88f60b43221b6405599d08f..1131a38612e2a3424ad93e53f40067d6051ca063 100644 (file)
@@ -10,6 +10,9 @@ Import-Package: com.mysql.jdbc;version="[5.0.0,6.0.0)";resolution:=optional,
  org.apache.xalan.processor,
  org.argeo.jackrabbit,
  org.argeo.jcr,
+ org.argeo.security.jackrabbit.providers,
+ org.argeo.security.jcr,
  org.h2;version="[1.0.0,2.0.0)";resolution:=optional,
  org.postgresql;version="[8.0.0,9.0.0)";resolution:=optional,
- org.springframework.beans.factory.config
+ org.springframework.beans.factory.config,
+ org.springframework.security.providers;version="2.0.6.RELEASE"
index 222f302908c93daefe8bb68e14b46740b04c5b05..9721feebbddd113526dc8c2356675824244f1b69 100644 (file)
@@ -9,6 +9,18 @@
        http://www.springframework.org/schema/util\r
        http://www.springframework.org/schema/util/spring-util-2.5.xsd">\r
 \r
+       <!-- REFERENCE -->\r
+       <list id="repositoryFactories" interface="javax.jcr.RepositoryFactory"\r
+               cardinality="0..N" />\r
+       <list id="repositories" interface="javax.jcr.Repository"\r
+               cardinality="0..N">\r
+               <listener ref="repositoryFactory" bind-method="register"\r
+                       unbind-method="unregister" />\r
+       </list>\r
+\r
+       <!-- SERVICES -->\r
+       <service ref="repositoryFactory" interface="javax.jcr.RepositoryFactory" />\r
+\r
        <service ref="nodeJcrRepository" interface="javax.jcr.Repository">\r
                <service-properties>\r
                        <beans:entry value="node">\r
@@ -31,5 +43,7 @@
                </service-properties>\r
        </service>\r
 \r
+       <service ref="jcrAuthenticationProvider"\r
+               interface="org.springframework.security.providers.AuthenticationProvider" />\r
 \r
 </beans:beans>
\ No newline at end of file
index ccb517d4f2bee602de9b7f89846fceecb8cd119b..a03a421b48014bac36b192524de45804a6e04fc5 100644 (file)
                <property name="workspace" value="${argeo.node.repo.workspace}" />
        </bean>
 
+       <bean id="jcrAuthenticationProvider" class="org.argeo.security.jackrabbit.providers.JackrabbitAuthenticationProvider">
+               <property name="repositoryFactories" ref="repositoryFactories" />
+       </bean>
+
+       <bean id="repositoryFactory" class="org.argeo.jackrabbit.JackrabbitRepositoryFactory">
+       </bean>
+
 </beans>
\ No newline at end of file
index 3040ad1769e2d4aa751205543ac413e36da3127f..5e63e5de82ded50b0a1244e017c1ff63c3092dec 100644 (file)
 
        <!-- Security -->
        <Security appName="Jackrabbit">
-               <SecurityManager
-                       class="org.apache.jackrabbit.core.security.simple.SimpleSecurityManager"
+               <SecurityManager class="org.argeo.security.jackrabbit.ArgeoSecurityManager"
                        workspaceName="security">
                </SecurityManager>
-               <AccessManager
-                       class="org.apache.jackrabbit.core.security.simple.SimpleAccessManager">
+               <AccessManager class="org.argeo.security.jackrabbit.ArgeoAccessManager">
                </AccessManager>
-               <LoginModule
-                       class="org.springframework.security.providers.jaas.SecurityContextLoginModule">
+               <LoginModule class="org.argeo.security.jackrabbit.ArgeoLoginModule">
                </LoginModule>
        </Security>
 </Repository>
\ No newline at end of file
index 0bfdef42b40f6d2359b688208a732e930a6c0892..4c4f4fb41a22a00bd3019c23c5c5a97841c4dead 100644 (file)
 
        <!-- Security -->
        <Security appName="Jackrabbit">
-               <SecurityManager
-                       class="org.apache.jackrabbit.core.security.simple.SimpleSecurityManager"
+               <SecurityManager class="org.argeo.security.jackrabbit.ArgeoSecurityManager"
                        workspaceName="security">
                </SecurityManager>
-               <AccessManager
-                       class="org.apache.jackrabbit.core.security.simple.SimpleAccessManager">
+               <AccessManager class="org.argeo.security.jackrabbit.ArgeoAccessManager">
                </AccessManager>
-               <LoginModule
-                       class="org.springframework.security.providers.jaas.SecurityContextLoginModule">
+               <LoginModule class="org.argeo.security.jackrabbit.ArgeoLoginModule">
                </LoginModule>
        </Security>
 </Repository>
\ No newline at end of file
index 2bf80b94177a0d44b197cc1bb097ce7217fc114b..84407be138a51932888a3149bcf2ed4989bc205d 100644 (file)
@@ -79,7 +79,7 @@
                -->
                <property name="maxThreads" value="8" />
 
-               <property name="allowAnonymousAccess" value="false" />
+               <property name="allowAnonymousAccess" value="true" />
                <property name="accessControlEnabled" value="false" />
                <property name="enableNtp" value="false" />
                <property name="enableKerberos" value="false" />
index 885f079c39b29192fd5436fa323a8d53c855da3c..3d5c77352f2a43d9454ec3355e47ddc689f18c4f 100644 (file)
       <plugin id="org.argeo.eclipse.ui"/>
       <plugin id="org.argeo.eclipse.ui.jcr"/>
       <plugin id="org.argeo.eclipse.ui.rcp"/>
+      <plugin id="org.argeo.infra.core"/>
+      <plugin id="org.argeo.infra.security.services" fragment="true"/>
       <plugin id="org.argeo.jackrabbit.webapp"/>
       <plugin id="org.argeo.jcr.ui.explorer"/>
       <plugin id="org.argeo.node.repo.jackrabbit"/>
       <plugin id="org.argeo.security.core"/>
       <plugin id="org.argeo.security.equinox"/>
+      <plugin id="org.argeo.security.jackrabbit" fragment="true"/>
       <plugin id="org.argeo.security.ldap"/>
       <plugin id="org.argeo.security.manager.ldap"/>
       <plugin id="org.argeo.security.mvc"/>
       <plugin id="org.argeo.server.ads.server"/>
       <plugin id="org.argeo.server.catalina" fragment="true"/>
       <plugin id="org.argeo.server.core"/>
+      <plugin id="org.argeo.server.ext.jackrabbit" fragment="true"/>
       <plugin id="org.argeo.server.jackrabbit"/>
       <plugin id="org.argeo.server.jcr"/>
       <plugin id="org.argeo.server.jcr.mvc"/>
       <plugin id="org.argeo.server.json"/>
       <plugin id="org.argeo.server.tika.jackrabbit" fragment="true"/>
       <plugin id="org.argeo.server.tomcat" fragment="true"/>
+      <plugin id="org.argeo.server.webextender" fragment="true"/>
+      <plugin id="org.argeo.slc.agent.ext.xalan" fragment="true"/>
+      <plugin id="org.argeo.slc.demo.log4j" fragment="true"/>
+      <plugin id="org.argeo.slc.gis.ext.dbcp" fragment="true"/>
       <plugin id="org.eclipse.core.commands"/>
       <plugin id="org.eclipse.core.contenttype"/>
       <plugin id="org.eclipse.core.databinding"/>
       <plugin id="org.springframework.osgi.web"/>
       <plugin id="org.springframework.osgi.web.extender"/>
       <plugin id="org.springframework.oxm"/>
+      <plugin id="org.springframework.security.acls" fragment="true"/>
       <plugin id="org.springframework.security.core"/>
       <plugin id="org.springframework.transaction"/>
       <plugin id="org.springframework.web"/>
index ac3cce9fdaf2d5fd065bea8636906b04cbe4c110..9f2926cb34d635d35e33215d6c811e70d80007d8 100644 (file)
@@ -1,24 +1,46 @@
 package org.argeo.jackrabbit;
 
+import java.util.HashMap;
 import java.util.Map;
 
 import javax.jcr.Repository;
 import javax.jcr.RepositoryException;
 import javax.jcr.RepositoryFactory;
 
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.jackrabbit.commons.JcrUtils;
+import org.apache.jackrabbit.jcr2dav.Jcr2davRepositoryFactory;
+import org.argeo.ArgeoException;
 import org.argeo.jcr.ArgeoJcrConstants;
-import org.argeo.jcr.DefaultRepositoryRegister;
+import org.argeo.jcr.DefaultRepositoryFactory;
 
-public class JackrabbitRepositoryFactory extends DefaultRepositoryRegister
+public class JackrabbitRepositoryFactory extends DefaultRepositoryFactory
                implements RepositoryFactory, ArgeoJcrConstants {
+       private final static Log log = LogFactory
+                       .getLog(JackrabbitRepositoryFactory.class);
 
        @SuppressWarnings("rawtypes")
        public Repository getRepository(Map parameters) throws RepositoryException {
-               String alias;
-               if (parameters.containsKey(JCR_REPOSITORY_ALIAS)) {
-                       alias = parameters.get(JCR_REPOSITORY_ALIAS).toString();
+               Repository repository = super.getRepository(parameters);
+               if (repository != null)
+                       return repository;
+
+               if (parameters.containsKey(JCR_REPOSITORY_URI)) {
+                       String uri = parameters.get(JCR_REPOSITORY_URI).toString();
+                       Map<String, String> params = new HashMap<String, String>();
+                       
+                       params.put(JcrUtils.REPOSITORY_URI, uri);
+                       repository = new Jcr2davRepositoryFactory().getRepository(params);
+                       if (repository == null)
+                               throw new ArgeoException("Remote Davex repository " + uri
+                                               + " not found");
+                       log.info("Initialized remote Jackrabbit repository " + repository
+                                       + " from uri " + uri);
+
                }
-               return null;
+
+               return repository;
        }
 
 }
index ded491510f819b02da138761e28f7c38b1bc74bd..eab7451db741471555979486f55a974f3bf3333c 100644 (file)
@@ -16,6 +16,7 @@ import javax.servlet.http.HttpServletRequest;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.jackrabbit.server.SessionProvider;
+import org.argeo.ArgeoException;
 
 /** To be injected, typically of scope="session" */
 public class SimpleSessionProvider implements SessionProvider, Serializable {
@@ -24,8 +25,7 @@ public class SimpleSessionProvider implements SessionProvider, Serializable {
        private final static Log log = LogFactory
                        .getLog(SimpleSessionProvider.class);
 
-       private transient Map<String, Session> sessions = Collections
-                       .synchronizedMap(new HashMap<String, Session>());
+       private transient Map<String, Session> sessions;
 
        private Credentials credentials = null;
 
@@ -33,10 +33,22 @@ public class SimpleSessionProvider implements SessionProvider, Serializable {
                        String workspace) throws LoginException, ServletException,
                        RepositoryException {
 
+               // since sessions is transient it can be restored from the session
+               if (sessions == null)
+                       sessions = Collections
+                                       .synchronizedMap(new HashMap<String, Session>());
+
                if (!sessions.containsKey(workspace)) {
-                       Session session = rep.login(credentials, workspace);
-                       sessions.put(workspace, session);
-                       return session;
+                       try {
+                               Session session = rep.login(credentials, workspace);
+                               if (log.isDebugEnabled())
+                                       log.debug("User " + session.getUserID() + " logged into "
+                                                       + request.getServletPath());
+                               sessions.put(workspace, session);
+                               return session;
+                       } catch (Exception e) {
+                               throw new ArgeoException("Cannot open session", e);
+                       }
                } else {
                        Session session = sessions.get(workspace);
                        if (!session.isLive()) {
@@ -49,17 +61,19 @@ public class SimpleSessionProvider implements SessionProvider, Serializable {
        }
 
        public void releaseSession(Session session) {
-               if (log.isDebugEnabled())
-                       log.debug("Releasing JCR session " + session);
-               // session.logout();
-               // FIXME: find a way to log out when the HTTP session is expired
+               if (log.isTraceEnabled())
+                       log.trace("Releasing JCR session " + session);
+       }
+
+       public void init() {
        }
 
        public void dispose() {
-               for (String workspace : sessions.keySet()) {
-                       Session session = sessions.get(workspace);
-                       if (session.isLive())
-                               session.logout();
-               }
+               if (sessions != null)
+                       for (String workspace : sessions.keySet()) {
+                               Session session = sessions.get(workspace);
+                               if (session.isLive())
+                                       session.logout();
+                       }
        }
 }
diff --git a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/DefaultRepositoryFactory.java b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/DefaultRepositoryFactory.java
new file mode 100644 (file)
index 0000000..25c3554
--- /dev/null
@@ -0,0 +1,24 @@
+package org.argeo.jcr;
+
+import java.util.Map;
+
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.RepositoryFactory;
+
+public class DefaultRepositoryFactory extends DefaultRepositoryRegister
+               implements RepositoryFactory, ArgeoJcrConstants {
+//     private final static Log log = LogFactory
+//                     .getLog(DefaultRepositoryFactory.class);
+
+       @SuppressWarnings("rawtypes")
+       public Repository getRepository(Map parameters) throws RepositoryException {
+               if (parameters.containsKey(JCR_REPOSITORY_ALIAS)) {
+                       String alias = parameters.get(JCR_REPOSITORY_ALIAS).toString();
+                       if (getRepositories().containsKey(alias))
+                               return getRepositories().get(alias);
+               }
+               return null;
+       }
+
+}