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