Websocket connection to Rabbitmq over SSL through ELB - amazon-web-services

I have installed a rabbitmq server on my AWS instance that is behind a load balancer. I am currently able to connect, send and receive messages using js from an http url. However when I attempt the same feat from an https url I cannot successfully maintain a connection.
The following snippet shows the several tacks I have taken so far:
var ws = null;
if (window.location.protocol.indexOf("https") >= 0){
//1 ws = new WebSocket('wss://myelbpublicdns.com:15674/ws');
//2 ws = new WebSocket('wss://myec2publicdns.com:15674/ws');
//3 ws = new WebSocket('wss://myurl.com:15674/ws');
} else {
ws = new WebSocket('ws://' + awshost + ':15674/ws');
}
var client = Stomp.over(ws);
client.connect(username, password, on_connect, on_error, '/');
So the connect via ws: works perfectly fine.
Connect of option 1 to my ELB gets an SSL_ERROR_BAD_CERT_DOMAIN stating that the cert is for myurl.com, ok makes sense
Connect of option 2 to the ec2 instance gets an SSL_ERROR_RX_RECORD_TOO_LONG
Connect of option 3 directly to myurl.com gets a 400 bad request.
port 15674 is open on my ELB with an ssl cert attached.
All ideas on how to get my wss: connection working are appreciated!

Can you check the below and confirm so that I can try to help this one.
Is your certificate generated with AWS ACM?
Have you tried new WebSocket('wss://www.myurl.com:15674/ws');

Related

Socket.IO connects but is not emitting

To prefice this is a MERN socket.io application unfortunately I can't share my source since it's also connected to my aws account.
When on localhost my entire app works perfectly, however when deploying to AWS the back end fails. There are no errors, and when looking at the network it does show up with a successful link to socket.io. I've changed and updated the server for nginx so that it doesn't give off a bad gateway error. However after doing this there is no other error, I just can't register or login, client side validation seems to work however back end validation does not. If you'd like to take a look it's currently on http://3.145.119.85/
I currently connect to socket.io like so
const [socket] = useState(() => io(":8000"));
My server side instantiating
> const express = require("express");
const app = express();
const cors = require("cors");
const fileUpload = require("express-fileupload");
const PORT = process.env.PORT || 8000;
require("./components/mongoose.config");
app.use(cors());
app.use(fileUpload());
app.use(express.json(), express.urlencoded({extended:true}));
const server = app.listen(PORT, () => console.log("listening at port " + PORT));
require("./components/puzzleio.sockets") (server);
Any help would be much appreciated
Ensure that you have changed the host address from localhost to the real aws address. It seemed natural that socket.io should connect to the root from where you serve your content.
Since you are using AWS and after each restart you get different DNS address you have sent to the page where you are initializing the socket.io then correct the req.headers.host (using express-expose).

SignalR can't connect when deployed behind AWS EB

I am trying to use SignalR on an application hosted in AWS EB, with an application loadbalancer in front.
It works perfectly fine when I test it locally, but when deployed, the websocket can not establish a connection and returns:
"Error: Failed to start the connection: Error: There was an error with the transport."
And
"There was an error with the transport. at WebSocket.o.onerror [as __zone_symbol__ON_PROPERTYerror]"
I have tried adding a middleware at the very start of my pipeline, that logs if i get a request for my hub, and this works, so I dont think it is the load balancer or anything AWS Related.
If i call the URL with Postman websocket, I get a status code 400.
I have followed the MS guide and added the configuration for JWT auth
jwtTokenOptions.Events = new JwtBearerEvents
{
OnMessageReceived = context =>
{
var accessToken = context.Request.Query["access_token"];
// If the request is for our hub...
var path = context.HttpContext.Request.Path;
if (!string.IsNullOrEmpty(accessToken) &&
(path.StartsWithSegments("/signalr")))
{
// Read the token out of the query string
context.Token = accessToken;
}
return Task.CompletedTask;
}
};
And as I said, it works fine locally. Any suggestions are most welcome
I fixed this by enabling web sockets for the IIS on the eb instance.
I did this by creating an eb extension with the following command
commands:
01_install_websockets_feature:
command: "%SystemRoot%\\System32\\dism.exe /online /enable-feature /featurename:IIS-WebSockets"
ignoreErrors: true

SignalR returns "Connection ID required" when ran in an AWS ECS container

