Embedded Tomcat - update/delete certificates without restarting - ssl

I am using embedded Tomcat and using SSLHostConfig to add SNI certificates when I create the connector. It works wonderfully.
I am also able to add certificates without restarting Tomcat using something like this:
SSLHostConfig sslHostConfig = new SSLHostConfig();
sslHostConfig2.setHostName(host);
sslHostConfig2.setCertificateFile(path);
connector.addSslHostConfig(sslHostConfig);
This also works perfectly.
Also, without restarting Tomcat, I can get a list of all the existing SSLHostConfig instances using this:
SSLHostConfig[] sslHostConfigs = connector.findSslHostConfigs();
However, I couldn't figure out how to update or delete an existing SSLHostConfig instance. Setting it to null in the array doesn't work. Also, replacing it in the array with a new SSLHostConfig instance doesn't work either.
Is there a way to delete or modify an SSLHostConfig instance without restarting Tomcat?
Thanks.

To update an SSLHostConfig with a new certificate file (which was referenced when creating it originally), this works:
Http11NioProtocol protocol (Http11NioProtocol)connector.getProtocolHandler();
protocol.reloadSslHostConfig(host);
Of course this assumes that you are using the Http11NioProtocol as the protocol handler for your connector.

Related

Dynamically map url suffix to port number

I am using mountebank to mock a number of REST APIs, each one is accessible through a random port. Users are able to create new mocks or remove old ones whenever they need to.
So I want to setup an apache server such that it maps the suffix of the server url to the associated port, for example: myserver.com/8000 gets automatically proxied to myserver.com:8000
I could regenerate apache config while adding a new reverse proxy, but I would need to restart the server each time and I don't think that's a good idea.
I tried using mod_proxy_express which dynamically generate a proxy map but it seems to only map servers names and not individual paths.
Is this technically possible in apache, or any other web server for that matter ?

How to assign an existing SSL certificate to a new IIS site through code?

I'm working on a simple tool for a test environment where I have to set up a few dozen sites through C# code. Thus I have a list of (sub)domain names (and other properties) in an array and I run through it to create the sites with their bindings. This works fine, except for the HTTPS bindings where I need to bind the proper SSL certificates from the store. For whatever reason, all sites end up with the same certificate.
The code is relatively straightforward. I first open the certificate store like this:
var store = new X509Store("MY", StoreLocation.LocalMachine);
store.Open(OpenFlags.OpenExistingOnly);
I then find for each domain the certificate where Certificate.Subject.EndsWith(domain.Domain) which also works fine. I display the hash and name and these are correct.
I then move on to create each domain with basic binding on port 80:
var site = manager.Sites.Add(domain.Name, "http", $"*:80:{domain.Domain}", domain.Folder);
And if a certificate is found, I'll also bind the HTTPS connection:
site.Bindings.Add($"*:443:{domain.Domain}", domain.Certificate.GetCertHash(), "MY");
I also write the hash to the console just to make sure I have the right value! And afterwards manager.CommitChanges(); gets called to commit the added site.
Then I check in IIS which certificate is attached and it turns out to be the wrong one! So each site has a certificate error and I don't understand why it goes wrong as everything seems to be correct.
So after the commit I again print the hash by enumerating the bindings to the console and it still shows the right hash. This is becoming really annoying!
As for the certificate that does gets picked... It seems to be the certificate for the last domain in my list. But why it gets assigned to all other bindings?
Is this a bug in the IIS manager?
A minor discovery: I went to IIS and changed the certificate to the proper one. This results in this message in IIS:
This is interesting as it will change the certificates for all the sites when I click "Yes". If I click "No" then I get back to the edit dialog so that doesn't solve anything. Don't think it's related, though...
Dum! Dum! Dumb! Solved it...
site.Bindings.Add($"*:443:{domain.Domain}", domain.Certificate.GetCertHash(), "MY", SslFlags.Sni);
It's the SslFlags.Sni flag in the end, as 5th parameter, that does the trick. It stands for "Server Name Indication", duh! And apparently you need it if you bind certificates by domain name...
Such a minor thing can be so annoying...

Shipyard, how to add "context" or "base path"?

I'm trying to setup a Shipyard server (controller) at work, but I've run into an issue. The server is up and running, which I can confirm with curl just fine. And we've configured Apache httpd to do forwarding, as we intend for the machine running Shipyard to not be directly accessible. So basically we setup a rule for Apache that incoming requests to /shipyard map to :8080/ which is where it's being served from. So the problem is that I need a way to tell Shipyard to remap "/" to "/shipyard". When I try to go to the Shipyard homepage, nothing on the page loads correctly. For example, Shipyard tried to load some js files:
/app/images/images.module.js
But to work with our forwarding, it needs to try to load:
/shipyard/app/images/images.module.js
With the kinds of servers I'm used to working with, this would normally be done by specifying a "context" or "base path" in your server config for it to serve from. I'm wondering how to do something similar for Shipyard?
It turns out there is already a github issue for this exact scenario:
https://github.com/shipyard/shipyard/issues/972

