001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.lib.collab.xmpp;
043:
044: import org.netbeans.lib.collab.CollaborationSessionListener;
045: import org.netbeans.lib.collab.CollaborationException;
046: import org.netbeans.lib.collab.RegistrationListener;
047: import org.netbeans.lib.collab.SecureRegistrationListener;
048: import org.netbeans.lib.collab.SecureSessionListener;
049: import org.netbeans.lib.collab.util.StringUtility;
050:
051: import java.security.cert.X509Certificate;
052: import java.util.*;
053: import java.net.*;
054: import java.io.*;
055:
056: /**
057: * This session provider is used to connect to an XMPP server via
058: * a proxy server. In this version, it can be used for web proxies
059: * and SOCKS V5 proxies.
060: * <p>
061: * The service URL used in the getSession() method must inidicate the
062: * XMPP server information (host and port) as well as the proxy server
063: * information (host, port, protocol, authentication credentials, and
064: * keepalive behavior). The format is as follows:
065: *
066: * <ul>
067: * <i>protocol</i>://<i>proxy-host</i>[:<i>proxy-port</i>]?<i>attrs</i>
068: * </ul>
069: * The default port is 5222. The attributes are provided using the
070: * usual URL query syntax. Available attributes are
071: * <ul>
072: * <li>service=<i>xmpp-host</i>[:<i>xmpp-port</i>] (mandatory)</li>
073: * <li>authname=<i>name</i> (proxy credential)</li>
074: * <li>password=<i>password</i> (proxy credential)</li>
075: * <li>keepalive=<i>seconds</i> (keepalive period in seconds)</li>
076: * </ul>
077: * Example:
078: * <ul>
079: * socks://sprox.example.com?service=jabber.org&authname=bob&password=secret
080: *</ul>
081: *
082: * HTTP/HTTPS tunneling is defined by the following specification:
083: * <ul>
084: * <a href="http://www.web-cache.com/Writings/Internet-Drafts/draft-luotonen-web-proxy-tunneling-01.txt">
085: http://www.web-cache.com/Writings/Internet-Drafts/draft-luotonen-web-proxy-tunneling-01.txt
086: * </a>
087: * </ul>
088: * SOCKS V5 tunneling is defined by the following specifications:
089: * <ul>
090: * <li><a href="http://www.ietf.org/rfc/rfc1928.txt">RFC 1928</a></li>
091: * <li><a href="http://www.ietf.org/rfc/rfc1929.txt">RFC 1929</a></li>
092: * </ul>
093:
094: * The service URL passed getSession must contain both the IM server and
095: * http proxy information. The format is as follows:
096: * <ul>
097: * <tt>http(s)://https-host:https-port?service=xmpp-host:xmpp-port</tt>
098: * </ul>
099: *
100: * @author Jacques Belissent
101: *
102: */
103: public class ProxySessionProvider extends XMPPSessionProvider {
104:
105: public final static String KEEPALIVE_ATTR = "keepalive";
106: public final static String AUTHNAME_ATTR = "authname";
107: public final static String PASSWORD_ATTR = "password";
108: public final static String SERVICE_ATTR = "service";
109: public final static String USE_SSL_ATTR = "usessl";
110:
111: protected XMPPSession createSession(String serviceUrl,
112: String destination, String loginName, String password,
113: int loginType, CollaborationSessionListener csl)
114: throws CollaborationException {
115: java.net.URI uri = null;
116: try {
117: uri = new java.net.URI(serviceUrl);
118: } catch (java.net.URISyntaxException use) {
119: throw new CollaborationException(use);
120: }
121: Map attributes = parseQuery(uri.getQuery());
122:
123: if (attributes.containsKey(KEEPALIVE_ATTR)) {
124: startKeepAlive(Long.parseLong((String) attributes
125: .get(KEEPALIVE_ATTR)) * 1000);
126: }
127:
128: StreamSourceCreator ssc = null;
129: if (uri.getScheme().equalsIgnoreCase("socks")) {
130: ssc = new Socks5StreamSourceCreator(csl, uri, attributes);
131: } else if (uri.getScheme().equalsIgnoreCase("http")
132: || uri.getScheme().equalsIgnoreCase("https")) {
133: ssc = new HTTPStreamSourceCreator(csl, uri, attributes);
134: }
135:
136: if (ssc != null) {
137: return new XMPPSession(this , (String) attributes
138: .get(SERVICE_ATTR), destination, loginName,
139: password, loginType, csl, ssc);
140: } else {
141: throw new CollaborationException("Unsupported protocol: "
142: + uri.getScheme());
143: }
144: }
145:
146: private Map parseQuery(String query) {
147:
148: HashMap attributes = new HashMap();
149: if (query != null) {
150: for (StringTokenizer st = new StringTokenizer(query, "&"); st
151: .hasMoreTokens();) {
152: String avp = st.nextToken();
153: int eqi = avp.indexOf("=");
154: if (eqi > 0 && eqi < avp.length()) {
155: try {
156: String val = URLDecoder.decode(avp
157: .substring(eqi + 1), "UTF-8");
158: attributes.put(avp.substring(0, eqi), val);
159: } catch (UnsupportedEncodingException uee) {
160: // never happens with UTF8
161: }
162: }
163: }
164: }
165: return attributes;
166: }
167:
168: protected long getKeepAliveInterval() {
169: //override since i look at keepalive in url and decide
170: return 0;
171: }
172:
173: protected String getDomain(String loginName, String serviceURL) {
174: String server = null;
175: java.net.URI uri = null;
176: try {
177: uri = new java.net.URI(serviceURL);
178: Map attributes = parseQuery(uri.getQuery());
179: server = (String) attributes.get(SERVICE_ATTR);
180: if (null == server) {
181: server = uri.getHost();
182: }
183: } catch (java.net.URISyntaxException use) {
184: // Should not happen , this has already been validated ...
185: throw new IllegalArgumentException("URI is invalid : "
186: + serviceURL + " , message : " + use.toString());
187: }
188:
189: return super.getDomain(loginName, server);
190: }
191:
192: }
|