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 info.magnolia.cms.beans.config.ContentRepository;
37 import info.magnolia.cms.core.Content;
38 import info.magnolia.cms.core.HierarchyManager;
39 import info.magnolia.cms.core.ItemType;
40 import info.magnolia.cms.core.MetaData;
41 import info.magnolia.cms.core.Path;
42 import info.magnolia.cms.core.search.Query;
43 import info.magnolia.cms.core.search.QueryManager;
44 import info.magnolia.cms.security.auth.Entity;
45 import info.magnolia.context.MgnlContext;
46
47 import java.util.ArrayList;
48 import java.util.Collection;
49 import java.util.Iterator;
50 import java.util.Set;
51
52 import javax.jcr.PathNotFoundException;
53 import javax.jcr.RepositoryException;
54 import javax.security.auth.Subject;
55
56 import org.apache.commons.codec.binary.Base64;
57 import org.apache.commons.lang.StringUtils;
58 import org.slf4j.Logger;
59 import org.slf4j.LoggerFactory;
60
61
62
63
64
65
66 public class MgnlUserManager implements UserManager {
67
68 private static final Logger log = LoggerFactory.getLogger(MgnlUserManager.class);
69
70 public static final String PROPERTY_EMAIL = "email";
71 public static final String PROPERTY_LANGUAGE = "language";
72 public static final String PROPERTY_LASTACCESS = "lastaccess";
73 public static final String PROPERTY_PASSWORD = "pswd";
74 public static final String PROPERTY_TITLE = "title";
75
76 public static final String NODE_ACLUSERS = "acl_users";
77
78 private String realmName;
79
80 private int maxFailedLoginAttempts;
81
82 private long lockTimePeriod;
83
84
85
86
87 public MgnlUserManager() {
88 }
89
90
91
92 public String getName() {
93 return getRealmName();
94 }
95
96 public void setName(String name) {
97 this.realmName = name;
98 }
99
100 public String getRealmName() {
101 return realmName;
102 }
103
104 public void setMaxFailedLoginAttempts(int maxFailedLoginAttempts){
105 this.maxFailedLoginAttempts = maxFailedLoginAttempts;
106 }
107
108 public int getMaxFailedLoginAttempts(){
109 return maxFailedLoginAttempts;
110 }
111
112 public void setLockTimePeriod(long lockTimePeriod){
113 this.lockTimePeriod = lockTimePeriod;
114 }
115
116 public long getLockTimePeriod(){
117 return lockTimePeriod;
118 }
119
120
121
122
123
124
125 public User getUser(String name) {
126 try {
127 return getFromRepository(name);
128 }
129 catch (RepositoryException e) {
130 log.info("Unable to load user [\"{} \"] due to: ", name, e);
131 return null;
132 }
133 }
134
135 public User getUser(Subject subject) throws UnsupportedOperationException {
136
137 if (subject == null) {
138 log.debug("subject not set.");
139 return new DummyUser();
140 }
141
142 Set<Entity> principalSet = subject.getPrincipals(Entity.class);
143 Iterator<Entity> entityIterator = principalSet.iterator();
144 if (!entityIterator.hasNext()) {
145
146 log.debug("user name not contained in principal set.");
147 return new DummyUser();
148 }
149 Entity userDetails = entityIterator.next();
150 String name = (String) userDetails.getProperty(Entity.NAME);
151 try {
152 return getFromRepository(name);
153 }
154 catch (PathNotFoundException e) {
155 log.error("user not registered in magnolia itself [\"{}\"]", name);
156 }
157 catch (Exception e) {
158 log.error("can't get jcr-node of current user", e);
159 }
160
161 return new DummyUser();
162 }
163
164 protected User getFromRepository(String name) throws RepositoryException {
165 final Content node = findUserNode(this.realmName, name);
166 if (node == null) {
167 log.debug("User not found: [{}]", name);
168 return null;
169 }
170
171 return newUserInstance(node);
172 }
173
174
175
176
177 protected Content findUserNode(String realm, String name) throws RepositoryException {
178 String where = "where jcr:path = '/" + realm + "/" + name + "'";
179 where += " or jcr:path like '/" + realm + "/%/" + name + "'";
180
181
182 if (Realm.REALM_ALL.equals(realm)) {
183 where = "where jcr:path like '%/" + name + "'";
184 }
185
186 String statement = "select * from " + ItemType.USER + " " + where;
187
188 QueryManager qm = getHierarchyManager().getQueryManager();
189 Query query = qm.createQuery(statement, Query.SQL);
190 Collection<Content> users = query.execute().getContent(ItemType.USER.getSystemName());
191 if (users.size() == 1) {
192 return users.iterator().next();
193 }
194 else if (users.size() > 1) {
195 log.error("More than one user found with name [{}] in realm [{}]", name, realm);
196 }
197 return null;
198 }
199
200
201
202
203 public User getSystemUser() throws UnsupportedOperationException {
204 throw new UnsupportedOperationException();
205 }
206
207
208
209
210 public User getAnonymousUser() throws UnsupportedOperationException {
211 throw new UnsupportedOperationException();
212 }
213
214
215
216
217 public Collection<User> getAllUsers() {
218 Collection<User> users = new ArrayList<User>();
219 try {
220 Content root = getHierarchyManager().getRoot().getContent(getRealmName());
221 updateUserListWithAllChildren(root, users);
222 }
223 catch (Exception e) {
224 log.error("can't find user");
225 }
226 return users;
227 }
228
229
230
231
232 public void updateUserListWithAllChildren(Content node, Collection<User> users){
233 Collection<Content> nodes = node.getChildren(ItemType.USER);
234 Collection<Content> folders = node.getChildren(ItemType.NT_FOLDER);
235 if(!nodes.isEmpty()){
236 for (Content userNode : nodes) {
237 users.add(newUserInstance(userNode));
238 }
239 }
240 if(!folders.isEmpty()){
241 Iterator<Content> it = folders.iterator();
242 while(it.hasNext()){
243 updateUserListWithAllChildren((Content)it.next(), users);
244 }
245 }
246 }
247
248 public User createUser(String name, String pw) {
249 validateUsername(name);
250 try {
251 final Content node = createUserNode(name);
252 node.createNodeData("name").setValue(name);
253 setPasswordProperty(node, pw);
254 node.createNodeData("language").setValue("en");
255
256 final String handle = node.getHandle();
257 final Content acls = node.createContent(NODE_ACLUSERS, ItemType.CONTENTNODE);
258
259 Content acl = acls.createContent(Path.getUniqueLabel(acls.getHierarchyManager(), acls.getHandle(), "0"), ItemType.CONTENTNODE);
260 acl.setNodeData("path", handle);
261 acl.setNodeData("permissions", new Long(Permission.READ));
262
263 addWrite(handle, PROPERTY_EMAIL, acls);
264 addWrite(handle, PROPERTY_LANGUAGE, acls);
265 addWrite(handle, PROPERTY_LASTACCESS, acls);
266 addWrite(handle, PROPERTY_PASSWORD, acls);
267 addWrite(handle, PROPERTY_TITLE, acls);
268
269 addWrite(handle, MetaData.DEFAULT_META_NODE, acls);
270
271 getHierarchyManager().save();
272 return newUserInstance(node);
273 }
274 catch (Exception e) {
275 log.info("can't create user [" + name + "]", e);
276 return null;
277 }
278 }
279
280 public void changePassword(User user, String newPassword) {
281 final Content userNode = ((MgnlUser) user).getUserNode();
282 try {
283 setPasswordProperty(userNode, newPassword);
284 userNode.save();
285 }
286 catch (RepositoryException e) {
287 throw new RuntimeException(e);
288 }
289 }
290
291 protected void setPasswordProperty(Content userNode, String clearPassword) throws RepositoryException {
292 userNode.createNodeData(PROPERTY_PASSWORD).setValue(encodePassword(clearPassword));
293 }
294
295 protected String encodePassword(String clearPassword) {
296 return new String(Base64.encodeBase64(clearPassword.getBytes()));
297 }
298
299 protected void validateUsername(String name) {
300 if (StringUtils.isBlank(name)) {
301 throw new IllegalArgumentException(name + " is not a valid username.");
302 }
303 }
304
305 protected Content createUserNode(String name) throws RepositoryException {
306 final String path = "/" + getRealmName();
307 return getHierarchyManager().createContent(path, name, ItemType.USER.getSystemName());
308 }
309
310
311
312
313 protected HierarchyManager getHierarchyManager() {
314 return MgnlContext.getSystemContext().getHierarchyManager(ContentRepository.USERS);
315 }
316
317
318
319
320 protected MgnlUser userInstance(Content node) {
321 return new MgnlUser(node);
322 }
323
324
325
326
327
328 protected User newUserInstance(Content node) {
329 return userInstance(node);
330 }
331
332 private Content addWrite(String parentPath, String property, Content acls) throws PathNotFoundException, RepositoryException, AccessDeniedException {
333 Content acl = acls.createContent(Path.getUniqueLabel(acls.getHierarchyManager(), acls.getHandle(), "0"), ItemType.CONTENTNODE);
334 acl.setNodeData("path", parentPath + "/" + property);
335 acl.setNodeData("permissions", new Long(Permission.ALL));
336 return acl;
337 }
338 }