1 package org
.argeo
.cms
.auth
;
3 import java
.io
.IOException
;
4 import java
.security
.cert
.X509Certificate
;
5 import java
.util
.Base64
;
6 import java
.util
.Collection
;
7 import java
.util
.Locale
;
9 import java
.util
.StringTokenizer
;
11 import javax
.security
.auth
.Subject
;
12 import javax
.security
.auth
.callback
.Callback
;
13 import javax
.security
.auth
.callback
.CallbackHandler
;
14 import javax
.security
.auth
.callback
.UnsupportedCallbackException
;
15 import javax
.security
.auth
.login
.LoginException
;
16 import javax
.security
.auth
.spi
.LoginModule
;
17 import javax
.servlet
.http
.HttpServletRequest
;
18 import javax
.servlet
.http
.HttpServletResponse
;
19 import javax
.servlet
.http
.HttpSession
;
21 import org
.apache
.commons
.logging
.Log
;
22 import org
.apache
.commons
.logging
.LogFactory
;
23 import org
.argeo
.cms
.CmsException
;
24 import org
.osgi
.framework
.BundleContext
;
25 import org
.osgi
.framework
.FrameworkUtil
;
26 import org
.osgi
.framework
.InvalidSyntaxException
;
27 import org
.osgi
.framework
.ServiceReference
;
28 import org
.osgi
.service
.http
.HttpContext
;
29 import org
.osgi
.service
.useradmin
.Authorization
;
31 public class HttpSessionLoginModule
implements LoginModule
{
32 private final static Log log
= LogFactory
.getLog(HttpSessionLoginModule
.class);
34 private Subject subject
= null;
35 private CallbackHandler callbackHandler
= null;
36 private Map
<String
, Object
> sharedState
= null;
38 private HttpServletRequest request
= null;
39 private HttpServletResponse response
= null;
41 private BundleContext bc
;
43 private Authorization authorization
;
44 private Locale locale
;
46 @SuppressWarnings("unchecked")
48 public void initialize(Subject subject
, CallbackHandler callbackHandler
, Map
<String
, ?
> sharedState
,
49 Map
<String
, ?
> options
) {
50 bc
= FrameworkUtil
.getBundle(HttpSessionLoginModule
.class).getBundleContext();
52 this.subject
= subject
;
53 this.callbackHandler
= callbackHandler
;
54 this.sharedState
= (Map
<String
, Object
>) sharedState
;
58 public boolean login() throws LoginException
{
59 if (callbackHandler
== null)
61 HttpRequestCallback httpCallback
= new HttpRequestCallback();
63 callbackHandler
.handle(new Callback
[] { httpCallback
});
64 } catch (IOException e
) {
65 throw new LoginException("Cannot handle http callback: " + e
.getMessage());
66 } catch (UnsupportedCallbackException e
) {
69 request
= httpCallback
.getRequest();
72 authorization
= (Authorization
) request
.getAttribute(HttpContext
.AUTHORIZATION
);
73 if (authorization
== null) {// search by session ID
74 HttpSession httpSession
= request
.getSession(false);
75 if (httpSession
== null) {
76 // TODO make sure this is always safe
77 if (log
.isTraceEnabled())
78 log
.trace("Create http session");
79 httpSession
= request
.getSession(true);
81 String httpSessionId
= httpSession
.getId();
82 // authorization = (Authorization)
83 // request.getSession().getAttribute(HttpContext.AUTHORIZATION);
84 // if (authorization == null) {
85 Collection
<ServiceReference
<CmsSession
>> sr
;
87 sr
= bc
.getServiceReferences(CmsSession
.class,
88 "(" + CmsSession
.SESSION_LOCAL_ID
+ "=" + httpSessionId
+ ")");
89 } catch (InvalidSyntaxException e
) {
90 throw new CmsException("Cannot get CMS session for id " + httpSessionId
, e
);
93 CmsSession cmsSession
= bc
.getService(sr
.iterator().next());
94 locale
= cmsSession
.getLocale();
95 authorization
= cmsSession
.getAuthorization();
96 if (authorization
.getName() == null)
97 authorization
= null;// anonymous is not sufficient
98 if (log
.isTraceEnabled())
99 log
.trace("Retrieved authorization from " + cmsSession
);
100 } else if (sr
.size() == 0)
101 authorization
= null;
103 throw new CmsException(sr
.size() + ">1 web sessions detected for http session " + httpSessionId
);
106 sharedState
.put(CmsAuthUtils
.SHARED_STATE_HTTP_REQUEST
, request
);
107 extractHttpAuth(request
);
108 extractClientCertificate(request
);
109 if (authorization
== null) {
117 public boolean commit() throws LoginException
{
118 byte[] outToken
= (byte[]) sharedState
.get(CmsAuthUtils
.SHARED_STATE_SPNEGO_OUT_TOKEN
);
119 if (outToken
!= null) {
120 response
.setHeader(CmsAuthUtils
.HEADER_WWW_AUTHENTICATE
,
121 "Negotiate " + java
.util
.Base64
.getEncoder().encodeToString(outToken
));
124 if (authorization
!= null) {
125 // Locale locale = request.getLocale();
127 locale
= request
.getLocale();
128 subject
.getPublicCredentials().add(locale
);
129 CmsAuthUtils
.addAuthorization(subject
, authorization
, locale
, request
);
130 CmsAuthUtils
.registerSessionAuthorization(request
, subject
, authorization
, locale
);
140 public boolean abort() throws LoginException
{
145 private void cleanUp() {
146 authorization
= null;
151 public boolean logout() throws LoginException
{
156 private void extractHttpAuth(final HttpServletRequest httpRequest
) {
157 String authHeader
= httpRequest
.getHeader(CmsAuthUtils
.HEADER_AUTHORIZATION
);
158 if (authHeader
!= null) {
159 StringTokenizer st
= new StringTokenizer(authHeader
);
160 if (st
.hasMoreTokens()) {
161 String basic
= st
.nextToken();
162 if (basic
.equalsIgnoreCase("Basic")) {
164 // TODO manipulate char[]
165 Base64
.Decoder decoder
= Base64
.getDecoder();
166 String credentials
= new String(decoder
.decode(st
.nextToken()), "UTF-8");
167 // log.debug("Credentials: " + credentials);
168 int p
= credentials
.indexOf(":");
170 final String login
= credentials
.substring(0, p
).trim();
171 final char[] password
= credentials
.substring(p
+ 1).trim().toCharArray();
172 sharedState
.put(CmsAuthUtils
.SHARED_STATE_NAME
, login
);
173 sharedState
.put(CmsAuthUtils
.SHARED_STATE_PWD
, password
);
175 throw new CmsException("Invalid authentication token");
177 } catch (Exception e
) {
178 throw new CmsException("Couldn't retrieve authentication", e
);
180 } else if (basic
.equalsIgnoreCase("Negotiate")) {
181 String spnegoToken
= st
.nextToken();
182 Base64
.Decoder decoder
= Base64
.getDecoder();
183 byte[] authToken
= decoder
.decode(spnegoToken
);
184 sharedState
.put(CmsAuthUtils
.SHARED_STATE_SPNEGO_TOKEN
, authToken
);
190 // String mail = request.getParameter(LdapAttrs.mail.name());
191 // String authPassword = request.getParameter(LdapAttrs.authPassword.name());
192 // if (authPassword != null) {
193 // sharedState.put(CmsAuthUtils.SHARED_STATE_PWD, authPassword);
195 // sharedState.put(CmsAuthUtils.SHARED_STATE_NAME, mail);
199 private void extractClientCertificate(HttpServletRequest req
) {
200 X509Certificate
[] certs
= (X509Certificate
[]) req
.getAttribute("javax.servlet.request.X509Certificate");
201 if (null != certs
&& certs
.length
> 0) {
202 sharedState
.put(CmsAuthUtils
.SHARED_STATE_NAME
, certs
[0].getSubjectX500Principal().getName());
203 sharedState
.put(CmsAuthUtils
.SHARED_STATE_CERTIFICATE_CHAIN
, certs
);