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