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