]> git.argeo.org Git - lgpl/argeo-commons.git/blob - NodeHttp.java
0de4cd29a67a38d6a3206e4fb3d9a29c88bccdf0
[lgpl/argeo-commons.git] / NodeHttp.java
1 package org.argeo.cms.internal.http;
2
3 import java.io.IOException;
4 import java.nio.file.Files;
5 import java.nio.file.Path;
6 import java.util.Properties;
7
8 import javax.jcr.Repository;
9 import javax.servlet.ServletException;
10 import javax.servlet.http.HttpServletRequest;
11 import javax.servlet.http.HttpServletResponse;
12
13 import org.apache.commons.logging.Log;
14 import org.apache.commons.logging.LogFactory;
15 import org.apache.jackrabbit.server.SessionProvider;
16 import org.apache.jackrabbit.server.remoting.davex.JcrRemotingServlet;
17 import org.apache.jackrabbit.webdav.simple.SimpleWebdavServlet;
18 import org.argeo.cms.CmsException;
19 import org.argeo.cms.internal.kernel.KernelConstants;
20 import org.argeo.node.NodeConstants;
21 import org.osgi.framework.BundleContext;
22 import org.osgi.framework.FrameworkUtil;
23 import org.osgi.framework.ServiceReference;
24 import org.osgi.service.http.HttpService;
25 import org.osgi.service.http.NamespaceException;
26 import org.osgi.util.tracker.ServiceTracker;
27
28 /**
29 * Intercepts and enriches http access, mainly focusing on security and
30 * transactionality.
31 */
32 public class NodeHttp implements KernelConstants {
33 private final static Log log = LogFactory.getLog(NodeHttp.class);
34
35 // Filters
36 // private final RootFilter rootFilter;
37
38 // private final DoSFilter dosFilter;
39 // private final QoSFilter qosFilter;
40
41 private final BundleContext bc = FrameworkUtil.getBundle(getClass()).getBundleContext();
42
43 private ServiceTracker<Repository, Repository> repositories;
44 private final ServiceTracker<HttpService, HttpService> httpServiceTracker;
45
46 public NodeHttp() {
47 // rootFilter = new RootFilter();
48 // dosFilter = new CustomDosFilter();
49 // qosFilter = new QoSFilter();
50
51 httpServiceTracker = new PrepareHttpStc();
52 httpServiceTracker.open();
53 }
54
55 // class CustomDosFilter extends DoSFilter {
56 // @Override
57 // protected String extractUserId(ServletRequest request) {
58 // HttpSession httpSession = ((HttpServletRequest) request)
59 // .getSession();
60 // if (isSessionAuthenticated(httpSession)) {
61 // String userId = ((SecurityContext) httpSession
62 // .getAttribute(SPRING_SECURITY_CONTEXT_KEY))
63 // .getAuthentication().getName();
64 // return userId;
65 // }
66 // return super.extractUserId(request);
67 //
68 // }
69 // }
70
71 public void destroy() {
72 repositories.close();
73 }
74
75 void registerRepositoryServlets(HttpService httpService, String alias, Repository repository) {
76 if (httpService == null)
77 throw new CmsException("No HTTP service available");
78 try {
79 registerWebdavServlet(httpService, alias, repository);
80 registerRemotingServlet(httpService, alias, repository);
81 if (NodeConstants.HOME.equals(alias))
82 registerFilesServlet(httpService, alias, repository);
83 if (log.isDebugEnabled())
84 log.debug("Registered servlets for repository '" + alias + "'");
85 } catch (Exception e) {
86 throw new CmsException("Could not register servlets for repository '" + alias + "'", e);
87 }
88 }
89
90 void unregisterRepositoryServlets(HttpService httpService, String alias) {
91 if (httpService == null)
92 return;
93 try {
94 httpService.unregister(webdavPath(alias));
95 httpService.unregister(remotingPath(alias));
96 httpService.unregister(filesPath(alias));
97 if (log.isDebugEnabled())
98 log.debug("Unregistered servlets for repository '" + alias + "'");
99 } catch (Exception e) {
100 log.error("Could not unregister servlets for repository '" + alias + "'", e);
101 }
102 }
103
104 void registerWebdavServlet(HttpService httpService, String alias, Repository repository)
105 throws NamespaceException, ServletException {
106 // WebdavServlet webdavServlet = new WebdavServlet(repository, new
107 // OpenInViewSessionProvider(alias));
108 WebdavServlet webdavServlet = new WebdavServlet(repository, new CmsSessionProvider(alias));
109 String path = webdavPath(alias);
110 Properties ip = new Properties();
111 ip.setProperty(WebdavServlet.INIT_PARAM_RESOURCE_CONFIG, HttpUtils.WEBDAV_CONFIG);
112 ip.setProperty(WebdavServlet.INIT_PARAM_RESOURCE_PATH_PREFIX, path);
113 httpService.registerServlet(path, webdavServlet, ip, new DataHttpContext());
114 }
115
116 void registerFilesServlet(HttpService httpService, String alias, Repository repository)
117 throws NamespaceException, ServletException {
118 WebdavServlet filesServlet = new WebdavServlet(repository, new CmsSessionProvider(alias));
119 String path = filesPath(alias);
120 Properties ip = new Properties();
121 ip.setProperty(WebdavServlet.INIT_PARAM_RESOURCE_CONFIG, HttpUtils.WEBDAV_CONFIG);
122 ip.setProperty(WebdavServlet.INIT_PARAM_RESOURCE_PATH_PREFIX, path);
123 httpService.registerServlet(path, filesServlet, ip, new PrivateHttpContext());
124 }
125
126 void registerRemotingServlet(HttpService httpService, String alias, Repository repository)
127 throws NamespaceException, ServletException {
128 RemotingServlet remotingServlet = new RemotingServlet(repository, new CmsSessionProvider(alias));
129 String path = remotingPath(alias);
130 Properties ip = new Properties();
131 ip.setProperty(JcrRemotingServlet.INIT_PARAM_RESOURCE_PATH_PREFIX, path);
132
133 // Looks like a bug in Jackrabbit remoting init
134 Path tmpDir;
135 try {
136 tmpDir = Files.createTempDirectory("remoting_" + alias);
137 } catch (IOException e) {
138 throw new CmsException("Cannot create temp directory for remoting servlet", e);
139 }
140 ip.setProperty(RemotingServlet.INIT_PARAM_HOME, tmpDir.toString());
141 ip.setProperty(RemotingServlet.INIT_PARAM_TMP_DIRECTORY, "remoting_" + alias);
142 ip.setProperty(RemotingServlet.INIT_PARAM_PROTECTED_HANDLERS_CONFIG, HttpUtils.DEFAULT_PROTECTED_HANDLERS);
143 ip.setProperty(RemotingServlet.INIT_PARAM_CREATE_ABSOLUTE_URI, "false");
144 httpService.registerServlet(path, remotingServlet, ip, new PrivateHttpContext());
145 }
146
147 private String webdavPath(String alias) {
148 return NodeConstants.PATH_DATA + "/" + alias;
149 }
150
151 private String remotingPath(String alias) {
152 return NodeConstants.PATH_JCR + "/" + alias;
153 }
154
155 private String filesPath(String alias) {
156 return NodeConstants.PATH_FILES;
157 }
158
159 // private Subject subjectFromRequest(HttpServletRequest request,
160 // HttpServletResponse response) {
161 // Authorization authorization = (Authorization)
162 // request.getAttribute(HttpContext.AUTHORIZATION);
163 // if (authorization == null)
164 // throw new CmsException("Not authenticated");
165 // try {
166 // LoginContext lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER,
167 // new HttpRequestCallbackHandler(request, response));
168 // lc.login();
169 // return lc.getSubject();
170 // } catch (LoginException e) {
171 // throw new CmsException("Cannot login", e);
172 // }
173 // }
174
175 private class RepositoriesStc extends ServiceTracker<Repository, Repository> {
176 private final HttpService httpService;
177
178 public RepositoriesStc(HttpService httpService) {
179 super(bc, Repository.class, null);
180 this.httpService = httpService;
181 }
182
183 @Override
184 public Repository addingService(ServiceReference<Repository> reference) {
185 Repository repository = bc.getService(reference);
186 Object jcrRepoAlias = reference.getProperty(NodeConstants.CN);
187 if (jcrRepoAlias != null) {
188 String alias = jcrRepoAlias.toString();
189 registerRepositoryServlets(httpService, alias, repository);
190 }
191 return repository;
192 }
193
194 @Override
195 public void modifiedService(ServiceReference<Repository> reference, Repository service) {
196 }
197
198 @Override
199 public void removedService(ServiceReference<Repository> reference, Repository service) {
200 Object jcrRepoAlias = reference.getProperty(NodeConstants.CN);
201 if (jcrRepoAlias != null) {
202 String alias = jcrRepoAlias.toString();
203 unregisterRepositoryServlets(httpService, alias);
204 }
205 }
206 }
207
208 private class PrepareHttpStc extends ServiceTracker<HttpService, HttpService> {
209 // private DataHttp dataHttp;
210 // private NodeHttp nodeHttp;
211
212 public PrepareHttpStc() {
213 super(bc, HttpService.class, null);
214 }
215
216 @Override
217 public HttpService addingService(ServiceReference<HttpService> reference) {
218 HttpService httpService = addHttpService(reference);
219 return httpService;
220 }
221
222 @Override
223 public void removedService(ServiceReference<HttpService> reference, HttpService service) {
224 // if (dataHttp != null)
225 // dataHttp.destroy();
226 // dataHttp = null;
227 // if (nodeHttp != null)
228 // nodeHttp.destroy();
229 // nodeHttp = null;
230 // destroy();
231 repositories.close();
232 repositories = null;
233 }
234
235 private HttpService addHttpService(ServiceReference<HttpService> sr) {
236 HttpService httpService = bc.getService(sr);
237 // TODO find constants
238 Object httpPort = sr.getProperty("http.port");
239 Object httpsPort = sr.getProperty("https.port");
240
241 try {
242 httpService.registerServlet("/!", new LinkServlet(), null, null);
243 httpService.registerServlet("/robots.txt", new RobotServlet(), null, null);
244 } catch (Exception e) {
245 throw new CmsException("Cannot register filters", e);
246 }
247 // track repositories
248 if (repositories != null)
249 throw new CmsException("An http service is already configured");
250 repositories = new RepositoriesStc(httpService);
251 repositories.open();
252 log.info(httpPortsMsg(httpPort, httpsPort));
253 // httpAvailable = true;
254 // checkReadiness();
255
256 bc.registerService(NodeHttp.class, NodeHttp.this, null);
257 return httpService;
258 }
259
260 private String httpPortsMsg(Object httpPort, Object httpsPort) {
261 return "HTTP " + httpPort + (httpsPort != null ? " - HTTPS " + httpsPort : "");
262 }
263 }
264
265 private class WebdavServlet extends SimpleWebdavServlet {
266 private static final long serialVersionUID = -4687354117811443881L;
267 private final Repository repository;
268
269 public WebdavServlet(Repository repository, SessionProvider sessionProvider) {
270 this.repository = repository;
271 setSessionProvider(sessionProvider);
272 }
273
274 public Repository getRepository() {
275 return repository;
276 }
277
278 @Override
279 protected void service(final HttpServletRequest request, final HttpServletResponse response)
280 throws ServletException, IOException {
281 WebdavServlet.super.service(request, response);
282 // try {
283 // Subject subject = subjectFromRequest(request);
284 // // TODO make it stronger, with eTags.
285 // // if (CurrentUser.isAnonymous(subject) &&
286 // // request.getMethod().equals("GET")) {
287 // // response.setHeader("Cache-Control", "no-transform, public,
288 // // max-age=300, s-maxage=900");
289 // // }
290 //
291 // Subject.doAs(subject, new PrivilegedExceptionAction<Void>() {
292 // @Override
293 // public Void run() throws Exception {
294 // WebdavServlet.super.service(request, response);
295 // return null;
296 // }
297 // });
298 // } catch (PrivilegedActionException e) {
299 // throw new CmsException("Cannot process webdav request",
300 // e.getException());
301 // }
302 }
303 }
304
305 private class RemotingServlet extends JcrRemotingServlet {
306 private static final long serialVersionUID = 4605238259548058883L;
307 private final Repository repository;
308 private final SessionProvider sessionProvider;
309
310 public RemotingServlet(Repository repository, SessionProvider sessionProvider) {
311 this.repository = repository;
312 this.sessionProvider = sessionProvider;
313 }
314
315 @Override
316 protected Repository getRepository() {
317 return repository;
318 }
319
320 @Override
321 protected SessionProvider getSessionProvider() {
322 return sessionProvider;
323 }
324
325 @Override
326 protected void service(final HttpServletRequest request, final HttpServletResponse response)
327 throws ServletException, IOException {
328 // try {
329 // Subject subject = subjectFromRequest(request, response);
330 // Subject.doAs(subject, new PrivilegedExceptionAction<Void>() {
331 // @Override
332 // public Void run() throws Exception {
333 RemotingServlet.super.service(request, response);
334 // return null;
335 // }
336 // });
337 // } catch (PrivilegedActionException e) {
338 // throw new CmsException("Cannot process JCR remoting request",
339 // e.getException());
340 // }
341 }
342 }
343
344 }