001: /**
002: * $Id: MessengerExpressHelper.java,v 1.33 2005/09/21 10:48:09 dg154973 Exp $
003: * Copyright 2002 Sun Microsystems, Inc. All
004: * rights reserved. Use of this product is subject
005: * to license terms. Federal Acquisitions:
006: * Commercial Software -- Government Users
007: * Subject to Standard License Terms and
008: * Conditions.
009: *
010: * Sun, Sun Microsystems, the Sun logo, and iPlanet
011: * are trademarks or registered trademarks of Sun Microsystems,
012: * Inc. in the United States and other countries.
013: */package com.sun.portal.providers.mail;
014:
015: import java.io.BufferedReader;
016: import com.sun.portal.providers.context.Theme;
017: import java.io.InputStreamReader;
018: import java.io.IOException;
019: import java.io.UnsupportedEncodingException;
020: import java.net.HttpURLConnection;
021: import java.net.MalformedURLException;
022: import java.net.URL;
023: import java.net.URLEncoder;
024: import java.util.Date;
025: import java.util.Properties;
026: import java.util.Hashtable;
027: import java.util.Enumeration;
028: import java.util.List;
029: import java.util.Map;
030: import java.util.Map.Entry;
031: import java.util.ResourceBundle;
032: import java.util.Set;
033: import java.util.StringTokenizer;
034: import java.util.Iterator;
035: import java.util.logging.Logger;
036: import java.util.logging.Level;
037: import javax.mail.Folder;
038: import javax.mail.Message;
039: import javax.mail.UIDFolder;
040: import javax.servlet.http.HttpServletRequest;
041: import javax.servlet.http.HttpServletResponse;
042: import com.iplanet.am.sdk.AMException;
043: import com.iplanet.am.sdk.AMStoreConnection;
044: import com.iplanet.am.sdk.AMUser;
045: import com.iplanet.sso.*;
046: import com.iplanet.sso.SSOToken;
047: import com.iplanet.sso.SSOException;
048: import com.sun.ssoadapter.SSOAdapter;
049: import com.sun.ssoadapter.SSOAdapterException;
050: import com.sun.ssoadapter.SSOAdapterFactory;
051: import com.sun.portal.providers.context.ProviderContext;
052: import com.sun.portal.providers.context.ProviderContextException;
053: import com.sun.portal.providers.Provider;
054: import com.sun.portal.providers.ProfileProviderAdapter;
055: import com.sun.portal.providers.ApplicationHelper;
056: import com.sun.portal.providers.ProviderException;
057: import com.sun.portal.providers.ProviderEditUtility;
058: import com.sun.portal.providers.util.ProviderProperties;
059: import com.sun.portal.log.common.PortalLogger;
060:
061: /**
062: * This class implements the MailApplicationHelper <p>
063: *
064: * Specific features include:
065: * <ul>
066: * <li> Support for username/password style authentication.</li>
067: * <li> Ability to generate web application URLs for the following:
068: * <ul>
069: * <li> Messenger Express</li>
070: * </ul>
071: * </li>
072: * </ul>
073: * <p>
074: *
075: * At the present time, username/password is stored in the clear. <p>
076: *
077: * This SSOAdapter implementation consumes the following Configuration
078: * properties:
079: * <ul>
080: * <li> <b>protocol</b> : Required value. Must be either "imap" or "pop3".
081: *
082: * <li> <b>uid</b> : Required value. Username (uid) of imap user.
083: * <li> <b>password</b> : Required value. Password of imap user.
084: * <li> <b>host</b> : Required value. Name of host providing IMAP service.
085: *
086: * <li> <b>port</b> : Optional value. Port number of IMAP server. Defaults to
087: * "143" when protocol is "imap", and "110" when protocol is "pop3".
088: * <li> <b>smtpServer</b> : Optional value. Specifies name of outgoing mail
089: * server. Defaults to value of host property.
090: * <li> <b>clientProtocol</b> : Protocol to specify within URLs that activate
091: * web application functionality. Defaults to "http".
092: * <li> <b>clientPort</b> : Port to specify within URLs that that activate
093: * web application functionality. Defaults to "80".
094: * <li> <b>checkInterval</b> : Specifies, in milliseconds, the minimum
095: * interval between web application activity checks.
096: * </ul>
097: *
098: *
099: *@author John Saare
100: *@created April 3, 2003
101: *@version 1.0
102: *@see com.sun.ssoadapter.SSOAdapter
103: */
104:
105: public class MessengerExpressHelper extends ApplicationHelper implements
106: MailApplicationHelper {
107:
108: public MailProvider provider = null;
109:
110: /**
111: * Description of the Field
112: */
113: public SSOAdapter ssoAdapter = null;
114: /**
115: * Description of the Field
116: */
117: public Properties adapterProperties = null;
118: private MsgExpURL mailMsgExpURL = null;
119: private long lastCheckTime = 0;
120: private long checkInterval;
121: protected String appName = "";
122: protected String containerName = "";
123: public String charset = null;
124:
125: // Create a logger for this class
126: private static Logger debugLogger = PortalLogger
127: .getLogger(MessengerExpressHelper.class);
128:
129: /**
130: * Initialize MessengerExpressHelper.
131: *
132: *@param ssoAdapter SSOAdapter object
133: */
134: public void init(MailProvider provider, SSOAdapter ssoAdapter)
135: throws Exception {
136: super .init((ProfileProviderAdapter) provider, ssoAdapter);
137: debugLogger.finer("PSMC_CSPPM0040");
138: this .provider = provider;
139: this .ssoAdapter = ssoAdapter;
140:
141: if (ssoAdapter != null) {
142: this .adapterProperties = ssoAdapter.getProperties();
143: }
144:
145: this .checkInterval = Integer.parseInt(adapterProperties
146: .getProperty("checkInterval", "5000"));
147: SSOToken token = ssoAdapter.getSSOToken();
148: charset = token.getProperty("CharSet");
149: debugLogger.log(Level.FINER, "PSMC_CSPPM0041", charset);
150: }
151:
152: /**
153: * Returns a client URL, if supported by the service.
154: *
155: * @param provider MailProvider
156: * @param ssoAdapter SSOAdapter
157: */
158: public String getStartURL(MailProvider provider,
159: HttpServletRequest request) {
160: debugLogger.finer("PSMC_CSPPM0040");
161: String url = null;
162: try {
163: url = getApplicationURL(provider, request);
164: ProviderContext pc = provider.getProviderContext();
165: url = pc.escape(url);
166: } catch (Exception e) {
167: debugLogger.log(Level.FINE, "PSMC_CSPPM0001", e);
168: }
169: return url;
170: }
171:
172: /**
173: * Returns client aware URL for mail application access
174: * to service associated with a particular instance
175: * of a MessengerExpressHelper.
176: *
177: * @param provider MailProvider
178: * @param request HttpServletRequest
179: */
180: public String getApplicationURL(MailProvider provider,
181: HttpServletRequest request) throws Exception {
182: debugLogger.finer("PSMC_CSPPM0040");
183: // construct base url to messaging server
184: ProviderContext pc = provider.getProviderContext();
185: String clientURL = null;
186: String clientProtocol = adapterProperties.getProperty(
187: "clientProtocol", "http");
188: String clientPort = adapterProperties.getProperty("clientPort",
189: adapterProperties.getProperty("port", "80"));
190: String host = adapterProperties.getProperty("host");
191: String baseURL = clientProtocol + "://" + host + ":"
192: + clientPort;
193:
194: // check for valid session, if not valid then return base url
195: SSOToken tok = ssoAdapter.getSSOToken();
196:
197: if (tok != null) {
198: // Check to see if SSO is enabled on the server. If so, do not use session id in
199: // any urls.
200: if (adapterProperties.getProperty("serverSSOEnabled", "")
201: .equals("true")) {
202: // In order to enable Messenger Express SSO, must access web server root.
203: clientURL = baseURL;
204: } else {
205: String enableProxyAuth = adapterProperties
206: .getProperty("enableProxyAuth");
207: String uid = null;
208: String password = null;
209: String domain = null;
210: if ((enableProxyAuth != null)
211: && (enableProxyAuth.equals("true"))) {
212: uid = adapterProperties
213: .getProperty("proxyAdminUid");
214: password = adapterProperties
215: .getProperty("proxyAdminPassword");
216: domain = adapterProperties.getProperty("domain");
217: } else {
218: uid = adapterProperties.getProperty("uid");
219: password = adapterProperties
220: .getProperty("password");
221: domain = adapterProperties.getProperty("domain");
222: }
223:
224: if (debugLogger.isLoggable(Level.FINER)) {
225: if (uid != null)
226: debugLogger.log(Level.FINER, "PSMC_CSPPM0042",
227: uid);
228: if (domain != null)
229: debugLogger.log(Level.FINER, "PSMC_CSPPM0043",
230: domain);
231: if (baseURL != null)
232: debugLogger.log(Level.FINER, "PSMC_CSPPM0044",
233: baseURL);
234: }
235:
236: clientURL = getWebmailURL(uid, password, domain,
237: baseURL);
238: }
239: } else {
240: clientURL = baseURL;
241: }
242:
243: return clientURL;
244: }
245:
246: /**
247: * Authenticate the user to Webmail / Messenger Express. If the return
248: * cookie contains 'sid' then the user is considered authenticated
249: *
250: * @param user String - user name
251: * @param pass String - user password
252: * @param baseURL String - base clientURL - url of the messenger express
253: * @return sso_uri String - single sign on URL to the messenger express
254: **/
255: private String getWebmailURL(String user, String pass,
256: String domain, String baseUrl) {
257: debugLogger.finer("PSMC_CSPPM0040");
258: if ((baseUrl != null) && (!baseUrl.equals(""))
259: && (baseUrl.charAt(baseUrl.length() - 1) == '/')) {
260: baseUrl = baseUrl.substring(0, baseUrl.length() - 1);
261: }
262:
263: MsgExpURL newMEUrl = new MsgExpURL(user, pass, baseUrl);
264: boolean urlValid = false;
265:
266: // If the single sign on url is already populated, check if any of
267: // of the user configurations have changed, and check if the
268: // session has timed out .. if yes, try and connect again.If not
269: // return the single sign on url
270:
271: // Check against the mail ME url
272: if ((mailMsgExpURL != null) && (mailMsgExpURL.equals(newMEUrl))
273: && (isValidSession(mailMsgExpURL))) {
274: urlValid = true;
275: newMEUrl = mailMsgExpURL;
276:
277: debugLogger.finer("PSMC_CSPPM0045");
278: }
279:
280: if (!urlValid) {
281: // Otherwise, build the single sign on URL
282: // Build WMAP protocol's Login command
283:
284: String enableProxyAuth = adapterProperties
285: .getProperty("enableProxyAuth");
286: String urlstr = null;
287:
288: if ((enableProxyAuth != null)
289: && (enableProxyAuth.equals("true"))) {
290: SSOToken tok = null;
291: urlstr = baseUrl + "/login.msc?user="
292: + ProviderEditUtility.encode(user, charset)
293: + "&password="
294: + ProviderEditUtility.encode(pass, charset);
295:
296: try {
297: tok = ssoAdapter.getSSOToken();
298: } catch (SSOAdapterException ssoae) {
299: tok = null;
300: }
301:
302: if (tok != null) {
303: AMStoreConnection amsc = null;
304: AMUser auser = null;
305: String puid = null;
306: String usrAttr = adapterProperties.getProperty(
307: "userAttribute", "uid");
308:
309: try {
310: amsc = new AMStoreConnection(tok);
311: auser = amsc.getUser(tok.getPrincipal()
312: .getName());
313: puid = auser.getStringAttribute(usrAttr);
314: } catch (SSOException ssoe) {
315: debugLogger.log(Level.INFO, "PSMC_CSPPM0046",
316: ssoe);
317: } catch (AMException ame) {
318: debugLogger.log(Level.INFO, "PSMC_CSPPM0046",
319: ame);
320: }
321:
322: if ((puid != null) && (puid.length() > 0)) {
323: if (domain != null) {
324: puid = puid + "@" + domain;
325: }
326: urlstr += "&proxyauth="
327: + ProviderEditUtility.encode(puid,
328: charset);
329: }
330: }
331: } else {
332: if ((domain != null) && (!domain.equals(""))) {
333: String fqUser = user + "@" + domain;
334: urlstr = baseUrl
335: + "/login.msc?user="
336: + ProviderEditUtility.encode(fqUser,
337: charset) + "&password="
338: + ProviderEditUtility.encode(pass, charset);
339:
340: } else {
341: urlstr = baseUrl + "/login.msc?user="
342: + ProviderEditUtility.encode(user, charset)
343: + "&password="
344: + ProviderEditUtility.encode(pass, charset);
345: debugLogger.finer("PSMC_CSPPM0047");
346: }
347: }
348:
349: debugLogger.log(Level.FINER, "PSMC_CSPPM0048", urlstr);
350: String authUrl = getRelativeSsoUrl(urlstr, newMEUrl);
351: debugLogger.log(Level.FINER, "PSMC_CSPPM0049", authUrl);
352:
353: if (authUrl != null) {
354: newMEUrl.setSsoUri(baseUrl + authUrl + "&view=portal");
355: } else {
356: newMEUrl = null;
357: debugLogger.finer("PSMC_CSPPM0050");
358: return null;
359: }
360: }
361:
362: mailMsgExpURL = newMEUrl;
363: String mailSessId = null;
364: if (newMEUrl != null) {
365: mailSessId = newMEUrl.getWebmailSessionId();
366: }
367: if (mailSessId == null) {
368: mailSessId = "";
369: }
370: if (newMEUrl != null) {
371: return newMEUrl.getSsoUri();
372: } else {
373: return baseUrl;
374: }
375: }
376:
377: /**
378: * Checks whether the current this.webmailSessionId for Messenger Express has
379: * timed out. This is done by checking if the page returned by sending a Get
380: * Mail WMAP command to messenger express contains string
381: * "parent.timeoutCB()". If yes, then the webmailSessionId has timed out.
382: *
383: *@param meURL Description of the Parameter
384: *@return boolean
385: */
386: private boolean isValidSession(MsgExpURL meURL) {
387: debugLogger.finer("PSMC_CSPPM0040");
388: Date newCheckDate = new Date();
389: long newCheckTime = newCheckDate.getTime();
390: long timeSinceLastCheck = newCheckTime - lastCheckTime;
391:
392: if (timeSinceLastCheck < checkInterval) {
393: return true;
394: }
395:
396: lastCheckTime = newCheckTime;
397:
398: String webmailSessionId = meURL.getWebmailSessionId();
399: if (webmailSessionId == null) {
400: debugLogger.finer("PSMC_CSPPM0051");
401: return false;
402: }
403: String pageContent = "";
404:
405: // Build the WMAP protocol's Get Mail command
406: // Get 0 messages (count=0) to reduce the traffic
407: String urlstr = meURL.baseUri
408: + "/mbox.msc?sid="
409: + webmailSessionId
410: + "&security=false&mbox=INBOX&start=0&count=20&date=false";
411:
412: HttpURLConnection urlconn = null;
413: try {
414: URL url = new URL(urlstr);
415: urlconn = (HttpURLConnection) url.openConnection();
416: urlconn.setInstanceFollowRedirects(false);
417: } catch (IOException ioe) {
418: debugLogger.log(Level.INFO, "PSMC_CSPPM0052", ioe);
419: pageContent = null;
420: meURL.setWebmailSessionId(null);
421: return false;
422: }
423: try {
424: BufferedReader in = new BufferedReader(
425: new InputStreamReader(urlconn.getInputStream()));
426: String inputLine = null;
427:
428: // Getting the content of the page
429: while ((inputLine = in.readLine()) != null) {
430: pageContent += inputLine;
431: }
432: in.close();
433: } catch (Exception e) {
434: debugLogger.log(Level.INFO, "PSMC_CSPPM0031", e);
435: e.printStackTrace();
436: pageContent = null;
437: meURL.setWebmailSessionId(null);
438: return false;
439: }
440: // Check if the page contents contain string "parent.timeoutCB()"
441: // If yes, then the webmailSessionId has timed out
442: if ((pageContent.indexOf("parent.timeoutCB()")) > 0) {
443: debugLogger.finer("PSMC_CSPPM0054");
444: pageContent = null;
445: meURL.setWebmailSessionId(null);
446: return false;
447: }
448: debugLogger.finer("PSMC_CSPPM0055");
449: return true;
450: }
451:
452: /**
453: * Given the login URL with the user name and password filled in, this method
454: * returns a single sign on url with a valid session ID. To generate such a
455: * URL, an WMAP login command is sent to the Messenger Express and if the
456: * response contains a cookie with a 'sid' parameter, then the URL is
457: * generated.
458: *
459: *@param urlstr WMAP Login command Url with user name and password
460: *@param meURL Description of the Parameter
461: *@return String Single Sign On URL
462: */
463: private String getRelativeSsoUrl(String urlstr, MsgExpURL meURL) {
464: debugLogger.finer("PSMC_CSPPM0040");
465: String authUrl = null;
466: HttpURLConnection urlconn = null;
467: try {
468: URL url = new URL(urlstr);
469: urlconn = (HttpURLConnection) url.openConnection();
470: urlconn.setInstanceFollowRedirects(false);
471:
472: } catch (MalformedURLException mfe) {
473: debugLogger.log(Level.INFO, "PSMC_CSPPM0056", meURL
474: .getBaseUri());
475: return null;
476: } catch (IOException ioe) {
477: debugLogger.log(Level.INFO, "PSMC_CSPPM0052", ioe);
478: return null;
479: }
480: String key;
481:
482: // Check if the headers of the response contain a Location field with
483: // parameter 'sid' set.
484: String location = urlconn.getHeaderField("Location");
485:
486: if (location != null) {
487: int sessionIdBegin = 0;
488: if ((sessionIdBegin = location.indexOf("sid")) < 0) {
489: // cannot authenticate to the Messenger Express
490: debugLogger.finer("PSMC_CSPPM0057");
491: meURL.setWebmailSessionId(null);
492: authUrl = null;
493: } else {
494: String inter = location.substring(sessionIdBegin + 4);
495: int sessionIdEnd = inter.indexOf("&");
496: String mailSessionId = inter.substring(0, sessionIdEnd);
497: meURL.setWebmailSessionId(mailSessionId);
498: if (location.charAt(0) != '/') {
499: authUrl = "/" + location;
500: } else {
501: authUrl = location;
502: }
503: }
504: }
505: return authUrl;
506: }
507:
508: /**
509: * Returns the contents of the MailProviders edit page
510: *
511: *@param mprov Description of the Parameter
512: *@param req Description of the Parameter
513: *@param res Description of the Parameter
514: *@return The appPrefsEdit value
515: */
516: public StringBuffer getAppPrefsEdit(MailProvider mprov,
517: HttpServletRequest req, HttpServletResponse res) {
518: setEditContainer(mprov.editContainer);
519: setContainerName(mprov.containerName);
520: setTargetProvider(mprov.targetProvider);
521: return super .getAppPrefsEdit((Provider) mprov, req, res);
522: }
523:
524: /**
525: * Processes values returned from the MailProvider edit page
526: *
527: *@param mprov Instance of Mail Provider
528: *@param req servlet request
529: *@param res servlet response
530: */
531: public URL processAppPrefsEdit(MailProvider mprov,
532: HttpServletRequest request, HttpServletResponse response)
533: throws ProviderException {
534: setEditContainer(mprov.editContainer);
535: setContainerName(mprov.containerName);
536: setTargetProvider(mprov.targetProvider);
537: return super .processAppPrefsEdit((Provider) mprov, request,
538: response);
539: }
540:
541: /**
542: * Returns client aware URL for message access
543: * to service associated with a particular instance
544: * of a PortalMailSSOHelper.
545: */
546: public String getMessageURL(MailProvider provider,
547: HttpServletRequest request, Message message)
548: throws Exception {
549: debugLogger.finer("PSMC_CSPPM0040");
550: String messageURL = null;
551: StringBuffer urlBuffer = new StringBuffer(getApplicationURL(
552: provider, request));
553: Folder folder = message.getFolder();
554:
555: if (adapterProperties.getProperty("serverSSOEnabled", "")
556: .equals("true")) {
557: // In order to enable Messenger Express SSO, must access
558: // proper message using format server/?argv=mbox=BOX&argv=msg=n
559: //
560: // The application url when server SSO is enabled is always
561: // proto://server:port
562: urlBuffer.append("/?argv=mbox=");
563: urlBuffer.append(ProviderEditUtility.encode(message
564: .getFolder().getFullName(), charset));
565: urlBuffer.append("&argv=msg=");
566: urlBuffer.append(((UIDFolder) folder).getUID(message));
567: } else {
568: urlBuffer.append("&mbox=");
569: urlBuffer.append(ProviderEditUtility.encode(message
570: .getFolder().getFullName(), charset));
571: urlBuffer.append("&msg=");
572: urlBuffer.append(((UIDFolder) folder).getUID(message));
573: }
574: messageURL = urlBuffer.toString();
575: debugLogger.log(Level.FINER, "PSMC_CSPPM0053", messageURL);
576: return messageURL;
577: }
578:
579: /**
580: * This is an inner class.
581: * Used to Store the credentials and server for the WebMail/Messenger
582: * Express authentication
583: *
584: */
585:
586: private class MsgExpURL {
587: private String user = null;
588: private String pass = null;
589: private String baseUri = null;
590: // Result
591: private String webmailSessionId = null;
592: private String sso_uri = null;
593:
594: /*
595: * Constructor
596: */
597: MsgExpURL(String user, String pass, String baseUri) {
598: this .user = user;
599: this .pass = pass;
600: this .baseUri = baseUri;
601: }
602:
603: boolean equals(MsgExpURL meUrl2Comp) {
604: // If any of the given arguments do not match the stored values,
605: // return false.
606: if ((!meUrl2Comp.baseUri.equals(this .baseUri))
607: || (!meUrl2Comp.user.equals(this .user))
608: || (!meUrl2Comp.pass.equals(this .pass))) {
609: return false;
610: }
611: return true;
612: }
613:
614: String getBaseUri() {
615: return this .baseUri;
616: }
617:
618: String getSsoUri() {
619: return this .sso_uri;
620: }
621:
622: void setSsoUri(String sso_uri) {
623: this .sso_uri = sso_uri;
624: }
625:
626: String getWebmailSessionId() {
627: return this .webmailSessionId;
628: }
629:
630: void setWebmailSessionId(String webmailSessionId) {
631: this .webmailSessionId = webmailSessionId;
632: }
633:
634: void release() {
635: user = null;
636: pass = null;
637: baseUri = null;
638: sso_uri = null;
639: webmailSessionId = null;
640: }
641:
642: }
643:
644: /**
645: * Returns a HTML link containing encoding specific for the app helper
646: */
647:
648: public String getAppHelperEditLink(HttpServletRequest req,
649: ProviderContext pc) {
650: debugLogger.finer("PSMC_CSPPM0040");
651: Hashtable tagTable = new Hashtable();
652: StringBuffer link = new StringBuffer();
653: try {
654: link.append(pc.getDesktopURL(req));
655: } catch (Exception e) {
656: return "";
657: }
658: link.append("?action=edit&provider=");
659: link.append(ProviderEditUtility.getRequestParameter("provider",
660: req));
661: link.append("&targetprovider=" + provider.getName());
662: link.append("&containerName=");
663: link.append(ProviderEditUtility.getRequestParameter(
664: "containerName", req));
665: link.append("&appPref=" + this .getName());
666:
667: tagTable.put("editLink", link.toString());
668: String content = null;
669:
670: try {
671: String fontTag = pc.getStringProperty(provider.getName(),
672: "fontFace1", "Sans-serif");
673: tagTable.put("iwtDesktop-fontFace1", fontTag);
674: ProviderEditUtility
675: .setDefaultPresentation(provider.getName(),
676: provider.getProviderContext(), tagTable);
677: content = pc.getTemplate(provider.getName(),
678: "edit-link.template", tagTable).toString();
679: debugLogger.log(Level.FINER, "PSMC_CSPPM0002", content
680: .toString());
681: } catch (Exception e) {
682: debugLogger.log(Level.INFO, "PSMC_CSPPM0003", e);
683: content = "";
684: }
685:
686: debugLogger.log(Level.FINER, "PSMC_CSPPM0004", content
687: .toString());
688:
689: return content;
690: }
691: }
|