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,\
try {
List<SimpleGrantedAuthority> 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(
/** 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";
}
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;
callbackHandler.handle(new Callback[] {});
}
- List<SimpleGrantedAuthority> authorities = Collections
- .singletonList(new SimpleGrantedAuthority(anonymousRole));
+ List<GrantedAuthorityPrincipal> authorities = Collections
+ .singletonList(new GrantedAuthorityPrincipal(
+ KernelHeader.ROLE_ANONYMOUS));
AnonymousAuthenticationToken anonymousToken = new AnonymousAuthenticationToken(
Activator.getSystemKey(), null, authorities);
import java.util.List;
import javax.jcr.Node;
+import javax.jcr.RepositoryException;
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
import java.util.UUID;
+import org.argeo.security.SystemAuthentication;
import org.osgi.framework.BundleActivator;
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;
/**
* 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;
/**
* @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;
}
-
}
package org.argeo.cms.internal.kernel;
+import java.lang.management.ManagementFactory;
+
import javax.jcr.RepositoryFactory;
import org.apache.commons.logging.Log;
*/
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;
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() {
// 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<String, String> props = new Hashtable<String, String>();
-// 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...");
// 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";
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<String, ?> asDictionary(Properties props) {
Hashtable<String, Object> hashtable = new Hashtable<String, Object>();
// Security
static void anonymousLogin(AuthenticationManager authenticationManager) {
try {
- List<SimpleGrantedAuthority> anonAuthorities = Collections
- .singletonList(new SimpleGrantedAuthority(ROLE_ANONYMOUS));
- UserDetails anonUser = new User(ANONYMOUS_USER, "", true, true,
- true, true, anonAuthorities);
+ List<GrantedAuthorityPrincipal> 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
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;
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;
}
}
- 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);
+ //
+ // }
+ // }
}
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;
/** 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<String> roles) {
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);
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;
*/
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 {
.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();
}
}
List<String> roles = new ArrayList<String>();
for (GrantedAuthority ga : userDetails.getAuthorities()) {
- if (ga.getAuthority().equals(userRole))
+ if (ga.getAuthority().equals(KernelHeader.ROLE_USER))
continue;
roles.add(ga.getAuthority());
}
- for (Iterator<Group> it = user.memberOf(); it.hasNext();) {
+ groups: for (Iterator<Group> 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);
LinkedHashSet<String> res = new LinkedHashSet<String>();
try {
Iterator<Authorizable> 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) {
}
}
+ 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 {
if (username == null)
username = session.getUserID();
User user = (User) getUserManager().getAuthorizable(username);
+
ArrayList<GrantedAuthorityPrincipal> authorities = new ArrayList<GrantedAuthorityPrincipal>();
- // FIXME make it more generic
- authorities.add(new GrantedAuthorityPrincipal("ROLE_USER"));
- Iterator<Group> groups = user.declaredMemberOf();
+ authorities.add(new GrantedAuthorityPrincipal(KernelHeader.ROLE_USER));
+
+ Group adminGroup = (Group) getUserManager().getAuthorizable(
+ KernelHeader.ROLE_ADMIN);
+
+ Iterator<? extends Authorizable> 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);
* 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";
}
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");
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,
}
public InternalAuthentication(String key) {
- this(key, DEFAULT_SYSTEM_USERNAME, DEFAULT_SYSTEM_ROLE);
+ this(key, SystemAuthentication.USERNAME_SYSTEM, SystemAuthentication.ROLE_SYSTEM);
}
}
</extension>
<extension
point="org.eclipse.ui.activities">
- <!-- TODO: find a way to exclude evrything -->
- <activityPatternBinding
- activityId="org.argeo.security.ui.adminActivity"
+ <activityPatternBinding
+ activityId="org.argeo.security.ui.userAdminActivity"
isEqualityPattern="true"
pattern="org.argeo.security.ui.admin/org.argeo.security.ui.admin.adminSecurityPerspective">
</activityPatternBinding>
+ <activityPatternBinding
+ activityId="org.argeo.security.ui.groupAdminActivity"
+ isEqualityPattern="true"
+ pattern="org.argeo.security.ui.admin/org.argeo.security.ui.admin.adminRolesView">
+ </activityPatternBinding>
</extension>
</plugin>
</with>
</enabledWhen>
</activity>
+ <activity
+ description="User Admins"
+ id="org.argeo.security.ui.userAdminActivity"
+ name="User Admin">
+ <enabledWhen>
+ <with variable="roles">
+ <iterate ifEmpty="false" operator="or">
+ <equals value="ROLE_USER_ADMIN" />
+ </iterate>
+ </with>
+ </enabledWhen>
+ </activity>
+ <activity
+ description="Group Admins"
+ id="org.argeo.security.ui.groupAdminActivity"
+ name="User Admin">
+ <enabledWhen>
+ <with variable="roles">
+ <iterate ifEmpty="false" operator="or">
+ <equals value="ROLE_GROUP_ADMIN" />
+ </iterate>
+ </with>
+ </enabledWhen>
+ </activity>
<activity
description="Non admins"
id="org.argeo.security.ui.notAdminActivity"
import javax.jcr.Credentials;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
-import javax.jcr.Repository;
import javax.jcr.Session;
import javax.jcr.nodetype.NodeType;