From 2f510fb09e18bc3d3e902c8131d0037763c5f279 Mon Sep 17 00:00:00 2001 From: Mathieu Baudier Date: Mon, 21 Mar 2011 22:29:36 +0000 Subject: [PATCH] Improve RAP security git-svn-id: https://svn.argeo.org/commons/trunk@4334 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- demo/log4j.properties | 2 +- .../META-INF/spring/ldap-jcr.xml | 9 +- .../META-INF/spring/ldap-osgi.xml | 19 +- .../security/equinox/SpringLoginModule.java | 7 + .../META-INF/spring/editors.xml | 1 + .../META-INF/spring/osgi.xml | 5 + .../META-INF/spring/views.xml | 3 +- .../org.argeo.security.ui.admin/plugin.xml | 9 +- .../security/ui/admin/commands/AddRole.java | 15 + .../ui/admin/editors/ArgeoUserEditor.java | 72 +++- .../admin/editors/ArgeoUserEditorInput.java | 25 ++ .../ui/admin/editors/DefaultUserMainPage.java | 336 ++++++------------ .../ui/admin/editors/UserRolesPage.java | 210 +++++++++++ .../security/ui/admin/views/UsersView.java | 134 +++++-- .../security/ui/rap/SecureEntryPoint.java | 46 ++- .../plugins/org.argeo.security.ui/plugin.xml | 2 +- .../security/ui/internal/CurrentUser.java | 3 +- .../org/argeo/security/UserAdminService.java | 3 + .../argeo/security/core/ArgeoUserDetails.java | 1 + .../core/DefaultUserAdminService.java | 5 + .../core/KeyBasedSystemExecutionService.java | 9 + .../argeo/security/jcr/JcrUserDetails.java | 17 + .../security/jackrabbit/ArgeoLoginModule.java | 4 +- .../jackrabbit/ArgeoSecurityManager.java | 8 +- .../ldap/jcr/JcrUserDetailsContextMapper.java | 138 ++++--- .../argeo/jackrabbit/JackrabbitContainer.java | 3 +- .../main/java/org/argeo/jcr/ArgeoNames.java | 2 +- .../jcr/ThreadBoundJcrSessionFactory.java | 9 + 28 files changed, 759 insertions(+), 338 deletions(-) create mode 100644 security/plugins/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/editors/UserRolesPage.java diff --git a/demo/log4j.properties b/demo/log4j.properties index 1e5895edf..cd83759a4 100644 --- a/demo/log4j.properties +++ b/demo/log4j.properties @@ -4,7 +4,7 @@ log4j.rootLogger=WARN, console log4j.logger.org.argeo=DEBUG log4j.logger.org.argeo.jackrabbit.remote.ExtendedDispatcherServlet=WARN -log4j.logger.org.springframework.security=WARN +log4j.logger.org.springframework.security=DEBUG log4j.logger.org.apache.catalina=INFO log4j.logger.org.apache.coyote=INFO diff --git a/security/modules/org.argeo.security.dao.ldap/META-INF/spring/ldap-jcr.xml b/security/modules/org.argeo.security.dao.ldap/META-INF/spring/ldap-jcr.xml index 794ac0195..b1dc9a9e1 100644 --- a/security/modules/org.argeo.security.dao.ldap/META-INF/spring/ldap-jcr.xml +++ b/security/modules/org.argeo.security.dao.ldap/META-INF/spring/ldap-jcr.xml @@ -18,11 +18,18 @@ + + - + + + + + + diff --git a/security/modules/org.argeo.security.dao.ldap/META-INF/spring/ldap-osgi.xml b/security/modules/org.argeo.security.dao.ldap/META-INF/spring/ldap-osgi.xml index 67ad89817..8deaeacde 100644 --- a/security/modules/org.argeo.security.dao.ldap/META-INF/spring/ldap-osgi.xml +++ b/security/modules/org.argeo.security.dao.ldap/META-INF/spring/ldap-osgi.xml @@ -7,13 +7,15 @@ http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> - - - - + + + + + + + + @@ -28,4 +30,7 @@ + \ No newline at end of file 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 c357a9ea7..90e8b3dec 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 @@ -1,6 +1,7 @@ package org.argeo.security.equinox; import java.util.Map; +import java.util.concurrent.Executor; import javax.security.auth.Subject; import javax.security.auth.callback.Callback; @@ -20,6 +21,7 @@ import org.springframework.security.providers.jaas.SecurityContextLoginModule; /** Login module which caches one subject per thread. */ public class SpringLoginModule extends SecurityContextLoginModule { private AuthenticationManager authenticationManager; + private Executor systemExecutor; private CallbackHandler callbackHandler; @@ -88,6 +90,7 @@ public class SpringLoginModule extends SecurityContextLoginModule { username, password, url, workspace); try { + Authentication authentication = authenticationManager .authenticate(credentials); registerAuthentication(authentication); @@ -127,6 +130,10 @@ public class SpringLoginModule extends SecurityContextLoginModule { this.authenticationManager = authenticationManager; } + public void setSystemExecutor(Executor systemExecutor) { + this.systemExecutor = systemExecutor; + } + // protected Subject getSubject() { // return subject.get(); // } diff --git a/security/plugins/org.argeo.security.ui.admin/META-INF/spring/editors.xml b/security/plugins/org.argeo.security.ui.admin/META-INF/spring/editors.xml index 84399c26e..c1eb9ea61 100644 --- a/security/plugins/org.argeo.security.ui.admin/META-INF/spring/editors.xml +++ b/security/plugins/org.argeo.security.ui.admin/META-INF/spring/editors.xml @@ -8,5 +8,6 @@ + diff --git a/security/plugins/org.argeo.security.ui.admin/META-INF/spring/osgi.xml b/security/plugins/org.argeo.security.ui.admin/META-INF/spring/osgi.xml index f77b5a029..690dd16a9 100644 --- a/security/plugins/org.argeo.security.ui.admin/META-INF/spring/osgi.xml +++ b/security/plugins/org.argeo.security.ui.admin/META-INF/spring/osgi.xml @@ -8,5 +8,10 @@ http://www.springframework.org/schema/beans/spring-beans-2.5.xsd" osgi:default-timeout="30000"> + + + \ No newline at end of file diff --git a/security/plugins/org.argeo.security.ui.admin/META-INF/spring/views.xml b/security/plugins/org.argeo.security.ui.admin/META-INF/spring/views.xml index 8cf9fd68c..cc5fbb57d 100644 --- a/security/plugins/org.argeo.security.ui.admin/META-INF/spring/views.xml +++ b/security/plugins/org.argeo.security.ui.admin/META-INF/spring/views.xml @@ -6,7 +6,8 @@ - + + diff --git a/security/plugins/org.argeo.security.ui.admin/plugin.xml b/security/plugins/org.argeo.security.ui.admin/plugin.xml index d5bc7d18d..f6c164391 100644 --- a/security/plugins/org.argeo.security.ui.admin/plugin.xml +++ b/security/plugins/org.argeo.security.ui.admin/plugin.xml @@ -7,7 +7,7 @@ class="org.argeo.security.ui.admin.SecurityAdminPerspective" icon="icons/security.gif" id="org.argeo.security.ui.admin.adminSecurityPerspective" - name="Security"> + name="Security Administration"> + locationURI="toolbar:org.argeo.security.ui.admin.adminRolesView"> + locationURI="toolbar:org.argeo.security.ui.admin.adminUsersView"> + + pattern="org.argeo.security.ui.admin/org.argeo.security.ui.admin.adminSecurityPerspective"> diff --git a/security/plugins/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/commands/AddRole.java b/security/plugins/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/commands/AddRole.java index 047c167e0..a036d12a3 100644 --- a/security/plugins/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/commands/AddRole.java +++ b/security/plugins/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/commands/AddRole.java @@ -2,11 +2,15 @@ package org.argeo.security.ui.admin.commands; import org.argeo.ArgeoException; import org.argeo.security.UserAdminService; +import org.argeo.security.ui.admin.editors.ArgeoUserEditor; import org.argeo.security.ui.admin.views.RolesView; import org.eclipse.core.commands.AbstractHandler; import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.commands.ExecutionException; +import org.eclipse.ui.IEditorReference; +import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.handlers.HandlerUtil; +import org.eclipse.ui.internal.EditorReference; /** Add a new role. */ public class AddRole extends AbstractHandler { @@ -30,6 +34,17 @@ public class AddRole extends AbstractHandler { throw new ArgeoException("Role " + role + " already exists"); userAdminService.newRole(role); rolesView.refresh(); + + // refresh editors + IEditorReference[] refs = HandlerUtil.getActiveWorkbenchWindow(event) + .getActivePage() + .findEditors(null, ArgeoUserEditor.ID, IWorkbenchPage.MATCH_ID); + for (IEditorReference ref : refs) { + ArgeoUserEditor userEditor = (ArgeoUserEditor) ref.getEditor(false); + if (userEditor != null) { + userEditor.refresh(); + } + } return null; } diff --git a/security/plugins/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/editors/ArgeoUserEditor.java b/security/plugins/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/editors/ArgeoUserEditor.java index 9b82e8783..a0e4dfc82 100644 --- a/security/plugins/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/editors/ArgeoUserEditor.java +++ b/security/plugins/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/editors/ArgeoUserEditor.java @@ -1,44 +1,62 @@ package org.argeo.security.ui.admin.editors; +import javax.jcr.Node; + import org.argeo.ArgeoException; +import org.argeo.jcr.ArgeoNames; import org.argeo.security.ArgeoUser; import org.argeo.security.SimpleArgeoUser; import org.argeo.security.UserAdminService; +import org.argeo.security.jcr.JcrUserDetails; import org.argeo.security.nature.SimpleUserNature; +import org.argeo.security.ui.admin.SecurityAdminPlugin; +import org.argeo.security.ui.admin.views.UsersView; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorSite; +import org.eclipse.ui.IWorkbench; import org.eclipse.ui.PartInitException; import org.eclipse.ui.forms.editor.FormEditor; +import org.springframework.security.userdetails.UserDetailsManager; /** Editor for an Argeo user. */ public class ArgeoUserEditor extends FormEditor { public final static String ID = "org.argeo.security.ui.admin.adminArgeoUserEditor"; private ArgeoUser user; + private JcrUserDetails userDetails; + private Node userHome; private UserAdminService userAdminService; + private UserDetailsManager userDetailsManager; public void init(IEditorSite site, IEditorInput input) throws PartInitException { super.init(site, input); + userHome = ((ArgeoUserEditorInput) getEditorInput()).getUserHome(); String username = ((ArgeoUserEditorInput) getEditorInput()) .getUsername(); + + userDetails = (JcrUserDetails) userDetailsManager + .loadUserByUsername(username); + if (username == null) {// new user = new SimpleArgeoUser(); user.getUserNatures().put(SimpleUserNature.TYPE, new SimpleUserNature()); } else user = userAdminService.getUser(username); + this.setPartProperty("name", username != null ? username : ""); setPartName(username != null ? username : ""); } protected void addPages() { try { - addPage(new DefaultUserMainPage(this, userAdminService, user)); - - } catch (PartInitException e) { - throw new ArgeoException("Not able to add page ", e); + addPage(new DefaultUserMainPage(this, + userHome.getNode(ArgeoNames.ARGEO_USER_PROFILE))); + addPage(new UserRolesPage(this, userDetails, userAdminService)); + } catch (Exception e) { + throw new ArgeoException("Cannot add pages", e); } } @@ -46,15 +64,39 @@ public class ArgeoUserEditor extends FormEditor { public void doSave(IProgressMonitor monitor) { // list pages // TODO: make it more generic - findPage(DefaultUserMainPage.ID).doSave(monitor); + DefaultUserMainPage defaultUserMainPage = (DefaultUserMainPage) findPage(DefaultUserMainPage.ID); + if (defaultUserMainPage.isDirty()) { + defaultUserMainPage.doSave(monitor); + String newPassword = defaultUserMainPage.getNewPassword(); + defaultUserMainPage.resetNewPassword(); + if (newPassword != null) + userDetails = userDetails.cloneWithNewPassword(newPassword); + } - if (userAdminService.userExists(user.getUsername())) - userAdminService.updateUser(user); - else { - userAdminService.newUser(user); - setPartName(user.getUsername()); + UserRolesPage userRolesPage = (UserRolesPage) findPage(UserRolesPage.ID); + if (userRolesPage.isDirty()) { + userRolesPage.doSave(monitor); + userDetails = userDetails.cloneWithNewRoles(userRolesPage + .getRoles()); } + + userDetailsManager.updateUser(userDetails); + + // if (userAdminService.userExists(user.getUsername())) + // userAdminService.updateUser(user); + // else { + // userAdminService.newUser(user); + // setPartName(user.getUsername()); + // } firePropertyChange(PROP_DIRTY); + + userRolesPage.setUserDetails(userDetails); + + // refresh users view + IWorkbench iw = SecurityAdminPlugin.getDefault().getWorkbench(); + UsersView usersView = (UsersView) iw.getActiveWorkbenchWindow() + .getActivePage().findView(UsersView.ID); + usersView.refresh(); } @Override @@ -66,7 +108,17 @@ public class ArgeoUserEditor extends FormEditor { return false; } + public void refresh() { + UserRolesPage userRolesPage = (UserRolesPage) findPage(UserRolesPage.ID); + userRolesPage.refresh(); + } + public void setUserAdminService(UserAdminService userAdminService) { this.userAdminService = userAdminService; } + + public void setUserDetailsManager(UserDetailsManager userDetailsManager) { + this.userDetailsManager = userDetailsManager; + } + } diff --git a/security/plugins/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/editors/ArgeoUserEditorInput.java b/security/plugins/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/editors/ArgeoUserEditorInput.java index 8812ee36a..51aeeef80 100644 --- a/security/plugins/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/editors/ArgeoUserEditorInput.java +++ b/security/plugins/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/editors/ArgeoUserEditorInput.java @@ -1,5 +1,12 @@ package org.argeo.security.ui.admin.editors; +import javax.jcr.Node; +import javax.jcr.PathNotFoundException; +import javax.jcr.RepositoryException; +import javax.jcr.ValueFormatException; + +import org.argeo.ArgeoException; +import org.argeo.jcr.ArgeoNames; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IPersistableElement; @@ -7,9 +14,23 @@ import org.eclipse.ui.IPersistableElement; /** Editor input for an Argeo user. */ public class ArgeoUserEditorInput implements IEditorInput { private final String username; + private final Node userHome; + @Deprecated public ArgeoUserEditorInput(String username) { this.username = username; + this.userHome = null; + } + + public ArgeoUserEditorInput(Node userHome) { + try { + this.username = userHome.getProperty(ArgeoNames.ARGEO_USER_ID) + .getString(); + this.userHome = userHome; + } catch (RepositoryException e) { + throw new ArgeoException("Cannot initialize editor input for " + + userHome, e); + } } public Object getAdapter(@SuppressWarnings("rawtypes") Class adapter) { @@ -48,4 +69,8 @@ public class ArgeoUserEditorInput implements IEditorInput { return username; } + public Node getUserHome() { + return userHome; + } + } 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 ee36b5731..cfaf6e4fb 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 @@ -1,131 +1,133 @@ package org.argeo.security.ui.admin.editors; +import java.util.Arrays; + +import javax.jcr.Node; +import javax.jcr.Property; +import javax.jcr.RepositoryException; + import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.argeo.security.ArgeoUser; -import org.argeo.security.SimpleArgeoUser; -import org.argeo.security.UserAdminService; -import org.argeo.security.nature.SimpleUserNature; -import org.argeo.security.ui.admin.SecurityAdminPlugin; -import org.eclipse.jface.viewers.CellEditor; -import org.eclipse.jface.viewers.CheckboxCellEditor; -import org.eclipse.jface.viewers.ColumnLabelProvider; -import org.eclipse.jface.viewers.EditingSupport; -import org.eclipse.jface.viewers.IStructuredContentProvider; -import org.eclipse.jface.viewers.TableViewer; -import org.eclipse.jface.viewers.TableViewerColumn; -import org.eclipse.jface.viewers.Viewer; +import org.argeo.ArgeoException; +import org.argeo.jcr.ArgeoNames; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.graphics.Image; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Table; -import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.forms.AbstractFormPart; import org.eclipse.ui.forms.IManagedForm; import org.eclipse.ui.forms.SectionPart; import org.eclipse.ui.forms.editor.FormEditor; import org.eclipse.ui.forms.editor.FormPage; -import org.eclipse.ui.forms.widgets.ColumnLayout; import org.eclipse.ui.forms.widgets.FormToolkit; import org.eclipse.ui.forms.widgets.ScrolledForm; import org.eclipse.ui.forms.widgets.Section; /** - * Display/edit the properties common to all {@link ArgeoUser} (username and - * roles) as well as the properties of the {@link SimpleUserNature}. + * Display/edit the properties common to all Argeo users */ -public class DefaultUserMainPage extends FormPage { +public class DefaultUserMainPage extends FormPage implements ArgeoNames { final static String ID = "argeoUserEditor.mainPage"; private final static Log log = LogFactory.getLog(DefaultUserMainPage.class); - private final static Image ROLE_CHECKED = SecurityAdminPlugin - .getImageDescriptor("icons/security.gif").createImage(); + private Node userProfile; - private ArgeoUser user; - private SimpleUserNature simpleNature; - private String simpleNatureType; - private UserAdminService securityService; + private char[] newPassword; - public DefaultUserMainPage(FormEditor editor, - UserAdminService securityService, ArgeoUser user) { + public DefaultUserMainPage(FormEditor editor, Node userProfile) { super(editor, ID, "Main"); - this.securityService = securityService; - this.user = user; - this.simpleNature = SimpleUserNature.findSimpleUserNature(user, - simpleNatureType); + this.userProfile = userProfile; } protected void createFormContent(final IManagedForm mf) { - ScrolledForm form = mf.getForm(); - form.setText(simpleNature.getFirstName() + " " - + simpleNature.getLastName()); - ColumnLayout mainLayout = new ColumnLayout(); - mainLayout.minNumColumns = 1; - mainLayout.maxNumColumns = 4; - mainLayout.topMargin = 0; - mainLayout.bottomMargin = 5; - mainLayout.leftMargin = mainLayout.rightMargin = mainLayout.horizontalSpacing = mainLayout.verticalSpacing = 10; - form.getBody().setLayout(mainLayout); - - createGeneralPart(form.getBody()); - createRolesPart(form.getBody()); - createPassworPart(form.getBody()); + try { + ScrolledForm form = mf.getForm(); + form.setText(userProfile.getProperty(ARGEO_FIRST_NAME).getString() + + " " + + userProfile.getProperty(ARGEO_LAST_NAME).getString()); + GridLayout mainLayout = new GridLayout(1, true); + // ColumnLayout mainLayout = new ColumnLayout(); + // mainLayout.minNumColumns = 1; + // mainLayout.maxNumColumns = 4; + // mainLayout.topMargin = 0; + // mainLayout.bottomMargin = 5; + // mainLayout.leftMargin = mainLayout.rightMargin = + // mainLayout.horizontalSpacing = mainLayout.verticalSpacing = 10; + form.getBody().setLayout(mainLayout); + + createGeneralPart(form.getBody()); + createPassworPart(form.getBody()); + } catch (RepositoryException e) { + throw new ArgeoException("Cannot create form content", e); + } } /** Creates the general section */ - protected void createGeneralPart(Composite parent) { + protected void createGeneralPart(Composite parent) + throws RepositoryException { FormToolkit tk = getManagedForm().getToolkit(); Section section = tk.createSection(parent, Section.TITLE_BAR); + section.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); section.setText("General"); - Composite body = tk.createComposite(section, SWT.WRAP); section.setClient(body); - GridLayout layout = new GridLayout(); - layout.marginWidth = layout.marginHeight = 0; - layout.numColumns = 2; + GridLayout layout = new GridLayout(2, false); + body.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); body.setLayout(layout); // add widgets (view) - final Text username; - if (user.getUsername() != null) { - tk.createLabel(body, "Username"); - tk.createLabel(body, user.getUsername()); - username = null; - } else { - username = createLT(body, "Username", ""); - } + // final Text username; + // if (user.getUsername() != null) { + // tk.createLabel(body, "Username"); + // tk.createLabel(body, user.getUsername()); + // username = null; + // } else { + // username = createLT(body, "Username", ""); + // } final Text firstName = createLT(body, "First name", - simpleNature.getFirstName()); + userProfile.getProperty(ARGEO_FIRST_NAME)); final Text lastName = createLT(body, "Last name", - simpleNature.getLastName()); - final Text email = createLT(body, "Email", simpleNature.getEmail()); + userProfile.getProperty(ARGEO_LAST_NAME)); + final Text email = createLT(body, "Email", + userProfile.getProperty(ARGEO_PRIMARY_EMAIL)); final Text description = createLT(body, "Description", - simpleNature.getDescription()); + userProfile.getProperty(Property.JCR_DESCRIPTION)); // create form part (controller) AbstractFormPart part = new SectionPart(section) { public void commit(boolean onSave) { - if (username != null) { - ((SimpleArgeoUser) user).setUsername(username.getText()); - username.setEditable(false); - username.setEnabled(false); + // if (username != null) { + // ((SimpleArgeoUser) user).setUsername(username.getText()); + // username.setEditable(false); + // username.setEnabled(false); + // } + // simpleNature.setFirstName(firstName.getText()); + // simpleNature.setLastName(lastName.getText()); + // simpleNature.setEmail(email.getText()); + // simpleNature.setDescription(description.getText()); + try { + userProfile.setProperty(ARGEO_FIRST_NAME, + firstName.getText()); + userProfile + .setProperty(ARGEO_LAST_NAME, lastName.getText()); + userProfile.setProperty(ARGEO_PRIMARY_EMAIL, + email.getText()); + userProfile.setProperty(Property.JCR_DESCRIPTION, + description.getText()); + super.commit(onSave); + if (log.isTraceEnabled()) + log.trace("General part committed"); + } catch (RepositoryException e) { + throw new ArgeoException("Cannot commit", e); } - simpleNature.setFirstName(firstName.getText()); - simpleNature.setLastName(lastName.getText()); - simpleNature.setEmail(email.getText()); - simpleNature.setDescription(description.getText()); - super.commit(onSave); - if (log.isTraceEnabled()) - log.trace("General part committed"); } }; - if (username != null) - username.addModifyListener(new FormPartML(part)); + // if (username != null) + // username.addModifyListener(new FormPartML(part)); firstName.addModifyListener(new FormPartML(part)); lastName.addModifyListener(new FormPartML(part)); email.addModifyListener(new FormPartML(part)); @@ -137,13 +139,13 @@ public class DefaultUserMainPage extends FormPage { protected void createPassworPart(Composite parent) { FormToolkit tk = getManagedForm().getToolkit(); Section section = tk.createSection(parent, Section.TITLE_BAR); + section.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); section.setText("Password"); Composite body = tk.createComposite(section, SWT.WRAP); section.setClient(body); - GridLayout layout = new GridLayout(); - layout.marginWidth = layout.marginHeight = 0; - layout.numColumns = 2; + GridLayout layout = new GridLayout(2, false); + body.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); body.setLayout(layout); // add widgets (view) @@ -151,119 +153,54 @@ public class DefaultUserMainPage extends FormPage { final Text password2 = createLP(body, "Repeat password", ""); // create form part (controller) AbstractFormPart part = new SectionPart(section) { + public void commit(boolean onSave) { if (!password1.getText().equals("") - && password1.getText().equals(password2.getText())) { - ((SimpleArgeoUser) user).setPassword(password1.getText()); + || !password2.getText().equals("")) { + if (password1.getText().equals(password2.getText())) { + newPassword = password1.getText().toCharArray(); + password1.setText(""); + password2.setText(""); + super.commit(onSave); + } else { + password1.setText(""); + password2.setText(""); + throw new ArgeoException("Passwords are not equals"); + } } - super.commit(onSave); - if (log.isTraceEnabled()) - log.trace("Password part committed"); } + }; password1.addModifyListener(new FormPartML(part)); password2.addModifyListener(new FormPartML(part)); getManagedForm().addPart(part); } - /** Creates the role section */ - protected void createRolesPart(Composite parent) { - FormToolkit tk = getManagedForm().getToolkit(); - Section section = tk.createSection(parent, Section.DESCRIPTION - | Section.TITLE_BAR); - section.setText("Roles"); - section.setDescription("Roles define " - + "the authorizations for this user."); - Table table = new Table(section, SWT.MULTI | SWT.H_SCROLL - | SWT.V_SCROLL); - section.setClient(table); - - AbstractFormPart part = new SectionPart(section) { - public void commit(boolean onSave) { - // roles have already been modified in editing - super.commit(onSave); - if (log.isTraceEnabled()) - log.trace("Role part committed"); - } - }; - getManagedForm().addPart(part); - - GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true); - gridData.verticalSpan = 20; - table.setLayoutData(gridData); - table.setLinesVisible(true); - table.setHeaderVisible(false); - TableViewer viewer = new TableViewer(table); - - // check column - TableViewerColumn column = createTableViewerColumn(viewer, "checked", - 20); - column.setLabelProvider(new ColumnLabelProvider() { - public String getText(Object element) { - return null; - } - - public Image getImage(Object element) { - String role = element.toString(); - if (user.getRoles().contains(role)) { - return ROLE_CHECKED; - } else { - return null; - } - } - }); - column.setEditingSupport(new RoleEditingSupport(viewer, part)); - - // role column - column = createTableViewerColumn(viewer, "Role", 200); - column.setLabelProvider(new ColumnLabelProvider() { - public String getText(Object element) { - return element.toString(); - } - - public Image getImage(Object element) { - return null; - } - }); - viewer.setContentProvider(new RolesContentProvider()); - viewer.setInput(getEditorSite()); - } - - protected TableViewerColumn createTableViewerColumn(TableViewer viewer, - String title, int bound) { - final TableViewerColumn viewerColumn = new TableViewerColumn(viewer, - SWT.NONE); - final TableColumn column = viewerColumn.getColumn(); - column.setText(title); - column.setWidth(bound); - column.setResizable(true); - column.setMoveable(true); - return viewerColumn; - - } - /** Creates label and text. */ protected Text createLT(Composite body, String label, String value) { FormToolkit toolkit = getManagedForm().getToolkit(); - toolkit.createLabel(body, label); + Label lbl = toolkit.createLabel(body, label); + lbl.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false)); Text text = toolkit.createText(body, value, SWT.BORDER); - text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); 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(); - toolkit.createLabel(body, label); + Label lbl = toolkit.createLabel(body, label); + lbl.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false)); Text text = toolkit.createText(body, value, SWT.BORDER | SWT.PASSWORD); - text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); return text; } - public void setSimpleNatureType(String simpleNatureType) { - this.simpleNatureType = simpleNatureType; - } - private class FormPartML implements ModifyListener { private AbstractFormPart formPart; @@ -277,61 +214,16 @@ public class DefaultUserMainPage extends FormPage { } - private class RolesContentProvider implements IStructuredContentProvider { - public Object[] getElements(Object inputElement) { - return securityService.listEditableRoles().toArray(); - } - - public void dispose() { - } - - public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { - } + public String getNewPassword() { + if (newPassword != null) + return new String(newPassword); + else + return null; } - /** Select the columns by editing the checkbox in the first column */ - class RoleEditingSupport extends EditingSupport { - - private final TableViewer viewer; - private final AbstractFormPart formPart; - - public RoleEditingSupport(TableViewer viewer, AbstractFormPart formPart) { - super(viewer); - this.viewer = viewer; - this.formPart = formPart; - } - - @Override - protected CellEditor getCellEditor(Object element) { - return new CheckboxCellEditor(null, SWT.CHECK | SWT.READ_ONLY); - - } - - @Override - protected boolean canEdit(Object element) { - return true; - } - - @Override - protected Object getValue(Object element) { - String role = element.toString(); - return user.getRoles().contains(role); - - } - - @Override - protected void setValue(Object element, Object value) { - Boolean inRole = (Boolean) value; - String role = element.toString(); - if (inRole && !user.getRoles().contains(role)) { - user.getRoles().add(role); - formPart.markDirty(); - } else if (!inRole && user.getRoles().contains(role)) { - user.getRoles().remove(role); - formPart.markDirty(); - } - viewer.refresh(); - } + public void resetNewPassword() { + if (newPassword != null) + Arrays.fill(newPassword, 'x'); + newPassword = null; } - } diff --git a/security/plugins/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/editors/UserRolesPage.java b/security/plugins/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/editors/UserRolesPage.java new file mode 100644 index 000000000..c5931068e --- /dev/null +++ b/security/plugins/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/editors/UserRolesPage.java @@ -0,0 +1,210 @@ +package org.argeo.security.ui.admin.editors; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.jcr.ArgeoNames; +import org.argeo.security.UserAdminService; +import org.argeo.security.ui.admin.SecurityAdminPlugin; +import org.eclipse.jface.viewers.CellEditor; +import org.eclipse.jface.viewers.CheckboxCellEditor; +import org.eclipse.jface.viewers.ColumnLabelProvider; +import org.eclipse.jface.viewers.EditingSupport; +import org.eclipse.jface.viewers.IStructuredContentProvider; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.TableViewerColumn; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.ui.forms.AbstractFormPart; +import org.eclipse.ui.forms.IManagedForm; +import org.eclipse.ui.forms.editor.FormEditor; +import org.eclipse.ui.forms.editor.FormPage; +import org.eclipse.ui.forms.widgets.ScrolledForm; +import org.springframework.security.GrantedAuthority; +import org.springframework.security.userdetails.UserDetails; + +/** + * Display/edit the roles of a user. + */ +public class UserRolesPage extends FormPage implements ArgeoNames { + final static String ID = "argeoUserEditor.rolesPage"; + + private final static Log log = LogFactory.getLog(UserRolesPage.class); + private final static Image ROLE_CHECKED = SecurityAdminPlugin + .getImageDescriptor("icons/security.gif").createImage(); + + private TableViewer rolesViewer; + private UserAdminService userAdminService; + private List roles; + + public UserRolesPage(FormEditor editor, UserDetails userDetails, + UserAdminService userAdminService) { + super(editor, ID, "Roles"); + setUserDetails(userDetails); + this.userAdminService = userAdminService; + } + + public void setUserDetails(UserDetails userDetails) { + this.roles = new ArrayList(); + for (GrantedAuthority ga : userDetails.getAuthorities()) + roles.add(ga.getAuthority()); + if (rolesViewer != null) + rolesViewer.refresh(); + } + + protected void createFormContent(final IManagedForm mf) { + ScrolledForm form = mf.getForm(); + form.setText("Roles"); + FillLayout mainLayout = new FillLayout(); + // ColumnLayout mainLayout = new ColumnLayout(); + // mainLayout.minNumColumns = 1; + // mainLayout.maxNumColumns = 4; + // mainLayout.topMargin = 0; + // mainLayout.bottomMargin = 5; + // mainLayout.leftMargin = mainLayout.rightMargin = + // mainLayout.horizontalSpacing = mainLayout.verticalSpacing = 10; + form.getBody().setLayout(mainLayout); + createRolesPart(form.getBody()); + } + + /** Creates the role section */ + protected void createRolesPart(Composite parent) { + Table table = new Table(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL); + + AbstractFormPart part = new AbstractFormPart() { + public void commit(boolean onSave) { + // roles have already been modified in editing + super.commit(onSave); + if (log.isTraceEnabled()) + log.trace("Role part committed"); + } + }; + getManagedForm().addPart(part); + + // GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true); + // gridData.verticalSpan = 20; + // table.setLayoutData(gridData); + table.setLinesVisible(true); + table.setHeaderVisible(false); + rolesViewer = new TableViewer(table); + + // check column + TableViewerColumn column = createTableViewerColumn(rolesViewer, + "checked", 20); + column.setLabelProvider(new ColumnLabelProvider() { + public String getText(Object element) { + return null; + } + + public Image getImage(Object element) { + String role = element.toString(); + if (roles.contains(role)) { + return ROLE_CHECKED; + } else { + return null; + } + } + }); + column.setEditingSupport(new RoleEditingSupport(rolesViewer, part)); + + // role column + column = createTableViewerColumn(rolesViewer, "Role", 200); + column.setLabelProvider(new ColumnLabelProvider() { + public String getText(Object element) { + return element.toString(); + } + + public Image getImage(Object element) { + return null; + } + }); + rolesViewer.setContentProvider(new RolesContentProvider()); + rolesViewer.setInput(getEditorSite()); + } + + protected TableViewerColumn createTableViewerColumn(TableViewer viewer, + String title, int bound) { + final TableViewerColumn viewerColumn = new TableViewerColumn(viewer, + SWT.NONE); + final TableColumn column = viewerColumn.getColumn(); + column.setText(title); + column.setWidth(bound); + column.setResizable(true); + column.setMoveable(true); + return viewerColumn; + + } + + public List getRoles() { + return roles; + } + + public void refresh() { + rolesViewer.refresh(); + } + + private class RolesContentProvider implements IStructuredContentProvider { + public Object[] getElements(Object inputElement) { + return userAdminService.listEditableRoles().toArray(); + } + + public void dispose() { + } + + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + } + } + + /** Select the columns by editing the checkbox in the first column */ + class RoleEditingSupport extends EditingSupport { + + private final TableViewer viewer; + private final AbstractFormPart formPart; + + public RoleEditingSupport(TableViewer viewer, AbstractFormPart formPart) { + super(viewer); + this.viewer = viewer; + this.formPart = formPart; + } + + @Override + protected CellEditor getCellEditor(Object element) { + return new CheckboxCellEditor(null, SWT.CHECK | SWT.READ_ONLY); + + } + + @Override + protected boolean canEdit(Object element) { + return true; + } + + @Override + protected Object getValue(Object element) { + String role = element.toString(); + return roles.contains(role); + + } + + @Override + protected void setValue(Object element, Object value) { + Boolean inRole = (Boolean) value; + String role = element.toString(); + if (inRole && !roles.contains(role)) { + roles.add(role); + formPart.markDirty(); + } else if (!inRole && roles.contains(role)) { + roles.remove(role); + formPart.markDirty(); + } + viewer.refresh(); + } + } + +} 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 df909b6c7..af3a886ef 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 @@ -1,13 +1,25 @@ package org.argeo.security.ui.admin.views; import java.util.ArrayList; +import java.util.List; + +import javax.jcr.Node; +import javax.jcr.NodeIterator; +import javax.jcr.RepositoryException; +import javax.jcr.Session; +import javax.jcr.observation.EventIterator; +import javax.jcr.observation.EventListener; +import javax.jcr.query.Query; import org.argeo.ArgeoException; +import org.argeo.eclipse.ui.dialogs.Error; +import org.argeo.jcr.ArgeoNames; +import org.argeo.jcr.ArgeoTypes; import org.argeo.security.ArgeoUser; -import org.argeo.security.UserAdminService; -import org.argeo.security.nature.SimpleUserNature; import org.argeo.security.ui.admin.SecurityAdminPlugin; import org.argeo.security.ui.admin.commands.OpenArgeoUserEditor; +import org.argeo.security.ui.admin.editors.ArgeoUserEditor; +import org.argeo.security.ui.admin.editors.ArgeoUserEditorInput; import org.eclipse.core.commands.Command; import org.eclipse.core.commands.IParameter; import org.eclipse.core.commands.Parameterization; @@ -27,18 +39,18 @@ import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PartInitException; import org.eclipse.ui.commands.ICommandService; import org.eclipse.ui.handlers.IHandlerService; import org.eclipse.ui.part.ViewPart; /** List all users. */ -public class UsersView extends ViewPart { +public class UsersView extends ViewPart implements ArgeoNames, ArgeoTypes, + EventListener { public final static String ID = "org.argeo.security.ui.admin.adminUsersView"; private TableViewer viewer; - private UserAdminService userAdminService; - - private String simpleNatureType = null; + private Session session; @Override public void createPartControl(Composite parent) { @@ -73,22 +85,39 @@ public class UsersView extends ViewPart { viewer.getTable().setFocus(); } - public void setUserAdminService(UserAdminService userAdminService) { - this.userAdminService = userAdminService; + public void setSession(Session session) { + this.session = session; } - public void setSimpleNatureType(String simpleNatureType) { - this.simpleNatureType = simpleNatureType; + public void refresh() { + viewer.refresh(); } - public void refresh() { + @Override + public void onEvent(EventIterator events) { viewer.refresh(); } private class UsersContentProvider implements IStructuredContentProvider { public Object[] getElements(Object inputElement) { - return userAdminService.listUsers().toArray(); + try { + Query query = session + .getWorkspace() + .getQueryManager() + .createQuery( + "select [" + ARGEO_USER_PROFILE + "] from [" + + ARGEO_USER_HOME + "]", Query.JCR_SQL2); + NodeIterator nit = query.execute().getNodes(); + List userProfiles = new ArrayList(); + while (nit.hasNext()) { + userProfiles.add(nit.nextNode()); + } + return userProfiles.toArray(); + } catch (RepositoryException e) { + throw new ArgeoException("Cannot list users", e); + } + // return userAdminService.listUsers().toArray(); } public void dispose() { @@ -102,26 +131,52 @@ public class UsersView extends ViewPart { private class UsersLabelProvider extends LabelProvider implements ITableLabelProvider { public String getColumnText(Object element, int columnIndex) { - // String currentUsername = CurrentUser.getUsername(); - String currentUsername = ""; - ArgeoUser user = (ArgeoUser) element; - SimpleUserNature simpleNature = SimpleUserNature - .findSimpleUserNature(user, simpleNatureType); - switch (columnIndex) { - case 0: - String userName = user.getUsername(); - if (userName.equals(currentUsername)) - userName = userName + "*"; - return userName; - case 1: - return simpleNature.getFirstName(); - case 2: - return simpleNature.getLastName(); - case 3: - return simpleNature.getEmail(); - default: - throw new ArgeoException("Unmanaged column " + columnIndex); + try { + Node userHome = (Node) element; + switch (columnIndex) { + case 0: + String userName = userHome.getProperty(ARGEO_USER_ID) + .getString(); + if (userName.equals(session.getUserID())) + return "[" + userName + "]"; + else + return userName; + case 1: + return userHome.getNode(ARGEO_USER_PROFILE) + .getProperty(ARGEO_FIRST_NAME).getString(); + case 2: + return userHome.getNode(ARGEO_USER_PROFILE) + .getProperty(ARGEO_LAST_NAME).getString(); + case 3: + return userHome.getNode(ARGEO_USER_PROFILE) + .getProperty(ARGEO_PRIMARY_EMAIL).getString(); + default: + throw new ArgeoException("Unmanaged column " + columnIndex); + } + } catch (RepositoryException e) { + throw new ArgeoException("Cannot get text", e); } + + // String currentUsername = CurrentUser.getUsername(); + // String currentUsername = ""; + // ArgeoUser user = (ArgeoUser) element; + // SimpleUserNature simpleNature = SimpleUserNature + // .findSimpleUserNature(user, simpleNatureType); + // switch (columnIndex) { + // case 0: + // String userName = user.getUsername(); + // if (userName.equals(currentUsername)) + // userName = userName + "*"; + // return userName; + // case 1: + // return simpleNature.getFirstName(); + // case 2: + // return simpleNature.getLastName(); + // case 3: + // return simpleNature.getEmail(); + // default: + // throw new ArgeoException("Unmanaged column " + columnIndex); + // } } public Image getColumnImage(Object element, int columnIndex) { @@ -133,10 +188,23 @@ public class UsersView extends ViewPart { class ViewDoubleClickListener implements IDoubleClickListener { public void doubleClick(DoubleClickEvent evt) { + if (evt.getSelection().isEmpty()) + return; + Object obj = ((IStructuredSelection) evt.getSelection()) .getFirstElement(); - - if (obj instanceof ArgeoUser) { + if (obj instanceof Node) { + try { + IWorkbench iw = SecurityAdminPlugin.getDefault() + .getWorkbench(); + iw.getActiveWorkbenchWindow() + .getActivePage() + .openEditor(new ArgeoUserEditorInput((Node) obj), + ArgeoUserEditor.ID); + } catch (PartInitException e) { + Error.show("Cannot open user editor for " + obj, e); + } + } else if (obj instanceof ArgeoUser) { ArgeoUser argeoUser = (ArgeoUser) obj; IWorkbench iw = SecurityAdminPlugin.getDefault().getWorkbench(); diff --git a/security/plugins/org.argeo.security.ui.rap/src/main/java/org/argeo/security/ui/rap/SecureEntryPoint.java b/security/plugins/org.argeo.security.ui.rap/src/main/java/org/argeo/security/ui/rap/SecureEntryPoint.java index d7dc18ca9..50f74e9c7 100644 --- a/security/plugins/org.argeo.security.ui.rap/src/main/java/org/argeo/security/ui/rap/SecureEntryPoint.java +++ b/security/plugins/org.argeo.security.ui.rap/src/main/java/org/argeo/security/ui/rap/SecureEntryPoint.java @@ -1,25 +1,45 @@ package org.argeo.security.ui.rap; import java.security.PrivilegedAction; +import java.util.Set; import javax.security.auth.Subject; import javax.security.auth.login.LoginException; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.argeo.eclipse.ui.dialogs.Error; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.jface.dialogs.ErrorDialog; +import org.eclipse.rwt.RWT; import org.eclipse.rwt.lifecycle.IEntryPoint; +import org.eclipse.rwt.service.SessionStoreEvent; +import org.eclipse.rwt.service.SessionStoreListener; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.application.IWorkbenchWindowConfigurer; import org.eclipse.ui.application.WorkbenchAdvisor; import org.eclipse.ui.application.WorkbenchWindowAdvisor; +import org.springframework.security.Authentication; +import org.springframework.security.context.SecurityContextHolder; -public class SecureEntryPoint implements IEntryPoint { +public class SecureEntryPoint implements IEntryPoint, SessionStoreListener { + private Log log = LogFactory.getLog(SecureEntryPoint.class); + + private final static String SECURITY_CONTEXT_ATTRIBUTE = "securityContextAttribute"; @Override public int createUI() { +// log.debug("THREAD=" + Thread.currentThread().getId() +// + ", RWT.getSessionStore().getId()=" +// + RWT.getSessionStore().getId()); + + Authentication authen = (Authentication) RWT.getSessionStore() + .getAttribute(SECURITY_CONTEXT_ATTRIBUTE); + if (authen != null) + SecurityContextHolder.getContext().setAuthentication(authen); + Integer returnCode = null; Display display = PlatformUI.createDisplay(); try { @@ -27,9 +47,18 @@ public class SecureEntryPoint implements IEntryPoint { Boolean retry = true; while (retry) { try { - SecureRapActivator.getLoginContext().login(); - subject = SecureRapActivator.getLoginContext() - .getSubject(); + // if (authen == null) + // SecureRapActivator.getLoginContext().login(); + subject = SecureRapActivator.getLoginContext().getSubject(); + Set auths = subject + .getPrincipals(Authentication.class); + if (auths.size() > 0) + SecurityContextHolder.getContext().setAuthentication( + auths.iterator().next()); + // authen = SecurityContextHolder.getContext() + // .getAuthentication(); + // RWT.getSessionStore().setAttribute( + // SECURITY_CONTEXT_ATTRIBUTE, authen); retry = false; } catch (LoginException e) { Error.show("Cannot login", e); @@ -99,4 +128,13 @@ public class SecureEntryPoint implements IEntryPoint { }; } + @Override + public void beforeDestroy(SessionStoreEvent event) { + if (log.isDebugEnabled()) + log.debug("RWT session " + event.getSessionStore().getId() + + " about to be destroyed. THREAD=" + + Thread.currentThread().getId()); + + } + } diff --git a/security/plugins/org.argeo.security.ui/plugin.xml b/security/plugins/org.argeo.security.ui/plugin.xml index e189e5efe..a9ad7d848 100644 --- a/security/plugins/org.argeo.security.ui/plugin.xml +++ b/security/plugins/org.argeo.security.ui/plugin.xml @@ -52,7 +52,7 @@ - diff --git a/security/plugins/org.argeo.security.ui/src/main/java/org/argeo/security/ui/internal/CurrentUser.java b/security/plugins/org.argeo.security.ui/src/main/java/org/argeo/security/ui/internal/CurrentUser.java index 1abdc1564..638eb03a5 100644 --- a/security/plugins/org.argeo.security.ui/src/main/java/org/argeo/security/ui/internal/CurrentUser.java +++ b/security/plugins/org.argeo.security.ui/src/main/java/org/argeo/security/ui/internal/CurrentUser.java @@ -23,7 +23,8 @@ public class CurrentUser { } public final static Set roles() { - Principal principal = getSubject().getPrincipals().iterator().next(); + Principal principal = getSubject().getPrincipals(Authentication.class) + .iterator().next(); Authentication authentication = (Authentication) principal; Set roles = Collections.synchronizedSet(new HashSet()); for (GrantedAuthority ga : authentication.getAuthorities()) { diff --git a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/UserAdminService.java b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/UserAdminService.java index cd49d6566..e813e72a4 100644 --- a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/UserAdminService.java +++ b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/UserAdminService.java @@ -1,5 +1,6 @@ package org.argeo.security; +import java.util.List; import java.util.Set; public interface UserAdminService { @@ -21,6 +22,8 @@ public interface UserAdminService { /** List users having this role (except the super user). */ public Set listUsersInRole(String role); + public List listUserRoles(String username); + public void deleteUser(String username); /* diff --git a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/ArgeoUserDetails.java b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/ArgeoUserDetails.java index edd7e2bf3..eac1d3706 100644 --- a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/ArgeoUserDetails.java +++ b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/ArgeoUserDetails.java @@ -33,6 +33,7 @@ import org.springframework.security.context.SecurityContextHolder; import org.springframework.security.userdetails.User; import org.springframework.security.userdetails.UserDetails; +@Deprecated public class ArgeoUserDetails extends User implements ArgeoUser { private static final long serialVersionUID = 1L; private final static Log log = LogFactory.getLog(ArgeoUserDetails.class); diff --git a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/DefaultUserAdminService.java b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/DefaultUserAdminService.java index 94cdfa94f..e744dd0e7 100644 --- a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/DefaultUserAdminService.java +++ b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/DefaultUserAdminService.java @@ -18,6 +18,7 @@ package org.argeo.security.core; import java.util.HashSet; import java.util.Iterator; +import java.util.List; import java.util.Set; import org.argeo.security.ArgeoUser; @@ -95,6 +96,10 @@ public class DefaultUserAdminService implements UserAdminService { return userAdminDao.listUsers(); } + public List listUserRoles(String username) { + return getUser(username).getRoles(); + } + public Set listEditableRoles() { return userAdminDao.listEditableRoles(); } diff --git a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/KeyBasedSystemExecutionService.java b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/KeyBasedSystemExecutionService.java index 08ef6428a..a02221e32 100644 --- a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/KeyBasedSystemExecutionService.java +++ b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/KeyBasedSystemExecutionService.java @@ -1,5 +1,6 @@ package org.argeo.security.core; +import org.argeo.ArgeoException; import org.argeo.security.SystemExecutionService; import org.springframework.core.task.SimpleAsyncTaskExecutor; import org.springframework.core.task.TaskExecutor; @@ -36,6 +37,14 @@ public class KeyBasedSystemExecutionService implements SystemExecutionService, public void run() { SecurityContext securityContext = SecurityContextHolder .getContext(); + Authentication currentAuth = securityContext + .getAuthentication(); + if (currentAuth != null) { + throw new ArgeoException( + "System execution on an already authenticated thread: " + + currentAuth + ", THREAD=" + + Thread.currentThread().getId()); + } Authentication auth = authenticationManager .authenticate(new InternalAuthentication( systemAuthenticationKey)); diff --git a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/jcr/JcrUserDetails.java b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/jcr/JcrUserDetails.java index ea66b5ff7..3815b843b 100644 --- a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/jcr/JcrUserDetails.java +++ b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/jcr/JcrUserDetails.java @@ -66,4 +66,21 @@ public class JcrUserDetails extends User { jcrUserDetails.isEnabled()); } + + public JcrUserDetails cloneWithNewRoles(List roles) { + List authorities = new ArrayList(); + for (String role : roles) { + authorities.add(new GrantedAuthorityImpl(role)); + } + return new JcrUserDetails(homePath, getUsername(), getPassword(), + isEnabled(), isAccountNonExpired(), isAccountNonExpired(), + isAccountNonLocked(), + authorities.toArray(new GrantedAuthority[authorities.size()])); + } + + public JcrUserDetails cloneWithNewPassword(String password) { + return new JcrUserDetails(homePath, getUsername(), password, + isEnabled(), isAccountNonExpired(), isAccountNonExpired(), + isAccountNonLocked(), getAuthorities()); + } } diff --git a/security/runtime/org.argeo.security.jackrabbit/src/main/java/org/argeo/security/jackrabbit/ArgeoLoginModule.java b/security/runtime/org.argeo.security.jackrabbit/src/main/java/org/argeo/security/jackrabbit/ArgeoLoginModule.java index d05cdf9ce..1ab93edbb 100644 --- a/security/runtime/org.argeo.security.jackrabbit/src/main/java/org/argeo/security/jackrabbit/ArgeoLoginModule.java +++ b/security/runtime/org.argeo.security.jackrabbit/src/main/java/org/argeo/security/jackrabbit/ArgeoLoginModule.java @@ -31,7 +31,9 @@ public class ArgeoLoginModule extends AbstractLoginModule { */ @Override protected Principal getPrincipal(Credentials credentials) { - return SecurityContextHolder.getContext().getAuthentication(); + org.springframework.security.Authentication authen = SecurityContextHolder + .getContext().getAuthentication(); + return authen; } protected Set getPrincipals() { 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 5612b6388..72479128c 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 @@ -16,8 +16,6 @@ import org.apache.jackrabbit.api.security.user.Group; import org.apache.jackrabbit.api.security.user.User; import org.apache.jackrabbit.api.security.user.UserManager; import org.apache.jackrabbit.core.DefaultSecurityManager; -import org.apache.jackrabbit.core.RepositoryImpl; -import org.apache.jackrabbit.core.security.AnonymousPrincipal; import org.apache.jackrabbit.core.security.SecurityConstants; import org.apache.jackrabbit.core.security.SystemPrincipal; import org.apache.jackrabbit.core.security.authorization.WorkspaceAccessManager; @@ -94,7 +92,7 @@ public class ArgeoSecurityManager extends DefaultSecurityManager { private class ArgeoWorkspaceAccessManagerImpl implements SecurityConstants, WorkspaceAccessManager { private final WorkspaceAccessManager wam; - private String defaultWorkspace; + //private String defaultWorkspace; public ArgeoWorkspaceAccessManagerImpl(WorkspaceAccessManager wam) { super(); @@ -103,8 +101,8 @@ public class ArgeoSecurityManager extends DefaultSecurityManager { public void init(Session systemSession) throws RepositoryException { wam.init(systemSession); - defaultWorkspace = ((RepositoryImpl) getRepository()).getConfig() - .getDefaultWorkspaceName(); +// defaultWorkspace = ((RepositoryImpl) getRepository()).getConfig() +// .getDefaultWorkspaceName(); } public void close() throws RepositoryException { 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 2d9fb1c1a..0e8dbab32 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 @@ -1,8 +1,11 @@ package org.argeo.security.ldap.jcr; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; import java.util.Arrays; import java.util.HashMap; import java.util.Map; +import java.util.Random; import java.util.concurrent.Executor; import javax.jcr.Node; @@ -10,6 +13,7 @@ import javax.jcr.Repository; import javax.jcr.RepositoryException; import javax.jcr.RepositoryFactory; import javax.jcr.Session; +import javax.jcr.nodetype.NodeType; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -22,6 +26,8 @@ import org.argeo.security.jcr.JcrUserDetails; import org.springframework.ldap.core.DirContextAdapter; import org.springframework.ldap.core.DirContextOperations; import org.springframework.security.GrantedAuthority; +import org.springframework.security.context.SecurityContextHolder; +import org.springframework.security.providers.encoding.PasswordEncoder; import org.springframework.security.userdetails.UserDetails; import org.springframework.security.userdetails.ldap.UserDetailsContextMapper; @@ -42,19 +48,38 @@ public class JcrUserDetailsContextMapper implements UserDetailsContextMapper, private Map propertyToAttributes = new HashMap(); private Executor systemExecutor; - private RepositoryFactory repositoryFactory; + private Session session; + + private PasswordEncoder passwordEncoder; + private final Random random; + + public JcrUserDetailsContextMapper() { + random = createRandom(); + } + + private static Random createRandom() { + try { + return SecureRandom.getInstance("SHA1PRNG"); + } catch (NoSuchAlgorithmException e) { + return new Random(System.currentTimeMillis()); + } + } public UserDetails mapUserFromContext(final DirContextOperations ctx, final String username, GrantedAuthority[] authorities) { - if (repositoryFactory == null) - throw new ArgeoException("No JCR repository factory registered"); + // if (repository == null) + // throw new ArgeoException("No JCR repository registered"); final StringBuffer userHomePathT = new StringBuffer(""); - systemExecutor.execute(new Runnable() { + Runnable action = new Runnable() { public void run() { String userHomepath = mapLdapToJcr(username, ctx); userHomePathT.append(userHomepath); } - }); + }; + if (SecurityContextHolder.getContext().getAuthentication() == null)// authentication + systemExecutor.execute(action); + else + action.run(); // password byte[] arr = (byte[]) ctx @@ -69,18 +94,24 @@ public class JcrUserDetailsContextMapper implements UserDetailsContextMapper, /** @return path to the user home node */ protected String mapLdapToJcr(String username, DirContextOperations ctx) { - Session session = null; + // Session session = null; try { - Repository nodeRepo = JcrUtils.getRepositoryByAlias( - repositoryFactory, ArgeoJcrConstants.ALIAS_NODE); - session = nodeRepo.login(); + // Repository nodeRepo = JcrUtils.getRepositoryByAlias( + // repositoryFactory, ArgeoJcrConstants.ALIAS_NODE); + // session = nodeRepo.login(); Node userHome = JcrUtils.getUserHome(session, username); if (userHome == null) userHome = createUserHome(session, username); String userHomePath = userHome.getPath(); - Node userProfile = userHome.hasNode(ARGEO_USER_PROFILE) ? userHome - .getNode(ARGEO_USER_PROFILE) : userHome - .addNode(ARGEO_USER_PROFILE); + Node userProfile; + if (userHome.hasNode(ARGEO_USER_PROFILE)) { + userProfile = userHome.getNode(ARGEO_USER_PROFILE); + } else { + userProfile = userHome.addNode(ARGEO_USER_PROFILE); + userProfile.addMixin(NodeType.MIX_TITLE); + userProfile.addMixin(NodeType.MIX_CREATED); + userProfile.addMixin(NodeType.MIX_LAST_MODIFIED); + } for (String jcrProperty : propertyToAttributes.keySet()) ldapToJcr(userProfile, jcrProperty, ctx); session.save(); @@ -91,7 +122,7 @@ public class JcrUserDetailsContextMapper implements UserDetailsContextMapper, JcrUtils.discardQuietly(session); throw new ArgeoException("Cannot synchronize JCR and LDAP", e); } finally { - session.logout(); + // JcrUtils.logoutQuietly(session); } } @@ -120,31 +151,40 @@ public class JcrUserDetailsContextMapper implements UserDetailsContextMapper, ctx.setAttributeValues("objectClass", userClasses); ctx.setAttributeValue(usernameAttribute, user.getUsername()); - ctx.setAttributeValue(passwordAttribute, user.getPassword()); + ctx.setAttributeValue(passwordAttribute, + encodePassword(user.getPassword())); final JcrUserDetails jcrUserDetails = (JcrUserDetails) user; - systemExecutor.execute(new Runnable() { - public void run() { - Session session = null; - try { - Repository nodeRepo = JcrUtils.getRepositoryByAlias( - repositoryFactory, ArgeoJcrConstants.ALIAS_NODE); - session = nodeRepo.login(); - Node userProfile = session.getNode(jcrUserDetails - .getHomePath() + '/' + ARGEO_USER_PROFILE); - for (String jcrProperty : propertyToAttributes.keySet()) - jcrToLdap(userProfile, jcrProperty, ctx); - if (log.isDebugEnabled()) - log.debug("Mapped " + userProfile + " to " - + ctx.getDn()); - } catch (RepositoryException e) { - throw new ArgeoException("Cannot synchronize JCR and LDAP", - e); - } finally { - session.logout(); - } - } - }); + // systemExecutor.execute(new Runnable() { + // public void run() { +// Session session = null; + try { + // Repository nodeRepo = JcrUtils.getRepositoryByAlias( + // repositoryFactory, ArgeoJcrConstants.ALIAS_NODE); + // session = nodeRepo.login(); + Node userProfile = session.getNode(jcrUserDetails.getHomePath() + + '/' + ARGEO_USER_PROFILE); + for (String jcrProperty : propertyToAttributes.keySet()) + jcrToLdap(userProfile, jcrProperty, ctx); + if (log.isDebugEnabled()) + log.debug("Mapped " + userProfile + " to " + ctx.getDn()); + } catch (RepositoryException e) { + throw new ArgeoException("Cannot synchronize JCR and LDAP", e); + } finally { + // session.logout(); + } + // } + // }); + } + + protected String encodePassword(String password) { + if (!password.startsWith("{")) { + byte[] salt = new byte[16]; + random.nextBytes(salt); + return passwordEncoder.encodePassword(password, salt); + } else { + return password; + } } protected void ldapToJcr(Node userProfile, String jcrProperty, @@ -201,15 +241,15 @@ public class JcrUserDetailsContextMapper implements UserDetailsContextMapper, this.homeBasePath = homeBasePath; } - public void register(RepositoryFactory repositoryFactory, - Map parameters) { - this.repositoryFactory = repositoryFactory; - } - - public void unregister(RepositoryFactory repositoryFactory, - Map parameters) { - this.repositoryFactory = null; - } + // public void register(RepositoryFactory repositoryFactory, + // Map parameters) { + // this.repositoryFactory = repositoryFactory; + // } + // + // public void unregister(RepositoryFactory repositoryFactory, + // Map parameters) { + // this.repositoryFactory = null; + // } public void setUsernameAttribute(String usernameAttribute) { this.usernameAttribute = usernameAttribute; @@ -223,4 +263,12 @@ public class JcrUserDetailsContextMapper implements UserDetailsContextMapper, this.userClasses = userClasses; } + public void setPasswordEncoder(PasswordEncoder passwordEncoder) { + this.passwordEncoder = passwordEncoder; + } + + public void setSession(Session session) { + this.session = session; + } + } 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 895c31c59..48845a0d8 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 @@ -98,7 +98,7 @@ public class JackrabbitContainer implements InitializingBean, DisposableBean, throw new ArgeoException("Remote Davex repository " + uri + " not found"); log.info("Initialized Jackrabbit repository " + repository - + " from uri " + uri); + + " from URI " + uri); // do not perform further initialization since we assume that the // remote repository has been properly configured return; @@ -275,6 +275,7 @@ public class JackrabbitContainer implements InitializingBean, DisposableBean, try { NamespaceHelper namespaceHelper = new NamespaceHelper(session); namespaceHelper.registerNamespaces(namespaces); + } catch (Exception e) { throw new ArgeoException("Cannot process new session", e); } 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 4b5ffb8db..4026e87ec 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 @@ -7,8 +7,8 @@ public interface ArgeoNames { public final static String ARGEO_URI = "argeo:uri"; public final static String ARGEO_USER_ID = "argeo:userID"; + // user profile public final static String ARGEO_USER_PROFILE = "argeo:userProfile"; - public final static String ARGEO_DISPLAY_NAME = "argeo:displayName"; public final static String ARGEO_FIRST_NAME = "argeo:firstName"; public final static String ARGEO_LAST_NAME = "argeo:lastName"; public final static String ARGEO_PRIMARY_EMAIL = "argeo:primaryEmail"; diff --git a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/ThreadBoundJcrSessionFactory.java b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/ThreadBoundJcrSessionFactory.java index aaafdc26a..9428c6959 100644 --- a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/ThreadBoundJcrSessionFactory.java +++ b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/ThreadBoundJcrSessionFactory.java @@ -167,4 +167,13 @@ public class ThreadBoundJcrSessionFactory implements FactoryBean, return ret; } } + + protected class MonitoringThread extends Thread{ + + @Override + public void run() { + Thread thread=null; + } + + } } -- 2.30.2