Unable to Connect to Rabbit MQ - .net-core

I am using amazon service and created rabbitmq broker now from the DOT NET code i am trying to connect to this broker.
var factory = new ConnectionFactory
{
Uri = new Uri("amqps://it:Password#hostname:5671")
};
var connection = factory.CreateConnection();
I am struggle here to get connection getting below error :
None of the specified endpoints were reachable
at RabbitMQ.Client.ConnectionFactory.CreateConnection(IEndpointResolver endpointResolver, String clientProvidedName)

Update:
It seems your client wants to connect using TLS/SSL (your uri specifies the protocol "amqps" and the port 5671).
Try enabling TLS/SSL:
var factory = new ConnectionFactory {
UserName = userName,
Password = password,
VirtualHost = "/",
HostName = hostName,
Port = port,
Ssl = new SslOption
{ Enabled = true, // <--------
ServerName = hostName }
};
The (JVM based) guide shows how to configure the connection factory. It sets the credentials on the factory, not in the URI:
ConnectionFactory factory = new ConnectionFactory();
factory.setUsername(username); // <----------
factory.setPassword(password); // <----------
//Replace the URL with your information
factory.setHost("b-c8352341-ec91-4a78-ad9c-a43f23d325bb.mq.us-west-2.amazonaws.com");
factory.setPort(5671);
// Allows client to establish a connection over TLS
factory.useSslProtocol()
// Create a connection
Connection conn = factory.newConnection();
(This needs to be translated to the corresponding .NET code)

Related

Is it possible in a .NET Core application to retrieve a certificate from AWS Certificate Manager and use it in a HttpClient post?

My .Net core application makes a post request to an external web service using HttpClient. The external web service requires a certificate to validate against.
The certificates are installed in AWS and I have an ARN that points to the certificate.
Is it possible to get the certificate programitically from AWS Certificate Manager and use this in my HtppClient, for example this is the code I would use normally to add a certificate but I need to get it from AWS.
private HttpClientHandler HttpClientHandler()
{
var handler = new HttpClientHandler
{
ClientCertificateOptions = ClientCertificateOption.Manual,
SslProtocols = SslProtocols.Tls12
};
handler.ClientCertificates.Add(new X509Certificate2("cert.crt")); //TODO: fetch from AWS.
return handler;
}
So, it's possible.
I installed AWSSDK.Core and AWSSDK.CertificateManager from NuGet.
Then, I created a credentials file for AWS, see instructions from Amazon
https://docs.aws.amazon.com/cli/latest/userguide/cli-config-files.html
Next, I used the AmazonCertificateManagerClient to get the certificate.
AmazonCertificateManagerClient client = new AmazonCertificateManagerClient();
var certificates = client.GetCertificateAsync(arn).Result;
I then converted the certificate from string to bytes and then add to the handler.
var handler = new HttpClientHandler{
ClientCertificateOptions = ClientCertificateOption.Manual,
SslProtocols = SslProtocols.Tls12
};
byte[] toBytes = Encoding.ASCII.GetBytes(certificates.Certificate);
var cert = new X509Certificate2(toBytes);
handler.ClientCertificates.Add(cert);
var httpClient = new HttpClient(handler);
Obviously, not production worthy code, hope it helps.
As mentioned by Zack the accepted answer does not work. It does retrieve a certificate out of ACM but it is not usable as a client certificate for HttpClient because it has no private key.
As far as I can tell there is no way to get the private key out of ACM so I ended up putting it in SecretsManager and doing something like:
var certManagerClient = new AmazonCertificateManagerClient();
var awsCert = certManagerClient.GetCertificateAsync(arn).Result;
byte[] awsBytes = Encoding.ASCII.GetBytes(awsCert.Certificate);
var cert = new X509Certificate2(awsBytes);
var secretsManagerClient = new AmazonSecretsManagerClient();
var privateKey = secretsManagerClient.GetSecretValueAsync(new GetSecretValueRequest { SecretId = secretId }).Result.SecretString;
byte[] privateKeyBytes = Convert.FromBase64String(privateKey);
var privateKey = RSA.Create();
privateKey.ImportRSAPrivateKey(new ReadOnlySpan<byte>(privateKeyBytes), out _);
var certWithPrivateKey = cert.CopyWithPrivateKey(privateKey);
And then using certWithPrivateKey in my HttpClientHandler:
var handler = new HttpClientHandler { ClientCertificateOptions = ClientCertificateOption.Manual };
handler.ClientCertificates.Add(certWithPrivateKey);
If you use the AWS SDK you can get certificates using the AmazonCertificateManagerClient. See the AWS SDK documentation for details. (select Amazon.CertificateManager > AmazonCertificateManagerClient)

