]> git.argeo.org Git - lgpl/argeo-commons.git/blob - DataHttpContext.java
581d6cbc1323c7add3783035da642a017c3fc5f3
[lgpl/argeo-commons.git] / DataHttpContext.java
1 package org.argeo.cms.internal.http;
2
3 import java.io.IOException;
4 import java.net.URL;
5 import java.util.StringTokenizer;
6
7 import javax.security.auth.callback.Callback;
8 import javax.security.auth.callback.CallbackHandler;
9 import javax.security.auth.callback.NameCallback;
10 import javax.security.auth.callback.PasswordCallback;
11 import javax.security.auth.login.LoginContext;
12 import javax.security.auth.login.LoginException;
13 import javax.servlet.http.HttpServletRequest;
14 import javax.servlet.http.HttpServletResponse;
15
16 import org.apache.commons.codec.binary.Base64;
17 import org.apache.commons.logging.Log;
18 import org.apache.commons.logging.LogFactory;
19 import org.argeo.cms.CmsException;
20 import org.argeo.cms.auth.HttpRequestCallback;
21 import org.argeo.cms.auth.HttpRequestCallbackHandler;
22 import org.argeo.node.NodeConstants;
23 import org.ietf.jgss.GSSContext;
24 import org.ietf.jgss.GSSCredential;
25 import org.ietf.jgss.GSSException;
26 import org.ietf.jgss.GSSManager;
27 import org.ietf.jgss.GSSName;
28 import org.ietf.jgss.Oid;
29 import org.osgi.framework.BundleContext;
30 import org.osgi.framework.FrameworkUtil;
31 import org.osgi.service.http.HttpContext;
32
33 class DataHttpContext implements HttpContext {
34 private final static Log log = LogFactory.getLog(DataHttpContext.class);
35
36 private final BundleContext bc = FrameworkUtil.getBundle(getClass()).getBundleContext();
37
38 // FIXME Make it more unique
39 private String httpAuthRealm = "Argeo";
40
41 @Override
42 public boolean handleSecurity(final HttpServletRequest request, HttpServletResponse response) throws IOException {
43
44 if (log.isTraceEnabled())
45 HttpUtils.logRequestHeaders(log, request);
46 LoginContext lc;
47 try {
48 lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER, new HttpRequestCallbackHandler(request, response));
49 lc.login();
50 // return true;
51 } catch (LoginException e) {
52 CallbackHandler token = extractHttpAuth(request, response);
53 if (token != null) {
54 try {
55 lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER, token);
56 lc.login();
57 } catch (LoginException e1) {
58 throw new CmsException("Could not login", e1);
59 }
60 } else {
61 lc = processUnauthorized(request, response);
62 if (lc == null)
63 return false;
64 }
65 }
66 request.setAttribute(NodeConstants.LOGIN_CONTEXT_USER, lc);
67 return true;
68 }
69
70 @Override
71 public URL getResource(String name) {
72 return bc.getBundle().getResource(name);
73 }
74
75 @Override
76 public String getMimeType(String name) {
77 return null;
78 }
79
80 protected LoginContext processUnauthorized(HttpServletRequest request, HttpServletResponse response) {
81 // anonymous
82 try {
83 LoginContext lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER);
84 lc.login();
85 return lc;
86 } catch (LoginException e1) {
87 if (log.isDebugEnabled())
88 log.error("Cannot log in as anonymous", e1);
89 return null;
90 }
91 }
92
93 protected CallbackHandler extractHttpAuth(final HttpServletRequest httpRequest, HttpServletResponse httpResponse) {
94 String authHeader = httpRequest.getHeader(HttpUtils.HEADER_AUTHORIZATION);
95 if (authHeader != null) {
96 StringTokenizer st = new StringTokenizer(authHeader);
97 if (st.hasMoreTokens()) {
98 String basic = st.nextToken();
99 if (basic.equalsIgnoreCase("Basic")) {
100 try {
101 // TODO manipulate char[]
102 String credentials = new String(Base64.decodeBase64(st.nextToken()), "UTF-8");
103 // log.debug("Credentials: " + credentials);
104 int p = credentials.indexOf(":");
105 if (p != -1) {
106 final String login = credentials.substring(0, p).trim();
107 final char[] password = credentials.substring(p + 1).trim().toCharArray();
108 return new CallbackHandler() {
109 public void handle(Callback[] callbacks) {
110 for (Callback cb : callbacks) {
111 if (cb instanceof NameCallback)
112 ((NameCallback) cb).setName(login);
113 else if (cb instanceof PasswordCallback)
114 ((PasswordCallback) cb).setPassword(password);
115 else if (cb instanceof HttpRequestCallback) {
116 ((HttpRequestCallback) cb).setRequest(httpRequest);
117 ((HttpRequestCallback) cb).setResponse(httpResponse);
118 }
119 }
120 }
121 };
122 } else {
123 throw new CmsException("Invalid authentication token");
124 }
125 } catch (Exception e) {
126 throw new CmsException("Couldn't retrieve authentication", e);
127 }
128 } else if (basic.equalsIgnoreCase("Negotiate")) {
129 // FIXME generalise
130 String _targetName = "HTTP/mostar.desktop.argeo.pro";
131 String spnegoToken = st.nextToken();
132 byte[] authToken = Base64.decodeBase64(spnegoToken);
133 GSSManager manager = GSSManager.getInstance();
134 try {
135 Oid krb5Oid = new Oid("1.3.6.1.5.5.2"); // http://java.sun.com/javase/6/docs/technotes/guides/security/jgss/jgss-features.html
136 GSSName gssName = manager.createName(_targetName, null);
137 GSSCredential serverCreds = manager.createCredential(gssName, GSSCredential.INDEFINITE_LIFETIME,
138 krb5Oid, GSSCredential.ACCEPT_ONLY);
139 GSSContext gContext = manager.createContext(serverCreds);
140
141 if (gContext == null) {
142 log.debug("SpnegoUserRealm: failed to establish GSSContext");
143 } else {
144 while (!gContext.isEstablished()) {
145 byte[] outToken = gContext.acceptSecContext(authToken, 0, authToken.length);
146 String outTokenStr = Base64.encodeBase64String(outToken);
147 httpResponse.setHeader("WWW-Authenticate", "Negotiate " + outTokenStr);
148 }
149 if (gContext.isEstablished()) {
150 String clientName = gContext.getSrcName().toString();
151 String role = clientName.substring(clientName.indexOf('@') + 1);
152
153 log.debug("SpnegoUserRealm: established a security context");
154 log.debug("Client Principal is: " + gContext.getSrcName());
155 log.debug("Server Principal is: " + gContext.getTargName());
156 log.debug("Client Default Role: " + role);
157
158 // TODO log in
159 }
160 }
161
162 } catch (GSSException gsse) {
163 log.warn(gsse, gsse);
164 }
165
166 }
167 }
168 }
169 return null;
170 }
171
172 protected void askForWwwAuth(HttpServletRequest request, HttpServletResponse response) {
173 response.setStatus(401);
174 response.setHeader(HttpUtils.HEADER_WWW_AUTHENTICATE, "basic realm=\"" + httpAuthRealm + "\"");
175
176 // SPNEGO
177 // response.setHeader(HEADER_WWW_AUTHENTICATE, "Negotiate");
178 // response.setDateHeader("Date", System.currentTimeMillis());
179 // response.setDateHeader("Expires", System.currentTimeMillis() + (24 *
180 // 60 * 60 * 1000));
181 // response.setHeader("Accept-Ranges", "bytes");
182 // response.setHeader("Connection", "Keep-Alive");
183 // response.setHeader("Keep-Alive", "timeout=5, max=97");
184 // response.setContentType("text/html; charset=UTF-8");
185
186 }
187
188 }