]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.cms/src/org/argeo/cms/internal/auth/AbstractLoginModule.java
Change from Session.ACTION_ADD_NODE to Session.ACTION_SET_PROPERTY permission in...
[lgpl/argeo-commons.git] / org.argeo.cms / src / org / argeo / cms / internal / auth / 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 @SuppressWarnings("unused")
51 private final static Log log = LogFactory.getLog(AbstractLoginModule.class);
52 private CallbackHandler callbackHandler;
53 private Subject subject;
54
55 private Authentication authentication;
56
57 // state
58 private BundleContext bundleContext;
59 private ServiceReference<AuthenticationManager> authenticationManager;
60
61 protected abstract Authentication processLogin(
62 CallbackHandler callbackHandler) throws LoginException,
63 UnsupportedCallbackException, IOException, InterruptedException;
64
65 @Override
66 public void initialize(Subject subject, CallbackHandler callbackHandler,
67 Map<String, ?> sharedState, Map<String, ?> options) {
68 this.callbackHandler = callbackHandler;
69 this.subject = subject;
70 this.bundleContext = Activator.getBundleContext();
71 this.authenticationManager = bundleContext
72 .getServiceReference(AuthenticationManager.class);
73 }
74
75 @Override
76 public boolean login() throws LoginException {
77 try {
78 Authentication currentAuth = SecurityContextHolder.getContext()
79 .getAuthentication();
80
81 if (currentAuth == null && Display.getCurrent() != null) {
82 // try to load authentication from session
83 HttpServletRequest httpRequest = RWT.getRequest();
84 HttpSession httpSession = httpRequest.getSession();
85 // log.debug(httpSession.getId());
86 Object contextFromSessionObject = httpSession
87 .getAttribute(SPRING_SECURITY_CONTEXT_KEY);
88 if (contextFromSessionObject != null) {
89 currentAuth = (Authentication) contextFromSessionObject;
90 SecurityContextHolder.getContext().setAuthentication(
91 currentAuth);
92 }
93 }
94
95 // thread already logged in
96 if (currentAuth != null) {
97 if (subject.getPrincipals(Authentication.class).size() == 0) {
98 // throw new LoginException(
99 // "Security context set but not Authentication principal");
100 } else {
101 Authentication principal = subject
102 .getPrincipals(Authentication.class).iterator()
103 .next();
104 if (principal != currentAuth)
105 throw new LoginException(
106 "Already authenticated with a different auth");
107 }
108 return true;
109 }
110
111 // if (callbackHandler == null)
112 // throw new LoginException("No callback handler available");
113
114 authentication = processLogin(callbackHandler);
115 if (authentication != null) {
116 //
117 // SET THE AUTHENTICATION
118 //
119 SecurityContext securityContext = SecurityContextHolder
120 .getContext();
121 securityContext.setAuthentication(authentication);
122 if (Display.getCurrent() != null) {
123 HttpServletRequest httpRequest = RWT.getRequest();
124 HttpSession httpSession = httpRequest.getSession();
125 if (httpSession.getAttribute(SPRING_SECURITY_CONTEXT_KEY) == null)
126 httpSession.setAttribute(SPRING_SECURITY_CONTEXT_KEY,
127 authentication);
128 }
129 return true;
130 } else {
131 throw new LoginException("No authentication returned");
132 }
133 } catch (LoginException e) {
134 throw e;
135 } catch (ThreadDeath e) {
136 LoginException le = new LoginException(
137 "Spring Security login thread died");
138 le.initCause(e);
139 throw le;
140 } catch (Exception e) {
141 LoginException le = new LoginException(
142 "Spring Security login failed");
143 le.initCause(e);
144 throw le;
145 }
146 }
147
148 @Override
149 public boolean logout() throws LoginException {
150 SecurityContextHolder.getContext().setAuthentication(null);
151 if (Display.getCurrent() != null) {
152 HttpServletRequest httpRequest = RWT.getRequest();
153 HttpSession httpSession = httpRequest.getSession();
154 if (httpSession.getAttribute(SPRING_SECURITY_CONTEXT_KEY) != null)
155 httpSession.setAttribute(SPRING_SECURITY_CONTEXT_KEY, null);
156 }
157 return true;
158 }
159
160 @Override
161 public boolean commit() throws LoginException {
162 return true;
163 }
164
165 @Override
166 public boolean abort() throws LoginException {
167 SecurityContextHolder.getContext().setAuthentication(null);
168 return true;
169 }
170
171 /**
172 * Return the related {@link BundleContext} (never null), or throws an
173 * Exception if the login module was not properly initialised.
174 */
175 protected BundleContext getBundleContext() {
176 if (bundleContext == null)
177 throw new ArgeoException("No bundle context provided");
178 return bundleContext;
179 }
180
181 AuthenticationManager getAuthenticationManager() {
182 BundleContext bc = getBundleContext();
183 assert authenticationManager != null;
184 return bc.getService(authenticationManager);
185 }
186
187 protected Subject getSubject() {
188 return subject;
189 }
190 }