First working remote node
authorMathieu Baudier <mbaudier@argeo.org>
Sat, 29 Oct 2011 15:40:33 +0000 (15:40 +0000)
committerMathieu Baudier <mbaudier@argeo.org>
Sat, 29 Oct 2011 15:40:33 +0000 (15:40 +0000)
git-svn-id: https://svn.argeo.org/commons/trunk@4866 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc

43 files changed:
demo/.project [new file with mode: 0644]
demo/argeo_node_rcp.properties
demo/argeo_node_rcp_remote.properties [new file with mode: 0644]
security/modules/org.argeo.security.dao.jackrabbit/META-INF/spring/jcrsecuritydao-osgi.xml
security/modules/org.argeo.security.dao.jackrabbit/META-INF/spring/jcrsecuritydao.xml
security/modules/org.argeo.security.dao.jackrabbit/META-INF/spring/services.xml
security/modules/org.argeo.security.dao.os/.project [new file with mode: 0644]
security/modules/org.argeo.security.dao.os/META-INF/MANIFEST.MF [new file with mode: 0644]
security/modules/org.argeo.security.dao.os/META-INF/spring/security-os-osgi.xml [new file with mode: 0644]
security/modules/org.argeo.security.dao.os/META-INF/spring/security-os.xml [new file with mode: 0644]
security/modules/org.argeo.security.dao.os/build.properties [new file with mode: 0644]
security/modules/org.argeo.security.dao.os/pom.xml [new file with mode: 0644]
security/modules/org.argeo.security.dao.os/security.properties [new file with mode: 0644]
security/modules/pom.xml
security/plugins/org.argeo.security.equinox/META-INF/spring/loginModules.xml
security/plugins/org.argeo.security.equinox/plugin.xml
security/plugins/org.argeo.security.equinox/src/main/java/org/argeo/security/equinox/SpringLoginModule.java
security/plugins/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/editors/DefaultUserMainPage.java
security/plugins/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/views/UsersView.java
security/plugins/org.argeo.security.ui.rap/plugin.xml
security/plugins/org.argeo.security.ui.rap/src/main/java/org/argeo/security/ui/rap/SecureWorkbenchAdvisor.java
security/plugins/org.argeo.security.ui.rcp/META-INF/jaas_default.txt
security/plugins/org.argeo.security.ui.rcp/plugin.xml
security/plugins/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/AbstractSecureApplication.java
security/plugins/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/SecureApplicationActivator.java
security/plugins/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/SecureWorkbenchAdvisor.java
security/plugins/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/SecureWorkbenchWindowAdvisor.java
security/plugins/org.argeo.security.ui/plugin.xml
security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/jcr/JcrAuthenticationProvider.java
security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/jcr/OsJcrAuthenticationProvider.java
security/runtime/org.argeo.security.jackrabbit/src/main/java/org/argeo/security/jackrabbit/ArgeoSecurityManager.java
security/runtime/org.argeo.security.jackrabbit/src/main/java/org/argeo/security/jackrabbit/providers/JackrabbitAuthenticationProvider.java
security/runtime/org.argeo.security.ldap/src/main/java/org/argeo/security/ldap/jcr/JcrUserDetailsContextMapper.java
server/modules/org.argeo.node.repo.jackrabbit/META-INF/spring/noderepo.xml
server/modules/org.argeo.node.repo.jackrabbit/pom.xml
server/plugins/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/views/GenericJcrBrowser.java
server/runtime/org.argeo.server.jackrabbit/pom.xml
server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/JackrabbitContainer.java
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/ArgeoNames.java
server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/JcrUtils.java
server/runtime/org.argeo.server.jcr/src/main/resources/org/argeo/jcr/argeo.cnd

diff --git a/demo/.project b/demo/.project
new file mode 100644 (file)
index 0000000..d22f4c5
--- /dev/null
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>org.argeo.commons.demo</name>
+       <comment></comment>
+       <projects>
+       </projects>
+       <buildSpec>
+       </buildSpec>
+       <natures>
+       </natures>
+</projectDescription>
index e19c8d162c01c2dd798f0766594d35849e1c207f..cd705db2dd748ef3be6bcfeb994a54d0005ec802 100644 (file)
@@ -2,7 +2,7 @@ argeo.osgi.start=\
 org.springframework.osgi.extender,\
 org.argeo.node.repofactory.jackrabbit,\
 org.argeo.node.repo.jackrabbit,\
-org.argeo.security.dao.jackrabbit,\
+org.argeo.security.dao.os,\
 org.argeo.security.equinox,\
 
 org.argeo.security.ui.initialPerspective=org.argeo.osgi.ui.explorer.perspective
diff --git a/demo/argeo_node_rcp_remote.properties b/demo/argeo_node_rcp_remote.properties
new file mode 100644 (file)
index 0000000..bd2344c
--- /dev/null
@@ -0,0 +1,14 @@
+argeo.osgi.start=\
+org.springframework.osgi.extender,\
+org.argeo.node.repofactory.jackrabbit,\
+org.argeo.node.repo.jackrabbit,\
+org.argeo.security.dao.jackrabbit,\
+org.argeo.security.equinox,\
+
+org.argeo.security.ui.initialPerspective=org.argeo.osgi.ui.explorer.perspective
+
+argeo.node.repo.uri=http://localhost:7070/org.argeo.jcr.webapp/remoting/node
+
+log4j.configuration=file:../../log4j.properties
+
+eclipse.application=org.argeo.security.ui.rcp.secureUi
index e893e9bfd90c95d3d340bf07430cbdef9929fb3a..5ab914764f264967c888c402d239051ae7624eac 100644 (file)
                <listener ref="jcrAuthenticationProvider" bind-method="register"\r
                        unbind-method="unregister" />\r
        </reference>\r
-       <reference id="nodeRepository" interface="javax.jcr.Repository"\r
-               filter="(argeo.jcr.repository.alias=${argeo.node.repo.alias})" cardinality="0..1">\r
-               <listener ref="osJcrAuthenticationProvider" bind-method="register"\r
-                       unbind-method="unregister" />\r
-       </reference>\r
-\r
-       <reference id="systemExecutionServiceRef" interface="org.argeo.security.SystemExecutionService"\r
-               cardinality="0..1">\r
-               <listener ref="osJcrAuthenticationProvider" bind-method="register"\r
-                       unbind-method="unregister" />\r
-       </reference>\r
 \r
        <!-- SERVICES -->\r
        <service ref="systemExecutionService" interface="org.argeo.security.SystemExecutionService" />\r
index bbe3a165e34968f6305f7874c0e4cf7546cdd406..c09a53bf24f3f7d05d79bbf3638ab2b5475cadae 100644 (file)
@@ -5,7 +5,4 @@
 
        <bean id="jcrAuthenticationProvider"
                class="org.argeo.security.jackrabbit.providers.JackrabbitAuthenticationProvider" />
-
-       <bean id="osJcrAuthenticationProvider" class="org.argeo.security.jcr.OsJcrAuthenticationProvider">
-       </bean>
 </beans>
\ No newline at end of file
index c2348433cc5346748393c8e10fa80e0cbac283bd..00bb4538e64646459523b90762f25f14a0a6ce1d 100644 (file)
@@ -31,7 +31,6 @@
                                        <property name="key" value="${argeo.security.systemKey}" />
                                </bean>
                                <ref bean="jcrAuthenticationProvider" />
-                               <ref bean="osJcrAuthenticationProvider" />
                        </list>
                </property>
        </bean>
