From 8b8ee149b20e2578a55e17413fa5f7399ff7ba14 Mon Sep 17 00:00:00 2001 From: Mathieu Baudier Date: Sat, 29 Oct 2011 15:40:33 +0000 Subject: [PATCH] First working remote node git-svn-id: https://svn.argeo.org/commons/trunk@4866 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- demo/.project | 11 ++ demo/argeo_node_rcp.properties | 2 +- demo/argeo_node_rcp_remote.properties | 14 +++ .../META-INF/spring/jcrsecuritydao-osgi.xml | 11 -- .../META-INF/spring/jcrsecuritydao.xml | 3 - .../META-INF/spring/services.xml | 1 - .../org.argeo.security.dao.os/.project | 22 ++++ .../META-INF/MANIFEST.MF | 17 +++ .../META-INF/spring/security-os-osgi.xml | 31 ++++++ .../META-INF/spring/security-os.xml | 41 +++++++ .../build.properties | 1 + .../modules/org.argeo.security.dao.os/pom.xml | 12 +++ .../security.properties | 2 + security/modules/pom.xml | 1 + .../META-INF/spring/loginModules.xml | 6 ++ .../org.argeo.security.equinox/plugin.xml | 4 + .../security/equinox/SpringLoginModule.java | 26 ++++- .../ui/admin/editors/DefaultUserMainPage.java | 24 ++--- .../security/ui/admin/views/UsersView.java | 13 +-- .../org.argeo.security.ui.rap/plugin.xml | 22 ++++ .../ui/rap/SecureWorkbenchAdvisor.java | 1 - .../META-INF/jaas_default.txt | 5 + .../org.argeo.security.ui.rcp/plugin.xml | 9 ++ .../ui/rcp/AbstractSecureApplication.java | 29 +++-- .../ui/rcp/SecureApplicationActivator.java | 1 + .../ui/rcp/SecureWorkbenchAdvisor.java | 18 +++- .../ui/rcp/SecureWorkbenchWindowAdvisor.java | 8 +- .../plugins/org.argeo.security.ui/plugin.xml | 21 ---- .../jcr/JcrAuthenticationProvider.java | 48 ++++++--- .../jcr/OsJcrAuthenticationProvider.java | 3 +- .../jackrabbit/ArgeoSecurityManager.java | 43 +++++++- .../JackrabbitAuthenticationProvider.java | 29 +++++ .../ldap/jcr/JcrUserDetailsContextMapper.java | 24 ++++- .../META-INF/spring/noderepo.xml | 6 ++ .../org.argeo.node.repo.jackrabbit/pom.xml | 1 + .../ui/explorer/views/GenericJcrBrowser.java | 16 ++- .../org.argeo.server.jackrabbit/pom.xml | 5 + .../argeo/jackrabbit/JackrabbitContainer.java | 101 +++++++++++++----- .../JackrabbitRepositoryFactory.java | 3 +- .../remote/SimpleSessionProvider.java | 79 ++++++++++++-- .../main/java/org/argeo/jcr/ArgeoNames.java | 1 + .../src/main/java/org/argeo/jcr/JcrUtils.java | 42 +++++--- .../main/resources/org/argeo/jcr/argeo.cnd | 1 + 43 files changed, 603 insertions(+), 155 deletions(-) create mode 100644 demo/.project create mode 100644 demo/argeo_node_rcp_remote.properties create mode 100644 security/modules/org.argeo.security.dao.os/.project create mode 100644 security/modules/org.argeo.security.dao.os/META-INF/MANIFEST.MF create mode 100644 security/modules/org.argeo.security.dao.os/META-INF/spring/security-os-osgi.xml create mode 100644 security/modules/org.argeo.security.dao.os/META-INF/spring/security-os.xml create mode 100644 security/modules/org.argeo.security.dao.os/build.properties create mode 100644 security/modules/org.argeo.security.dao.os/pom.xml create mode 100644 security/modules/org.argeo.security.dao.os/security.properties diff --git a/demo/.project b/demo/.project new file mode 100644 index 000000000..d22f4c565 --- /dev/null +++ b/demo/.project @@ -0,0 +1,11 @@ + + + org.argeo.commons.demo + + + + + + + + diff --git a/demo/argeo_node_rcp.properties b/demo/argeo_node_rcp.properties index e19c8d162..cd705db2d 100644 --- a/demo/argeo_node_rcp.properties +++ b/demo/argeo_node_rcp.properties @@ -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 index 000000000..bd2344c26 --- /dev/null +++ b/demo/argeo_node_rcp_remote.properties @@ -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 diff --git a/security/modules/org.argeo.security.dao.jackrabbit/META-INF/spring/jcrsecuritydao-osgi.xml b/security/modules/org.argeo.security.dao.jackrabbit/META-INF/spring/jcrsecuritydao-osgi.xml index e893e9bfd..5ab914764 100644 --- a/security/modules/org.argeo.security.dao.jackrabbit/META-INF/spring/jcrsecuritydao-osgi.xml +++ b/security/modules/org.argeo.security.dao.jackrabbit/META-INF/spring/jcrsecuritydao-osgi.xml @@ -15,17 +15,6 @@ - - - - - - - diff --git a/security/modules/org.argeo.security.dao.jackrabbit/META-INF/spring/jcrsecuritydao.xml b/security/modules/org.argeo.security.dao.jackrabbit/META-INF/spring/jcrsecuritydao.xml index bbe3a165e..c09a53bf2 100644 --- a/security/modules/org.argeo.security.dao.jackrabbit/META-INF/spring/jcrsecuritydao.xml +++ b/security/modules/org.argeo.security.dao.jackrabbit/META-INF/spring/jcrsecuritydao.xml @@ -5,7 +5,4 @@ - - - \ No newline at end of file diff --git a/security/modules/org.argeo.security.dao.jackrabbit/META-INF/spring/services.xml b/security/modules/org.argeo.security.dao.jackrabbit/META-INF/spring/services.xml index c2348433c..00bb4538e 100644 --- a/security/modules/org.argeo.security.dao.jackrabbit/META-INF/spring/services.xml +++ b/security/modules/org.argeo.security.dao.jackrabbit/META-INF/spring/services.xml @@ -31,7 +31,6 @@ - diff --git a/security/modules/org.argeo.security.dao.os/.project b/security/modules/org.argeo.security.dao.os/.project new file mode 100644 index 000000000..cefcc33f3 --- /dev/null +++ b/security/modules/org.argeo.security.dao.os/.project @@ -0,0 +1,22 @@ + + + org.argeo.security.dao.os + + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + + 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 index 000000000..1a72f4088 --- /dev/null +++ b/security/modules/org.argeo.security.dao.os/META-INF/MANIFEST.MF @@ -0,0 +1,17 @@ +Manifest-Version: 1.0 +Private-Package: . +Tool: Bnd-1.15.0 +Bundle-Name: Commons Security DAO OS +Created-By: 1.6.0_20 (Sun Microsystems Inc.) +Bundle-RequiredExecutionEnvironment: J2SE-1.5 +Bundle-Vendor: Argeo +Bundle-Version: 0.3.4.SNAPSHOT-r20111029_170433 +Bundle-ManifestVersion: 2 +Bundle-License: http://www.apache.org/licenses/LICENSE-2.0.txt +Import-Package: javax.jcr,org.argeo.security,org.argeo.security.core,o + rg.argeo.security.jcr,org.springframework.beans.factory.config,org.sp + ringframework.security,org.springframework.security.adapters,org.spri + ngframework.security.providers +Bundle-SymbolicName: org.argeo.security.dao.os +Bundle-DocURL: http://www.argeo.org + 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 index 000000000..ba6f0bf87 --- /dev/null +++ b/security/modules/org.argeo.security.dao.os/META-INF/spring/security-os-osgi.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + \ 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 index 000000000..180f1fe8d --- /dev/null +++ b/security/modules/org.argeo.security.dao.os/META-INF/spring/security-os.xml @@ -0,0 +1,41 @@ + + + + + + + osgibundle:security.properties + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 index 000000000..5f22cdd44 --- /dev/null +++ b/security/modules/org.argeo.security.dao.os/build.properties @@ -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 index 000000000..e19515a1f --- /dev/null +++ b/security/modules/org.argeo.security.dao.os/pom.xml @@ -0,0 +1,12 @@ + + 4.0.0 + + org.argeo.commons.security + 0.3.4-SNAPSHOT + modules + .. + + org.argeo.security.dao.os + Commons Security DAO OS + \ 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 index 000000000..beebcb5dc --- /dev/null +++ b/security/modules/org.argeo.security.dao.os/security.properties @@ -0,0 +1,2 @@ +argeo.security.systemKey=argeo +argeo.node.repo.alias=node diff --git a/security/modules/pom.xml b/security/modules/pom.xml index 859503785..8d10e4d92 100644 --- a/security/modules/pom.xml +++ b/security/modules/pom.xml @@ -12,6 +12,7 @@ pom Commons Security Modules + org.argeo.security.dao.os org.argeo.security.dao.jackrabbit org.argeo.security.dao.ldap org.argeo.security.services diff --git a/security/plugins/org.argeo.security.equinox/META-INF/spring/loginModules.xml b/security/plugins/org.argeo.security.equinox/META-INF/spring/loginModules.xml index 5714e0e19..fe7bb602d 100644 --- a/security/plugins/org.argeo.security.equinox/META-INF/spring/loginModules.xml +++ b/security/plugins/org.argeo.security.equinox/META-INF/spring/loginModules.xml @@ -9,6 +9,12 @@ + + + + + diff --git a/security/plugins/org.argeo.security.equinox/plugin.xml b/security/plugins/org.argeo.security.equinox/plugin.xml index 0bacbda67..4032022dc 100644 --- a/security/plugins/org.argeo.security.equinox/plugin.xml +++ b/security/plugins/org.argeo.security.equinox/plugin.xml @@ -6,6 +6,10 @@ + + + + diff --git a/security/plugins/org.argeo.security.equinox/src/main/java/org/argeo/security/equinox/SpringLoginModule.java b/security/plugins/org.argeo.security.equinox/src/main/java/org/argeo/security/equinox/SpringLoginModule.java index 03f5f35ed..dada34405 100644 --- a/security/plugins/org.argeo.security.equinox/src/main/java/org/argeo/security/equinox/SpringLoginModule.java +++ b/security/plugins/org.argeo.security.equinox/src/main/java/org/argeo/security/equinox/SpringLoginModule.java @@ -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; + } } diff --git a/security/plugins/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/editors/DefaultUserMainPage.java b/security/plugins/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/editors/DefaultUserMainPage.java index 22927bd11..5a20377ca 100644 --- a/security/plugins/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/editors/DefaultUserMainPage.java +++ b/security/plugins/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/editors/DefaultUserMainPage.java @@ -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(); diff --git a/security/plugins/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/views/UsersView.java b/security/plugins/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/views/UsersView.java index 4242436d4..a41f20af5 100644 --- a/security/plugins/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/views/UsersView.java +++ b/security/plugins/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/views/UsersView.java @@ -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); } diff --git a/security/plugins/org.argeo.security.ui.rap/plugin.xml b/security/plugins/org.argeo.security.ui.rap/plugin.xml index 9b284c251..d9afe3e2b 100644 --- a/security/plugins/org.argeo.security.ui.rap/plugin.xml +++ b/security/plugins/org.argeo.security.ui.rap/plugin.xml @@ -22,4 +22,26 @@ + + + + + + + + + + + + + diff --git a/security/plugins/org.argeo.security.ui.rap/src/main/java/org/argeo/security/ui/rap/SecureWorkbenchAdvisor.java b/security/plugins/org.argeo.security.ui.rap/src/main/java/org/argeo/security/ui/rap/SecureWorkbenchAdvisor.java index 06a83306d..c2d740099 100644 --- a/security/plugins/org.argeo.security.ui.rap/src/main/java/org/argeo/security/ui/rap/SecureWorkbenchAdvisor.java +++ b/security/plugins/org.argeo.security.ui.rap/src/main/java/org/argeo/security/ui/rap/SecureWorkbenchAdvisor.java @@ -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); diff --git a/security/plugins/org.argeo.security.ui.rcp/META-INF/jaas_default.txt b/security/plugins/org.argeo.security.ui.rcp/META-INF/jaas_default.txt index bbabac66a..124d7ad9f 100644 --- a/security/plugins/org.argeo.security.ui.rcp/META-INF/jaas_default.txt +++ b/security/plugins/org.argeo.security.ui.rcp/META-INF/jaas_default.txt @@ -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; }; diff --git a/security/plugins/org.argeo.security.ui.rcp/plugin.xml b/security/plugins/org.argeo.security.ui.rcp/plugin.xml index 39b8c848c..53eaa525d 100644 --- a/security/plugins/org.argeo.security.ui.rcp/plugin.xml +++ b/security/plugins/org.argeo.security.ui.rcp/plugin.xml @@ -31,4 +31,13 @@ + + + + + + diff --git a/security/plugins/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/AbstractSecureApplication.java b/security/plugins/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/AbstractSecureApplication.java index 7487567a8..f898d9df3 100644 --- a/security/plugins/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/AbstractSecureApplication.java +++ b/security/plugins/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/AbstractSecureApplication.java @@ -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(); diff --git a/security/plugins/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/SecureApplicationActivator.java b/security/plugins/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/SecureApplicationActivator.java index 1c8bd7c25..6ab4edeed 100644 --- a/security/plugins/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/SecureApplicationActivator.java +++ b/security/plugins/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/SecureApplicationActivator.java @@ -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"; diff --git a/security/plugins/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/SecureWorkbenchAdvisor.java b/security/plugins/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/SecureWorkbenchAdvisor.java index bca01e714..b01dd05ba 100644 --- a/security/plugins/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/SecureWorkbenchAdvisor.java +++ b/security/plugins/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/SecureWorkbenchAdvisor.java @@ -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; } + } diff --git a/security/plugins/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/SecureWorkbenchWindowAdvisor.java b/security/plugins/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/SecureWorkbenchWindowAdvisor.java index d85c17c1a..41e50e78a 100644 --- a/security/plugins/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/SecureWorkbenchWindowAdvisor.java +++ b/security/plugins/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/SecureWorkbenchWindowAdvisor.java @@ -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$ } } diff --git a/security/plugins/org.argeo.security.ui/plugin.xml b/security/plugins/org.argeo.security.ui/plugin.xml index 59ccd3bee..914661532 100644 --- a/security/plugins/org.argeo.security.ui/plugin.xml +++ b/security/plugins/org.argeo.security.ui/plugin.xml @@ -10,27 +10,6 @@ class="org.argeo.security.ui.dialogs.DefaultLoginDialog"> - - - - - - - - - - - - parameters = new HashMap(); - 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 authorities = new ArrayList(); + 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 parameters = new HashMap(); + 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. diff --git a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/jcr/OsJcrAuthenticationProvider.java b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/jcr/OsJcrAuthenticationProvider.java index 2eadf5669..9abac5972 100644 --- a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/jcr/OsJcrAuthenticationProvider.java +++ b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/jcr/OsJcrAuthenticationProvider.java @@ -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); 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 index a38f42541..8f2632d0f 100644 --- 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 @@ -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 userGroupIds = new ArrayList(); @@ -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 } 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 index d9f9f379a..ea84a073e 100644 --- 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 @@ -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 diff --git a/security/runtime/org.argeo.security.ldap/src/main/java/org/argeo/security/ldap/jcr/JcrUserDetailsContextMapper.java b/security/runtime/org.argeo.security.ldap/src/main/java/org/argeo/security/ldap/jcr/JcrUserDetailsContextMapper.java index fe212ccf8..b6657f0c5 100644 --- a/security/runtime/org.argeo.security.ldap/src/main/java/org/argeo/security/ldap/jcr/JcrUserDetailsContextMapper.java +++ b/security/runtime/org.argeo.security.ldap/src/main/java/org/argeo/security/ldap/jcr/JcrUserDetailsContextMapper.java @@ -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); diff --git a/server/modules/org.argeo.node.repo.jackrabbit/META-INF/spring/noderepo.xml b/server/modules/org.argeo.node.repo.jackrabbit/META-INF/spring/noderepo.xml index 02d697b24..8e477fe71 100644 --- a/server/modules/org.argeo.node.repo.jackrabbit/META-INF/spring/noderepo.xml +++ b/server/modules/org.argeo.node.repo.jackrabbit/META-INF/spring/noderepo.xml @@ -27,6 +27,12 @@ classpath:/org/argeo/jcr/argeo.cnd + + + + + + diff --git a/server/modules/org.argeo.node.repo.jackrabbit/pom.xml b/server/modules/org.argeo.node.repo.jackrabbit/pom.xml index 12ea019c0..32840cd19 100644 --- a/server/modules/org.argeo.node.repo.jackrabbit/pom.xml +++ b/server/modules/org.argeo.node.repo.jackrabbit/pom.xml @@ -17,6 +17,7 @@ maven-bundle-plugin + ${project.artifactId};singleton:=true *, com.mysql.jdbc;version="[5.0.0,6.0.0)";resolution:=optional, diff --git a/server/plugins/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/views/GenericJcrBrowser.java b/server/plugins/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/views/GenericJcrBrowser.java index 3af60844c..292fc816e 100644 --- a/server/plugins/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/views/GenericJcrBrowser.java +++ b/server/plugins/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/views/GenericJcrBrowser.java @@ -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 ""; - 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( diff --git a/server/runtime/org.argeo.server.jackrabbit/pom.xml b/server/runtime/org.argeo.server.jackrabbit/pom.xml index 1b2fe2316..dc02e48d9 100644 --- a/server/runtime/org.argeo.server.jackrabbit/pom.xml +++ b/server/runtime/org.argeo.server.jackrabbit/pom.xml @@ -56,6 +56,11 @@ org.argeo.server.core 0.3.4-SNAPSHOT + + org.argeo.commons.security + org.argeo.security.core + 0.3.4-SNAPSHOT + org.argeo.commons.server org.argeo.server.jcr.mvc diff --git a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/JackrabbitContainer.java b/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/JackrabbitContainer.java index a708aadd1..c2e0034ff 100644 --- a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/JackrabbitContainer.java +++ b/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/JackrabbitContainer.java @@ -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; } diff --git a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/JackrabbitRepositoryFactory.java b/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/JackrabbitRepositoryFactory.java index bcf02a3c1..6fe5bf340 100644 --- a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/JackrabbitRepositoryFactory.java +++ b/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/JackrabbitRepositoryFactory.java @@ -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 params = new HashMap(); params.put(JcrUtils.REPOSITORY_URI, uri); repository = new Jcr2davRepositoryFactory().getRepository(params); diff --git a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/SimpleSessionProvider.java b/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/SimpleSessionProvider.java index 6647eb94b..8e8b1d945 100644 --- a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/SimpleSessionProvider.java +++ b/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/SimpleSessionProvider.java @@ -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 userGroupIds = new ArrayList(); + if (user != null) + for (Iterator 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); } } } diff --git a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/ArgeoNames.java b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/ArgeoNames.java index 2dc0c2eb4..7f060ef68 100644 --- a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/ArgeoNames.java +++ b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/ArgeoNames.java @@ -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"; diff --git a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/JcrUtils.java b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/JcrUtils.java index 5efc24049..facd475ca 100644 --- a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/JcrUtils.java +++ b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/JcrUtils.java @@ -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); diff --git a/server/runtime/org.argeo.server.jcr/src/main/resources/org/argeo/jcr/argeo.cnd b/server/runtime/org.argeo.server.jcr/src/main/resources/org/argeo/jcr/argeo.cnd index 4038dccc2..dbf9a927f 100644 --- a/server/runtime/org.argeo.server.jcr/src/main/resources/org/argeo/jcr/argeo.cnd +++ b/server/runtime/org.argeo.server.jcr/src/main/resources/org/argeo/jcr/argeo.cnd @@ -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 -- 2.39.2