View Javadoc
1   package org.argeo.cms.internal.kernel;
2   
3   import java.security.PrivilegedAction;
4   import java.text.SimpleDateFormat;
5   import java.util.HashSet;
6   import java.util.Set;
7   
8   import javax.jcr.Node;
9   import javax.jcr.Property;
10  import javax.jcr.Repository;
11  import javax.jcr.RepositoryException;
12  import javax.jcr.Session;
13  import javax.jcr.nodetype.NodeType;
14  import javax.jcr.security.Privilege;
15  import javax.naming.InvalidNameException;
16  import javax.naming.ldap.LdapName;
17  import javax.security.auth.Subject;
18  import javax.security.auth.login.LoginContext;
19  
20  import org.argeo.api.NodeConstants;
21  import org.argeo.api.NodeUtils;
22  import org.argeo.cms.CmsException;
23  import org.argeo.jcr.JcrRepositoryWrapper;
24  import org.argeo.jcr.JcrUtils;
25  
26  /**
27   * Make sure each user has a home directory available.
28   */
29  class EgoRepository extends JcrRepositoryWrapper implements KernelConstants {
30  
31  	/** The home base path. */
32  //	private String homeBasePath = KernelConstants.DEFAULT_HOME_BASE_PATH;
33  //	private String usersBasePath = KernelConstants.DEFAULT_USERS_BASE_PATH;
34  //	private String groupsBasePath = KernelConstants.DEFAULT_GROUPS_BASE_PATH;
35  
36  	private Set<String> checkedUsers = new HashSet<String>();
37  
38  	private SimpleDateFormat usersDatePath = new SimpleDateFormat("YYYY/MM");
39  
40  	private String defaultHomeWorkspace = NodeConstants.HOME_WORKSPACE;
41  	private String defaultGroupsWorkspace = NodeConstants.SRV_WORKSPACE;
42  //	private String defaultGuestsWorkspace = NodeConstants.GUESTS_WORKSPACE;
43  	private final boolean remote;
44  
45  	public EgoRepository(Repository repository, boolean remote) {
46  		super(repository);
47  		this.remote = remote;
48  		putDescriptor(NodeConstants.CN, NodeConstants.EGO_REPOSITORY);
49  		if (!remote) {
50  			LoginContext lc;
51  			try {
52  				lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_DATA_ADMIN);
53  				lc.login();
54  			} catch (javax.security.auth.login.LoginException e1) {
55  				throw new CmsException("Cannot login as systrem", e1);
56  			}
57  			Subject.doAs(lc.getSubject(), new PrivilegedAction<Void>() {
58  
59  				@Override
60  				public Void run() {
61  					loginOrCreateWorkspace(defaultHomeWorkspace);
62  					loginOrCreateWorkspace(defaultGroupsWorkspace);
63  					return null;
64  				}
65  
66  			});
67  		}
68  	}
69  
70  	private void loginOrCreateWorkspace(String workspace) {
71  		Session adminSession = null;
72  		try {
73  			adminSession = JcrUtils.loginOrCreateWorkspace(getRepository(workspace), workspace);
74  //			JcrUtils.addPrivilege(adminSession, "/", NodeConstants.ROLE_USER, Privilege.JCR_READ);
75  
76  //			initJcr(adminSession);
77  		} catch (RepositoryException e) {
78  			throw new CmsException("Cannot init JCR home", e);
79  		} finally {
80  			JcrUtils.logoutQuietly(adminSession);
81  		}
82  	}
83  
84  //	@Override
85  //	public Session login(Credentials credentials, String workspaceName)
86  //			throws LoginException, NoSuchWorkspaceException, RepositoryException {
87  //		if (workspaceName == null) {
88  //			return super.login(credentials, getUserHomeWorkspace());
89  //		} else {
90  //			return super.login(credentials, workspaceName);
91  //		}
92  //	}
93  
94  	protected String getUserHomeWorkspace() {
95  		// TODO base on JAAS Subject metadata
96  		return defaultHomeWorkspace;
97  	}
98  
99  	protected String getGroupsWorkspace() {
100 		// TODO base on JAAS Subject metadata
101 		return defaultGroupsWorkspace;
102 	}
103 
104 //	protected String getGuestsWorkspace() {
105 //		// TODO base on JAAS Subject metadata
106 //		return defaultGuestsWorkspace;
107 //	}
108 
109 	@Override
110 	protected void processNewSession(Session session, String workspaceName) {
111 		String username = session.getUserID();
112 		if (username == null || username.toString().equals(""))
113 			return;
114 		if (session.getUserID().equals(NodeConstants.ROLE_ANONYMOUS))
115 			return;
116 
117 		String userHomeWorkspace = getUserHomeWorkspace();
118 		if (workspaceName == null || !workspaceName.equals(userHomeWorkspace))
119 			return;
120 
121 		if (checkedUsers.contains(username))
122 			return;
123 		Session adminSession = KernelUtils.openAdminSession(getRepository(workspaceName), workspaceName);
124 		try {
125 			syncJcr(adminSession, username);
126 			checkedUsers.add(username);
127 		} finally {
128 			JcrUtils.logoutQuietly(adminSession);
129 		}
130 	}
131 
132 	/*
133 	 * JCR
134 	 */
135 	/** Session is logged out. */
136 	private void initJcr(Session adminSession) {
137 		try {
138 //			JcrUtils.mkdirs(adminSession, homeBasePath);
139 //			JcrUtils.mkdirs(adminSession, groupsBasePath);
140 			adminSession.save();
141 
142 //			JcrUtils.addPrivilege(adminSession, homeBasePath, NodeConstants.ROLE_USER_ADMIN, Privilege.JCR_READ);
143 //			JcrUtils.addPrivilege(adminSession, groupsBasePath, NodeConstants.ROLE_USER_ADMIN, Privilege.JCR_READ);
144 			adminSession.save();
145 		} catch (RepositoryException e) {
146 			throw new CmsException("Cannot initialize home repository", e);
147 		} finally {
148 			JcrUtils.logoutQuietly(adminSession);
149 		}
150 	}
151 
152 	protected synchronized void syncJcr(Session adminSession, String username) {
153 		// only in the default workspace
154 //		if (workspaceName != null)
155 //			return;
156 		// skip system users
157 		if (username.endsWith(NodeConstants.ROLES_BASEDN))
158 			return;
159 
160 		try {
161 			Node userHome = NodeUtils.getUserHome(adminSession, username);
162 			if (userHome == null) {
163 //				String homePath = generateUserPath(username);
164 				String userId = extractUserId(username);
165 //				if (adminSession.itemExists(homePath))// duplicate user id
166 //					userHome = adminSession.getNode(homePath).getParent().addNode(JcrUtils.lastPathElement(homePath));
167 //				else
168 //					userHome = JcrUtils.mkdirs(adminSession, homePath);
169 				userHome = adminSession.getRootNode().addNode(userId);
170 //				userHome.addMixin(NodeTypes.NODE_USER_HOME);
171 				userHome.addMixin(NodeType.MIX_CREATED);
172 				userHome.addMixin(NodeType.MIX_TITLE);
173 				userHome.setProperty(Property.JCR_ID, username);
174 				// TODO use display name
175 				userHome.setProperty(Property.JCR_TITLE, userId);
176 //				userHome.setProperty(NodeNames.LDAP_UID, username);
177 				adminSession.save();
178 
179 				JcrUtils.clearAccessControList(adminSession, userHome.getPath(), username);
180 				JcrUtils.addPrivilege(adminSession, userHome.getPath(), username, Privilege.JCR_ALL);
181 //				JackrabbitSecurityUtils.denyPrivilege(adminSession, userHome.getPath(), NodeConstants.ROLE_USER,
182 //						Privilege.JCR_READ);
183 			}
184 			if (adminSession.hasPendingChanges())
185 				adminSession.save();
186 		} catch (RepositoryException e) {
187 			JcrUtils.discardQuietly(adminSession);
188 			throw new CmsException("Cannot sync node security model for " + username, e);
189 		}
190 	}
191 
192 	/** Generate path for a new user home */
193 	private String generateUserPath(String username) {
194 		LdapName dn;
195 		try {
196 			dn = new LdapName(username);
197 		} catch (InvalidNameException e) {
198 			throw new CmsException("Invalid name " + username, e);
199 		}
200 		String userId = dn.getRdn(dn.size() - 1).getValue().toString();
201 		return '/' + userId;
202 //		int atIndex = userId.indexOf('@');
203 //		if (atIndex < 0) {
204 //			return homeBasePath+'/' + userId;
205 //		} else {
206 //			return usersBasePath + '/' + usersDatePath.format(new Date()) + '/' + userId;
207 //		}
208 	}
209 
210 	private String extractUserId(String username) {
211 		LdapName dn;
212 		try {
213 			dn = new LdapName(username);
214 		} catch (InvalidNameException e) {
215 			throw new CmsException("Invalid name " + username, e);
216 		}
217 		String userId = dn.getRdn(dn.size() - 1).getValue().toString();
218 		return userId;
219 //		int atIndex = userId.indexOf('@');
220 //		if (atIndex < 0) {
221 //			return homeBasePath+'/' + userId;
222 //		} else {
223 //			return usersBasePath + '/' + usersDatePath.format(new Date()) + '/' + userId;
224 //		}
225 	}
226 
227 	public void createWorkgroup(LdapName dn) {
228 		String groupsWorkspace = getGroupsWorkspace();
229 		Session adminSession = KernelUtils.openAdminSession(getRepository(groupsWorkspace), groupsWorkspace);
230 		String cn = dn.getRdn(dn.size() - 1).getValue().toString();
231 		Node newWorkgroup = NodeUtils.getGroupHome(adminSession, cn);
232 		if (newWorkgroup != null) {
233 			JcrUtils.logoutQuietly(adminSession);
234 			throw new CmsException("Workgroup " + newWorkgroup + " already exists for " + dn);
235 		}
236 		try {
237 			// TODO enhance transformation of cn to a valid node name
238 			// String relPath = cn.replaceAll("[^a-zA-Z0-9]", "_");
239 			String relPath = JcrUtils.replaceInvalidChars(cn);
240 			newWorkgroup = adminSession.getRootNode().addNode(relPath, NodeType.NT_UNSTRUCTURED);
241 //			newWorkgroup = JcrUtils.mkdirs(adminSession.getNode(groupsBasePath), relPath, NodeType.NT_UNSTRUCTURED);
242 //			newWorkgroup.addMixin(NodeTypes.NODE_GROUP_HOME);
243 			newWorkgroup.addMixin(NodeType.MIX_CREATED);
244 			newWorkgroup.addMixin(NodeType.MIX_TITLE);
245 			newWorkgroup.setProperty(Property.JCR_ID, dn.toString());
246 			newWorkgroup.setProperty(Property.JCR_TITLE, cn);
247 //			newWorkgroup.setProperty(NodeNames.LDAP_CN, cn);
248 			adminSession.save();
249 			JcrUtils.addPrivilege(adminSession, newWorkgroup.getPath(), dn.toString(), Privilege.JCR_ALL);
250 			adminSession.save();
251 		} catch (RepositoryException e) {
252 			throw new CmsException("Cannot create workgroup", e);
253 		} finally {
254 			JcrUtils.logoutQuietly(adminSession);
255 		}
256 
257 	}
258 
259 	public boolean isRemote() {
260 		return remote;
261 	}
262 
263 }