]> git.argeo.org Git - lgpl/argeo-commons.git/blob - argeo/cms/auth/HttpSessionLoginModule.java
Prepare next development cycle
[lgpl/argeo-commons.git] / argeo / cms / auth / HttpSessionLoginModule.java
1 package org.argeo.cms.auth;
2
3 import java.io.IOException;
4 import java.security.cert.X509Certificate;
5 import java.util.Collection;
6 import java.util.Map;
7 import java.util.StringTokenizer;
8
9 import javax.security.auth.Subject;
10 import javax.security.auth.callback.Callback;
11 import javax.security.auth.callback.CallbackHandler;
12 import javax.security.auth.callback.UnsupportedCallbackException;
13 import javax.security.auth.login.LoginException;
14 import javax.security.auth.spi.LoginModule;
15 import javax.servlet.http.HttpServletRequest;
16
17 import org.apache.commons.codec.binary.Base64;
18 import org.apache.commons.logging.Log;
19 import org.apache.commons.logging.LogFactory;
20 import org.argeo.cms.CmsException;
21 import org.osgi.framework.BundleContext;
22 import org.osgi.framework.FrameworkUtil;
23 import org.osgi.framework.InvalidSyntaxException;
24 import org.osgi.framework.ServiceReference;
25 import org.osgi.service.http.HttpContext;
26 import org.osgi.service.useradmin.Authorization;
27
28 public class HttpSessionLoginModule implements LoginModule {
29 private final static Log log = LogFactory.getLog(HttpSessionLoginModule.class);
30
31 private Subject subject = null;
32 private CallbackHandler callbackHandler = null;
33 private Map<String, Object> sharedState = null;
34
35 private HttpServletRequest request = null;
36
37 private BundleContext bc;
38
39 private Authorization authorization;
40
41 @SuppressWarnings("unchecked")
42 @Override
43 public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState,
44 Map<String, ?> options) {
45 bc = FrameworkUtil.getBundle(HttpSessionLoginModule.class).getBundleContext();
46 assert bc != null;
47 this.subject = subject;
48 this.callbackHandler = callbackHandler;
49 this.sharedState = (Map<String, Object>) sharedState;
50 }
51
52 @Override
53 public boolean login() throws LoginException {
54 if (callbackHandler == null)
55 return false;
56 HttpRequestCallback httpCallback = new HttpRequestCallback();
57 try {
58 callbackHandler.handle(new Callback[] { httpCallback });
59 } catch (IOException e) {
60 throw new LoginException("Cannot handle http callback: " + e.getMessage());
61 } catch (UnsupportedCallbackException e) {
62 return false;
63 }
64 request = httpCallback.getRequest();
65 if (request == null)
66 return false;
67 authorization = (Authorization) request.getAttribute(HttpContext.AUTHORIZATION);
68 if (authorization == null) {// search by session ID
69 String httpSessionId = request.getSession().getId();
70 // authorization = (Authorization)
71 // request.getSession().getAttribute(HttpContext.AUTHORIZATION);
72 // if (authorization == null) {
73 Collection<ServiceReference<WebCmsSession>> sr;
74 try {
75 sr = bc.getServiceReferences(WebCmsSession.class,
76 "(" + WebCmsSession.CMS_SESSION_ID + "=" + httpSessionId + ")");
77 } catch (InvalidSyntaxException e) {
78 throw new CmsException("Cannot get CMS session for id " + httpSessionId, e);
79 }
80 if (sr.size() == 1) {
81 WebCmsSession cmsSession = bc.getService(sr.iterator().next());
82 authorization = cmsSession.getAuthorization();
83 if (log.isTraceEnabled())
84 log.trace("Retrieved authorization from " + cmsSession);
85 } else if (sr.size() == 0)
86 authorization = null;
87 else
88 throw new CmsException(sr.size() + ">1 web sessions detected for http session " + httpSessionId);
89
90 }
91 sharedState.put(CmsAuthUtils.SHARED_STATE_HTTP_REQUEST, request);
92 extractHttpAuth(request);
93 extractClientCertificate(request);
94 if (authorization == null)
95 return false;
96 sharedState.put(CmsAuthUtils.SHARED_STATE_AUTHORIZATION, authorization);
97 return true;
98 }
99
100 // private Authorization checkHttp() {
101 // Authorization authorization = null;
102 // if (request != null) {
103 // authorization = (Authorization)
104 // request.getAttribute(HttpContext.AUTHORIZATION);
105 // if (authorization == null) {
106 // String httpSessionId = request.getSession().getId();
107 // authorization = (Authorization)
108 // request.getSession().getAttribute(HttpContext.AUTHORIZATION);
109 // if (authorization == null) {
110 // Collection<ServiceReference<WebCmsSession>> sr;
111 // try {
112 // sr = bc.getServiceReferences(WebCmsSession.class,
113 // "(" + WebCmsSession.CMS_SESSION_ID + "=" + httpSessionId + ")");
114 // } catch (InvalidSyntaxException e) {
115 // throw new CmsException("Cannot get CMS session for id " + httpSessionId,
116 // e);
117 // }
118 // if (sr.size() == 1) {
119 // WebCmsSession cmsSession = bc.getService(sr.iterator().next());
120 // authorization = cmsSession.getAuthorization();
121 // if (log.isTraceEnabled())
122 // log.trace("Retrieved authorization from " + cmsSession);
123 // } else if (sr.size() == 0)
124 // return null;
125 // else
126 // throw new CmsException(
127 // sr.size() + ">1 web sessions detected for http session " +
128 // httpSessionId);
129 // }
130 // }
131 // }
132 // return authorization;
133 // }
134
135 @Override
136 public boolean commit() throws LoginException {
137 // TODO create CmsSession in another module
138 Authorization authorizationToRegister;
139 if (authorization == null) {
140 authorizationToRegister = (Authorization) sharedState.get(CmsAuthUtils.SHARED_STATE_AUTHORIZATION);
141 } else { // this login module did the authorization
142 CmsAuthUtils.addAuthentication(subject, authorization);
143 authorizationToRegister = authorization;
144 }
145 if (authorizationToRegister == null) {
146 return false;
147 }
148 if (request == null)
149 return false;
150 CmsAuthUtils.registerSessionAuthorization(bc, request, subject, authorizationToRegister);
151
152 if (authorization != null) {
153 // CmsAuthUtils.addAuthentication(subject, authorization);
154 cleanUp();
155 return true;
156 } else {
157 cleanUp();
158 return false;
159 }
160 }
161
162 @Override
163 public boolean abort() throws LoginException {
164 cleanUp();
165 return false;
166 }
167
168 private void cleanUp() {
169 authorization = null;
170 request = null;
171 }
172
173 @Override
174 public boolean logout() throws LoginException {
175 return CmsAuthUtils.logoutSession(bc, subject);
176 }
177
178 private void extractHttpAuth(final HttpServletRequest httpRequest) {
179 String authHeader = httpRequest.getHeader(CmsAuthUtils.HEADER_AUTHORIZATION);
180 if (authHeader != null) {
181 StringTokenizer st = new StringTokenizer(authHeader);
182 if (st.hasMoreTokens()) {
183 String basic = st.nextToken();
184 if (basic.equalsIgnoreCase("Basic")) {
185 try {
186 // TODO manipulate char[]
187 String credentials = new String(Base64.decodeBase64(st.nextToken()), "UTF-8");
188 // log.debug("Credentials: " + credentials);
189 int p = credentials.indexOf(":");
190 if (p != -1) {
191 final String login = credentials.substring(0, p).trim();
192 final char[] password = credentials.substring(p + 1).trim().toCharArray();
193 sharedState.put(CmsAuthUtils.SHARED_STATE_NAME, login);
194 sharedState.put(CmsAuthUtils.SHARED_STATE_PWD, password);
195 } else {
196 throw new CmsException("Invalid authentication token");
197 }
198 } catch (Exception e) {
199 throw new CmsException("Couldn't retrieve authentication", e);
200 }
201 } else if (basic.equalsIgnoreCase("Negotiate")) {
202 String spnegoToken = st.nextToken();
203 byte[] authToken = Base64.decodeBase64(spnegoToken);
204 sharedState.put(CmsAuthUtils.SHARED_STATE_SPNEGO_TOKEN, authToken);
205 }
206 }
207 }
208 }
209
210 private X509Certificate[] extractClientCertificate(HttpServletRequest req) {
211 X509Certificate[] certs = (X509Certificate[]) req.getAttribute("javax.servlet.request.X509Certificate");
212 if (null != certs && certs.length > 0) {
213 return certs;
214 }
215 return null;
216 }
217
218 }