]> git.argeo.org Git - lgpl/argeo-commons.git/blob - security/runtime/org.argeo.security.ldap/src/main/java/org/argeo/security/ldap/jcr/JcrUserDetailsContextMapper.java
Clean up LDAP dao
[lgpl/argeo-commons.git] / security / runtime / org.argeo.security.ldap / src / main / java / org / argeo / security / ldap / jcr / JcrUserDetailsContextMapper.java
1 package org.argeo.security.ldap.jcr;
2
3 import java.util.Arrays;
4 import java.util.HashMap;
5 import java.util.Map;
6
7 import javax.jcr.Node;
8 import javax.jcr.Repository;
9 import javax.jcr.RepositoryException;
10 import javax.jcr.RepositoryFactory;
11 import javax.jcr.Session;
12
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;
26
27 /**
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
30 * level.
31 */
32 public class JcrUserDetailsContextMapper implements UserDetailsContextMapper {
33 private final static Log log = LogFactory
34 .getLog(JcrUserDetailsContextMapper.class);
35
36 private Map<String, String> propertyToAttributes = new HashMap<String, String>();
37 private SystemExecutionService systemExecutionService;
38 private String homeBasePath = "/home";
39 private RepositoryFactory repositoryFactory;
40
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() {
47 public void run() {
48 Session session = null;
49 try {
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);
57 session.save();
58 if (log.isDebugEnabled())
59 log.debug("Mapped " + ctx.getDn() + " to "
60 + userProfile);
61 } catch (RepositoryException e) {
62 throw new ArgeoException("Cannot synchronize JCR and LDAP",
63 e);
64 } finally {
65 session.logout();
66 }
67 }
68 });
69
70 // password
71 byte[] arr = (byte[]) ctx.getAttributeSortedStringSet("userPassword")
72 .first();
73 JcrUserDetails userDetails = new JcrUserDetails(userHomePath, username,
74 new String(arr), true, true, true, true, authorities);
75 Arrays.fill(arr, (byte) 0);
76 return userDetails;
77 }
78
79 public void mapUserToContext(UserDetails user, final DirContextAdapter ctx) {
80 if (!(user instanceof JcrUserDetails))
81 throw new ArgeoException("Unsupported user details: "
82 + user.getClass());
83
84 ctx.setAttributeValues("objectClass", new String[] { "inetOrgPerson" });
85 ctx.setAttributeValue("uid", user.getUsername());
86 ctx.setAttributeValue("userPassword", user.getPassword());
87
88 final JcrUserDetails jcrUserDetails = (JcrUserDetails) user;
89 systemExecutionService.executeAsSystem(new Runnable() {
90 public void run() {
91 Session session = null;
92 try {
93 Repository nodeRepo = JcrUtils.getRepositoryByAlias(
94 repositoryFactory, ArgeoJcrConstants.ALIAS_NODE);
95 session = nodeRepo.login();
96 Node userProfile = session.getNode(jcrUserDetails
97 .getHomePath()
98 + '/'
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 "
104 + ctx.getDn());
105 } catch (RepositoryException e) {
106 throw new ArgeoException("Cannot synchronize JCR and LDAP",
107 e);
108 } finally {
109 session.logout();
110 }
111 }
112 });
113 }
114
115 protected String usernameToHomePath(String username) {
116 return homeBasePath + '/' + JcrUtils.firstCharsToPath(username, 2)
117 + '/' + username;
118 }
119
120 protected void ldapToJcr(Node userProfile, String jcrProperty,
121 DirContextOperations ctx) {
122 try {
123 String ldapAttribute;
124 if (propertyToAttributes.containsKey(jcrProperty))
125 ldapAttribute = propertyToAttributes.get(jcrProperty);
126 else
127 throw new ArgeoException(
128 "No LDAP attribute mapped for JCR proprty "
129 + jcrProperty);
130
131 String value = ctx.getStringAttribute(ldapAttribute);
132 if (value == null)
133 return;
134 userProfile.setProperty(jcrProperty, value);
135 } catch (Exception e) {
136 throw new ArgeoException("Cannot map JCR property " + jcrProperty
137 + " from LDAP", e);
138 }
139 }
140
141 protected void jcrToLdap(Node userProfile, String jcrProperty,
142 DirContextOperations ctx) {
143 try {
144 if (!userProfile.hasProperty(jcrProperty))
145 return;
146 String value = userProfile.getProperty(jcrProperty).getString();
147
148 String ldapAttribute;
149 if (propertyToAttributes.containsKey(jcrProperty))
150 ldapAttribute = propertyToAttributes.get(jcrProperty);
151 else
152 throw new ArgeoException(
153 "No LDAP attribute mapped for JCR proprty "
154 + jcrProperty);
155 ctx.setAttributeValue(ldapAttribute, value);
156 } catch (Exception e) {
157 throw new ArgeoException("Cannot map JCR property " + jcrProperty
158 + " from LDAP", e);
159 }
160 }
161
162 public void setPropertyToAttributes(Map<String, String> propertyToAttributes) {
163 this.propertyToAttributes = propertyToAttributes;
164 }
165
166 public void setSystemExecutionService(
167 SystemExecutionService systemExecutionService) {
168 this.systemExecutionService = systemExecutionService;
169 }
170
171 public void setHomeBasePath(String homeBasePath) {
172 this.homeBasePath = homeBasePath;
173 }
174
175 public void register(RepositoryFactory repositoryFactory,
176 Map<String, String> parameters) {
177 this.repositoryFactory = repositoryFactory;
178 }
179
180 public void unregister(RepositoryFactory repositoryFactory,
181 Map<String, String> parameters) {
182 this.repositoryFactory = null;
183 }
184 }