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.sso.SSOToken;
015: import com.iplanet.sso.SSOTokenEvent;
016: import com.iplanet.sso.SSOException;
017: import com.sun.ssoadapter.SSOAdapter;
018: import com.sun.ssoadapter.AbstractSSOAdapter;
019: import com.sun.ssoadapter.SSOAdapterException;
020: import com.sun.comclient.calendar.*;
021: import com.sun.ssoadapter.SSOAdapterLogger;
022:
023: import java.util.Properties;
024: import java.net.HttpURLConnection;
025: import java.net.URL;
026: import java.io.*;
027: import java.util.*;
028: import java.util.logging.Level;
029: import java.util.logging.Logger;
030:
031: import javax.servlet.http.*;
032:
033: /**
034: * This class implements CalendarSSOAdapter and CalendarApplicationAdapter functionality
035: * specific to the Sun One Portal and Calendar services.
036: * <p>Specific features include:
037: * <ul>
038: * <li>Support for username/password style authentication.</li>
039: * <li>Ability to generate web application URLs for the following:
040: * <ul>
041: * <li>Calendar Express</li>
042: * <li>MAP JSP Calendar application. The URL generated in this
043: * case will specify a configuration index via the
044: * query string parameter: "ci". </li>
045: * </ul>
046: * </li>
047: * </ul>
048: * <p>At the present time, username/password is stored in the clear.
049: * <p>This CalendarSSOAdapter implementation consumes the following
050: * Configuration properties:
051: * <ul>
052: * <li><b>protocol</b>: Required value. Specifies the protocol
053: * JCAPI will use to connect to the calendar server.
054: * For the time being, this should always be "http".
055: * <li><b>uid</b>: Required value. Username (uid) of calendar user.
056: * <li><b>password</b>: Required value. Password of calendar user.
057: * <li><b>host</b>: Required value. Name of host providing IMAP service.
058: * <li><b>port</b>: Optional value. Port number of calendar server.
059: * <li><b>clientProtocol</b>: Protocol to specify within URLs that activate
060: * web application functionality. Defaults to "http".
061: * <li><b>clientPort</b>: Port to specify within URLs that that activate web
062: * application functionality. Defaults to "80".
063: * <li><b>jspContextPath</b>: The "request context path" to use when forming a URL
064: * that activates MAP JSP application functionality.
065: * Defaults to request.getContextPath().
066: * <li><b>jspLaunch</b>: The document path to use when forming a URL
067: * that activates MAP JSP application functionality.
068: * </ul>
069: *
070: * @version 1.0
071: * @see com.sun.ssoadapter.SSOAdapter
072: * @see com.sun.ssoadapter.SSOAdapterFactory
073: *
074: */
075:
076: public class NotesCalendarSSOAdapter extends AbstractSSOAdapter {
077:
078: protected CalendarSession calSession;
079: protected CalendarStore calStore;
080:
081: protected static String CALENDAR_DEFAULT_PORT = "80";
082: protected static String CALENDAR_DEFAULT_PROTOCOL = "http";
083:
084: protected static String serviceClass = "com.sun.ssoadapter.calendar.pim.APimCalStore";
085:
086: private static Logger logger = SSOAdapterLogger
087: .getLogger("com.sun.portal.ssoadapter.impl");
088:
089: /**
090: * Initialize and validate SSOAdapter.
091: *
092: * @param adapterName Used to identify the SSOAdapter
093: * @param token Used to identify the user on who's behalf the request is
094: * being processed.
095: * @param adapterProperties Contains the adapter information that will drive
096: * the operation of this instance of an SSOAdapter.
097: */
098: public void init(String adapterName, SSOToken token,
099: Properties adapterProperties, List userPropertiesList,
100: List encodedProperteisList, Locale locale)
101: throws SSOAdapterException {
102:
103: super .init(adapterName, token, adapterProperties,
104: userPropertiesList, encodedProperteisList, locale);
105:
106: if (logger.isLoggable(Level.INFO)) {
107: Properties dp = new Properties();
108: dp.putAll(adapterProperties);
109: dp.remove(PROP_PASSWORD_NAME);
110: dp.remove("proxyAdminPassword");
111:
112: String[] param = new String[5];
113: param[0] = adapterName;
114: param[1] = (String) dp.toString();
115: param[2] = identifier;
116: param[3] = userPropertiesList.toString();
117: param[4] = encodedProperteisList.toString();
118:
119: logger.log(Level.INFO, "PSSA_CSSI0001", param);
120: }
121:
122: if (adapterProperties.getProperty("validate", "false").equals(
123: "true")) {
124: try {
125: validate();
126: } catch (ValidationException ve) {
127: throw new SSOAdapterException(ve.getLocalizedMessage(
128: "ssoadapter", locale), true);
129: }
130: }
131:
132: }
133:
134: /**
135: * Validates configuration.
136: */
137: public void validate() throws ValidationException {
138:
139: if (logger.isLoggable(Level.INFO)) {
140: logger.log(Level.INFO, "PSSA_CSSI0003", new String[] {
141: adapterName, identifier });
142: }
143:
144: String portString = adapterProperties
145: .getProperty(PROP_PORT_NAME);
146: if ((portString != null) && (portString.length() > 0)) {
147: try {
148: int portInt = Integer.parseInt(portString);
149: } catch (Exception e) {
150: ValidationException ve = new ValidationException();
151: ve.setErrorMessageID("invalidPort");
152: throw ve;
153: }
154: }
155:
156: String hostString = adapterProperties
157: .getProperty(PROP_HOST_NAME);
158: if (hostString == null) {
159: ValidationException ve = new ValidationException();
160: ve.setErrorMessageID("missingHost");
161: throw ve;
162: }
163:
164: String uidString = adapterProperties.getProperty(PROP_UID_NAME);
165: if (uidString == null) {
166: ValidationException ve = new ValidationException();
167: ve.setErrorMessageID("missingUid");
168: throw ve;
169: }
170:
171: String passwordString = adapterProperties
172: .getProperty(PROP_PASSWORD_NAME);
173: if (passwordString == null) {
174: ValidationException ve = new ValidationException();
175: ve.setErrorMessageID("missingPassword");
176: throw ve;
177: }
178:
179: String clientPortString = adapterProperties
180: .getProperty("clientPort");
181: if ((clientPortString != null)
182: && (clientPortString.length() > 0)) {
183: try {
184: int portInt = Integer.parseInt(clientPortString);
185: } catch (Exception e) {
186: ValidationException ve = new ValidationException();
187: ve.setErrorMessageID("invalidClientPort");
188: throw ve;
189: }
190: }
191:
192: }
193:
194: /**
195: * Tests service availability.
196: */
197: public boolean isAvailable() {
198: if (calStore != null && calStore.isConnected()) {
199: if (logger.isLoggable(Level.INFO)) {
200: logger.log(Level.INFO, "PSSA_CSSI0014", new String[] {
201: adapterName, identifier });
202: }
203: return true;
204: } else {
205: return false;
206: }
207: }
208:
209: /**
210: * Adapter specific Connection.
211: */
212: public Object getConnection() {
213: Object obj = null;
214:
215: try {
216: obj = getCalStore();
217: } catch (Exception e) {
218: if (logger.isLoggable(Level.INFO)) {
219: logger.log(Level.INFO, "PSSA_CSSI0010", new String[] {
220: adapterName, identifier });
221: logger.log(Level.INFO, "PSSA_CSSI0011", e);
222: }
223: return null;
224: }
225:
226: if (obj != null) {
227: if (logger.isLoggable(Level.INFO)) {
228: logger.log(Level.INFO, "PSSA_CSSI0012", new String[] {
229: adapterName, identifier });
230: }
231: }
232:
233: return obj;
234: }
235:
236: /**
237: * Returns a JCAPI CalStore object.
238: */
239: public CalendarStore getCalStore() throws Exception {
240: if (isAvailable()) {
241: return calStore;
242: }
243:
244: calSession = getCalSession();
245:
246: if (calSession == null) {
247: return null;
248: }
249:
250: String host = adapterProperties.getProperty(PROP_HOST_NAME);
251: String portStr = adapterProperties.getProperty(PROP_PORT_NAME,
252: CALENDAR_DEFAULT_PORT);
253: int port = Integer.parseInt(portStr);
254:
255: calStore = calSession.getStore(serviceClass);
256: calStore.connect(host, port);
257:
258: return calStore;
259: }
260:
261: /**
262: * Returns a JCAPI CalSession object.
263: */
264: public CalendarSession getCalSession() throws Exception {
265: if (calSession != null) {
266: if (logger.isLoggable(Level.INFO)) {
267: logger.log(Level.INFO, "PSSA_CSSI0017", new String[] {
268: adapterName, identifier });
269: }
270: return calSession;
271: }
272:
273: // check for mandatory properties, if they are null then there's
274: // no point in trying to establish a connection
275: //
276: String host = adapterProperties.getProperty(PROP_HOST_NAME);
277:
278: if (host == null) {
279: if (logger.isLoggable(Level.INFO)) {
280: logger.log(Level.INFO, "PSSA_CSSI0015", new String[] {
281: adapterName, identifier });
282: }
283: return null;
284: }
285:
286: String uid = adapterProperties.getProperty(PROP_UID_NAME);
287: String password = adapterProperties
288: .getProperty(PROP_PASSWORD_NAME);
289: String protocol = adapterProperties.getProperty(
290: PROP_PROTOCOL_NAME, CALENDAR_DEFAULT_PROTOCOL);
291: Properties props = new Properties();
292:
293: // TODO: Is this really needed for Notes?
294: String ocxHost = adapterProperties.getProperty("ocxHost", host);
295:
296: if (uid != null && (uid.length() > 0))
297: props.put("cal.user", uid);
298: else {
299: String portStr = adapterProperties.getProperty(
300: PROP_PORT_NAME, CALENDAR_DEFAULT_PORT);
301: //This assumes the domino server is working in SSO mode.
302: RemoteDominoSession domSess = new RemoteDominoSession(
303: protocol, host, portStr, getSSOToken());
304: String ltpaToken = domSess.getLTPAToken();
305: if (ltpaToken != null) {
306: props.put("lotus.ltpatoken.value", ltpaToken);
307:
308: //presently Aligo does not work when user is null: To be Removed
309: props.put("cal.user", "sso");
310: password = "sso";
311: }
312: }
313: if (password != null)
314: props.put("cal.password", password);
315: if (protocol != null)
316: props.put("cal.protocol", protocol);
317: if (ocxHost != null)
318: props.put("cal.exchange.ocxhost", ocxHost);
319:
320: props.put("cal.pim.service", "notes");
321:
322: if (logger.isLoggable(Level.INFO))
323: props.put("cal.pim.debug", "true");
324:
325: calSession = calSession.getInstance(props);
326:
327: return calSession;
328: }
329:
330: /**
331: * Adapter specific Connection termination.
332: *
333: * @return true if the connection was terminated successfully.
334: */
335: public boolean closeConnection() {
336: boolean retval = true;
337:
338: try {
339: calStore.disconnect();
340: calStore = null;
341: calSession = null;
342: } catch (Exception e) {
343: retval = false;
344: }
345:
346: if (logger.isLoggable(Level.INFO)) {
347: logger.log(Level.INFO, "PSSA_CSSI0005", new String[] {
348: adapterName, identifier });
349: }
350:
351: return retval;
352: }
353:
354: /**
355: * Implements SSOTokenListener "ssoTokenChanged" method.
356: *
357: * The following are possible SSO token event types:
358: * <ul>
359: * <li>SSO_TOKEN_IDLE_TIMEOUT
360: * <li>SSO_TOKEN_MAX_TIMEOUT
361: * <li>SSO_TOKEN_DESTROY
362: * </ul>
363: *
364: * The event getType() method is used to ensure that one of the
365: * three types above are the basis for this event. If getType()
366: * returns a type not listed above, then an SSOException is thrown.
367: *
368: * @param evt SSOTokenEvent
369: */
370: public void ssoTokenChanged(SSOTokenEvent evt) {
371:
372: try {
373: int evtType = evt.getType();
374:
375: if (calStore != null) {
376: calStore.disconnect();
377: }
378:
379: calStore = null;
380: calSession = null;
381: } catch (Exception e) {
382: if (logger.isLoggable(Level.WARNING)) {
383: logger.log(Level.WARNING, "PSSA_CSSI0006", e);
384: }
385: return;
386: }
387:
388: if (logger.isLoggable(Level.INFO)) {
389: logger.log(Level.INFO, "PSSA_CSSI0002", new String[] {
390: adapterName, identifier });
391: }
392: }
393:
394: }
|