-
Notifications
You must be signed in to change notification settings - Fork 94
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Trying to log into server with wrong credentials times out instead of returning an error #192
Comments
This is by design; The aim of If you want to handle such errors then add an
Partially because it can be confusing; for example when establishing a web-socket connection should the username/password be passed when establishing the http connection (e.g. |
Okay, I get it now. I was just looking for simple way to error out on first non-network-related error when the app was starting as "your credentials is wrong" is almost always non-recoverable/config error in my use case, thanks for the info.
Okay but Websockets already have option for customizing requests with It also blocks from having 2 different configs, say if someone wanted to migrate from old to new server with different creds. |
I'm open to PR's on this but am keen to avoid handling lots of options (don't want this to get as complicated as the V3 client). One approach might be to pass the URL to |
Maybe I'd describe how I hit it. I was trying to use library ( So I looked at what config struct exported, saw no user/password whatsoever and thought "well, it wants 4ee8c92 fixed that discoverability issue (at least for me), I just think it's a bit ugly to have to throw if cfg.MQTTURL[0].User != nil && len(cfg.MQTTURL[0].User.Username()) > 0 {
mqttTr.mqttCfg.ConnectUsername = cfg.MQTTURL[0].User.Username()
p, _ := cfg.MQTTURL[0].User.Password()
mqttTr.mqttCfg.ConnectPassword = []byte(p)
} boilerplate every time I want to just use URL alone. And that is obviously wrong for the rare case multiple URLs would require different credentials. I guess the question is whether that kind of feature is desired. If the assumption is "multiple server support is there just to support a cluster of identical machines", not for using it as crutch during infrastructure migration to server with different config then it isn't worth changing. But if "you put URL of old server as first, new server as second, to allow seamless migration for clients when the old one is down" is desired use case, then the "Server" should be separate struct with URL + credentials + TLS config so there is no global server config values, just per server one.... and that makes config uglier for majority of cases where user doesn't need more than one server or they differ only in URL.
That sounds like good way to leave a way to do it without messing the config too much; I'll give it a go and throw a PR when I find a moment. |
I'm open to retrieving the username from the URL; however, as I said, this can get confusing (see this workaround in the v3 client). As such neither solution is perfect... Given the need to introduce a bit of a hack for the username/password within the URL to work with websockets I think my preference is for the modification to
The issue with this is that when using QOS1+ this can result in lost messages (because the sessions between the two servers will not be in sync). I was even considering only supporting a single URL (to try and avoid users making mistakes that lead to lost messages). Another alternative might be to have a |
Interesting discussion, Just ran into the connection issue as well.
Hmm, bad authentication is not really a connection error though, as the connection was successful. I love the simplicity argument but in this case every single user of paho will now have to hook into OnError and implement a workaround for a use-case that is over-simplified. I hope this makes a case for detecting authentication errors on connect and return an error instead of retrying until the cows come home. |
This is one perspective; however you are assuming that the issue is client side. A server side issue is also possible (and potentially has a much larger impact); for example:
In my case this has the potential to knock hundreds of clients offline; some of these cannot be accessed remotely (e.g. behind NAT) so, without retry, would need to be physically visited to re-establish connectivity. Hence I feel that the safer approach, for a production system, is to retry (so I, for one, am not one of the "every single user of paho" that has to implement a work around :-) ). There are also a range of other issues with returning on an auth (or any other error) including:
Hopefully this provides an explanation of my reasoning for the design decisions; however I should also note that part of the reason I created autopaho was to meet my use-case (lots or remote units with dodgy connections and a requirement that no data is lost); so the design will be influenced by that (and also by the V3 client, paho async c client, paho python etc). Autopaho will not be suitable for all use-cases (I've tried to keep it reasonably flexible but there are limits to that). If this is an issue that multiple users are encountering then we should definitely improve the documentation (this needs work anyway!). |
I think there are 2 cases to consider there:
From my experience the case 2 is what you described, it might be just temporary server misconfiguration but case 1. happens almost exclusively during testing&setup phase and is user error OR it is something that should be communicated to user rather than just retried in the background. So it should be pretty easy for user to configure. I think it might be sensible to give ability to easily split off "network errors" (mostly network timeouts), from "authentication errors" (we got connected to server but it returned error). One way would be via documented error types (currently it's pretty random, bad auth will return So ability to do either mqttCfg.OnServerError = func(err error) {
if err.ErrorCode == paho.ReasonUnauthorized || e.ErrorCode == paho.ReasonBadMethod {
log.Error("wrong username or password")
authFail++
} else {
log.Errorf("Server refused connection: %s",err)
}
if authFail > 100 { botherUser() }
} or mqttCfg.OnError = func(err error) {
switch e := err.(type) {
case *autopaho.ConnectionError: log.Warnf("connection error: %s",e)
case *autopaho.ServerError:
if e.ErrorCode == paho.ReasonUnauthorized || e.ErrorCode == paho.ReasonBadMethod{
log.Error("wrong username or password")
authFail++
} else {
log.Errorf("Server refused connection: %s",err)
}
if authFail > 100{ botherUser() }
default: log.Warnf("error[%T]: %s",e,e)
} I do think second one is a bit cleaner as there is only one hook for errors and "simple" app might just log it, while more complex needs can be handled via types |
This was really the intention with
I would vote for this option. As you say, in many cases the error callback will just be used to log errors so having a single callback simplifies users code (and with error types users can differentiate the errors should they need to).
This kind of inconsistency tends to creep into open source software; originally everything was just a wrapped error; then a user submitted a PR to add ConnackError. I'd be happy to see a PR cleaning this up (but would ask that |
Thank you for elaborating @MattBrittan and @XANi. The distinction between an initial connection and successive connection problems is a good one. |
As per this PR you can use a type assertion to check if the error is a |
As per discussion in eclipse-paho#192 I've added URL as a parameter, and also an example on how to use it to extract password from URL
As per discussion in eclipse-paho#192 I've added URL as a parameter, and also an example on how to use it to extract password from URL
As per discussion in eclipse-paho#192 I've added URL as a parameter, and also an example on how to use it to extract password from URL
when trying to connect to server
and password is wrong (or unset, btw why it doesn't take password from url.URL automatically but need separate call?) this will time out instead of returning authorization error. I've snooped on tcpdump and server is returning code 135 not authorized to the client but client just hangs till timeout.
Version:
v0.12.0
The text was updated successfully, but these errors were encountered: