]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.security.core/src/org/argeo/security/jcr/jackrabbit/JackrabbitUserAdminService.java
Adapt to CMS kernel
[lgpl/argeo-commons.git] / org.argeo.security.core / src / org / argeo / security / jcr / jackrabbit / JackrabbitUserAdminService.java
1 package org.argeo.security.jcr.jackrabbit;
2
3 import java.util.ArrayList;
4 import java.util.Iterator;
5 import java.util.LinkedHashSet;
6 import java.util.List;
7 import java.util.Set;
8
9 import javax.jcr.Node;
10 import javax.jcr.Repository;
11 import javax.jcr.RepositoryException;
12 import javax.jcr.Session;
13 import javax.jcr.SimpleCredentials;
14
15 import org.apache.jackrabbit.api.JackrabbitSession;
16 import org.apache.jackrabbit.api.security.user.Authorizable;
17 import org.apache.jackrabbit.api.security.user.Group;
18 import org.apache.jackrabbit.api.security.user.User;
19 import org.apache.jackrabbit.api.security.user.UserManager;
20 import org.apache.jackrabbit.core.security.authentication.CryptedSimpleCredentials;
21 import org.argeo.ArgeoException;
22 import org.argeo.jcr.JcrUtils;
23 import org.argeo.jcr.UserJcrUtils;
24 import org.argeo.security.UserAdminService;
25 import org.argeo.security.jcr.JcrSecurityModel;
26 import org.argeo.security.jcr.JcrUserDetails;
27 import org.springframework.dao.DataAccessException;
28 import org.springframework.security.authentication.AuthenticationProvider;
29 import org.springframework.security.authentication.BadCredentialsException;
30 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
31 import org.springframework.security.core.Authentication;
32 import org.springframework.security.core.AuthenticationException;
33 import org.springframework.security.core.GrantedAuthority;
34 import org.springframework.security.core.authority.SimpleGrantedAuthority;
35 import org.springframework.security.core.context.SecurityContextHolder;
36 import org.springframework.security.core.userdetails.UserDetails;
37 import org.springframework.security.core.userdetails.UsernameNotFoundException;
38
39 /**
40 * An implementation of {@link UserAdminService} which closely wraps Jackrabbits
41 * implementation. Roles are implemented with Groups.
42 */
43 public class JackrabbitUserAdminService implements UserAdminService,
44 AuthenticationProvider {
45 final static String userRole = "ROLE_USER";
46 final static String adminRole = "ROLE_ADMIN";
47
48 private Repository repository;
49 private JcrSecurityModel securityModel;
50
51 private JackrabbitSession adminSession = null;
52
53 private String superUsername = "root";
54 private String superUserInitialPassword = "demo";
55
56 public void init() throws RepositoryException {
57 Authentication authentication = SecurityContextHolder.getContext()
58 .getAuthentication();
59 authentication.getName();
60 adminSession = (JackrabbitSession) repository.login();
61 Authorizable adminGroup = getUserManager().getAuthorizable(adminRole);
62 if (adminGroup == null) {
63 adminGroup = getUserManager().createGroup(adminRole);
64 adminSession.save();
65 }
66 Authorizable superUser = getUserManager()
67 .getAuthorizable(superUsername);
68 if (superUser == null) {
69 superUser = getUserManager().createUser(superUsername,
70 superUserInitialPassword);
71 ((Group) adminGroup).addMember(superUser);
72 securityModel.sync(adminSession, superUsername, null);
73 adminSession.save();
74 }
75 }
76
77 public void destroy() throws RepositoryException {
78 JcrUtils.logoutQuietly(adminSession);
79 }
80
81 private UserManager getUserManager() throws RepositoryException {
82 return adminSession.getUserManager();
83 }
84
85 @Override
86 public void createUser(UserDetails user) {
87 try {
88 // FIXME workaround for issue in new user wizard where
89 // security model is hardcoded and it already exists
90 if (getUserManager().getAuthorizable(user.getUsername()) == null) {
91 getUserManager().createUser(user.getUsername(),
92 user.getPassword());
93 securityModel.sync(adminSession, user.getUsername(), null);
94 }
95 updateUser(user);
96 } catch (RepositoryException e) {
97 throw new ArgeoException("Cannot create user " + user, e);
98 }
99 }
100
101 @Override
102 public void updateUser(UserDetails userDetails) {
103 try {
104 User user = (User) getUserManager().getAuthorizable(
105 userDetails.getUsername());
106 if (user == null)
107 throw new ArgeoException("No user " + userDetails.getUsername());
108
109 // new password
110 String newPassword = userDetails.getPassword();
111 if (!newPassword.trim().equals("")) {
112 SimpleCredentials sp = new SimpleCredentials(
113 userDetails.getUsername(), newPassword.toCharArray());
114 CryptedSimpleCredentials credentials = (CryptedSimpleCredentials) user
115 .getCredentials();
116 if (!credentials.matches(sp))
117 user.changePassword(new String(newPassword));
118 }
119
120 List<String> roles = new ArrayList<String>();
121 for (GrantedAuthority ga : userDetails.getAuthorities()) {
122 if (ga.getAuthority().equals(userRole))
123 continue;
124 roles.add(ga.getAuthority());
125 }
126
127 for (Iterator<Group> it = user.memberOf(); it.hasNext();) {
128 Group group = it.next();
129 if (roles.contains(group.getPrincipal().getName()))
130 roles.remove(group.getPrincipal().getName());
131 else
132 group.removeMember(user);
133 }
134
135 // remaining (new ones)
136 for (String role : roles) {
137 Group group = (Group) getUserManager().getAuthorizable(role);
138 if (group == null)
139 throw new ArgeoException("Group " + role
140 + " does not exist,"
141 + " whereas it was granted to user " + userDetails);
142 group.addMember(user);
143 }
144 } catch (Exception e) {
145 throw new ArgeoException("Cannot update user details", e);
146 }
147
148 }
149
150 @Override
151 public void deleteUser(String username) {
152 try {
153 getUserManager().getAuthorizable(username).remove();
154 } catch (RepositoryException e) {
155 throw new ArgeoException("Cannot remove user " + username, e);
156 }
157 }
158
159 @Override
160 public void changePassword(String oldPassword, String newPassword) {
161 Authentication authentication = SecurityContextHolder.getContext()
162 .getAuthentication();
163 String username = authentication.getName();
164 try {
165 SimpleCredentials sp = new SimpleCredentials(username,
166 oldPassword.toCharArray());
167 User user = (User) getUserManager().getAuthorizable(username);
168 CryptedSimpleCredentials credentials = (CryptedSimpleCredentials) user
169 .getCredentials();
170 if (credentials.matches(sp))
171 user.changePassword(newPassword);
172 else
173 throw new BadCredentialsException("Bad credentials provided");
174 } catch (Exception e) {
175 throw new ArgeoException("Cannot change password for user "
176 + username, e);
177 }
178 }
179
180 @Override
181 public boolean userExists(String username) {
182 try {
183 Authorizable authorizable = getUserManager().getAuthorizable(
184 username);
185 if (authorizable != null && authorizable instanceof User)
186 return true;
187 return false;
188 } catch (RepositoryException e) {
189 throw new ArgeoException("Cannot check whether user " + username
190 + " exists ", e);
191 }
192 }
193
194 @Override
195 public Set<String> listUsers() {
196 LinkedHashSet<String> res = new LinkedHashSet<String>();
197 try {
198 Iterator<Authorizable> users = getUserManager().findAuthorizables(
199 "rep:principalName", null, UserManager.SEARCH_TYPE_USER);
200 while (users.hasNext()) {
201 res.add(users.next().getPrincipal().getName());
202 }
203 return res;
204 } catch (RepositoryException e) {
205 throw new ArgeoException("Cannot list users", e);
206 }
207 }
208
209 @Override
210 public Set<String> listUsersInRole(String role) {
211 LinkedHashSet<String> res = new LinkedHashSet<String>();
212 try {
213 Group group = (Group) getUserManager().getAuthorizable(role);
214 Iterator<Authorizable> users = group.getMembers();
215 // NB: not recursive
216 while (users.hasNext()) {
217 res.add(users.next().getPrincipal().getName());
218 }
219 return res;
220 } catch (RepositoryException e) {
221 throw new ArgeoException("Cannot list users in role " + role, e);
222 }
223 }
224
225 @Override
226 public void synchronize() {
227 }
228
229 @Override
230 public void newRole(String role) {
231 try {
232 getUserManager().createGroup(role);
233 } catch (RepositoryException e) {
234 throw new ArgeoException("Cannot create role " + role, e);
235 }
236 }
237
238 @Override
239 public Set<String> listEditableRoles() {
240 LinkedHashSet<String> res = new LinkedHashSet<String>();
241 try {
242 Iterator<Authorizable> groups = getUserManager().findAuthorizables(
243 "rep:principalName", null, UserManager.SEARCH_TYPE_GROUP);
244 while (groups.hasNext()) {
245 res.add(groups.next().getPrincipal().getName());
246 }
247 return res;
248 } catch (RepositoryException e) {
249 throw new ArgeoException("Cannot list groups", e);
250 }
251 }
252
253 @Override
254 public void deleteRole(String role) {
255 try {
256 getUserManager().getAuthorizable(role).remove();
257 } catch (RepositoryException e) {
258 throw new ArgeoException("Cannot remove role " + role, e);
259 }
260 }
261
262 @Override
263 public UserDetails loadUserByUsername(String username)
264 throws UsernameNotFoundException, DataAccessException {
265 try {
266 User user = (User) getUserManager().getAuthorizable(username);
267 if (user == null)
268 throw new UsernameNotFoundException("User " + username
269 + " cannot be found");
270 return loadJcrUserDetails(adminSession, username);
271 } catch (RepositoryException e) {
272 throw new ArgeoException("Cannot load user " + username, e);
273 }
274 }
275
276 protected JcrUserDetails loadJcrUserDetails(Session session, String username)
277 throws RepositoryException {
278 if (username == null)
279 username = session.getUserID();
280 User user = (User) getUserManager().getAuthorizable(username);
281 ArrayList<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
282 // FIXME make it more generic
283 authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
284 Iterator<Group> groups = user.declaredMemberOf();
285 while (groups.hasNext()) {
286 Group group = groups.next();
287 // String role = "ROLE_"
288 // + group.getPrincipal().getName().toUpperCase();
289 String role = group.getPrincipal().getName();
290 authorities.add(new SimpleGrantedAuthority(role));
291 }
292
293 Node userProfile = UserJcrUtils.getUserProfile(session, username);
294 JcrUserDetails userDetails = new JcrUserDetails(userProfile, "",
295 authorities);
296 return userDetails;
297 }
298
299 // AUTHENTICATION PROVIDER
300 public synchronized Authentication authenticate(
301 Authentication authentication) throws AuthenticationException {
302 UsernamePasswordAuthenticationToken siteAuth = (UsernamePasswordAuthenticationToken) authentication;
303 String username = siteAuth.getName();
304 try {
305 SimpleCredentials sp = new SimpleCredentials(siteAuth.getName(),
306 siteAuth.getCredentials().toString().toCharArray());
307 User user = (User) getUserManager().getAuthorizable(username);
308 if (user == null)
309 throw new BadCredentialsException("Bad credentials");
310 CryptedSimpleCredentials credentials = (CryptedSimpleCredentials) user
311 .getCredentials();
312 // String providedPassword = siteAuth.getCredentials().toString();
313 if (!credentials.matches(sp))
314 throw new BadCredentialsException("Bad credentials");
315
316 // session = repository.login(sp, null);
317
318 Node userProfile = UserJcrUtils.getUserProfile(adminSession,
319 username);
320 JcrUserDetails.checkAccountStatus(userProfile);
321 } catch (BadCredentialsException e) {
322 throw e;
323 } catch (Exception e) {
324 throw new BadCredentialsException(
325 "Cannot authenticate " + siteAuth, e);
326 }
327
328 try {
329 JcrUserDetails userDetails = loadJcrUserDetails(adminSession,
330 username);
331 UsernamePasswordAuthenticationToken authenticated = new UsernamePasswordAuthenticationToken(
332 siteAuth, "", userDetails.getAuthorities());
333 authenticated.setDetails(userDetails);
334 return authenticated;
335 } catch (RepositoryException e) {
336 throw new ArgeoException(
337 "Unexpected exception when authenticating " + siteAuth, e);
338 }
339 }
340
341 @SuppressWarnings("rawtypes")
342 public boolean supports(Class authentication) {
343 return UsernamePasswordAuthenticationToken.class
344 .isAssignableFrom(authentication);
345 }
346
347 public void setRepository(Repository repository) {
348 this.repository = repository;
349 }
350
351 public void setSecurityModel(JcrSecurityModel securityModel) {
352 this.securityModel = securityModel;
353 }
354
355 }