001: /*
002: * JOSSO: Java Open Single Sign-On
003: *
004: * Copyright 2004-2008, Atricore, Inc.
005: *
006: * This is free software; you can redistribute it and/or modify it
007: * under the terms of the GNU Lesser General Public License as
008: * published by the Free Software Foundation; either version 2.1 of
009: * the License, or (at your option) any later version.
010: *
011: * This software is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this software; if not, write to the Free
018: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
019: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
020: */
021:
022: package org.josso.wls92.agent.jaas;
023:
024: import org.apache.commons.logging.Log;
025: import org.apache.commons.logging.LogFactory;
026: import org.josso.Lookup;
027: import org.josso.gateway.identity.SSORole;
028: import org.josso.gateway.identity.SSOUser;
029: import org.josso.gateway.identity.exceptions.SSOIdentityException;
030: import org.josso.gateway.identity.service.SSOIdentityManager;
031:
032: import javax.security.auth.Subject;
033: import javax.security.auth.callback.*;
034: import javax.security.auth.login.FailedLoginException;
035: import javax.security.auth.login.LoginException;
036: import javax.security.auth.spi.LoginModule;
037: import java.util.Map;
038:
039: /**
040: * SSO Gateway Login Module implementation for Weblogic.
041: *
042: * Date: Nov 20, 2007
043: * Time: 6:24:15 PM
044: *
045: * @author <a href="mailto:sgonzalez@josso.org">Sebastian Gonzalez Oyuela</a>
046: */
047: public class SSOGatewayLoginModuleImpl implements LoginModule {
048:
049: private static final Log logger = LogFactory
050: .getLog(SSOGatewayLoginModuleImpl.class);
051:
052: // initial state
053: private Subject _subject;
054: private CallbackHandler _callbackHandler;
055:
056: // the authentication status
057: protected boolean _succeeded;
058: protected boolean commitSucceeded;
059:
060: // the logged user and his roles.
061: protected WLSJOSSOUser _ssoUserPrincipal;
062: protected WLSJOSSORole[] _ssoRolePrincipals;
063:
064: /**
065: * Initialize this LoginModule
066: *
067: * @param subject the Subject to be authenticated.
068: *
069: * @param callbackHandler a CallbackHandler for communicating
070: * with the end user (prompting for user names and
071: * passwords, for example).
072: *
073: * @param sharedState shared LoginModule state.
074: *
075: * @param options options specified in the login Configuration
076: * for this particular LoginModule.
077: */
078: public void initialize(Subject subject,
079: CallbackHandler callbackHandler, Map sharedState,
080: Map options) {
081:
082: this ._subject = subject;
083: this ._callbackHandler = callbackHandler;
084: }
085:
086: /**
087: * Authenticate the user by prompting for the SSO Session Identifier assigned by the SSO Gateway on logon.
088: *
089: * This method obtains from the gateway, using the provided session identifier, the user associated with
090: * such session identifier.
091: * Only the NameCallBack is used, since its not a user/password pair but only one value containing the session
092: * identifier. Any other callback type is ignored.
093: *
094: * @return true in all cases since this LoginModule
095: * should not be ignored.
096: *
097: * @exception javax.security.auth.login.FailedLoginException if the authentication fails.
098: *
099: * @exception javax.security.auth.login.LoginException if this LoginModule
100: * is unable to perform the authentication.
101: */
102: public boolean login() throws LoginException {
103:
104: if (_callbackHandler == null)
105: throw new LoginException(
106: "Error: no CallbackHandler available "
107: + "to garner authentication information from the user");
108:
109: Callback[] callbacks = new Callback[2];
110:
111: // Just ask for the session identifier
112: callbacks[0] = new NameCallback("JOSSO Session Identifier");
113: callbacks[1] = new PasswordCallback("password", false);
114:
115: String ssoSessionId;
116: String ssoSessionId2 = null;
117: try {
118: _callbackHandler.handle(callbacks);
119: ssoSessionId = ((NameCallback) callbacks[0]).getName();
120: if (((PasswordCallback) callbacks[1]).getPassword() != null)
121: ssoSessionId2 = String
122: .valueOf(((PasswordCallback) callbacks[1])
123: .getPassword());
124: } catch (java.io.IOException ioe) {
125: throw new LoginException(ioe.toString());
126: } catch (UnsupportedCallbackException uce) {
127: throw new LoginException(
128: "Error: "
129: + uce.getCallback().toString()
130: + " not available to garner authentication information "
131: + "from the user");
132: }
133:
134: logger.info("Session requested authentication to gateway : "
135: + ssoSessionId + "/" + ssoSessionId2);
136:
137: try {
138:
139: if (ssoSessionId2 != null
140: && !ssoSessionId2.equals(ssoSessionId))
141: ssoSessionId = ssoSessionId2;
142:
143: // If no session is found, ignore this module.
144: if (ssoSessionId == null) {
145: logger.info("Session authentication failed : "
146: + ssoSessionId);
147: _succeeded = false;
148: return false;
149: }
150:
151: SSOIdentityManager im = Lookup.getInstance()
152: .lookupSSOAgent().getSSOIdentityManager();
153: SSOUser jossoUser = im.findUserInSession(ssoSessionId);
154: WLSJOSSOUser wlsUser = new WLSJOSSOUser(jossoUser);
155:
156: logger.info("Session authentication succeeded : "
157: + ssoSessionId);
158: _ssoUserPrincipal = wlsUser;
159: _succeeded = true;
160:
161: } catch (SSOIdentityException e) {
162: // Ignore this ... (user does not exist for this session)
163: logger.info(e.getMessage());
164: _succeeded = false;
165: return false;
166:
167: } catch (Exception e) {
168:
169: logger.error("Session login failed for Principal : "
170: + _ssoUserPrincipal + e.getMessage());
171:
172: // Only log if debug is enabled ...
173: if (logger.isDebugEnabled())
174: logger.debug(e.getMessage(), e);
175:
176: _succeeded = false;
177: clearCredentials();
178: throw new FailedLoginException(
179: "Fatal error authenticating session : "
180: + _ssoUserPrincipal + " : "
181: + e.getMessage());
182: }
183:
184: return true;
185: }
186:
187: /**
188: * This method is called if the LoginContext's overall authentication succeeded.
189: *
190: * Using the SSO user name, saved by the previosuly executed login() operation, obtains from the gateway
191: * the roles associated with the user and fills the Subject with the user and role principals.
192: * If this LoginModule's own authentication attempted failed, then this method removes any state that was
193: * originally saved.
194: *
195: * @exception LoginException if the commit fails.
196: *
197: * @return true if this LoginModule's own login and commit
198: * attempts succeeded, or false otherwise.
199: */
200: public boolean commit() throws LoginException {
201: if (_succeeded == false) {
202: return false;
203: } else {
204:
205: try {
206:
207: // Add the SSOUser as a Principal
208: if (!_subject.getPrincipals().contains(
209: _ssoUserPrincipal)) {
210: _subject.getPrincipals().add(_ssoUserPrincipal);
211: }
212:
213: logger.info("Added SSOUser Principal to the Subject : "
214: + _ssoUserPrincipal);
215:
216: _ssoRolePrincipals = getRoleSets();
217:
218: // Add to the Subject the SSORoles associated with the SSOUser .
219: for (int i = 0; i < _ssoRolePrincipals.length; i++) {
220: if (_subject.getPrincipals().contains(
221: _ssoRolePrincipals[i]))
222: continue;
223:
224: _subject.getPrincipals().add(_ssoRolePrincipals[i]);
225: logger
226: .info("Added SSORole Principal to the Subject : "
227: + _ssoRolePrincipals[i]);
228: }
229:
230: commitSucceeded = true;
231: return true;
232:
233: } catch (Exception e) {
234: logger.error("Session commit failed for Principal : "
235: + _ssoUserPrincipal + e.getMessage());
236: // Only log if debug is enabled ...
237: if (logger.isDebugEnabled())
238: logger.debug(e.getMessage(), e);
239:
240: throw new LoginException(
241: "Session commit failed for Principal : "
242: + _ssoUserPrincipal + " : "
243: + e.getMessage());
244: } finally {
245: // in any case, clean out state
246: clearCredentials();
247: }
248:
249: }
250: }
251:
252: /**
253: * This method is called if the LoginContext's
254: * overall authentication failed.
255: *
256: * @exception LoginException if the abort fails.
257: *
258: * @return false if this LoginModule's own login and/or commit attempts
259: * failed, and true otherwise.
260: */
261: public boolean abort() throws LoginException {
262: if (_succeeded == false) {
263: return false;
264: } else if (_succeeded == true && commitSucceeded == false) {
265: // login _succeeded but overall authentication failed
266: _succeeded = false;
267: clearCredentials();
268: } else {
269: // overall authentication _succeeded and commit _succeeded,
270: // but someone else's commit failed
271: logout();
272: }
273: return true;
274: }
275:
276: /**
277: * Logout the user.
278: *
279: * This method removes the SSO User and Role Principals from the Subject that were added by the commit()
280: * method.
281: *
282: * @exception LoginException if the logout fails.
283: *
284: * @return true in all cases since this LoginModule
285: * should not be ignored.
286: */
287: public boolean logout() throws LoginException {
288: _subject.getPrincipals().remove(_ssoUserPrincipal);
289: logger.info("Removed SSOUser Principal from Subject : "
290: + _ssoUserPrincipal);
291:
292: // Remove all the SSORole Principals from the Subject.
293: for (int i = 0; i < _ssoRolePrincipals.length; i++) {
294: _subject.getPrincipals().remove(_ssoRolePrincipals[i]);
295: logger.info("Removed SSORole Principal from Subject : "
296: + _ssoRolePrincipals[i]);
297: }
298:
299: _succeeded = commitSucceeded;
300: clearCredentials();
301: return true;
302: }
303:
304: /**
305: * Reset the login module state.
306: */
307: private void clearCredentials() {
308: _ssoUserPrincipal = null;
309: _ssoRolePrincipals = null;
310: }
311:
312: /**
313: * Retreives the list of roles associated to current principal
314: */
315: protected WLSJOSSORole[] getRoleSets() throws LoginException {
316: try {
317: // obtain user roles principals and add it to the subject
318: SSOIdentityManager im = Lookup.getInstance()
319: .lookupSSOAgent().getSSOIdentityManager();
320:
321: SSORole[] roles = im.findRolesByUsername(_ssoUserPrincipal
322: .getName());
323: WLSJOSSORole[] wlsRoles = new WLSJOSSORole[roles.length];
324:
325: for (int i = 0; i < roles.length; i++) {
326: SSORole role = roles[i];
327: WLSJOSSORole wlsRole = new WLSJOSSORole(role);
328: wlsRoles[i] = wlsRole;
329: }
330:
331: return wlsRoles;
332:
333: } catch (Exception e) {
334: logger.error("Session login failed for Principal : "
335: + _ssoUserPrincipal, e);
336: throw new LoginException(
337: "Session login failed for Principal : "
338: + _ssoUserPrincipal);
339: }
340:
341: }
342: }
|