]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.cms/src/org/argeo/cms/auth/HttpSessionLoginModule.java
Improve SSL testing
[lgpl/argeo-commons.git] / org.argeo.cms / src / org / 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 import javax.servlet.http.HttpServletResponse;
17 import javax.servlet.http.HttpSession;
18
19 import org.apache.commons.codec.binary.Base64;
20 import org.apache.commons.logging.Log;
21 import org.apache.commons.logging.LogFactory;
22 import org.argeo.cms.CmsException;
23 import org.argeo.naming.LdapAttrs;
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;
30
31 public class HttpSessionLoginModule implements LoginModule {
32 private final static Log log = LogFactory.getLog(HttpSessionLoginModule.class);
33
34 private Subject subject = null;
35 private CallbackHandler callbackHandler = null;
36 private Map<String, Object> sharedState = null;
37
38 private HttpServletRequest request = null;
39 private HttpServletResponse response = null;
40
41 private BundleContext bc;
42
43 private Authorization authorization;
44
45 @SuppressWarnings("unchecked")
46 @Override
47 public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState,
48 Map<String, ?> options) {
49 bc = FrameworkUtil.getBundle(HttpSessionLoginModule.class).getBundleContext();
50 assert bc != null;
51 this.subject = subject;
52 this.callbackHandler = callbackHandler;
53 this.sharedState = (Map<String, Object>) sharedState;
54 }
55
56 @Override
57 public boolean login() throws LoginException {
58 if (callbackHandler == null)
59 return false;
60 HttpRequestCallback httpCallback = new HttpRequestCallback();
61 try {
62 callbackHandler.handle(new Callback[] { httpCallback });
63 } catch (IOException e) {
64 throw new LoginException("Cannot handle http callback: " + e.getMessage());
65 } catch (UnsupportedCallbackException e) {
66 return false;
67 }
68 request = httpCallback.getRequest();
69 if (request == null)
70 return false;
71 authorization = (Authorization) request.getAttribute(HttpContext.AUTHORIZATION);
72 if (authorization == null) {// search by session ID
73 HttpSession httpSession = request.getSession(false);
74 if (httpSession == null) {
75 // TODO make sure this is always safe
76 if (log.isTraceEnabled())
77 log.trace("Create http session");
78 httpSession = request.getSession(true);
79 }
80 String httpSessionId = httpSession.getId();
81 // authorization = (Authorization)
82 // request.getSession().getAttribute(HttpContext.AUTHORIZATION);
83 // if (authorization == null) {
84 Collection<ServiceReference<CmsSession>> sr;
85 try {
86 sr = bc.getServiceReferences(CmsSession.class,
87 "(" + CmsSession.SESSION_LOCAL_ID + "=" + httpSessionId + ")");
88 } catch (InvalidSyntaxException e) {
89 throw new CmsException("Cannot get CMS session for id " + httpSessionId, e);
90 }
91 if (sr.size() == 1) {
92 CmsSession cmsSession = bc.getService(sr.iterator().next());
93 authorization = cmsSession.getAuthorization();
94 if (authorization.getName() == null)
95 authorization = null;// anonymous is not sufficient
96 if (log.isTraceEnabled())
97 log.trace("Retrieved authorization from " + cmsSession);
98 } else if (sr.size() == 0)
99 authorization = null;
100 else
101 throw new CmsException(sr.size() + ">1 web sessions detected for http session " + httpSessionId);
102
103 }
104 sharedState.put(CmsAuthUtils.SHARED_STATE_HTTP_REQUEST, request);
105 extractHttpAuth(request);
106 extractClientCertificate(request);
107 if (authorization == null) {
108 return false;
109 } else {
110 return true;
111 }
112 }
113
114 @Override
115 public boolean commit() throws LoginException {
116 byte[] outToken = (byte[]) sharedState.get(CmsAuthUtils.SHARED_STATE_SPNEGO_OUT_TOKEN);
117 if (outToken != null) {
118 response.setHeader(CmsAuthUtils.HEADER_WWW_AUTHENTICATE,
119 "Negotiate " + java.util.Base64.getEncoder().encodeToString(outToken));
120 }
121
122 if (authorization != null) {
123 CmsAuthUtils.addAuthorization(subject, authorization, request.getLocale(), request);
124 cleanUp();
125 return true;
126 } else {
127 cleanUp();
128 return false;
129 }
130 }
131
132 @Override
133 public boolean abort() throws LoginException {
134 cleanUp();
135 return false;
136 }
137
138 private void cleanUp() {
139 authorization = null;
140 request = null;
141 }
142
143 @Override
144 public boolean logout() throws LoginException {
145 cleanUp();
146 return true;
147 }
148
149 private void extractHttpAuth(final HttpServletRequest httpRequest) {
150 String authHeader = httpRequest.getHeader(CmsAuthUtils.HEADER_AUTHORIZATION);
151 if (authHeader != null) {
152 StringTokenizer st = new StringTokenizer(authHeader);
153 if (st.hasMoreTokens()) {
154 String basic = st.nextToken();
155 if (basic.equalsIgnoreCase("Basic")) {
156 try {
157 // TODO manipulate char[]
158 String credentials = new String(Base64.decodeBase64(st.nextToken()), "UTF-8");
159 // log.debug("Credentials: " + credentials);
160 int p = credentials.indexOf(":");
161 if (p != -1) {
162 final String login = credentials.substring(0, p).trim();
163 final char[] password = credentials.substring(p + 1).trim().toCharArray();
164 sharedState.put(CmsAuthUtils.SHARED_STATE_NAME, login);
165 sharedState.put(CmsAuthUtils.SHARED_STATE_PWD, password);
166 } else {
167 throw new CmsException("Invalid authentication token");
168 }
169 } catch (Exception e) {
170 throw new CmsException("Couldn't retrieve authentication", e);
171 }
172 } else if (basic.equalsIgnoreCase("Negotiate")) {
173 String spnegoToken = st.nextToken();
174 byte[] authToken = Base64.decodeBase64(spnegoToken);
175 sharedState.put(CmsAuthUtils.SHARED_STATE_SPNEGO_TOKEN, authToken);
176 }
177 }
178 }
179
180 // auth token
181 // String mail = request.getParameter(LdapAttrs.mail.name());
182 // String authPassword = request.getParameter(LdapAttrs.authPassword.name());
183 // if (authPassword != null) {
184 // sharedState.put(CmsAuthUtils.SHARED_STATE_PWD, authPassword);
185 // if (mail != null)
186 // sharedState.put(CmsAuthUtils.SHARED_STATE_NAME, mail);
187 // }
188 }
189
190 private X509Certificate[] extractClientCertificate(HttpServletRequest req) {
191 X509Certificate[] certs = (X509Certificate[]) req.getAttribute("javax.servlet.request.X509Certificate");
192 if (null != certs && certs.length > 0) {
193 return certs;
194 }
195 return null;
196 }
197
198 }