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

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.

Related

ShinyProxy 2.6.1 access with Identity Server

I followed the instruction from this website to add the authentication with Identity Server. The configuration is quite simple
proxy:
title: Open Analytics Shiny Proxy
port: 8080
authentication: openid
openid:
auth-url: https://identityserverurl/connect/authorize
token-url: https://identityserverurl/connect/token
jwks-url: https://identityserverurl/.well-known/openid-configuration/jwks
logout-url: https://identityserverurl/Account/Logout?return=http://yourshinyproxy:8080/
client-id: ShinyProxy
client-secret: secret
scopes: [ "openid", "profile", "roles" ]
username-attribute: aud
roles-claim: role
And the authentication seems working. When I add the access-groups to display only the app for a particular role, it doesn't work
specs:
- id: 01_hello
display-name: Hello Application
description: Application which demonstrates the basics of a Shiny app
container-cmd: ["R", "-e", "shinyproxy::run_01_hello()"]
container-image: openanalytics/shinyproxy-demo
container-network: sp-example-net
access-groups: 200122-user
The same code is working with the version 2.4.3 of ShinyProxy.
Is there anything I missed for this configuration in the ShinyProxy 2.6.1?

Not able to make mqtt call in browser

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

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.

Keycloak 403 (Forbidden) on Keycloak.loadUserProfile()

I am new to Keycloak. I have tried to get the user information using below code:
keycloakAuth.loadUserProfile().success(function(profile) {
debugger
console.log(profile);
}).error(function(res) {
debugger
console.log('Failed to load profile');
});
installation json is :
{
"realm": "CheckRealm",
"realm-public-key": "MIIBIjASDFJJK677132HJJAOCAQ8AMIIBCgKCAQEAgo4deAfr8BeqWOiCsddwMtH5nh8EK2cKIeInpt7LnoCyMsGj1HTP835HpslOURrR6Bgc42V7r6J/MIHqx3+KESTqpcQSe9ll6eUjzaMbIX2GPmy9OnviH6srUgOlDAKhL+/SDh/iv8RfErAPO9cxnoBWUUTyfyes1YRn34KILBdHZoaWk5mteJx9aV4bfA5tGTT6aF8o1NkCX1OUfXiaAD5sqKZV5vbI+QsOUsNshvGfE5JR2EpwZbWH/vRQVusxLURjC51v96ieQ8zUME5LwAQ0TgZcspHTb4Y+KuYRTuDQKuxRUYFeNbvqUGeT2s2sHMmWOQIDAQAB",
"auth-server-url": "https://something.com/auth",
"url": "https://something.com/auth",
"ssl-required": "external",
"resource": "sample-tracker",
"clientId": "sample-tracker",
"credentials": {
"secret": "bnmbsdk87wq"
}
}
I got the mentioned error :Failed to load resource: the server responded with a status of 403 (Forbidden)
To solve this situation you need to configure your keycloak or RedHat Single Sign-On (if you are using the supported version).
Open the keycloak admin console, for example: http://localhost:8180/auth/admin. Then click on Configure > clients and select the account client. The account client must be enabled.
Next, still in Configure > clients, select the client that you are trying to access and click on the scope tab. Add the view-profile role of account application.
The user also needs to have this permission.
There is a resolved issue about this in https://issues.jboss.org/browse/LIVEOAK-204 .

Resources