]> git.argeo.org Git - lgpl/argeo-commons.git/blob - security/runtime/org.argeo.security.jackrabbit/src/main/java/org/argeo/security/jackrabbit/ArgeoSecurityManager.java
244207bc59dd6f80cb838296cb3eece79531abd7
[lgpl/argeo-commons.git] / security / runtime / org.argeo.security.jackrabbit / src / main / java / org / argeo / security / jackrabbit / ArgeoSecurityManager.java
1 /*
2 * Copyright (C) 2007-2012 Mathieu Baudier
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.argeo.security.jackrabbit;
17
18 import java.security.Principal;
19 import java.util.ArrayList;
20 import java.util.Collections;
21 import java.util.HashMap;
22 import java.util.Iterator;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.Set;
26
27 import javax.jcr.RepositoryException;
28 import javax.jcr.Session;
29 import javax.security.auth.Subject;
30
31 import org.apache.commons.logging.Log;
32 import org.apache.commons.logging.LogFactory;
33 import org.apache.jackrabbit.api.security.user.Group;
34 import org.apache.jackrabbit.api.security.user.User;
35 import org.apache.jackrabbit.api.security.user.UserManager;
36 import org.apache.jackrabbit.core.DefaultSecurityManager;
37 import org.apache.jackrabbit.core.security.AnonymousPrincipal;
38 import org.apache.jackrabbit.core.security.SecurityConstants;
39 import org.apache.jackrabbit.core.security.authorization.WorkspaceAccessManager;
40 import org.argeo.ArgeoException;
41 import org.springframework.security.Authentication;
42 import org.springframework.security.GrantedAuthority;
43
44 /** Integrates Spring Security and Jackrabbit Security user and roles. */
45 public class ArgeoSecurityManager extends DefaultSecurityManager {
46 private final static Log log = LogFactory
47 .getLog(ArgeoSecurityManager.class);
48
49 /** TODO? use a bounded buffer */
50 private Map<String, String> userRolesCache = Collections
51 .synchronizedMap(new HashMap<String, String>());
52
53 /**
54 * Since this is called once when the session is created, we take the
55 * opportunity to make sure that Jackrabbit users and groups reflect Spring
56 * Security name and authorities.
57 */
58 @Override
59 public String getUserID(Subject subject, String workspaceName)
60 throws RepositoryException {
61 if (log.isTraceEnabled())
62 log.trace(subject);
63 // skip anonymous user (no rights)
64 if (!subject.getPrincipals(AnonymousPrincipal.class).isEmpty())
65 return super.getUserID(subject, workspaceName);
66 // skip Jackrabbit system user (all rights)
67 if (!subject.getPrincipals(ArgeoSystemPrincipal.class).isEmpty())
68 return super.getUserID(subject, workspaceName);
69
70 // retrieve Spring authentication from JAAS
71 // TODO? use Spring Security context holder
72 Authentication authen;
73 Set<Authentication> authens = subject
74 .getPrincipals(Authentication.class);
75 if (authens.size() == 0)
76 throw new ArgeoException("No Spring authentication found in "
77 + subject);
78 else
79 authen = authens.iterator().next();
80
81 String userId = authen.getName();
82 StringBuffer roles = new StringBuffer("");
83 GrantedAuthority[] authorities = authen.getAuthorities();
84 for (GrantedAuthority ga : authorities) {
85 roles.append(ga.toString());
86 }
87
88 // do not sync if not changed
89 if (userRolesCache.containsKey(userId)
90 && userRolesCache.get(userId).equals(roles.toString()))
91 return userId;
92
93 // sync Spring and Jackrabbit
94 // workspace is irrelevant here
95 UserManager systemUm = getSystemUserManager(null);
96 syncSpringAndJackrabbitSecurity(systemUm, authen);
97 userRolesCache.put(userId, roles.toString());
98
99 return userId;
100 }
101
102 /**
103 * Make sure that the Jackrabbit security model contains this user and its
104 * granted authorities
105 */
106 static void syncSpringAndJackrabbitSecurity(UserManager systemUm,
107 Authentication authen) throws RepositoryException {
108 long begin = System.currentTimeMillis();
109
110 String userId = authen.getName();
111 User user = (User) systemUm.getAuthorizable(userId);
112 if (user == null) {
113 user = systemUm.createUser(userId, authen.getCredentials()
114 .toString(), authen, null);
115 // SecurityJcrUtils.createUserHomeIfNeeded(getSystemSession(),
116 // userId);
117 // getSystemSession().save();
118 // setSecurityHomeAuthorizations(user);
119 log.info(userId + " added as " + user);
120 }
121
122 // process groups
123 List<String> userGroupIds = new ArrayList<String>();
124 for (GrantedAuthority ga : authen.getAuthorities()) {
125 Group group = (Group) systemUm.getAuthorizable(ga.getAuthority());
126 if (group == null) {
127 group = systemUm.createGroup(ga.getAuthority());
128 log.info(ga.getAuthority() + " added as " + group);
129 }
130 if (!group.isMember(user))
131 group.addMember(user);
132 userGroupIds.add(ga.getAuthority());
133 }
134
135 // check if user has not been removed from some groups
136 for (Iterator<Group> it = user.declaredMemberOf(); it.hasNext();) {
137 Group group = it.next();
138 if (!userGroupIds.contains(group.getID()))
139 group.removeMember(user);
140 }
141
142 if (log.isTraceEnabled())
143 log.trace("Spring and Jackrabbit Security synchronized for user "
144 + userId + " in " + (System.currentTimeMillis() - begin)
145 + " ms");
146 }
147
148 // protected synchronized void setSecurityHomeAuthorizations(User user) {
149 // // give read privileges on user security home
150 // String userId = "<not yet set>";
151 // try {
152 // userId = user.getID();
153 // Node userHome = SecurityJcrUtils.getUserHome(getSystemSession(), userId);
154 // if (userHome == null)
155 // throw new ArgeoException("No security home available for user "
156 // + userId);
157 //
158 // String path = userHome.getPath();
159 // Principal principal = user.getPrincipal();
160 //
161 // JackrabbitAccessControlManager acm = (JackrabbitAccessControlManager)
162 // getSystemSession()
163 // .getAccessControlManager();
164 // JackrabbitAccessControlPolicy[] ps = acm
165 // .getApplicablePolicies(principal);
166 // if (ps.length == 0) {
167 // // log.warn("No ACL found for " + user);
168 // return;
169 // }
170 //
171 // JackrabbitAccessControlList list = (JackrabbitAccessControlList) ps[0];
172 //
173 // // add entry
174 // Privilege[] privileges = new Privilege[] { acm
175 // .privilegeFromName(Privilege.JCR_READ) };
176 // Map<String, Value> restrictions = new HashMap<String, Value>();
177 // ValueFactory vf = getSystemSession().getValueFactory();
178 // restrictions.put("rep:nodePath",
179 // vf.createValue(path, PropertyType.PATH));
180 // restrictions.put("rep:glob", vf.createValue("*"));
181 // list.addEntry(principal, privileges, true /* allow or deny */,
182 // restrictions);
183 // } catch (Exception e) {
184 // e.printStackTrace();
185 // throw new ArgeoException(
186 // "Cannot set authorization on security home for " + userId
187 // + ": " + e.getMessage());
188 // }
189 //
190 // }
191
192 @Override
193 protected WorkspaceAccessManager createDefaultWorkspaceAccessManager() {
194 WorkspaceAccessManager wam = super
195 .createDefaultWorkspaceAccessManager();
196 return new ArgeoWorkspaceAccessManagerImpl(wam);
197 }
198
199 private class ArgeoWorkspaceAccessManagerImpl implements SecurityConstants,
200 WorkspaceAccessManager {
201 private final WorkspaceAccessManager wam;
202
203 // private String defaultWorkspace;
204
205 public ArgeoWorkspaceAccessManagerImpl(WorkspaceAccessManager wam) {
206 super();
207 this.wam = wam;
208 }
209
210 public void init(Session systemSession) throws RepositoryException {
211 wam.init(systemSession);
212 // defaultWorkspace = ((RepositoryImpl) getRepository()).getConfig()
213 // .getDefaultWorkspaceName();
214 }
215
216 public void close() throws RepositoryException {
217 }
218
219 public boolean grants(Set<Principal> principals, String workspaceName)
220 throws RepositoryException {
221 // everybody has access to all workspaces
222 // TODO: implements finer access to workspaces
223 return true;
224
225 // anonymous has access to the default workspace (required for
226 // remoting which does a default login when initializing the
227 // repository)
228 // Boolean anonymous = false;
229 // for (Principal principal : principals)
230 // if (principal instanceof AnonymousPrincipal)
231 // anonymous = true;
232 //
233 // if (anonymous && workspaceName.equals(defaultWorkspace))
234 // return true;
235 // else
236 // return wam.grants(principals, workspaceName);
237 }
238 }
239
240 }