Not able to make mqtt call in browser - aws-iot

I am using below plugin to make mqtt call
aws-iot-device-sdk-browser
On trying to set protocol mqtt or mqtts, it is failing to connect saying as invalid options.
If we set protocol to wss, it is connecting to with out aws certificates.
To keep it secure need to pass cert files.
Can i make mqtt call from browser or wss call with making sure to accept cert files
awsIot.device({
clientId: clientId,
accessKeyId: accessKeyId,
//privateKey: privateKey,
//clientCert: clientCert,
//caCert: caCert,
secretKey: secretKey,
region: region,
baseReconnectTimeMs: 3000,
poty: port,
protocol: 'wss',
host: host,
debug: true
});
Can anyone please help to make mqtt call or make secure connection from wss using aws-iot-device-sdk-browser is secure with cert files

Related

https://www.example.com and https://example.com socket.io connection problem

How do I get both https://example.com and https://www.example.com for endpoints to connect?
socket.io connect no problem at htttps://example.com
but not https://www.example.com
my server looks like
const server = http.createServer(app);
const io = socketIo(server, {
cors: {
origin: "https://www.example.com:3000",
methods: ["GET", "POST"],
allowedHeaders: ["my-custom-header"],
credentials: true
}});
and my client endpoint looks like this
const ENDPOINT = 'https://example.com/';
Configure your DNS to point both example.com and www.example.com to the same host IP address and then support both domains with your cors configuration. Then, either URL will go to the same host.
You can avoid cors entirely if you configure socket.io to start immediately with a webSocket, not with the http polling that it usually starts with. You can do that in the client by adding the transports: ['websocket'] option to the client connect.
And, your custom header was probably blocking CORs and requiring pre-flight permission. CORs has two levels, simple and not-simple. When you add a custom header, you force CORs into the not-simple route where it requires preflight which is probably more than the built-in socketio cors features will handle.

Websocket disconnects immediately after handshake (guacamole)

Forgive bad formatting as it is my first question on here, and thanks in advance for reading!
I am currently writing a remote web application that utilises Apache Guacamole to allow RDP, VNC, and SSH connections. The components I am using are:
Django for backend server - API calls (database info) and Guacamole Websocket Transmissions;
I am using Pyguacamole with Django consumers to handle Guacamole Server communication;
Reactjs for frontend and proxy;
Nginx for reverse proxy;
All this is hosted on a Centos Stream 8 vm
Basically, my websocket has trouble communicating through a proxy. When I run the application without a proxy (firefox in centos running localhost:3000 directly), the guacamole connection works! Though this is where the application communicates directly with the Django server on port 8000. What I want is for the react application to proxy websocket communications to port 8000 for me, so my nginx proxy only has to deal with port 3000 for production.
Here is the code I have tried for my react proxy (src/setupProxy.js):
const { createProxyMiddleware } = require('http-proxy-middleware');
let proxy_location = '';
module.exports = function(app) {
app.use(createProxyMiddleware('/api', { target: 'http://localhost:8000', changeOrigin: true, logLevel: "debug" } ));
app.use( createProxyMiddleware('/ws', { target: 'ws://localhost:8000' + proxy_location, ws: true, changeOrigin: true, logLebel: "debug" } ));
};
I have also already tried with http://localhost:8000 for the ws target url. Also, the api proxy works, but I am unsure if the ws proxy works. After making a websocket request, the consumer does a guacamole handshake, but disconnects the websocket before it can send anything back.
Also, the HPM output shows that it does try upgrading to websocket, but the client disconnects immediately.
Do let me know if you require more information.
I managed to find what was wrong, it was a small mistake though I felt the need to update this thread.
Basically, in consumers I used accept() instead of websocket_accept(), receive() instead of websocket_receive(), and so on. Careless mistake on my part, but hope this helps someone out!

React & AWS IoT MQTT over WSS - "connection lost - will attempt reconnection in x seconds"

