]> git.argeo.org Git - lgpl/argeo-commons.git/blob - security/runtime/org.argeo.security.jackrabbit/src/main/java/org/argeo/security/jackrabbit/ArgeoSecurityManager.java
Improve RCP security
[lgpl/argeo-commons.git] / security / runtime / org.argeo.security.jackrabbit / src / main / java / org / argeo / security / jackrabbit / ArgeoSecurityManager.java
1 package org.argeo.security.jackrabbit;
2
3 import java.security.Principal;
4 import java.util.ArrayList;
5 import java.util.Iterator;
6 import java.util.List;
7 import java.util.Set;
8
9 import javax.jcr.Node;
10 import javax.jcr.RepositoryException;
11 import javax.jcr.Session;
12 import javax.jcr.security.AccessControlList;
13 import javax.jcr.security.AccessControlManager;
14 import javax.jcr.security.AccessControlPolicy;
15 import javax.jcr.security.AccessControlPolicyIterator;
16 import javax.jcr.security.Privilege;
17 import javax.security.auth.Subject;
18
19 import org.apache.commons.logging.Log;
20 import org.apache.commons.logging.LogFactory;
21 import org.apache.jackrabbit.api.security.user.Group;
22 import org.apache.jackrabbit.api.security.user.User;
23 import org.apache.jackrabbit.api.security.user.UserManager;
24 import org.apache.jackrabbit.core.DefaultSecurityManager;
25 import org.apache.jackrabbit.core.security.SecurityConstants;
26 import org.apache.jackrabbit.core.security.SystemPrincipal;
27 import org.apache.jackrabbit.core.security.authorization.WorkspaceAccessManager;
28 import org.argeo.ArgeoException;
29 import org.argeo.jcr.JcrUtils;
30 import org.springframework.security.Authentication;
31 import org.springframework.security.GrantedAuthority;
32
33 /** Intermediary class in order to have a consistent naming in config files. */
34 public class ArgeoSecurityManager extends DefaultSecurityManager {
35 public final static String HOME_BASE_PATH = "/home";
36
37 private Log log = LogFactory.getLog(ArgeoSecurityManager.class);
38
39 @Override
40 /** Since this is called once when the session is created, we take the opportunity to synchronize Spring and Jackrabbit users and groups.*/
41 public String getUserID(Subject subject, String workspaceName)
42 throws RepositoryException {
43 long begin = System.currentTimeMillis();
44
45 if (!subject.getPrincipals(SystemPrincipal.class).isEmpty())
46 return super.getUserID(subject, workspaceName);
47
48 Authentication authen;
49 Set<Authentication> authens = subject
50 .getPrincipals(Authentication.class);
51 if (authens.size() == 0)
52 throw new ArgeoException("No Spring authentication found in "
53 + subject);
54 else
55 authen = authens.iterator().next();
56
57 UserManager systemUm = getSystemUserManager(workspaceName);
58
59 String userId = authen.getName();
60 User user = (User) systemUm.getAuthorizable(userId);
61 if (user == null) {
62 user = systemUm.createUser(userId, authen.getCredentials()
63 .toString(), authen, null);
64 log.info(userId + " added as " + user);
65 }
66
67 setHomeNodeAuthorizations(user);
68
69 // process groups
70 List<String> userGroupIds = new ArrayList<String>();
71 for (GrantedAuthority ga : authen.getAuthorities()) {
72 Group group = (Group) systemUm.getAuthorizable(ga.getAuthority());
73 if (group == null) {
74 group = systemUm.createGroup(ga.getAuthority());
75 log.info(ga.getAuthority() + " added as " + group);
76 }
77 if (!group.isMember(user))
78 group.addMember(user);
79 userGroupIds.add(ga.getAuthority());
80
81 }
82
83 // check if user has not been removed from some groups
84 for (Iterator<Group> it = user.declaredMemberOf(); it.hasNext();) {
85 Group group = it.next();
86 if (!userGroupIds.contains(group.getID()))
87 group.removeMember(user);
88 }
89
90 if (log.isTraceEnabled())
91 log.trace("Spring and Jackrabbit Security synchronized for user "
92 + userId + " in " + (System.currentTimeMillis() - begin)
93 + " ms");
94 return userId;
95 }
96
97 protected void setHomeNodeAuthorizations(User user) {
98 // give all privileges on user home
99 // FIXME: fails on an empty repo
100 String userId = "<not yet set>";
101 try {
102 userId = user.getID();
103 Node userHome = JcrUtils.getUserHome(getSystemSession(), userId);
104 // autocreate home node?
105 // if (userHome == null)
106 // userHome = JcrUtils.createUserHome(getSystemSession(),
107 // HOME_BASE_PATH, userId);
108
109 if (userHome != null) {
110 String path = userHome.getPath();
111 AccessControlPolicy policy = null;
112 AccessControlManager acm = getSystemSession()
113 .getAccessControlManager();
114 AccessControlPolicyIterator policyIterator = acm
115 .getApplicablePolicies(path);
116 if (policyIterator.hasNext()) {
117 policy = policyIterator.nextAccessControlPolicy();
118 } else {
119 AccessControlPolicy[] existingPolicies = acm
120 .getPolicies(path);
121 policy = existingPolicies[0];
122 }
123 if (policy instanceof AccessControlList) {
124 Privilege[] privileges = { acm
125 .privilegeFromName(Privilege.JCR_ALL) };
126 ((AccessControlList) policy).addAccessControlEntry(
127 user.getPrincipal(), privileges);
128 acm.setPolicy(path, policy);
129 }
130 }
131 } catch (Exception e) {
132 log.warn("Cannot set authorization on user node for " + userId
133 + ": " + e.getMessage());
134 }
135
136 }
137
138 @Override
139 protected WorkspaceAccessManager createDefaultWorkspaceAccessManager() {
140 WorkspaceAccessManager wam = super
141 .createDefaultWorkspaceAccessManager();
142 return new ArgeoWorkspaceAccessManagerImpl(wam);
143 }
144
145 private class ArgeoWorkspaceAccessManagerImpl implements SecurityConstants,
146 WorkspaceAccessManager {
147 private final WorkspaceAccessManager wam;
148
149 // private String defaultWorkspace;
150
151 public ArgeoWorkspaceAccessManagerImpl(WorkspaceAccessManager wam) {
152 super();
153 this.wam = wam;
154 }
155
156 public void init(Session systemSession) throws RepositoryException {
157 wam.init(systemSession);
158 // defaultWorkspace = ((RepositoryImpl) getRepository()).getConfig()
159 // .getDefaultWorkspaceName();
160 }
161
162 public void close() throws RepositoryException {
163 }
164
165 public boolean grants(Set<Principal> principals, String workspaceName)
166 throws RepositoryException {
167 // everybody has access to all workspaces
168 // TODO: implements finer access to workspaces
169 return true;
170
171 // anonymous has access to the default workspace (required for
172 // remoting which does a default login when initializing the
173 // repository)
174 // Boolean anonymous = false;
175 // for (Principal principal : principals)
176 // if (principal instanceof AnonymousPrincipal)
177 // anonymous = true;
178 //
179 // if (anonymous && workspaceName.equals(defaultWorkspace))
180 // return true;
181 // else
182 // return wam.grants(principals, workspaceName);
183 }
184 }
185
186 }