if (SecurityContextHolder.getContext().getAuthentication() != null)
return super.login();
+ // reset all principals and credentials
+ if (log.isTraceEnabled())
+ log.trace("Resetting all principals and credentials of " + subject);
+ if (subject.getPrincipals() != null)
+ subject.getPrincipals().clear();
+ if (subject.getPrivateCredentials() != null)
+ subject.getPrivateCredentials().clear();
+ if (subject.getPublicCredentials() != null)
+ subject.getPublicCredentials().clear();
+
// ask for username and password
Callback label = new TextOutputCallback(TextOutputCallback.INFORMATION,
"Required login");
@Override
public boolean logout() throws LoginException {
-// if (log.isDebugEnabled())
-// log.debug("logout subject=" + subject);
+ // if (log.isDebugEnabled())
+ // log.debug("logout subject=" + subject);
return super.logout();
}
public void deleteUser(String username);
+ /** Synchronize with the underlying DAO. */
+ public void synchronize();
+
/*
* ROLES
*/
userAdminDao.createUser(user);
}
+
+
+
+ public void synchronize() {
+ // TODO Auto-generated method stub
+
+ }
public ArgeoUser getUser(String username) {
return userAdminDao.getUser(username);
import org.argeo.jcr.ThreadBoundJcrSessionFactory;
import org.springframework.security.Authentication;
import org.springframework.security.context.SecurityContextHolder;
+import org.springframework.security.userdetails.UserDetails;
public class SecureThreadBoundSession extends ThreadBoundJcrSessionFactory {
private final static Log log = LogFactory
Authentication authentication = SecurityContextHolder.getContext()
.getAuthentication();
if (authentication != null) {
- if (!session.getUserID().equals(
- authentication.getPrincipal().toString())) {
- log.warn("Current session has user ID " + session.getUserID()
- + " while authentication is " + authentication
- + ". Re-login.");
- return login();
+ String userID = session.getUserID();
+ UserDetails userDetails = (UserDetails) authentication.getDetails();
+ if (userDetails != null) {
+ String currentUserName = userDetails.getUsername();
+ if (!userID.equals(currentUserName)) {
+ log.warn("Current session has user ID " + userID
+ + " while logged is user is " + currentUserName
+ + "(authentication=" + authentication + ")"
+ + ". Re-login.");
+ return login();
+ }
}
}
return super.preCall(session);
package org.argeo.security.jackrabbit;
+import javax.jcr.PathNotFoundException;
import javax.jcr.RepositoryException;
+import javax.jcr.security.Privilege;
+import org.apache.jackrabbit.core.id.ItemId;
import org.apache.jackrabbit.core.security.DefaultAccessManager;
+import org.apache.jackrabbit.spi.Path;
/** Intermediary class in order to have a consistent naming in config files. */
public class ArgeoAccessManager extends DefaultAccessManager {
@Override
- public boolean canAccess(String workspaceName) throws RepositoryException {
+ public boolean canRead(Path itemPath, ItemId itemId)
+ throws RepositoryException {
// TODO Auto-generated method stub
- return super.canAccess(workspaceName);
+ return super.canRead(itemPath, itemId);
+ }
+
+ @Override
+ public Privilege[] getPrivileges(String absPath)
+ throws PathNotFoundException, RepositoryException {
+ // TODO Auto-generated method stub
+ return super.getPrivileges(absPath);
+ }
+
+ @Override
+ public boolean hasPrivileges(String absPath, Privilege[] privileges)
+ throws PathNotFoundException, RepositoryException {
+ // TODO Auto-generated method stub
+ return super.hasPrivileges(absPath, privileges);
}
}
principals.add(new AnonymousPrincipal());
else
for (GrantedAuthority ga : authen.getAuthorities()) {
+ principals.add(new GrantedAuthorityPrincipal(ga));
// FIXME: make it more generic
if (adminRole.equals(ga.getAuthority()))
principals.add(new AdminPrincipal(authen.getName()));
*/
@Override
public boolean logout() throws LoginException {
- Set<AdminPrincipal> adminPrincipals = subject
- .getPrincipals(AdminPrincipal.class);
- Set<AnonymousPrincipal> anonymousPrincipals = subject
- .getPrincipals(AnonymousPrincipal.class);
+ clearPrincipals(AdminPrincipal.class);
+ clearPrincipals(AnonymousPrincipal.class);
+ clearPrincipals(GrantedAuthorityPrincipal.class);
Set<SimpleCredentials> thisCredentials = subject
.getPublicCredentials(SimpleCredentials.class);
if (thisCredentials != null)
thisCredentials.clear();
- if (adminPrincipals != null)
- adminPrincipals.clear();
- if (anonymousPrincipals != null)
- anonymousPrincipals.clear();
return true;
}
+ private <T extends Principal> void clearPrincipals(Class<T> clss) {
+ Set<T> principals = subject.getPrincipals(clss);
+ if (principals != null)
+ principals.clear();
+ }
+
@SuppressWarnings("rawtypes")
@Override
protected void doInit(CallbackHandler callbackHandler, Session session,
import java.util.List;
import java.util.Set;
+import javax.jcr.AccessDeniedException;
+import javax.jcr.Node;
+import javax.jcr.PathNotFoundException;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
+import javax.jcr.UnsupportedRepositoryOperationException;
+import javax.jcr.lock.LockException;
+import javax.jcr.security.AccessControlException;
+import javax.jcr.security.AccessControlList;
+import javax.jcr.security.AccessControlManager;
+import javax.jcr.security.AccessControlPolicy;
+import javax.jcr.security.AccessControlPolicyIterator;
+import javax.jcr.security.Privilege;
+import javax.jcr.version.VersionException;
import javax.security.auth.Subject;
import org.apache.commons.logging.Log;
import org.apache.jackrabbit.core.security.SystemPrincipal;
import org.apache.jackrabbit.core.security.authorization.WorkspaceAccessManager;
import org.argeo.ArgeoException;
+import org.argeo.jcr.JcrUtils;
import org.springframework.security.Authentication;
import org.springframework.security.GrantedAuthority;
.toString(), authen, null);
log.info(userId + " added as " + user);
}
+
+ setHomeNodeAuthorizations(user);
+ // process groups
List<String> userGroupIds = new ArrayList<String>();
for (GrantedAuthority ga : authen.getAuthorities()) {
Group group = (Group) systemUm.getAuthorizable(ga.getAuthority());
if (group == null) {
- group = systemUm.createGroup(ga.getAuthority(),
- new GrantedAuthorityPrincipal(ga), null);
+ group = systemUm.createGroup(ga.getAuthority());
log.info(ga.getAuthority() + " added as " + group);
}
if (!group.isMember(user))
group.addMember(user);
userGroupIds.add(ga.getAuthority());
+
}
// check if user has not been removed from some groups
return userId;
}
+ protected void setHomeNodeAuthorizations(User user) {
+ // give all privileges on user home
+ // FIXME: fails on an empty repo
+ String userId = "<not yet set>";
+ try {
+ userId = user.getID();
+ Node userHome = JcrUtils.getUserHome(getSystemSession(), userId);
+ if (userHome != null) {
+ String path = userHome.getPath();
+ AccessControlPolicy policy = null;
+ AccessControlManager acm = getSystemSession()
+ .getAccessControlManager();
+ AccessControlPolicyIterator policyIterator = acm
+ .getApplicablePolicies(path);
+ if (policyIterator.hasNext()) {
+ policy = policyIterator.nextAccessControlPolicy();
+ } else {
+ AccessControlPolicy[] existingPolicies = acm
+ .getPolicies(path);
+ policy = existingPolicies[0];
+ }
+ if (policy instanceof AccessControlList) {
+ Privilege[] privileges = { acm
+ .privilegeFromName(Privilege.JCR_ALL) };
+ ((AccessControlList) policy).addAccessControlEntry(
+ user.getPrincipal(), privileges);
+ acm.setPolicy(path, policy);
+ }
+ }
+ } catch (Exception e) {
+ log.warn("Cannot set authorization on user node for " + userId
+ + ": " + e.getMessage());
+ }
+
+ }
+
@Override
protected WorkspaceAccessManager createDefaultWorkspaceAccessManager() {
WorkspaceAccessManager wam = super
private class ArgeoWorkspaceAccessManagerImpl implements SecurityConstants,
WorkspaceAccessManager {
private final WorkspaceAccessManager wam;
- //private String defaultWorkspace;
+
+ // private String defaultWorkspace;
public ArgeoWorkspaceAccessManagerImpl(WorkspaceAccessManager wam) {
super();
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 {
import org.springframework.security.GrantedAuthority;
-/** Wraps a {@link GrantedAuthority} as a prin,cipal. */
+/** Wraps a {@link GrantedAuthority} as a principal. */
class GrantedAuthorityPrincipal implements Principal {
private final GrantedAuthority grantedAuthority;
import java.util.concurrent.Executor;
import javax.jcr.Node;
+import javax.jcr.Property;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.nodetype.NodeType;
public UserDetails mapUserFromContext(final DirContextOperations ctx,
final String username, GrantedAuthority[] authorities) {
- // if (repository == null)
- // throw new ArgeoException("No JCR repository registered");
final StringBuffer userHomePathT = new StringBuffer("");
Runnable action = new Runnable() {
public void run() {
/** @return path to the user home node */
protected String mapLdapToJcr(String username, DirContextOperations ctx) {
- // Session session = null;
try {
- // Repository nodeRepo = JcrUtils.getRepositoryByAlias(
- // repositoryFactory, ArgeoJcrConstants.ALIAS_NODE);
- // session = nodeRepo.login();
Node userHome = JcrUtils.getUserHome(session, username);
if (userHome == null)
userHome = JcrUtils.createUserHome(session, homeBasePath,
userProfile.addMixin(NodeType.MIX_CREATED);
userProfile.addMixin(NodeType.MIX_LAST_MODIFIED);
}
+
for (String jcrProperty : propertyToAttributes.keySet())
ldapToJcr(userProfile, jcrProperty, ctx);
+
+ // assign default values
+ if (!userProfile.hasProperty(Property.JCR_DESCRIPTION))
+ userProfile.setProperty(Property.JCR_DESCRIPTION, "");
+ if (!userProfile.hasProperty(Property.JCR_TITLE))
+ userProfile.setProperty(Property.JCR_TITLE, userProfile
+ .getProperty(ARGEO_FIRST_NAME).getString()
+ + " "
+ + userProfile.getProperty(ARGEO_LAST_NAME).getString());
+
session.save();
- if (log.isDebugEnabled())
- log.debug("Mapped " + ctx.getDn() + " to " + userProfile);
+ if (log.isTraceEnabled())
+ log.trace("Mapped " + ctx.getDn() + " to " + userProfile);
return userHomePath;
} catch (Exception e) {
JcrUtils.discardQuietly(session);
throw new ArgeoException("Cannot synchronize JCR and LDAP", e);
- } finally {
- // JcrUtils.logoutQuietly(session);
}
}
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_PROFILE);
for (String jcrProperty : propertyToAttributes.keySet())
jcrToLdap(userProfile, jcrProperty, ctx);
- if (log.isDebugEnabled())
- log.debug("Mapped " + userProfile + " to " + ctx.getDn());
+
+ if (log.isTraceEnabled())
+ log.trace("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) {
protected void jcrToLdap(Node userProfile, String jcrProperty,
DirContextOperations ctx) {
try {
- if (!userProfile.hasProperty(jcrProperty))
- return;
- String value = userProfile.getProperty(jcrProperty).getString();
-
String ldapAttribute;
if (propertyToAttributes.containsKey(jcrProperty))
ldapAttribute = propertyToAttributes.get(jcrProperty);
throw new ArgeoException(
"No LDAP attribute mapped for JCR proprty "
+ jcrProperty);
+
+ // fix issue with empty 'sn' in LDAP
+ if (ldapAttribute.equals("sn")
+ && (!userProfile.hasProperty(jcrProperty) || userProfile
+ .getProperty(jcrProperty).getString().trim()
+ .equals("")))
+ userProfile.setProperty(jcrProperty, "empty");
+
+ if (!userProfile.hasProperty(jcrProperty))
+ return;
+ String value = userProfile.getProperty(jcrProperty).getString();
+
ctx.setAttributeValue(ldapAttribute, value);
} catch (Exception e) {
throw new ArgeoException("Cannot map JCR property " + jcrProperty
this.homeBasePath = homeBasePath;
}
- // public void register(RepositoryFactory repositoryFactory,
- // Map<String, String> parameters) {
- // this.repositoryFactory = repositoryFactory;
- // }
- //
- // public void unregister(RepositoryFactory repositoryFactory,
- // Map<String, String> parameters) {
- // this.repositoryFactory = null;
- // }
-
public void setUsernameAttribute(String usernameAttribute) {
this.usernameAttribute = usernameAttribute;
}
<bean id="genericJcrQueryEditor"
class="org.argeo.eclipse.ui.jcr.editors.GenericJcrQueryEditor" scope="prototype">
- <property name="session" ref="jcrSession" />
</bean>
</beans>
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"\r
osgi:default-timeout="30000">\r
\r
- <reference id="nodeJcrSession" interface="javax.jcr.Session"\r
- filter="(argeo.jcr.repository.alias=node)" />\r
-\r
<set id="repositories" interface="javax.jcr.Repository">\r
<listener ref="repositoryRegister" bind-method="register"\r
unbind-method="unregister" />\r
--- /dev/null
+package org.argeo.jackrabbit;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Executor;
+
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.security.AccessControlList;
+import javax.jcr.security.AccessControlPolicy;
+import javax.jcr.security.AccessControlPolicyIterator;
+import javax.jcr.security.Privilege;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.jackrabbit.api.JackrabbitSession;
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlManager;
+import org.apache.jackrabbit.api.security.user.Group;
+import org.apache.jackrabbit.api.security.user.UserManager;
+import org.argeo.ArgeoException;
+import org.argeo.jcr.JcrUtils;
+
+public class JackrabbitAuthorizations {
+ private final static Log log = LogFactory
+ .getLog(JackrabbitAuthorizations.class);
+
+ private Repository repository;
+ private Executor systemExecutor;
+
+ /**
+ * key := privilege1,privilege2/path/to/node<br/>
+ * value := group1,group2
+ */
+ private Map<String, String> groupPrivileges = new HashMap<String, String>();
+
+ public void init() {
+ systemExecutor.execute(new Runnable() {
+ public void run() {
+ JackrabbitSession session = null;
+ try {
+ session = (JackrabbitSession) repository.login();
+ initAuthorizations(session);
+ } catch (Exception e) {
+ JcrUtils.discardQuietly(session);
+ } finally {
+ JcrUtils.logoutQuietly(session);
+ }
+ }
+ });
+ }
+
+ protected void initAuthorizations(JackrabbitSession session)
+ throws RepositoryException {
+ JackrabbitAccessControlManager acm = (JackrabbitAccessControlManager) session
+ .getAccessControlManager();
+ UserManager um = session.getUserManager();
+
+ for (String privileges : groupPrivileges.keySet()) {
+ String path = null;
+ int slashIndex = privileges.indexOf('/');
+ if (slashIndex == 0) {
+ throw new ArgeoException("Privilege " + privileges
+ + " badly formatted it starts with /");
+ } else if (slashIndex > 0) {
+ path = privileges.substring(slashIndex);
+ privileges = privileges.substring(0, slashIndex);
+ }
+
+ if (path == null)
+ path = "/";
+
+ List<Privilege> privs = new ArrayList<Privilege>();
+ for (String priv : privileges.split(",")) {
+ privs.add(acm.privilegeFromName(priv));
+ }
+
+ String groupNames = groupPrivileges.get(privileges);
+ for (String groupName : groupNames.split(",")) {
+ Group group = (Group) um.getAuthorizable(groupName);
+ if (group == null)
+ group = um.createGroup(groupName);
+
+ AccessControlPolicy policy = null;
+ AccessControlPolicyIterator policyIterator = acm
+ .getApplicablePolicies(path);
+ if (policyIterator.hasNext()) {
+ policy = policyIterator.nextAccessControlPolicy();
+ } else {
+ AccessControlPolicy[] existingPolicies = acm
+ .getPolicies(path);
+ policy = existingPolicies[0];
+ }
+ if (policy instanceof AccessControlList) {
+ ((AccessControlList) policy).addAccessControlEntry(
+ group.getPrincipal(),
+ privs.toArray(new Privilege[privs.size()]));
+ acm.setPolicy(path, policy);
+ }
+ if (log.isDebugEnabled())
+ log.debug("Added privileges " + privileges + " to "
+ + groupName + " on " + path);
+ }
+ }
+ session.save();
+ }
+
+ public void setGroupPrivileges(Map<String, String> groupPrivileges) {
+ this.groupPrivileges = groupPrivileges;
+ }
+
+ public void setRepository(Repository repository) {
+ this.repository = repository;
+ }
+
+ public void setSystemExecutor(Executor systemExecutor) {
+ this.systemExecutor = systemExecutor;
+ }
+
+}
else
action.run();
}
-
+
public void destroy() throws Exception {
if (repository != null) {
if (repository instanceof JackrabbitRepository)
threadSession = login();
}
+ preCall(threadSession);
Object ret = method.invoke(threadSession, args);
if ("logout".equals(method.getName())) {
session.remove();