Difference between revisions of "Jetty/Feature/NPN"

From Eclipsepedia

< Jetty‎ | Feature
Jump to: navigation, search
 
(23 intermediate revisions by 3 users not shown)
Line 1: Line 1:
 
{{Jetty Feature  
 
{{Jetty Feature  
 
| introduction =  
 
| introduction =  
 +
 +
{{Jetty Redirect|http://www.eclipse.org/jetty/documentation/current/npn-chapter.html}}
  
 
The Jetty project provides an implementation of the [http://technotes.googlecode.com/git/nextprotoneg.html Next Protocol Negotiation TLS Extension] (NPN) for OpenJDK 7 or greater.
 
The Jetty project provides an implementation of the [http://technotes.googlecode.com/git/nextprotoneg.html Next Protocol Negotiation TLS Extension] (NPN) for OpenJDK 7 or greater.
 +
NPN allows the application layer to negotiate which protocol to use over the secure connection.
  
Jetty's NPN implementation, although hosted under the umbrella of the Jetty project, is independent of Jetty (the Servlet Container), and can be reused in any other Java network server.
+
NPN currently negotiates using SPDY as an application level protocol on port 443, and also negotiates the SPDY version. However, NPN is not SPDY specific in any way.
 
+
Jetty's NPN implementation, although hosted under the umbrella of the Jetty project, is independent of Jetty (the servlet container); you can use it in any other Java network server.
| body =
+
| body =  
 
+
===Starting the JVM===
==JVM Startup Usage==
+
  
In order to enable NPN support, you need to start the JVM with:
+
To enable NPN support, you need to start the JVM with:
  
 
<source lang="bash">
 
<source lang="bash">
Line 16: Line 18:
 
</source>
 
</source>
  
where <code>path_to_npn_boot_jar</code> is the path on file system for the NPN Boot jar file, for example one at the following Maven coordinates [http://repo2.maven.org/maven2/org/mortbay/jetty/npn/npn-boot org.mortbay.jetty.npn:npn-boot].
+
where <code>path_to_npn_boot_jar</code> is the path on the file system for the NPN Boot jar file, for exampleone at the Maven coordinates [http://repo2.maven.org/maven2/org/mortbay/jetty/npn/npn-boot org.mortbay.jetty.npn:npn-boot].  
  
==API Usage==
+
(Note that the current versions of the npn packages no longer align with Jetty versions. Look at the dates in those file paths before looking at the version number.)
  
Applications needs to interact with the negotiation of the next protocol performed by the NPN TLS extension. For example, server applications need to know whether the client supports NPN, and client applications needs to know the list of protocols supported by the server, and so on.
+
===Understanding the NPN API===
  
In order to provide this interaction, Jetty's NPN implementation provides an API to applications, hosted at Maven coordinates <code>org.eclipse.jetty.npn:npn-api</code>.
+
Applications need to interact with NPN TLS extension protocol negotiations. For example, server applications need to know whether the client supports NPN, and client applications needs to know the list of protocols the server supports, and so on.
This dependency needs to be declared as "provided", because it is already included in the <code>npn-boot</code> jar (see section above) and therefore will be available in the boot classpath.
+
  
The API is composed of a single class, <code>org.eclipse.jetty.npn.NextProtoNego</code>, and applications need to register instances of <code>SSLSocket</code> or <code>SSLEngine</code> with a <code>ClientProvider</code> or <code>ServerProvider</code> (depending on whether the application is a client or server application).
+
To implement this interaction, Jetty's NPN implementation provides an API to applications, hosted at Maven coordinates <code>org.eclipse.jetty.npn:npn-api</code>.
Refer to [<code>NextProtoNego</code> javadocs http://download.eclipse.org/jetty/stable-7/apidocs/org/eclipse/jetty/npn/NextProtoNego.html] and to the examples below for further details about client and server provider methods.
+
You need to declare this dependency as ''provided'', because the <code>npn-boot</code> jar already includes it (see the previous section), and it is therefore available in the boot classpath.
  
===Client Example===
+
The API consists of a single class, <code>org.eclipse.jetty.npn.NextProtoNego</code>, and applications need to register instances of <code>SSLSocket</code> or <code>SSLEngine</code> with a <code>ClientProvider</code> or <code>ServerProvider</code> (depending on whether the application is a client or server application).
 +
Refer to [http://download.eclipse.org/jetty/stable-7/apidocs/org/eclipse/jetty/npn/NextProtoNego.html <code>NextProtoNego</code> javadocs] and to the examples below for further details about client and server provider methods.
 +
 
 +
====Client Example====
  
 
<source lang="java">
 
<source lang="java">
Line 56: Line 60:
 
</source>
 
</source>
  
The <code>NextProtoNego.ClientProvider</code> methods <code>supports()</code>, <code>unsupported()</code> and <code>selectProtocol(List&lt;String&gt;)</code> will be called by the NPN implementation, so that the client application can, respectively, decide whether to support NPN, whether the server supports NPN, and select one of the protocols supported by the server.
+
The NPN implementation calls <code>NextProtoNego.ClientProvider</code> methods <code>supports()</code>, <code>unsupported()</code> and <code>selectProtocol(List&lt;String&gt;)</code>, so that the client application can decide:
 +
* whether to support NPN.
 +
* whether the server supports NPN.
 +
* to select one of the protocols the server supports.
  
The example for <code>SSLEngine</code> is identical, and you just need to replace the <code>SSLSocket</code> instance with a <code>SSLEngine</code> instance.
+
The example for <code>SSLEngine</code> is identical, and you just need to replace the <code>SSLSocket</code> instance with an <code>SSLEngine</code> instance.
  
===Server Example===
+
====Server Example====
  
 
<source lang="java">
 
<source lang="java">
Line 85: Line 92:
 
</source>
 
</source>
  
The <code>NextProtoNego.ServerProvider</code> methods <code>unsupported()</code>, <code>protocols()</code> and <code>protocolSelected(String)</code> will be called by the NPN implementation, so that the server application can, respectively, know whether the client supports NPN, provide the list of protocols supported by the server, and know what is the protocol chosen by the client.
+
The NPN implementation calls <code>NextProtoNego.ServerProvider</code> methods <code>unsupported()</code>, <code>protocols()</code> and <code>protocolSelected(String)</code>, so that the server application can
 +
* know whether the client supports NPN.
 +
* provide the list of protocols the server supports.
 +
* know which protocol the client chooses.
  
==Implementation Details==
+
====Implementation Details====
  
The NPN implementation relies on modification of few OpenJDK classes and on few new classes that needs to live in the <code>sun.security.ssl</code> package.
+
It is common that the <code>NextProtoNego.ServerProvider</code> (and the <code>NextProtoNego.ClientProvider</code>) are implemented as (anonymous) inner classes, and that their method's implementations require references to the the <code>sslSocket</code> (or <code>sslEngine</code>), either directly or indirectly.
These classes are released under the same GPLv2+exception license of OpenJDK.
+
  
The <code>NextProtoNego</code> class is released under same license as the classes of the Jetty project.  
+
Since the <code>NextProtoNego</code> class holds [<code>sslSocket</code>/<code>sslEngine</code>, provider] pairs in a <code>WeakHashMap</code>, if the value (i.e. the provider implementation) holds a strong (even indirect) reference to the key, then the <code>WeakHashMap</code> entries will never be removed, leading to a memory leak.
 +
 
 +
For example in Jetty the implementation of <code>NextProtoNego.ServerProvider</code> requires a reference to a <code>org.eclipse.jetty.io.nio.SslConnection</code> that in turn holds a reference to the <code>sslEngine</code>. Therefore the <code>NextProtoNego.ServerProvider</code> implementation does not use the <code>SslConnection</code> directly, but instead via an <code>AtomicReference</code> that is cleared upon connection close.
 +
 
 +
Note that declaring the <code>SslConnection</code> as a final local variable and referencing it from within the anonymous <code>NextProtoNego.ServerProvider</code> class generates a hidden field in the anonymous inner class, causing the memory leak, so it must be avoided.
  
==Usage in Unit Tests==
+
===Using Unit Tests===
  
It is possible to write and run unit tests that make use of the NPN implementation.
+
You can write and run unit tests that use the NPN implementation.
The solution that we used with Maven is to specify an additional command line argument to the Surefire plugin:
+
The solution that we use with Maven is to specify an additional command line argument to the Surefire plugin:
  
 
<source lang="xml">
 
<source lang="xml">
Line 124: Line 137:
 
</project>
 
</project>
 
</source>
 
</source>
 +
 +
===Debugging===
 +
 +
You can enable debug logging for the NPN implementation in this way:
 +
 +
<source lang="java">
 +
NextProtoNego.debug = true;
 +
</source>
 +
 +
Since the <code>NextProtoNego</code> class is in the boot classpath, we chose not to use logging libraries because we do not want to override application logging library choices; therefore the logging is performed directly on <code>System.err</code>.
 +
 +
===License Details===
 +
 +
The NPN implementation relies on modification of a few OpenJDK classes and on a few new classes that need to live in the <code>sun.security.ssl</code> package.
 +
These classes are released under the same GPLv2+exception license of OpenJDK.
 +
 +
The <code>NextProtoNego</code> class is released under same license as the classes of the Jetty project.
  
 
}}
 
}}
 +
 +
===Versions===
 +
 +
The NPN implementation, relying on modifications of OpenJDK classes, updates every time there are updates to the modified OpenJDK classes.
 +
{|border="1" cellpadding="5" style="text-align:center"
 +
|+ NPN vs OpenJDK versions
 +
|-
 +
!NPN version!!OpenJDK version
 +
|-
 +
!1.0.0.v20120402
 +
| 1.7.0 - 1.7.0u2 - 1.7.0u3
 +
|-
 +
!1.1.0.v20120525
 +
| 1.7.0u4 - 1.7.0u5
 +
|-
 +
!1.1.1.v20121030
 +
| 1.7.0u6 - 1.7.0u7
 +
|-
 +
!1.1.3.v20130313
 +
| 1.7.0u9 - 1.7.0u10 - 1.7.0u11
 +
|-
 +
!1.1.4.v20130313
 +
| 1.7.0u13
 +
|-
 +
!1.1.5.v20130313
 +
| 1.7.0u15 - 1.7.0u17
 +
|}

Latest revision as of 15:24, 23 April 2013



Contents

[edit] Introduction


The Jetty project provides an implementation of the Next Protocol Negotiation TLS Extension (NPN) for OpenJDK 7 or greater. NPN allows the application layer to negotiate which protocol to use over the secure connection.

NPN currently negotiates using SPDY as an application level protocol on port 443, and also negotiates the SPDY version. However, NPN is not SPDY specific in any way. Jetty's NPN implementation, although hosted under the umbrella of the Jetty project, is independent of Jetty (the servlet container); you can use it in any other Java network server.

[edit] Feature

Starting the JVM

To enable NPN support, you need to start the JVM with:

java -Xbootclasspath/p:<path_to_npn_boot_jar> ...

where path_to_npn_boot_jar is the path on the file system for the NPN Boot jar file, for example, one at the Maven coordinates org.mortbay.jetty.npn:npn-boot.

(Note that the current versions of the npn packages no longer align with Jetty versions. Look at the dates in those file paths before looking at the version number.)

Understanding the NPN API

Applications need to interact with NPN TLS extension protocol negotiations. For example, server applications need to know whether the client supports NPN, and client applications needs to know the list of protocols the server supports, and so on.

To implement this interaction, Jetty's NPN implementation provides an API to applications, hosted at Maven coordinates org.eclipse.jetty.npn:npn-api. You need to declare this dependency as provided, because the npn-boot jar already includes it (see the previous section), and it is therefore available in the boot classpath.

The API consists of a single class, org.eclipse.jetty.npn.NextProtoNego, and applications need to register instances of SSLSocket or SSLEngine with a ClientProvider or ServerProvider (depending on whether the application is a client or server application). Refer to NextProtoNego javadocs and to the examples below for further details about client and server provider methods.

Client Example

SSLContext sslContext = ...;
SSLSocket sslSocket = (SSLSocket)context.getSocketFactory()
        .createSocket("localhost", server.getLocalPort());
 
NextProtoNego.put(sslSocket, new NextProtoNego.ClientProvider()
{
    @Override
    public boolean supports()
    {
        return true;
    }
 
    @Override
    public void unsupported()
    {
    }
 
    @Override
    public String selectProtocol(List<String> protocols)
    {
        return protocols.get(0);
    }
});

The NPN implementation calls NextProtoNego.ClientProvider methods supports(), unsupported() and selectProtocol(List<String>), so that the client application can decide:

  • whether to support NPN.
  • whether the server supports NPN.
  • to select one of the protocols the server supports.

The example for SSLEngine is identical, and you just need to replace the SSLSocket instance with an SSLEngine instance.

Server Example

SSLSocket sslSocket = ...;
NextProtoNego.put(sslSocket, new NextProtoNego.ServerProvider()
{
    @Override
    public void unsupported()
    {
    }
 
    @Override
    public List<String> protocols()
    {
        return Arrays.asList("http/1.1");
    }
 
    @Override
    public void protocolSelected(String protocol)
    {
        System.out.println("Protocol Selected is: " + protocol);
    }
});

The NPN implementation calls NextProtoNego.ServerProvider methods unsupported(), protocols() and protocolSelected(String), so that the server application can

  • know whether the client supports NPN.
  • provide the list of protocols the server supports.
  • know which protocol the client chooses.

Implementation Details

It is common that the NextProtoNego.ServerProvider (and the NextProtoNego.ClientProvider) are implemented as (anonymous) inner classes, and that their method's implementations require references to the the sslSocket (or sslEngine), either directly or indirectly.

Since the NextProtoNego class holds [sslSocket/sslEngine, provider] pairs in a WeakHashMap, if the value (i.e. the provider implementation) holds a strong (even indirect) reference to the key, then the WeakHashMap entries will never be removed, leading to a memory leak.

For example in Jetty the implementation of NextProtoNego.ServerProvider requires a reference to a org.eclipse.jetty.io.nio.SslConnection that in turn holds a reference to the sslEngine. Therefore the NextProtoNego.ServerProvider implementation does not use the SslConnection directly, but instead via an AtomicReference that is cleared upon connection close.

Note that declaring the SslConnection as a final local variable and referencing it from within the anonymous NextProtoNego.ServerProvider class generates a hidden field in the anonymous inner class, causing the memory leak, so it must be avoided.

Using Unit Tests

You can write and run unit tests that use the NPN implementation. The solution that we use with Maven is to specify an additional command line argument to the Surefire plugin:

<project ...>
 
  <properties>
    <npn-version>7.6.2.v20120308</npn-version>
  </properties>
 
  <build>
    <plugins>
      <plugin>
        <artifactId>maven-surefire-plugin</artifactId>
        <configuration>
          <argLine>-Xbootclasspath/p:${settings.localRepository}/org/mortbay/jetty/npn/npn-boot/${npn-version}/npn-boot-${npn-version}.jar</argLine>
        </configuration>
      </plugin>
 
      ...
 
    </plugins>
  </build>
 
  ...
 
</project>

Debugging

You can enable debug logging for the NPN implementation in this way:

NextProtoNego.debug = true;

Since the NextProtoNego class is in the boot classpath, we chose not to use logging libraries because we do not want to override application logging library choices; therefore the logging is performed directly on System.err.

License Details

The NPN implementation relies on modification of a few OpenJDK classes and on a few new classes that need to live in the sun.security.ssl package. These classes are released under the same GPLv2+exception license of OpenJDK.

The NextProtoNego class is released under same license as the classes of the Jetty project.

[edit] Versions

The NPN implementation, relying on modifications of OpenJDK classes, updates every time there are updates to the modified OpenJDK classes.

NPN vs OpenJDK versions
NPN version OpenJDK version
1.0.0.v20120402 1.7.0 - 1.7.0u2 - 1.7.0u3
1.1.0.v20120525 1.7.0u4 - 1.7.0u5
1.1.1.v20121030 1.7.0u6 - 1.7.0u7
1.1.3.v20130313 1.7.0u9 - 1.7.0u10 - 1.7.0u11
1.1.4.v20130313 1.7.0u13
1.1.5.v20130313 1.7.0u15 - 1.7.0u17