Firewall : Is inbound required for getting response while Outbound rule already there?

I developed one MVC web application which have Web APIs and hosted in Amazon Instance and one windows application for calling those APIs for getting response from that server.
Both Web and Windows applications are developed in asp.net framework 4.5 using c# language.
Windows application is installed in more than 200 client's system which are highly secure servers it selves with all Inbound ports blocked in Firewall.
I am using HttpWebRequest with BindIPEndPoint for calling Web APIs using configured TCP port range [default 7777-7786].
API calls working fine from Windows Application if there are Allow Inbound and Outbound firewall Rules.
But the problem is clients are not allowing me any Inbound Firewall rules, they only allowing Outbound Firewall rules for those port range And Windows application is not working with blocked inbound rules for those port range.
Is it must I need to open Inbound Rule in Firewall for those port range for calling/getting request/response to/from APIs ? If no need of Inbound Firewall rule then please explain Why ?
Below is the API call which use one static TCP port in my Windows Application :
try
{
string address = RevWatchURL;
address = address + "api/GetRevGuardLatestPatch";
HttpWebRequest httpWebRequest = WebRequest.Create(address) as HttpWebRequest;
httpWebRequest.ContentType = "text/json";
httpWebRequest.Method = "POST";
httpWebRequest.Timeout = 300000;
httpWebRequest.ServicePoint.BindIPEndPointDelegate =
new BindIPEndPoint(CommonValues.BindIPEndPointCallbackRGPatch);
string enRevGuardUniqueId =
Encryption.EncryptionTechnique(Convert.ToString(UniqueId), null, null);
using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
string json = "{\"UniqueId\":\"" + enRevGuardUniqueId + "\"}";
streamWriter.Write(json);
streamWriter.Flush();
streamWriter.Close();
}
try
{
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
returnVal = streamReader.ReadToEnd();
streamReader.Close();
httpResponse.Close();
}
}
catch (WebException ex)
{
}
finally
{
httpWebRequest.Abort();
}
Obj = JsonConvert.DeserializeObject<CommonValues.RevGuardPatchClass>(returnVal);
}
catch (Exception ex)
{
MessageBox.Show("Error", "API", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
}
BindIPEndPoint Method:
public static IPEndPoint BindIPEndPointCallbackRGPatch(ServicePoint servicePoint,
IPEndPoint remoteEndPoint, int retryCount)
{
return new IPEndPoint(IPAddress.Any, 7777);
}

Google Analytics Access Token - TLS 1.1+

I'm using C# to request an access token from Google:
string serviceAccountEmail = ConfigurationManager.AppSettings["analyticsServiceAccountEmail"].ToString();
string securityKey = ConfigurationManager.AppSettings["analyticsSecurityKeyLocation"].ToString();
string password = ConfigurationManager.AppSettings["analyticsSecurityPassword"].ToString();
var certificate = new X509Certificate2(securityKey, password, X509KeyStorageFlags.Exportable);
var scopes = new List<string> { "https://www.googleapis.com/auth/analytics.readonly", "https://www.googleapis.com/auth/analytics" };
ServiceAccountCredential credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
Scopes = scopes
}.FromCertificate(certificate));
Task<bool> task = credential.RequestAccessTokenAsync(CancellationToken.None);
task.Wait();
if (!task.Result || credential.Token == null || string.IsNullOrEmpty(credential.Token.AccessToken))
{
throw new Exception("Failed to get token from Google");
}
return credential.Token.AccessToken;
I had to disable TLS 1.0 for PCI compliance. Since I have done that, this code is breaking with the following error:
One or more errors occurred.: An error occurred while sending the
request.: The underlying connection was closed: An unexpected error
occurred on a receive.: The client and server cannot communicate,
because they do not possess a common algorithm
Any suggestions as to how I can make the call using TLS 1.1+?
It has to be done in Application_start through Global.asax:
Please read this before you make change : How do I disable SSL fallback and use only TLS for outbound connections in .NET? (Poodle mitigation)
The way to do it is :
System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 Or SecurityProtocolType.Tls11 Or SecurityProtocolType.Tls12
This will turn on communication support for SSL3, falling back to TLS 1.1 or TLS 1.2 as applicable.

