use TLS 1.2 to connect securely to RabbitMQ - rabbitmq

I am trying to connect to a RabbitMQ server using TLS1.2 but I can't seem to do it. I have verified that my username and password are working as I can connect to the RabbitMQ web client.
using System;
using System.Net;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Configuration;
using System.Xml;
using System.Xml.Linq;
using System.Xml.XPath;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
namespace DigitalFulfillmentRabbitMQ
{
public class RabbitMQService
{
public IConnection GetRabbitMqConnection()
{
ConnectionFactory connectionFactory = new ConnectionFactory();
// ServicePointManager.CertificatePolicy = new TrustAllCertificatePolicy();
// connectionFactory.Ssl.CertificateValidationCallback = CheckValidationResult();
System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
connectionFactory.HostName = ConfigurationManager.AppSettings["RabbitMQServer"].ToString();
connectionFactory.VirtualHost = ConfigurationManager.AppSettings["RabbitMQVHOST"].ToString();
connectionFactory.Port = Int32.Parse(ConfigurationManager.AppSettings["RabbitMQPort"].ToString());
connectionFactory.UserName = ConfigurationManager.AppSettings["RabbitMQAccountUserName"].ToString();
connectionFactory.Password = ConfigurationManager.AppSettings["RabbitMQAccountPassword"].ToString();
// connectionFactory.Ssl.ServerName = System.Net.Dns.GetHostName();
connectionFactory.Ssl.ServerName = ConfigurationManager.AppSettings["RabbitMQServer"].ToString();
connectionFactory.Ssl.CertPath = ConfigurationManager.AppSettings["RabbitMQSSLCertPath"].ToString();
// connectionFactory.Ssl.CertPassphrase = ConfigurationManager.AppSettings["RabbitMQSSLCertPassphrase"].ToString();
connectionFactory.Ssl.Enabled = Convert.ToBoolean(ConfigurationManager.AppSettings["RabbitMQSSLIsEnabled"].ToString());
connectionFactory.Ssl.Version = System.Security.Authentication.SslProtocols.Tls12;
return connectionFactory.CreateConnection();
}
}
}
The certificate is a .pem certificate I have put on the client. I'm using port 8071. The certificate path is of format "D:\RabbitMQ_DF_SIT_Server_certificate\ca_certificate.pem". I'm using the RabbitMQ client from NuGet 5.1.0
I doubt I need Certificate Validation Callback Method because from what I understand its one way connection. This application will only consume & not publish at all. What am I missing? The certificate is sitting on the client server but not installed per se.
It throws an error :
RabbitMQ.Client.Exceptions.BrokerUnreachableException: None of the specified endpoints were reachable ---> System.AggregateException: One or more errors occurred. ---> System.Security.Authentication.AuthenticationException: A call to SSPI failed, see inner exception. ---> System.ComponentModel.Win32Exception: The client and server cannot communicate, because they do not possess a common algorithm

In order to use TLS with RabbitMQ one has to enable this via the RabbitMQ config located in Windows at %APPDATA%/RabbitMQ/rabbitmq.conf file.
Depending on the Erlang version being used, the config can be the classic format / ini style. For more details, please refer to https://www.rabbitmq.com/configure.html
With the newer ini style configuration format, the config should look like this
listeners.ssl.default = 5671
ssl_options.verify = verify_none
ssl_options.fail_if_no_peer_cert = false
ssl_options.cacertfile = <location to cacertfile.crt>
ssl_options.certfile = <location to certfile.crt>
ssl_options.keyfile = <location to private.key>
All of the above can be automated and verified via a script that I wrote for this
https://gist.github.com/skewl84/a72321379a65c4c5cfd447f8806b5188
The script above does
Check if OpenSSL is installed else download to generate Self-Signed certificate if neccessary
Modify RabbbitMQ config to enable TLS
Use OpenSSL to Test TLS after it has been enabled on the RabbitMQ

Related

Amazon Secrets Manager, Java 7, and CipherSuites

