2 * Copyright (C) 2007-2012 Argeo GmbH
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package org
.argeo
.cms
.internal
.auth
;
18 import java
.io
.IOException
;
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
;
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
;
42 /** Login module which caches one subject per thread. */
43 public abstract class AbstractLoginModule
implements LoginModule
{
45 * From org.springframework.security.context.
46 * HttpSessionContextIntegrationFilter
48 private final static String SPRING_SECURITY_CONTEXT_KEY
= "SPRING_SECURITY_CONTEXT";
50 private final static Log log
= LogFactory
.getLog(AbstractLoginModule
.class);
51 private CallbackHandler callbackHandler
;
52 private Subject subject
;
54 private Authentication authentication
;
57 private BundleContext bundleContext
;
58 private ServiceReference
<AuthenticationManager
> authenticationManager
;
60 protected abstract Authentication
processLogin(
61 CallbackHandler callbackHandler
) throws LoginException
,
62 UnsupportedCallbackException
, IOException
, InterruptedException
;
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);
75 public boolean login() throws LoginException
{
77 Authentication currentAuth
= SecurityContextHolder
.getContext()
80 if (currentAuth
== null) {
82 // TODO Do it at Spring Security level?
84 // try to load authentication from session
85 HttpServletRequest httpRequest
= RWT
.getRequest();
86 HttpSession httpSession
= httpRequest
.getSession();
87 // log.debug(httpSession.getId());
88 Object contextFromSessionObject
= httpSession
89 .getAttribute(SPRING_SECURITY_CONTEXT_KEY
);
90 if (contextFromSessionObject
!= null) {
91 currentAuth
= (Authentication
) contextFromSessionObject
;
92 SecurityContextHolder
.getContext().setAuthentication(
95 } catch (Exception e
) {
96 if (log
.isTraceEnabled())
97 log
.trace("Could not get session", e
);
102 // thread already logged in
103 if (currentAuth
!= null) {
104 if (subject
.getPrincipals(Authentication
.class).size() == 0) {
105 // throw new LoginException(
106 // "Security context set but not Authentication principal");
108 Authentication principal
= subject
109 .getPrincipals(Authentication
.class).iterator()
111 if (principal
!= currentAuth
)
112 throw new LoginException(
113 "Already authenticated with a different auth");
118 // if (callbackHandler == null)
119 // throw new LoginException("No callback handler available");
121 authentication
= processLogin(callbackHandler
);
122 if (authentication
!= null) {
124 // SET THE AUTHENTICATION
126 SecurityContext securityContext
= SecurityContextHolder
128 securityContext
.setAuthentication(authentication
);
130 HttpServletRequest httpRequest
= RWT
.getRequest();
131 HttpSession httpSession
= httpRequest
.getSession();
132 if (httpSession
.getAttribute(SPRING_SECURITY_CONTEXT_KEY
) == null)
133 httpSession
.setAttribute(SPRING_SECURITY_CONTEXT_KEY
,
135 } catch (Exception e
) {
136 if (log
.isTraceEnabled())
137 log
.trace("Could not add security context to session",
142 throw new LoginException("No authentication returned");
144 } catch (LoginException e
) {
146 } catch (ThreadDeath e
) {
147 LoginException le
= new LoginException(
148 "Spring Security login thread died");
151 } catch (Exception e
) {
152 LoginException le
= new LoginException(
153 "Spring Security login failed");
160 public boolean logout() throws LoginException
{
161 SecurityContextHolder
.getContext().setAuthentication(null);
162 if (Display
.getCurrent() != null) {
163 HttpServletRequest httpRequest
= RWT
.getRequest();
164 if (httpRequest
!= null) {
165 HttpSession httpSession
= httpRequest
.getSession();
166 if (httpSession
.getAttribute(SPRING_SECURITY_CONTEXT_KEY
) != null)
167 httpSession
.setAttribute(SPRING_SECURITY_CONTEXT_KEY
, null);
169 httpSession
.setMaxInactiveInterval(0);
176 public boolean commit() throws LoginException
{
181 public boolean abort() throws LoginException
{
182 SecurityContextHolder
.getContext().setAuthentication(null);
187 * Return the related {@link BundleContext} (never null), or throws an
188 * Exception if the login module was not properly initialised.
190 protected BundleContext
getBundleContext() {
191 if (bundleContext
== null)
192 throw new ArgeoException("No bundle context provided");
193 return bundleContext
;
196 AuthenticationManager
getAuthenticationManager() {
197 BundleContext bc
= getBundleContext();
198 assert authenticationManager
!= null;
199 return bc
.getService(authenticationManager
);
202 protected Subject
getSubject() {