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.portal.providers.calendar;
013:
014: import com.iplanet.sso.SSOToken;
015: import com.iplanet.sso.SSOException;
016: import com.iplanet.am.sdk.AMException;
017: import com.iplanet.am.sdk.AMStoreConnection;
018: import com.iplanet.am.sdk.AMUser;
019:
020: import com.sun.ssoadapter.SSOAdapter;
021: import com.sun.ssoadapter.SSOAdapterException;
022:
023: import com.sun.comclient.calendar.*;
024: import com.sun.comclient.calendar.socs.*;
025:
026: import java.util.Properties;
027: import java.net.HttpURLConnection;
028: import java.net.MalformedURLException;
029: import java.net.URL;
030: import java.net.URLConnection;
031: import java.net.URLEncoder;
032: import java.util.Date;
033: import java.util.Hashtable;
034: import java.util.logging.Logger;
035: import java.util.logging.Level;
036: import java.io.InputStreamReader;
037: import java.io.BufferedReader;
038:
039: import javax.servlet.http.HttpServletRequest;
040: import javax.servlet.http.HttpServletResponse;
041:
042: import com.sun.ssoadapter.SSOAdapter;
043: import com.sun.ssoadapter.SSOAdapterException;
044: import com.sun.ssoadapter.SSOAdapterFactory;
045:
046: import com.sun.portal.providers.context.ProviderContext;
047: import com.sun.portal.providers.context.ProviderContextException;
048: import com.sun.portal.providers.ProviderException;
049: import com.sun.portal.providers.Provider;
050: import com.sun.portal.providers.ProfileProviderAdapter;
051: import com.sun.portal.providers.ApplicationHelper;
052: import com.sun.portal.providers.ProviderEditUtility;
053: import com.sun.portal.log.common.PortalLogger;
054:
055: /**
056: * This class implements CalendarSSOHelper and CalendarApplicationHelper functionality
057: * specific to the Sun One Portal and Calendar services.
058: * <p>Specific features include:
059: * <ul>
060: * <li>Support for username/password style authentication.</li>
061: * <li>Ability to generate web application URLs for the following:
062: * <ul>
063: * <li>Calendar Express</li>
064: * <li>MAP JSP Calendar application. The URL generated in this
065: * case will specify a configuration index via the
066: * query string parameter: "ci". </li>
067: * </ul>
068: * </li>
069: * </ul>
070: * <p>At the present time, username/password is stored in the clear.
071: * <p>This CalendarSSOHelper implementation consumes the following
072: * Configuration properties:
073: * <ul>
074: * <li><b>protocol</b>: Required value. Specifies the protocol
075: * JCAPI will use to connect to the calendar server.
076: * For the time being, this should always be "http".
077: * <li><b>uid</b>: Required value. Username (uid) of calendar user.
078: * <li><b>password</b>: Required value. Password of calendar user.
079: * <li><b>host</b>: Required value. Name of host providing IMAP service.
080: * <li><b>port</b>: Optional value. Port number of calendar server.
081: * Defaults to "80"
082: * <li><b>clientProtocol</b>: Protocol to specify within URLs that activate
083: * web application functionality. Defaults to "http".
084: * <li><b>clientPort</b>: Port to specify within URLs that that activate web
085: * application functionality. Defaults to "80".
086: * <li><b>jspContextPath</b>: The "request context path" to use when forming a URL
087: * that activates MAP JSP application functionality.
088: * Defaults to request.getContextPath().
089: * <li><b>jspLaunch</b>: The document path to use when forming a URL
090: * that activates MAP JSP application functionality.
091: * </ul>
092: *
093: * @version 1.0
094: * @see com.sun.ssoadapter.SSOAdapter
095: * @see com.sun.ssoadapter.SSOAdapterFactory
096: *
097: */
098:
099: public class CalendarExpressHelper extends ApplicationHelper implements
100: CalendarApplicationHelper {
101:
102: public CalendarProvider provider = null;
103: public SSOAdapter ssoAdapter = null;
104: public Properties adapterProperties = null;
105:
106: protected String appName = "";
107: protected String containerName = "";
108:
109: private CalExpress calendarExpressObj = null;
110: private long lastCheckTime = 0;
111: private long checkInterval;
112: protected String charset = null;
113:
114: // Create a logger for this class
115: private static Logger debugLogger = PortalLogger
116: .getLogger(CalendarExpressHelper.class);
117:
118: /**
119: * Initialize CalendarExpressHelper.
120: *
121: * @param provider CalendarProvider
122: * @param ssoAdapter SSOAdapter
123: */
124: public void init(CalendarProvider provider, SSOAdapter ssoAdapter)
125: throws Exception {
126: super .init((ProfileProviderAdapter) provider, ssoAdapter);
127: this .provider = provider;
128: this .ssoAdapter = ssoAdapter;
129:
130: if (ssoAdapter != null) {
131: this .adapterProperties = ssoAdapter.getProperties();
132: }
133:
134: this .checkInterval = Integer.parseInt(adapterProperties
135: .getProperty("checkInterval", "5000"));
136: // Added for URLEncoding
137: SSOToken token = ssoAdapter.getSSOToken();
138: charset = token.getProperty("CharSet");
139: debugLogger.log(Level.FINER, "PSCC_CSPPC0001", charset);
140: }
141:
142: /**
143: * Returns a client URL, if supported by the service.
144: *
145: * @param provider CalendarProvider
146: * @param ssoAdapter SSOAdapter
147: */
148: public String getStartURL(CalendarProvider provider,
149: HttpServletRequest request) {
150: String url = null;
151:
152: try {
153: url = getApplicationURL(provider, request);
154: ProviderContext pc = provider.getProviderContext();
155: url = pc.escape(url);
156: } catch (Exception e) {
157: debugLogger.log(Level.FINE, "PSCC_CSPPC0002", e);
158: }
159:
160: return url;
161: }
162:
163: /**
164: * Returns client aware URL for calendar application access
165: * to service associated with a particular instance
166: * of a CalendarExpressHelper.
167: *
168: * @param provider CalendarProvider
169: * @param request HttpServletRequest
170: */
171: public String getApplicationURL(CalendarProvider provider,
172: HttpServletRequest request) throws Exception {
173: String clientURL = null;
174: String clientProtocol = adapterProperties.getProperty(
175: "clientProtocol", "http");
176: String host = adapterProperties.getProperty("host");
177: String clientPort = adapterProperties.getProperty("clientPort",
178: adapterProperties.getProperty("port", "80"));
179: String baseURL = clientProtocol + "://" + host + ":"
180: + clientPort;
181: String domain = adapterProperties.getProperty("domain");
182:
183: // check for a valid user session. if the session is not valid, then only
184: // the baseURL is returned. this is applicable for the authless desktop
185: //
186: SSOToken tok = ssoAdapter.getSSOToken();
187:
188: if (tok != null) {
189: String puid = null;
190: String enableProxyAuth = adapterProperties.getProperty(
191: "enableProxyAuth", "false");
192:
193: // at this point we have a valid user session. if admin proxy authentication
194: // is enabled, then we need to retrieve the user naming attribute. this value
195: // represents the user's uid.
196: //
197: if (enableProxyAuth.equals("true")) {
198: AMStoreConnection amsc = null;
199: AMUser auser = null;
200: String usrAttr = adapterProperties.getProperty(
201: "userAttribute", "uid");
202:
203: try {
204: amsc = new AMStoreConnection(tok);
205: auser = amsc.getUser(tok.getPrincipal().getName());
206: puid = auser.getStringAttribute(usrAttr);
207: } catch (SSOException ssoe) {
208: debugLogger.log(Level.INFO, "PSCC_CSPPC0003", ssoe);
209: } catch (AMException ame) {
210: debugLogger.log(Level.INFO, "PSCC_CSPPC0003", ame);
211: }
212:
213: // check for hosted domain support
214: if (domain != null) {
215: puid = puid + "@" + domain;
216: }
217: }
218:
219: // retrieve the channel's 'calendar' property. this property specifies
220: // which calendar the user wants to view in the channel content.
221: //
222: // if it has not been set (calid == null), then
223: //
224: // if sso adapter 'enableProxyAuthentication' then calid = sso adapter 'userAttribute'
225: // else calid = sso adapter 'uid'
226: //
227: String calid = null;
228:
229: try {
230: calid = provider.getStringProperty("calendar");
231: } catch (ProviderException pe) {
232: calid = null;
233: }
234:
235: if ((calid == null) || (calid.length() == 0)) {
236:
237: if (enableProxyAuth.equals("true")) {
238: calid = puid;
239: } else {
240: calid = adapterProperties.getProperty("uid");
241:
242: // check for hosted domain support
243: if (domain != null) {
244: calid = calid + "@" + domain;
245: }
246: }
247: }
248:
249: calid = ProviderEditUtility.encode(calid, charset);
250:
251: // Check to see if SSO is enabled on the server. If so, do not use session id in
252: // any urls.
253: if (adapterProperties.getProperty("serverSSOEnabled", "")
254: .equals("true")) {
255: // In order to enable Calendar Express SSO, must access server root.
256: clientURL = baseURL;
257: } else {
258:
259: // Get the calendar session id for the calendar store. This is stored in SOCSSession
260: //
261: String eprc = adapterProperties.getProperty(
262: "enablePerRequestConnection", "false");
263: String sessionID = null;
264:
265: if (eprc.equals("true")) {
266: sessionID = getCESessionId(baseURL, tok, puid);
267: } else {
268: SOCSCalendarStore socsStore = (SOCSCalendarStore) ssoAdapter
269: .getConnection();
270: sessionID = socsStore.getSOCSSession().getID();
271: }
272:
273: String command = "/command.shtml?view=overview&id="
274: + sessionID + "&calid=" + calid;
275: clientURL = baseURL + command;
276: }
277: } else {
278: clientURL = baseURL;
279: }
280:
281: return clientURL;
282: }
283:
284: /**
285: * Returns client aware URL for event access
286: * to service associated with a particular instance
287: * of a PortalCalendarSSOHelper.
288: *
289: * @param provider CalendarProvider
290: * @param request HttpServletRequest
291: * @param event Calendar Event
292: */
293: public String getEventURL(CalendarProvider provider,
294: HttpServletRequest request, VEvent event) throws Exception {
295: return null;
296: }
297:
298: /**
299: * Returns client aware URL for task access
300: * to service associated with a particular instance
301: * of a PortalCalendarSSOHelper.
302: *
303: * @param provider CalendarProvider
304: * @param request HttpServletRequest
305: * @param task Calendar Task
306: */
307: public String getTaskURL(CalendarProvider provider,
308: HttpServletRequest request, VTodo task) throws Exception {
309: return null;
310: }
311:
312: /**
313: * Returns the contents of the CalendarProviders edit page
314: *
315: *@param cprov Description of the Parameter
316: *@param req Description of the Parameter
317: *@param res Description of the Parameter
318: *@return The appPrefsEdit value
319: */
320: public StringBuffer getAppPrefsEdit(CalendarProvider cprov,
321: HttpServletRequest req, HttpServletResponse res) {
322: setEditContainer(cprov.editContainer);
323: setContainerName(cprov.containerName);
324: setTargetProvider(cprov.targetProvider);
325: return super .getAppPrefsEdit((Provider) cprov, req, res);
326: }
327:
328: /**
329: * Processes values returned from the CalendarProvider edit page
330: *
331: *@param cprov Instance of Calendar Provider
332: *@param req servlet request
333: *@param res servlet response
334: */
335: public URL processAppPrefsEdit(CalendarProvider cprov,
336: HttpServletRequest request, HttpServletResponse response)
337: throws ProviderException {
338: setEditContainer(cprov.editContainer);
339: setContainerName(cprov.containerName);
340: setTargetProvider(cprov.targetProvider);
341: return super .processAppPrefsEdit((Provider) cprov, request,
342: response);
343: }
344:
345: /**
346: * Returns a HTML link containing encoding specific for the app helper
347: */
348:
349: public String getAppHelperEditLink(HttpServletRequest req,
350: ProviderContext pc) {
351:
352: Hashtable tagTable = new Hashtable();
353: StringBuffer link = new StringBuffer();
354: try {
355: link.append(pc.getDesktopURL(req));
356: } catch (Exception e) {
357: return "";
358: }
359: link.append("?action=edit&provider=");
360: link.append(ProviderEditUtility.getRequestParameter("provider",
361: req));
362: link.append("&targetprovider=" + provider.getName());
363: link.append("&containerName=");
364: link.append(ProviderEditUtility.getRequestParameter(
365: "containerName", req));
366: link.append("&appPref=" + this .getName());
367:
368: tagTable.put("editLink", link.toString());
369: String content = null;
370:
371: try {
372: String fontTag = pc.getStringProperty(provider.getName(),
373: "fontFace1", "Sans-serif");
374: tagTable.put("iwtDesktop-fontFace1", fontTag);
375: content = pc.getTemplate(provider.getName(),
376: "edit-link.template", tagTable).toString();
377: debugLogger.log(Level.FINER, "PSCC_CSPPC0004", content
378: .toString());
379: } catch (Exception e) {
380: debugLogger.log(Level.INFO, "PSCC_CSPPC0005", e);
381: content = "";
382: }
383:
384: debugLogger.log(Level.FINER, "PSCC_CSPPC0006", content
385: .toString());
386: return content;
387: }
388:
389: /**
390: * Authenticate the user to Calendar Express. Need to retrieve the
391: * session id, X-NSCP-WCAP-SESSION-ID, from the XML response.
392: *
393: * @param baseURL String - base clientURL - url of the calendar express
394: * @param token token
395: * @param puid proxy uid
396: * @return sid String - session id
397: **/
398: private String getCESessionId(String baseUrl, SSOToken token,
399: String puid) {
400:
401: // check for admin proxy authentication. if enabled and puid is null then
402: // there is a problem and we do not want to generate a valid URL, so return
403: // null
404: String enableProxyAuth = adapterProperties.getProperty(
405: "enableProxyAuth", "false");
406:
407: if ((enableProxyAuth.equals("true")) && (puid == null)) {
408: return null;
409: }
410:
411: String sid = null;
412: String user = adapterProperties.getProperty("uid");
413: String password = adapterProperties.getProperty("password");
414: boolean urlValid = false;
415:
416: if (enableProxyAuth.equals("true")) {
417: user = adapterProperties.getProperty("proxyAdminUid");
418: password = adapterProperties
419: .getProperty("proxyAdminPassword");
420: } else {
421: String domain = adapterProperties.getProperty("domain");
422:
423: if (domain != null) {
424: user = user + "@" + domain;
425: }
426: }
427:
428: CalExpress newCalExpressObj = new CalExpress(user, password,
429: baseUrl);
430:
431: //
432: // If the single sign on url is already populated, check if any of
433: // of the user configurations have changed, and check if the
434: // session has timed out .. if yes, try and connect again. If not
435: // return the single sign on url
436: //
437:
438: // Check against the Calendar Express URL
439: if ((calendarExpressObj != null)
440: && (calendarExpressObj.equals(newCalExpressObj))
441: && (isValidSession(calendarExpressObj))) {
442: urlValid = true;
443: newCalExpressObj = calendarExpressObj;
444: }
445:
446: // Otherwise, build the single sign on URL and generate WCAP login
447: //
448: if (!urlValid) {
449: String resource = baseUrl + "/login.wcap?" + "user="
450: + ProviderEditUtility.encode(user, charset)
451: + "&password="
452: + ProviderEditUtility.encode(password, charset)
453: + "&fmt-out=text/xml";
454:
455: if (puid != null) {
456: resource += "&proxyauth="
457: + ProviderEditUtility.encode(puid, charset);
458: debugLogger.log(Level.FINER, "PSCC_CSPPC0007",
459: new Object[] { user, puid });
460: } else {
461: debugLogger.log(Level.FINER, "PSCC_CSPPC0008", user);
462: }
463:
464: String startDelim = "<X-NSCP-WCAP-SESSION-ID>";
465: String endDelim = "</X-NSCP-WCAP-SESSION-ID>";
466: String line = null;
467: BufferedReader in = null;
468: URLConnection urlconn = null;
469: URL url = null;
470:
471: try {
472: url = new URL(resource);
473: urlconn = (URLConnection) url.openConnection();
474: urlconn.setDoInput(true);
475: urlconn.setDoOutput(true);
476: urlconn.setUseCaches(false);
477: in = new BufferedReader(new InputStreamReader(urlconn
478: .getInputStream()));
479:
480: while ((line = in.readLine()) != null) {
481: if (line.indexOf(startDelim) != -1) {
482: int start = line.indexOf(startDelim) + 24;
483: int end = line.indexOf(endDelim);
484: sid = line.substring(start, end);
485: break;
486: }
487: }
488:
489: in.close();
490: } catch (Exception e) {
491: debugLogger.log(Level.INFO, "PSCC_CSPPC0009", e);
492: return null;
493: }
494:
495: if (sid != null) {
496: newCalExpressObj.setSessionId(sid);
497: }
498: }
499:
500: calendarExpressObj = newCalExpressObj;
501:
502: return calendarExpressObj.getSessionId();
503: }
504:
505: /**
506: *
507: *
508: */
509: private boolean isValidSession(CalExpress calexp) {
510:
511: Date newCheckDate = new Date();
512: long newCheckTime = newCheckDate.getTime();
513: long timeSinceLastCheck = newCheckTime - lastCheckTime;
514:
515: if (timeSinceLastCheck < checkInterval) {
516: return true;
517: }
518:
519: lastCheckTime = newCheckTime;
520: String cesid = calexp.getSessionId();
521:
522: if (cesid == null) {
523: return false;
524: }
525:
526: String startDelim = "<X-NSCP-WCAP-CHECK-ID>";
527: String endDelim = "</X-NSCP-WCAP-CHECK-ID>";
528: String line = null;
529: String vid = null;
530: BufferedReader in = null;
531: URLConnection urlconn = null;
532: URL url = null;
533:
534: String resource = calexp.getBaseUri() + "/check_id.wcap?"
535: + "id=" + calexp.getSessionId() + "&fmt-out=text/xml";
536:
537: try {
538: url = new URL(resource);
539: urlconn = (URLConnection) url.openConnection();
540: urlconn.setDoInput(true);
541: urlconn.setDoOutput(true);
542: urlconn.setUseCaches(false);
543: in = new BufferedReader(new InputStreamReader(urlconn
544: .getInputStream()));
545:
546: while ((line = in.readLine()) != null) {
547: if (line.indexOf(startDelim) != -1) {
548: int start = line.indexOf(startDelim) + 22;
549: int end = line.indexOf(endDelim);
550: vid = line.substring(start, end);
551: break;
552: }
553: }
554:
555: in.close();
556: } catch (Exception e) {
557: debugLogger.log(Level.FINE, "PSCC_CSPPC0010", e);
558: return false;
559: }
560:
561: if ((vid != null) && (vid.equals("1"))) {
562: return true;
563: } else {
564: return false;
565: }
566:
567: }
568:
569: /*
570: * Inner Class. This class is responsible for storing Calendar Express
571: * server and credential information used for authentication.
572: *
573: */
574: private class CalExpress {
575: private String user = null;
576: private String pass = null;
577: private String baseUri = null;
578: private String sid = null;
579:
580: /*
581: * Constructor
582: */
583: CalExpress(String user, String pass, String baseUri) {
584: this .user = user;
585: this .pass = pass;
586:
587: // remove trailing '/'
588: if ((baseUri != null) && (!baseUri.equals(""))
589: && (baseUri.charAt(baseUri.length() - 1) == '/')) {
590: baseUri = baseUri.substring(0, baseUri.length() - 1);
591: }
592:
593: this .baseUri = baseUri;
594: }
595:
596: boolean equals(CalExpress ceUrl2Comp) {
597: // If any of the given arguments do not match the stored values,
598: // return false.
599: if ((!ceUrl2Comp.baseUri.equals(this .baseUri))
600: || (!ceUrl2Comp.user.equals(this .user))
601: || (!ceUrl2Comp.pass.equals(this .pass))) {
602: return false;
603: }
604: return true;
605: }
606:
607: String getBaseUri() {
608: return this .baseUri;
609: }
610:
611: String getSessionId() {
612: return this .sid;
613: }
614:
615: void setSessionId(String sid) {
616: this.sid = sid;
617: }
618: }
619:
620: }
|