]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeHttp.java
Remove deprecated code
[lgpl/argeo-commons.git] / org.argeo.cms / src / org / argeo / cms / internal / kernel / NodeHttp.java
1 package org.argeo.cms.internal.kernel;
2
3 import java.io.IOException;
4 import java.util.Properties;
5 import java.util.StringTokenizer;
6
7 import javax.servlet.FilterChain;
8 import javax.servlet.Servlet;
9 import javax.servlet.ServletException;
10 import javax.servlet.http.HttpServletRequest;
11 import javax.servlet.http.HttpServletResponse;
12 import javax.servlet.http.HttpSession;
13
14 import org.apache.commons.codec.binary.Base64;
15 import org.apache.commons.logging.Log;
16 import org.apache.commons.logging.LogFactory;
17 import org.argeo.cms.CmsException;
18 import org.argeo.jackrabbit.servlet.OpenInViewSessionProvider;
19 import org.argeo.jackrabbit.servlet.RemotingServlet;
20 import org.argeo.jackrabbit.servlet.WebdavServlet;
21 import org.argeo.jcr.ArgeoJcrConstants;
22 import org.eclipse.equinox.http.servlet.ExtendedHttpService;
23 import org.osgi.framework.BundleContext;
24 import org.osgi.service.http.NamespaceException;
25 import org.osgi.util.tracker.ServiceTracker;
26 import org.springframework.security.authentication.AuthenticationManager;
27 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
28 import org.springframework.security.core.Authentication;
29 import org.springframework.security.core.context.SecurityContext;
30 import org.springframework.security.core.context.SecurityContextHolder;
31
32 /**
33 * Intercepts and enriches http access, mainly focusing on security and
34 * transactionality.
35 */
36 class NodeHttp implements KernelConstants, ArgeoJcrConstants {
37 private final static Log log = LogFactory.getLog(NodeHttp.class);
38
39 private final static String ATTR_AUTH = "auth";
40 private final static String HEADER_AUTHORIZATION = "Authorization";
41 private final static String HEADER_WWW_AUTHENTICATE = "WWW-Authenticate";
42
43 static final String SPRING_SECURITY_CONTEXT_KEY = "SPRING_SECURITY_CONTEXT";
44
45 private final AuthenticationManager authenticationManager;
46 private final BundleContext bundleContext;
47 private ExtendedHttpService httpService;
48
49 // FIXME Make it more unique
50 private String httpAuthRealm = "Argeo";
51
52 // Filters
53 // private final RootFilter rootFilter;
54
55 // remoting
56 private OpenInViewSessionProvider sessionProvider;
57 private WebdavServlet publicWebdavServlet;
58 private WebdavServlet privateWebdavServlet;
59 private RemotingServlet publicRemotingServlet;
60 private RemotingServlet privateRemotingServlet;
61
62 NodeHttp(BundleContext bundleContext, JackrabbitNode node,
63 NodeSecurity authenticationManager) {
64 this.bundleContext = bundleContext;
65 this.authenticationManager = authenticationManager;
66
67 // Equinox dependency
68 ServiceTracker<ExtendedHttpService, ExtendedHttpService> st = new ServiceTracker<ExtendedHttpService, ExtendedHttpService>(
69 bundleContext, ExtendedHttpService.class, null);
70 st.open();
71 try {
72 httpService = st.waitForService(1000);
73 } catch (InterruptedException e) {
74 httpService = null;
75 }
76
77 if (httpService == null)
78 throw new CmsException("Could not find "
79 + ExtendedHttpService.class + " service.");
80
81 // Filters
82 // rootFilter = new RootFilter();
83
84 // DAV
85 sessionProvider = new OpenInViewSessionProvider();
86 publicWebdavServlet = new WebdavServlet(node, sessionProvider);
87 privateWebdavServlet = new WebdavServlet(node, sessionProvider);
88 publicRemotingServlet = new RemotingServlet(node, sessionProvider);
89 privateRemotingServlet = new RemotingServlet(node, sessionProvider);
90 }
91
92 void publish() {
93 try {
94 registerWebdavServlet(PATH_WEBDAV_PUBLIC, ALIAS_NODE, true,
95 publicWebdavServlet);
96 registerWebdavServlet(PATH_WEBDAV_PRIVATE, ALIAS_NODE, false,
97 privateWebdavServlet);
98 registerRemotingServlet(PATH_REMOTING_PUBLIC, ALIAS_NODE, true,
99 publicRemotingServlet);
100 registerRemotingServlet(PATH_REMOTING_PRIVATE, ALIAS_NODE, false,
101 privateRemotingServlet);
102
103 // httpService.registerFilter("/", rootFilter, null, null);
104 } catch (Exception e) {
105 throw new CmsException("Cannot publish HTTP services to OSGi", e);
106 }
107 }
108
109 private void registerWebdavServlet(String pathPrefix, String alias,
110 Boolean anonymous, WebdavServlet webdavServlet)
111 throws NamespaceException, ServletException {
112 String path = pathPrefix + "/" + alias;
113 Properties initParameters = new Properties();
114 initParameters.setProperty(WebdavServlet.INIT_PARAM_RESOURCE_CONFIG,
115 KernelConstants.WEBDAV_CONFIG);
116 initParameters.setProperty(
117 WebdavServlet.INIT_PARAM_RESOURCE_PATH_PREFIX, path);
118 httpService.registerFilter(path, anonymous ? new AnonymousFilter()
119 : new DavFilter(), null, null);
120 // Cast to servlet because of a weird behaviour in Eclipse
121 httpService.registerServlet(path, (Servlet) webdavServlet,
122 initParameters, null);
123 }
124
125 private void registerRemotingServlet(String pathPrefix, String alias,
126 Boolean anonymous, RemotingServlet remotingServlet)
127 throws NamespaceException, ServletException {
128 String path = pathPrefix + "/" + alias;
129 Properties initParameters = new Properties();
130 initParameters.setProperty(
131 RemotingServlet.INIT_PARAM_RESOURCE_PATH_PREFIX, path);
132
133 // Looks like a bug in Jackrabbit remoting init
134 initParameters.setProperty(RemotingServlet.INIT_PARAM_HOME,
135 KernelUtils.getOsgiInstanceDir(bundleContext)
136 + "/tmp/jackrabbit");
137 initParameters.setProperty(RemotingServlet.INIT_PARAM_TMP_DIRECTORY,
138 "remoting");
139 // Cast to servlet because of a weird behaviour in Eclipse
140 httpService.registerFilter(path, anonymous ? new AnonymousFilter()
141 : new DavFilter(), null, null);
142 httpService.registerServlet(path, (Servlet) remotingServlet,
143 initParameters, null);
144 }
145
146 private Boolean isSessionAuthenticated(HttpSession httpSession) {
147 SecurityContext contextFromSession = (SecurityContext) httpSession
148 .getAttribute(SPRING_SECURITY_CONTEXT_KEY);
149 return contextFromSession != null;
150 }
151
152 private void requestBasicAuth(HttpSession httpSession,
153 HttpServletResponse response) {
154 response.setStatus(401);
155 response.setHeader(HEADER_WWW_AUTHENTICATE, "basic realm=\""
156 + httpAuthRealm + "\"");
157 httpSession.setAttribute(ATTR_AUTH, Boolean.TRUE);
158 }
159
160 private UsernamePasswordAuthenticationToken basicAuth(String authHeader) {
161 if (authHeader != null) {
162 StringTokenizer st = new StringTokenizer(authHeader);
163 if (st.hasMoreTokens()) {
164 String basic = st.nextToken();
165 if (basic.equalsIgnoreCase("Basic")) {
166 try {
167 String credentials = new String(Base64.decodeBase64(st
168 .nextToken()), "UTF-8");
169 log.debug("Credentials: " + credentials);
170 int p = credentials.indexOf(":");
171 if (p != -1) {
172 String login = credentials.substring(0, p).trim();
173 String password = credentials.substring(p + 1)
174 .trim();
175
176 return new UsernamePasswordAuthenticationToken(
177 login, password);
178 } else {
179 throw new CmsException(
180 "Invalid authentication token");
181 }
182 } catch (Exception e) {
183 throw new CmsException(
184 "Couldn't retrieve authentication", e);
185 }
186 }
187 }
188 }
189 throw new CmsException("Couldn't retrieve authentication");
190 }
191
192 /** Intercepts all requests. Authenticates. */
193 class RootFilter extends HttpFilter {
194
195 @Override
196 public void doFilter(HttpSession httpSession,
197 HttpServletRequest request, HttpServletResponse response,
198 FilterChain filterChain) throws IOException, ServletException {
199
200 // Authenticate from session
201 if (isSessionAuthenticated(httpSession)) {
202 filterChain.doFilter(request, response);
203 return;
204 }
205
206 // TODO Kerberos
207
208 // TODO Certificate
209
210 // Process basic auth
211 String basicAuth = request.getHeader(HEADER_AUTHORIZATION);
212 if (basicAuth != null) {
213 UsernamePasswordAuthenticationToken token = basicAuth(basicAuth);
214 Authentication auth = authenticationManager.authenticate(token);
215 SecurityContextHolder.getContext().setAuthentication(auth);
216 httpSession.setAttribute(SPRING_SECURITY_CONTEXT_KEY,
217 SecurityContextHolder.getContext());
218 httpSession.setAttribute(ATTR_AUTH, Boolean.FALSE);
219 filterChain.doFilter(request, response);
220 return;
221 }
222
223 Boolean doBasicAuth = true;
224 if (doBasicAuth) {
225 requestBasicAuth(httpSession, response);
226 // skip filter chain
227 return;
228 }
229
230 // TODO Login page
231
232 // Anonymous
233 KernelUtils.anonymousLogin(authenticationManager);
234 filterChain.doFilter(request, response);
235 }
236 }
237
238 /** Intercepts all requests. Authenticates. */
239 class AnonymousFilter extends HttpFilter {
240 @Override
241 public void doFilter(HttpSession httpSession,
242 HttpServletRequest request, HttpServletResponse response,
243 FilterChain filterChain) throws IOException, ServletException {
244
245 // Authenticate from session
246 if (isSessionAuthenticated(httpSession)) {
247 filterChain.doFilter(request, response);
248 return;
249 }
250
251 KernelUtils.anonymousLogin(authenticationManager);
252 filterChain.doFilter(request, response);
253 }
254 }
255
256 /** Intercepts all requests. Authenticates. */
257 class DavFilter extends HttpFilter {
258
259 @Override
260 public void doFilter(HttpSession httpSession,
261 HttpServletRequest request, HttpServletResponse response,
262 FilterChain filterChain) throws IOException, ServletException {
263
264 // Authenticate from session
265 if (isSessionAuthenticated(httpSession)) {
266 filterChain.doFilter(request, response);
267 return;
268 }
269
270 // Process basic auth
271 String basicAuth = request.getHeader(HEADER_AUTHORIZATION);
272 if (basicAuth != null) {
273 UsernamePasswordAuthenticationToken token = basicAuth(basicAuth);
274 Authentication auth = authenticationManager.authenticate(token);
275 SecurityContextHolder.getContext().setAuthentication(auth);
276 httpSession.setAttribute(SPRING_SECURITY_CONTEXT_KEY,
277 SecurityContextHolder.getContext());
278 httpSession.setAttribute(ATTR_AUTH, Boolean.FALSE);
279 filterChain.doFilter(request, response);
280 return;
281 }
282
283 requestBasicAuth(httpSession, response);
284 }
285 }
286
287 }