]> git.argeo.org Git - lgpl/argeo-commons.git/blob - NodeHttp.java
901731aa063eb2c113d1376c33e85477a1413f4e
[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 if (NodeConstants.HOME.equals(alias))
97 httpService.unregister(filesPath(alias));
98 if (log.isDebugEnabled())
99 log.debug("Unregistered servlets for repository '" + alias + "'");
100 } catch (Exception e) {
101 log.error("Could not unregister servlets for repository '" + alias + "'", e);
102 }
103 }
104
105 void registerWebdavServlet(HttpService httpService, String alias, Repository repository)
106 throws NamespaceException, ServletException {
107 // WebdavServlet webdavServlet = new WebdavServlet(repository, new
108 // OpenInViewSessionProvider(alias));
109 WebdavServlet webdavServlet = new WebdavServlet(repository, new CmsSessionProvider(alias));
110 String path = webdavPath(alias);
111 Properties ip = new Properties();
112 ip.setProperty(WebdavServlet.INIT_PARAM_RESOURCE_CONFIG, HttpUtils.WEBDAV_CONFIG);
113 ip.setProperty(WebdavServlet.INIT_PARAM_RESOURCE_PATH_PREFIX, path);
114 httpService.registerServlet(path, webdavServlet, ip, new DataHttpContext());
115 }
116
117 void registerFilesServlet(HttpService httpService, String alias, Repository repository)
118 throws NamespaceException, ServletException {
119 WebdavServlet filesServlet = new WebdavServlet(repository, new CmsSessionProvider(alias));
120 String path = filesPath(alias);
121 Properties ip = new Properties();
122 ip.setProperty(WebdavServlet.INIT_PARAM_RESOURCE_CONFIG, HttpUtils.WEBDAV_CONFIG);
123 ip.setProperty(WebdavServlet.INIT_PARAM_RESOURCE_PATH_PREFIX, path);
124 httpService.registerServlet(path, filesServlet, ip, new PrivateHttpContext());
125 }
126
127 void registerRemotingServlet(HttpService httpService, String alias, Repository repository)
128 throws NamespaceException, ServletException {
129 RemotingServlet remotingServlet = new RemotingServlet(repository, new CmsSessionProvider(alias));
130 String path = remotingPath(alias);
131 Properties ip = new Properties();
132 ip.setProperty(JcrRemotingServlet.INIT_PARAM_RESOURCE_PATH_PREFIX, path);
133
134 // Looks like a bug in Jackrabbit remoting init
135 Path tmpDir;
136 try {
137 tmpDir = Files.createTempDirectory("remoting_" + alias);
138 } catch (IOException e) {
139 throw new CmsException("Cannot create temp directory for remoting servlet", e);
140 }
141 ip.setProperty(RemotingServlet.INIT_PARAM_HOME, tmpDir.toString());
142 ip.setProperty(RemotingServlet.INIT_PARAM_TMP_DIRECTORY, "remoting_" + alias);
143 ip.setProperty(RemotingServlet.INIT_PARAM_PROTECTED_HANDLERS_CONFIG, HttpUtils.DEFAULT_PROTECTED_HANDLERS);
144 ip.setProperty(RemotingServlet.INIT_PARAM_CREATE_ABSOLUTE_URI, "false");
145 httpService.registerServlet(path, remotingServlet, ip, new PrivateHttpContext());
146 }
147
148 private String webdavPath(String alias) {
149 return NodeConstants.PATH_DATA + "/" + alias;
150 }
151
152 private String remotingPath(String alias) {
153 return NodeConstants.PATH_JCR + "/" + alias;
154 }
155
156 private String filesPath(String alias) {
157 return NodeConstants.PATH_FILES;
158 }
159
160 // private Subject subjectFromRequest(HttpServletRequest request,
161 // HttpServletResponse response) {
162 // Authorization authorization = (Authorization)
163 // request.getAttribute(HttpContext.AUTHORIZATION);
164 // if (authorization == null)
165 // throw new CmsException("Not authenticated");
166 // try {
167 // LoginContext lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER,
168 // new HttpRequestCallbackHandler(request, response));
169 // lc.login();
170 // return lc.getSubject();
171 // } catch (LoginException e) {
172 // throw new CmsException("Cannot login", e);
173 // }
174 // }
175
176 private class RepositoriesStc extends ServiceTracker<Repository, Repository> {
177 private final HttpService httpService;
178
179 public RepositoriesStc(HttpService httpService) {
180 super(bc, Repository.class, null);
181 this.httpService = httpService;
182 }
183
184 @Override
185 public Repository addingService(ServiceReference<Repository> reference) {
186 Repository repository = bc.getService(reference);
187 Object jcrRepoAlias = reference.getProperty(NodeConstants.CN);
188 if (jcrRepoAlias != null) {
189 String alias = jcrRepoAlias.toString();
190 registerRepositoryServlets(httpService, alias, repository);
191 }
192 return repository;
193 }
194
195 @Override
196 public void modifiedService(ServiceReference<Repository> reference, Repository service) {
197 }
198
199 @Override
200 public void removedService(ServiceReference<Repository> reference, Repository service) {
201 Object jcrRepoAlias = reference.getProperty(NodeConstants.CN);
202 if (jcrRepoAlias != null) {
203 String alias = jcrRepoAlias.toString();
204 unregisterRepositoryServlets(httpService, alias);
205 }
206 }
207 }
208
209 private class PrepareHttpStc extends ServiceTracker<HttpService, HttpService> {
210 // private DataHttp dataHttp;
211 // private NodeHttp nodeHttp;
212
213 public PrepareHttpStc() {
214 super(bc, HttpService.class, null);
215 }
216
217 @Override
218 public HttpService addingService(ServiceReference<HttpService> reference) {
219 HttpService httpService = addHttpService(reference);
220 return httpService;
221 }
222
223 @Override
224 public void removedService(ServiceReference<HttpService> reference, HttpService service) {
225 // if (dataHttp != null)
226 // dataHttp.destroy();
227 // dataHttp = null;
228 // if (nodeHttp != null)
229 // nodeHttp.destroy();
230 // nodeHttp = null;
231 // destroy();
232 repositories.close();
233 repositories = null;
234 }
235
236 private HttpService addHttpService(ServiceReference<HttpService> sr) {
237 HttpService httpService = bc.getService(sr);
238 // TODO find constants
239 Object httpPort = sr.getProperty("http.port");
240 Object httpsPort = sr.getProperty("https.port");
241
242 try {
243 httpService.registerServlet("/!", new LinkServlet(), null, null);
244 httpService.registerServlet("/robots.txt", new RobotServlet(), null, null);
245 } catch (Exception e) {
246 throw new CmsException("Cannot register filters", e);
247 }
248 // track repositories
249 if (repositories != null)
250 throw new CmsException("An http service is already configured");
251 repositories = new RepositoriesStc(httpService);
252 repositories.open();
253 log.info(httpPortsMsg(httpPort, httpsPort));
254 // httpAvailable = true;
255 // checkReadiness();
256
257 bc.registerService(NodeHttp.class, NodeHttp.this, null);
258 return httpService;
259 }
260
261 private String httpPortsMsg(Object httpPort, Object httpsPort) {
262 return "HTTP " + httpPort + (httpsPort != null ? " - HTTPS " + httpsPort : "");
263 }
264 }
265
266 private class WebdavServlet extends SimpleWebdavServlet {
267 private static final long serialVersionUID = -4687354117811443881L;
268 private final Repository repository;
269
270 public WebdavServlet(Repository repository, SessionProvider sessionProvider) {
271 this.repository = repository;
272 setSessionProvider(sessionProvider);
273 }
274
275 public Repository getRepository() {
276 return repository;
277 }
278
279 @Override
280 protected void service(final HttpServletRequest request, final HttpServletResponse response)
281 throws ServletException, IOException {
282 WebdavServlet.super.service(request, response);
283 // try {
284 // Subject subject = subjectFromRequest(request);
285 // // TODO make it stronger, with eTags.
286 // // if (CurrentUser.isAnonymous(subject) &&
287 // // request.getMethod().equals("GET")) {
288 // // response.setHeader("Cache-Control", "no-transform, public,
289 // // max-age=300, s-maxage=900");
290 // // }
291 //
292 // Subject.doAs(subject, new PrivilegedExceptionAction<Void>() {
293 // @Override
294 // public Void run() throws Exception {
295 // WebdavServlet.super.service(request, response);
296 // return null;
297 // }
298 // });
299 // } catch (PrivilegedActionException e) {
300 // throw new CmsException("Cannot process webdav request",
301 // e.getException());
302 // }
303 }
304 }
305
306 private class RemotingServlet extends JcrRemotingServlet {
307 private static final long serialVersionUID = 4605238259548058883L;
308 private final Repository repository;
309 private final SessionProvider sessionProvider;
310
311 public RemotingServlet(Repository repository, SessionProvider sessionProvider) {
312 this.repository = repository;
313 this.sessionProvider = sessionProvider;
314 }
315
316 @Override
317 protected Repository getRepository() {
318 return repository;
319 }
320
321 @Override
322 protected SessionProvider getSessionProvider() {
323 return sessionProvider;
324 }
325
326 @Override
327 protected void service(final HttpServletRequest request, final HttpServletResponse response)
328 throws ServletException, IOException {
329 // try {
330 // Subject subject = subjectFromRequest(request, response);
331 // Subject.doAs(subject, new PrivilegedExceptionAction<Void>() {
332 // @Override
333 // public Void run() throws Exception {
334 RemotingServlet.super.service(request, response);
335 // return null;
336 // }
337 // });
338 // } catch (PrivilegedActionException e) {
339 // throw new CmsException("Cannot process JCR remoting request",
340 // e.getException());
341 // }
342 }
343 }
344
345 }