On 09/01/2017 20:13, Jesse Schulman wrote:
> On Thu, Jan 5, 2017 at 9:48 PM Jesse Schulman <je...@dreamtsoft.com> wrote:
> 
>> On Thu, Jan 5, 2017 at 2:08 PM Mark Thomas <ma...@apache.org> wrote:
>>
>> On 05/01/2017 21:05, Jesse Schulman wrote:
>>> We are using tomcat-embed 8.5.9, java8 and running on Centos7.  Given
>>> Tomcat's new support for SNI, we wish to support adding/removing/updating
>>> certificates via our application at runtime without restarting tomcat or
>>> binding/unbinding the port.
>>>
>>> Our configuration is very simple, we have a single servlet for all
>>> requests, so we have a single connector/endpoint to manage all
>>> SSLHostConfigs.
>>>
>>> It appears that by manipulating the list of SSLHostConfig objects in the
>>> AbstractEndpoint we can achieve what we want, there however don't appear
>> to
>>> be any public methods available that allow that kind of operation.
>>
>> It should be possible with the current API. What can't you do?
>>
>>
>> I don't think I can modify an existing/added SSLHostConfig (remove an old
>> expiring certificate and add a new certificate).  I also don't think I can
>> remove the SSLHostConfig for a given SNI hostname once it has been added.
>>
>>> I was able to extend a few tomcat classes (Connector,
>>> AbstractHttp11JsseProtocol, NioEndpoint) to expose what I need and verify
>>> that I can change the SSLHostConfig at runtime, however I would prefer to
>>> use APIs fully supported by tomcat.
>>>
>>> Is there any way to do what I want with the currently available APIs, or
>>> are there any plans to expose this kind of functionality?
>>
>> It depends exactly what you want to do.
>>
>> AbstractEndpoint.addSslHostConfig()
>> AbstractEndpoint.findSslHostConfigs()
>>
>> should be enough.
>>
>>
>> It seems addSslHostConfig does a putIfAbsent, which means I can't replace
>> an existing SSLHostConfig to update the certificate for an SNI hostname (or
>> the default SSLHostConfig).  I also can't remove an SSLHostConfig entirely,
>> which is something we'd like to support in our application.  For me it
>> would be simplest to create a new SSLHostConfig and replace the old one
>> when there is a need to update a certificate.
>>
>>
>>
>>> If not, are there any risks or issues with taking the approach described
>>> above by extending classes to expose what I need?
>>
>> It depends what you want to do. Generally, there is a risk we'll change
>> an API you are depending on since a lot of those are treated as internal
>> APIs. Some sample code might help.
>>
>>
>> I would of course test when we upgrade tomcat, and leverage any new APIs
>> that would allow me to remove any of my custom code.
>>
>> I extended AbstractHttp11JsseProtocol just so I could control which
>> endpoint implementation was used and so I could get access to my endpoint
>> implementation.  My protocol is basically a copy of Http11NioProtocol that
>> constructs my endpoint implementation and has a getter for the same.
>>
>> The endpoint is where I added functionality and looks like this:
>>
>> public class MyNioEndpoint extends NioEndpoint {
>>     private static final MyLogger LOGGER =
>> MyLogger.getLogger(MyNioEndpoint.class.getName());
>>
>>     public void removeSSLHostConfig(String sniHostName) {
>>         if (Strings.isNullOrEmpty(sniHostName)) {
>>             LOGGER.error("Cannot remove host config for invalid hostname:
>> " + sniHostName);
>>             return;
>>         }
>>
>>         if (sniHostName.equals(getDefaultSSLHostConfigName())) {
>>             LOGGER.error("Cannot remove default SSLHostConfig");
>>             return;
>>         }
>>
>>         SSLHostConfig removed = sslHostConfigs.remove(sniHostName);
>>         if (removed != null)
>>             releaseSSLContext(removed);
>>     }
>>
>>     public void addOrUpdateSSLHostConfig(SSLHostConfig config) {
>>         if (config == null) {
>>             LOGGER.error("null SSLHostConfig provided");
>>             return;
>>         }
>>
>>         String hostName = config.getHostName();
>>         if (Strings.isNullOrEmpty(hostName)) {
>>             LOGGER.error("Invalid SSLHostConfig provided, cannot
>> add/update, hostname was empty");
>>             return;
>>         }
>>
>>         for (SSLHostConfig loadedConfig : findSslHostConfigs()) {
>>             if (hostName.equals(loadedConfig.getHostName())) {
>>                 sslHostConfigs.remove(hostName);
>>                 releaseSSLContext(loadedConfig);
>>                 addSslHostConfig(loadedConfig);
>>                 return;
>>             }
>>         }
>>
>>         addSslHostConfig(config);
>>     }
>>
>> }
>>
>> Thanks for the reply, your help/suggestions are much appreciated!
>> Jesse
>>
>>
> I am bumping this, I think I made it sound as if I had all my questions
> answered (since I didn't put any questions in my response).  Here are my
> remaining questions:
> 
> Is there an existing/supported way to remove/replace an existing
> SSLHostConfig in AbstractEndpoint that is exposed via the Connector similar
> to how addSslHostConfig and findSslHostConfigs are exposed?  Such that I
> don't need the MyEndpoint class I shared above?

No.

> If the answer to the first question is no, are there any concerns with the
> code I shared?  By releasing the SSLContext is that ensuring that nothing
> will stick around from an SSLHostConfig that is removed/replaced, or is
> there more to do?

Yes, when using APR. You can't release the SSLContext until every
connection using the SSLContext is closed else you are likely to get a
JVM crash.

I recommend opening an enhancement request to make removal of an
SSLContext possible. Patches welcome ;)


Mark


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org

Reply via email to