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.JCRPropertyHidingPredicate;
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 private boolean hasAny(final String name, final String nodeName) {
187 long start = System.currentTimeMillis();
188 try {
189 String sessionName;
190 if (StringUtils.equalsIgnoreCase(nodeName, NODE_ROLES)) {
191 sessionName = RepositoryConstants.USER_ROLES;
192 } else {
193 sessionName = RepositoryConstants.USER_GROUPS;
194 }
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 Node groupsOrRoles = session.getNode(getPath()).getNode(nodeName);
202 List<String> list = new ArrayList<String>();
203 for (PropertyIterator props = new FilteringPropertyIterator(groupsOrRoles.getProperties(), new JCRPropertyHidingPredicate()); props.hasNext();) {
204
205 Property property = props.nextProperty();
206
207 try {
208 list.add(property.getString());
209 } catch (ItemNotFoundException e) {
210 log.debug("Role [{}] does not exist in the ROLES repository", name);
211 }
212 }
213 return list;
214 }});
215
216
217 return MgnlContext.doInSystemContext(new JCRSessionOp<Boolean>(sessionName) {
218
219 @Override
220 public Boolean exec(Session session) throws RepositoryException {
221 for (String groupOrRole : groupsOrRoles) {
222
223 try {
224 if (session.getNodeByIdentifier(groupOrRole).getName().equalsIgnoreCase(name)) {
225 return true;
226 }
227 } catch (ItemNotFoundException e) {
228 log.debug("Role [{}] does not exist in the ROLES repository", name);
229 } catch (RepositoryException e) {
230
231 log.debug(e.getMessage(), e);
232 }
233 }
234 return false;
235 }});
236
237 } catch (RepositoryException e) {
238 log.debug(e.getMessage(), e);
239
240 } finally {
241 log.debug("checked {} for {} in {}ms.", new Object[] {name, nodeName, (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
315 allGroups.addAll(groups);
316
317 return allGroups;
318 }
319
320 @Override
321 public Collection<String> getRoles() {
322 log.debug("getRoles()");
323 return roles;
324 }
325
326 @Override
327 public Collection<String> getAllRoles() {
328
329 log.debug("get roles for {}", getName());
330
331 final Set<String> allRoles = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
332 final Collection<String> roles = getRoles();
333
334
335 allRoles.addAll(roles);
336
337 Collection<String> allGroups = getAllGroups();
338
339
340 GroupManager man = SecuritySupport.Factory.getInstance().getGroupManager();
341
342
343 for (String group : allGroups) {
344 try {
345 allRoles.addAll(man.getGroup(group).getRoles());
346 } catch (AccessDeniedException e) {
347 log.debug("Skipping denied group " + group + " for user " + getName(), e);
348 } catch (UnsupportedOperationException e) {
349 log.debug("Skipping unsupported getGroup() for group " + group + " and user " + getName(), e);
350 }
351 }
352 return allRoles;
353 }
354
355 public String getPath() {
356 return this.path;
357 }
358
359 @Deprecated
360 public void setPath(String path) {
361 this.path = path;
362 }
363
364
365
366
367 private void addSubgroups(final Set<String> allGroups, GroupManager man, Collection<String> groups) {
368 for (String groupName : groups) {
369
370 if (!allGroups.contains(groupName)) {
371 try {
372 Group group = man.getGroup(groupName);
373 if (group == null) {
374 log.error("Failed to resolve group {} for user {}.", groupName, name);
375 continue;
376 }
377 Collection<String> subgroups = group.getGroups();
378
379 addSubgroups(allGroups, man, subgroups);
380 allGroups.addAll(subgroups);
381 } catch (AccessDeniedException e) {
382 log.debug("Skipping denied group " + groupName + " for user " + getName(), e);
383 } catch (UnsupportedOperationException e) {
384 log.debug("Skipping unsupported getGroup() for group " + groupName + " and user " + getName(), e);
385 }
386
387 }
388 }
389 }
390
391 public String getRealm() {
392 return realm;
393 }
394
395
396
397
398
399 @Deprecated
400 public void setLastAccess() {
401 throw new UnsupportedOperationException("Use manager to update user details.");
402 }
403
404
405
406
407
408 @Deprecated
409 public Content getUserNode() {
410 throw new UnsupportedOperationException("Underlying storage node is no longer exposed nor required for custom user stores.");
411 }
412
413
414
415
416 @Override
417 @Deprecated
418 public void setProperty(String propertyName, String value) {
419 throw new UnsupportedOperationException("Use manager to modify properties of the user.");
420 }
421
422 @Override
423 public String getIdentifier() {
424 return uuid;
425 }
426
427
428
429
430 @Deprecated
431 public String getUuid() {
432 return uuid;
433 }
434
435 @Override
436 public String toString() {
437 return "MgnlUser - " + name + " [" + uuid + "]";
438 }
439 }