I am trying to get AWS Secrets Manager to work on an older Java 7 platform. Unfortunately we're locked on Java 7 for now.
The issue I have is that Java 7 had some security issues with SSL, and most modern Java platforms are using newer cipherSuites. Thus I get the error
javax.net.ssl.SSLHandshakeException: No negotiable cipher suite
In other interfaces I've been able to solve the issue by doing an .setEnabledCipherSuites on the SSL socket.
The problem here is that the Secrets Manager client does not expose the socket (AFAICT), nor does it expose the SocketFactory. I've been trying to create a new SSLContext wrapping the stock SSLContext that will provide a custom SocketFactory but creating and installing a custom SSLContext has proven to be quite complicated.
Before I end up pulling out the rest of my hair, is there an easier way to do this?
AWS Secrets Manager uses Apache HTTP Client (httpclient-4.5.7) under the covers. Is there a static way of hooking the Apache client with a custom Socket, SocketFactory, or SSLContext? One that does not require access to the HTTPClient object (which is not exposed either).
After much head banging I came up with the following code:
final String ciphers[] =
{ "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_AES_128_CBC_SHA256",
"TLS_RSA_WITH_AES_256_CBC_SHA256" };
final String[] protocols = new String[]
{ "TLSv1.2" };
// create and initialize an SSLContext for a custom socket factory
final SSLContext sslcontext = SSLContext.getInstance("SSL");
sslcontext.init(null, null, new SecureRandom());
// and here's our SocketFactory
final SSLConnectionSocketFactory secureSocketFactory = new SSLConnectionSocketFactory(sslcontext, protocols,
ciphers, new DefaultHostnameVerifier());
// Create a custom AWS Client Configuration with our socket factory
final ClientConfiguration cc = new ClientConfiguration();
final ApacheHttpClientConfig acc = cc.getApacheHttpClientConfig();
acc.setSslSocketFactory(secureSocketFactory);
// Create a Secrets Manager client with our custom AWS Client Configuration
final AWSSecretsManager client = AWSSecretsManagerClientBuilder //
.standard() //
.withRegion(region) //
.withClientConfiguration(cc) //
.build();
client is then used for the requests.

Managed CSOM on Sharepoint 201. Could not create SSL/TLS secure channel

I have a Windows Server 2016 VM and Visual Studio 2017 Community Edition. I am writing a simple script just to check the connectivity with the Sharepoint 2013. The Sharepoint Server is NOT installed on the VM, it is somewhere within the intranet.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.SharePoint.Client;
using System.Security;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
string siteUrl = "https://xxx.yyy.org:443";
ClientContext clientContext = new ClientContext(siteUrl);
Web site = clientContext.Web;
List documents = site.Lists.GetByTitle("Documents");
//Prepare the request
clientContext.Load(site);
//Submit the Request
clientContext.ExecuteQuery();
Console.ReadKey();
}
}
}
But I am getting this exception:
System.Net.WebException occurred
HResult=0x80131509
Message=The request was aborted: Could not create SSL/TLS secure channel.
Source=System
StackTrace:
at System.Net.HttpWebRequest.GetResponse()
at Microsoft.SharePoint.Client.SPWebRequestExecutor.Execute()
at Microsoft.SharePoint.Client.ClientContext.GetFormDigestInfoPrivate()
at Microsoft.SharePoint.Client.ClientContext.EnsureFormDigest()
at Microsoft.SharePoint.Client.ClientContext.ExecuteQuery()
at ConsoleApp1.Program.Main(String[] args) in C:\Users\AdminDD\source\repos\ConsoleApp1\ConsoleApp1\Program.cs:line
I've read this thread and I signed in through IE. The certificate of the browser seems valid and the problem remains. Is there any suggestion on how to solve this ?
I had the exact same issue.
Check your project .Net Version. It worked after upgrading from 4.5 --> 4.6
you should do a request on your url https://yoursite/ absolute url only, nothing more
$response = Invoke-WebRequest -Verbose -URI $anUrl -CertificateThumbprint $CertificateThumbprint -UseDefaultCredentials -SessionVariable websession -ErrorAction:Stop
get cookie authentification in reponse, and then add it in your csom query
$request.ClientCertificates.Add($global:cert)
$request.CookieContainer = New-Object System.Net.CookieContainer
$c3 = New-Object System.Net.Cookie($global:cookieName3, $global:cookieVal3, "/", $global:cookieDomaine);
$request.CookieContainer.Add($c3);
here is a working sample

