/*
- * Copyright (C) 2007-2012 Mathieu Baudier
+ * Copyright (C) 2007-2012 Argeo GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
import java.security.Principal;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import javax.jcr.RepositoryException;
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.security.AMContext;
+import org.apache.jackrabbit.core.security.AccessManager;
import org.apache.jackrabbit.core.security.AnonymousPrincipal;
import org.apache.jackrabbit.core.security.SecurityConstants;
import org.apache.jackrabbit.core.security.authorization.WorkspaceAccessManager;
-import org.argeo.ArgeoException;
import org.springframework.security.Authentication;
import org.springframework.security.GrantedAuthority;
+import org.springframework.security.context.SecurityContextHolder;
-/** Integrates Spring Security and Jackrabbit Security user and roles. */
+/** Integrates Spring Security and Jackrabbit Security users and roles. */
public class ArgeoSecurityManager extends DefaultSecurityManager {
- private Log log = LogFactory.getLog(ArgeoSecurityManager.class);
+ /** Legacy security sync */
+ final static String PROPERTY_JACKRABBIT_SECURITY_SYNC_1_1 = "argeo.jackarabbit.securitySync.1.1";
+
+ private final static Log log = LogFactory
+ .getLog(ArgeoSecurityManager.class);
+
+ private static Boolean synchronize = Boolean.parseBoolean(System
+ .getProperty(PROPERTY_JACKRABBIT_SECURITY_SYNC_1_1, "false"));
+
+ /** TODO? use a bounded buffer */
+ private Map<String, String> userRolesCache = Collections
+ .synchronizedMap(new HashMap<String, String>());
+
+ @Override
+ public AccessManager getAccessManager(Session session, AMContext amContext)
+ throws RepositoryException {
+ synchronized (getSystemSession()) {
+ return super.getAccessManager(session, amContext);
+ }
+ }
+
+ @Override
+ public UserManager getUserManager(Session session)
+ throws RepositoryException {
+ synchronized (getSystemSession()) {
+ return super.getUserManager(session);
+ }
+ }
/**
* Since this is called once when the session is created, we take the
@Override
public String getUserID(Subject subject, String workspaceName)
throws RepositoryException {
+ if (!synchronize) {
+ Authentication authentication = SecurityContextHolder.getContext()
+ .getAuthentication();
+ if (authentication != null)
+ return authentication.getName();
+ else
+ return super.getUserID(subject, workspaceName);
+ }
+
if (log.isTraceEnabled())
log.trace(subject);
// skip anonymous user (no rights)
Authentication authen;
Set<Authentication> authens = subject
.getPrincipals(Authentication.class);
- if (authens.size() == 0)
- throw new ArgeoException("No Spring authentication found in "
- + subject);
- else
+ String userId = super.getUserID(subject, workspaceName);
+ if (authens.size() == 0) {
+ // make sure that logged-in user has a Principal, useful for testing
+ // using an admin user
+ UserManager systemUm = getSystemUserManager(null);
+ if (systemUm.getAuthorizable(userId) == null)
+ systemUm.createUser(userId, "");
+ } else {// Spring Security
authen = authens.iterator().next();
- // sync Spring and Jackrabbit
- syncSpringAndJackrabbitSecurity(authen);
+ if (!userId.equals(authen.getName()))
+ log.warn("User ID is '" + userId + "' but authen is "
+ + authen.getName());
+ StringBuffer roles = new StringBuffer("");
+ GrantedAuthority[] authorities = authen.getAuthorities();
+ for (GrantedAuthority ga : authorities) {
+ roles.append(ga.toString());
+ }
+
+ // do not sync if not changed
+ if (userRolesCache.containsKey(userId)
+ && userRolesCache.get(userId).equals(roles.toString()))
+ return userId;
- return authen.getName();
+ // sync Spring and Jackrabbit
+ // workspace is irrelevant here
+ UserManager systemUm = getSystemUserManager(null);
+ syncSpringAndJackrabbitSecurity(systemUm, authen);
+ userRolesCache.put(userId, roles.toString());
+ }
+ return userId;
}
/**
* Make sure that the Jackrabbit security model contains this user and its
* granted authorities
*/
- protected void syncSpringAndJackrabbitSecurity(Authentication authen)
- throws RepositoryException {
+ static private void syncSpringAndJackrabbitSecurity(UserManager systemUm,
+ Authentication authen) throws RepositoryException {
long begin = System.currentTimeMillis();
- // workspace is irrelevant here
- UserManager systemUm = getSystemUserManager(null);
-
String userId = authen.getName();
User user = (User) systemUm.getAuthorizable(userId);
if (user == null) {
user = systemUm.createUser(userId, authen.getCredentials()
.toString(), authen, null);
- // SecurityJcrUtils.createUserHomeIfNeeded(getSystemSession(),
- // userId);
- // getSystemSession().save();
- // setSecurityHomeAuthorizations(user);
log.info(userId + " added as " + user);
}
+ " ms");
}
- // protected synchronized void setSecurityHomeAuthorizations(User user) {
- // // give read privileges on user security home
- // String userId = "<not yet set>";
- // try {
- // userId = user.getID();
- // Node userHome = SecurityJcrUtils.getUserHome(getSystemSession(), userId);
- // if (userHome == null)
- // throw new ArgeoException("No security home available for user "
- // + userId);
- //
- // String path = userHome.getPath();
- // Principal principal = user.getPrincipal();
- //
- // JackrabbitAccessControlManager acm = (JackrabbitAccessControlManager)
- // getSystemSession()
- // .getAccessControlManager();
- // JackrabbitAccessControlPolicy[] ps = acm
- // .getApplicablePolicies(principal);
- // if (ps.length == 0) {
- // // log.warn("No ACL found for " + user);
- // return;
- // }
- //
- // JackrabbitAccessControlList list = (JackrabbitAccessControlList) ps[0];
- //
- // // add entry
- // Privilege[] privileges = new Privilege[] { acm
- // .privilegeFromName(Privilege.JCR_READ) };
- // Map<String, Value> restrictions = new HashMap<String, Value>();
- // ValueFactory vf = getSystemSession().getValueFactory();
- // restrictions.put("rep:nodePath",
- // vf.createValue(path, PropertyType.PATH));
- // restrictions.put("rep:glob", vf.createValue("*"));
- // list.addEntry(principal, privileges, true /* allow or deny */,
- // restrictions);
- // } catch (Exception e) {
- // e.printStackTrace();
- // throw new ArgeoException(
- // "Cannot set authorization on security home for " + userId
- // + ": " + e.getMessage());
- // }
- //
- // }
-
@Override
protected WorkspaceAccessManager createDefaultWorkspaceAccessManager() {
WorkspaceAccessManager wam = super
WorkspaceAccessManager {
private final WorkspaceAccessManager wam;
- // private String defaultWorkspace;
-
public ArgeoWorkspaceAccessManagerImpl(WorkspaceAccessManager wam) {
super();
this.wam = wam;
public void init(Session systemSession) throws RepositoryException {
wam.init(systemSession);
- // defaultWorkspace = ((RepositoryImpl) getRepository()).getConfig()
- // .getDefaultWorkspaceName();
}
public void close() throws RepositoryException {
public boolean grants(Set<Principal> principals, String workspaceName)
throws RepositoryException {
- // everybody has access to all workspaces
// TODO: implements finer access to workspaces
return true;
-
- // anonymous has access to the default workspace (required for
- // remoting which does a default login when initializing the
- // repository)
- // Boolean anonymous = false;
- // for (Principal principal : principals)
- // if (principal instanceof AnonymousPrincipal)
- // anonymous = true;
- //
- // if (anonymous && workspaceName.equals(defaultWorkspace))
- // return true;
- // else
- // return wam.grants(principals, workspaceName);
}
}