View Javadoc
1   /*
2    * Copyright 2014 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. 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, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package io.netty.handler.ssl;
17  
18  import static io.netty.handler.ssl.ApplicationProtocolUtil.toList;
19  import static io.netty.util.internal.ObjectUtil.checkNotNull;
20  
21  import java.util.Collections;
22  import java.util.List;
23  import java.util.Set;
24  
25  import javax.net.ssl.SSLEngine;
26  import javax.net.ssl.SSLHandshakeException;
27  
28  /**
29   * Common base class for {@link JdkApplicationProtocolNegotiator} classes to inherit from.
30   */
31  class JdkBaseApplicationProtocolNegotiator implements JdkApplicationProtocolNegotiator {
32      private final List<String> protocols;
33      private final ProtocolSelectorFactory selectorFactory;
34      private final ProtocolSelectionListenerFactory listenerFactory;
35      private final SslEngineWrapperFactory wrapperFactory;
36  
37      /**
38       * Create a new instance.
39       * @param wrapperFactory Determines which application protocol will be used by wrapping the SSLEngine in use.
40       * @param selectorFactory How the peer selecting the protocol should behave.
41       * @param listenerFactory How the peer being notified of the selected protocol should behave.
42       * @param protocols The order of iteration determines the preference of support for protocols.
43       */
44      protected JdkBaseApplicationProtocolNegotiator(SslEngineWrapperFactory wrapperFactory,
45              ProtocolSelectorFactory selectorFactory, ProtocolSelectionListenerFactory listenerFactory,
46              Iterable<String> protocols) {
47          this(wrapperFactory, selectorFactory, listenerFactory, toList(protocols));
48      }
49  
50      /**
51       * Create a new instance.
52       * @param wrapperFactory Determines which application protocol will be used by wrapping the SSLEngine in use.
53       * @param selectorFactory How the peer selecting the protocol should behave.
54       * @param listenerFactory How the peer being notified of the selected protocol should behave.
55       * @param protocols The order of iteration determines the preference of support for protocols.
56       */
57      protected JdkBaseApplicationProtocolNegotiator(SslEngineWrapperFactory wrapperFactory,
58              ProtocolSelectorFactory selectorFactory, ProtocolSelectionListenerFactory listenerFactory,
59              String... protocols) {
60          this(wrapperFactory, selectorFactory, listenerFactory, toList(protocols));
61      }
62  
63      /**
64       * Create a new instance.
65       * @param wrapperFactory Determines which application protocol will be used by wrapping the SSLEngine in use.
66       * @param selectorFactory How the peer selecting the protocol should behave.
67       * @param listenerFactory How the peer being notified of the selected protocol should behave.
68       * @param protocols The order of iteration determines the preference of support for protocols.
69       */
70      private JdkBaseApplicationProtocolNegotiator(SslEngineWrapperFactory wrapperFactory,
71              ProtocolSelectorFactory selectorFactory, ProtocolSelectionListenerFactory listenerFactory,
72              List<String> protocols) {
73          this.wrapperFactory = checkNotNull(wrapperFactory, "wrapperFactory");
74          this.selectorFactory = checkNotNull(selectorFactory, "selectorFactory");
75          this.listenerFactory = checkNotNull(listenerFactory, "listenerFactory");
76          this.protocols = Collections.unmodifiableList(checkNotNull(protocols, "protocols"));
77      }
78  
79      @Override
80      public List<String> protocols() {
81          return protocols;
82      }
83  
84      @Override
85      public ProtocolSelectorFactory protocolSelectorFactory() {
86          return selectorFactory;
87      }
88  
89      @Override
90      public ProtocolSelectionListenerFactory protocolListenerFactory() {
91          return listenerFactory;
92      }
93  
94      @Override
95      public SslEngineWrapperFactory wrapperFactory() {
96          return wrapperFactory;
97      }
98  
99      static final ProtocolSelectorFactory FAIL_SELECTOR_FACTORY = new ProtocolSelectorFactory() {
100         @Override
101         public ProtocolSelector newSelector(SSLEngine engine, Set<String> supportedProtocols) {
102             return new FailProtocolSelector((JdkSslEngine) engine, supportedProtocols);
103         }
104     };
105 
106     static final ProtocolSelectorFactory NO_FAIL_SELECTOR_FACTORY = new ProtocolSelectorFactory() {
107         @Override
108         public ProtocolSelector newSelector(SSLEngine engine, Set<String> supportedProtocols) {
109             return new NoFailProtocolSelector((JdkSslEngine) engine, supportedProtocols);
110         }
111     };
112 
113     static final ProtocolSelectionListenerFactory FAIL_SELECTION_LISTENER_FACTORY =
114             new ProtocolSelectionListenerFactory() {
115         @Override
116         public ProtocolSelectionListener newListener(SSLEngine engine, List<String> supportedProtocols) {
117             return new FailProtocolSelectionListener((JdkSslEngine) engine, supportedProtocols);
118         }
119     };
120 
121     static final ProtocolSelectionListenerFactory NO_FAIL_SELECTION_LISTENER_FACTORY =
122             new ProtocolSelectionListenerFactory() {
123         @Override
124         public ProtocolSelectionListener newListener(SSLEngine engine, List<String> supportedProtocols) {
125             return new NoFailProtocolSelectionListener((JdkSslEngine) engine, supportedProtocols);
126         }
127     };
128 
129     protected static class NoFailProtocolSelector implements ProtocolSelector {
130         private final JdkSslEngine jettyWrapper;
131         private final Set<String> supportedProtocols;
132 
133         public NoFailProtocolSelector(JdkSslEngine jettyWrapper, Set<String> supportedProtocols) {
134             this.jettyWrapper = jettyWrapper;
135             this.supportedProtocols = supportedProtocols;
136         }
137 
138         @Override
139         public void unsupported() {
140             jettyWrapper.getSession().setApplicationProtocol(null);
141         }
142 
143         @Override
144         public String select(List<String> protocols) throws Exception {
145             for (int i = 0; i < protocols.size(); ++i) {
146                 String p = protocols.get(i);
147                 if (supportedProtocols.contains(p)) {
148                     jettyWrapper.getSession().setApplicationProtocol(p);
149                     return p;
150                 }
151             }
152             return noSelectMatchFound();
153         }
154 
155         public String noSelectMatchFound() throws Exception {
156             jettyWrapper.getSession().setApplicationProtocol(null);
157             return null;
158         }
159     }
160 
161     protected static final class FailProtocolSelector extends NoFailProtocolSelector {
162         public FailProtocolSelector(JdkSslEngine jettyWrapper, Set<String> supportedProtocols) {
163             super(jettyWrapper, supportedProtocols);
164         }
165 
166         @Override
167         public String noSelectMatchFound() throws Exception {
168             throw new SSLHandshakeException("Selected protocol is not supported");
169         }
170     }
171 
172     protected static class NoFailProtocolSelectionListener implements ProtocolSelectionListener {
173         private final JdkSslEngine jettyWrapper;
174         private final List<String> supportedProtocols;
175 
176         public NoFailProtocolSelectionListener(JdkSslEngine jettyWrapper, List<String> supportedProtocols) {
177             this.jettyWrapper = jettyWrapper;
178             this.supportedProtocols = supportedProtocols;
179         }
180 
181         @Override
182         public void unsupported() {
183             jettyWrapper.getSession().setApplicationProtocol(null);
184         }
185 
186         @Override
187         public void selected(String protocol) throws Exception {
188             if (supportedProtocols.contains(protocol)) {
189                 jettyWrapper.getSession().setApplicationProtocol(protocol);
190             } else {
191                 noSelectedMatchFound(protocol);
192             }
193         }
194 
195         public void noSelectedMatchFound(String protocol) throws Exception {
196         }
197     }
198 
199     protected static final class FailProtocolSelectionListener extends NoFailProtocolSelectionListener {
200         public FailProtocolSelectionListener(JdkSslEngine jettyWrapper, List<String> supportedProtocols) {
201             super(jettyWrapper, supportedProtocols);
202         }
203 
204         @Override
205         public void noSelectedMatchFound(String protocol) throws Exception {
206             throw new SSLHandshakeException("No compatible protocols found");
207         }
208     }
209 }