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