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