1 package org
.argeo
.cms
.internal
.kernel
;
3 import java
.io
.IOException
;
4 import java
.util
.Properties
;
5 import java
.util
.StringTokenizer
;
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
;
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
;
33 * Intercepts and enriches http access, mainly focusing on security and
36 class NodeHttp
implements KernelConstants
, ArgeoJcrConstants
{
37 private final static Log log
= LogFactory
.getLog(NodeHttp
.class);
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";
43 private final AuthenticationManager authenticationManager
;
44 private final BundleContext bundleContext
;
45 private ExtendedHttpService httpService
;
47 // FIXME Make it more unique
48 private String httpAuthRealm
= "Argeo";
51 // private final RootFilter rootFilter;
54 private OpenInViewSessionProvider sessionProvider
;
55 private WebdavServlet publicWebdavServlet
;
56 private WebdavServlet privateWebdavServlet
;
57 private RemotingServlet publicRemotingServlet
;
58 private RemotingServlet privateRemotingServlet
;
60 NodeHttp(BundleContext bundleContext
, JackrabbitNode node
,
61 NodeSecurity authenticationManager
) {
62 this.bundleContext
= bundleContext
;
63 this.authenticationManager
= authenticationManager
;
66 ServiceTracker
<ExtendedHttpService
, ExtendedHttpService
> st
= new ServiceTracker
<ExtendedHttpService
, ExtendedHttpService
>(
67 bundleContext
, ExtendedHttpService
.class, null);
70 httpService
= st
.waitForService(1000);
71 } catch (InterruptedException e
) {
75 if (httpService
== null)
76 throw new CmsException("Could not find "
77 + ExtendedHttpService
.class + " service.");
80 // rootFilter = new RootFilter();
83 sessionProvider
= new OpenInViewSessionProvider();
84 publicWebdavServlet
= new WebdavServlet(node
, sessionProvider
);
85 privateWebdavServlet
= new WebdavServlet(node
, sessionProvider
);
86 publicRemotingServlet
= new RemotingServlet(node
, sessionProvider
);
87 privateRemotingServlet
= new RemotingServlet(node
, sessionProvider
);
92 registerWebdavServlet(PATH_WEBDAV_PUBLIC
, ALIAS_NODE
, true,
94 registerWebdavServlet(PATH_WEBDAV_PRIVATE
, ALIAS_NODE
, false,
95 privateWebdavServlet
);
96 registerRemotingServlet(PATH_REMOTING_PUBLIC
, ALIAS_NODE
, true,
97 publicRemotingServlet
);
98 registerRemotingServlet(PATH_REMOTING_PRIVATE
, ALIAS_NODE
, false,
99 privateRemotingServlet
);
101 // httpService.registerFilter("/", rootFilter, null, null);
102 } catch (Exception e
) {
103 throw new CmsException("Cannot publish HTTP services to OSGi", e
);
107 private void registerWebdavServlet(String pathPrefix
, String alias
,
108 Boolean anonymous
, WebdavServlet webdavServlet
)
109 throws NamespaceException
, ServletException
{
110 String path
= pathPrefix
+ "/" + alias
;
111 Properties initParameters
= new Properties();
112 initParameters
.setProperty(WebdavServlet
.INIT_PARAM_RESOURCE_CONFIG
,
113 KernelConstants
.WEBDAV_CONFIG
);
114 initParameters
.setProperty(
115 WebdavServlet
.INIT_PARAM_RESOURCE_PATH_PREFIX
, path
);
116 httpService
.registerFilter(path
, anonymous ?
new AnonymousFilter()
117 : new DavFilter(), null, null);
118 // Cast to servlet because of a weird behaviour in Eclipse
119 httpService
.registerServlet(path
, (Servlet
) webdavServlet
,
120 initParameters
, null);
123 private void registerRemotingServlet(String pathPrefix
, String alias
,
124 Boolean anonymous
, RemotingServlet remotingServlet
)
125 throws NamespaceException
, ServletException
{
126 String path
= pathPrefix
+ "/" + alias
;
127 Properties initParameters
= new Properties();
128 initParameters
.setProperty(
129 RemotingServlet
.INIT_PARAM_RESOURCE_PATH_PREFIX
, path
);
131 // Looks like a bug in Jackrabbit remoting init
132 initParameters
.setProperty(RemotingServlet
.INIT_PARAM_HOME
,
133 KernelUtils
.getOsgiInstanceDir(bundleContext
)
134 + "/tmp/jackrabbit");
135 initParameters
.setProperty(RemotingServlet
.INIT_PARAM_TMP_DIRECTORY
,
137 // Cast to servlet because of a weird behaviour in Eclipse
138 httpService
.registerFilter(path
, anonymous ?
new AnonymousFilter()
139 : new DavFilter(), null, null);
140 httpService
.registerServlet(path
, (Servlet
) remotingServlet
,
141 initParameters
, null);
144 private Boolean
isSessionAuthenticated(HttpSession httpSession
) {
145 SecurityContext contextFromSession
= (SecurityContext
) httpSession
146 .getAttribute(SPRING_SECURITY_CONTEXT_KEY
);
147 return contextFromSession
!= null;
150 private void requestBasicAuth(HttpSession httpSession
,
151 HttpServletResponse response
) {
152 response
.setStatus(401);
153 response
.setHeader(HEADER_WWW_AUTHENTICATE
, "basic realm=\""
154 + httpAuthRealm
+ "\"");
155 httpSession
.setAttribute(ATTR_AUTH
, Boolean
.TRUE
);
158 private UsernamePasswordAuthenticationToken
basicAuth(String authHeader
) {
159 if (authHeader
!= null) {
160 StringTokenizer st
= new StringTokenizer(authHeader
);
161 if (st
.hasMoreTokens()) {
162 String basic
= st
.nextToken();
163 if (basic
.equalsIgnoreCase("Basic")) {
165 String credentials
= new String(Base64
.decodeBase64(st
166 .nextToken()), "UTF-8");
167 log
.debug("Credentials: " + credentials
);
168 int p
= credentials
.indexOf(":");
170 String login
= credentials
.substring(0, p
).trim();
171 String password
= credentials
.substring(p
+ 1)
174 return new UsernamePasswordAuthenticationToken(
177 throw new CmsException(
178 "Invalid authentication token");
180 } catch (Exception e
) {
181 throw new CmsException(
182 "Couldn't retrieve authentication", e
);
187 throw new CmsException("Couldn't retrieve authentication");
190 /** Intercepts all requests. Authenticates. */
191 class RootFilter
extends HttpFilter
{
194 public void doFilter(HttpSession httpSession
,
195 HttpServletRequest request
, HttpServletResponse response
,
196 FilterChain filterChain
) throws IOException
, ServletException
{
198 // Authenticate from session
199 if (isSessionAuthenticated(httpSession
)) {
200 filterChain
.doFilter(request
, response
);
208 // Process basic auth
209 String basicAuth
= request
.getHeader(HEADER_AUTHORIZATION
);
210 if (basicAuth
!= null) {
211 UsernamePasswordAuthenticationToken token
= basicAuth(basicAuth
);
212 Authentication auth
= authenticationManager
.authenticate(token
);
213 SecurityContextHolder
.getContext().setAuthentication(auth
);
214 httpSession
.setAttribute(SPRING_SECURITY_CONTEXT_KEY
,
215 SecurityContextHolder
.getContext());
216 httpSession
.setAttribute(ATTR_AUTH
, Boolean
.FALSE
);
217 filterChain
.doFilter(request
, response
);
221 Boolean doBasicAuth
= true;
223 requestBasicAuth(httpSession
, response
);
231 KernelUtils
.anonymousLogin(authenticationManager
);
232 filterChain
.doFilter(request
, response
);
236 /** Intercepts all requests. Authenticates. */
237 class AnonymousFilter
extends HttpFilter
{
239 public void doFilter(HttpSession httpSession
,
240 HttpServletRequest request
, HttpServletResponse response
,
241 FilterChain filterChain
) throws IOException
, ServletException
{
243 // Authenticate from session
244 if (isSessionAuthenticated(httpSession
)) {
245 filterChain
.doFilter(request
, response
);
249 KernelUtils
.anonymousLogin(authenticationManager
);
250 filterChain
.doFilter(request
, response
);
254 /** Intercepts all requests. Authenticates. */
255 class DavFilter
extends HttpFilter
{
258 public void doFilter(HttpSession httpSession
,
259 HttpServletRequest request
, HttpServletResponse response
,
260 FilterChain filterChain
) throws IOException
, ServletException
{
262 // Authenticate from session
263 if (isSessionAuthenticated(httpSession
)) {
264 filterChain
.doFilter(request
, response
);
268 // Process basic auth
269 String basicAuth
= request
.getHeader(HEADER_AUTHORIZATION
);
270 if (basicAuth
!= null) {
271 UsernamePasswordAuthenticationToken token
= basicAuth(basicAuth
);
272 Authentication auth
= authenticationManager
.authenticate(token
);
273 SecurityContextHolder
.getContext().setAuthentication(auth
);
274 httpSession
.setAttribute(SPRING_SECURITY_CONTEXT_KEY
,
275 SecurityContextHolder
.getContext());
276 httpSession
.setAttribute(ATTR_AUTH
, Boolean
.FALSE
);
277 filterChain
.doFilter(request
, response
);
281 requestBasicAuth(httpSession
, response
);