1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.cms.security;
35
36 import static info.magnolia.cms.security.SecurityConstants.NODE_GROUPS;
37 import static info.magnolia.cms.security.SecurityConstants.NODE_ROLES;
38 import info.magnolia.cms.core.Content;
39 import info.magnolia.context.MgnlContext;
40 import info.magnolia.jcr.iterator.FilteringPropertyIterator;
41 import info.magnolia.jcr.predicate.JCRMgnlPropertyHidingPredicate;
42 import info.magnolia.repository.RepositoryConstants;
43
44 import java.io.Serializable;
45 import java.util.ArrayList;
46 import java.util.Calendar;
47 import java.util.Collection;
48 import java.util.Collections;
49 import java.util.List;
50 import java.util.Map;
51 import java.util.Set;
52 import java.util.TreeSet;
53
54 import javax.jcr.ItemNotFoundException;
55 import javax.jcr.Node;
56 import javax.jcr.Property;
57 import javax.jcr.PropertyIterator;
58 import javax.jcr.RepositoryException;
59 import javax.jcr.Session;
60
61 import org.apache.commons.lang.StringUtils;
62 import org.apache.jackrabbit.util.ISO8601;
63 import org.slf4j.Logger;
64 import org.slf4j.LoggerFactory;
65
66
67
68
69
70
71
72
73
74 public class MgnlUser extends AbstractUser implements User, Serializable {
75
76 private static final long serialVersionUID = 222L;
77
78 private static final Logger log = LoggerFactory.getLogger(MgnlUser.class);
79
80 private final Map<String, String> properties;
81 private final Collection<String> groups;
82 private final Collection<String> roles;
83
84 private final String name;
85 private final String language;
86 private final String encodedPassword;
87 private boolean enabled = true;
88 private String path;
89 private String uuid;
90
91 private final String realm;
92
93
94 public MgnlUser(String name, String realm, Collection<String> groups, Collection<String> roles, Map<String, String> properties) {
95 this.name = name;
96 this.roles = Collections.unmodifiableCollection(roles);
97 this.groups = Collections.unmodifiableCollection(groups);
98 this.properties = Collections.unmodifiableMap(properties);
99 this.realm = realm;
100
101
102 language = properties.get(MgnlUserManager.PROPERTY_LANGUAGE);
103 String enbld = properties.get(MgnlUserManager.PROPERTY_ENABLED);
104
105 enabled = enbld == null ? true : Boolean.parseBoolean(properties.get(MgnlUserManager.PROPERTY_ENABLED));
106 encodedPassword = properties.get(MgnlUserManager.PROPERTY_PASSWORD);
107 }
108
109 public MgnlUser(String name, String realm, Collection<String> groups, Collection<String> roles, Map<String, String> properties, String path, String uuid) {
110 this(name,realm,groups,roles,properties);
111 this.path = path;
112 this.uuid = uuid;
113 }
114
115
116
117
118
119
120 @Override
121 public boolean inGroup(String groupName) {
122 log.debug("inGroup({})", groupName);
123 return this.hasAny(groupName, NODE_GROUPS);
124 }
125
126
127
128
129
130 @Override
131 public void removeGroup(String groupName) throws UnsupportedOperationException {
132 log.debug("removeGroup({})", groupName);
133 throw new UnsupportedOperationException("use manager to remove groups!");
134 }
135
136
137
138
139
140 @Override
141 public void addGroup(String groupName) throws UnsupportedOperationException {
142 log.debug("addGroup({})", groupName);
143 throw new UnsupportedOperationException("use manager to add groups!");
144 }
145
146 @Override
147 public boolean isEnabled() {
148 log.debug("isEnabled()");
149 return enabled ;
150 }
151
152
153
154
155
156 @Override
157 @Deprecated
158 public void setEnabled(boolean enabled) {
159 log.debug("setEnabled({})", enabled);
160 throw new UnsupportedOperationException("use manager to enable user!");
161 }
162
163
164
165
166
167
168 @Override
169 public boolean hasRole(String roleName) {
170 return SecuritySupport.Factory.getInstance().getUserManager(getRealm()).hasAny(getName(), roleName, NODE_ROLES);
171 }
172
173 @Override
174 public void removeRole(String roleName) throws UnsupportedOperationException {
175 log.debug("removeRole({})", roleName);
176 throw new UnsupportedOperationException("use manager to remove roles!");
177 }
178
179 @Override
180 public void addRole(String roleName) throws UnsupportedOperationException {
181 log.debug("addRole({})", roleName);
182 throw new UnsupportedOperationException("use manager to add roles!");
183 }
184
185
186
187
188
189
190
191 private boolean hasAny(final String groupOrRoleName, final String groupOrRole) {
192 long start = System.currentTimeMillis();
193 try {
194 final String workspaceName = StringUtils.equalsIgnoreCase(groupOrRole, NODE_ROLES) ? RepositoryConstants.USER_ROLES : RepositoryConstants.USER_GROUPS;
195
196
197 final Collection<String> groupsOrRoles = MgnlContext.doInSystemContext(new SilentSessionOp<Collection<String>>(RepositoryConstants.USERS) {
198
199 @Override
200 public Collection<String> doExec(Session session) throws RepositoryException {
201 List<String> list = new ArrayList<String>();
202 if (!session.getNode(getPath()).hasNode(groupOrRole)) {
203 return list;
204 }
205 Node groupsOrRoles = session.getNode(getPath()).getNode(groupOrRole);
206 for (PropertyIterator props = new FilteringPropertyIterator(groupsOrRoles.getProperties(), new JCRMgnlPropertyHidingPredicate()); props.hasNext();) {
207
208 Property property = props.nextProperty();
209 try {
210 list.add(property.getString());
211 } catch (ItemNotFoundException e) {
212 log.debug("Role or group [{}] does not exist in the ROLES/GROUPS workspace", groupOrRoleName);
213 } catch (IllegalArgumentException e) {
214 log.debug("{} has invalid value", property.getPath());
215 }
216 }
217 return list;
218 }});
219
220
221 return MgnlContext.doInSystemContext(new JCRSessionOp<Boolean>(workspaceName) {
222
223 @Override
224 public Boolean exec(Session session) throws RepositoryException {
225 for (String groupOrRole : groupsOrRoles) {
226
227 try {
228 if (session.getNodeByIdentifier(groupOrRole).getName().equalsIgnoreCase(groupOrRoleName)) {
229 return true;
230 }
231 } catch (RepositoryException e) {
232 log.debug("Role or group [{}] does not exist in the ROLES/GROUPS workspace", groupOrRoleName);
233 }
234 }
235 return false;
236 }});
237
238 } catch (Exception e) {
239 log.error("Exception when trying to read " + groupOrRole, e);
240 } finally {
241 log.debug("checked {} for {} in {}ms.", new Object[] {groupOrRoleName, groupOrRole, (System.currentTimeMillis() - start)});
242 }
243 return false;
244 }
245
246 public int getFailedLoginAttempts(){
247 try{
248 return Integer.valueOf(this.properties.get("failedLoginAttempts"));
249 }catch(Exception e){
250 return 0;
251 }
252 }
253
254 public Calendar getReleaseTime(){
255 try{
256 return ISO8601.parse(this.properties.get("releaseTime"));
257 }catch(Exception e){
258 return null;
259 }
260 }
261
262 @Override
263 public String getName() {
264 log.debug("getName()=>{}", name);
265 return name;
266 }
267
268 @Override
269 public String getPassword() {
270 return encodedPassword;
271 }
272
273 @Deprecated
274
275
276
277 protected String decodePassword(String encodedPassword) {
278 throw new UnsupportedOperationException();
279 }
280
281 @Override
282 public String getLanguage() {
283 log.debug("getLang()=>{}", language);
284 return this.language;
285 }
286
287 @Override
288 public String getProperty(String propertyName) {
289 log.debug("getProperty({})", propertyName);
290 return properties.get(propertyName);
291 }
292
293 @Override
294 public Collection<String> getGroups() {
295 log.debug("getGroups()");
296 return groups;
297 }
298
299 @Override
300 public Collection<String> getAllGroups() {
301
302
303 log.debug("get groups for {}", getName());
304
305 final Set<String> allGroups = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
306 final Collection<String> groups = getGroups();
307
308
309 GroupManager man = SecuritySupport.Factory.getInstance().getGroupManager();
310
311
312 addSubgroups(allGroups, man, groups);
313
314 return allGroups;
315 }
316
317 @Override
318 public Collection<String> getRoles() {
319 log.debug("getRoles()");
320 return roles;
321 }
322
323 @Override
324 public Collection<String> getAllRoles() {
325
326 log.debug("get roles for {}", getName());
327
328 final Set<String> allRoles = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
329 final Collection<String> roles = getRoles();
330
331
332 allRoles.addAll(roles);
333
334 Collection<String> allGroups = getAllGroups();
335
336
337 GroupManager man = SecuritySupport.Factory.getInstance().getGroupManager();
338
339
340 for (String group : allGroups) {
341 try {
342 allRoles.addAll(man.getGroup(group).getRoles());
343 } catch (AccessDeniedException e) {
344 log.debug("Skipping denied group " + group + " for user " + getName(), e);
345 } catch (UnsupportedOperationException e) {
346 log.debug("Skipping unsupported getGroup() for group " + group + " and user " + getName(), e);
347 }
348 }
349 return allRoles;
350 }
351
352 public String getPath() {
353 return this.path;
354 }
355
356 @Deprecated
357 public void setPath(String path) {
358 this.path = path;
359 }
360
361
362
363
364 private void addSubgroups(final Set<String> allGroups, GroupManager man, Collection<String> groups) {
365 for (String groupName : groups) {
366
367 if (!allGroups.contains(groupName)) {
368 allGroups.add(groupName);
369 try {
370 Group group = man.getGroup(groupName);
371 if (group == null) {
372 log.error("Failed to resolve group {} for user {}.", groupName, name);
373 continue;
374 }
375 Collection<String> subgroups = group.getGroups();
376
377 addSubgroups(allGroups, man, subgroups);
378 } catch (AccessDeniedException e) {
379 log.debug("Skipping denied group " + groupName + " for user " + getName(), e);
380 } catch (UnsupportedOperationException e) {
381 log.debug("Skipping unsupported getGroup() for group " + groupName + " and user " + getName(), e);
382 }
383
384 }
385 }
386 }
387
388 public String getRealm() {
389 return realm;
390 }
391
392
393
394
395
396 @Deprecated
397 public void setLastAccess() {
398 throw new UnsupportedOperationException("Use manager to update user details.");
399 }
400
401
402
403
404
405 @Deprecated
406 public Content getUserNode() {
407 throw new UnsupportedOperationException("Underlying storage node is no longer exposed nor required for custom user stores.");
408 }
409
410
411
412
413 @Override
414 @Deprecated
415 public void setProperty(String propertyName, String value) {
416 throw new UnsupportedOperationException("Use manager to modify properties of the user.");
417 }
418
419 @Override
420 public String getIdentifier() {
421 return uuid;
422 }
423
424
425
426
427 @Deprecated
428 public String getUuid() {
429 return uuid;
430 }
431
432 @Override
433 public String toString() {
434 return "MgnlUser - " + name + " [" + uuid + "]";
435 }
436 }