use tlsv1.2 in mobilefirst javascript http adapter

I asked a similar question before and was able to use tlsv1.2 in java adapter, now I need to be able to do the same thing but in a javascript http adapter. Anyone know how to force the adapter to use tlsv1.2? This is Mobilefirst 7.0 on a mac.
Here is a code snippet of how to do it in java adapter:
SSLContext context = SSLContext.getInstance("TLSv1.2");
context.init(null, null, null);
HttpClientBuilder clientBuilder = HttpClientBuilder.create().setSslcontext(context);
CloseableHttpClient httpClient = clientBuilder.build();
HttpGet request = new HttpGet(new URI(baseURL));
request.addHeader("Authorization", authHeader);
CloseableHttpResponse httpResponse = httpClient.execute(request);
json = EntityUtils.toString(httpResponse.getEntity());
Don't see a way to do this in the http adapter:
function getProbes(appName) {
var input = {
method : 'get',
returnedContentType : 'json',
path : "greenspot-web/rest/category/category/" + appName,
body : {
contentType : 'application/json',
content : ''
}
};
input.headers = headers;
var res = WL.Server.invokeHttp(input);
Last fall, work was done to add TLS V1.2 support when running with WebSphere, so installing the latest fix pack for 7.0 and up should enable you to do this
To write your JavaScript adapter to use TLS V1.2, the key issue is to use the WebSphere JSSEHelper API instead of the Apache HTTP client. The Apache client cannot handle the WebSphere SSL context that is required for force the version switch. Using JSSEHelper allows the adapter to correctly handle the WebSphere trust store and set the protocol.
Here are some links:
WebSphere JSSEHelper documentation
Programmatically specifying an outbound SSL configuration using JSSEHelper API
Does this help?
There is no way to do this with the JavaScript HTTP adapter. Maybe by invoking Java code from the JavaScript adapter? Could be. Perhaps this will help guide you to the right place: https://developer.ibm.com/mobilefirstplatform/documentation/getting-started-7-1/foundation/server-side-development-category/javascript-adapters/using-java-adapters/

Can I self-host an HTTPS service in WCF without the certificate store and without using netsh http add sslcert?

I am attempting to host a service that serves up basic web content (HTML, javascript, json) using a WebHttpBinding with minimal administrator involvement.
Thus far I have been successful, the only admin priviledges necessary are at install time (register the http reservation for the service account and to create the service itself). However, now I am running into issues with SSL. Ideally I would like to support a certificate outside the windows certificate store. I found this article - http://www.codeproject.com/KB/WCF/wcfcertificates.aspx - which seems to indicate you can specify the certificate on the service host, however at runtime navigating a browser to https://localhost/Dev/MyService results in a 404.
[ServiceContract]
public interface IWhoAmIService
{
[OperationContract]
[WebInvoke(
Method = "GET",
UriTemplate = "/")]
Stream WhoAmI();
}
public class WhoAmIService : IWhoAmIService
{
public Stream WhoAmI()
{
string html = "<html><head><title>Hello, world!</title></head><body><p>Hello from {0}</p></body></html>";
html = string.Format(html, WindowsIdentity.GetCurrent().Name);
WebOperationContext.Current.OutgoingResponse.ContentType = "text/html";
return new MemoryStream(Encoding.UTF8.GetBytes(html));
}
}
static void Main(string[] args)
{
ServiceHost host = new ServiceHost(typeof(WhoAmIService), new Uri("https://localhost:443/Dev/WhoAmI"));
host.Credentials.ServiceCertificate.Certificate = new X509Certificate2(#"D:\dev\Server.pfx", "private");
WebHttpBehavior behvior = new WebHttpBehavior();
behvior.DefaultBodyStyle = WebMessageBodyStyle.Bare;
behvior.DefaultOutgoingResponseFormat = WebMessageFormat.Json;
behvior.AutomaticFormatSelectionEnabled = false;
WebHttpBinding secureBinding = new WebHttpBinding();
secureBinding.Security.Mode = WebHttpSecurityMode.Transport;
secureBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
ServiceEndpoint secureEndpoint = host.AddServiceEndpoint(typeof(IWhoAmIService), secureBinding, "");
secureEndpoint.Behaviors.Add(behvior);
host.Open();
Console.WriteLine("Press enter to exit...");
Console.ReadLine();
host.Close();
}
If I change my binding security to none and the base uri to start with http, it serves up okay. This post seems to indicate that an additional command needs to be executed to register a certificate with a port with netsh (http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/6907d765-7d4c-48e8-9e29-3ac5b4b9c405/). When I try this, it fails with some obscure error (1312).
C:\Windows\system32>netsh http add sslcert ipport=0.0.0.0:443 certhash=0b740a29f
29f2cc795bf4f8730b83f303f26a6d5 appid={00112233-4455-6677-8899-AABBCCDDEEFF}
SSL Certificate add failed, Error: 1312
A specified logon session does not exist. It may already have been terminated.
How can I host this service using HTTPS without the Windows Certificate Store?
It is not possible. HTTPS is provided on OS level (http.sys kernel driver) - it is the same as providing HTTP reservation and OS level demands certificate in certificate store. You must use netsh to assign the certificate to selected port and allow accessing the private key.
The article uses certificates from files because it doesn't use HTTPS. It uses message security and message security is not possible (unless you develop your own non-interoperable) with REST services and webHttpBinding.
The only way to make this work with HTTPS is not using built-in HTTP processing dependent on http.sys = you will either have to implement whole HTTP yourselves and prepare new HTTP channel for WCF or you will have to find such implementation.

I'm having trouble launching my WCF service using a console application. What can be wrong?

Here's my code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using BankServiceClient.BankServiceReference;
namespace BankServiceClient
{
class Program
{
static void Main(string[] args)
{
Uri baseAddress = new Uri("http://localhost:8000/Simple");
Type instanceType = typeof(BankServiceReference.BankClient);
ServiceHost host = new ServiceHost(instanceType,baseAddress);
using (host)
{
Type contractType = typeof(BankServiceReference.IBank);
string relativeAddress = "BankService";
host.AddServiceEndpoint(contractType, new BasicHttpBinding(), relativeAddress);
host.Open();
Console.WriteLine("Press <ENTER> to quit.");
Console.ReadLine();
host.Close();
}
/*
* Consuming a WCF Service and using its method.
*/
//IBank proxy = new BankClient();
//double number = proxy.GetBalance(1234);
//Console.WriteLine(number.ToString());
//Console.ReadLine();
}
}
}
First, a couple of questions:
The 'baseAddress' attribute, what exactly is it? When I launched my service using the default F5 (no console application) the service launched on a random port on localHost. How can I write in an exact number and expect it to go there? Confused at this one.
What is the relativeAddress attribute? It says BankService but what should I write in that attribute? Confused at this one as well.
Here's the exact error message I get when I try to run this Console application:
HTTP could not register URL
http://+:8000/Simple/. Your process
does not have access rights to this
namespace (see
http://go.microsoft.com/fwlink/?LinkId=70353
for details).
First is your client project set to be the start up project?
And to answer your questions.
1) baseAddress (URI Class) is the base address for your hosted service. I am thinking you are launching some other project.
2) You have two options on configuring endpoints(reference). Relative and Absolute. The way you did it will take your base and appends your relative -> http://localhost:8000/Simple/BankService
Lastly to fix your hosting issue see this SO link:
WCF ServiceHost access rights