1 package org
.argeo
.cms
.internal
.http
;
3 import javax
.security
.auth
.Subject
;
4 import javax
.security
.auth
.login
.LoginContext
;
5 import javax
.security
.auth
.login
.LoginException
;
7 import org
.argeo
.api
.cms
.CmsAuth
;
8 import org
.argeo
.api
.cms
.CmsLog
;
9 import org
.argeo
.cms
.auth
.CurrentUser
;
10 import org
.argeo
.cms
.auth
.RemoteAuthCallbackHandler
;
11 import org
.argeo
.cms
.auth
.SpnegoLoginModule
;
13 import com
.sun
.net
.httpserver
.Authenticator
;
14 import com
.sun
.net
.httpserver
.HttpExchange
;
15 import com
.sun
.net
.httpserver
.HttpPrincipal
;
17 public class CmsAuthenticator
extends Authenticator
{
18 final static String HEADER_AUTHORIZATION
= "Authorization";
19 final static String HEADER_WWW_AUTHENTICATE
= "WWW-Authenticate";
21 private final static CmsLog log
= CmsLog
.getLog(CmsAuthenticator
.class);
23 // TODO make it configurable
24 private final String httpAuthRealm
= "Argeo";
25 private final boolean forceBasic
= false;
28 public Result
authenticate(HttpExchange exch
) {
29 // if (log.isTraceEnabled())
30 // HttpUtils.logRequestHeaders(log, request);
31 RemoteAuthHttpExchange remoteAuthHttpExchange
= new RemoteAuthHttpExchange(exch
);
32 ClassLoader currentThreadContextClassLoader
= Thread
.currentThread().getContextClassLoader();
33 Thread
.currentThread().setContextClassLoader(CmsAuthenticator
.class.getClassLoader());
37 .newLoginContext(new RemoteAuthCallbackHandler(remoteAuthHttpExchange
, remoteAuthHttpExchange
));
39 } catch (LoginException e
) {
40 // FIXME better analyse failure so as not to try endlessly
41 if (authIsRequired(exch
)) {
42 return askForWwwAuth(exch
);
44 lc
= processUnauthorized(exch
);
45 // if (log.isTraceEnabled())
46 // HttpUtils.logResponseHeaders(log, response);
49 return new Authenticator
.Failure(403);
51 Thread
.currentThread().setContextClassLoader(currentThreadContextClassLoader
);
54 Subject subject
= lc
.getSubject();
56 // Subject.doAs(subject, new PrivilegedAction<Void>() {
59 // public Void run() {
60 // // TODO also set login context in order to log out ?
61 // RemoteAuthUtils.configureRequestSecurity(new ServletHttpRequest(request));
66 String username
= CurrentUser
.getUsername(subject
);
67 HttpPrincipal httpPrincipal
= new HttpPrincipal(username
, httpAuthRealm
);
68 return new Authenticator
.Success(httpPrincipal
);
71 protected boolean authIsRequired(HttpExchange httpExchange
) {
75 protected LoginContext
processUnauthorized(HttpExchange httpExchange
) {
77 RemoteAuthHttpExchange remoteAuthExchange
= new RemoteAuthHttpExchange(httpExchange
);
79 ClassLoader currentContextClassLoader
= Thread
.currentThread().getContextClassLoader();
81 Thread
.currentThread().setContextClassLoader(CmsAuthenticator
.class.getClassLoader());
82 LoginContext lc
= CmsAuth
.ANONYMOUS
83 .newLoginContext(new RemoteAuthCallbackHandler(remoteAuthExchange
, remoteAuthExchange
));
86 } catch (LoginException e1
) {
87 if (log
.isDebugEnabled())
88 log
.error("Cannot log in as anonymous", e1
);
91 Thread
.currentThread().setContextClassLoader(currentContextClassLoader
);
95 protected Authenticator
.Retry
askForWwwAuth(HttpExchange httpExchange
) {
96 // response.setHeader(HttpUtils.HEADER_WWW_AUTHENTICATE, "basic
97 // realm=\"" + httpAuthRealm + "\"");
98 if (SpnegoLoginModule
.hasAcceptorCredentials() && !forceBasic
)// SPNEGO
99 httpExchange
.getResponseHeaders().set(HEADER_WWW_AUTHENTICATE
, "Negotiate");
101 httpExchange
.getResponseHeaders().set(HEADER_WWW_AUTHENTICATE
, "Basic realm=\"" + httpAuthRealm
+ "\"");
103 // response.setDateHeader("Date", System.currentTimeMillis());
104 // response.setDateHeader("Expires", System.currentTimeMillis() + (24 *
106 // response.setHeader("Accept-Ranges", "bytes");
107 // response.setHeader("Connection", "Keep-Alive");
108 // response.setHeader("Keep-Alive", "timeout=5, max=97");
109 // response.setContentType("text/html; charset=UTF-8");
111 return new Authenticator
.Retry(401);