001: // @(#)ESession.java 1.14 "@(#)ESession.java 1.14 99/10/11 Sun Microsystems"
002: /*
003: * Netlet worker thread.
004: *
005: * Functionality :
006: * 1. Reads the session ID of the user and the dynamic algorithm that that is currently
007: * being used for that particular rule
008: * 2. Validates the Session of the user using DSAME APi's and obtains the Netlet User
009: * Profile of that user.
010: * 3. Reads the Session Key of the user from the Session API. Session Key is generated for
011: * each user by the Netlet Config Servlet.
012: * 4. Creates Dyanamic algorithm based on the user's cipher choice and the session key of the
013: * user
014: * 5. Extends the Session timer based on Netlet activity using NetletGroup and NetletGroupManager
015: * 6. Forwards request to Netlet Proxy in case Netlet Proxy is enabled
016: * 7. Instance of this class also gets bundled with Netlet Proxy and all the fore mentioned functionalities
017: * gets moved on to NetletProxy in case its enabled.
018: *
019: * @modified Rajesh T
020: *
021: *
022: * Export Restriction Comment :
023: * Refers to removal of pluggable algorithmn support from Netlet Crypto Provider
024: *
025: * @ see com.sun.portal.netlet.eproxy.NetletGroupManger
026: * @ see com.sun.portal.netlet.eproxy.NetletGroup
027: * @ see com.sun.portal.netlet.ciph.crypt.CipherGroup
028: * @ see com.sun.portal.netlet.eproxy.SessionKey - To be moved to - com.sun.portal.netlet.crypt.keymanagement.*
029: */
030:
031: package com.sun.portal.netlet.eproxy;
032:
033: import java.io.DataInputStream;
034: import java.io.IOException;
035: import java.net.MalformedURLException;
036: import java.net.Socket;
037: import java.net.URL;
038: import java.util.Hashtable;
039: import java.util.List;
040: import java.util.StringTokenizer;
041: import java.util.logging.Level;
042: import java.util.logging.Logger;
043:
044: import org.mozilla.jss.ssl.SSLSocket;
045:
046: import com.iplanet.sso.SSOException;
047: import com.iplanet.sso.SSOToken;
048: import com.iplanet.sso.SSOTokenManager;
049: import com.sun.portal.cli.cert.JSSUtil;
050: import com.sun.portal.log.common.PortalLogger;
051: import com.sun.portal.netlet.econnection.KeyConstants;
052: import com.sun.portal.netlet.econnection.ProxyCipherMsg;
053: import com.sun.portal.netlet.econnection.GWRunnable;
054: import com.sun.portal.rproxy.configservlet.client.GatewayProfile;
055: import com.sun.portal.rproxy.configservlet.client.GetResponseException;
056: import com.sun.portal.rproxy.configservlet.client.NetletProfile;
057: import com.sun.portal.rproxy.configservlet.client.SendRequestException;
058: import com.sun.portal.rproxy.monitoring.MonitoringSubsystem;
059: import com.sun.portal.util.GWLocale;
060: import com.sun.portal.util.GWLogManager;
061: import com.sun.portal.util.ServiceIdentifier;
062: import com.sun.portal.util.SRAEvent;
063:
064: public class ESession implements KeyConstants, GWRunnable {
065:
066: // should make sessId another object type...
067: protected SessionRequest sessReq = null;
068:
069: // protected SessionKey sKey;
070: protected NetletProfile userProfile;
071:
072: // protected String defaultLoopbackPort = "8000";
073: // protected static String serverName =
074: // SystemProperties.get("portal.server.host");
075: // protected static String serverPort =
076: // SystemProperties.get("portal.server.port");
077:
078: protected ProxyCipherMsg pMsg;
079:
080: protected RWGroupCrypt rwg = null;
081:
082: protected RWGroupForward rwgf = null;
083:
084: protected RWGroupFtp rwgcf = null;
085:
086: protected Socket fromSock;
087:
088: protected DataInputStream fromClient;
089:
090: protected Integer logId;
091:
092: protected SessionAuthenticator sessionAuth;
093:
094: protected static boolean useNetletProxy = false;
095:
096: protected String netletProxyHost = null;
097:
098: // protected static final int DEFAULT_NETLET_PROXY_PORT = 10555;
099: protected int netletProxyPort = 10555;
100:
101: // protected Hashtable userAlgoChoice = new Hashtable();
102: protected Hashtable cipherList = new Hashtable();
103:
104: // protected Hashtable customAlgorithms = new Hashtable();
105: public static final String NETLET_PROXY = "__sra_netlet_proxy__";
106:
107: private boolean validatePDC = false;
108:
109: private String digest = null;
110:
111: private static Logger logger = PortalLogger
112: .getLogger(ESession.class);
113:
114: static {
115: useNetletProxy = GatewayProfile.getBoolean("UseNetletProxy",
116: false)
117: && ServiceIdentifier.isGateway();
118: }
119:
120: public ESession(Socket s, Integer _logId) {
121:
122: try {
123: fromClient = new DataInputStream(s.getInputStream());
124: } catch (IOException e) {
125: // logger.log(Level.SEVERE, "ESession: Unable to create
126: // DataInputStream -> ", e);
127: logger.log(Level.SEVERE, "PSSRNTLT_CSPNEPROX018");
128: return;
129: }
130:
131: logId = _logId;
132: fromSock = s;
133: sessionAuth = new SessionAuthenticator();
134: }
135:
136: public void run() {
137: String logmsg;
138: SSOToken ssoToken = null;
139:
140: /*
141: * If PDC is enabled, read and check the client certificate
142: */
143: if (!readClientCertificate()) {
144: cleanUp();
145: // logger.info("Unable to read Client Certificate: Closing Netlet
146: // Connections");
147: logger.info("PSSRNTLT_CSPNEPROX019");
148:
149: return;
150: }
151:
152: /*
153: * If unable to read session id - clean and return
154: */
155:
156: if (readSessionId() != 0) {
157: cleanUp();
158: return;
159: }
160:
161: /*
162: * If invalid session id - clean and return
163: */
164:
165: // need to check session id here...
166: if (sessionAuth.authenticate(sessReq) != 0) {
167: // logger.severe("ESession: invalid session id");
168: logger.severe("PSSRNTLT_CSPNEPROX020");
169: cleanUp();
170: return;
171: }
172:
173: try {
174:
175: /*
176: * Get the Netlet Session Key of the user stored in the DSAME
177: * Session Server - Netlet Key generated by the Netlet Config
178: * servlet and stored in DSAME session for distribution to all GW's
179: * Netlet Proxies and Netlet Applet
180: */
181:
182: SSOTokenManager ssoTokenManager = SSOTokenManager
183: .getInstance();
184: ssoToken = ssoTokenManager.createSSOToken(sessReq
185: .getSessionID());
186: /*
187: * refresh of Session needed to invalidate the DSAME SDK SSOToken
188: * local cache in the GW - Read the session key only after refresh
189: */
190:
191: ssoTokenManager.refreshSession(ssoToken);
192: // String dynSessionKey =
193: // ssoToken.getProperty("_sessionKey").toString();
194: // sKey = new SessionKey(dynSessionKey);
195:
196: /*
197: *
198: */
199:
200: if (validatePDC) {
201: if (!verifyClientCertificate(ssoToken)) {
202: cleanUp();
203: // logger.info("Unable to verify Client Certificate: Closing
204: // Netlet Connections");
205: logger.info("PSSRNTLT_CSPNEPROX021");
206: return;
207: }
208: }
209:
210: /*
211: * Read the profile of the user to find key lengths for the
212: * algorithms he is using Comment this piece if pref - proved to be
213: * costly
214: */
215:
216: userProfile = new NetletProfile(ssoToken.getTokenID()
217: .toString());
218:
219: /*
220: * Read the Key Size specification for this user Key size
221: * specification is of the form AlgoName|Key-length
222: *
223: * Eg : RC4|128 - RC4 uses 128 bits key
224: */
225:
226: List algoEnum = userProfile.getStringList("Ciphers");
227: StringBuffer algoList = new StringBuffer();
228:
229: /*
230: * construct a single string buffer out of the string-list and
231: * tokenize it - Better than 'n' number of String tokenizers
232: */
233:
234: for (int x = 0; x < algoEnum.size(); x++)
235: algoList.append((String) (algoEnum.get(x))).append("|");
236:
237: StringTokenizer algoSplitter = new StringTokenizer(algoList
238: .toString(), "|");
239:
240: while (algoSplitter.hasMoreElements())
241: cipherList.put(algoSplitter.nextToken(), algoSplitter
242: .nextToken());
243:
244: // /Export Restriction Comment
245: /*
246: * algoEnum=userProfile.getStringList("pluggedin-algorithms"); //
247: * logger.info("pluggedin-algorithms -> " + algoEnum); Object[]
248: * params4 = { algoEnum}; logger.log( Level.INFO ,
249: * "PSSRNTLT_CSPNEPROX022" , params4 );
250: *
251: * algoList = new StringBuffer(); //algoList.setLength(0);
252: *
253: * for(int x=0; x < algoEnum.size(); x ++)
254: * algoList.append((String)(algoEnum.get(x))).append("|");
255: *
256: * algoSplitter = new StringTokenizer(algoList.toString(),"|");
257: *
258: * while(algoSplitter.hasMoreElements()){
259: * NetletCrypto.addCipher(algoSplitter.nextToken(),algoSplitter.nextToken());
260: * algoSplitter.nextToken(); }
261: *
262: * //// algoEnum=userProfile.getStringList("UserCipher");
263: * //algoList.setLength(0); algoList = new StringBuffer();
264: *
265: * for(int x=0; x < algoEnum.size(); x ++)
266: * algoList.append((String)(algoEnum.get(x))).append("|");
267: *
268: * algoSplitter = new StringTokenizer(algoList.toString(),"|");
269: * while(algoSplitter.hasMoreElements())
270: * userAlgoChoice.put(algoSplitter.nextToken(),algoSplitter.nextToken());
271: */
272: } catch (SSOException se) {
273: // logger.severe("ESession: Unable to create CipherGroup -> " + se);
274: logger.log(Level.SEVERE, "PSSRNTLT_CSPNEPROX023", se);
275: } catch (GetResponseException gre) {
276: // logger.severe("ESession: Unable to create CipherGroup -> " +
277: // gre);
278: logger.log(Level.SEVERE, "PSSRNTLT_CSPNEPROX024", gre);
279: } catch (SendRequestException sre) {
280: // logger.severe("ESession: Unable to create CipherGroup -> " +
281: // sre);
282: logger.log(Level.SEVERE, "PSSRNTLT_CSPNEPROX025", sre);
283: }
284:
285: /*
286: * If netlet proxy enabled forward it to netlet proxy else process the
287: * request.
288: */
289:
290: if (useNetletProxy) {
291: String sessionId = sessReq.getSessionID();
292: /*
293: * netletProxyHost = (new SessionID(sessionId)).getSessionServer();
294: */
295: // String defaultNetletProxyHost =
296: // SystemProperties.get("portal.server.host");
297: /*
298: * Maintaining stickiness to a single NetletProxy (NLP). Session
299: * stickiness is a absolute must for netlet proxies as dynamic
300: * protocols like ftp may be in active mode and require command and
301: * data channel routed to the same NLP - Rajesh T
302: */
303:
304: // netletProxyHost = GatewayProfile.getString("NetletProxyHost",
305: // defaultNetletProxyHost);
306: try {
307: netletProxyHost = getAssociatedNetletProxy(ssoToken);
308: } catch (SSOException soe) {
309: soe.printStackTrace();
310: // logger.severe("Invalid SSOToken while looking op NLP -> " +
311: // soe);
312: logger.log(Level.SEVERE, "PSSRNTLT_CSPNEPROX026", soe);
313: return;
314: }
315:
316: URL nlp_url = null;
317: try {
318: nlp_url = new URL(netletProxyHost);
319: } catch (MalformedURLException me) {
320: me.printStackTrace();
321: }
322: netletProxyHost = nlp_url.getHost();
323: int nlp_Port = nlp_url.getPort();
324: if (!(nlp_Port == -1)) {
325: netletProxyPort = nlp_Port;
326: }
327: nlp_url = null;
328:
329: // logger.info("ESession: Netlet proxy host -> " +
330: Object[] param = { netletProxyHost, netletProxyPort + "" };
331:
332: // logger.info("ESession: Netlet proxy host -> " + netletProxyHost +
333: // " port -> " + netletProxyPort);
334: logger.log(Level.INFO, "PSSRNTLT_CSPNEPROX027");
335: rwgf = new RWGroupForward(fromSock, netletProxyHost,
336: netletProxyPort, sessionId);
337:
338: try {
339: NetletGroupManager.getNetletGroupManager()
340: .registerReaderWriter(rwgf, sessionId);
341: } catch (SSOException se) {
342: try {
343: NetletGroupManager.getNetletGroupManager()
344: .unregister(sessionId);
345: } catch (Exception e) {
346: // logger.severe("ESession: Unable to register/unregister
347: // with NetletGroupManager");
348: logger.severe("PSSRNTLT_CSPNEPROX028");
349: }
350: }
351: logmsg = GWLocale.getPFString("es1", new Object[] { logId,
352: new String(GWLogManager.getUserId(sessionId)),
353: netletProxyHost, new Integer(netletProxyPort) });
354: if (GWLogManager.loggingEnabled)
355: GWLogManager.write("netlet", logmsg);
356:
357: } else {
358:
359: /*
360: * Check for Access Control violations
361: */
362:
363: NetletAccessController netletAccessCheck = new NetletAccessController(
364: userProfile);
365:
366: /*
367: * Process netlet request either at the GW or at the Netlet proxy
368: * depending on whether netlet proxy is enabled or not.
369: */
370: // didn't use to encrypt proxy conf info...so hack it in
371: try {
372: pMsg = new ProxyCipherMsg();
373: } catch (Throwable t) {
374: t.printStackTrace();
375: }
376:
377: if (pMsg.readMsg(fromClient) == 0) {
378:
379: // if in map file, don't need to use
380: // netlet sent config
381: // logger.info("ESession: srcPort -> " + pMsg.getSrcPort());
382: Object[] params11 = { pMsg.getSrcPort() + "" };
383: logger.log(Level.INFO, "PSSRNTLT_CSPNEPROX029",
384: params11);
385: Redirect rd = new Redirect(pMsg.getSrcPort(), sessReq);
386: if (rd.doRedirect()) {
387: // logger.info("ESession: redirect to -> " +
388: // rd.getDstPortList() + " " + rd.getDstHost());
389: Object[] params12 = { rd.getDstPortList(), " ",
390: rd.getDstHost() };
391: logger.log(Level.INFO, "PSSRNTLT_CSPNEPROX030",
392: params12);
393: logmsg = GWLocale.getPFString("es2", new Object[] {
394: logId,
395: new String(GWLogManager.getUserId(sessReq
396: .getSessionID())), rd.getDstHost(),
397: rd.getDstPortList() });
398:
399: if (!netletAccessCheck.isAccessAllowed(rd
400: .getDstHost())) {
401: cleanUp();
402: return;
403: }
404:
405: rwg = new RWGroupCrypt(fromSock, pMsg.getSrcPort(),
406: rd.getDstPortList(), rd.getDstHost(),
407: sessionAuth, sessReq);
408: try {
409: NetletGroupManager.getNetletGroupManager()
410: .registerReaderWriter(rwg,
411: sessReq.getSessionID());
412:
413: } catch (SSOException se) {
414: try {
415: NetletGroupManager.getNetletGroupManager()
416: .unregister(sessReq.getSessionID());
417: } catch (Exception e) {
418: // logger.severe("ESession: Unable to
419: // register/unregister with NetletGroupManager");
420: logger.severe("PSSRNTLT_CSPNEPROX031");
421: }
422: }
423: } else if ((pMsg.getDstPort()).equals("-1")) {
424: // logger.info("ESession: FTP data connection to -> " +
425: // rd.getDstHost());
426: Object[] params14 = { rd.getDstHost() };
427: logger.log(Level.INFO, "PSSRNTLT_CSPNEPROX032",
428: params14);
429: logmsg = GWLocale.getPFString("es4", new Object[] {
430: logId, rd.getDstHost() });
431:
432: rwgcf = new RWGroupFtp(fromSock, sessionAuth,
433: sessReq);
434:
435: try {
436: NetletGroupManager.getNetletGroupManager()
437: .registerReaderWriter(rwgcf,
438: sessReq.getSessionID());
439:
440: } catch (SSOException se) {
441: try {
442: NetletGroupManager.getNetletGroupManager()
443: .unregister(sessReq.getSessionID());
444: } catch (Exception e) {
445: // logger.severe("ESession: Unable to
446: // register/unregister with NetletGroupManager");
447: logger.severe("PSSRNTLT_CSPNEPROX033");
448: }
449: }
450:
451: } else {
452: logmsg = GWLocale.getPFString("es3", new Object[] {
453: logId,
454: new String(GWLogManager.getUserId(sessReq
455: .getSessionID())),
456: pMsg.getHostName(), pMsg.getDstPort() });
457:
458: if (!netletAccessCheck.isAccessAllowed(pMsg
459: .getHostName())) {
460: cleanUp();
461: return;
462: }
463:
464: rwg = new RWGroupCrypt(fromSock, pMsg.getSrcPort(),
465: pMsg.getDstPort(), pMsg.getHostName(),
466: sessionAuth, sessReq);
467:
468: try {
469: NetletGroupManager.getNetletGroupManager()
470: .registerReaderWriter(rwg,
471: sessReq.getSessionID());
472: } catch (SSOException se) {
473: try {
474: NetletGroupManager.getNetletGroupManager()
475: .unregister(sessReq.getSessionID());
476: } catch (Exception e) {
477: // logger.severe("ESession: Unable to
478: // register/unregister with NetletGroupManager");
479: logger.severe("PSSRNTLT_CSPNEPROX034");
480: }
481: }
482: }
483: if (GWLogManager.loggingEnabled)
484: GWLogManager.write("netlet", logmsg);
485: } else {
486: // logger.severe("ESession: unable to get proxy config!");
487: logger.severe("PSSRNTLT_CSPNEPROX035");
488: }
489: pMsg = null;
490: }
491: }
492:
493: public void stop() {
494: cleanUp();
495: }
496:
497: private void cleanUp() {
498: /**
499: * Bug 4710658
500: */
501: if (fromSock != null) {
502: try {
503: fromSock.close();
504: // fromSock = null;
505: } catch (IOException e) {
506: } finally {
507: MonitoringSubsystem
508: .handleEvent(SRAEvent.PLAIN_SOCKET_DESTROYED);
509: fromSock = null;
510: }
511: }
512: // End of code change for Bug 4710658
513: }
514:
515: /*
516: * @ returns the session id of the user.
517: */
518:
519: public String getSessionID() {
520: return (sessReq.getSessionID());
521: }
522:
523: /*
524: * @ returns the session key of the user
525: */
526: /*
527: * public byte[] getSessionKey() { byte[] key = new byte[SESSION_KEYLEN];
528: * System.arraycopy(sKey.getSessionKey(), 0, key, 0, SESSION_KEYLEN); return
529: * (key); }
530: */
531:
532: public boolean isDone() {
533: if (rwg != null) {
534: return (rwg.isDone());
535: }
536: if (rwgf != null) {
537: return (rwgf.isDone());
538: }
539: if (rwgcf != null) {
540: return (rwgcf.isDone());
541: }
542: if (fromSock == null) {
543: return true;
544: }
545: return (false);
546: }
547:
548: /*
549: * reads the session id of the user and the dynamic algorithm that this rule
550: * is configured for. The session id and the dynamic algorithm are always
551: * encrypted using the publicly distributed Session Key and the default
552: * cipher. final version should throw an exception on error...not return a
553: * value plus, this is more a "read" now than negotiate
554: */
555:
556: private int readSessionId() {
557: if (sessReq == null) {
558: sessReq = new SessionRequest();
559: }
560: if (sessReq.readMsg(fromClient) == 0) {
561: // logger.info("ESession: sessId = " + sessReq.getSessionID());
562: Object[] params18 = { sessReq.getSessionID() };
563: logger.log(Level.INFO, "PSSRNTLT_CSPNEPROX036", params18);
564: } else {
565: // logger.info("ESession: negotiateSessionId IOException");
566: logger.info("PSSRNTLT_CSPNEPROX037");
567: return -1;
568: }
569: return 0;
570: }
571:
572: /*
573: * Maintaining session stickiness as well as load balancing requests
574: */
575:
576: private String getAssociatedNetletProxy(SSOToken ssoToken)
577: throws SSOException {
578:
579: String associatedNLP = ssoToken.getProperty(NETLET_PROXY);
580: /*
581: * Does the user session has a NLP ?
582: */
583: if (associatedNLP == null) {
584:
585: /*
586: * User session does not have a NLP so round-robin to the next NLP
587: */
588: associatedNLP = NetletProxyRouter.getNetletProxyAlive();
589: if (associatedNLP == null) {
590:
591: /*
592: * All NLP's are down so allow it to fail
593: */
594: return NetletProxyRouter.getServer();
595: } else {
596:
597: /*
598: * Associate the NLP's with user session
599: */
600: ssoToken.setProperty(NETLET_PROXY, associatedNLP);
601: return associatedNLP;
602: }
603: } else {
604:
605: /*
606: * User session has a NLP so check availibility and use
607: */
608: if (NetletProxyRouter.isNetletProxyAlive(associatedNLP)) {
609: return associatedNLP;
610: } else {
611: /*
612: * User associated NLP is down so see any other NLP's
613: */
614: associatedNLP = NetletProxyRouter.getNetletProxyAlive();
615: if (associatedNLP == null) {
616:
617: /*
618: * All NLP's are down so allow it to fail
619: */
620:
621: return NetletProxyRouter.getServer();
622: } else {
623:
624: /*
625: * Associate the new NLP with user session
626: */
627:
628: ssoToken.setProperty(NETLET_PROXY, associatedNLP);
629: return associatedNLP;
630: }
631: }
632: }
633: }
634:
635: /*
636: * Check whether PDC is required If yes read the Client certificate from
637: * SSLSocket For Every Netlet connections posting the client certificate to
638: * internal DSAME server would be a costly operation. So when first time PDC
639: * is verfied along with authentication process a Digest of the certificate
640: * is stored in the users session for further PDC validations.
641: */
642:
643: private boolean readClientCertificate() {
644: if (!(fromSock instanceof SSLSocket)) {
645: /*
646: * GW is not running in SSL mode so return true
647: */
648: return true;
649: } else if (!com.sun.portal.rproxy.connectionhandler.Session.doingPDC) {
650: /*
651: * GW is in SSL but PDC is ignored so return true
652: */
653: return true;
654: } else {
655:
656: /*
657: * Read the client cert from the SSL Socket and derive a digest out
658: * of it
659: */
660:
661: try {
662: org.mozilla.jss.crypto.X509Certificate clientCert = ((SSLSocket) fromSock)
663: .getStatus().getPeerCertificate();
664: byte certbyte[] = clientCert.getEncoded();
665: String xxb64Cert = JSSUtil.getDefaultDecoder()
666: .getEncodedStr(certbyte);
667: digest = JSSUtil.getDefaultDecoder().digest(xxb64Cert);
668: } catch (Exception e) {
669: // logger.severe("Netlet : Unable to get client cert");
670: logger.severe("PSSRNTLT_CSPNEPROX038");
671: return false;
672: }
673:
674: return false;
675: }
676: }
677:
678: /*
679: * Compare the calculated digested that is obtained from the client socket
680: * with the certificate store in the users session
681: */
682:
683: private boolean verifyClientCertificate(SSOToken ssoToken) {
684:
685: String pdcCertInfo = null;
686:
687: if (digest == null || digest.trim().length() == 0) {
688: /*
689: * Derived digest is null
690: */
691: return false;
692: }
693: try {
694: pdcCertInfo = ssoToken
695: .getProperty(com.sun.portal.rproxy.connectionhandler.Session.PDC_CERT_INFO);
696: } catch (SSOException soe) {
697: // logger.log(Level.SEVERE, "Netlet : Unable to get certificate
698: // digest",soe);
699: logger.log(Level.SEVERE, "PSSRNTLT_CSPNEPROX039");
700: return false;
701: }
702:
703: if (pdcCertInfo == null || pdcCertInfo.trim().length() == 0) {
704: /*
705: * No digest found in user session
706: */
707:
708: return false;
709: }
710:
711: if (digest.equals(pdcCertInfo)) {
712: /*
713: * Digest match -PDC sucessfull
714: */
715:
716: return true;
717: } else {
718:
719: /*
720: * Digest does not match - PDC failed
721: */
722:
723: return false;
724: }
725: }
726:
727: //GWRunnable Methods
728: public String getType() {
729: return ESESSION;
730: }
731: //GWRunnable Methods
732:
733: }
|