I am unable to successfully connect to an AWS IoT device via MQTT using websockets with authenticated cognito users.
I am using aws-iot-device-sdk in a react application.
Upon trying to connect, the following debug logs get printed to the web browser console:
canonical request: GET
/mqtt
X-Amz-Algorithm=<removed>
SignedHeaders=host
host:<removed>.iot.us-east-1.amazonaws.com
host
<removed>
index.js:102 hashed canonical request: <removed>
index.js:111 string to sign: <removed>
<removed>
20210618/us-east-1/<removed>
index.js:117 signing key: <removed>
index.js:125 signature: <removed>
index.js:137 url: wss://<removed>.iot.us-east-1.amazonaws.com/mqtt?X-Amz-Algorithm=<removed>
index.js:630 using websockets, will connect to 'wss://<removed>.iot.us-east-1.amazonaws.com/mqtt?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=....
index.js:781 connection lost - will attempt reconnection in 128 seconds...
JS Code To Create the Device and Connect:
var device = awsIot.device({
clientId : <unique client id>,
region : 'us-east-1',
debug : true,
host : '<removed>.iot.us-east-1.amazonaws.com',
protocol : 'wss',
accessKeyId : accessKeyId,
secretKey : secretAccessKey,
sessionToken : sessionToken
});
device.on('connect', function(err, data) {
if (err) {
console.log(`Connection Error: ${err}`);
return;
}
console.log('connected');
})
Authenticated IoT AWS Roles:
"Action": [
"iot:Connect",
"iot:Subscribe",
"iot:Publish",
"iot:Receive"
],
"Resource": [
"arn:aws:iot:us-east-1:<removed>:client/cognito_user_*",
"arn:aws:iot:us-east-1:<removed>:topic*/resource/*"
]
I am able to connect to the MQTT broker using certs with MQTT.fx but the application I am working on requires authenticated cognito users to be able connect to the broker. Any insight would be appreciated.
Solved this problem.
The problem I was having was the Cognito User did not have a necessary certificate associated with it in order to access the resource.

How can I connect my Reactjs Web App to a secured MQTT broker?

I have a reactjs web application that needs to connect to a secured mqtt broker.
The web application is deployed in AWS elastic beanstalk and is using HTTPS. I already have a secured MQTT broker but when trying to connect my web app to the mqtt broker I have this error:
Error in connection establishment: net::ERR_CERT_AUTHORITY_INVALID
I am using MQTTjs package. I already have certificate for both server and client side.
Here's my code:
var client = mqtt.connect('wss://[ipaddress]:8884');
I also tried this code:
var mqtt = require('mqtt');
var fs = require('fs');
var path = require('path');
var CERT = fs.readFileSync(path.join(__dirname, './ca.crt'));
var KEY = fs.readFileSync(path.join(__dirname, './ca.key'));
var options = {
rejectUnauthorized: true,
port: 8884,
host: ipaddress,
protocol: 'mqtts',
ca: CERT,
keyPath: KEY,
certPath: CERT
}
But the error for this code is:
Uncaught TypeError: fs.readFileSync is not a function
You can't load certificates from disk in the browser. So the second version of the code just won't work.
You need to add both the CA and the Client certificate to your browsers certificate store.
The browser should then use the CA cert to validate the broker and should then pick the correct client cert to present to the broker as identification.

create-react-app proxy request fails with 404 when backend is hosted on Azure

