View Javadoc
1   package org.argeo.maintenance;
2   
3   import java.io.IOException;
4   import java.util.EnumSet;
5   import java.util.HashSet;
6   import java.util.Set;
7   
8   import javax.jcr.NoSuchWorkspaceException;
9   import javax.jcr.Repository;
10  import javax.jcr.RepositoryException;
11  import javax.jcr.Session;
12  import javax.transaction.UserTransaction;
13  
14  import org.apache.commons.logging.Log;
15  import org.apache.commons.logging.LogFactory;
16  import org.argeo.api.NodeUtils;
17  import org.argeo.jcr.Jcr;
18  import org.argeo.jcr.JcrUtils;
19  import org.argeo.naming.Distinguished;
20  import org.osgi.service.useradmin.Group;
21  import org.osgi.service.useradmin.Role;
22  import org.osgi.service.useradmin.UserAdmin;
23  
24  /** Make sure roles and access rights are properly configured. */
25  public abstract class AbstractMaintenanceService {
26  	private final static Log log = LogFactory.getLog(AbstractMaintenanceService.class);
27  
28  	private Repository repository;
29  //	private UserAdminService userAdminService;
30  	private UserAdmin userAdmin;
31  	private UserTransaction userTransaction;
32  
33  	public void init() {
34  		makeSureRolesExists(getRequiredRoles());
35  		configureStandardRoles();
36  
37  		Set<String> workspaceNames = getWorkspaceNames();
38  		if (workspaceNames == null || workspaceNames.isEmpty()) {
39  			configureJcr(repository, null);
40  		} else {
41  			for (String workspaceName : workspaceNames)
42  				configureJcr(repository, workspaceName);
43  		}
44  	}
45  
46  	/** Configures a workspace. */
47  	protected void configureJcr(Repository repository, String workspaceName) {
48  		Session adminSession;
49  		try {
50  			adminSession = NodeUtils.openDataAdminSession(repository, workspaceName);
51  		} catch (RuntimeException e1) {
52  			if (e1.getCause() != null && e1.getCause() instanceof NoSuchWorkspaceException) {
53  				Session defaultAdminSession = NodeUtils.openDataAdminSession(repository, null);
54  				try {
55  					defaultAdminSession.getWorkspace().createWorkspace(workspaceName);
56  					log.info("Created JCR workspace " + workspaceName);
57  				} catch (RepositoryException e) {
58  					throw new IllegalStateException("Cannot create workspace " + workspaceName, e);
59  				} finally {
60  					Jcr.logout(defaultAdminSession);
61  				}
62  				adminSession = NodeUtils.openDataAdminSession(repository, workspaceName);
63  			} else
64  				throw e1;
65  		}
66  		try {
67  			if (prepareJcrTree(adminSession)) {
68  				configurePrivileges(adminSession);
69  			}
70  		} catch (RepositoryException | IOException e) {
71  			throw new IllegalStateException("Cannot initialise JCR data layer.", e);
72  		} finally {
73  			JcrUtils.logoutQuietly(adminSession);
74  		}
75  	}
76  
77  	/** To be overridden. */
78  	protected Set<String> getWorkspaceNames() {
79  		return null;
80  	}
81  
82  	/**
83  	 * To be overridden in order to programmatically set relationships between
84  	 * roles. Does nothing by default.
85  	 */
86  	protected void configureStandardRoles() {
87  	}
88  
89  	/**
90  	 * Creates the base JCR tree structure expected for this app if necessary.
91  	 * 
92  	 * Expects a clean session ({@link Session#hasPendingChanges()} should return
93  	 * false) and saves it once the changes have been done. Thus the session can be
94  	 * rolled back if an exception occurs.
95  	 * 
96  	 * @return true if something as been updated
97  	 */
98  	public boolean prepareJcrTree(Session adminSession) throws RepositoryException, IOException {
99  		return false;
100 	}
101 
102 	/**
103 	 * Adds app specific default privileges.
104 	 * 
105 	 * Expects a clean session ({@link Session#hasPendingChanges()} should return
106 	 * false} and saves it once the changes have been done. Thus the session can be
107 	 * rolled back if an exception occurs.
108 	 * 
109 	 * Warning: no check is done and corresponding privileges are always added, so
110 	 * only call this when necessary
111 	 */
112 	public void configurePrivileges(Session session) throws RepositoryException {
113 	}
114 
115 	/** The system roles that must be available in the system. */
116 	protected Set<String> getRequiredRoles() {
117 		return new HashSet<>();
118 	}
119 
120 	public void destroy() {
121 
122 	}
123 
124 	/*
125 	 * UTILITIES
126 	 */
127 
128 	/** Create these roles as group if they don't exist. */
129 	protected void makeSureRolesExists(EnumSet<? extends Distinguished> enumSet) {
130 		makeSureRolesExists(Distinguished.enumToDns(enumSet));
131 	}
132 
133 	/** Create these roles as group if they don't exist. */
134 	protected void makeSureRolesExists(Set<String> requiredRoles) {
135 		if (requiredRoles == null)
136 			return;
137 		if (getUserAdmin() == null) {
138 			log.warn("No user admin service available, cannot make sure that role exists");
139 			return;
140 		}
141 		for (String role : requiredRoles) {
142 			Role systemRole = getUserAdmin().getRole(role);
143 			if (systemRole == null) {
144 				try {
145 					getUserTransaction().begin();
146 					getUserAdmin().createRole(role, Role.GROUP);
147 					getUserTransaction().commit();
148 					log.info("Created role " + role);
149 				} catch (Exception e) {
150 					try {
151 						getUserTransaction().rollback();
152 					} catch (Exception e1) {
153 						// silent
154 					}
155 					throw new IllegalStateException("Cannot create role " + role, e);
156 				}
157 			}
158 		}
159 	}
160 
161 	/** Add a user or group to a group. */
162 	protected void addToGroup(String roledDn, String groupDn) {
163 		if (roledDn.contentEquals(groupDn)) {
164 			if (log.isTraceEnabled())
165 				log.trace("Ignore adding group " + groupDn + " to itself");
166 			return;
167 		}
168 
169 		if (getUserAdmin() == null) {
170 			log.warn("No user admin service available, cannot add group " + roledDn + " to " + groupDn);
171 			return;
172 		}
173 		Group managerGroup = (Group) getUserAdmin().getRole(roledDn);
174 		Group group = (Group) getUserAdmin().getRole(groupDn);
175 		if (group == null)
176 			throw new IllegalArgumentException("Group " + groupDn + " not found");
177 		try {
178 			getUserTransaction().begin();
179 			if (group.addMember(managerGroup))
180 				log.info("Added " + roledDn + " to " + group);
181 			getUserTransaction().commit();
182 		} catch (Exception e) {
183 			try {
184 				getUserTransaction().rollback();
185 			} catch (Exception e1) {
186 				// silent
187 			}
188 			throw new IllegalStateException("Cannot add " + managerGroup + " to " + group);
189 		}
190 	}
191 
192 	/*
193 	 * DEPENDENCY INJECTION
194 	 */
195 	public void setRepository(Repository repository) {
196 		this.repository = repository;
197 	}
198 
199 //	public void setUserAdminService(UserAdminService userAdminService) {
200 //		this.userAdminService = userAdminService;
201 //	}
202 
203 	protected UserTransaction getUserTransaction() {
204 		return userTransaction;
205 	}
206 
207 	protected UserAdmin getUserAdmin() {
208 		return userAdmin;
209 	}
210 
211 	public void setUserAdmin(UserAdmin userAdmin) {
212 		this.userAdmin = userAdmin;
213 	}
214 
215 	public void setUserTransaction(UserTransaction userTransaction) {
216 		this.userTransaction = userTransaction;
217 	}
218 
219 }