]> git.argeo.org Git - lgpl/argeo-commons.git/blob - AbstractLoginModule.java
f464ebad9c37669f16c41c28c078f36b5441fe0b
[lgpl/argeo-commons.git] / AbstractLoginModule.java
1 /*
2 * Copyright (C) 2007-2012 Argeo GmbH
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.argeo.cms.internal.auth;
17
18 import java.io.IOException;
19 import java.util.Map;
20
21 import javax.security.auth.Subject;
22 import javax.security.auth.callback.CallbackHandler;
23 import javax.security.auth.callback.UnsupportedCallbackException;
24 import javax.security.auth.login.LoginException;
25 import javax.security.auth.spi.LoginModule;
26 import javax.servlet.http.HttpServletRequest;
27 import javax.servlet.http.HttpSession;
28
29 import org.apache.commons.logging.Log;
30 import org.apache.commons.logging.LogFactory;
31 import org.argeo.ArgeoException;
32 import org.argeo.cms.internal.kernel.Activator;
33 import org.eclipse.rap.rwt.RWT;
34 import org.eclipse.swt.widgets.Display;
35 import org.osgi.framework.BundleContext;
36 import org.osgi.framework.ServiceReference;
37 import org.springframework.security.authentication.AuthenticationManager;
38 import org.springframework.security.core.Authentication;
39 import org.springframework.security.core.context.SecurityContext;
40 import org.springframework.security.core.context.SecurityContextHolder;
41
42 /** Login module which caches one subject per thread. */
43 public abstract class AbstractLoginModule implements LoginModule {
44 /**
45 * From org.springframework.security.context.
46 * HttpSessionContextIntegrationFilter
47 */
48 private final static String SPRING_SECURITY_CONTEXT_KEY = "SPRING_SECURITY_CONTEXT";
49
50 private final static Log log = LogFactory.getLog(AbstractLoginModule.class);
51 private CallbackHandler callbackHandler;
52 private Subject subject;
53
54 private Authentication authentication;
55
56 // state
57 private BundleContext bundleContext;
58 private ServiceReference<AuthenticationManager> authenticationManager;
59
60 protected abstract Authentication processLogin(
61 CallbackHandler callbackHandler) throws LoginException,
62 UnsupportedCallbackException, IOException, InterruptedException;
63
64 @Override
65 public void initialize(Subject subject, CallbackHandler callbackHandler,
66 Map<String, ?> sharedState, Map<String, ?> options) {
67 this.callbackHandler = callbackHandler;
68 this.subject = subject;
69 this.bundleContext = Activator.getBundleContext();
70 this.authenticationManager = bundleContext
71 .getServiceReference(AuthenticationManager.class);
72 }
73
74 @Override
75 public boolean login() throws LoginException {
76 try {
77 Authentication currentAuth = SecurityContextHolder.getContext()
78 .getAuthentication();
79
80 if (currentAuth == null && Display.getCurrent() != null) {
81 // try to load authentication from session
82 HttpServletRequest httpRequest = RWT.getRequest();
83 HttpSession httpSession = httpRequest.getSession();
84 // log.debug(httpSession.getId());
85 Object contextFromSessionObject = httpSession
86 .getAttribute(SPRING_SECURITY_CONTEXT_KEY);
87 if (contextFromSessionObject != null) {
88 currentAuth = (Authentication) contextFromSessionObject;
89 SecurityContextHolder.getContext().setAuthentication(
90 currentAuth);
91 }
92 }
93
94 // thread already logged in
95 if (currentAuth != null) {
96 if (subject.getPrincipals(Authentication.class).size() == 0) {
97 // throw new LoginException(
98 // "Security context set but not Authentication principal");
99 } else {
100 Authentication principal = subject
101 .getPrincipals(Authentication.class).iterator()
102 .next();
103 if (principal != currentAuth)
104 throw new LoginException(
105 "Already authenticated with a different auth");
106 }
107 return true;
108 }
109
110 // if (callbackHandler == null)
111 // throw new LoginException("No callback handler available");
112
113 authentication = processLogin(callbackHandler);
114 if (authentication != null) {
115 //
116 // SET THE AUTHENTICATION
117 //
118 SecurityContext securityContext = SecurityContextHolder
119 .getContext();
120 securityContext.setAuthentication(authentication);
121 if (Display.getCurrent() != null) {
122 HttpServletRequest httpRequest = RWT.getRequest();
123 HttpSession httpSession = httpRequest.getSession();
124 if (httpSession.getAttribute(SPRING_SECURITY_CONTEXT_KEY) == null)
125 httpSession.setAttribute(SPRING_SECURITY_CONTEXT_KEY,
126 authentication);
127 }
128 return true;
129 } else {
130 throw new LoginException("No authentication returned");
131 }
132 } catch (LoginException e) {
133 throw e;
134 } catch (ThreadDeath e) {
135 LoginException le = new LoginException(
136 "Spring Security login thread died");
137 le.initCause(e);
138 throw le;
139 } catch (Exception e) {
140 LoginException le = new LoginException(
141 "Spring Security login failed");
142 le.initCause(e);
143 throw le;
144 }
145 }
146
147 @Override
148 public boolean logout() throws LoginException {
149 SecurityContextHolder.getContext().setAuthentication(null);
150 if (Display.getCurrent() != null) {
151 HttpServletRequest httpRequest = RWT.getRequest();
152 HttpSession httpSession = httpRequest.getSession();
153 if (httpSession.getAttribute(SPRING_SECURITY_CONTEXT_KEY) != null)
154 httpSession.setAttribute(SPRING_SECURITY_CONTEXT_KEY, null);
155 }
156 return true;
157 }
158
159 @Override
160 public boolean commit() throws LoginException {
161 return true;
162 }
163
164 @Override
165 public boolean abort() throws LoginException {
166 SecurityContextHolder.getContext().setAuthentication(null);
167 return true;
168 }
169
170 /**
171 * Return the related {@link BundleContext} (never null), or throws an
172 * Exception if the login module was not properly initialised.
173 */
174 protected BundleContext getBundleContext() {
175 if (bundleContext == null)
176 throw new ArgeoException("No bundle context provided");
177 return bundleContext;
178 }
179
180 AuthenticationManager getAuthenticationManager() {
181 BundleContext bc = getBundleContext();
182 assert authenticationManager != null;
183 return bc.getService(authenticationManager);
184 }
185
186 protected Subject getSubject() {
187 return subject;
188 }
189 }