I have a grails project which uses Spring websockets. I have implemented the DefaultHandshakeHandler to create random principal name for each new session and use convertAndSendToUser to send messages.
Everything works fine in local run. I am also able to deploy the WAR file on an AWS EC2 Linux Instance running latest tomcat. The file deploys fine and the Connect and Disconnect events on websockets can be detected correctly.*
The only problem is, My CustomHandshakeHandler's determineUser does not get called on production. Due to this my StompHeaderAccessor's principal is always null and the code starts spitting NPEs.
This is how i have declared the CustomHandshakeHandler :
class CustomHandshakeHandler extends DefaultHandshakeHandler {
#Override
protected Principal determineUser(ServerHttpRequest request,
WebSocketHandler wsHandler,
Map<String, Object> attributes) {
// Generate principal with UUID as name
return new StompPrincipal(UUID.randomUUID().toString())
}
}
This is how i set the handshake handler configuration :
#Override
void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
stompEndpointRegistry.addEndpoint("/ws-ep") // Set websocket endpoint to connect to
.setHandshakeHandler(new CustomHandshakeHandler()) // Set custom handshake handler
.withSockJS() // Add Sock JS support for frontend
}
I tried deploying the same WAR file on local Tomcat 8 and it again works fine. It seems problem happens due to AWS. I also searched for some other AWS and websocket related issues. I came across some ELB compatibility related things but i Don't think that's my case since my websockets are working fine (Events are being received)
Can someone please help out or point me in right directions
Problem was with Nginx settings which upgrade the Http Request to WS request. This question helped a lot : Spring WebSocket: Handshake failed due to invalid Upgrade header: null
Related
I am trying to run a web api application created with Visual Studio 2022 on my windows 10 laptop and keep receiving this ERR_SSL_VERSION_OR_CIPHER_MISMATCH, both on Chrome and Edge.
The startup code for the application:
using Microsoft.AspNetCore.Authentication.Negotiate;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme)
.AddNegotiate();
builder.Services.AddAuthorization(options =>
{
// By default, all incoming requests will be authorized according to the default policy.
options.FallbackPolicy = options.DefaultPolicy;
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
I remember it did worked for sometime ago. Any idea this happens?
From connection log I got this exception.
Microsoft.AspNetCore.Server.Kestrel.Https.Internal.HttpsConnectionMiddleware | Failed to authenticate HTTPS connection. System.Security.Authentication.AuthenticationException: Authentication failed, see inner exception.
---> System.ComponentModel.Win32Exception (0x80090331): The client and server cannot communicate, because they do not possess a common algorithm.
at System.Net.SSPIWrapper.AcquireCredentialsHandle(ISSPIInterface secModule, String package, CredentialUse intent, SCH_CREDENTIALS* scc)
at System.Net.Security.SslStreamPal.AcquireCredentialsHandle(CredentialUse credUsage, SCH_CREDENTIALS* secureCredential)
at System.Net.Security.SslStreamPal.AcquireCredentialsHandleSchCredentials(SslStreamCertificateContext certificateContext, SslProtocols protocols, EncryptionPolicy policy, Boolean isServer)
at System.Net.Security.SslStreamPal.AcquireCredentialsHandle(SslStreamCertificateContext certificateContext, SslProtocols protocols, EncryptionPolicy policy, Boolean isServer)
I am new to using Micrometer as a metrics/stats producer and I am having a hard time in getting it configured correctly with my Jersey/Embedded Jetty server. I would like to get Jetty statistics added.
I already have the servlet producing stats for the JVM in a Prometheus format.
Does anyone know of a good working example on how to configure it?
I am not using SpringBoot.
The best way is to look at the Spring Boot code. For example it binds the jetty connections
JettyConnectionMetrics.addToAllConnectors(server, this.meterRegistry, this.tags);
And it uses an ApplicationStartedEvent to find the server reference.
private Server findServer(ApplicationContext applicationContext) {
if (applicationContext instanceof WebServerApplicationContext) {
WebServer webServer = ((WebServerApplicationContext) applicationContext).getWebServer();
if (webServer instanceof JettyWebServer) {
return ((JettyWebServer) webServer).getServer();
}
}
return null;
}
There are other classes that record the thread usage and SSL handshake metrics.
I've been trying to use the javacscript version of the Eclipse Paho MQTT client to access the Google IOTCore MQTT Bridge, as suggested here:
https://cloud.google.com/iot/docs/how-tos/mqtt-bridge
However, whatever I do, any attempt to connect with known good credentials (working with other clients) results in this connection error:
errorCode: 7, errorMessage: "AMQJS0007E Socket error:undefined."
Not much to go on there, so I'm wondering if anyone has ever been successful connecting to the MQTT Bridge via Javascript with Eclipse Paho, the client implementation suggested by Google in their documentation.
I've gone through their troubleshooting steps, and things seem to be on the up and up, so no help there either.
https://cloud.google.com/iot/docs/troubleshooting
I have noticed that in their docs they have sample code for Java/Python, etc, but not Javascript, so I'm wondering if it's simply not supported and their documentation just fails to mention as such.
I've simplified my code to just use the 'Hello World' example in the Paho documentation, and as far as I can tell I've done things correctly (including using my device path as the ClientID, the JWT token as the password, specifying an 'unused' userName field and explicitly requiring MQTT v3.1.1).
In the meantime I'm falling back to polling via their HTTP bridge, but that has obvious latency and network traffic shortcomings.
// Create a client instance
client = new Paho.MQTT.Client("mqtt.googleapis.com", Number(8883), "projects/[my-project-id]/locations/us-central1/registries/[my registry name]/devices/[my device id]");
// set callback handlers
client.onConnectionLost = onConnectionLost;
client.onMessageArrived = onMessageArrived;
// connect the client
client.connect({
mqttVersion: 4, // maps to MQTT V3.1.1, required by IOTCore
onSuccess:onConnect,
onFailure: onFailure,
userName: 'unused', // suggested by Google for this field
password: '[My Confirmed Working JWT Token]' // working JWT token
function onFailure(resp) {
console.log(resp);
}
// called when the client connects
function onConnect() {
// Once a connection has been made, make a subscription and send a message.
console.log("onConnect");
client.subscribe("World");
message = new Paho.MQTT.Message("Hello");
message.destinationName = "World";
client.send(message);
}
// called when the client loses its connection
function onConnectionLost(responseObject) {
if (responseObject.errorCode !== 0) {
console.log("onConnectionLost:"+responseObject.errorMessage);
}
}
// called when a message arrives
function onMessageArrived(message) {
console.log("onMessageArrived:"+message.payloadString);
}
I'm a Googler (but I don't work in Cloud IoT).
Your code looks good to me and it should work. I will try it for myself this evening or tomorrow and report back to you.
I've spent the past day working on a Golang version of the samples published on Google's documentation. Like you, I was disappointed to not see all Google's regular languages covered by samples.
Are you running the code from a browser or is it running on Node.JS?
Do you have a package.json (if Node) that you would share too please?
Update
Here's a Node.JS (JavaScript but non-browser) that connects to Cloud IoT, subscribes to /devices/${DEVICE}/config and publishes to /devices/${DEVICE}/events.
https://gist.github.com/DazWilkin/65ad8890d5f58eae9612632d594af2de
Place all the files in the same directory
Replace values in index.js of the location of Google's CA and your key
Replaces [[YOUR-X]] values in config.json
Use "npm install" to pull the packages
Use node index.js
You should be able to pull messages from the Pub/Sub subscription and you should be able to send config messages to the device.
Short answer is no. Google Cloud IoT Core doesn't support WebSockets.
All the JavaScript MQTT libraries use WebSocket because JavaScript is restricted to perform HTTP requests and WebSocket connections only.
i am using embedded Jetty to implement HTTP/2. At the moment i am trying to add a ServerSessionListener (from: org.eclipse.jetty.http2.api.Session.Listener.Adapter) to my Server.
i tried to add it to the Context and Server via: addEventListener with no success.
Maybe someone can give me a hint about what i am doing wrong..
I want to add a session Listener to my HTTP2 Connection to track the connected Sessions (Clients) and their connection duration.
Regards!
You can add an implementation of Connection.Listener as a bean to the connector itself, for example:
http2Connector.addBean(new Connection.Listener()
{
public void onOpened(Connection connection) { ... }
public void onClosed(Connection connection) { ... }
});
Alternatively you can add the Connection.Listener as a bean to the ConnectionFactory.
In both cases, every time a connection is created, the listener is added to the connection and will be invoked when the connection opens and when it closes.
You can use Jetty's ConnectorStatistics class that already gathers a number of statistics about connections and already implements Connection.Listener.
I have a project which, for purposes of server configuration, is just a wicket quickstart archetype. I've added some application code, but haven't really done anything to change the default jetty configuration.
I can run and test my application locally using:
http://localhost:8080
or:
http://bekkar:8080 (my PC's network name)
or:
http://192.168.1.2:8080/ (my PC's local IP)
I want to access my wicket app from outside my router firewall. (I eventually will test it on my Blackberry, but for now I'm using Google Chrome to try to reach it externally.)
Using http://www.whatismyip.com/ I found my router's IP.
I use:
http://###.###.###.###:8080
and I get a screen that says Authentication Required, asking for a username and password. I don't have any kind of authentication set up in my wicket app.
I have a NetGear router, WGR614v7. Using the router admin, under port forwarding, I add the following custom service:
Service Name=wicket
Starting Port=8080
Ending Port=8080
Server IP Address=192.168.1.2 //my computer's local IP
After adding the port forwarding service definition, I get a different message from Chrome:
Oops! Google Chrome could not connect to ###.###.###.###:8080
How can I make my wicket jetty quickstart accessible from outside my router firewall? I don't know if this is a wicket/jetty issue (belonging on SO) or a firewall issue (belonging on serverfault), so I'll post it here, first.
Thanks!
First, try with just simple apache, or woof. Be sure to bind it to 0.0.0.0 (all IPs).
A) If you can't reach it, it's the router config problem.
B) If that works, you know it't jetty/wicket config.
case A) I don't know that router, but look for port forwarding. I wasn't able to get ASUS WL500gP passing requests in, so I am not the right one to advice here :)
case B) Does Jetty bind to 0.0.0.0? Can you reach it from other machine on the local network?
Not much useful answer, but I hope it helps a bit.
I run jetty/wicket apps on my system all the time and access them remotely. I don't think there is anything special that I've done with Jetty, and especially not wicket to make this work. But if it helps, here is an example Start.java file (this is from one of my apps -- not sure if it is the same as the one in quickstart, as I don't have a quickstart available right now):
public class Start {
public static void main(String[] args) throws Exception {
Server server = new Server();
SocketConnector connector = new SocketConnector();
// Set some timeout options to make debugging easier.
connector.setMaxIdleTime(1000 * 60 * 60);
connector.setSoLingerTime(-1);
connector.setPort(8080);
server.setConnectors(new Connector[] { connector });
WebAppContext bb = new WebAppContext();
bb.setServer(server);
bb.setContextPath("/");
bb.setWar("src/main/webapp");
// START JMX SERVER
// MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
// MBeanContainer mBeanContainer = new MBeanContainer(mBeanServer);
// server.getContainer().addEventListener(mBeanContainer);
// mBeanContainer.start();
server.addHandler(bb);
try {
System.out.println(">>> STARTING EMBEDDED JETTY SERVER, PRESS ANY KEY TO STOP");
server.start();
System.in.read();
System.out.println(">>> STOPPING EMBEDDED JETTY SERVER");
// while (System.in.available() == 0) {
// Thread.sleep(5000);
// }
server.stop();
server.join();
} catch (Exception e) {
e.printStackTrace();
System.exit(100);
}
}
}
I'm using a DLink router, so I'm not sure how to configure yours. However, you should also check your router to see if it has remote web admin turned on, and if it is on port 8080. If so, turn it off, as it might be interfering with your port forwarding.