From d12f4cda6ff7b1de242a19362c3680f30ccc5168 Mon Sep 17 00:00:00 2001 From: Mathieu Baudier Date: Sat, 14 Feb 2015 21:04:53 +0000 Subject: [PATCH] Introduce ROLE_USER_ADMIN and ROLE_GROUP_ADMIN git-svn-id: https://svn.argeo.org/commons/trunk@7881 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- org.argeo.cms/bnd.bnd | 1 + org.argeo.cms/src/org/argeo/cms/CmsLogin.java | 2 +- .../src/org/argeo/cms/KernelHeader.java | 12 ++ .../internal/auth/AnonymousLoginModule.java | 8 +- .../cms/internal/auth/JcrSecurityModel.java | 4 + .../argeo/cms/internal/kernel/Activator.java | 13 +- .../org/argeo/cms/internal/kernel/Kernel.java | 34 +++-- .../cms/internal/kernel/KernelConstants.java | 7 - .../cms/internal/kernel/KernelUtils.java | 15 ++- .../argeo/cms/internal/kernel/NodeHttp.java | 32 +++-- .../useradmin/SimpleJcrSecurityModel.java | 18 ++- .../JackrabbitUserAdminService.java | 121 ++++++++++++++---- .../argeo/security/SystemAuthentication.java | 5 +- .../core/AbstractSystemExecution.java | 2 +- .../security/core/InternalAuthentication.java | 6 +- org.argeo.security.ui.admin/plugin.xml | 10 +- org.argeo.security.ui/plugin.xml | 24 ++++ .../argeo/jackrabbit/JackrabbitWrapper.java | 1 - 18 files changed, 218 insertions(+), 97 deletions(-) diff --git a/org.argeo.cms/bnd.bnd b/org.argeo.cms/bnd.bnd index 459d3e094..af1220832 100644 --- a/org.argeo.cms/bnd.bnd +++ b/org.argeo.cms/bnd.bnd @@ -8,6 +8,7 @@ org.springframework.context,\ org.springframework.security.authentication.jaas,\ org.apache.jackrabbit.api,\ org.apache.jackrabbit.commons,\ +org.apache.jackrabbit.core.security.user,\ org.eclipse.*;resolution:=optional,\ org.eclipse.core.commands;resolution:=optional,\ org.eclipse.swt;resolution:=optional,\ diff --git a/org.argeo.cms/src/org/argeo/cms/CmsLogin.java b/org.argeo.cms/src/org/argeo/cms/CmsLogin.java index e8a2e48fd..d93a95225 100644 --- a/org.argeo.cms/src/org/argeo/cms/CmsLogin.java +++ b/org.argeo.cms/src/org/argeo/cms/CmsLogin.java @@ -31,7 +31,7 @@ public class CmsLogin { try { List anonAuthorities = Collections .singletonList(new SimpleGrantedAuthority( - KernelConstants.ANONYMOUS_USER)); + KernelHeader.USERNAME_ANONYMOUS)); UserDetails anonUser = new User("anonymous", "", true, true, true, true, anonAuthorities); AnonymousAuthenticationToken anonToken = new AnonymousAuthenticationToken( diff --git a/org.argeo.cms/src/org/argeo/cms/KernelHeader.java b/org.argeo.cms/src/org/argeo/cms/KernelHeader.java index db1034a90..c72a410f0 100644 --- a/org.argeo.cms/src/org/argeo/cms/KernelHeader.java +++ b/org.argeo.cms/src/org/argeo/cms/KernelHeader.java @@ -2,7 +2,19 @@ package org.argeo.cms; /** Public properties of the CMS Kernel */ public interface KernelHeader { + // LOGIN CONTEXTS final static String LOGIN_CONTEXT_USER = "USER"; final static String LOGIN_CONTEXT_ANONYMOUS = "ANONYMOUS"; final static String LOGIN_CONTEXT_SYSTEM = "SYSTEM"; + + // RESERVED ROLES + public final static String ROLE_ADMIN = "ROLE_ADMIN"; + public final static String ROLE_GROUP_ADMIN = "ROLE_GROUP_ADMIN"; + public final static String ROLE_USER_ADMIN = "ROLE_USER_ADMIN"; + public final static String ROLE_USER = "ROLE_USER"; + public final static String ROLE_ANONYMOUS = "ROLE_ANONYMOUS"; + + // RESERVED USERNAMES + public final static String USERNAME_ADMIN = "root"; + public final static String USERNAME_ANONYMOUS = "anonymous"; } diff --git a/org.argeo.cms/src/org/argeo/cms/internal/auth/AnonymousLoginModule.java b/org.argeo.cms/src/org/argeo/cms/internal/auth/AnonymousLoginModule.java index 6078b8f2b..372f27e60 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/auth/AnonymousLoginModule.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/auth/AnonymousLoginModule.java @@ -25,16 +25,15 @@ import javax.security.auth.callback.CallbackHandler; import javax.security.auth.callback.UnsupportedCallbackException; import javax.security.auth.login.LoginException; +import org.argeo.cms.KernelHeader; import org.argeo.cms.internal.kernel.Activator; import org.argeo.util.LocaleCallback; import org.argeo.util.LocaleUtils; import org.springframework.security.authentication.AnonymousAuthenticationToken; import org.springframework.security.core.Authentication; -import org.springframework.security.core.authority.SimpleGrantedAuthority; /** Login module which caches one subject per thread. */ public class AnonymousLoginModule extends AbstractLoginModule { - private String anonymousRole = "ROLE_ANONYMOUS"; /** Comma separated list of locales */ private String availableLocales = null; @@ -52,8 +51,9 @@ public class AnonymousLoginModule extends AbstractLoginModule { callbackHandler.handle(new Callback[] {}); } - List authorities = Collections - .singletonList(new SimpleGrantedAuthority(anonymousRole)); + List authorities = Collections + .singletonList(new GrantedAuthorityPrincipal( + KernelHeader.ROLE_ANONYMOUS)); AnonymousAuthenticationToken anonymousToken = new AnonymousAuthenticationToken( Activator.getSystemKey(), null, authorities); diff --git a/org.argeo.cms/src/org/argeo/cms/internal/auth/JcrSecurityModel.java b/org.argeo.cms/src/org/argeo/cms/internal/auth/JcrSecurityModel.java index 2cf1e241a..ad769222b 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/auth/JcrSecurityModel.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/auth/JcrSecurityModel.java @@ -18,6 +18,7 @@ package org.argeo.cms.internal.auth; import java.util.List; import javax.jcr.Node; +import javax.jcr.RepositoryException; import javax.jcr.Session; /** @@ -25,6 +26,9 @@ import javax.jcr.Session; * profile. */ public interface JcrSecurityModel { + /** Initialize the JCR security model */ + public void init(Session adminSession) throws RepositoryException; + /** * To be called before user details are loaded. Make sure than any logged in * user has a home directory with full access and a profile with information diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/Activator.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/Activator.java index 5ec9f5087..9a31d089b 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/Activator.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/Activator.java @@ -2,6 +2,7 @@ package org.argeo.cms.internal.kernel; import java.util.UUID; +import org.argeo.security.SystemAuthentication; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; @@ -10,7 +11,11 @@ import org.osgi.framework.BundleContext; * access to kernel information for the rest of the bundle (and only it) */ public class Activator implements BundleActivator { - private final static String systemKey = UUID.randomUUID().toString(); + private final static String systemKey; + static { + systemKey = UUID.randomUUID().toString(); + System.setProperty(SystemAuthentication.SYSTEM_KEY_PROPERTY, systemKey); + } private static BundleContext bundleContext; private Kernel kernel; @@ -34,7 +39,9 @@ public class Activator implements BundleActivator { /** * Singleton interface to the {@link BundleContext} related to the calling - * thread. Can be used only within the CMS bundle. + * thread. + * + * @BundleScope */ public static BundleContext getBundleContext() { return bundleContext; @@ -43,9 +50,9 @@ public class Activator implements BundleActivator { /** * @return a String which is guaranteed to be unique between and constant * within a Java static context (typically a VM launch) + * @BundleScope */ public final static String getSystemKey() { return systemKey; } - } diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/Kernel.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/Kernel.java index f2d3995d3..62efa364d 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/Kernel.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/Kernel.java @@ -1,5 +1,7 @@ package org.argeo.cms.internal.kernel; +import java.lang.management.ManagementFactory; + import javax.jcr.RepositoryFactory; import org.apache.commons.logging.Log; @@ -24,7 +26,8 @@ import org.springframework.security.core.context.SecurityContextHolder; */ final class Kernel { private final static Log log = LogFactory.getLog(Kernel.class); -// private static final String PROP_WORKBENCH_AUTOSTART = "org.eclipse.rap.workbenchAutostart"; + // private static final String PROP_WORKBENCH_AUTOSTART = + // "org.eclipse.rap.workbenchAutostart"; private final BundleContext bundleContext; @@ -60,10 +63,13 @@ final class Kernel { throw new ArgeoException("Cannot initialize", e); } - long duration = System.currentTimeMillis() - begin; - log.info("## ARGEO CMS UP in " + (duration / 1000) + "." - + (duration % 1000) + "s ##"); - directorsCut(); + long jvmUptime = ManagementFactory.getRuntimeMXBean().getUptime(); + log.info("## ARGEO CMS UP in " + (jvmUptime / 1000) + "." + + (jvmUptime % 1000) + "s ##"); + long initDuration = System.currentTimeMillis() - begin; + if (log.isTraceEnabled()) + log.trace("Kernel initialization took " + initDuration + "ms"); + directorsCut(initDuration); } void destroy() { @@ -75,25 +81,15 @@ final class Kernel { // Clean hanging threads from Jackrabbit TransientFileFactory.shutdown(); - + long duration = System.currentTimeMillis() - begin; log.info("## ARGEO CMS DOWN in " + (duration / 1000) + "." + (duration % 1000) + "s ##"); } -// private void registerWorkbench(final WorkbenchApplicationConfiguration wac) { -// new Thread("Worbench Launcher") { -// public void run() { -// Hashtable props = new Hashtable(); -// props.put(ApplicationLauncher.PROPERTY_CONTEXT_NAME, "ui"); -// workbenchReg = bundleContext.registerService( -// ApplicationConfiguration.class, wac, props); -// } -// }.start(); -// } - - private void directorsCut() { - final long ms = 128l + (long) (Math.random() * 128d); + private void directorsCut(long initDuration) { + // final long ms = 128l + (long) (Math.random() * 128d); + long ms = initDuration / 10; log.info("Spend " + ms + "ms" + " reflecting on the progress brought to mankind" + " by Free Software..."); diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelConstants.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelConstants.java index eab67785e..79fd1f77a 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelConstants.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelConstants.java @@ -18,15 +18,8 @@ public interface KernelConstants { // Security final static String DEFAULT_SECURITY_KEY = "argeo"; - final static String ANONYMOUS_USER = "anonymous"; - final static String ADMIN_USER = "root"; final static String JAAS_CONFIG = "/org/argeo/cms/internal/kernel/jaas.cfg"; - // Roles - final static String ROLE_USER = "ROLE_USER"; - final static String ROLE_ADMIN = "ROLE_ADMIN"; - final static String ROLE_ANONYMOUS = "ROLE_ANONYMOUS"; - // DAV final static String WEBDAV_CONFIG = "/org/argeo/cms/internal/kernel/webdav-config.xml"; final static String PATH_DATA = "/data"; diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelUtils.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelUtils.java index ba2a352a7..80c166e0a 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelUtils.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelUtils.java @@ -13,17 +13,19 @@ import javax.servlet.http.HttpServletRequest; import org.apache.commons.logging.Log; import org.argeo.cms.CmsException; +import org.argeo.cms.KernelHeader; +import org.argeo.cms.internal.auth.GrantedAuthorityPrincipal; import org.osgi.framework.BundleContext; import org.springframework.security.authentication.AnonymousAuthenticationToken; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.core.Authentication; -import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; +/** Package utilities */ class KernelUtils implements KernelConstants { - final static String OSGI_INSTANCE_AREA = "osgi.instance.area"; + private final static String OSGI_INSTANCE_AREA = "osgi.instance.area"; static Dictionary asDictionary(Properties props) { Hashtable hashtable = new Hashtable(); @@ -52,10 +54,11 @@ class KernelUtils implements KernelConstants { // Security static void anonymousLogin(AuthenticationManager authenticationManager) { try { - List anonAuthorities = Collections - .singletonList(new SimpleGrantedAuthority(ROLE_ANONYMOUS)); - UserDetails anonUser = new User(ANONYMOUS_USER, "", true, true, - true, true, anonAuthorities); + List anonAuthorities = Collections + .singletonList(new GrantedAuthorityPrincipal( + KernelHeader.ROLE_ANONYMOUS)); + UserDetails anonUser = new User(KernelHeader.USERNAME_ANONYMOUS, + "", true, true, true, true, anonAuthorities); AnonymousAuthenticationToken anonToken = new AnonymousAuthenticationToken( DEFAULT_SECURITY_KEY, anonUser, anonAuthorities); Authentication authentication = authenticationManager diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeHttp.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeHttp.java index f0fbe461a..f3a90ebfd 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeHttp.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeHttp.java @@ -8,7 +8,6 @@ import java.util.StringTokenizer; import javax.servlet.FilterChain; import javax.servlet.Servlet; import javax.servlet.ServletException; -import javax.servlet.ServletRequest; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; @@ -22,7 +21,6 @@ import org.argeo.jackrabbit.servlet.RemotingServlet; import org.argeo.jackrabbit.servlet.WebdavServlet; import org.argeo.jcr.ArgeoJcrConstants; import org.eclipse.equinox.http.servlet.ExtendedHttpService; -import org.eclipse.jetty.servlets.DoSFilter; import org.osgi.framework.BundleContext; import org.osgi.service.http.NamespaceException; import org.osgi.util.tracker.ServiceTracker; @@ -295,19 +293,19 @@ class NodeHttp implements KernelConstants, ArgeoJcrConstants { } } - class CustomDosFilter extends DoSFilter { - @Override - protected String extractUserId(ServletRequest request) { - HttpSession httpSession = ((HttpServletRequest) request) - .getSession(); - if (isSessionAuthenticated(httpSession)) { - String userId = ((SecurityContext) httpSession - .getAttribute(SPRING_SECURITY_CONTEXT_KEY)) - .getAuthentication().getName(); - return userId; - } - return super.extractUserId(request); - - } - } + // class CustomDosFilter extends DoSFilter { + // @Override + // protected String extractUserId(ServletRequest request) { + // HttpSession httpSession = ((HttpServletRequest) request) + // .getSession(); + // if (isSessionAuthenticated(httpSession)) { + // String userId = ((SecurityContext) httpSession + // .getAttribute(SPRING_SECURITY_CONTEXT_KEY)) + // .getAuthentication().getName(); + // return userId; + // } + // return super.extractUserId(request); + // + // } + // } } diff --git a/org.argeo.cms/src/org/argeo/cms/internal/useradmin/SimpleJcrSecurityModel.java b/org.argeo.cms/src/org/argeo/cms/internal/useradmin/SimpleJcrSecurityModel.java index c39f9e56d..7c4685304 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/useradmin/SimpleJcrSecurityModel.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/useradmin/SimpleJcrSecurityModel.java @@ -25,6 +25,7 @@ import javax.jcr.security.Privilege; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.jackrabbit.core.security.user.UserAccessControlProvider; import org.argeo.ArgeoException; import org.argeo.cms.internal.auth.JcrSecurityModel; import org.argeo.jcr.ArgeoJcrConstants; @@ -45,6 +46,20 @@ public class SimpleJcrSecurityModel implements JcrSecurityModel { /** The home base path. */ private String homeBasePath = "/home"; + private String peopleBasePath = ArgeoJcrConstants.PEOPLE_BASE_PATH; + + @Override + public void init(Session adminSession) throws RepositoryException { + JcrUtils.mkdirs(adminSession, homeBasePath); + + JcrUtils.mkdirs(adminSession, peopleBasePath); + JcrUtils.addPrivilege(adminSession, peopleBasePath, + UserAccessControlProvider.USER_ADMIN_GROUP_NAME, + Privilege.JCR_ALL); + // JcrUtils.addPrivilege(adminSession, "/", + // UserAccessControlProvider.USER_ADMIN_GROUP_NAME, + // Privilege.JCR_READ); + } public synchronized Node sync(Session session, String username, List roles) { @@ -79,8 +94,7 @@ public class SimpleJcrSecurityModel implements JcrSecurityModel { Node userProfile = UserJcrUtils.getUserProfile(session, username); // new user if (userProfile == null) { - String personPath = generateUserPath( - ArgeoJcrConstants.PEOPLE_BASE_PATH, username); + String personPath = generateUserPath(peopleBasePath, username); Node personBase = JcrUtils.mkdirs(session, personPath); userProfile = personBase.addNode(ArgeoNames.ARGEO_PROFILE); userProfile.addMixin(ArgeoTypes.ARGEO_USER_PROFILE); diff --git a/org.argeo.cms/src/org/argeo/cms/internal/useradmin/jackrabbit/JackrabbitUserAdminService.java b/org.argeo.cms/src/org/argeo/cms/internal/useradmin/jackrabbit/JackrabbitUserAdminService.java index e7f44943b..d35f996f4 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/useradmin/jackrabbit/JackrabbitUserAdminService.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/useradmin/jackrabbit/JackrabbitUserAdminService.java @@ -20,7 +20,9 @@ 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.security.authentication.CryptedSimpleCredentials; +import org.apache.jackrabbit.core.security.user.UserAccessControlProvider; import org.argeo.ArgeoException; +import org.argeo.cms.KernelHeader; import org.argeo.cms.internal.auth.GrantedAuthorityPrincipal; import org.argeo.cms.internal.auth.JcrSecurityModel; import org.argeo.jcr.JcrUtils; @@ -46,15 +48,14 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException; */ public class JackrabbitUserAdminService implements UserAdminService, AuthenticationProvider { - final static String userRole = "ROLE_USER"; - final static String adminRole = "ROLE_ADMIN"; + private final static String JACKR_ADMINISTRATORS = "administrators"; + private final static String REP_PRINCIPAL_NAME = "rep:principalName"; private Repository repository; private JcrSecurityModel securityModel; private JackrabbitSession adminSession = null; - private String superUsername = "root"; private String superUserInitialPassword = "demo"; public void init() throws RepositoryException { @@ -62,18 +63,20 @@ public class JackrabbitUserAdminService implements UserAdminService, .getAuthentication(); authentication.getName(); adminSession = (JackrabbitSession) repository.login(); - Authorizable adminGroup = getUserManager().getAuthorizable(adminRole); + securityModel.init(adminSession); + Authorizable adminGroup = getUserManager().getAuthorizable( + KernelHeader.ROLE_ADMIN); if (adminGroup == null) { - adminGroup = getUserManager().createGroup(adminRole); + adminGroup = getUserManager().createGroup(KernelHeader.ROLE_ADMIN); adminSession.save(); } - Authorizable superUser = getUserManager() - .getAuthorizable(superUsername); + Authorizable superUser = getUserManager().getAuthorizable( + KernelHeader.USERNAME_ADMIN); if (superUser == null) { - superUser = getUserManager().createUser(superUsername, - superUserInitialPassword); + superUser = getUserManager().createUser( + KernelHeader.USERNAME_ADMIN, superUserInitialPassword); ((Group) adminGroup).addMember(superUser); - securityModel.sync(adminSession, superUsername, null); + securityModel.sync(adminSession, KernelHeader.USERNAME_ADMIN, null); adminSession.save(); } } @@ -131,27 +134,49 @@ public class JackrabbitUserAdminService implements UserAdminService, List roles = new ArrayList(); for (GrantedAuthority ga : userDetails.getAuthorities()) { - if (ga.getAuthority().equals(userRole)) + if (ga.getAuthority().equals(KernelHeader.ROLE_USER)) continue; roles.add(ga.getAuthority()); } - for (Iterator it = user.memberOf(); it.hasNext();) { + groups: for (Iterator it = user.memberOf(); it.hasNext();) { Group group = it.next(); - if (roles.contains(group.getPrincipal().getName())) - roles.remove(group.getPrincipal().getName()); - else + String groupName = group.getPrincipal().getName(); + String role = groupNameToRole(groupName); + if (role == null) + continue groups; + + if (roles.contains(role)) + roles.remove(role); + else { group.removeMember(user); + if (role.equals(KernelHeader.ROLE_ADMIN)) { + Group administratorsGroup = ((Group) getUserManager() + .getAuthorizable(JACKR_ADMINISTRATORS)); + if (administratorsGroup.isDeclaredMember(user)) + administratorsGroup.removeMember(user); + } + } } - // remaining (new ones) + // remaining (new memberships) for (String role : roles) { - Group group = (Group) getUserManager().getAuthorizable(role); + String groupName = roleToGroupName(role); + Group group = (Group) getUserManager().getAuthorizable( + groupName); if (group == null) throw new ArgeoException("Group " + role + " does not exist," + " whereas it was granted to user " + userDetails); group.addMember(user); + + // add to Jackrabbit administrators + if (role.equals(KernelHeader.ROLE_ADMIN)) { + Group administratorsGroup = (Group) getUserManager() + .getAuthorizable(JACKR_ADMINISTRATORS); + administratorsGroup.addMember(user); + } + } } catch (Exception e) { throw new ArgeoException("Cannot update user details", e); @@ -252,9 +277,13 @@ public class JackrabbitUserAdminService implements UserAdminService, LinkedHashSet res = new LinkedHashSet(); try { Iterator groups = getUserManager().findAuthorizables( - "rep:principalName", null, UserManager.SEARCH_TYPE_GROUP); + REP_PRINCIPAL_NAME, null, UserManager.SEARCH_TYPE_GROUP); while (groups.hasNext()) { - res.add(groups.next().getPrincipal().getName()); + Group group = (Group) groups.next(); + String groupName = group.getPrincipal().getName(); + String role = groupNameToRole(groupName); + if (role != null && !role.equals(KernelHeader.ROLE_GROUP_ADMIN)) + res.add(role); } return res; } catch (RepositoryException e) { @@ -271,6 +300,32 @@ public class JackrabbitUserAdminService implements UserAdminService, } } + protected String roleToGroupName(String role) { + String groupName; + if (role.equals(KernelHeader.ROLE_USER_ADMIN)) + groupName = UserAccessControlProvider.USER_ADMIN_GROUP_NAME; + else if (role.equals(KernelHeader.ROLE_GROUP_ADMIN)) + groupName = UserAccessControlProvider.GROUP_ADMIN_GROUP_NAME; + else + groupName = role; + return groupName; + } + + protected String groupNameToRole(String groupName) { + String role; + if (groupName.equals(UserAccessControlProvider.USER_ADMIN_GROUP_NAME)) { + role = KernelHeader.ROLE_USER_ADMIN; + } else if (groupName + .equals(UserAccessControlProvider.GROUP_ADMIN_GROUP_NAME)) { + role = KernelHeader.ROLE_GROUP_ADMIN; + } else if (groupName.equals(JACKR_ADMINISTRATORS)) { + return null; + } else { + role = groupName; + } + return role; + } + @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException { @@ -290,16 +345,28 @@ public class JackrabbitUserAdminService implements UserAdminService, if (username == null) username = session.getUserID(); User user = (User) getUserManager().getAuthorizable(username); + ArrayList authorities = new ArrayList(); - // FIXME make it more generic - authorities.add(new GrantedAuthorityPrincipal("ROLE_USER")); - Iterator groups = user.declaredMemberOf(); + authorities.add(new GrantedAuthorityPrincipal(KernelHeader.ROLE_USER)); + + Group adminGroup = (Group) getUserManager().getAuthorizable( + KernelHeader.ROLE_ADMIN); + + Iterator groups; + if (username.equals(KernelHeader.USERNAME_ADMIN) + || adminGroup.isDeclaredMember(user)) { + groups = getUserManager().findAuthorizables(REP_PRINCIPAL_NAME, + null, UserManager.SEARCH_TYPE_GROUP); + } else { + groups = user.declaredMemberOf(); + } + while (groups.hasNext()) { - Group group = groups.next(); - // String role = "ROLE_" - // + group.getPrincipal().getName().toUpperCase(); - String role = group.getPrincipal().getName(); - authorities.add(new GrantedAuthorityPrincipal(role)); + Authorizable group = groups.next(); + String groupName = group.getPrincipal().getName(); + String role = groupNameToRole(groupName); + if (role != null) + authorities.add(new GrantedAuthorityPrincipal(role)); } Node userProfile = UserJcrUtils.getUserProfile(session, username); diff --git a/org.argeo.security.core/src/org/argeo/security/SystemAuthentication.java b/org.argeo.security.core/src/org/argeo/security/SystemAuthentication.java index 2722c1f7d..d489761e5 100644 --- a/org.argeo.security.core/src/org/argeo/security/SystemAuthentication.java +++ b/org.argeo.security.core/src/org/argeo/security/SystemAuthentication.java @@ -19,5 +19,8 @@ package org.argeo.security; * Marks a system authentication, that is which did not require a login process. */ public interface SystemAuthentication { - + /** 'admin' for consistency with JCR */ + public final static String USERNAME_SYSTEM = "admin"; + public final static String ROLE_SYSTEM = "ROLE_SYSTEM"; + public final static String SYSTEM_KEY_PROPERTY = "argeo.security.systemKey"; } diff --git a/org.argeo.security.core/src/org/argeo/security/core/AbstractSystemExecution.java b/org.argeo.security.core/src/org/argeo/security/core/AbstractSystemExecution.java index bdd110da9..3acf26c8a 100644 --- a/org.argeo.security.core/src/org/argeo/security/core/AbstractSystemExecution.java +++ b/org.argeo.security.core/src/org/argeo/security/core/AbstractSystemExecution.java @@ -73,7 +73,7 @@ public abstract class AbstractSystemExecution { String key = systemAuthenticationKey != null ? systemAuthenticationKey : System.getProperty( - InternalAuthentication.SYSTEM_KEY_PROPERTY, + SystemAuthentication.SYSTEM_KEY_PROPERTY, InternalAuthentication.SYSTEM_KEY_DEFAULT); if (key == null) throw new ArgeoException("No system key defined"); diff --git a/org.argeo.security.core/src/org/argeo/security/core/InternalAuthentication.java b/org.argeo.security.core/src/org/argeo/security/core/InternalAuthentication.java index ee5e145ba..31e29d18d 100644 --- a/org.argeo.security.core/src/org/argeo/security/core/InternalAuthentication.java +++ b/org.argeo.security.core/src/org/argeo/security/core/InternalAuthentication.java @@ -25,10 +25,6 @@ import org.springframework.security.core.authority.SimpleGrantedAuthority; public class InternalAuthentication extends UsernamePasswordAuthenticationToken implements SystemAuthentication { private static final long serialVersionUID = -6783376375615949315L; - /** 'admin' for consistency with JCR */ - public final static String DEFAULT_SYSTEM_USERNAME = "admin"; - public final static String DEFAULT_SYSTEM_ROLE = "ROLE_SYSTEM"; - public final static String SYSTEM_KEY_PROPERTY = "argeo.security.systemKey"; public final static String SYSTEM_KEY_DEFAULT = "argeo"; public InternalAuthentication(String key, String systemUsername, @@ -38,7 +34,7 @@ public class InternalAuthentication extends UsernamePasswordAuthenticationToken } public InternalAuthentication(String key) { - this(key, DEFAULT_SYSTEM_USERNAME, DEFAULT_SYSTEM_ROLE); + this(key, SystemAuthentication.USERNAME_SYSTEM, SystemAuthentication.ROLE_SYSTEM); } } diff --git a/org.argeo.security.ui.admin/plugin.xml b/org.argeo.security.ui.admin/plugin.xml index e260bdea4..f7c18f5e9 100644 --- a/org.argeo.security.ui.admin/plugin.xml +++ b/org.argeo.security.ui.admin/plugin.xml @@ -143,11 +143,15 @@ - - + + diff --git a/org.argeo.security.ui/plugin.xml b/org.argeo.security.ui/plugin.xml index 24fb40a44..7d18541af 100644 --- a/org.argeo.security.ui/plugin.xml +++ b/org.argeo.security.ui/plugin.xml @@ -64,6 +64,30 @@ + + + + + + + + + + + + + + + + + +