1 package org
.argeo
.security
.jackrabbit
;
3 import java
.util
.ArrayList
;
4 import java
.util
.Iterator
;
5 import java
.util
.LinkedHashSet
;
9 import javax
.jcr
.Repository
;
10 import javax
.jcr
.RepositoryException
;
11 import javax
.jcr
.Session
;
12 import javax
.jcr
.SimpleCredentials
;
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
;
39 * An implementation of {@link UserAdminService} which closely wraps Jackrabbits
40 * implementation. Roles are implemented with Groups.
42 public class JackrabbitUserAdminService
implements UserAdminService
,
43 AuthenticationProvider
{
44 private Repository repository
;
45 private JcrSecurityModel securityModel
;
47 private JackrabbitSession adminSession
= null;
49 private String superUsername
= "root";
50 private String superUserInitialPassword
= "demo";
52 public void init() throws RepositoryException
{
53 Authentication authentication
= SecurityContextHolder
.getContext()
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");
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);
74 public void destroy() throws RepositoryException
{
75 JcrUtils
.logoutQuietly(adminSession
);
78 private UserManager
getUserManager() throws RepositoryException
{
79 return adminSession
.getUserManager();
83 public void createUser(UserDetails user
) {
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
);
93 public void updateUser(UserDetails user
) {
98 public void deleteUser(String username
) {
100 getUserManager().getAuthorizable(username
).remove();
101 } catch (RepositoryException e
) {
102 throw new ArgeoException("Cannot remove user " + username
, e
);
107 public void changePassword(String oldPassword
, String newPassword
) {
108 Authentication authentication
= SecurityContextHolder
.getContext()
109 .getAuthentication();
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
118 if (credentials
.matches(sp
))
119 user
.changePassword(newPassword
);
121 throw new BadCredentialsException("Bad credentials provided");
122 } catch (Exception e
) {
123 throw new ArgeoException("Cannot change password for user "
124 + authentication
.getName(), e
);
129 public boolean userExists(String username
) {
131 Authorizable authorizable
= getUserManager().getAuthorizable(
133 if (authorizable
!= null && authorizable
instanceof User
)
136 } catch (RepositoryException e
) {
137 throw new ArgeoException("Cannot check whether user " + username
143 public Set
<String
> listUsers() {
144 LinkedHashSet
<String
> res
= new LinkedHashSet
<String
>();
146 Iterator
<Authorizable
> users
= getUserManager().findAuthorizables(
147 null, null, UserManager
.SEARCH_TYPE_USER
);
148 while (users
.hasNext()) {
149 res
.add(users
.next().getPrincipal().getName());
152 } catch (RepositoryException e
) {
153 throw new ArgeoException("Cannot list users", e
);
158 public Set
<String
> listUsersInRole(String role
) {
159 LinkedHashSet
<String
> res
= new LinkedHashSet
<String
>();
161 Group group
= (Group
) getUserManager().getAuthorizable(role
);
162 Iterator
<Authorizable
> users
= group
.getMembers();
164 while (users
.hasNext()) {
165 res
.add(users
.next().getPrincipal().getName());
168 } catch (RepositoryException e
) {
169 throw new ArgeoException("Cannot list users in role " + role
, e
);
174 public void synchronize() {
178 public void newRole(String role
) {
180 getUserManager().createGroup(role
);
181 } catch (RepositoryException e
) {
182 throw new ArgeoException("Cannot create role " + role
, e
);
187 public Set
<String
> listEditableRoles() {
188 LinkedHashSet
<String
> res
= new LinkedHashSet
<String
>();
190 Iterator
<Authorizable
> groups
= getUserManager().findAuthorizables(
191 null, null, UserManager
.SEARCH_TYPE_GROUP
);
192 while (groups
.hasNext()) {
193 res
.add(groups
.next().getPrincipal().getName());
196 } catch (RepositoryException e
) {
197 throw new ArgeoException("Cannot list groups", e
);
202 public void deleteRole(String role
) {
204 getUserManager().getAuthorizable(role
).remove();
205 } catch (RepositoryException e
) {
206 throw new ArgeoException("Cannot remove role " + role
, e
);
211 public UserDetails
loadUserByUsername(String username
)
212 throws UsernameNotFoundException
, DataAccessException
{
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
);
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
));
239 Node userProfile
= UserJcrUtils
.getUserProfile(session
, username
);
240 JcrUserDetails userDetails
= new JcrUserDetails(userProfile
,
241 credentials
.toString(),
242 authorities
.toArray(new GrantedAuthority
[authorities
.size()]));
246 // AUTHENTICATION PROVIDER
247 public synchronized Authentication
authenticate(
248 Authentication authentication
) throws AuthenticationException
{
249 UsernamePasswordAuthenticationToken siteAuth
= (UsernamePasswordAuthenticationToken
) authentication
;
250 String username
= siteAuth
.getName();
252 SimpleCredentials sp
= new SimpleCredentials(siteAuth
.getName(),
253 siteAuth
.getCredentials().toString().toCharArray());
254 User user
= (User
) getUserManager().getAuthorizable(username
);
255 CryptedSimpleCredentials credentials
= (CryptedSimpleCredentials
) user
257 // String providedPassword = siteAuth.getCredentials().toString();
258 if (!credentials
.matches(sp
)) {
259 throw new BadCredentialsException("Passwords do not match");
261 // session = repository.login(sp, null);
263 Node userProfile
= UserJcrUtils
.getUserProfile(adminSession
,
265 JcrUserDetails
.checkAccountStatus(userProfile
);
266 } catch (Exception e
) {
267 throw new BadCredentialsException(
268 "Cannot authenticate " + siteAuth
, e
);
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
);
284 @SuppressWarnings("rawtypes")
285 public boolean supports(Class authentication
) {
286 return UsernamePasswordAuthenticationToken
.class
287 .isAssignableFrom(authentication
);
290 public void setRepository(Repository repository
) {
291 this.repository
= repository
;
294 public void setSecurityModel(JcrSecurityModel securityModel
) {
295 this.securityModel
= securityModel
;