diff --git a/security/modules/org.argeo.security.dao.os/.project b/security/modules/org.argeo.security.dao.os/.project
new file mode 100644 (file)
index 0000000..cefcc33
--- /dev/null
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>org.argeo.security.dao.os</name>
+       <comment></comment>
+       <projects>
+       </projects>
+       <buildSpec>
+               <buildCommand>
+                       <name>org.eclipse.pde.ManifestBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.pde.SchemaBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+       </buildSpec>
+       <natures>
+               <nature>org.eclipse.pde.PluginNature</nature>
+       </natures>
+</projectDescription>
diff --git a/security/modules/org.argeo.security.dao.os/META-INF/MANIFEST.MF b/security/modules/org.argeo.security.dao.os/META-INF/MANIFEST.MF
new file mode 100644 (file)
index 0000000..1a72f40
--- /dev/null
@@ -0,0 +1,17 @@
+Manifest-Version: 1.0\r
+Private-Package: .\r
+Tool: Bnd-1.15.0\r
+Bundle-Name: Commons Security DAO OS\r
+Created-By: 1.6.0_20 (Sun Microsystems Inc.)\r
+Bundle-RequiredExecutionEnvironment: J2SE-1.5\r
+Bundle-Vendor: Argeo\r
+Bundle-Version: 0.3.4.SNAPSHOT-r20111029_170433\r
+Bundle-ManifestVersion: 2\r
+Bundle-License: http://www.apache.org/licenses/LICENSE-2.0.txt\r
+Import-Package: javax.jcr,org.argeo.security,org.argeo.security.core,o\r
+ rg.argeo.security.jcr,org.springframework.beans.factory.config,org.sp\r
+ ringframework.security,org.springframework.security.adapters,org.spri\r
+ ngframework.security.providers\r
+Bundle-SymbolicName: org.argeo.security.dao.os\r
+Bundle-DocURL: http://www.argeo.org\r
+\r
diff --git a/security/modules/org.argeo.security.dao.os/META-INF/spring/security-os-osgi.xml b/security/modules/org.argeo.security.dao.os/META-INF/spring/security-os-osgi.xml
new file mode 100644 (file)
index 0000000..ba6f0bf
--- /dev/null
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<beans:beans xmlns="http://www.springframework.org/schema/osgi"\r
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans"\r
+       xmlns:util="http://www.springframework.org/schema/util"\r
+       xsi:schemaLocation="http://www.springframework.org/schema/osgi  \r
+       http://www.springframework.org/schema/osgi/spring-osgi-1.1.xsd\r
+       http://www.springframework.org/schema/beans   \r
+       http://www.springframework.org/schema/beans/spring-beans-2.5.xsd\r
+       http://www.springframework.org/schema/util\r
+       http://www.springframework.org/schema/util/spring-util-2.5.xsd">\r
+\r
+       <!-- REFERENCE -->\r
+       <reference id="nodeRepository" interface="javax.jcr.Repository"\r
+               filter="(argeo.jcr.repository.alias=${argeo.node.repo.alias})" cardinality="0..1">\r
+               <listener ref="osJcrAuthenticationProvider" bind-method="register"\r
+                       unbind-method="unregister" />\r
+       </reference>\r
+\r
+       <reference id="systemExecutionServiceRef" interface="org.argeo.security.SystemExecutionService"\r
+               cardinality="0..1">\r
+               <listener ref="osJcrAuthenticationProvider" bind-method="register"\r
+                       unbind-method="unregister" />\r
+       </reference>\r
+\r
+       <!-- SERVICES -->\r
+       <service ref="systemExecutionService" interface="org.argeo.security.SystemExecutionService" />\r
+\r
+       <service ref="authenticationManager"\r
+               interface="org.springframework.security.AuthenticationManager" />\r
+\r
+</beans:beans>
\ No newline at end of file
diff --git a/security/modules/org.argeo.security.dao.os/META-INF/spring/security-os.xml b/security/modules/org.argeo.security.dao.os/META-INF/spring/security-os.xml
new file mode 100644 (file)
index 0000000..180f1fe
--- /dev/null
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
+
+       <bean
+               class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
+               <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
+               <property name="locations">
+                       <value>osgibundle:security.properties</value>
+               </property>
+       </bean>
+
+       <bean id="osJcrAuthenticationProvider" class="org.argeo.security.jcr.OsJcrAuthenticationProvider">
+       </bean>
+
+
+       <bean id="systemExecutionService" class="org.argeo.security.core.KeyBasedSystemExecutionService">
+               <property name="systemAuthenticationKey" value="${argeo.security.systemKey}" />
+               <property name="authenticationManager" ref="authenticationManager" />
+       </bean>
+
+       <bean id="authenticationManager" class="org.springframework.security.providers.ProviderManager">
+               <property name="providers">
+                       <bean factory-bean="authenticationProvidersRegister"
+                               factory-method="getProviders" />
+               </property>
+       </bean>
+
+       <bean id="authenticationProvidersRegister" class="org.argeo.security.core.AuthenticationProvidersRegister">
+               <property name="defaultProviders">
+                       <list>
+                               <bean class="org.springframework.security.adapters.AuthByAdapterProvider">
+                                       <property name="key" value="${argeo.security.systemKey}" />
+                               </bean>
+                               <ref bean="osJcrAuthenticationProvider" />
+                       </list>
+               </property>
+       </bean>
+
+</beans>
\ No newline at end of file
diff --git a/security/modules/org.argeo.security.dao.os/build.properties b/security/modules/org.argeo.security.dao.os/build.properties
new file mode 100644 (file)
index 0000000..5f22cdd
--- /dev/null
@@ -0,0 +1 @@
+bin.includes = META-INF/
diff --git a/security/modules/org.argeo.security.dao.os/pom.xml b/security/modules/org.argeo.security.dao.os/pom.xml
new file mode 100644 (file)
index 0000000..e19515a
--- /dev/null
@@ -0,0 +1,12 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+       <modelVersion>4.0.0</modelVersion>
+       <parent>
+               <groupId>org.argeo.commons.security</groupId>
+               <version>0.3.4-SNAPSHOT</version>
+               <artifactId>modules</artifactId>
+               <relativePath>..</relativePath>
+       </parent>
+       <artifactId>org.argeo.security.dao.os</artifactId>
+       <name>Commons Security DAO OS</name>
+</project>
\ No newline at end of file
diff --git a/security/modules/org.argeo.security.dao.os/security.properties b/security/modules/org.argeo.security.dao.os/security.properties
new file mode 100644 (file)
index 0000000..beebcb5
--- /dev/null
@@ -0,0 +1,2 @@
+argeo.security.systemKey=argeo
+argeo.node.repo.alias=node
index 85950378543e7a535300f75632cbd488c9d57086..8d10e4d9214b6dcbe238f0d55eba1084763c6e21 100644 (file)
@@ -12,6 +12,7 @@
        <packaging>pom</packaging>
        <name>Commons Security Modules</name>
        <modules>
+               <module>org.argeo.security.dao.os</module>
                <module>org.argeo.security.dao.jackrabbit</module>
                <module>org.argeo.security.dao.ldap</module>
                <module>org.argeo.security.services</module>
index 5714e0e19329f40bf9b01687c06f08fdc082f21d..fe7bb602d39999fd9dd726d572e9fe18d5cbdbb9 100644 (file)
@@ -9,6 +9,12 @@
                <property name="authenticationManager" ref="authenticationManager" />
        </bean>
 
+       <bean id="springLoginModuleRemote" class="org.argeo.security.equinox.SpringLoginModule"
+               scope="prototype">
+               <property name="remote" value="true" />
+               <property name="authenticationManager" ref="authenticationManager" />
+       </bean>
+
        <bean id="osSpringLoginModule" class="org.argeo.security.equinox.OsSpringLoginModule"
                scope="prototype">
                <property name="authenticationManager" ref="authenticationManager" />
index 0bacbda67b808b2e8f3fc0e333c8c5ba7b9d2016..4032022dcb2147cf2c5a93055609c02d938cc77a 100644 (file)
@@ -6,6 +6,10 @@
   <loginModule class="org.argeo.eclipse.spring.SpringExtensionFactory" description="Argeo Spring Login Module"/>
   </extension>
 
+  <extension id="springLoginModuleRemote" name="Argeo Spring" point="org.eclipse.equinox.security.loginModule">
+  <loginModule class="org.argeo.eclipse.spring.SpringExtensionFactory" description="Argeo Spring Login Module"/>
+  </extension>
+
   <extension id="osSpringLoginModule" name="Argeo Spring OS" point="org.eclipse.equinox.security.loginModule">
   <loginModule class="org.argeo.eclipse.spring.SpringExtensionFactory" description="Argeo Spring OS Login Module"/>
   </extension>
