001: /**
002: * Copyright 2002 Sun Microsystems, Inc. All
003: * rights reserved. Use of this product is subject
004: * to license terms. Federal Acquisitions:
005: * Commercial Software -- Government Users
006: * Subject to Standard License Terms and
007: * Conditions.
008: *
009: * Sun, Sun Microsystems, the Sun logo, and iPlanet
010: * are trademarks or registered trademarks of Sun Microsystems,
011: * Inc. in the United States and other countries.
012: */package com.sun.ssoadapter.impl;
013:
014: import com.iplanet.am.sdk.AMException;
015: import com.iplanet.am.sdk.AMStoreConnection;
016: import com.iplanet.am.sdk.AMUser;
017: import com.iplanet.sso.SSOToken;
018: import com.iplanet.sso.SSOTokenEvent;
019: import com.iplanet.sso.SSOException;
020: import com.sun.ssoadapter.SSOAdapter;
021: import com.sun.ssoadapter.AbstractSSOAdapter;
022: import com.sun.ssoadapter.SSOAdapterException;
023: import com.sun.comclient.calendar.*;
024: import com.sun.comclient.calendar.socs.*;
025: import com.sun.ssoadapter.SSOAdapterLogger;
026:
027: import java.util.Properties;
028: import java.net.HttpURLConnection;
029: import java.net.URL;
030: import java.io.*;
031: import java.util.*;
032: import javax.servlet.http.*;
033:
034: import java.util.logging.Level;
035: import java.util.logging.Logger;
036: import java.util.logging.LogRecord;
037:
038: /**
039: * This class extends the abstract SSOAdapter functionality
040: * specific to the Sun One Portal and Calendar services.
041: * <p>Specific features include:
042: * <ul>
043: * <li>Support for username/password style authentication.</li>
044: * </ul>
045: * <p>At the present time, username/password is stored in the clear.
046: * <p>This CalendarSSOHelper implementation consumes the following
047: * Configuration properties:
048: * <ul>
049: * <li><b>protocol</b>: Required value. Specifies the protocol
050: * JCAPI will use to connect to the calendar server.
051: * For the time being, this should always be "http".
052: * <li><b>uid</b>: Required value. Username (uid) of calendar user.
053: * <li><b>password</b>: Required value. Password of calendar user.
054: * <li><b>host</b>: Required value. Name of host providing IMAP service.
055: * <li><b>port</b>: Optional value. Port number of calendar server.
056: * Defaults to "80"
057: * <li><b>clientProtocol</b>: Protocol to specify within URLs that activate
058: * web application functionality. Defaults to "http".
059: * <li><b>clientPort</b>: Port to specify within URLs that that activate web
060: * application functionality. Defaults to "80".
061: * <li><b>checkInterval</b>: Specifies, in milliseconds, the minimum interval
062: * between backend server availability checks.
063: * </ul>
064: *
065: * @version 1.0
066: * @see com.sun.ssoadapter.SSOAdapter
067: * @see com.sun.ssoadapter.SSOAdapterFactory
068: *
069: */
070:
071: public class JCAPISSOAdapter extends AbstractSSOAdapter {
072:
073: protected long checkInterval;
074: protected long lastCheckTime = 0;
075:
076: protected static String CALENDAR_DEFAULT_PORT = "80";
077: protected static String CLIENT_DEFAULT_PORT = "80";
078: protected static String CALENDAR_DEFAULT_PROTOCOL = "http";
079: protected static String CLIENT_DEFAULT_PROTOCOL = "http";
080: protected static String serviceClass = "com.sun.comclient.calendar.socs.SOCSCalendarStore";
081:
082: /**
083: * CalendarSession object for this CalendarSSOHelper.
084: */
085: protected CalendarSession calSession;
086:
087: /**
088: * CalendarStore object for this CalendarSSOHelper.
089: */
090: protected CalendarStore calStore;
091:
092: private static Logger logger = SSOAdapterLogger
093: .getLogger("com.sun.portal.ssoadapter.impl");
094:
095: /**
096: * Initialize and validate JCAPISSOAdapter.
097: *
098: * @param adapterName Used to identify the SSOAdapter
099: * @param token Used to identify the user on who's behalf the request is
100: * being processed.
101: * @param adapterProperties Contains the adapter information that will drive
102: * the operation of this instance of an SSOAdapter.
103: */
104: public void init(String adapterName, SSOToken token,
105: Properties adapterProperties, List userPropertiesList,
106: List encodedProperteisList, Locale locale)
107: throws SSOAdapterException {
108:
109: super .init(adapterName, token, adapterProperties,
110: userPropertiesList, encodedProperteisList, locale);
111:
112: if (logger.isLoggable(Level.INFO)) {
113: Properties dp = new Properties();
114: dp.putAll(adapterProperties);
115: dp.remove(PROP_PASSWORD_NAME);
116: dp.remove("proxyAdminPassword");
117:
118: String[] param = new String[5];
119: param[0] = adapterName;
120: param[1] = (String) dp.toString();
121: param[2] = identifier;
122: param[3] = userPropertiesList.toString();
123: param[4] = encodedProperteisList.toString();
124:
125: logger.log(Level.INFO, "PSSA_CSSI0001", param);
126: }
127:
128: // check interval
129: try {
130: checkInterval = Integer.parseInt(adapterProperties
131: .getProperty("checkInterval", "5000"));
132: } catch (Exception e) {
133: String msg = this .getClass().getName()
134: + ".init(): invalid \"checkInterval\" "
135: + "parameter in adapterProperties \"" + getName()
136: + "\"";
137: throw new SSOAdapterException(msg);
138: }
139:
140: // check for validation
141: if (adapterProperties.getProperty("validate", "false").equals(
142: "true")) {
143: try {
144: validate();
145: } catch (ValidationException ve) {
146: throw new SSOAdapterException(ve.getLocalizedMessage(
147: "ssoadapter", locale), true);
148: }
149: }
150:
151: }
152:
153: /**
154: * Validates configuration.
155: */
156: public void validate() throws ValidationException {
157:
158: if (logger.isLoggable(Level.INFO)) {
159: logger.log(Level.INFO, "PSSA_CSSI0003", new String[] {
160: adapterName, identifier });
161: }
162:
163: String portString = adapterProperties
164: .getProperty(PROP_PORT_NAME);
165: if ((portString != null) && (portString.length() > 0)) {
166: try {
167: int portInt = Integer.parseInt(portString);
168: } catch (Exception e) {
169: ValidationException ve = new ValidationException();
170: ve.setErrorMessageID("invalidPort");
171: throw ve;
172: }
173: }
174:
175: String hostString = adapterProperties
176: .getProperty(PROP_HOST_NAME);
177: if (hostString == null) {
178: ValidationException ve = new ValidationException();
179: ve.setErrorMessageID("missingHost");
180: throw ve;
181: }
182:
183: String clientPortString = adapterProperties
184: .getProperty(PROP_CLIENT_PORT);
185: if ((clientPortString != null)
186: && (clientPortString.length() > 0)) {
187: try {
188: int portInt = Integer.parseInt(clientPortString);
189: } catch (Exception e) {
190: ValidationException ve = new ValidationException();
191: ve.setErrorMessageID("invalidClientPort");
192: throw ve;
193: }
194: }
195:
196: String enableProxyAuth = adapterProperties.getProperty(
197: "enableProxyAuth", "false");
198: if (enableProxyAuth.equals("false")) {
199: String uidString = adapterProperties
200: .getProperty(PROP_UID_NAME);
201: if (uidString == null) {
202: ValidationException ve = new ValidationException();
203: ve.setErrorMessageID("missingUid");
204: throw ve;
205: }
206:
207: String passwordString = adapterProperties
208: .getProperty(PROP_PASSWORD_NAME);
209: if (passwordString == null) {
210: ValidationException ve = new ValidationException();
211: ve.setErrorMessageID("missingPassword");
212: throw ve;
213: }
214: }
215:
216: }
217:
218: /**
219: * Adapter specific Connection.
220: */
221: public Object getConnection() {
222: Object obj = null;
223:
224: try {
225: obj = getCalStore();
226: } catch (Exception e) {
227: if (logger.isLoggable(Level.INFO)) {
228: logger.log(Level.INFO, "PSSA_CSSI0010", new String[] {
229: adapterName, identifier });
230: logger.log(Level.INFO, "PSSA_CSSI0011", e);
231: }
232: return null;
233: }
234:
235: if (obj != null) {
236: if (logger.isLoggable(Level.INFO)) {
237: logger.log(Level.INFO, "PSSA_CSSI0012", new String[] {
238: adapterName, identifier });
239: }
240: }
241:
242: return obj;
243: }
244:
245: /**
246: * Returns a JCAPI CalendarStore object.
247: */
248: public CalendarStore getCalStore() throws Exception {
249:
250: Date newCheckDate = new Date();
251: long newCheckTime = newCheckDate.getTime();
252: long timeSinceLastCheck = newCheckTime - lastCheckTime;
253:
254: if (timeSinceLastCheck < checkInterval && calStore != null) {
255: if (logger.isLoggable(Level.INFO)) {
256: logger.log(Level.INFO, "PSSA_CSSI0013", new String[] {
257: adapterName, identifier });
258: }
259: return calStore;
260: }
261:
262: lastCheckTime = newCheckTime;
263:
264: // check for an existing store
265: //
266: if (isAvailable()) {
267: return calStore;
268: }
269:
270: // check for mandatory properties, if they are null then there's
271: // no point in trying to establish a connection
272: //
273: String host = adapterProperties.getProperty(PROP_HOST_NAME);
274:
275: if (host == null) {
276: if (logger.isLoggable(Level.INFO)) {
277: logger.log(Level.INFO, "PSSA_CSSI0015", new String[] {
278: adapterName, identifier });
279: }
280: return null;
281: }
282:
283: String portStr = adapterProperties.getProperty(PROP_PORT_NAME,
284: CALENDAR_DEFAULT_PORT);
285: int port = Integer.parseInt(portStr);
286:
287: calSession = getCalSession();
288: calStore = calSession.getStore(serviceClass);
289: calStore.connect(host, port);
290:
291: return calStore;
292: }
293:
294: /**
295: * Returns a JCAPI CalSession object.
296: */
297: public CalendarSession getCalSession() throws Exception {
298:
299: if (calSession != null) {
300: if (logger.isLoggable(Level.INFO)) {
301: logger.log(Level.INFO, "PSSA_CSSI0017", new String[] {
302: adapterName, identifier });
303: }
304: return calSession;
305: }
306:
307: String host = adapterProperties.getProperty(PROP_HOST_NAME);
308: String port = adapterProperties.getProperty(PROP_PORT_NAME,
309: CALENDAR_DEFAULT_PORT);
310: String protocol = adapterProperties.getProperty(
311: PROP_PROTOCOL_NAME, CALENDAR_DEFAULT_PROTOCOL);
312: String domain = adapterProperties.getProperty("domain");
313: String enableProxyAuth = adapterProperties.getProperty(
314: "enableProxyAuth", "false");
315: String uid = null;
316: String puid = null;
317: String password = null;
318: Properties props = new Properties();
319:
320: // check to see if admin proxyauth has been enabled and
321: // that we have a valid session (ssotoken)
322: //
323: if (enableProxyAuth.equals("true")) {
324: if (logger.isLoggable(Level.INFO)) {
325: logger.log(Level.INFO, "PSSA_CSSI0018", new String[] {
326: adapterName, identifier });
327: }
328: SSOToken tok = getSSOToken();
329: AMStoreConnection amsc = null;
330: AMUser auser = null;
331: String usrAttr = null;
332:
333: if (tok != null) {
334: uid = adapterProperties.getProperty("proxyAdminUid");
335: password = adapterProperties
336: .getProperty("proxyAdminPassword");
337: usrAttr = adapterProperties.getProperty(
338: "userAttribute", "uid");
339:
340: try {
341: amsc = new AMStoreConnection(tok);
342: auser = amsc.getUser(tok.getPrincipal().getName());
343: puid = auser.getStringAttribute(usrAttr);
344: } catch (SSOException ssoe) {
345: if (logger.isLoggable(Level.SEVERE)) {
346: LogRecord rec = new LogRecord(Level.INFO,
347: "PSSA_CSSI0004");
348: String[] param = { adapterName, usrAttr,
349: identifier };
350: rec.setParameters(param);
351: rec.setThrown(ssoe);
352: rec.setLoggerName(logger.getName());
353: logger.log(rec);
354: }
355: } catch (AMException ame) {
356: if (logger.isLoggable(Level.SEVERE)) {
357: LogRecord rec = new LogRecord(Level.INFO,
358: "PSSA_CSSI0004");
359: String[] param = { adapterName, usrAttr,
360: identifier };
361: rec.setParameters(param);
362: rec.setThrown(ame);
363: logger.log(rec);
364: }
365: }
366: }
367:
368: if (domain != null && (domain.length() > 0)) {
369: puid = puid + "@" + domain;
370: }
371:
372: if (logger.isLoggable(Level.INFO)) {
373: logger.log(Level.INFO, "PSSA_CSSI0019", new String[] {
374: adapterName, puid, identifier });
375: }
376:
377: } else {
378: uid = adapterProperties.getProperty(PROP_UID_NAME);
379: password = adapterProperties
380: .getProperty(PROP_PASSWORD_NAME);
381:
382: if (domain != null && (domain.length() > 0)) {
383: uid = uid + "@" + domain;
384: }
385:
386: if (logger.isLoggable(Level.INFO)) {
387: logger.log(Level.INFO, "PSSA_CSSI0020", new String[] {
388: adapterName, uid, identifier });
389: }
390: }
391:
392: if (host != null)
393: props.put("cal.host", host);
394: if (port != null)
395: props.put("cal.port", port);
396: if (uid != null)
397: props.put("cal.user", uid);
398: if (password != null)
399: props.put("cal.password", password);
400: if (protocol != null)
401: props.put("cal.protocol", protocol);
402: if (puid != null)
403: props.put("cal.proxyauth", puid);
404:
405: calSession = calSession.getInstance(props);
406:
407: return calSession;
408: }
409:
410: /**
411: * Tests service availability.
412: */
413: public boolean isAvailable() {
414: if (calStore != null && calStore.isConnected()) {
415: if (logger.isLoggable(Level.INFO)) {
416: logger.log(Level.INFO, "PSSA_CSSI0014", new String[] {
417: adapterName, identifier });
418: }
419: return true;
420: } else {
421: return false;
422: }
423: }
424:
425: /**
426: * Adapter specific Connection termination.
427: *
428: * @return true if the connection was terminated successfully.
429: */
430: public boolean closeConnection() {
431: boolean retval = true;
432:
433: try {
434: calStore.disconnect();
435: calStore = null;
436: calSession = null;
437: } catch (Exception e) {
438: retval = false;
439: }
440:
441: if (logger.isLoggable(Level.INFO)) {
442: logger.log(Level.INFO, "PSSA_CSSI0005", new String[] {
443: adapterName, identifier });
444: }
445:
446: return retval;
447: }
448:
449: /**
450: * Implements SSOTokenListener "ssoTokenChanged" method.
451: *
452: * The following are possible SSO token event types:
453: * <ul>
454: * <li>SSO_TOKEN_IDLE_TIMEOUT
455: * <li>SSO_TOKEN_MAX_TIMEOUT
456: * <li>SSO_TOKEN_DESTROY
457: * </ul>
458: *
459: * The event getType() method is used to ensure that one of the
460: * three types above are the basis for this event. If getType()
461: * returns a type not listed above, then an SSOException is thrown.
462: *
463: * @param evt SSOTokenEvent
464: */
465: public void ssoTokenChanged(SSOTokenEvent evt) {
466:
467: try {
468: int evtType = evt.getType();
469:
470: if (calStore != null) {
471: calStore.disconnect();
472: }
473:
474: calStore = null;
475: calSession = null;
476: } catch (Exception e) {
477: if (logger.isLoggable(Level.WARNING)) {
478: logger.log(Level.WARNING, "PSSA_CSSI0006", e);
479: }
480: return;
481: }
482:
483: if (logger.isLoggable(Level.INFO)) {
484: logger.log(Level.INFO, "PSSA_CSSI0002", new String[] {
485: adapterName, identifier });
486: }
487: }
488:
489: }
|