View Javadoc

1   /*
2    * Copyright (c) 2012 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.eclipse.jetty.npn;
18  
19  import java.util.Collections;
20  import java.util.List;
21  import java.util.Map;
22  import java.util.WeakHashMap;
23  import javax.net.ssl.SSLEngine;
24  import javax.net.ssl.SSLSocket;
25  
26  /**
27   * <p>{@link NextProtoNego} provides an API to applications that want to make use of the
28   * <a href="http://technotes.googlecode.com/git/nextprotoneg.html">Next Protocol Negotiation</a>.</p>
29   * <p>The NPN extension is only available when using the TLS protocol, therefore applications must
30   * ensure that the TLS protocol is used:</p>
31   * <pre>
32   * SSLContext context = SSLContext.getInstance("TLSv1");
33   * </pre>
34   * <p>Refer to the
35   * <a href="http://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#SSLContext">list
36   * of standard SSLContext protocol names</a> for further information on TLS protocol versions supported.</p>
37   * <p>Applications must register instances of either {@link SSLSocket} or {@link SSLEngine} with a
38   * {@link ClientProvider} or with a {@link ServerProvider}, depending whether they are on client or
39   * server side.</p>
40   * <p>The NPN implementation will invoke the provider callbacks to allow applications to interact
41   * with the negotiation of the next protocol.</p>
42   * <p>Client side typical usage:</p>
43   * <pre>
44   * SSLSocket sslSocket = ...;
45   * NextProtoNego.put(sslSocket, new NextProtoNego.ClientProvider()
46   * {
47   *     &#64;Override
48   *     public boolean supports()
49   *     {
50   *         return true;
51   *     }
52   *
53   *     &#64;Override
54   *     public void unsupported()
55   *     {
56   *     }
57   *
58   *     &#64;Override
59   *     public String selectProtocol(List&lt;String&gt; protocols)
60   *     {
61   *         return protocols.get(0);
62   *     }
63   *  });
64   * </pre>
65   * <p>Server side typical usage:</p>
66   * <pre>
67   * SSLSocket sslSocket = ...;
68   * NextProtoNego.put(sslSocket, new NextProtoNego.ServerProvider()
69   * {
70   *     &#64;Override
71   *     public void unsupported()
72   *     {
73   *     }
74   *
75   *     &#64;Override
76   *     public List<String> protocols()
77   *     {
78   *         return Arrays.asList("http/1.1");
79   *     }
80   *
81   *     &#64;Override
82   *     public void protocolSelected(String protocol)
83   *     {
84   *         System.out.println("Protocol Selected is: " + protocol);
85   *     }
86   *  });
87   * </pre>
88   * <p>There is no need to unregister {@link SSLSocket} or {@link SSLEngine} instances, as they
89   * are kept in a {@link WeakHashMap} and will be garbage collected when the application does not
90   * hard reference them anymore.</p>
91   * <p>In order to help application development, you can set the {@link NextProtoNego#debug} field
92   * to {@code true} to have debug code printed to {@link System#err}.</p>
93   */
94  public class NextProtoNego
95  {
96      /**
97       * <p>Enables debug logging on {@link System#err}.</p>
98       */
99      public static boolean debug = false;
100 
101     private static Map<Object, Provider> objects = Collections.synchronizedMap(new WeakHashMap<Object, Provider>());
102 
103     private NextProtoNego()
104     {
105     }
106 
107     /**
108      * <p>Registers a SSLSocket with a provider.</p>
109      *
110      * @param socket the socket to register with the provider
111      * @param provider the provider to register with the socket
112      */
113     public static void put(SSLSocket socket, Provider provider)
114     {
115         objects.put(socket, provider);
116     }
117 
118     /**
119      * @param socket a socket registered with {@link #put(SSLSocket, Provider)}
120      * @return the provider registered with the given socket
121      */
122     public static Provider get(SSLSocket socket)
123     {
124         return objects.get(socket);
125     }
126 
127     /**
128      * <p>Registers a SSLEngine with a provider.</p>
129      *
130      * @param engine the engine to register with the provider
131      * @param provider the provider to register with the engine
132      */
133     public static void put(SSLEngine engine, Provider provider)
134     {
135         objects.put(engine, provider);
136     }
137 
138     /**
139      *
140      * @param engine an engine registered with {@link #put(SSLEngine, Provider)}
141      * @return the provider registered with the given engine
142      */
143     public static Provider get(SSLEngine engine)
144     {
145         return objects.get(engine);
146     }
147 
148     /**
149      * <p>Base, empty, interface for providers.</p>
150      */
151     public interface Provider
152     {
153     }
154 
155     /**
156      * <p>The client-side provider interface that applications must implement to interact
157      * with the negotiation of the next protocol.</p>
158      */
159     public interface ClientProvider extends Provider
160     {
161         /**
162          * <p>Callback invoked to let the implementation know whether an
163          * empty NPN extension should be added to a ClientHello SSL message.</p>
164          *
165          * @return true to add the NPN extension, false otherwise
166          */
167         public boolean supports();
168 
169         /**
170          * <p>Callback invoked to let the application know that the server does
171          * not support NPN.</p>
172          */
173         public void unsupported();
174 
175         /**
176          * <p>Callback invoked to let the application select a protocol
177          * among the ones sent by the server.</p>
178          *
179          * @param protocols the protocols sent by the server
180          * @return the protocol selected by the application, or null if the
181          * NextProtocol SSL message should not be sent to the server
182          */
183         public String selectProtocol(List<String> protocols);
184     }
185 
186     /**
187      * <p>The server-side provider interface that applications must implement to interact
188      * with the negotiation of the next protocol.</p>
189      */
190     public interface ServerProvider extends Provider
191     {
192         /**
193          * <p>Callback invoked to let the application know that the client does not
194          * support NPN.</p>
195          */
196         public void unsupported();
197 
198         /**
199          * <p>Callback invoked to let the implementation know the list
200          * of protocols that should be added to an NPN extension in a
201          * ServerHello SSL message.</p>
202          * <p>This callback is invoked only if the client sent a NPN extension.</p>
203          *
204          * @return the list of protocols, or null if no NPN extension
205          * should be sent to the client
206          */
207         public List<String> protocols();
208 
209         /**
210          * <p>Callback invoked to let the application know the protocol selected
211          * by the client.</p>
212          * <p>This callback is invoked only if the client sent a NextProtocol SSL message.</p>
213          *
214          * @param protocol the selected protocol
215          */
216         public void protocolSelected(String protocol);
217     }
218 }