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
;
12 import org
.argeo
.util
.http
.HttpHeader
;
14 import com
.sun
.net
.httpserver
.Authenticator
;
15 import com
.sun
.net
.httpserver
.HttpExchange
;
16 import com
.sun
.net
.httpserver
.HttpPrincipal
;
18 public class CmsAuthenticator
extends Authenticator
{
19 // final static String HEADER_AUTHORIZATION = "Authorization";
20 // final static String HEADER_WWW_AUTHENTICATE = "WWW-Authenticate";
22 private final static CmsLog log
= CmsLog
.getLog(CmsAuthenticator
.class);
24 // TODO make it configurable
25 private final String httpAuthRealm
= "Argeo";
26 private final boolean forceBasic
= false;
29 public Result
authenticate(HttpExchange exch
) {
30 // if (log.isTraceEnabled())
31 // HttpUtils.logRequestHeaders(log, request);
32 RemoteAuthHttpExchange remoteAuthHttpExchange
= new RemoteAuthHttpExchange(exch
);
33 ClassLoader currentThreadContextClassLoader
= Thread
.currentThread().getContextClassLoader();
34 Thread
.currentThread().setContextClassLoader(CmsAuthenticator
.class.getClassLoader());
38 .newLoginContext(new RemoteAuthCallbackHandler(remoteAuthHttpExchange
, remoteAuthHttpExchange
));
40 } catch (LoginException e
) {
41 // FIXME better analyse failure so as not to try endlessly
42 if (authIsRequired(exch
)) {
43 return askForWwwAuth(exch
);
45 lc
= processUnauthorized(exch
);
46 // if (log.isTraceEnabled())
47 // HttpUtils.logResponseHeaders(log, response);
50 return new Authenticator
.Failure(403);
52 Thread
.currentThread().setContextClassLoader(currentThreadContextClassLoader
);
55 Subject subject
= lc
.getSubject();
57 // Subject.doAs(subject, new PrivilegedAction<Void>() {
60 // public Void run() {
61 // // TODO also set login context in order to log out ?
62 // RemoteAuthUtils.configureRequestSecurity(new ServletHttpRequest(request));
67 String username
= CurrentUser
.getUsername(subject
);
68 HttpPrincipal httpPrincipal
= new HttpPrincipal(username
, httpAuthRealm
);
69 return new Authenticator
.Success(httpPrincipal
);
72 protected boolean authIsRequired(HttpExchange httpExchange
) {
76 protected LoginContext
processUnauthorized(HttpExchange httpExchange
) {
78 RemoteAuthHttpExchange remoteAuthExchange
= new RemoteAuthHttpExchange(httpExchange
);
80 ClassLoader currentContextClassLoader
= Thread
.currentThread().getContextClassLoader();
82 Thread
.currentThread().setContextClassLoader(CmsAuthenticator
.class.getClassLoader());
83 LoginContext lc
= CmsAuth
.ANONYMOUS
84 .newLoginContext(new RemoteAuthCallbackHandler(remoteAuthExchange
, remoteAuthExchange
));
87 } catch (LoginException e1
) {
88 if (log
.isDebugEnabled())
89 log
.error("Cannot log in as anonymous", e1
);
92 Thread
.currentThread().setContextClassLoader(currentContextClassLoader
);
96 protected Authenticator
.Retry
askForWwwAuth(HttpExchange httpExchange
) {
97 // response.setHeader(HttpUtils.HEADER_WWW_AUTHENTICATE, "basic
98 // realm=\"" + httpAuthRealm + "\"");
99 if (SpnegoLoginModule
.hasAcceptorCredentials() && !forceBasic
)// SPNEGO
100 httpExchange
.getResponseHeaders().set(HttpHeader
.WWW_AUTHENTICATE
.getName(), HttpHeader
.NEGOTIATE
);
102 httpExchange
.getResponseHeaders().set(HttpHeader
.WWW_AUTHENTICATE
.getName(),
103 HttpHeader
.BASIC
+ " " + HttpHeader
.REALM
+ "=\"" + httpAuthRealm
+ "\"");
105 // response.setDateHeader("Date", System.currentTimeMillis());
106 // response.setDateHeader("Expires", System.currentTimeMillis() + (24 *
108 // response.setHeader("Accept-Ranges", "bytes");
109 // response.setHeader("Connection", "Keep-Alive");
110 // response.setHeader("Keep-Alive", "timeout=5, max=97");
111 // response.setContentType("text/html; charset=UTF-8");
113 return new Authenticator
.Retry(401);