Can you connect to a hub that is located on a different host / server?

Let's say I have a website on www.website.com. My SaaS with signalr is hosted on www.signalr.com.
Can I connect to www.signalr.com signalr server from www.website.com ?
Instead of :
var connection = $.hubConnection();
var contosoChatHubProxy = connection.createHubProxy('contosoChatHub');
Something like :
var connection = $.hubConnection();
var contosoChatHubProxy = connection.createHubProxy('www.signalr.com/contosoChatHub');
Short answer: Yes - As the SinalR documentation exemplifies.
The first step is enabling cross domain on your server. Now, you can either enable calls from all domains, or only from specified ones. (See this SO post on this matter)
public void Configuration(IAppBuilder app)
{
var policy = new CorsPolicy()
{
AllowAnyHeader = true,
AllowAnyMethod = true,
SupportsCredentials = true
};
policy.Origins.Add("domain"); //be sure to include the port:
//example: "http://localhost:8081"
app.UseCors(new CorsOptions
{
PolicyProvider = new CorsPolicyProvider
{
PolicyResolver = context => Task.FromResult(policy)
}
});
app.MapSignalR();
}
The next step is configuring the client to connect to a specific domain.
Using the generated proxy(see the documentation for more information), you would connect to a hub named TestHub in the following way:
var hub = $.connection.testHub;
//here you define the client methods (at least one of them)
$.connection.hub.start();
Now, the only thing you have to do is specify the URL where SignalR is configured on the server. (basically the server).
By default, if you don't specify it, it is assumed that it is the same domain as the client.
`var hub = $.connection.testHub;
//here you specify the domain:
$.connection.hub.url = "http://yourdomain/signalr" - with the default routing
//if you routed SignalR in other way, you enter the route you defined.
//here you define the client methods (at least one of them)
$.connection.hub.start();`
And that should be it. Hope this helps. Best of luck!

Web request to 'https://accounts.google.com/o/oauth2/token' failed. No connection could be ...target machine actively refused it 173.194.70.84:443

I am building an application to fetch data via google analytics. For that purpose I have created a service account information from Google API console and in my .NET webform application successfully able to fetch data via following code:
string clientEmailId = ConfigurationManager.AppSettings.Get("clientEmailId");
string keyFile = AnalyticsKeyFileInitialPath + ConfigurationManager.AppSettings.Get("keyFile");
string keyPass = ConfigurationManager.AppSettings.Get("keyPass");
var desc = GoogleAuthenticationServer.Description;
var key = new X509Certificate2(keyFile, keyPass, X509KeyStorageFlags.Exportable);
var client = new AssertionFlowClient(desc, key) { ServiceAccountId = clientEmailId, Scope = scopeUrl };
var auth = new OAuth2Authenticator<AssertionFlowClient>(client, AssertionFlowClient.GetState);
var gas = new AnalyticsService(new BaseClientService.Initializer
{
Authenticator = auth
});
//auth.LoadAccessToken();
var accounts = gas.Management.Accounts.List().Fetch();
Now I am calling same code via WCF service but getting following error
Exception Message: Unable to connect to the remote server
Inner Exception: Web request to 'https://accounts.google.com/o/oauth2/token' failed.
Inner Exception: No connection could be made because the target machine actively refused it 173.194.70.84:443
Any idea what I could be doing wrong?

Resources