I am having a bit of trouble setting up my create-react-app application to proxy requests to my test hosting on Microsoft azure. I have set up the proxy in my app's package.json as follows:
"proxy":{
"/api/*":{
"target":"https://mytestbackend.azurewebsites.net",
"secure":false
}
}
I have set up an axios request to be sent to the backend server on azure. It is in a stand-alone .js which I call from one of my react application's events. It looks like this:
import axios from 'axios';
const login = async (username, password) => {
console.log("Username to send is:"+username);
console.log("password to send is:"+password);
let response = await axios.post('/api/user/login', {username:username,password:password});
console.log(response);
};
export {login};
The problem can't be in my react components, because those two console.log() call show that the values entered are being recieved. If I remove the "secure":false setting from package.json, request fails with Http Error: 500. But if I use the secure setting, it fails with a 404 page. Can someone please shed a little light on what am I doing wrong? Can I only use the proxy on "localhost"? The documentation suggests otherwise. Any help is greatly appreciated.
I have verified that CORS is enabled for the domain on which the dev server is running on the Azure Management Portal. And if I do the request by using the backend's URL directly (that is, not using the create-react-app proxy), it works. The problem must be something in the way the proxy is configured.
The response text for the HTTP Errpr 500 which happens when not using secure is :
Proxy error: Could not proxy request /api/user/login from localhost:3000 to https://mytestbackend.azurewebsites.net (undefined).
Additional info: I have also tested by running my Backend locally on my development machine. The error message occurs but the "undefined" in the parenthesis says "UNABLE_TO_VERIFY_LEAF_SIGNATURE". If using "secure: false, I can call the login endpoint successfully, but calls to other endpoints which require authentication fail because the cookie is not sent by axios.
Doing:
curl -v https://mytestbackend.azurewebsites.net/api/user/login
Has this output:
* SSLv3, TLS handshake, Client hello (1):
* SSLv3, TLS handshake, Server hello (2):
* SSLv3, TLS handshake, CERT (11):
* SSLv3, TLS alert, Server hello (2):
* SSL certificate problem: unable to get local issuer certificate
* Closing connection #0
curl: (60) SSL certificate problem: unable to get local issuer certificate
More details here: http://curl.haxx.se/docs/sslcerts.html
curl performs SSL certificate verification by default, using a "bundle"
of Certificate Authority (CA) public keys (CA certs). If the default
bundle file isn't adequate, you can specify an alternate file
using the --cacert option.
If this HTTPS server uses a certificate signed by a CA represented in
the bundle, the certificate verification probably failed due to a
problem with the certificate (it might be expired, or the name might
not match the domain name in the URL).
If you'd like to turn off curl's verification of the certificate, use
the -k (or --insecure) option.
create-react-app use WebPackDevServer which uses https://github.com/chimurai/http-proxy-middleware#options
So you can use all the options from the same
Now one key header that is import in such cases of externally hosted server is host. This at times can issues if not correct, see below example
Websocket works on EC2 url but not on ElasticBeanstalk URL
Next is the cookies might be associated with localhost, i checked and they should go without any modification. But you might want to use the cookieDomainRewrite: "" option as well
So the final config I would use is below
"proxy":{
"/api/*":{
"target":"https://mytestbackend.azurewebsites.net",
"secure":false,
"headers": {
"host": "mytestbackend.azurewebsites.net"
},
"cookieDomainRewrite": ""
}
}
Also on your client you want to use the withCredentials:true
let userinfo =await axios.get('/api/secured/userinfo',{withCredentials:true});
Create react app http-proxy-middleware, and should support the full set of options.
Some things I would try:
The path to match may be /api/** instead of /api/* if you want to nest multiple levels deep (eg. for /api/user/login)
You may need to add changeOrigin: true if you're proxying to something remotely (not on localhost)
You will likely want to keep secure: false as you aren't running localhost with https.
So in total, I would try
"proxy":{
"/api/**": {
"target": "https://mytestbackend.azurewebsites.net",
"secure": false,
"changeOrigin": true
}
}
After days of trying unsuccessfully to do this, I finally found a setup that works. Proxy is configured like this:
"proxy": {
"/api/user/login": {
"target": "https://localhost:44396",
"logLevel": "debug",
"secure": false
},
"/api/secured/userinfo": {
"target": "https://localhost:44396",
"secure": false,
"logLevel":"debug",
"secure":false
}
Request to both endpoints on the client have withCredientials:true
try {
await axios({
method:'post',
url:'/api/user/login',
withCredentials:true,
data:
{username:username,password:password}}
);
let userinfo =await axios.get('/api/secured/userinfo',{withCredentials:true});
return userinfo;
As you can see, I've moved to testing on my local dev machine. For whatever reason, this setup refuses to work on the azure-hosted backend. I would have preferred that it work as I originally intended, but at least now I can continue with my project.

Resources