]> git.argeo.org Git - lgpl/argeo-commons.git/blob - security/runtime/org.argeo.security.jackrabbit/src/main/java/org/argeo/security/jackrabbit/ArgeoSecurityManager.java
Big cleanup of the security layers
[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.HashMap;
6 import java.util.Iterator;
7 import java.util.List;
8 import java.util.Map;
9 import java.util.Set;
10
11 import javax.jcr.Node;
12 import javax.jcr.PropertyType;
13 import javax.jcr.RepositoryException;
14 import javax.jcr.Session;
15 import javax.jcr.Value;
16 import javax.jcr.ValueFactory;
17 import javax.jcr.security.Privilege;
18 import javax.security.auth.Subject;
19
20 import org.apache.commons.logging.Log;
21 import org.apache.commons.logging.LogFactory;
22 import org.apache.jackrabbit.api.security.JackrabbitAccessControlList;
23 import org.apache.jackrabbit.api.security.JackrabbitAccessControlManager;
24 import org.apache.jackrabbit.api.security.JackrabbitAccessControlPolicy;
25 import org.apache.jackrabbit.api.security.user.Group;
26 import org.apache.jackrabbit.api.security.user.User;
27 import org.apache.jackrabbit.api.security.user.UserManager;
28 import org.apache.jackrabbit.core.DefaultSecurityManager;
29 import org.apache.jackrabbit.core.security.SecurityConstants;
30 import org.apache.jackrabbit.core.security.SystemPrincipal;
31 import org.apache.jackrabbit.core.security.authorization.WorkspaceAccessManager;
32 import org.argeo.ArgeoException;
33 import org.argeo.jcr.JcrUtils;
34 import org.springframework.security.Authentication;
35 import org.springframework.security.GrantedAuthority;
36
37 /** Intermediary class in order to have a consistent naming in config files. */
38 public class ArgeoSecurityManager extends DefaultSecurityManager {
39 private Log log = LogFactory.getLog(ArgeoSecurityManager.class);
40
41 @Override
42 /** Since this is called once when the session is created, we take the opportunity to synchronize Spring and Jackrabbit users and groups.*/
43 public String getUserID(Subject subject, String workspaceName)
44 throws RepositoryException {
45 long begin = System.currentTimeMillis();
46
47 // skip Jackrabbit system user
48 if (!subject.getPrincipals(SystemPrincipal.class).isEmpty())
49 return super.getUserID(subject, workspaceName);
50
51 Authentication authen;
52 Set<Authentication> authens = subject
53 .getPrincipals(Authentication.class);
54 if (authens.size() == 0)
55 throw new ArgeoException("No Spring authentication found in "
56 + subject);
57 else
58 authen = authens.iterator().next();
59
60 // skip argeo system authenticated
61 // if (authen instanceof SystemAuthentication)
62 // return super.getUserID(subject, workspaceName);
63
64 UserManager systemUm = getSystemUserManager(workspaceName);
65
66 String userId = authen.getName();
67 User user = (User) systemUm.getAuthorizable(userId);
68 if (user == null) {
69 user = systemUm.createUser(userId, authen.getCredentials()
70 .toString(), authen, null);
71 log.info(userId + " added as " + user);
72 }
73
74 //setHomeNodeAuthorizations(user);
75
76 // process groups
77 List<String> userGroupIds = new ArrayList<String>();
78 for (GrantedAuthority ga : authen.getAuthorities()) {
79 Group group = (Group) systemUm.getAuthorizable(ga.getAuthority());
80 if (group == null) {
81 group = systemUm.createGroup(ga.getAuthority());
82 log.info(ga.getAuthority() + " added as " + group);
83 }
84 if (!group.isMember(user))
85 group.addMember(user);
86 userGroupIds.add(ga.getAuthority());
87 }
88
89 // check if user has not been removed from some groups
90 for (Iterator<Group> it = user.declaredMemberOf(); it.hasNext();) {
91 Group group = it.next();
92 if (!userGroupIds.contains(group.getID()))
93 group.removeMember(user);
94 }
95
96 // write roles in profile for easy access
97 // if (!(authen instanceof SystemAuthentication)) {
98 // Node userProfile = JcrUtils.getUserProfile(getSystemSession(),
99 // userId);
100 // boolean writeRoles = false;
101 // if (userProfile.hasProperty(ArgeoNames.ARGEO_REMOTE_ROLES)) {
102 // Value[] roles = userProfile.getProperty(ArgeoNames.ARGEO_REMOTE_ROLES)
103 // .getValues();
104 // if (roles.length != userGroupIds.size())
105 // writeRoles = true;
106 // else
107 // for (int i = 0; i < roles.length; i++)
108 // if (!roles[i].getString().equals(userGroupIds.get(i)))
109 // writeRoles = true;
110 // } else
111 // writeRoles = true;
112 //
113 // if (writeRoles) {
114 // userProfile.getSession().getWorkspace().getVersionManager()
115 // .checkout(userProfile.getPath());
116 // String[] roleIds = userGroupIds.toArray(new String[userGroupIds
117 // .size()]);
118 // userProfile.setProperty(ArgeoNames.ARGEO_REMOTE_ROLES, roleIds);
119 // JcrUtils.updateLastModified(userProfile);
120 // userProfile.getSession().save();
121 // userProfile.getSession().getWorkspace().getVersionManager()
122 // .checkin(userProfile.getPath());
123 // }
124 // }
125
126 if (log.isTraceEnabled())
127 log.trace("Spring and Jackrabbit Security synchronized for user "
128 + userId + " in " + (System.currentTimeMillis() - begin)
129 + " ms");
130 return userId;
131 }
132
133 protected synchronized void setHomeNodeAuthorizations(User user) {
134 // give all privileges on user home
135 // FIXME: fails on an empty repo
136 String userId = "<not yet set>";
137 try {
138 userId = user.getID();
139 Node userHome = null;
140 try {
141 userHome = JcrUtils.getUserHome(getSystemSession(), userId);
142 if (userHome == null) {
143 userHome = JcrUtils.createUserHomeIfNeeded(getSystemSession(), userId);
144 //log.warn("No home available for user "+userId);
145 return;
146 }
147 } catch (Exception e) {
148 // silent
149 }
150
151 if (userHome != null) {
152 String path = userHome.getPath();
153 Principal principal = user.getPrincipal();
154
155 JackrabbitAccessControlManager acm = (JackrabbitAccessControlManager) getSystemSession()
156 .getAccessControlManager();
157 JackrabbitAccessControlPolicy[] ps = acm
158 .getApplicablePolicies(principal);
159 if (ps.length == 0) {
160 // log.warn("No ACL found for " + user);
161 return;
162 }
163
164 JackrabbitAccessControlList list = (JackrabbitAccessControlList) ps[0];
165
166 // add entry
167 Privilege[] privileges = new Privilege[] { acm
168 .privilegeFromName(Privilege.JCR_ALL) };
169 Map<String, Value> restrictions = new HashMap<String, Value>();
170 ValueFactory vf = getSystemSession().getValueFactory();
171 restrictions.put("rep:nodePath",
172 vf.createValue(path, PropertyType.PATH));
173 restrictions.put("rep:glob", vf.createValue("*"));
174 list.addEntry(principal, privileges, true /* allow or deny */,
175 restrictions);
176 }
177 } catch (Exception e) {
178 e.printStackTrace();
179 log.warn("Cannot set authorization on user node for " + userId
180 + ": " + e.getMessage());
181 }
182
183 }
184
185 @Override
186 protected WorkspaceAccessManager createDefaultWorkspaceAccessManager() {
187 WorkspaceAccessManager wam = super
188 .createDefaultWorkspaceAccessManager();
189 return new ArgeoWorkspaceAccessManagerImpl(wam);
190 }
191
192 private class ArgeoWorkspaceAccessManagerImpl implements SecurityConstants,
193 WorkspaceAccessManager {
194 private final WorkspaceAccessManager wam;
195
196 // private String defaultWorkspace;
197
198 public ArgeoWorkspaceAccessManagerImpl(WorkspaceAccessManager wam) {
199 super();
200 this.wam = wam;
201 }
202
203 public void init(Session systemSession) throws RepositoryException {
204 wam.init(systemSession);
205 // defaultWorkspace = ((RepositoryImpl) getRepository()).getConfig()
206 // .getDefaultWorkspaceName();
207 }
208
209 public void close() throws RepositoryException {
210 }
211
212 public boolean grants(Set<Principal> principals, String workspaceName)
213 throws RepositoryException {
214 // everybody has access to all workspaces
215 // TODO: implements finer access to workspaces
216 return true;
217
218 // anonymous has access to the default workspace (required for
219 // remoting which does a default login when initializing the
220 // repository)
221 // Boolean anonymous = false;
222 // for (Principal principal : principals)
223 // if (principal instanceof AnonymousPrincipal)
224 // anonymous = true;
225 //
226 // if (anonymous && workspaceName.equals(defaultWorkspace))
227 // return true;
228 // else
229 // return wam.grants(principals, workspaceName);
230 }
231 }
232
233 }