1 package org
.argeo
.security
.ldap
.jcr
;
3 import java
.util
.Arrays
;
4 import java
.util
.HashMap
;
8 import javax
.jcr
.Repository
;
9 import javax
.jcr
.RepositoryException
;
10 import javax
.jcr
.RepositoryFactory
;
11 import javax
.jcr
.Session
;
13 import org
.apache
.commons
.logging
.Log
;
14 import org
.apache
.commons
.logging
.LogFactory
;
15 import org
.argeo
.ArgeoException
;
16 import org
.argeo
.jcr
.ArgeoJcrConstants
;
17 import org
.argeo
.jcr
.ArgeoNames
;
18 import org
.argeo
.jcr
.JcrUtils
;
19 import org
.argeo
.security
.SystemExecutionService
;
20 import org
.argeo
.security
.jcr
.JcrUserDetails
;
21 import org
.springframework
.ldap
.core
.DirContextAdapter
;
22 import org
.springframework
.ldap
.core
.DirContextOperations
;
23 import org
.springframework
.security
.GrantedAuthority
;
24 import org
.springframework
.security
.userdetails
.UserDetails
;
25 import org
.springframework
.security
.userdetails
.ldap
.UserDetailsContextMapper
;
28 * Maps LDAP attributes and JCR properties. This class is meant to be robust,
29 * checks of which values should be mandatory should be performed at a higher
32 public class JcrUserDetailsContextMapper
implements UserDetailsContextMapper
{
33 private final static Log log
= LogFactory
34 .getLog(JcrUserDetailsContextMapper
.class);
36 private Map
<String
, String
> propertyToAttributes
= new HashMap
<String
, String
>();
37 private SystemExecutionService systemExecutionService
;
38 private String homeBasePath
= "/home";
39 private RepositoryFactory repositoryFactory
;
41 public UserDetails
mapUserFromContext(final DirContextOperations ctx
,
42 final String username
, GrantedAuthority
[] authorities
) {
43 if (repositoryFactory
== null)
44 throw new ArgeoException("No JCR repository factory registered");
45 final String userHomePath
= usernameToHomePath(username
);
46 systemExecutionService
.executeAsSystem(new Runnable() {
48 Session session
= null;
50 Repository nodeRepo
= JcrUtils
.getRepositoryByAlias(
51 repositoryFactory
, ArgeoJcrConstants
.ALIAS_NODE
);
52 session
= nodeRepo
.login();
53 Node userProfile
= JcrUtils
.mkdirs(session
, userHomePath
54 + '/' + ArgeoNames
.ARGEO_USER_PROFILE
);
55 for (String jcrProperty
: propertyToAttributes
.keySet())
56 ldapToJcr(userProfile
, jcrProperty
, ctx
);
58 if (log
.isDebugEnabled())
59 log
.debug("Mapped " + ctx
.getDn() + " to "
61 } catch (RepositoryException e
) {
62 throw new ArgeoException("Cannot synchronize JCR and LDAP",
71 byte[] arr
= (byte[]) ctx
.getAttributeSortedStringSet("userPassword")
73 JcrUserDetails userDetails
= new JcrUserDetails(userHomePath
, username
,
74 new String(arr
), true, true, true, true, authorities
);
75 Arrays
.fill(arr
, (byte) 0);
79 public void mapUserToContext(UserDetails user
, final DirContextAdapter ctx
) {
80 if (!(user
instanceof JcrUserDetails
))
81 throw new ArgeoException("Unsupported user details: "
84 ctx
.setAttributeValues("objectClass", new String
[] { "inetOrgPerson" });
85 ctx
.setAttributeValue("uid", user
.getUsername());
86 ctx
.setAttributeValue("userPassword", user
.getPassword());
88 final JcrUserDetails jcrUserDetails
= (JcrUserDetails
) user
;
89 systemExecutionService
.executeAsSystem(new Runnable() {
91 Session session
= null;
93 Repository nodeRepo
= JcrUtils
.getRepositoryByAlias(
94 repositoryFactory
, ArgeoJcrConstants
.ALIAS_NODE
);
95 session
= nodeRepo
.login();
96 Node userProfile
= session
.getNode(jcrUserDetails
99 + ArgeoNames
.ARGEO_USER_PROFILE
);
100 for (String jcrProperty
: propertyToAttributes
.keySet())
101 jcrToLdap(userProfile
, jcrProperty
, ctx
);
102 if (log
.isDebugEnabled())
103 log
.debug("Mapped " + userProfile
+ " to "
105 } catch (RepositoryException e
) {
106 throw new ArgeoException("Cannot synchronize JCR and LDAP",
115 protected String
usernameToHomePath(String username
) {
116 return homeBasePath
+ '/' + JcrUtils
.firstCharsToPath(username
, 2)
120 protected void ldapToJcr(Node userProfile
, String jcrProperty
,
121 DirContextOperations ctx
) {
123 String ldapAttribute
;
124 if (propertyToAttributes
.containsKey(jcrProperty
))
125 ldapAttribute
= propertyToAttributes
.get(jcrProperty
);
127 throw new ArgeoException(
128 "No LDAP attribute mapped for JCR proprty "
131 String value
= ctx
.getStringAttribute(ldapAttribute
);
134 userProfile
.setProperty(jcrProperty
, value
);
135 } catch (Exception e
) {
136 throw new ArgeoException("Cannot map JCR property " + jcrProperty
141 protected void jcrToLdap(Node userProfile
, String jcrProperty
,
142 DirContextOperations ctx
) {
144 if (!userProfile
.hasProperty(jcrProperty
))
146 String value
= userProfile
.getProperty(jcrProperty
).getString();
148 String ldapAttribute
;
149 if (propertyToAttributes
.containsKey(jcrProperty
))
150 ldapAttribute
= propertyToAttributes
.get(jcrProperty
);
152 throw new ArgeoException(
153 "No LDAP attribute mapped for JCR proprty "
155 ctx
.setAttributeValue(ldapAttribute
, value
);
156 } catch (Exception e
) {
157 throw new ArgeoException("Cannot map JCR property " + jcrProperty
162 public void setPropertyToAttributes(Map
<String
, String
> propertyToAttributes
) {
163 this.propertyToAttributes
= propertyToAttributes
;
166 public void setSystemExecutionService(
167 SystemExecutionService systemExecutionService
) {
168 this.systemExecutionService
= systemExecutionService
;
171 public void setHomeBasePath(String homeBasePath
) {
172 this.homeBasePath
= homeBasePath
;
175 public void register(RepositoryFactory repositoryFactory
,
176 Map
<String
, String
> parameters
) {
177 this.repositoryFactory
= repositoryFactory
;
180 public void unregister(RepositoryFactory repositoryFactory
,
181 Map
<String
, String
> parameters
) {
182 this.repositoryFactory
= null;