I am trying to get a .Net Core 3.1 SignalR Web API with an Angular front end to work with websockets.
The code works perfectly fine when ran locally, either from within in the IDE or via docker run. However, once the code gets deployed to an ECS instance in AWS behind an API Gateway the web sockets refuse to connect.
I setup my mappings like so:
app.UsePathBase("/ui");
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
"default",
"{controller}/{action=Index}/{id?}")
.RequireCors(PolicyName);
endpoints.MapHub<SessionHub>("/ws/session");
endpoints.MapHub<SessionsHub>("/ws/sessions");
});
And on the client I connect to the hub like so:
this.sessionsHubConnection = new HubConnectionBuilder()
.withUrl(`${window.origin}/ws/sessions`, {
skipNegotiation: true,
transport: HttpTransportType.WebSockets,
accessTokenFactory: () => this.getAccessToken()
})
.withAutomaticReconnect()
.build();
The following Fiddler trace shows the initial HTTP request to initialize the websocket connection and the error being returned by kestrel.
I tweaked my web socket middleware for handling the access token to also Console.Write some additional debugging statements that I think might prove insightful:
public async Task Invoke(HttpContext httpContext)
{
var request = httpContext.Request;
Console.WriteLine($"Starting connection id: {httpContext.Connection.Id}");
// web sockets cannot pass headers so we must take the access token from query param and
// add it to the header before authentication middleware runs
if (request.Path.StartsWithSegments("/ws", StringComparison.OrdinalIgnoreCase)
&&
request.Query.TryGetValue("access_token", out var accessToken))
{
request.Headers.Add("Authorization", $"Bearer {accessToken}");
}
try
{
var sb = new StringBuilder();
sb.AppendLine($"Connection Id: {httpContext.Connection.Id}");
Console.WriteLine(sb.ToString());
await _next(httpContext);
sb = new StringBuilder();
sb.AppendLine($"Status code {httpContext.Response.StatusCode}"); <-- this line
sb.AppendLine($"Connection Id: {httpContext.Connection.Id}"); <-- and this line
Console.WriteLine(sb.ToString());
}
catch (Exception e)
{
Console.WriteLine(e.Message);
Console.WriteLine(e.StackTrace);
throw;
}
}
And in the AWS logs you can see that the connection Id is present but is being ignored by the EndpointMiddleware(?) for some reason.
Any idea what could be causing this? Two ideas I have yet to be able to rule out are:
The HTTP/S termination at our API gateway is confusing Kestrel since the browser client is building the socket request under HTTPS, but as far as Kestrel is concerned everything is communicating over HTTP?
app.UsePathBase("/ui"); is confusing Kestrel and all the web socket paths should actually be /ui/ws/session?

Frontend code directly access http instead of https and cause mix content error

As an academic project, we host our web application with Amazon S3 (For Angular) and Apache Server (For Django). We have made both sites https (for both frontend and backend). We can access the backend successfully on our localhost using ng serve. However, for the production site, it always gives us a mixed content error (try to connect HTTP for our backend). But we actually put https in our angular code. Are there any suggestions on that?
Attached is our frontend code
export class AuthenticationService {
private ip: string = 'https://sunrise.99jhs.com';
authenticate(username: string, password: string) {
const headers = new HttpHeaders();
headers.append('Access-Control-Allow-Origin', '*');
return this.http.post<any>(this.ip + '/api-token-auth/', {username, password}, {headers});
}
Attached is error message
Mixed Content: The page at 'https://sunrise.4jhs.com/' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint 'http://sunrise.99jhs.com/api-token-auth'. This request has been blocked; the content must be served over HTTPS.
We build the angular code using
ng build --prod
Try not to specificity the protocol at all
private ip: string = '//sunrise.99jhs.com';
The problem is not with the private IP value. It specifies the https protocol.
The problem is with this code:
return this.http.post(this.ip + '/api-token-auth/', {
The URL resulting from that code is the problem. If you notice, this is the URL being referenced in the error message.
Add an https specifier there. That should resolve the issue.

HTTP error code: 302 when calling https webservice

I am trying to call a SOAP RPC style web service and getting the following error:
Exception in thread "main" com.sun.xml.internal.ws.client.ClientTransportException: The server sent HTTP status code 302:
This is a https web service and I have imported the certificate into cacerts thru browser but getting same result. Please note that, I can consume a REST webservice from the same machine without importing the certificate.
What I am missing when calling a SOAP service? Is it my client issue or something need to be done on the server side. I have access to the server.
HTTP status code 302 is a redirect, and so is unlikely due to a certificate problem. My initial guess is that you need to add a / (or remove it) from your URL. Some http server frameworks will redirect when a resource does not end in a /, so, instead of:
GET /myRpcEndpoint
Try
GET /myRpcEndpoint/
The other possibility is that this resource requires authentication and the server is redirecting you to a login page. If you want to know what is going on (and not guess), take a look a the the response headers for the 302. There will be a Location header telling you where the server wants you to go instead.
Had a similar issue where client code would receive a HTTP 302 error code when communicating with https and would work fine when communicating with http. In client code,you might need to specify the endpoint address on the request context using the BindingProvider.ENDPOINT_ADDRESS_PROPERTY property. Following the JAX-WS paradigm, the example below should work.
Please note that only the BindingProvider.ENDPOINT_ADDRESS_PROPERTY needs to be defined, the rest of your code should remain the same.
public static void main(String args[]) throws {
ObjectFactory factory = new ObjectFactory();
GetProducts_Service service = new GetProducts_Service();
GetProducts getProducts = service.getGetProductsPort();
final BindingProvider getProductsBP = (BindingProvider) getProducts;
getProductsBP.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY,
"https://example.server.net/ExampleServicesWar/GetProducts");
GetProductsRequest request = factory.createGetProductsRequest();
GetProductsResponse response=getProducts.getProducts(request);
List<Product> products=response.getProducts();
}
All you have to is to use correct end point url
((BindingProvider)port).getRequestContext().put(BindingProvider.
ENDPOINT_ADDRESS_PROPERTY, "https://yourservice");
Need to import at the top:
import javax.xml.ws.BindingProvider;
port is Method call:
full source:
private static String getApplicationStatus(java.lang.String remoteAccessKey, java.lang.Integer responseId) {
net.quotit.oes._2010.ws.applicationstatusupdate.OASStatusUpdateService service = new net.quotit.oes._2010.ws.applicationstatusupdate.OASStatusUpdateService();
net.quotit.oes._2010.ws.applicationstatusupdate.IApplicationStatusUpdate port = service.getStatusUpdate();
((BindingProvider)port).getRequestContext().put(BindingProvider.
ENDPOINT_ADDRESS_PROPERTY, "https://servicename/basic");
return port.getApplicationStatus(remoteAccessKey, responseId);
}