index 03f5f35ed960d2c8d529337f4c0f8cef7838cb2c..dada3440525caf6c95b3e0172c25c33201223713 100644 (file)
@@ -20,6 +20,8 @@ import org.springframework.security.providers.jaas.SecurityContextLoginModule;
 
 /** Login module which caches one subject per thread. */
 public class SpringLoginModule extends SecurityContextLoginModule {
+       final static String NODE_REPO_URI = "argeo.node.repo.uri";
+
        private final static Log log = LogFactory.getLog(SpringLoginModule.class);
 
        private AuthenticationManager authenticationManager;
@@ -30,6 +32,8 @@ public class SpringLoginModule extends SecurityContextLoginModule {
 
        private Long waitBetweenFailedLoginAttempts = 5 * 1000l;
 
+       private Boolean remote = false;
+
        public SpringLoginModule() {
 
        }
@@ -64,12 +68,16 @@ public class SpringLoginModule extends SecurityContextLoginModule {
                        PasswordCallback passwordCallback = new PasswordCallback(
                                        "Password", false);
 
-                       // NameCallback urlCallback = new NameCallback("Site URL");
+                       NameCallback urlCallback = new NameCallback("Site URL");
 
                        if (callbackHandler == null)
                                throw new LoginException("No call back handler available");
-                       callbackHandler.handle(new Callback[] { nameCallback,
-                                       passwordCallback });
+                       if (remote)
+                               callbackHandler.handle(new Callback[] { nameCallback,
+                                               passwordCallback, urlCallback });
+                       else
+                               callbackHandler.handle(new Callback[] { nameCallback,
+                                               passwordCallback });
 
                        // Set user name and password
                        String username = nameCallback.getName();
@@ -80,12 +88,16 @@ public class SpringLoginModule extends SecurityContextLoginModule {
                        if (passwordCallback.getPassword() != null)
                                password = String.valueOf(passwordCallback.getPassword());
 
-                       // String url = urlCallback.getName();
+                       String url = remote ? urlCallback.getName() : null;
+                       if (remote && (url == null || url.trim().equals("")))
+                               // for convenience, may be removed in the future
+                               url = System.getProperty(NODE_REPO_URI);
+
                        // TODO: set it via system properties
                        String workspace = null;
 
                        SiteAuthenticationToken credentials = new SiteAuthenticationToken(
-                                       username, password, null, workspace);
+                                       username, password, url, workspace);
 
                        Authentication authentication;
                        try {
@@ -135,4 +147,8 @@ public class SpringLoginModule extends SecurityContextLoginModule {
                        AuthenticationManager authenticationManager) {
                this.authenticationManager = authenticationManager;
        }
+
+       public void setRemote(Boolean remote) {
+               this.remote = remote;
+       }
 }
index 22927bd1126c6713f9a30ba705ad5a28ee69cba7..5a20377cabce94977ba7e811a62ef94cfa291bfb 100644 (file)
@@ -46,9 +46,8 @@ public class DefaultUserMainPage extends FormPage implements ArgeoNames {
        protected void createFormContent(final IManagedForm mf) {
                try {
                        ScrolledForm form = mf.getForm();
-                       form.setText(userProfile.getProperty(ARGEO_FIRST_NAME).getString()
-                                       + " "
-                                       + userProfile.getProperty(ARGEO_LAST_NAME).getString());
+                       form.setText(getProperty(ARGEO_FIRST_NAME) + " "
+                                       + getProperty(ARGEO_LAST_NAME));
                        GridLayout mainLayout = new GridLayout(1, true);
                        // ColumnLayout mainLayout = new ColumnLayout();
                        // mainLayout.minNumColumns = 1;
@@ -89,13 +88,13 @@ public class DefaultUserMainPage extends FormPage implements ArgeoNames {
                // username = createLT(body, "Username", "");
                // }
                final Text firstName = createLT(body, "First name",
-                               userProfile.getProperty(ARGEO_FIRST_NAME));
+                               getProperty(ARGEO_FIRST_NAME));
                final Text lastName = createLT(body, "Last name",
-                               userProfile.getProperty(ARGEO_LAST_NAME));
+                               getProperty(ARGEO_LAST_NAME));
                final Text email = createLT(body, "Email",
-                               userProfile.getProperty(ARGEO_PRIMARY_EMAIL));
+                               getProperty(ARGEO_PRIMARY_EMAIL));
                final Text description = createLT(body, "Description",
-                               userProfile.getProperty(Property.JCR_DESCRIPTION));
+                               getProperty(Property.JCR_DESCRIPTION));
 
                // create form part (controller)
                AbstractFormPart part = new SectionPart(section) {
@@ -136,6 +135,12 @@ public class DefaultUserMainPage extends FormPage implements ArgeoNames {
                getManagedForm().addPart(part);
        }
 
+       /** @return the property, or teh empty string if not set */
+       protected String getProperty(String name) throws RepositoryException {
+               return userProfile.hasProperty(name) ? userProfile.getProperty(name)
+                               .getString() : "";
+       }
+
        /** Creates the password section */
        protected void createPassworPart(Composite parent) {
                FormToolkit tk = getManagedForm().getToolkit();
@@ -187,11 +192,6 @@ public class DefaultUserMainPage extends FormPage implements ArgeoNames {
                return text;
        }
 
-       protected Text createLT(Composite body, String label, Property value)
-                       throws RepositoryException {
-               return createLT(body, label, value.getString());
-       }
-
        /** Creates label and password. */
        protected Text createLP(Composite body, String label, String value) {
                FormToolkit toolkit = getManagedForm().getToolkit();
index 4242436d479a1abadf9bbd782388f6a3bf2b9120..a41f20af5560daada24541d3a9f9a860f2445a2d 100644 (file)
@@ -129,6 +129,7 @@ public class UsersView extends ViewPart implements ArgeoNames, ArgeoTypes,
                public String getColumnText(Object element, int columnIndex) {
                        try {
                                Node userHome = (Node) element;
+                               Node userProfile = userHome.getNode(ARGEO_PROFILE);
                                switch (columnIndex) {
                                case 0:
                                        String userName = userHome.getProperty(ARGEO_USER_ID)
@@ -138,14 +139,14 @@ public class UsersView extends ViewPart implements ArgeoNames, ArgeoTypes,
                                        else
                                                return userName;
                                case 1:
-                                       return userHome.getNode(ARGEO_PROFILE)
-                                                       .getProperty(ARGEO_FIRST_NAME).getString();
+                                       return userProfile.hasProperty(ARGEO_FIRST_NAME) ? userProfile
+                                                       .getProperty(ARGEO_FIRST_NAME).getString() : "";
                                case 2:
-                                       return userHome.getNode(ARGEO_PROFILE)
-                                                       .getProperty(ARGEO_LAST_NAME).getString();
+                                       return userProfile.hasProperty(ARGEO_LAST_NAME) ? userProfile
+                                                       .getProperty(ARGEO_LAST_NAME).getString() : "";
                                case 3:
-                                       return userHome.getNode(ARGEO_PROFILE)
-                                                       .getProperty(ARGEO_PRIMARY_EMAIL).getString();
+                                       return userProfile.hasProperty(ARGEO_PRIMARY_EMAIL) ? userProfile
+                                                       .getProperty(ARGEO_PRIMARY_EMAIL).getString() : "";
                                default:
                                        throw new ArgeoException("Unmanaged column " + columnIndex);
                                }
index 9b284c251757d56b68175c6f68651270a769044d..d9afe3e2b0090d6d5802c677e15ccc447457d160 100644 (file)
        </branding>
        </extension>
 
+   <extension
+         point="org.eclipse.equinox.security.callbackHandlerMapping">
+      <callbackHandlerMapping
+            callbackHandlerId="org.argeo.security.ui.defaultLoginDialog"
+            configName="SPRING">
+      </callbackHandlerMapping>
+   </extension>
+   <extension
+         point="org.eclipse.equinox.security.callbackHandlerMapping">
+         <callbackHandlerMapping
+            callbackHandlerId="org.argeo.security.ui.defaultLoginDialog"
+            configName="NIX">
+      </callbackHandlerMapping>
+   </extension>
+   <extension
+         point="org.eclipse.equinox.security.callbackHandlerMapping">
+      <callbackHandlerMapping
+            callbackHandlerId="org.argeo.security.ui.defaultLoginDialog"
+            configName="SPRING_SECURITY_CONTEXT">
+      </callbackHandlerMapping>
+   </extension>
+
 </plugin>
index 06a83306db794940db3d05f3e27308b281d4c472..c2d74009974b4ede506764fb0d12ed7bd67b214f 100644 (file)
@@ -6,7 +6,6 @@ import org.eclipse.ui.application.WorkbenchAdvisor;
 import org.eclipse.ui.application.WorkbenchWindowAdvisor;
 
 public class SecureWorkbenchAdvisor extends WorkbenchAdvisor {
-       //static final String DEFAULT_PERSPECTIVE_ID = "org.argeo.security.ui.adminSecurityPerspective"; //$NON-NLS-1$
        public final static String INITIAL_PERSPECTIVE_PROPERTY = "org.argeo.security.ui.initialPerspective";
        private String initialPerspective = System.getProperty(
                        INITIAL_PERSPECTIVE_PROPERTY, null);
index bbabac66a197754f0e49937a3a6d63840502e45a..124d7ad9f57c93ec0cb70e4f8bd860a5fa6bdc18 100644 (file)
@@ -17,6 +17,11 @@ WINDOWS {
         extensionId="org.argeo.security.equinox.osSpringLoginModule";
 };
 
+REMOTE {
+    org.eclipse.equinox.security.auth.module.ExtensionLoginModule sufficient
+        extensionId="org.argeo.security.equinox.springLoginModuleRemote";
+};
+
 KEYRING {
     org.argeo.util.crypto.KeyringLoginModule required;
 };
index 39b8c848ccb02c2dd701814c621e9536af44b8b0..53eaa525dbbbd2b15145f679f8769161c1722413 100644 (file)
          </run>
       </application>
    </extension>
+   
+   <extension
+         point="org.eclipse.equinox.security.callbackHandlerMapping">
+      <callbackHandlerMapping
+            callbackHandlerId="org.argeo.security.ui.defaultLoginDialog"
+            configName="REMOTE">
+      </callbackHandlerMapping>
+   </extension>
+   
 </plugin>
index 7487567a8ba03c01557e95be665111c569f688d7..f898d9df3fceaebdcce46c085d07700f36aef61f 100644 (file)
@@ -20,6 +20,8 @@ import org.eclipse.ui.application.WorkbenchAdvisor;
  * RCP workbench initialization
  */
 public abstract class AbstractSecureApplication implements IApplication {
+       final static String NODE_REPO_URI = "argeo.node.repo.uri";
+
        private static final Log log = LogFactory
                        .getLog(AbstractSecureApplication.class);
 
@@ -29,20 +31,27 @@ public abstract class AbstractSecureApplication implements IApplication {
 
        public Object start(IApplicationContext context) throws Exception {
                // wait for the system to be initialized
-//             try {
-//                     Thread.sleep(3000);
-//             } catch (Exception e2) {
-//                     // silent
-//             }
+               // try {
+               // Thread.sleep(3000);
+               // } catch (Exception e2) {
+               // // silent
+               // }
+
+               boolean remote = System.getProperty(NODE_REPO_URI) != null;
 
                // choose login context
                final ILoginContext loginContext;
-               if (OperatingSystem.os == OperatingSystem.WINDOWS)
+               if (remote) {
                        loginContext = SecureApplicationActivator
-                                       .createLoginContext(SecureApplicationActivator.CONTEXT_WINDOWS);
-               else
-                       loginContext = SecureApplicationActivator
-                                       .createLoginContext(SecureApplicationActivator.CONTEXT_NIX);
+                                       .createLoginContext(SecureApplicationActivator.CONTEXT_REMOTE);
+               } else {
+                       if (OperatingSystem.os == OperatingSystem.WINDOWS)
+                               loginContext = SecureApplicationActivator
+                                               .createLoginContext(SecureApplicationActivator.CONTEXT_WINDOWS);
+                       else
+                               loginContext = SecureApplicationActivator
+                                               .createLoginContext(SecureApplicationActivator.CONTEXT_NIX);
+               }
 
                final Display display = PlatformUI.createDisplay();
 
index 1c8bd7c25e7a4c4be58896f0efb339f3c28abe67..6ab4edeed5ce05898c47c90bed8727594916a7f3 100644 (file)
@@ -10,6 +10,7 @@ import org.osgi.framework.BundleContext;
 /** Activator able to create {@link ILoginContext} */
 public class SecureApplicationActivator implements BundleActivator {
 
+       public final static String CONTEXT_REMOTE = "REMOTE";
        public final static String CONTEXT_NIX = "NIX";
        public final static String CONTEXT_WINDOWS = "WINDOWS";
        private static final String JAAS_CONFIG_FILE = "/META-INF/jaas_default.txt";
index bca01e714b2388b353fdc741a1c8cb9e1530ed38..b01dd05ba4973939820725f079aa2016d4bf2100 100644 (file)
@@ -1,19 +1,18 @@
 package org.argeo.security.ui.rcp;
 
+import org.eclipse.ui.IPerspectiveDescriptor;
 import org.eclipse.ui.application.IWorkbenchWindowConfigurer;
 import org.eclipse.ui.application.WorkbenchAdvisor;
 import org.eclipse.ui.application.WorkbenchWindowAdvisor;
 
 public class SecureWorkbenchAdvisor extends WorkbenchAdvisor {
-       static final String DEFAULT_PERSPECTIVE_ID = "org.argeo.security.ui.adminSecurityPerspective"; //$NON-NLS-1$
        public final static String INITIAL_PERSPECTIVE_PROPERTY = "org.argeo.security.ui.initialPerspective";
+       private String initialPerspective = System.getProperty(
+                       INITIAL_PERSPECTIVE_PROPERTY, null);
 
        private final String username;
-       private String initialPerspective = System.getProperty(
-                       INITIAL_PERSPECTIVE_PROPERTY, DEFAULT_PERSPECTIVE_ID);
 
        public SecureWorkbenchAdvisor(String username) {
-               super();
                this.username = username;
        }
 
@@ -23,6 +22,17 @@ public class SecureWorkbenchAdvisor extends WorkbenchAdvisor {
        }
 
        public String getInitialWindowPerspectiveId() {
+               if (initialPerspective != null) {
+                       // check whether this user can see the declared perspective
+                       // (typically the perspective won't be listed if this user doesn't
+                       // have the right to see it)
+                       IPerspectiveDescriptor pd = getWorkbenchConfigurer().getWorkbench()
+                                       .getPerspectiveRegistry()
+                                       .findPerspectiveWithId(initialPerspective);
+                       if (pd == null)
+                               return null;
+               }
                return initialPerspective;
        }
+
 }
index d85c17c1a7ffbcecf40c3afd0d62e5922809950f..41e50e78a32662df3c464b9e39156833c8b033dc 100644 (file)
@@ -29,7 +29,13 @@ public class SecureWorkbenchWindowAdvisor extends WorkbenchWindowAdvisor {
                configurer.setShowProgressIndicator(true);
 
                configurer.setShowPerspectiveBar(true);
-               configurer.setTitle("Argeo UI - " + username); //$NON-NLS-1$
+               String remoteUri = System
+                               .getProperty(AbstractSecureApplication.NODE_REPO_URI);
+               if (remoteUri != null)
+                       configurer
+                                       .setTitle("Argeo UI - " + username + " (" + remoteUri + ")"); //$NON-NLS-1$
+               else
+                       configurer.setTitle("Argeo UI - " + username); //$NON-NLS-1$
 
        }
 }
index 59ccd3beec46e7b982bbb98e30270682bd721aac..9146615326a44b0983ad105e7a76b4579fead1fa 100644 (file)
             class="org.argeo.security.ui.dialogs.DefaultLoginDialog">
       </callbackHandler>
    </extension>
-   <extension
-         point="org.eclipse.equinox.security.callbackHandlerMapping">
-      <callbackHandlerMapping
-            callbackHandlerId="org.argeo.security.ui.defaultLoginDialog"
-            configName="SPRING">
-      </callbackHandlerMapping>
-   </extension>
-   <extension
-         point="org.eclipse.equinox.security.callbackHandlerMapping">
-         <callbackHandlerMapping
-            callbackHandlerId="org.argeo.security.ui.defaultLoginDialog"
-            configName="NIX">
-      </callbackHandlerMapping>
-   </extension>
-   <extension
-         point="org.eclipse.equinox.security.callbackHandlerMapping">
-      <callbackHandlerMapping
-            callbackHandlerId="org.argeo.security.ui.defaultLoginDialog"
-            configName="SPRING_SECURITY_CONTEXT">
-      </callbackHandlerMapping>
-   </extension>
    <extension
          point="org.eclipse.ui.commands">
       <command
index 9791da8a017fa0988df49475107ac7ca98d00188..c19e709a1547e91e7fd144c628e6507ce1c23698 100644 (file)
@@ -1,17 +1,22 @@
 package org.argeo.security.jcr;
 
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
+import javax.jcr.Credentials;
 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.JcrUtils;
 import org.argeo.security.SiteAuthenticationToken;
 import org.springframework.security.Authentication;
@@ -21,7 +26,7 @@ import org.springframework.security.GrantedAuthorityImpl;
 import org.springframework.security.providers.AuthenticationProvider;
 import org.springframework.security.userdetails.UserDetails;
 
-/** Connects to a JCR repository and delegate authentication to it. */
+/** Connects to a JCR repository and delegates authentication to it. */
 public class JcrAuthenticationProvider implements AuthenticationProvider {
        public final static String ROLE_REMOTE_JCR_AUTHENTICATED = "ROLE_REMOTE_JCR_AUTHENTICATED";
 
@@ -37,31 +42,39 @@ public class JcrAuthenticationProvider implements AuthenticationProvider {
                        return null;
 
                try {
-                       Map<String, String> parameters = new HashMap<String, String>();
-                       parameters.put(ArgeoJcrConstants.JCR_REPOSITORY_URI, url);
-
-                       Repository repository = null;
-                       repository = repositoryFactory.getRepository(parameters);
+                       SimpleCredentials sp = new SimpleCredentials(siteAuth.getName(),
+                                       siteAuth.getCredentials().toString().toCharArray());
+                       // get repository
+                       Repository repository = getRepository(url, sp);
                        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 = JcrUtils.getUserHome(session);
-                       if (userHome == null)
-                               throw new ArgeoException("No home found for user "
-                                               + session.getUserID());
-                       GrantedAuthority[] authorities = {};
+
+                       // retrieve remote roles
+                       Node userProfile = JcrUtils.getUserProfile(session);
+                       List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
+                       if (userProfile.hasProperty(ArgeoNames.ARGEO_REMOTE_ROLES)) {
+                               Value[] roles = userProfile.getProperty(
+                                               ArgeoNames.ARGEO_REMOTE_ROLES).getValues();
+                               for (int i = 0; i < roles.length; i++)
+                                       authorities.add(new GrantedAuthorityImpl(roles[i]
+                                                       .getString()));
+                       }
                        JcrAuthenticationToken authen = new JcrAuthenticationToken(
-                                       siteAuth.getPrincipal(), siteAuth.getCredentials(),
-                                       authorities, url, userHome);
+                                       siteAuth.getPrincipal(),
+                                       siteAuth.getCredentials(),
+                                       authorities.toArray(new GrantedAuthority[authorities.size()]),
+                                       url, userHome);
                        authen.setDetails(getUserDetails(userHome, authen));
+
                        return authen;
                } catch (RepositoryException e) {
                        throw new ArgeoException(
@@ -69,6 +82,13 @@ public class JcrAuthenticationProvider implements AuthenticationProvider {
                }
        }
 
+       protected Repository getRepository(String url, Credentials credentials)
+                       throws RepositoryException {
+               Map<String, String> parameters = new HashMap<String, String>();
+               parameters.put(ArgeoJcrConstants.JCR_REPOSITORY_URI, url);
+               return repositoryFactory.getRepository(parameters);
+       }
+
        /**
         * By default, assigns only the role {@value #ROLE_REMOTE_JCR_AUTHENTICATED}
         * . Should typically be overridden in order to assign more relevant roles.
index 2eadf5669724e5f7cb6000e2819f766f929e72c5..9abac5972a7f584fc1aaca81326d49877e4c41af 100644 (file)
@@ -35,7 +35,7 @@ public class OsJcrAuthenticationProvider extends OsAuthenticationProvider {
                                Session session = null;
                                try {
                                        session = repository.login(workspace);
-                                       // WARNING: at this stage we assume that teh java properties
+                                       // WARNING: at this stage we assume that the java properties
                                        // will have the same value
                                        String userName = System.getProperty("user.name");
                                        Node userHome = JcrUtils.getUserHome(session, userName);
@@ -44,6 +44,7 @@ public class OsJcrAuthenticationProvider extends OsAuthenticationProvider {
                                                                homeBasePath, userName);
                                        // authen.setDetails(getUserDetails(userHome, authen));
                                } catch (RepositoryException e) {
+                                       JcrUtils.discardQuietly(session);
                                        throw new ArgeoException(
                                                        "Unexpected exception when synchronizing OS and JCR security ",
                                                        e);
index a38f42541507dff6300a808ce1deab1a4797aa11..8f2632d0ff0ccf0445c968a86f8b4e771c36c58b 100644 (file)
@@ -46,6 +46,7 @@ public class ArgeoSecurityManager extends DefaultSecurityManager {
                        throws RepositoryException {
                long begin = System.currentTimeMillis();
 
+               // skip Jackrabbit system user
                if (!subject.getPrincipals(SystemPrincipal.class).isEmpty())
                        return super.getUserID(subject, workspaceName);
 
@@ -58,6 +59,10 @@ public class ArgeoSecurityManager extends DefaultSecurityManager {
                else
                        authen = authens.iterator().next();
 
+               // skip argeo system authenticated
+               // if (authen instanceof SystemAuthentication)
+               // return super.getUserID(subject, workspaceName);
+
                UserManager systemUm = getSystemUserManager(workspaceName);
 
                String userId = authen.getName();
@@ -68,7 +73,7 @@ public class ArgeoSecurityManager extends DefaultSecurityManager {
                        log.info(userId + " added as " + user);
                }
 
-               setHomeNodeAuthorizations(user);
+               //setHomeNodeAuthorizations(user);
 
                // process groups
                List<String> userGroupIds = new ArrayList<String>();
@@ -81,7 +86,6 @@ public class ArgeoSecurityManager extends DefaultSecurityManager {
                        if (!group.isMember(user))
                                group.addMember(user);
                        userGroupIds.add(ga.getAuthority());
-
                }
 
                // check if user has not been removed from some groups
@@ -91,6 +95,36 @@ public class ArgeoSecurityManager extends DefaultSecurityManager {
                                group.removeMember(user);
                }
 
+               // write roles in profile for easy access
+//             if (!(authen instanceof SystemAuthentication)) {
+//                     Node userProfile = JcrUtils.getUserProfile(getSystemSession(),
+//                                     userId);
+//                     boolean writeRoles = false;
+//                     if (userProfile.hasProperty(ArgeoNames.ARGEO_REMOTE_ROLES)) {
+//                             Value[] roles = userProfile.getProperty(ArgeoNames.ARGEO_REMOTE_ROLES)
+//                                             .getValues();
+//                             if (roles.length != userGroupIds.size())
+//                                     writeRoles = true;
+//                             else
+//                                     for (int i = 0; i < roles.length; i++)
+//                                             if (!roles[i].getString().equals(userGroupIds.get(i)))
+//                                                     writeRoles = true;
+//                     } else
+//                             writeRoles = true;
+//
+//                     if (writeRoles) {
+//                             userProfile.getSession().getWorkspace().getVersionManager()
+//                                             .checkout(userProfile.getPath());
+//                             String[] roleIds = userGroupIds.toArray(new String[userGroupIds
+//                                             .size()]);
+//                             userProfile.setProperty(ArgeoNames.ARGEO_REMOTE_ROLES, roleIds);
+//                             JcrUtils.updateLastModified(userProfile);
+//                             userProfile.getSession().save();
+//                             userProfile.getSession().getWorkspace().getVersionManager()
+//                                             .checkin(userProfile.getPath());
+//                     }
+//             }
+
                if (log.isTraceEnabled())
                        log.trace("Spring and Jackrabbit Security synchronized for user "
                                        + userId + " in " + (System.currentTimeMillis() - begin)
@@ -107,9 +141,12 @@ public class ArgeoSecurityManager extends DefaultSecurityManager {
                        Node userHome = null;
                        try {
                                userHome = JcrUtils.getUserHome(getSystemSession(), userId);
-                               if (userHome == null)
+                               if (userHome == null) {
                                        userHome = JcrUtils.createUserHome(getSystemSession(),
                                                        HOME_BASE_PATH, userId);
+                                       //log.warn("No home available for user "+userId);
+                                       return;
+                               }
                        } catch (Exception e) {
                                // silent
                        }
index d9f9f379a79a9cd6c127c78c870af4b8534b6633..ea84a073eb4862b262299cdef7a4844c14b6a7a7 100644 (file)
@@ -3,8 +3,11 @@ package org.argeo.security.jackrabbit.providers;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Properties;
 
+import javax.jcr.Credentials;
 import javax.jcr.Node;
+import javax.jcr.Repository;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
 
@@ -13,15 +16,38 @@ 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.jackrabbit.JackrabbitContainer;
+import org.argeo.jcr.ArgeoJcrConstants;
 import org.argeo.security.jcr.JcrAuthenticationProvider;
+import org.osgi.framework.BundleContext;
 import org.springframework.security.GrantedAuthority;
 import org.springframework.security.GrantedAuthorityImpl;
 
 public class JackrabbitAuthenticationProvider extends JcrAuthenticationProvider {
+       // @Override
+       // protected Repository getRepository(String url, Credentials credentials)
+       // throws RepositoryException {
+       // JackrabbitContainer repository = new JackrabbitContainer();
+       // repository.setUri(url);
+       // repository.setRemoteSystemCredentials(credentials);
+       // repository.init();
+       // if (bundleContext != null) {
+       // // FIXME check if not already a node
+       // Properties properties = new Properties();
+       // properties.put(ArgeoJcrConstants.JCR_REPOSITORY_ALIAS,
+       // ArgeoJcrConstants.ALIAS_NODE);
+       // bundleContext.registerService(Repository.class.getName(),
+       // repository, properties);
+       // }
+       // return repository;
+       // }
 
        @Override
        protected GrantedAuthority[] getGrantedAuthorities(Session session) {
                try {
+                       if (!(session instanceof JackrabbitSession))
+                               return super.getGrantedAuthorities(session);
+
                        JackrabbitSession jackrabbitSession = (JackrabbitSession) session;
                        UserManager userManager = jackrabbitSession.getUserManager();
                        User user = (User) userManager.getAuthorizable(session.getUserID());
@@ -39,6 +65,9 @@ public class JackrabbitAuthenticationProvider extends JcrAuthenticationProvider
        @Override
        protected Boolean isEnabled(Node userHome) {
                try {
+                       if (!(userHome.getSession() instanceof JackrabbitSession))
+                               return super.isEnabled(userHome);
+
                        UserManager userManager = ((JackrabbitSession) userHome
                                        .getSession()).getUserManager();
                        User user = (User) userManager.getAuthorizable(userHome
index fe212ccf89d489cc61b0d50ff8574fa0c1914687..b6657f0c597998dc015290ac713d7e1e6651161e 100644 (file)
@@ -128,14 +128,17 @@ public class JcrUserDetailsContextMapper implements UserDetailsContextMapper,
                try {
 
                        Node userHome = JcrUtils.getUserHome(session, username);
-                       if (userHome == null)
+                       boolean justCreatedHome = false;
+                       if (userHome == null) {
                                userHome = JcrUtils.createUserHome(session, homeBasePath,
                                                username);
+                               justCreatedHome = true;
+                       }
                        String userHomePath = userHome.getPath();
                        Node userProfile; // = userHome.getNode(ARGEO_PROFILE);
                        if (userHome.hasNode(ARGEO_PROFILE)) {
                                userProfile = userHome.getNode(ARGEO_PROFILE);
-                               if (syncLatency != 0) {
+                               if (syncLatency != 0 && !justCreatedHome) {
                                        Calendar lastModified = userProfile.getProperty(
                                                        Property.JCR_LAST_MODIFIED).getDate();
                                        long timeSinceLastUpdate = System.currentTimeMillis()
@@ -151,6 +154,8 @@ public class JcrUserDetailsContextMapper implements UserDetailsContextMapper,
                                // userProfile.addMixin(NodeType.MIX_LAST_MODIFIED);
                        }
 
+                       session.getWorkspace().getVersionManager()
+                                       .checkout(userProfile.getPath());
                        for (String jcrProperty : propertyToAttributes.keySet())
                                ldapToJcr(userProfile, jcrProperty, ctx);
 
@@ -164,6 +169,8 @@ public class JcrUserDetailsContextMapper implements UserDetailsContextMapper,
                                                + userProfile.getProperty(ARGEO_LAST_NAME).getString());
                        JcrUtils.updateLastModified(userProfile);
                        session.save();
+                       session.getWorkspace().getVersionManager()
+                                       .checkin(userProfile.getPath());
                        if (log.isTraceEnabled())
                                log.trace("Mapped " + ctx.getDn() + " to " + userProfile);
                        return userHomePath;
@@ -219,9 +226,16 @@ public class JcrUserDetailsContextMapper implements UserDetailsContextMapper,
                                                                + jcrProperty);
 
                        String value = ctx.getStringAttribute(ldapAttribute);
-                       if (value == null)
-                               return;
-                       userProfile.setProperty(jcrProperty, value);
+                       String jcrValue = userProfile.hasProperty(jcrProperty) ? userProfile
+                                       .getProperty(jcrProperty).getString() : null;
+                       if (value != null && jcrValue != null) {
+                               if (!value.equals(jcrValue))
+                                       userProfile.setProperty(jcrProperty, value);
+                       } else if (value != null && jcrValue == null) {
+                               userProfile.setProperty(jcrProperty, value);
+                       } else if (value == null && jcrValue != null) {
+                               userProfile.setProperty(jcrProperty, value);
+                       }
                } catch (Exception e) {
                        throw new ArgeoException("Cannot map JCR property " + jcrProperty
                                        + " from LDAP", e);
index 02d697b243aa3c7ae87cd5f7d0342b7bee34bcbc..8e477fe71b71b47da0c47c4f4468c9eee2b2fd00 100644 (file)
                                <value>classpath:/org/argeo/jcr/argeo.cnd</value>
                        </list>
                </property>
+               <property name="remoteSystemCredentials">
+                       <bean class="javax.jcr.SimpleCredentials">
+                               <constructor-arg value="root" />
+                               <constructor-arg value="demo" />
+                       </bean>
+               </property>
        </bean>
 
        <!-- Execute initialization with a system authentication -->
index 12ea019c035f4fee521dc939b91712ea30258e81..32840cd1933a5e508cc8b0e8c86c5b025190d09f 100644 (file)
@@ -17,6 +17,7 @@
                                <artifactId>maven-bundle-plugin</artifactId>
                                <configuration>
                                        <instructions>
+                                               <Bundle-SymbolicName>${project.artifactId};singleton:=true</Bundle-SymbolicName>
                                                <Import-Package>
                                                        *,
                                                        com.mysql.jdbc;version="[5.0.0,6.0.0)";resolution:=optional,
index 3af60844c907be7d5be60de784f354f30b5dfbce..292fc816e00ffdc8ce2f3f89576b3fa699e49767 100644 (file)
@@ -1,12 +1,12 @@
 package org.argeo.jcr.ui.explorer.views;
 
-import java.util.Arrays;
 import java.util.List;
 
 import javax.jcr.Property;
 import javax.jcr.PropertyType;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
+import javax.jcr.Value;
 import javax.jcr.observation.Event;
 import javax.jcr.observation.EventListener;
 import javax.jcr.observation.ObservationManager;
@@ -152,9 +152,17 @@ public class GenericJcrBrowser extends AbstractJcrBrowser {
                                        Property property = (Property) element;
                                        if (property.getType() == PropertyType.BINARY)
                                                return "<binary>";
-                                       else if (property.isMultiple())
-                                               return Arrays.asList(property.getValues()).toString();
-                                       else
+                                       else if (property.isMultiple()) {
+                                               StringBuffer buf = new StringBuffer("[");
+                                               Value[] values = property.getValues();
+                                               for (int i = 0; i < values.length; i++) {
+                                                       if (i != 0)
+                                                               buf.append(", ");
+                                                       buf.append(values[i].getString());
+                                               }
+                                               buf.append(']');
+                                               return buf.toString();
+                                       } else
                                                return property.getValue().getString();
                                } catch (RepositoryException e) {
                                        throw new ArgeoException(
index 1b2fe2316faf668a283d54bcea1a3ef2451c40fc..dc02e48d92ea29bfc51d3107afa24be46b8a5927 100644 (file)
                        <artifactId>org.argeo.server.core</artifactId>
                        <version>0.3.4-SNAPSHOT</version>
                </dependency>
+               <dependency>
+                       <groupId>org.argeo.commons.security</groupId>
+                       <artifactId>org.argeo.security.core</artifactId>
+                       <version>0.3.4-SNAPSHOT</version>
+               </dependency>
                <dependency>
                        <groupId>org.argeo.commons.server</groupId>
                        <artifactId>org.argeo.server.jcr.mvc</artifactId>
index a708aadd1d67a6eada7401b8bcf94d3cf95ff8ad..c2e0034ff183f0ca5b623ba7d992eb16f5148535 100644 (file)
@@ -40,6 +40,7 @@ import javax.jcr.Node;
 import javax.jcr.Repository;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
+import javax.jcr.SimpleCredentials;
 import javax.jcr.Value;
 
 import org.apache.commons.io.FileUtils;
@@ -57,9 +58,13 @@ import org.apache.jackrabbit.jcr2dav.Jcr2davRepositoryFactory;
 import org.argeo.ArgeoException;
 import org.argeo.jcr.ArgeoNames;
 import org.argeo.jcr.JcrUtils;
+import org.argeo.security.SystemAuthentication;
 import org.springframework.context.ResourceLoaderAware;
 import org.springframework.core.io.Resource;
 import org.springframework.core.io.ResourceLoader;
+import org.springframework.security.Authentication;
+import org.springframework.security.context.SecurityContextHolder;
+import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
 import org.springframework.util.SystemPropertyUtils;
 import org.xml.sax.InputSource;
 
@@ -75,7 +80,6 @@ public class JackrabbitContainer implements Repository, ResourceLoaderAware {
        private Resource variables;
 
        private Boolean inMemory = false;
-       private String uri = null;
 
        // wrapped repository
        private Repository repository;
@@ -97,21 +101,41 @@ public class JackrabbitContainer implements Repository, ResourceLoaderAware {
 
        private Executor systemExecutor;
 
-       public void init() throws Exception {
+       // remote
+       private String uri = null;
+       private Credentials remoteSystemCredentials = null;
+
+       /**
+        * Empty constructor, {@link #init()} should be called after properties have
+        * been set
+        */
+       public JackrabbitContainer() {
+       }
+
+       /**
+        * Convenience constructor for remote, {@link #init()} is called in the
+        * constructor.
+        */
+       public JackrabbitContainer(String uri, Credentials remoteSystemCredentials) {
+               setUri(uri);
+               setRemoteSystemCredentials(remoteSystemCredentials);
+               init();
+       }
+
+       public void init() {
                if (repository != null) {
                        // we are just wrapping another repository
-                       importNodeTypeDefinitions(repository);
+                       importNodeTypeDefinitions();
                        return;
                }
 
                createJackrabbitRepository();
-
                // migrate if needed
                migrate();
 
                // apply new CND files after migration
                if (cndFiles != null && cndFiles.size() > 0)
-                       importNodeTypeDefinitions(repository);
+                       importNodeTypeDefinitions();
        }
 
        /** Actually creates a new repository. */
@@ -135,6 +159,9 @@ public class JackrabbitContainer implements Repository, ResourceLoaderAware {
                                // the
                                // remote repository has been properly configured
                                return;
+                       } else {
+                               // reset uri to null in order to optimize isRemote()
+                               uri = null;
                        }
 
                        // local repository
@@ -337,14 +364,18 @@ public class JackrabbitContainer implements Repository, ResourceLoaderAware {
         * changed. In case of failures an error will be logged but no exception
         * will be thrown.
         */
-       protected void importNodeTypeDefinitions(final Repository repository) {
+       protected void importNodeTypeDefinitions() {
+               // importing node def on remote si currently not supported
+               if (isRemote())
+                       return;
+
                Runnable action = new Runnable() {
                        public void run() {
                                Reader reader = null;
                                Session session = null;
                                try {
-                                       session = repository.login();
-                                       processNewSession(session);
+                                       session = login();
+                                       // processNewSession(session);
                                        // Load cnds as resources
                                        for (String resUrl : cndFiles) {
                                                Resource res = resourceLoader.getResource(resUrl);
@@ -381,20 +412,32 @@ public class JackrabbitContainer implements Repository, ResourceLoaderAware {
                return getRepository().getDescriptorKeys();
        }
 
-       public Session login() throws LoginException, RepositoryException {
-               Session session = getRepository().login();
-               processNewSession(session);
-               return session;
-       }
-
+       /** Central login method */
        public Session login(Credentials credentials, String workspaceName)
                        throws LoginException, NoSuchWorkspaceException,
                        RepositoryException {
+
+               // retrieve credentials for remote
+               if (credentials == null && isRemote()) {
+                       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)
+                                               && remoteSystemCredentials != null) {
+                                       credentials = remoteSystemCredentials;
+                               }
+                       }
+               }
+
                Session session;
                try {
                        session = getRepository().login(credentials, workspaceName);
                } catch (NoSuchWorkspaceException e) {
-                       if (autocreateWorkspaces)
+                       if (autocreateWorkspaces && workspaceName != null)
                                session = createWorkspaceAndLogsIn(credentials, workspaceName);
                        else
                                throw e;
@@ -403,26 +446,22 @@ public class JackrabbitContainer implements Repository, ResourceLoaderAware {
                return session;
        }
 
+       public Session login() throws LoginException, RepositoryException {
+               return login(null, null);
+       }
+
        public Session login(Credentials credentials) throws LoginException,
                        RepositoryException {
-               Session session = getRepository().login(credentials);
-               processNewSession(session);
-               return session;
+               return login(credentials, null);
        }
 
        public Session login(String workspaceName) throws LoginException,
                        NoSuchWorkspaceException, RepositoryException {
-               Session session;
-               try {
-                       session = getRepository().login(workspaceName);
-               } catch (NoSuchWorkspaceException e) {
-                       if (autocreateWorkspaces)
-                               session = createWorkspaceAndLogsIn(null, workspaceName);
-                       else
-                               throw e;
-               }
-               processNewSession(session);
-               return session;
+               return login(null, workspaceName);
+       }
+
+       public Boolean isRemote() {
+               return uri != null;
        }
 
        /** Wraps access to the repository, making sure it is available. */
@@ -508,6 +547,10 @@ public class JackrabbitContainer implements Repository, ResourceLoaderAware {
                this.uri = uri;
        }
 
+       public void setRemoteSystemCredentials(Credentials remoteSystemCredentials) {
+               this.remoteSystemCredentials = remoteSystemCredentials;
+       }
+
        public void setSystemExecutor(Executor systemExecutor) {
                this.systemExecutor = systemExecutor;
        }
index bcf02a3c1e564896a9dffb7b6b73ceabcdb2577b..6fe5bf3406bcde3bcb3b5d6de7649d2209e40bb5 100644 (file)
@@ -15,6 +15,7 @@ import org.argeo.ArgeoException;
 import org.argeo.jcr.ArgeoJcrConstants;
 import org.argeo.jcr.DefaultRepositoryFactory;
 
+/** Repository factory which can access remote Jackrabbit repositories */
 public class JackrabbitRepositoryFactory extends DefaultRepositoryFactory
                implements RepositoryFactory, ArgeoJcrConstants {
        private final static Log log = LogFactory
@@ -33,7 +34,7 @@ public class JackrabbitRepositoryFactory extends DefaultRepositoryFactory
                        uri = parameters.get(JcrUtils.REPOSITORY_URI).toString();
                else
                        return null;
-               
+
                Map<String, String> params = new HashMap<String, String>();
                params.put(JcrUtils.REPOSITORY_URI, uri);
                repository = new Jcr2davRepositoryFactory().getRepository(params);
index 6647eb94bf77f958a9f5aa27884976aada8afd93..8e8b1d945ce22f2c7a3883d74cfc0f6673150b57 100644 (file)
@@ -1,24 +1,37 @@
 package org.argeo.jackrabbit.remote;
 
 import java.io.Serializable;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 
 import javax.jcr.LoginException;
+import javax.jcr.Node;
 import javax.jcr.Repository;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
+import javax.jcr.Value;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+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.apache.jackrabbit.server.SessionProvider;
 import org.argeo.ArgeoException;
+import org.argeo.jcr.ArgeoNames;
 import org.argeo.jcr.JcrUtils;
 
-/** To be injected, typically of scope="session" */
+/**
+ * To be injected, typically of scope="session". Implements an open session in
+ * view patter: a new JCR session is created for each request
+ */
 public class SimpleSessionProvider implements SessionProvider, Serializable {
        private static final long serialVersionUID = 2270957712453841368L;
 
@@ -34,7 +47,10 @@ public class SimpleSessionProvider implements SessionProvider, Serializable {
                        RepositoryException {
 
                if (openSessionInView) {
-                       return rep.login(workspace);
+                       JackrabbitSession session = (JackrabbitSession) rep
+                                       .login(workspace);
+                       writeRemoteRoles(session);
+                       return session;
                } else {
                        // since sessions is transient it can't be restored from the session
                        if (sessions == null)
@@ -43,7 +59,9 @@ public class SimpleSessionProvider implements SessionProvider, Serializable {
 
                        if (!sessions.containsKey(workspace)) {
                                try {
-                                       Session session = rep.login(null, workspace);
+                                       JackrabbitSession session = (JackrabbitSession) rep.login(
+                                                       null, workspace);
+                                       writeRemoteRoles(session);
                                        if (log.isTraceEnabled())
                                                log.trace("User " + session.getUserID()
                                                                + " logged into " + request.getServletPath());
@@ -64,11 +82,60 @@ public class SimpleSessionProvider implements SessionProvider, Serializable {
                }
        }
 
+       protected void writeRemoteRoles(JackrabbitSession session)
+                       throws RepositoryException {
+               // retrieve roles
+               String userId = session.getUserID();
+               UserManager userManager = session.getUserManager();
+               User user = (User) userManager.getAuthorizable(userId);
+               if (user == null) {
+                       // anonymous
+                       return;
+               }
+               List<String> userGroupIds = new ArrayList<String>();
+               if (user != null)
+                       for (Iterator<Group> it = user.memberOf(); it.hasNext();)
+                               userGroupIds.add(it.next().getID());
+
+               // write roles if needed
+               Node userProfile = JcrUtils.getUserProfile(session);
+               boolean writeRoles = false;
+               if (userProfile.hasProperty(ArgeoNames.ARGEO_REMOTE_ROLES)) {
+                       Value[] roles = userProfile.getProperty(
+                                       ArgeoNames.ARGEO_REMOTE_ROLES).getValues();
+                       if (roles.length != userGroupIds.size())
+                               writeRoles = true;
+                       else
+                               for (int i = 0; i < roles.length; i++)
+                                       if (!roles[i].getString().equals(userGroupIds.get(i)))
+                                               writeRoles = true;
+               } else
+                       writeRoles = true;
+
+               if (writeRoles) {
+                       session.getWorkspace().getVersionManager()
+                                       .checkout(userProfile.getPath());
+                       String[] roleIds = userGroupIds.toArray(new String[userGroupIds
+                                       .size()]);
+                       userProfile.setProperty(ArgeoNames.ARGEO_REMOTE_ROLES, roleIds);
+                       JcrUtils.updateLastModified(userProfile);
+                       session.save();
+                       session.getWorkspace().getVersionManager()
+                                       .checkin(userProfile.getPath());
+               }
+
+       }
+
        public void releaseSession(Session session) {
                if (log.isTraceEnabled())
                        log.trace("Releasing JCR session " + session);
-               if (openSessionInView)
-                       JcrUtils.logoutQuietly(session);
+               if (openSessionInView) {
+                       if (session.isLive()) {
+                               session.logout();
+                               if (log.isTraceEnabled())
+                                       log.trace("Logged out remote JCR session " + session);
+                       }
+               }
        }
 
        public void init() {
@@ -81,7 +148,7 @@ public class SimpleSessionProvider implements SessionProvider, Serializable {
                                if (session.isLive()) {
                                        session.logout();
                                        if (log.isDebugEnabled())
-                                               log.debug("Logged out JCR session " + session);
+                                               log.debug("Logged out remote JCR session " + session);
                                }
                        }
        }
index 2dc0c2eb4f23c540a7ca56bdb51103ce8fe3b454..7f060ef6845bf177a26c26f5f2898078cc75519b 100644 (file)
@@ -12,6 +12,7 @@ public interface ArgeoNames {
 
        public final static String ARGEO_REMOTE = "argeo:remote";
        public final static String ARGEO_PASSWORD = "argeo:password";
+       public final static String ARGEO_REMOTE_ROLES = "argeo:remoteRoles";
 
        // user profile
        public final static String ARGEO_PROFILE = "argeo:profile";
index 5efc240498f198283b03848934a26adfd297f27b..facd475cafd1e789c1689e7f88e317ff1ec1d749 100644 (file)
@@ -632,16 +632,18 @@ public class JcrUtils implements ArgeoJcrConstants {
                                                        relPath, p.getValue(), null);
                                        diffs.put(relPath, pDiff);
                                } else {
-                                       if (p.isMultiple())
-                                               continue props;
-                                       Value referenceValue = p.getValue();
-                                       Value newValue = observed.getProperty(name).getValue();
-                                       if (!referenceValue.equals(newValue)) {
-                                               String relPath = propertyRelPath(baseRelPath, name);
-                                               PropertyDiff pDiff = new PropertyDiff(
-                                                               PropertyDiff.MODIFIED, relPath, referenceValue,
-                                                               newValue);
-                                               diffs.put(relPath, pDiff);
+                                       if (p.isMultiple()) {
+                                               // FIXME implement multiple
+                                       } else {
+                                               Value referenceValue = p.getValue();
+                                               Value newValue = observed.getProperty(name).getValue();
+                                               if (!referenceValue.equals(newValue)) {
+                                                       String relPath = propertyRelPath(baseRelPath, name);
+                                                       PropertyDiff pDiff = new PropertyDiff(
+                                                                       PropertyDiff.MODIFIED, relPath,
+                                                                       referenceValue, newValue);
+                                                       diffs.put(relPath, pDiff);
+                                               }
                                        }
                                }
                        }
@@ -653,10 +655,14 @@ public class JcrUtils implements ArgeoJcrConstants {
                                if (name.startsWith("jcr:"))
                                        continue props;
                                if (!reference.hasProperty(name)) {
-                                       String relPath = propertyRelPath(baseRelPath, name);
-                                       PropertyDiff pDiff = new PropertyDiff(PropertyDiff.ADDED,
-                                                       relPath, null, p.getValue());
-                                       diffs.put(relPath, pDiff);
+                                       if (p.isMultiple()) {
+                                               // FIXME implement multiple
+                                       } else {
+                                               String relPath = propertyRelPath(baseRelPath, name);
+                                               PropertyDiff pDiff = new PropertyDiff(
+                                                               PropertyDiff.ADDED, relPath, null, p.getValue());
+                                               diffs.put(relPath, pDiff);
+                                       }
                                }
                        }
                } catch (RepositoryException e) {
@@ -994,8 +1000,8 @@ public class JcrUtils implements ArgeoJcrConstants {
                        Constraint constraint = qomf.comparison(userIdDop,
                                        QueryObjectModelFactory.JCR_OPERATOR_EQUAL_TO, userIdSop);
                        Query query = qomf.createQuery(sel, constraint, null, null);
-                       Node userHome = JcrUtils.querySingleNode(query);
-                       return userHome;
+                       Node userProfile = JcrUtils.querySingleNode(query);
+                       return userProfile;
                } catch (RepositoryException e) {
                        throw new ArgeoException(
                                        "Cannot find profile for user " + username, e);
@@ -1036,8 +1042,12 @@ public class JcrUtils implements ArgeoJcrConstants {
                        } else {
                                userProfile = userHome.addNode(ArgeoNames.ARGEO_PROFILE);
                                userProfile.addMixin(ArgeoTypes.ARGEO_USER_PROFILE);
+                               // session.getWorkspace().getVersionManager()
+                               // .checkout(userProfile.getPath());
                                userProfile.setProperty(ArgeoNames.ARGEO_USER_ID, username);
                                session.save();
+                               session.getWorkspace().getVersionManager()
+                                               .checkin(userProfile.getPath());
                                // we need to save the profile before adding the user home type
                        }
                        userHome.addMixin(ArgeoTypes.ARGEO_USER_HOME);
index 4038dccc2cd147179bbdb56f12e7adf680bd1bb5..dbf9a927fbdca5750049c9df7db971beb5ba652d 100644 (file)
@@ -21,6 +21,7 @@ mixin
 [argeo:userProfile] > mix:created, mix:lastModified, mix:title, mix:versionable
 mixin
 - argeo:userID (STRING) m
+- argeo:remoteRoles (STRING) *
 
 [argeo:preferenceNode] > mix:lastModified, mix:versionable
 mixin