X-Git-Url: https://git.argeo.org/?a=blobdiff_plain;ds=sidebyside;f=security%2Fruntime%2Forg.argeo.security.jackrabbit%2Fsrc%2Fmain%2Fjava%2Forg%2Fargeo%2Fsecurity%2Fjackrabbit%2FArgeoSecurityManager.java;h=1109980696d61d110aab683ddbde53f937286d4b;hb=1d5afdce3e91054f07ddd3c98309c363b4cf1d46;hp=a3a6d42d6ee85f43969205bd7fdca6a13c38e301;hpb=10c220cf49f5b146bac50ed7fe2578135cd466f1;p=lgpl%2Fargeo-commons.git 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 a3a6d42d6..110998069 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 @@ -1,21 +1,51 @@ +/* + * Copyright (C) 2007-2012 Mathieu Baudier + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.argeo.security.jackrabbit; +import java.security.Principal; import java.util.ArrayList; +import java.util.HashMap; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Set; +import javax.jcr.Node; +import javax.jcr.PropertyType; import javax.jcr.RepositoryException; +import javax.jcr.Session; +import javax.jcr.Value; +import javax.jcr.ValueFactory; +import javax.jcr.security.Privilege; import javax.security.auth.Subject; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.jackrabbit.api.security.JackrabbitAccessControlList; +import org.apache.jackrabbit.api.security.JackrabbitAccessControlManager; +import org.apache.jackrabbit.api.security.JackrabbitAccessControlPolicy; 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.security.SystemPrincipal; +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.argeo.jcr.JcrUtils; import org.springframework.security.Authentication; import org.springframework.security.GrantedAuthority; @@ -23,13 +53,23 @@ import org.springframework.security.GrantedAuthority; public class ArgeoSecurityManager extends DefaultSecurityManager { private Log log = LogFactory.getLog(ArgeoSecurityManager.class); + /** + * Since this is called once when the session is created, we take the + * opportunity to make sure that Jackrabbit users and groups reflect Spring + * Security name and authorities. + */ @Override - /** Since this is called once when the session is created, we take the opportunity to synchronize Spring and Jackrabbit users and groups.*/ public String getUserID(Subject subject, String workspaceName) throws RepositoryException { long begin = System.currentTimeMillis(); - if (!subject.getPrincipals(SystemPrincipal.class).isEmpty()) + if (log.isTraceEnabled()) + log.trace(subject); + // skip anonymous user (no rights) + if (!subject.getPrincipals(AnonymousPrincipal.class).isEmpty()) + return super.getUserID(subject, workspaceName); + // skip Jackrabbit system user (all rights) + if (!subject.getPrincipals(ArgeoSystemPrincipal.class).isEmpty()) return super.getUserID(subject, workspaceName); Authentication authen; @@ -48,15 +88,18 @@ public class ArgeoSecurityManager extends DefaultSecurityManager { if (user == null) { user = systemUm.createUser(userId, authen.getCredentials() .toString(), authen, null); + JcrUtils.createUserHomeIfNeeded(getSystemSession(), userId); + getSystemSession().save(); + setSecurityHomeAuthorizations(user); log.info(userId + " added as " + user); } + // process groups List userGroupIds = new ArrayList(); 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)) @@ -71,10 +114,102 @@ public class ArgeoSecurityManager extends DefaultSecurityManager { group.removeMember(user); } - if (log.isDebugEnabled()) - log.debug("Spring and Jackrabbit Security synchronized for user " + if (log.isTraceEnabled()) + log.trace("Spring and Jackrabbit Security synchronized for user " + userId + " in " + (System.currentTimeMillis() - begin) + " ms"); return userId; } + + protected synchronized void setSecurityHomeAuthorizations(User user) { + // give read privileges on user security home + String userId = ""; + try { + userId = user.getID(); + Node userHome = JcrUtils.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 restrictions = new HashMap(); + 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 + .createDefaultWorkspaceAccessManager(); + return new ArgeoWorkspaceAccessManagerImpl(wam); + } + + private class ArgeoWorkspaceAccessManagerImpl implements SecurityConstants, + 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 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); + } + } + }