1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.springframework.security.adapters.jboss;
17
18 import org.springframework.security.AccountExpiredException;
19 import org.springframework.security.Authentication;
20 import org.springframework.security.AuthenticationException;
21 import org.springframework.security.AuthenticationManager;
22 import org.springframework.security.CredentialsExpiredException;
23
24 import org.springframework.security.adapters.PrincipalSpringSecurityUserToken;
25
26 import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
27
28 import org.jboss.security.SimpleGroup;
29 import org.jboss.security.SimplePrincipal;
30 import org.jboss.security.auth.spi.AbstractServerLoginModule;
31
32 import org.springframework.beans.factory.access.BeanFactoryLocator;
33 import org.springframework.beans.factory.access.BeanFactoryReference;
34 import org.springframework.beans.factory.access.SingletonBeanFactoryLocator;
35
36 import org.springframework.context.ApplicationContext;
37 import org.springframework.context.support.ClassPathXmlApplicationContext;
38
39 import java.security.Principal;
40 import java.security.acl.Group;
41
42 import java.util.Map;
43
44 import javax.security.auth.Subject;
45 import javax.security.auth.callback.Callback;
46 import javax.security.auth.callback.CallbackHandler;
47 import javax.security.auth.callback.NameCallback;
48 import javax.security.auth.callback.PasswordCallback;
49 import javax.security.auth.callback.UnsupportedCallbackException;
50 import javax.security.auth.login.FailedLoginException;
51 import javax.security.auth.login.LoginException;
52
53
54
55
56
57
58
59
60
61
62
63 public class JbossSpringSecurityLoginModule extends AbstractServerLoginModule {
64
65
66 private AuthenticationManager authenticationManager;
67 private Principal identity;
68 private String key;
69 private char[] credential;
70
71
72
73 protected Principal getIdentity() {
74 return this.identity;
75 }
76
77 protected Group[] getRoleSets() throws LoginException {
78 SimpleGroup roles = new SimpleGroup("Roles");
79 Group[] roleSets = {roles};
80
81 if (this.identity instanceof Authentication) {
82 Authentication user = (Authentication) this.identity;
83
84 for (int i = 0; i < user.getAuthorities().length; i++) {
85 roles.addMember(new SimplePrincipal(user.getAuthorities()[i].getAuthority()));
86 }
87 }
88
89 return roleSets;
90 }
91
92 protected String[] getUsernameAndPassword() throws LoginException {
93 String[] info = {null, null};
94
95
96 if (callbackHandler == null) {
97 throw new LoginException("Error: no CallbackHandler available " + "to collect authentication information");
98 }
99
100 NameCallback nc = new NameCallback("User name: ", "guest");
101 PasswordCallback pc = new PasswordCallback("Password: ", false);
102 Callback[] callbacks = {nc, pc};
103 String username = null;
104 String password = null;
105
106 try {
107 callbackHandler.handle(callbacks);
108 username = nc.getName();
109
110 char[] tmpPassword = pc.getPassword();
111
112 if (tmpPassword != null) {
113 credential = new char[tmpPassword.length];
114 System.arraycopy(tmpPassword, 0, credential, 0, tmpPassword.length);
115 pc.clearPassword();
116 password = new String(credential);
117 }
118 } catch (java.io.IOException ioe) {
119 throw new LoginException(ioe.toString());
120 } catch (UnsupportedCallbackException uce) {
121 throw new LoginException("CallbackHandler does not support: " + uce.getCallback());
122 }
123
124 info[0] = username;
125 info[1] = password;
126
127 return info;
128 }
129
130 public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) {
131 super.initialize(subject, callbackHandler, sharedState, options);
132
133 if (super.log.isInfoEnabled()) {
134 super.log.info("initializing jboss login module");
135 }
136
137 this.key = (String) options.get("key");
138
139 if ((key == null) || "".equals(key)) {
140 throw new IllegalArgumentException("key must be defined");
141 }
142
143 String singletonId = (String) options.get("singletonId");
144
145 String appContextLocation = (String) options.get("appContextLocation");
146
147 if ((((singletonId == null) || "".equals(singletonId)) && (appContextLocation == null))
148 || "".equals(appContextLocation)) {
149 throw new IllegalArgumentException("appContextLocation must be defined");
150 }
151
152 String beanName = (String) options.get("authenticationManager");
153
154
155 if ((singletonId == null) || "".equals(singletonId)) {
156 if (Thread.currentThread().getContextClassLoader().getResource(appContextLocation) == null) {
157 if (super.log.isInfoEnabled()) {
158 super.log.info("cannot locate " + appContextLocation);
159 }
160
161 throw new IllegalArgumentException("Cannot locate " + appContextLocation);
162 }
163 }
164
165 ApplicationContext ctx = null;
166
167 if ((singletonId == null) || "".equals(singletonId)) {
168 try {
169 ctx = new ClassPathXmlApplicationContext(appContextLocation);
170 } catch (Exception e) {
171 if (super.log.isInfoEnabled()) {
172 super.log.info("error loading spring context " + appContextLocation + " " + e);
173 }
174
175 throw new IllegalArgumentException("error loading spring context " + appContextLocation + " " + e);
176 }
177 } else {
178 if (super.log.isInfoEnabled()) {
179 super.log.debug("retrieving singleton instance " + singletonId);
180 }
181
182 BeanFactoryLocator bfl = SingletonBeanFactoryLocator.getInstance();
183 BeanFactoryReference bf = bfl.useBeanFactory(singletonId);
184 ctx = (ApplicationContext) bf.getFactory();
185
186 if (ctx == null) {
187 if (super.log.isInfoEnabled()) {
188 super.log.info("singleton " + beanName + " does not exists");
189 }
190
191 throw new IllegalArgumentException("singleton " + singletonId + " does not exists");
192 }
193 }
194
195 if ((beanName == null) || "".equals(beanName)) {
196 Map beans = null;
197
198 try {
199 beans = ctx.getBeansOfType(AuthenticationManager.class, true, true);
200 } catch (Exception e) {
201 if (super.log.isInfoEnabled()) {
202 super.log.info("exception in getBeansOfType " + e);
203 }
204
205 throw new IllegalStateException("spring error in get beans by class");
206 }
207
208 if (beans.size() == 0) {
209 throw new IllegalArgumentException(
210 "Bean context must contain at least one bean of type AuthenticationManager");
211 }
212
213 beanName = (String) beans.keySet().iterator().next();
214 }
215
216 authenticationManager = (AuthenticationManager) ctx.getBean(beanName);
217
218 if (super.log.isInfoEnabled()) {
219 super.log.info("Successfully started JbossSpringLoginModule");
220 }
221 }
222
223 public boolean login() throws LoginException {
224 super.loginOk = false;
225
226 String[] info = getUsernameAndPassword();
227 String username = info[0];
228 String password = info[1];
229
230 if ((username == null) && (password == null)) {
231 identity = null;
232 super.log.trace("Authenticating as unauthenticatedIdentity=" + identity);
233 }
234
235 if (username == null) {
236 username = "";
237 }
238
239 if (password == null) {
240 password = "";
241 }
242
243 if (super.log.isDebugEnabled()) {
244 super.log.debug("checking identity");
245 }
246
247 if (identity == null) {
248 super.log.debug("creating usernamepassword token");
249
250 Authentication request = new UsernamePasswordAuthenticationToken(username, password);
251 Authentication response = null;
252
253 try {
254 if (super.log.isDebugEnabled()) {
255 super.log.debug("attempting authentication");
256 }
257
258 response = authenticationManager.authenticate(request);
259
260 if (super.log.isDebugEnabled()) {
261 super.log.debug("authentication succeded");
262 }
263 } catch (CredentialsExpiredException cee) {
264 if (super.log.isDebugEnabled()) {
265 super.log.debug("Credential has expired");
266 }
267
268 throw new javax.security.auth.login.CredentialExpiredException(
269 "The credential used to identify the user has expired");
270 } catch (AccountExpiredException cee) {
271 if (super.log.isDebugEnabled()) {
272 super.log.debug("Account has expired, throwing jaas exception");
273 }
274
275 throw new javax.security.auth.login.AccountExpiredException(
276 "The account specified in login has expired");
277 } catch (AuthenticationException failed) {
278 if (super.log.isDebugEnabled()) {
279 super.log.debug("Bad password for username=" + username);
280 }
281
282 throw new FailedLoginException("Password Incorrect/Password Required");
283 }
284
285 super.log.debug("user is logged. redirecting to jaas classes");
286
287 identity = new PrincipalSpringSecurityUserToken(this.key, response.getName(), response.getCredentials().toString(),
288 response.getAuthorities(), response.getPrincipal());
289 }
290
291 if (getUseFirstPass() == true) {
292
293 sharedState.put("javax.security.auth.login.name", username);
294 sharedState.put("javax.security.auth.login.password", credential);
295 }
296
297 super.loginOk = true;
298 super.log.trace("User '" + identity + "' authenticated, loginOk=" + loginOk);
299
300 return true;
301 }
302 }