SonarQube: weak ephemeral Diffie-Hellman key issue with SSL

How do we by pass this issue with SonarQube server v5.1 and firefox? Chrome & IE are working fine but firefox is not allowing to access the server in https mode. I looked at https://weakdh.org/sysadmin.html but I am not sure what server SonarQube uses and how to implement fix for this problem. Any help is appreciated. Thanks.
When a user wants to enable (or restrict) access to a SonarQube instance over HTTPS, the recommended way is to put it behind another WebServer she configures at will.
So, the way to go here, is to add an Apache, Nginx or whatever in front of the SQ instance and configure it according to the recommendations in the link you provided and generate a "safe" server certificate.
I fixed it by setting the following property in sonar.properties file.
sonar.web.https.ciphers=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA256,TLS_RSA_WITH_AES_256_CBC_SHA

Using mod_proxy_ajp, how do I set "special" AJP attributes?

I have set up an Apache Web Server 2.4 to act as a proxy for Apache Tomcat 7, communicating via the AJP protocol (mod_proxy_ajp on the Apache side and an AJP connector on the Tomcat side). Everything works great for basic functionality.
Now, I am looking to set some specific AJP attributes, but can't quite get it to work...
Looking at the mod_proxy_ajp page (http://httpd.apache.org/docs/current/mod/mod_proxy_ajp.html), under the Request Packet Structure section, I see a listing of attributes. These attributes include the likes of remote_user, and ssl_cert (code values 0x03 and 0x07, respectively). There is also an "everything else" attribute called req_attribute with code value 0x0A that can be used to set any arbitrary attribute in an AJP request.
Further, on the same page, under the Environment Variables section, it states the following:
Environment variables whose names have the prefix AJP_ are forwarded to the origin server as AJP request attributes (with the AJP_ prefix removed from the name of the key).
This seems straightforward enough, and indeed, I am easily able to set an arbitrary AJP attribute such as "doug-attribute" by setting an Apache environment variable called "AJP_doug-attribute", and assigning a relevant value. After doing such, I can analyze the traffic using Wireshark, and see the "doug-attribute" field show up in the dissected AJP block, prefixed with a hex value of 0x0A (the "req_attribute" type listed above). So far so good.
Now I want to try to set the ssl_cert attribute. In the same fashion, I set an environment variable called "AJP_ssl_cert". Doing so, it does show up in Wireshark, but with prefix code "0x0A". Further, my Java application that wants to read the "javax.servlet.request.x509certificate" does not find the certificate.
However, I also notice some other attributes in the Wireshark capture that are listed on the website, like ssl_cipher and ssl_key_size. But in the capture, they show up as "SSL-Cipher" and "SSL-Key-Size" (and have the appropriate "0x08" and "0x0B" prefix codes). So, I try setting the cert attribute again, this time as "SSL-Cert", but I get the same results as before.
To compare, I altered the Apache configuration to require client certificates, and then provided one in the browser when visiting the associated web page. At this point, I look at the Wireshark capture, and sure enough, there is now an attribute named "SSL-Cert", with code "0x07", and my web application in Tomcat is successfully able to find the certificate.
Is there any way that I can manually set the attributes listed on the mod_proxy_ajp page, or does the module handle them differently from other arbitrary request attributes (like "doug-attribute")? I feel like there must be something I am missing here.
As some background, the reason that I am trying to do this is that I have a configuration with multiple Apache web servers proxying each other, and then at the end, an Apache web server proxying to a Tomcat instance via AJP. All the Apache web servers use SSL and require client certificates. With just one Apache server, Tomcat can receive the user's certificate just fine without any special configuration on my part. However, with multiple, it ultimately receives the server certificate of the previous Apache proxy (set on that machine using the SSLProxyMachineCertificateFile directive).
What I am hoping to do is place the original user's certificate into the headers of the intermediate proxied requests, and then manually set that certificate in the AJP attributes at the back end so that the web application in Tomcat can read the certificate and use it to perform its authorization stuff (this part is already set in stone, otherwise I would just add the certificate as a header and make the Java app read the header).
EDIT: of course, if there is an easier way to accomplish passing the user's certificate through the proxy chain, I'd be more than happy to hear it! :)