Merge pull request #120 from PierreF/backend-error
Improve handling of backend failure
This commit is contained in:
commit
c0667a4c6e
|
@ -14,6 +14,11 @@
|
|||
|
||||
#include "go-auth.h"
|
||||
|
||||
// Same constant as one in go-auth.go.
|
||||
#define AuthRejected 0
|
||||
#define AuthGranted 1
|
||||
#define AuthError 2
|
||||
|
||||
int mosquitto_auth_plugin_version(void) {
|
||||
#ifdef MOSQ_AUTH_PLUGIN_VERSION
|
||||
#if MOSQ_AUTH_PLUGIN_VERSION == 5
|
||||
|
@ -87,11 +92,23 @@ int mosquitto_auth_unpwd_check(void *userdata, const char *username, const char
|
|||
GoString go_password = {password, strlen(password)};
|
||||
GoString go_clientid = {clientid, strlen(clientid)};
|
||||
|
||||
if(AuthUnpwdCheck(go_username, go_password, go_clientid)){
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
GoUint8 ret = AuthUnpwdCheck(go_username, go_password, go_clientid);
|
||||
|
||||
return MOSQ_ERR_AUTH;
|
||||
switch (ret)
|
||||
{
|
||||
case AuthGranted:
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
break;
|
||||
case AuthRejected:
|
||||
return MOSQ_ERR_AUTH;
|
||||
break;
|
||||
case AuthError:
|
||||
return MOSQ_ERR_UNKNOWN;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "unknown plugin error: %d\n", ret);
|
||||
return MOSQ_ERR_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
#if MOSQ_AUTH_PLUGIN_VERSION >= 4
|
||||
|
@ -118,11 +135,23 @@ int mosquitto_auth_acl_check(void *userdata, const char *clientid, const char *u
|
|||
GoString go_topic = {topic, strlen(topic)};
|
||||
GoInt32 go_access = access;
|
||||
|
||||
if(AuthAclCheck(go_clientid, go_username, go_topic, go_access)){
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
GoUint8 ret = AuthAclCheck(go_clientid, go_username, go_topic, go_access);
|
||||
|
||||
return MOSQ_ERR_ACL_DENIED;
|
||||
switch (ret)
|
||||
{
|
||||
case AuthGranted:
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
break;
|
||||
case AuthRejected:
|
||||
return MOSQ_ERR_ACL_DENIED;
|
||||
break;
|
||||
case AuthError:
|
||||
return MOSQ_ERR_UNKNOWN;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "unknown plugin error: %d\n", ret);
|
||||
return MOSQ_ERR_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
#if MOSQ_AUTH_PLUGIN_VERSION >= 4
|
||||
|
|
|
@ -317,34 +317,34 @@ func checkCommentOrEmpty(line string) bool {
|
|||
}
|
||||
|
||||
//GetUser checks that user exists and password is correct.
|
||||
func (o *Files) GetUser(username, password, clientid string) bool {
|
||||
func (o *Files) GetUser(username, password, clientid string) (bool, error) {
|
||||
|
||||
fileUser, ok := o.Users[username]
|
||||
if !ok {
|
||||
return false
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if o.hasher.Compare(password, fileUser.Password) {
|
||||
return true
|
||||
return true, nil
|
||||
}
|
||||
|
||||
log.Warnf("wrong password for user %s", username)
|
||||
|
||||
return false
|
||||
return false, nil
|
||||
|
||||
}
|
||||
|
||||
//GetSuperuser returns false for files backend.
|
||||
func (o *Files) GetSuperuser(username string) bool {
|
||||
return false
|
||||
func (o *Files) GetSuperuser(username string) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
//CheckAcl checks that the topic may be read/written by the given user/clientid.
|
||||
func (o *Files) CheckAcl(username, topic, clientid string, acc int32) bool {
|
||||
func (o *Files) CheckAcl(username, topic, clientid string, acc int32) (bool, error) {
|
||||
//If there are no acls and Files is the only backend, all access is allowed.
|
||||
//If there are other backends, then we can't blindly grant access.
|
||||
if !o.CheckAcls {
|
||||
return o.filesOnly
|
||||
return o.filesOnly, nil
|
||||
}
|
||||
|
||||
fileUser, ok := o.Users[username]
|
||||
|
@ -353,7 +353,7 @@ func (o *Files) CheckAcl(username, topic, clientid string, acc int32) bool {
|
|||
if ok {
|
||||
for _, aclRecord := range fileUser.AclRecords {
|
||||
if TopicsMatch(aclRecord.Topic, topic) && (acc == int32(aclRecord.Acc) || int32(aclRecord.Acc) == MOSQ_ACL_READWRITE || (acc == MOSQ_ACL_SUBSCRIBE && topic != "#" && (int32(aclRecord.Acc) == MOSQ_ACL_READ || int32(aclRecord.Acc) == MOSQ_ACL_SUBSCRIBE))) {
|
||||
return true
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -362,11 +362,11 @@ func (o *Files) CheckAcl(username, topic, clientid string, acc int32) bool {
|
|||
aclTopic := strings.Replace(aclRecord.Topic, "%c", clientid, -1)
|
||||
aclTopic = strings.Replace(aclTopic, "%u", username, -1)
|
||||
if TopicsMatch(aclTopic, topic) && (acc == int32(aclRecord.Acc) || int32(aclRecord.Acc) == MOSQ_ACL_READWRITE || (acc == MOSQ_ACL_SUBSCRIBE && topic != "#" && (int32(aclRecord.Acc) == MOSQ_ACL_READ || int32(aclRecord.Acc) == MOSQ_ACL_SUBSCRIBE))) {
|
||||
return true
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
return false, nil
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -77,19 +77,34 @@ func TestFiles(t *testing.T) {
|
|||
})
|
||||
|
||||
Convey("Given a username and a correct password, it should correctly authenticate it", func() {
|
||||
authenticated := files.GetUser(user1, user1, clientID)
|
||||
authenticated, err := files.GetUser(user1, user1, clientID)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeTrue)
|
||||
})
|
||||
|
||||
Convey("Given a username and an incorrect password, it should not authenticate it", func() {
|
||||
authenticated := files.GetUser(user1, user2, clientID)
|
||||
authenticated, err := files.GetUser(user1, user2, clientID)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
})
|
||||
|
||||
Convey("Given a wrong username, it should not authenticate it and not return error", func() {
|
||||
authenticated, err := files.GetUser(user4, "whatever_password", "")
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
})
|
||||
|
||||
//There are no superusers for files
|
||||
Convey("For any user superuser should return false", func() {
|
||||
superuser := files.GetSuperuser(user1)
|
||||
superuser, err := files.GetSuperuser(user1)
|
||||
So(err, ShouldBeNil)
|
||||
So(superuser, ShouldBeFalse)
|
||||
|
||||
Convey("Including non-present username", func() {
|
||||
superuser, err := files.GetSuperuser(user4)
|
||||
So(err, ShouldBeNil)
|
||||
So(superuser, ShouldBeFalse)
|
||||
})
|
||||
})
|
||||
|
||||
testTopic1 := `test/topic/1`
|
||||
|
@ -99,11 +114,15 @@ func TestFiles(t *testing.T) {
|
|||
readWriteTopic := "readwrite/topic"
|
||||
|
||||
Convey("User 1 should be able to publish and not subscribe to test topic 1, and only subscribe but not publish to topic 2", func() {
|
||||
tt1 := files.CheckAcl(user1, testTopic1, clientID, 2)
|
||||
tt2 := files.CheckAcl(user1, testTopic1, clientID, 1)
|
||||
tt3 := files.CheckAcl(user1, testTopic2, clientID, 2)
|
||||
tt4 := files.CheckAcl(user1, testTopic2, clientID, 1)
|
||||
tt1, err1 := files.CheckAcl(user1, testTopic1, clientID, 2)
|
||||
tt2, err2 := files.CheckAcl(user1, testTopic1, clientID, 1)
|
||||
tt3, err3 := files.CheckAcl(user1, testTopic2, clientID, 2)
|
||||
tt4, err4 := files.CheckAcl(user1, testTopic2, clientID, 1)
|
||||
|
||||
So(err1, ShouldBeNil)
|
||||
So(err2, ShouldBeNil)
|
||||
So(err3, ShouldBeNil)
|
||||
So(err4, ShouldBeNil)
|
||||
So(tt1, ShouldBeTrue)
|
||||
So(tt2, ShouldBeFalse)
|
||||
So(tt3, ShouldBeFalse)
|
||||
|
@ -111,28 +130,37 @@ func TestFiles(t *testing.T) {
|
|||
})
|
||||
|
||||
Convey("User 1 should be able to subscribe or publish to a readwrite topic rule", func() {
|
||||
tt1 := files.CheckAcl(user1, readWriteTopic, clientID, 2)
|
||||
tt2 := files.CheckAcl(user1, readWriteTopic, clientID, 1)
|
||||
tt1, err1 := files.CheckAcl(user1, readWriteTopic, clientID, 2)
|
||||
tt2, err2 := files.CheckAcl(user1, readWriteTopic, clientID, 1)
|
||||
So(err1, ShouldBeNil)
|
||||
So(err2, ShouldBeNil)
|
||||
So(tt1, ShouldBeTrue)
|
||||
So(tt2, ShouldBeTrue)
|
||||
})
|
||||
|
||||
Convey("User 2 should be able to read any test/topic/X but not any/other", func() {
|
||||
tt1 := files.CheckAcl(user2, testTopic1, clientID, 1)
|
||||
tt2 := files.CheckAcl(user2, testTopic2, clientID, 1)
|
||||
tt3 := files.CheckAcl(user2, testTopic3, clientID, 1)
|
||||
tt1, err1 := files.CheckAcl(user2, testTopic1, clientID, 1)
|
||||
tt2, err2 := files.CheckAcl(user2, testTopic2, clientID, 1)
|
||||
tt3, err3 := files.CheckAcl(user2, testTopic3, clientID, 1)
|
||||
|
||||
So(err1, ShouldBeNil)
|
||||
So(err2, ShouldBeNil)
|
||||
So(err3, ShouldBeNil)
|
||||
So(tt1, ShouldBeTrue)
|
||||
So(tt2, ShouldBeTrue)
|
||||
So(tt3, ShouldBeFalse)
|
||||
})
|
||||
|
||||
Convey("User 3 should be able to read any test/X but not other/...", func() {
|
||||
tt1 := files.CheckAcl(user3, testTopic1, clientID, 1)
|
||||
tt2 := files.CheckAcl(user3, testTopic2, clientID, 1)
|
||||
tt3 := files.CheckAcl(user3, testTopic3, clientID, 1)
|
||||
tt4 := files.CheckAcl(user3, testTopic4, clientID, 1)
|
||||
tt1, err1 := files.CheckAcl(user3, testTopic1, clientID, 1)
|
||||
tt2, err2 := files.CheckAcl(user3, testTopic2, clientID, 1)
|
||||
tt3, err3 := files.CheckAcl(user3, testTopic3, clientID, 1)
|
||||
tt4, err4 := files.CheckAcl(user3, testTopic4, clientID, 1)
|
||||
|
||||
So(err1, ShouldBeNil)
|
||||
So(err2, ShouldBeNil)
|
||||
So(err3, ShouldBeNil)
|
||||
So(err4, ShouldBeNil)
|
||||
So(tt1, ShouldBeTrue)
|
||||
So(tt2, ShouldBeTrue)
|
||||
So(tt3, ShouldBeTrue)
|
||||
|
@ -140,20 +168,23 @@ func TestFiles(t *testing.T) {
|
|||
})
|
||||
|
||||
Convey("User 4 should not be able to read since it's not in the passwords file", func() {
|
||||
tt1 := files.CheckAcl(user4, testTopic1, clientID, 1)
|
||||
tt1, err1 := files.CheckAcl(user4, testTopic1, clientID, 1)
|
||||
|
||||
So(err1, ShouldBeNil)
|
||||
So(tt1, ShouldBeFalse)
|
||||
})
|
||||
|
||||
//Now check against patterns.
|
||||
|
||||
Convey("Given a topic that mentions username, acl check should pass", func() {
|
||||
tt1 := files.CheckAcl(user1, "test/test1", clientID, 1)
|
||||
tt1, err1 := files.CheckAcl(user1, "test/test1", clientID, 1)
|
||||
So(err1, ShouldBeNil)
|
||||
So(tt1, ShouldBeTrue)
|
||||
})
|
||||
|
||||
Convey("Given a topic that mentions clientid, acl check should pass", func() {
|
||||
tt1 := files.CheckAcl(user1, "test/test_client", clientID, 1)
|
||||
tt1, err1 := files.CheckAcl(user1, "test/test_client", clientID, 1)
|
||||
So(err1, ShouldBeNil)
|
||||
So(tt1, ShouldBeTrue)
|
||||
})
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ func NewGRPC(authOpts map[string]string, logLevel log.Level) (GRPC, error) {
|
|||
}
|
||||
|
||||
// GetUser checks that the username exists and the given password hashes to the same password.
|
||||
func (o GRPC) GetUser(username, password, clientid string) bool {
|
||||
func (o GRPC) GetUser(username, password, clientid string) (bool, error) {
|
||||
|
||||
req := gs.GetUserRequest{
|
||||
Username: username,
|
||||
|
@ -64,18 +64,18 @@ func (o GRPC) GetUser(username, password, clientid string) bool {
|
|||
|
||||
if err != nil {
|
||||
log.Errorf("grpc get user error: %s", err)
|
||||
return false
|
||||
return false, err
|
||||
}
|
||||
|
||||
return resp.Ok
|
||||
return resp.Ok, nil
|
||||
|
||||
}
|
||||
|
||||
// GetSuperuser checks that the user is a superuser.
|
||||
func (o GRPC) GetSuperuser(username string) bool {
|
||||
func (o GRPC) GetSuperuser(username string) (bool, error) {
|
||||
|
||||
if o.disableSuperuser {
|
||||
return false
|
||||
return false, nil
|
||||
}
|
||||
|
||||
req := gs.GetSuperuserRequest{
|
||||
|
@ -86,15 +86,15 @@ func (o GRPC) GetSuperuser(username string) bool {
|
|||
|
||||
if err != nil {
|
||||
log.Errorf("grpc get superuser error: %s", err)
|
||||
return false
|
||||
return false, err
|
||||
}
|
||||
|
||||
return resp.Ok
|
||||
return resp.Ok, nil
|
||||
|
||||
}
|
||||
|
||||
// CheckAcl checks if the user has access to the given topic.
|
||||
func (o GRPC) CheckAcl(username, topic, clientid string, acc int32) bool {
|
||||
func (o GRPC) CheckAcl(username, topic, clientid string, acc int32) (bool, error) {
|
||||
|
||||
req := gs.CheckAclRequest{
|
||||
Username: username,
|
||||
|
@ -107,10 +107,10 @@ func (o GRPC) CheckAcl(username, topic, clientid string, acc int32) bool {
|
|||
|
||||
if err != nil {
|
||||
log.Errorf("grpc check acl error: %s", err)
|
||||
return false
|
||||
return false, err
|
||||
}
|
||||
|
||||
return resp.Ok
|
||||
return resp.Ok, nil
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -92,19 +92,23 @@ func TestGRPC(t *testing.T) {
|
|||
|
||||
Convey("given incorrect credentials user should not be authenticated", func(c C) {
|
||||
|
||||
auth := g.GetUser(grpcUsername, "wrong", grpcClientId)
|
||||
auth, err := g.GetUser(grpcUsername, "wrong", grpcClientId)
|
||||
So(err, ShouldBeNil)
|
||||
c.So(auth, ShouldBeFalse)
|
||||
Convey("given correct credential user should be authenticated", func(c C) {
|
||||
|
||||
auth := g.GetUser(grpcUsername, grpcPassword, grpcClientId)
|
||||
auth, err := g.GetUser(grpcUsername, grpcPassword, grpcClientId)
|
||||
So(err, ShouldBeNil)
|
||||
c.So(auth, ShouldBeTrue)
|
||||
|
||||
Convey("given a non superuser user the service should respond false", func(c C) {
|
||||
auth = g.GetSuperuser(grpcUsername)
|
||||
auth, err = g.GetSuperuser(grpcUsername)
|
||||
So(err, ShouldBeNil)
|
||||
So(auth, ShouldBeFalse)
|
||||
|
||||
Convey("switching to a superuser should return true", func(c C) {
|
||||
auth = g.GetSuperuser(grpcSuperuser)
|
||||
auth, err = g.GetSuperuser(grpcSuperuser)
|
||||
So(err, ShouldBeNil)
|
||||
So(auth, ShouldBeTrue)
|
||||
|
||||
Convey("but if we disable superuser checks it should return false", func(c C) {
|
||||
|
@ -112,16 +116,19 @@ func TestGRPC(t *testing.T) {
|
|||
g, err = NewGRPC(authOpts, log.DebugLevel)
|
||||
c.So(err, ShouldBeNil)
|
||||
|
||||
auth = g.GetSuperuser(grpcSuperuser)
|
||||
auth, err = g.GetSuperuser(grpcSuperuser)
|
||||
So(err, ShouldBeNil)
|
||||
So(auth, ShouldBeFalse)
|
||||
})
|
||||
|
||||
Convey("authorizing a wrong topic should fail", func(c C) {
|
||||
auth = g.CheckAcl(grpcUsername, "wrong/topic", grpcClientId, grpcAcc)
|
||||
auth, err = g.CheckAcl(grpcUsername, "wrong/topic", grpcClientId, grpcAcc)
|
||||
So(err, ShouldBeNil)
|
||||
So(auth, ShouldBeFalse)
|
||||
|
||||
Convey("switching to a correct one should succedd", func(c C) {
|
||||
auth = g.CheckAcl(grpcUsername, grpcTopic, grpcClientId, grpcAcc)
|
||||
auth, err = g.CheckAcl(grpcUsername, grpcTopic, grpcClientId, grpcAcc)
|
||||
So(err, ShouldBeNil)
|
||||
So(auth, ShouldBeTrue)
|
||||
|
||||
})
|
||||
|
|
|
@ -126,7 +126,7 @@ func NewHTTP(authOpts map[string]string, logLevel log.Level) (HTTP, error) {
|
|||
return http, nil
|
||||
}
|
||||
|
||||
func (o HTTP) GetUser(username, password, clientid string) bool {
|
||||
func (o HTTP) GetUser(username, password, clientid string) (bool, error) {
|
||||
|
||||
var dataMap = map[string]interface{}{
|
||||
"username": username,
|
||||
|
@ -144,10 +144,10 @@ func (o HTTP) GetUser(username, password, clientid string) bool {
|
|||
|
||||
}
|
||||
|
||||
func (o HTTP) GetSuperuser(username string) bool {
|
||||
func (o HTTP) GetSuperuser(username string) (bool, error) {
|
||||
|
||||
if o.SuperuserUri == "" {
|
||||
return false
|
||||
return false, nil
|
||||
}
|
||||
|
||||
var dataMap = map[string]interface{}{
|
||||
|
@ -162,7 +162,7 @@ func (o HTTP) GetSuperuser(username string) bool {
|
|||
|
||||
}
|
||||
|
||||
func (o HTTP) CheckAcl(username, topic, clientid string, acc int32) bool {
|
||||
func (o HTTP) CheckAcl(username, topic, clientid string, acc int32) (bool, error) {
|
||||
|
||||
dataMap := map[string]interface{}{
|
||||
"username": username,
|
||||
|
@ -182,11 +182,11 @@ func (o HTTP) CheckAcl(username, topic, clientid string, acc int32) bool {
|
|||
|
||||
}
|
||||
|
||||
func (o HTTP) httpRequest(uri, username string, dataMap map[string]interface{}, urlValues map[string][]string) bool {
|
||||
func (o HTTP) httpRequest(uri, username string, dataMap map[string]interface{}, urlValues map[string][]string) (bool, error) {
|
||||
|
||||
// Don't do the request if the client is nil.
|
||||
if o.Client == nil {
|
||||
return false
|
||||
return false, errors.New("http client not initialized")
|
||||
}
|
||||
|
||||
tlsStr := "http://"
|
||||
|
@ -211,7 +211,7 @@ func (o HTTP) httpRequest(uri, username string, dataMap map[string]interface{},
|
|||
|
||||
if err != nil {
|
||||
log.Errorf("marshal error: %s", err)
|
||||
return false
|
||||
return false, err
|
||||
}
|
||||
|
||||
contentReader := bytes.NewReader(dataJson)
|
||||
|
@ -220,7 +220,7 @@ func (o HTTP) httpRequest(uri, username string, dataMap map[string]interface{},
|
|||
|
||||
if err != nil {
|
||||
log.Errorf("req error: %s", err)
|
||||
return false
|
||||
return false, err
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
@ -230,21 +230,24 @@ func (o HTTP) httpRequest(uri, username string, dataMap map[string]interface{},
|
|||
|
||||
if err != nil {
|
||||
log.Errorf("POST error: %s", err)
|
||||
return false
|
||||
return false, err
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("read error: %s", err)
|
||||
return false
|
||||
return false, err
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
||||
log.Infof("error code: %d", resp.StatusCode)
|
||||
return false
|
||||
if resp.StatusCode >= 500 {
|
||||
err = fmt.Errorf("error code: %d", resp.StatusCode)
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
|
||||
if o.ResponseMode == "text" {
|
||||
|
@ -252,7 +255,7 @@ func (o HTTP) httpRequest(uri, username string, dataMap map[string]interface{},
|
|||
//For test response, we expect "ok" or an error message.
|
||||
if string(body) != "ok" {
|
||||
log.Infof("api error: %s", string(body))
|
||||
return false
|
||||
return false, nil
|
||||
}
|
||||
|
||||
} else if o.ResponseMode == "json" {
|
||||
|
@ -263,18 +266,18 @@ func (o HTTP) httpRequest(uri, username string, dataMap map[string]interface{},
|
|||
|
||||
if err != nil {
|
||||
log.Errorf("unmarshal error: %s", err)
|
||||
return false
|
||||
return false, err
|
||||
}
|
||||
|
||||
if !response.Ok {
|
||||
log.Infof("api error: %s", response.Error)
|
||||
return false
|
||||
return false, nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
log.Debugf("http request approved for %s", username)
|
||||
return true
|
||||
return true, nil
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -102,26 +102,30 @@ func TestHTTPAllJsonServer(t *testing.T) {
|
|||
|
||||
Convey("Given correct password/username, get user should return true", func() {
|
||||
|
||||
authenticated := hb.GetUser(username, password, clientId)
|
||||
authenticated, err := hb.GetUser(username, password, clientId)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeTrue)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given incorrect password/username, get user should return false", func() {
|
||||
|
||||
authenticated := hb.GetUser(username, "wrong_password", clientId)
|
||||
authenticated, err := hb.GetUser(username, "wrong_password", clientId)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given correct username, get superuser should return true", func() {
|
||||
|
||||
authenticated := hb.GetSuperuser(username)
|
||||
authenticated, err := hb.GetSuperuser(username)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeTrue)
|
||||
|
||||
Convey("But disabling superusers by removing superuri should now return false", func() {
|
||||
hb.SuperuserUri = ""
|
||||
superuser := hb.GetSuperuser(username)
|
||||
superuser, err := hb.GetSuperuser(username)
|
||||
So(err, ShouldBeNil)
|
||||
So(superuser, ShouldBeFalse)
|
||||
})
|
||||
|
||||
|
@ -129,35 +133,40 @@ func TestHTTPAllJsonServer(t *testing.T) {
|
|||
|
||||
Convey("Given incorrect username, get superuser should return false", func() {
|
||||
|
||||
authenticated := hb.GetSuperuser("not_admin")
|
||||
authenticated, err := hb.GetSuperuser("not_admin")
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given correct topic, username, client id and acc, acl check should return true", func() {
|
||||
|
||||
authenticated := hb.CheckAcl(username, topic, clientId, MOSQ_ACL_READ)
|
||||
authenticated, err := hb.CheckAcl(username, topic, clientId, MOSQ_ACL_READ)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeTrue)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given an acc that requires more privileges than the user has, check acl should return false", func() {
|
||||
|
||||
authenticated := hb.CheckAcl(username, topic, clientId, MOSQ_ACL_WRITE)
|
||||
authenticated, err := hb.CheckAcl(username, topic, clientId, MOSQ_ACL_WRITE)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given a topic not present in acls, check acl should return false", func() {
|
||||
|
||||
authenticated := hb.CheckAcl(username, "fake/topic", clientId, MOSQ_ACL_READ)
|
||||
authenticated, err := hb.CheckAcl(username, "fake/topic", clientId, MOSQ_ACL_READ)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given a clientId that doesn't match, check acl should return false", func() {
|
||||
|
||||
authenticated := hb.CheckAcl(username, topic, "fake_client_id", MOSQ_ACL_READ)
|
||||
authenticated, err := hb.CheckAcl(username, topic, "fake_client_id", MOSQ_ACL_READ)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
@ -236,26 +245,30 @@ func TestHTTPJsonStatusOnlyServer(t *testing.T) {
|
|||
|
||||
Convey("Given correct password/username, get user should return true", func() {
|
||||
|
||||
authenticated := hb.GetUser(username, password, clientId)
|
||||
authenticated, err := hb.GetUser(username, password, clientId)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeTrue)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given incorrect password/username, get user should return false", func() {
|
||||
|
||||
authenticated := hb.GetUser(username, "wrong_password", clientId)
|
||||
authenticated, err := hb.GetUser(username, "wrong_password", clientId)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given correct username, get superuser should return true", func() {
|
||||
|
||||
authenticated := hb.GetSuperuser(username)
|
||||
authenticated, err := hb.GetSuperuser(username)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeTrue)
|
||||
|
||||
Convey("But disabling superusers by removing superuri should now return false", func() {
|
||||
hb.SuperuserUri = ""
|
||||
superuser := hb.GetSuperuser(username)
|
||||
superuser, err := hb.GetSuperuser(username)
|
||||
So(err, ShouldBeNil)
|
||||
So(superuser, ShouldBeFalse)
|
||||
})
|
||||
|
||||
|
@ -263,35 +276,40 @@ func TestHTTPJsonStatusOnlyServer(t *testing.T) {
|
|||
|
||||
Convey("Given incorrect username, get superuser should return false", func() {
|
||||
|
||||
authenticated := hb.GetSuperuser("not_admin")
|
||||
authenticated, err := hb.GetSuperuser("not_admin")
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given correct topic, username, client id and acc, acl check should return true", func() {
|
||||
|
||||
authenticated := hb.CheckAcl(username, topic, clientId, MOSQ_ACL_READ)
|
||||
authenticated, err := hb.CheckAcl(username, topic, clientId, MOSQ_ACL_READ)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeTrue)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given an acc that requires more privileges than the user has, check acl should return false", func() {
|
||||
|
||||
authenticated := hb.CheckAcl(username, topic, clientId, MOSQ_ACL_WRITE)
|
||||
authenticated, err := hb.CheckAcl(username, topic, clientId, MOSQ_ACL_WRITE)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given a topic not present in acls, check acl should return false", func() {
|
||||
|
||||
authenticated := hb.CheckAcl(username, "fake/topic", clientId, MOSQ_ACL_READ)
|
||||
authenticated, err := hb.CheckAcl(username, "fake/topic", clientId, MOSQ_ACL_READ)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given a clientId that doesn't match, check acl should return false", func() {
|
||||
|
||||
authenticated := hb.CheckAcl(username, topic, "fake_client_id", MOSQ_ACL_READ)
|
||||
authenticated, err := hb.CheckAcl(username, topic, "fake_client_id", MOSQ_ACL_READ)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
@ -374,26 +392,30 @@ func TestHTTPJsonTextResponseServer(t *testing.T) {
|
|||
|
||||
Convey("Given correct password/username, get user should return true", func() {
|
||||
|
||||
authenticated := hb.GetUser(username, password, clientId)
|
||||
authenticated, err := hb.GetUser(username, password, clientId)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeTrue)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given incorrect password/username, get user should return false", func() {
|
||||
|
||||
authenticated := hb.GetUser(username, "wrong_password", clientId)
|
||||
authenticated, err := hb.GetUser(username, "wrong_password", clientId)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given correct username, get superuser should return true", func() {
|
||||
|
||||
authenticated := hb.GetSuperuser(username)
|
||||
authenticated, err := hb.GetSuperuser(username)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeTrue)
|
||||
|
||||
Convey("But disabling superusers by removing superuri should now return false", func() {
|
||||
hb.SuperuserUri = ""
|
||||
superuser := hb.GetSuperuser(username)
|
||||
superuser, err := hb.GetSuperuser(username)
|
||||
So(err, ShouldBeNil)
|
||||
So(superuser, ShouldBeFalse)
|
||||
})
|
||||
|
||||
|
@ -401,35 +423,40 @@ func TestHTTPJsonTextResponseServer(t *testing.T) {
|
|||
|
||||
Convey("Given incorrect username, get superuser should return false", func() {
|
||||
|
||||
authenticated := hb.GetSuperuser("not_admin")
|
||||
authenticated, err := hb.GetSuperuser("not_admin")
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given correct topic, username, client id and acc, acl check should return true", func() {
|
||||
|
||||
authenticated := hb.CheckAcl(username, topic, clientId, MOSQ_ACL_READ)
|
||||
authenticated, err := hb.CheckAcl(username, topic, clientId, MOSQ_ACL_READ)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeTrue)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given an acc that requires more privileges than the user has, check acl should return false", func() {
|
||||
|
||||
authenticated := hb.CheckAcl(username, topic, clientId, MOSQ_ACL_WRITE)
|
||||
authenticated, err := hb.CheckAcl(username, topic, clientId, MOSQ_ACL_WRITE)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given a topic not present in acls, check acl should return false", func() {
|
||||
|
||||
authenticated := hb.CheckAcl(username, "fake/topic", clientId, MOSQ_ACL_READ)
|
||||
authenticated, err := hb.CheckAcl(username, "fake/topic", clientId, MOSQ_ACL_READ)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given a clientId that doesn't match, check acl should return false", func() {
|
||||
|
||||
authenticated := hb.CheckAcl(username, topic, "fake_client_id", MOSQ_ACL_READ)
|
||||
authenticated, err := hb.CheckAcl(username, topic, "fake_client_id", MOSQ_ACL_READ)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
@ -521,26 +548,30 @@ func TestHTTPFormJsonResponseServer(t *testing.T) {
|
|||
|
||||
Convey("Given correct password/username, get user should return true", func() {
|
||||
|
||||
authenticated := hb.GetUser(username, password, clientId)
|
||||
authenticated, err := hb.GetUser(username, password, clientId)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeTrue)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given incorrect password/username, get user should return false", func() {
|
||||
|
||||
authenticated := hb.GetUser(username, "wrong_password", clientId)
|
||||
authenticated, err := hb.GetUser(username, "wrong_password", clientId)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given correct username, get superuser should return true", func() {
|
||||
|
||||
authenticated := hb.GetSuperuser(username)
|
||||
authenticated, err := hb.GetSuperuser(username)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeTrue)
|
||||
|
||||
Convey("But disabling superusers by removing superuri should now return false", func() {
|
||||
hb.SuperuserUri = ""
|
||||
superuser := hb.GetSuperuser(username)
|
||||
superuser, err := hb.GetSuperuser(username)
|
||||
So(err, ShouldBeNil)
|
||||
So(superuser, ShouldBeFalse)
|
||||
})
|
||||
|
||||
|
@ -548,35 +579,40 @@ func TestHTTPFormJsonResponseServer(t *testing.T) {
|
|||
|
||||
Convey("Given incorrect username, get superuser should return false", func() {
|
||||
|
||||
authenticated := hb.GetSuperuser("not_admin")
|
||||
authenticated, err := hb.GetSuperuser("not_admin")
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given correct topic, username, client id and acc, acl check should return true", func() {
|
||||
|
||||
authenticated := hb.CheckAcl(username, topic, clientId, MOSQ_ACL_READ)
|
||||
authenticated, err := hb.CheckAcl(username, topic, clientId, MOSQ_ACL_READ)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeTrue)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given an acc that requires more privileges than the user has, check acl should return false", func() {
|
||||
|
||||
authenticated := hb.CheckAcl(username, topic, clientId, MOSQ_ACL_WRITE)
|
||||
authenticated, err := hb.CheckAcl(username, topic, clientId, MOSQ_ACL_WRITE)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given a topic not present in acls, check acl should return false", func() {
|
||||
|
||||
authenticated := hb.CheckAcl(username, "fake/topic", clientId, MOSQ_ACL_READ)
|
||||
authenticated, err := hb.CheckAcl(username, "fake/topic", clientId, MOSQ_ACL_READ)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given a clientId that doesn't match, check acl should return false", func() {
|
||||
|
||||
authenticated := hb.CheckAcl(username, topic, "fake_client_id", MOSQ_ACL_READ)
|
||||
authenticated, err := hb.CheckAcl(username, topic, "fake_client_id", MOSQ_ACL_READ)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
@ -646,26 +682,30 @@ func TestHTTPFormStatusOnlyServer(t *testing.T) {
|
|||
|
||||
Convey("Given correct password/username, get user should return true", func() {
|
||||
|
||||
authenticated := hb.GetUser(username, password, clientId)
|
||||
authenticated, err := hb.GetUser(username, password, clientId)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeTrue)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given incorrect password/username, get user should return false", func() {
|
||||
|
||||
authenticated := hb.GetUser(username, "wrong_password", clientId)
|
||||
authenticated, err := hb.GetUser(username, "wrong_password", clientId)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given correct username, get superuser should return true", func() {
|
||||
|
||||
authenticated := hb.GetSuperuser(username)
|
||||
authenticated, err := hb.GetSuperuser(username)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeTrue)
|
||||
|
||||
Convey("But disabling superusers by removing superuri should now return false", func() {
|
||||
hb.SuperuserUri = ""
|
||||
superuser := hb.GetSuperuser(username)
|
||||
superuser, err := hb.GetSuperuser(username)
|
||||
So(err, ShouldBeNil)
|
||||
So(superuser, ShouldBeFalse)
|
||||
})
|
||||
|
||||
|
@ -673,35 +713,40 @@ func TestHTTPFormStatusOnlyServer(t *testing.T) {
|
|||
|
||||
Convey("Given incorrect username, get superuser should return false", func() {
|
||||
|
||||
authenticated := hb.GetSuperuser("not_admin")
|
||||
authenticated, err := hb.GetSuperuser("not_admin")
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given correct topic, username, client id and acc, acl check should return true", func() {
|
||||
|
||||
authenticated := hb.CheckAcl(username, topic, clientId, MOSQ_ACL_READ)
|
||||
authenticated, err := hb.CheckAcl(username, topic, clientId, MOSQ_ACL_READ)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeTrue)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given an acc that requires more privileges than the user has, check acl should return false", func() {
|
||||
|
||||
authenticated := hb.CheckAcl(username, topic, clientId, MOSQ_ACL_WRITE)
|
||||
authenticated, err := hb.CheckAcl(username, topic, clientId, MOSQ_ACL_WRITE)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given a topic not present in acls, check acl should return false", func() {
|
||||
|
||||
authenticated := hb.CheckAcl(username, "fake/topic", clientId, MOSQ_ACL_READ)
|
||||
authenticated, err := hb.CheckAcl(username, "fake/topic", clientId, MOSQ_ACL_READ)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given a clientId that doesn't match, check acl should return false", func() {
|
||||
|
||||
authenticated := hb.CheckAcl(username, topic, "fake_client_id", MOSQ_ACL_READ)
|
||||
authenticated, err := hb.CheckAcl(username, topic, "fake_client_id", MOSQ_ACL_READ)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
@ -776,26 +821,30 @@ func TestHTTPFormTextResponseServer(t *testing.T) {
|
|||
|
||||
Convey("Given correct password/username, get user should return true", func() {
|
||||
|
||||
authenticated := hb.GetUser(username, password, clientId)
|
||||
authenticated, err := hb.GetUser(username, password, clientId)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeTrue)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given incorrect password/username, get user should return false", func() {
|
||||
|
||||
authenticated := hb.GetUser(username, "wrong_password", clientId)
|
||||
authenticated, err := hb.GetUser(username, "wrong_password", clientId)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given correct username, get superuser should return true", func() {
|
||||
|
||||
authenticated := hb.GetSuperuser(username)
|
||||
authenticated, err := hb.GetSuperuser(username)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeTrue)
|
||||
|
||||
Convey("But disabling superusers by removing superuri should now return false", func() {
|
||||
hb.SuperuserUri = ""
|
||||
superuser := hb.GetSuperuser(username)
|
||||
superuser, err := hb.GetSuperuser(username)
|
||||
So(err, ShouldBeNil)
|
||||
So(superuser, ShouldBeFalse)
|
||||
})
|
||||
|
||||
|
@ -803,35 +852,40 @@ func TestHTTPFormTextResponseServer(t *testing.T) {
|
|||
|
||||
Convey("Given incorrect username, get superuser should return false", func() {
|
||||
|
||||
authenticated := hb.GetSuperuser("not_admin")
|
||||
authenticated, err := hb.GetSuperuser("not_admin")
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given correct topic, username, client id and acc, acl check should return true", func() {
|
||||
|
||||
authenticated := hb.CheckAcl(username, topic, clientId, MOSQ_ACL_READ)
|
||||
authenticated, err := hb.CheckAcl(username, topic, clientId, MOSQ_ACL_READ)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeTrue)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given an acc that requires more privileges than the user has, check acl should return false", func() {
|
||||
|
||||
authenticated := hb.CheckAcl(username, topic, clientId, MOSQ_ACL_WRITE)
|
||||
authenticated, err := hb.CheckAcl(username, topic, clientId, MOSQ_ACL_WRITE)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given a topic not present in acls, check acl should return false", func() {
|
||||
|
||||
authenticated := hb.CheckAcl(username, "fake/topic", clientId, MOSQ_ACL_READ)
|
||||
authenticated, err := hb.CheckAcl(username, "fake/topic", clientId, MOSQ_ACL_READ)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given a clientId that doesn't match, check acl should return false", func() {
|
||||
|
||||
authenticated := hb.CheckAcl(username, topic, "fake_client_id", MOSQ_ACL_READ)
|
||||
authenticated, err := hb.CheckAcl(username, topic, "fake_client_id", MOSQ_ACL_READ)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
|
|
@ -95,7 +95,7 @@ func NewJavascript(authOpts map[string]string, logLevel log.Level) (*Javascript,
|
|||
return javascript, nil
|
||||
}
|
||||
|
||||
func (o *Javascript) GetUser(username, password, clientid string) bool {
|
||||
func (o *Javascript) GetUser(username, password, clientid string) (bool, error) {
|
||||
params := map[string]interface{}{
|
||||
"username": username,
|
||||
"password": password,
|
||||
|
@ -107,10 +107,10 @@ func (o *Javascript) GetUser(username, password, clientid string) bool {
|
|||
log.Errorf("js error: %s", err)
|
||||
}
|
||||
|
||||
return granted
|
||||
return granted, err
|
||||
}
|
||||
|
||||
func (o *Javascript) GetSuperuser(username string) bool {
|
||||
func (o *Javascript) GetSuperuser(username string) (bool, error) {
|
||||
params := map[string]interface{}{
|
||||
"username": username,
|
||||
}
|
||||
|
@ -120,10 +120,10 @@ func (o *Javascript) GetSuperuser(username string) bool {
|
|||
log.Errorf("js error: %s", err)
|
||||
}
|
||||
|
||||
return granted
|
||||
return granted, err
|
||||
}
|
||||
|
||||
func (o *Javascript) CheckAcl(username, topic, clientid string, acc int32) bool {
|
||||
func (o *Javascript) CheckAcl(username, topic, clientid string, acc int32) (bool, error) {
|
||||
params := map[string]interface{}{
|
||||
"username": username,
|
||||
"topic": topic,
|
||||
|
@ -136,7 +136,7 @@ func (o *Javascript) CheckAcl(username, topic, clientid string, acc int32) bool
|
|||
log.Errorf("js error: %s", err)
|
||||
}
|
||||
|
||||
return granted
|
||||
return granted, err
|
||||
}
|
||||
|
||||
//GetName returns the backend's name
|
||||
|
|
|
@ -40,38 +40,48 @@ func TestJavascript(t *testing.T) {
|
|||
So(err, ShouldBeNil)
|
||||
|
||||
Convey("User checks should work", func() {
|
||||
userResponse := javascript.GetUser("correct", "good", "some-id")
|
||||
userResponse, err := javascript.GetUser("correct", "good", "some-id")
|
||||
So(err, ShouldBeNil)
|
||||
So(userResponse, ShouldBeTrue)
|
||||
|
||||
userResponse = javascript.GetUser("correct", "bad", "some-id")
|
||||
userResponse, err = javascript.GetUser("correct", "bad", "some-id")
|
||||
So(err, ShouldBeNil)
|
||||
So(userResponse, ShouldBeFalse)
|
||||
|
||||
userResponse = javascript.GetUser("wrong", "good", "some-id")
|
||||
userResponse, err = javascript.GetUser("wrong", "good", "some-id")
|
||||
So(err, ShouldBeNil)
|
||||
So(userResponse, ShouldBeFalse)
|
||||
})
|
||||
|
||||
Convey("Superuser checks should work", func() {
|
||||
superuserResponse := javascript.GetSuperuser("admin")
|
||||
superuserResponse, err := javascript.GetSuperuser("admin")
|
||||
So(err, ShouldBeNil)
|
||||
So(superuserResponse, ShouldBeTrue)
|
||||
|
||||
superuserResponse = javascript.GetSuperuser("non-admin")
|
||||
superuserResponse, err = javascript.GetSuperuser("non-admin")
|
||||
So(err, ShouldBeNil)
|
||||
So(superuserResponse, ShouldBeFalse)
|
||||
})
|
||||
|
||||
Convey("ACL checks should work", func() {
|
||||
aclResponse := javascript.CheckAcl("correct", "test/topic", "id", 1)
|
||||
aclResponse, err := javascript.CheckAcl("correct", "test/topic", "id", 1)
|
||||
So(err, ShouldBeNil)
|
||||
So(aclResponse, ShouldBeTrue)
|
||||
|
||||
aclResponse = javascript.CheckAcl("incorrect", "test/topic", "id", 1)
|
||||
aclResponse, err = javascript.CheckAcl("incorrect", "test/topic", "id", 1)
|
||||
So(err, ShouldBeNil)
|
||||
So(aclResponse, ShouldBeFalse)
|
||||
|
||||
aclResponse = javascript.CheckAcl("correct", "bad/topic", "id", 1)
|
||||
aclResponse, err = javascript.CheckAcl("correct", "bad/topic", "id", 1)
|
||||
So(err, ShouldBeNil)
|
||||
So(aclResponse, ShouldBeFalse)
|
||||
|
||||
aclResponse = javascript.CheckAcl("correct", "test/topic", "wrong-id", 1)
|
||||
aclResponse, err = javascript.CheckAcl("correct", "test/topic", "wrong-id", 1)
|
||||
So(err, ShouldBeNil)
|
||||
So(aclResponse, ShouldBeFalse)
|
||||
|
||||
aclResponse = javascript.CheckAcl("correct", "test/topic", "id", 2)
|
||||
aclResponse, err = javascript.CheckAcl("correct", "test/topic", "id", 2)
|
||||
So(err, ShouldBeNil)
|
||||
So(aclResponse, ShouldBeFalse)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -21,9 +21,9 @@ type tokenOptions struct {
|
|||
}
|
||||
|
||||
type jwtChecker interface {
|
||||
GetUser(username string) bool
|
||||
GetSuperuser(username string) bool
|
||||
CheckAcl(username, topic, clientid string, acc int32) bool
|
||||
GetUser(username string) (bool, error)
|
||||
GetSuperuser(username string) (bool, error)
|
||||
CheckAcl(username, topic, clientid string, acc int32) (bool, error)
|
||||
Halt()
|
||||
}
|
||||
|
||||
|
@ -97,17 +97,17 @@ func NewJWT(authOpts map[string]string, logLevel log.Level, hasher hashing.HashC
|
|||
}
|
||||
|
||||
//GetUser authenticates a given user.
|
||||
func (o *JWT) GetUser(token, password, clientid string) bool {
|
||||
func (o *JWT) GetUser(token, password, clientid string) (bool, error) {
|
||||
return o.checker.GetUser(token)
|
||||
}
|
||||
|
||||
//GetSuperuser checks if the given user is a superuser.
|
||||
func (o *JWT) GetSuperuser(token string) bool {
|
||||
func (o *JWT) GetSuperuser(token string) (bool, error) {
|
||||
return o.checker.GetSuperuser(token)
|
||||
}
|
||||
|
||||
//CheckAcl checks user authorization.
|
||||
func (o *JWT) CheckAcl(token, topic, clientid string, acc int32) bool {
|
||||
func (o *JWT) CheckAcl(token, topic, clientid string, acc int32) (bool, error) {
|
||||
return o.checker.CheckAcl(token, topic, clientid, acc)
|
||||
}
|
||||
|
||||
|
|
|
@ -84,7 +84,7 @@ func NewJsJWTChecker(authOpts map[string]string, options tokenOptions) (jwtCheck
|
|||
return checker, nil
|
||||
}
|
||||
|
||||
func (o *jsJWTChecker) GetUser(token string) bool {
|
||||
func (o *jsJWTChecker) GetUser(token string) (bool, error) {
|
||||
params := map[string]interface{}{
|
||||
"token": token,
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ func (o *jsJWTChecker) GetUser(token string) bool {
|
|||
|
||||
if err != nil {
|
||||
log.Printf("jwt get user error: %s", err)
|
||||
return false
|
||||
return false, err
|
||||
}
|
||||
|
||||
params["username"] = username
|
||||
|
@ -105,10 +105,10 @@ func (o *jsJWTChecker) GetUser(token string) bool {
|
|||
log.Errorf("js error: %s", err)
|
||||
}
|
||||
|
||||
return granted
|
||||
return granted, err
|
||||
}
|
||||
|
||||
func (o *jsJWTChecker) GetSuperuser(token string) bool {
|
||||
func (o *jsJWTChecker) GetSuperuser(token string) (bool, error) {
|
||||
params := map[string]interface{}{
|
||||
"token": token,
|
||||
}
|
||||
|
@ -118,7 +118,7 @@ func (o *jsJWTChecker) GetSuperuser(token string) bool {
|
|||
|
||||
if err != nil {
|
||||
log.Printf("jwt get user error: %s", err)
|
||||
return false
|
||||
return false, err
|
||||
}
|
||||
|
||||
params["username"] = username
|
||||
|
@ -129,10 +129,10 @@ func (o *jsJWTChecker) GetSuperuser(token string) bool {
|
|||
log.Errorf("js error: %s", err)
|
||||
}
|
||||
|
||||
return granted
|
||||
return granted, err
|
||||
}
|
||||
|
||||
func (o *jsJWTChecker) CheckAcl(token, topic, clientid string, acc int32) bool {
|
||||
func (o *jsJWTChecker) CheckAcl(token, topic, clientid string, acc int32) (bool, error) {
|
||||
params := map[string]interface{}{
|
||||
"token": token,
|
||||
"topic": topic,
|
||||
|
@ -145,7 +145,7 @@ func (o *jsJWTChecker) CheckAcl(token, topic, clientid string, acc int32) bool {
|
|||
|
||||
if err != nil {
|
||||
log.Printf("jwt get user error: %s", err)
|
||||
return false
|
||||
return false, err
|
||||
}
|
||||
|
||||
params["username"] = username
|
||||
|
@ -156,7 +156,7 @@ func (o *jsJWTChecker) CheckAcl(token, topic, clientid string, acc int32) bool {
|
|||
log.Errorf("js error: %s", err)
|
||||
}
|
||||
|
||||
return granted
|
||||
return granted, err
|
||||
}
|
||||
|
||||
func (o *jsJWTChecker) Halt() {
|
||||
|
|
|
@ -77,23 +77,23 @@ func NewLocalJWTChecker(authOpts map[string]string, logLevel log.Level, hasher h
|
|||
return checker, nil
|
||||
}
|
||||
|
||||
func (o *localJWTChecker) GetUser(token string) bool {
|
||||
func (o *localJWTChecker) GetUser(token string) (bool, error) {
|
||||
username, err := getUsernameForToken(o.options, token, o.options.skipUserExpiration)
|
||||
|
||||
if err != nil {
|
||||
log.Printf("jwt local get user error: %s", err)
|
||||
return false
|
||||
return false, err
|
||||
}
|
||||
|
||||
return o.getLocalUser(username)
|
||||
}
|
||||
|
||||
func (o *localJWTChecker) GetSuperuser(token string) bool {
|
||||
func (o *localJWTChecker) GetSuperuser(token string) (bool, error) {
|
||||
username, err := getUsernameForToken(o.options, token, o.options.skipUserExpiration)
|
||||
|
||||
if err != nil {
|
||||
log.Printf("jwt local get superuser error: %s", err)
|
||||
return false
|
||||
return false, err
|
||||
}
|
||||
|
||||
if o.db == mysqlDB {
|
||||
|
@ -103,12 +103,12 @@ func (o *localJWTChecker) GetSuperuser(token string) bool {
|
|||
return o.postgres.GetSuperuser(username)
|
||||
}
|
||||
|
||||
func (o *localJWTChecker) CheckAcl(token, topic, clientid string, acc int32) bool {
|
||||
func (o *localJWTChecker) CheckAcl(token, topic, clientid string, acc int32) (bool, error) {
|
||||
username, err := getUsernameForToken(o.options, token, o.options.skipACLExpiration)
|
||||
|
||||
if err != nil {
|
||||
log.Printf("jwt local check acl error: %s", err)
|
||||
return false
|
||||
return false, err
|
||||
}
|
||||
|
||||
if o.db == mysqlDB {
|
||||
|
@ -132,9 +132,9 @@ func (o *localJWTChecker) Halt() {
|
|||
}
|
||||
}
|
||||
|
||||
func (o *localJWTChecker) getLocalUser(username string) bool {
|
||||
func (o *localJWTChecker) getLocalUser(username string) (bool, error) {
|
||||
if o.userQuery == "" {
|
||||
return false
|
||||
return false, nil
|
||||
}
|
||||
|
||||
var count sql.NullInt64
|
||||
|
@ -147,19 +147,19 @@ func (o *localJWTChecker) getLocalUser(username string) bool {
|
|||
|
||||
if err != nil {
|
||||
log.Debugf("local JWT get user error: %s", err)
|
||||
return false
|
||||
return false, err
|
||||
}
|
||||
|
||||
if !count.Valid {
|
||||
log.Debugf("local JWT get user error: user %s not found", username)
|
||||
return false
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if count.Int64 > 0 {
|
||||
return true
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return false
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func extractOpts(authOpts map[string]string, db string) map[string]string {
|
||||
|
|
|
@ -118,7 +118,7 @@ func NewRemoteJWTChecker(authOpts map[string]string, options tokenOptions) (jwtC
|
|||
return checker, nil
|
||||
}
|
||||
|
||||
func (o *remoteJWTChecker) GetUser(token string) bool {
|
||||
func (o *remoteJWTChecker) GetUser(token string) (bool, error) {
|
||||
var dataMap map[string]interface{}
|
||||
var urlValues url.Values
|
||||
|
||||
|
@ -127,7 +127,7 @@ func (o *remoteJWTChecker) GetUser(token string) bool {
|
|||
|
||||
if err != nil {
|
||||
log.Printf("jwt remote get user error: %s", err)
|
||||
return false
|
||||
return false, err
|
||||
}
|
||||
|
||||
dataMap = map[string]interface{}{
|
||||
|
@ -142,9 +142,9 @@ func (o *remoteJWTChecker) GetUser(token string) bool {
|
|||
return o.jwtRequest(o.host, o.userUri, token, dataMap, urlValues)
|
||||
}
|
||||
|
||||
func (o *remoteJWTChecker) GetSuperuser(token string) bool {
|
||||
func (o *remoteJWTChecker) GetSuperuser(token string) (bool, error) {
|
||||
if o.superuserUri == "" {
|
||||
return false
|
||||
return false, nil
|
||||
}
|
||||
var dataMap map[string]interface{}
|
||||
var urlValues = url.Values{}
|
||||
|
@ -154,7 +154,7 @@ func (o *remoteJWTChecker) GetSuperuser(token string) bool {
|
|||
|
||||
if err != nil {
|
||||
log.Printf("jwt remote get superuser error: %s", err)
|
||||
return false
|
||||
return false, err
|
||||
}
|
||||
|
||||
dataMap = map[string]interface{}{
|
||||
|
@ -169,7 +169,7 @@ func (o *remoteJWTChecker) GetSuperuser(token string) bool {
|
|||
return o.jwtRequest(o.host, o.superuserUri, token, dataMap, urlValues)
|
||||
}
|
||||
|
||||
func (o *remoteJWTChecker) CheckAcl(token, topic, clientid string, acc int32) bool {
|
||||
func (o *remoteJWTChecker) CheckAcl(token, topic, clientid string, acc int32) (bool, error) {
|
||||
dataMap := map[string]interface{}{
|
||||
"clientid": clientid,
|
||||
"topic": topic,
|
||||
|
@ -186,7 +186,7 @@ func (o *remoteJWTChecker) CheckAcl(token, topic, clientid string, acc int32) bo
|
|||
|
||||
if err != nil {
|
||||
log.Printf("jwt remote check acl error: %s", err)
|
||||
return false
|
||||
return false, err
|
||||
}
|
||||
|
||||
dataMap["username"] = username
|
||||
|
@ -201,11 +201,11 @@ func (o *remoteJWTChecker) Halt() {
|
|||
// NO-OP
|
||||
}
|
||||
|
||||
func (o *remoteJWTChecker) jwtRequest(host, uri, token string, dataMap map[string]interface{}, urlValues url.Values) bool {
|
||||
func (o *remoteJWTChecker) jwtRequest(host, uri, token string, dataMap map[string]interface{}, urlValues url.Values) (bool, error) {
|
||||
|
||||
// Don't do the request if the client is nil.
|
||||
if o.client == nil {
|
||||
return false
|
||||
return false, errors.New("jwt http client not initialized")
|
||||
}
|
||||
|
||||
tlsStr := "http://"
|
||||
|
@ -229,7 +229,7 @@ func (o *remoteJWTChecker) jwtRequest(host, uri, token string, dataMap map[strin
|
|||
|
||||
if err != nil {
|
||||
log.Errorf("marshal error: %s", err)
|
||||
return false
|
||||
return false, err
|
||||
}
|
||||
|
||||
contentReader := bytes.NewReader(dataJSON)
|
||||
|
@ -237,7 +237,7 @@ func (o *remoteJWTChecker) jwtRequest(host, uri, token string, dataMap map[strin
|
|||
|
||||
if err != nil {
|
||||
log.Errorf("req error: %s", err)
|
||||
return false
|
||||
return false, err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
default:
|
||||
|
@ -247,7 +247,7 @@ func (o *remoteJWTChecker) jwtRequest(host, uri, token string, dataMap map[strin
|
|||
|
||||
if err != nil {
|
||||
log.Errorf("req error: %s", err)
|
||||
return false
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -257,21 +257,24 @@ func (o *remoteJWTChecker) jwtRequest(host, uri, token string, dataMap map[strin
|
|||
|
||||
if err != nil {
|
||||
log.Errorf("error: %v", err)
|
||||
return false
|
||||
return false, err
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("read error: %s", err)
|
||||
return false
|
||||
return false, err
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
||||
log.Infof("error code: %d", resp.StatusCode)
|
||||
return false
|
||||
if resp.StatusCode >= 500 {
|
||||
err = fmt.Errorf("error code: %d", resp.StatusCode)
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
|
||||
if o.responseMode == "text" {
|
||||
|
@ -279,7 +282,7 @@ func (o *remoteJWTChecker) jwtRequest(host, uri, token string, dataMap map[strin
|
|||
//For test response, we expect "ok" or an error message.
|
||||
if string(body) != "ok" {
|
||||
log.Infof("api error: %s", string(body))
|
||||
return false
|
||||
return false, nil
|
||||
}
|
||||
|
||||
} else if o.responseMode == "json" {
|
||||
|
@ -290,16 +293,16 @@ func (o *remoteJWTChecker) jwtRequest(host, uri, token string, dataMap map[strin
|
|||
|
||||
if err != nil {
|
||||
log.Errorf("unmarshal error: %s", err)
|
||||
return false
|
||||
return false, err
|
||||
}
|
||||
|
||||
if !response.Ok {
|
||||
log.Infof("api error: %s", response.Error)
|
||||
return false
|
||||
return false, nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
log.Debugf("jwt request approved for %s", token)
|
||||
return true
|
||||
return true, nil
|
||||
}
|
||||
|
|
|
@ -115,31 +115,40 @@ func TestJsJWTChecker(t *testing.T) {
|
|||
checker, err := NewJsJWTChecker(authOpts, tkOptions)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
userResponse := checker.GetUser("correct")
|
||||
userResponse, err := checker.GetUser("correct")
|
||||
So(err, ShouldBeNil)
|
||||
So(userResponse, ShouldBeTrue)
|
||||
|
||||
userResponse = checker.GetUser("bad")
|
||||
userResponse, err = checker.GetUser("bad")
|
||||
So(err, ShouldBeNil)
|
||||
So(userResponse, ShouldBeFalse)
|
||||
|
||||
superuserResponse := checker.GetSuperuser("admin")
|
||||
superuserResponse, err := checker.GetSuperuser("admin")
|
||||
So(err, ShouldBeNil)
|
||||
So(superuserResponse, ShouldBeTrue)
|
||||
|
||||
superuserResponse = checker.GetSuperuser("non-admin")
|
||||
superuserResponse, err = checker.GetSuperuser("non-admin")
|
||||
So(err, ShouldBeNil)
|
||||
So(superuserResponse, ShouldBeFalse)
|
||||
|
||||
aclResponse := checker.CheckAcl("correct", "test/topic", "id", 1)
|
||||
aclResponse, err := checker.CheckAcl("correct", "test/topic", "id", 1)
|
||||
So(err, ShouldBeNil)
|
||||
So(aclResponse, ShouldBeTrue)
|
||||
|
||||
aclResponse = checker.CheckAcl("incorrect", "test/topic", "id", 1)
|
||||
aclResponse, err = checker.CheckAcl("incorrect", "test/topic", "id", 1)
|
||||
So(err, ShouldBeNil)
|
||||
So(userResponse, ShouldBeFalse)
|
||||
|
||||
aclResponse = checker.CheckAcl("correct", "bad/topic", "id", 1)
|
||||
aclResponse, err = checker.CheckAcl("correct", "bad/topic", "id", 1)
|
||||
So(err, ShouldBeNil)
|
||||
So(aclResponse, ShouldBeFalse)
|
||||
|
||||
aclResponse = checker.CheckAcl("correct", "test/topic", "wrong-id", 1)
|
||||
aclResponse, err = checker.CheckAcl("correct", "test/topic", "wrong-id", 1)
|
||||
So(err, ShouldBeNil)
|
||||
So(aclResponse, ShouldBeFalse)
|
||||
|
||||
aclResponse = checker.CheckAcl("correct", "test/topic", "id", 2)
|
||||
aclResponse, err = checker.CheckAcl("correct", "test/topic", "id", 2)
|
||||
So(err, ShouldBeNil)
|
||||
So(aclResponse, ShouldBeFalse)
|
||||
|
||||
Convey("Tokens may be pre-parsed and passed to the scripts", func() {
|
||||
|
@ -157,7 +166,8 @@ func TestJsJWTChecker(t *testing.T) {
|
|||
token, err := jwtToken.SignedString([]byte(jwtSecret))
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
userResponse := checker.GetUser(token)
|
||||
userResponse, err := checker.GetUser(token)
|
||||
So(err, ShouldBeNil)
|
||||
So(userResponse, ShouldBeTrue)
|
||||
})
|
||||
})
|
||||
|
@ -222,7 +232,8 @@ func TestLocalPostgresJWT(t *testing.T) {
|
|||
|
||||
Convey("Given a correct token, it should correctly authenticate it", func() {
|
||||
|
||||
authenticated := jwt.GetUser(token)
|
||||
authenticated, err := jwt.GetUser(token)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeTrue)
|
||||
})
|
||||
|
||||
|
@ -231,21 +242,24 @@ func TestLocalPostgresJWT(t *testing.T) {
|
|||
wrongToken, err := wrongJwtToken.SignedString([]byte(jwtSecret))
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
authenticated := jwt.GetUser(wrongToken)
|
||||
authenticated, err := jwt.GetUser(wrongToken)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given a token that is admin, super user should pass", func() {
|
||||
superuser := jwt.GetSuperuser(token)
|
||||
superuser, err := jwt.GetSuperuser(token)
|
||||
So(err, ShouldBeNil)
|
||||
So(superuser, ShouldBeTrue)
|
||||
|
||||
Convey("But disabling superusers by removing superuri should now return false", func() {
|
||||
authOpts["jwt_superquery"] = ""
|
||||
authOpts["jwt_pg_superquery"] = ""
|
||||
jwt, err := NewLocalJWTChecker(authOpts, log.DebugLevel, hashing.NewHasher(authOpts, ""), tkOptions)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
superuser := jwt.GetSuperuser(username)
|
||||
superuser, err := jwt.GetSuperuser(token)
|
||||
So(err, ShouldBeNil)
|
||||
So(superuser, ShouldBeFalse)
|
||||
})
|
||||
})
|
||||
|
@ -268,9 +282,11 @@ func TestLocalPostgresJWT(t *testing.T) {
|
|||
testTopic1 := `test/topic/1`
|
||||
testTopic2 := `test/topic/2`
|
||||
|
||||
tt1 := jwt.CheckAcl(token, testTopic1, clientID, MOSQ_ACL_READ)
|
||||
tt2 := jwt.CheckAcl(token, testTopic2, clientID, MOSQ_ACL_READ)
|
||||
tt1, err1 := jwt.CheckAcl(token, testTopic1, clientID, MOSQ_ACL_READ)
|
||||
tt2, err2 := jwt.CheckAcl(token, testTopic2, clientID, MOSQ_ACL_READ)
|
||||
|
||||
So(err1, ShouldBeNil)
|
||||
So(err2, ShouldBeNil)
|
||||
So(tt1, ShouldBeTrue)
|
||||
So(tt2, ShouldBeFalse)
|
||||
|
||||
|
@ -279,16 +295,19 @@ func TestLocalPostgresJWT(t *testing.T) {
|
|||
Convey("Given read only privileges, a pub check should fail", func() {
|
||||
|
||||
testTopic1 := "test/topic/1"
|
||||
tt1 := jwt.CheckAcl(token, testTopic1, clientID, MOSQ_ACL_WRITE)
|
||||
tt1, err1 := jwt.CheckAcl(token, testTopic1, clientID, MOSQ_ACL_WRITE)
|
||||
So(err1, ShouldBeNil)
|
||||
So(tt1, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given wildcard subscriptions against strict db acl, acl checks should fail", func() {
|
||||
|
||||
tt1 := jwt.CheckAcl(token, singleLevelACL, clientID, MOSQ_ACL_READ)
|
||||
tt2 := jwt.CheckAcl(token, hierarchyACL, clientID, MOSQ_ACL_READ)
|
||||
tt1, err1 := jwt.CheckAcl(token, singleLevelACL, clientID, MOSQ_ACL_READ)
|
||||
tt2, err2 := jwt.CheckAcl(token, hierarchyACL, clientID, MOSQ_ACL_READ)
|
||||
|
||||
So(err1, ShouldBeNil)
|
||||
So(err2, ShouldBeNil)
|
||||
So(tt1, ShouldBeFalse)
|
||||
So(tt2, ShouldBeFalse)
|
||||
|
||||
|
@ -300,7 +319,8 @@ func TestLocalPostgresJWT(t *testing.T) {
|
|||
So(err, ShouldBeNil)
|
||||
|
||||
Convey("Given a topic not strictly present that matches a db single level wildcard, acl check should pass", func() {
|
||||
tt1 := jwt.CheckAcl(token, "test/topic/whatever", clientID, MOSQ_ACL_READ)
|
||||
tt1, err1 := jwt.CheckAcl(token, "test/topic/whatever", clientID, MOSQ_ACL_READ)
|
||||
So(err1, ShouldBeNil)
|
||||
So(tt1, ShouldBeTrue)
|
||||
})
|
||||
|
||||
|
@ -310,7 +330,8 @@ func TestLocalPostgresJWT(t *testing.T) {
|
|||
So(err, ShouldBeNil)
|
||||
|
||||
Convey("Given a topic not strictly present that matches a hierarchy wildcard, acl check should pass", func() {
|
||||
tt1 := jwt.CheckAcl(token, "test/what/ever", clientID, MOSQ_ACL_READ)
|
||||
tt1, err1 := jwt.CheckAcl(token, "test/what/ever", clientID, MOSQ_ACL_READ)
|
||||
So(err1, ShouldBeNil)
|
||||
So(tt1, ShouldBeTrue)
|
||||
})
|
||||
|
||||
|
@ -324,13 +345,16 @@ func TestLocalPostgresJWT(t *testing.T) {
|
|||
|
||||
Convey("So checking against them should give false and true for any user", func() {
|
||||
|
||||
tt1 := jwt.CheckAcl(token, singleLevelACL, clientID, MOSQ_ACL_READ)
|
||||
tt2 := jwt.CheckAcl(token, hierarchyACL, clientID, MOSQ_ACL_READ)
|
||||
tt1, err1 := jwt.CheckAcl(token, singleLevelACL, clientID, MOSQ_ACL_READ)
|
||||
tt2, err2 := jwt.CheckAcl(token, hierarchyACL, clientID, MOSQ_ACL_READ)
|
||||
|
||||
So(err1, ShouldBeNil)
|
||||
So(err2, ShouldBeNil)
|
||||
So(tt1, ShouldBeTrue)
|
||||
So(tt2, ShouldBeTrue)
|
||||
|
||||
superuser := jwt.GetSuperuser(token)
|
||||
superuser, err := jwt.GetSuperuser(token)
|
||||
So(err, ShouldBeNil)
|
||||
So(superuser, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
@ -411,7 +435,8 @@ func TestLocalMysqlJWT(t *testing.T) {
|
|||
|
||||
Convey("Given a correct token, it should correctly authenticate it", func() {
|
||||
|
||||
authenticated := jwt.GetUser(token)
|
||||
authenticated, err := jwt.GetUser(token)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeTrue)
|
||||
|
||||
})
|
||||
|
@ -421,20 +446,23 @@ func TestLocalMysqlJWT(t *testing.T) {
|
|||
wrongToken, err := wrongJwtToken.SignedString([]byte(jwtSecret))
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
authenticated := jwt.GetUser(wrongToken)
|
||||
authenticated, err := jwt.GetUser(wrongToken)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given a token that is admin, super user should pass", func() {
|
||||
superuser := jwt.GetSuperuser(token)
|
||||
superuser, err := jwt.GetSuperuser(token)
|
||||
So(err, ShouldBeNil)
|
||||
So(superuser, ShouldBeTrue)
|
||||
Convey("But disabling superusers by removing superuri should now return false", func() {
|
||||
authOpts["jwt_superquery"] = ""
|
||||
authOpts["jwt_mysql_superquery"] = ""
|
||||
jwt, err := NewLocalJWTChecker(authOpts, log.DebugLevel, hashing.NewHasher(authOpts, ""), tkOptions)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
superuser := jwt.GetSuperuser(username)
|
||||
superuser, err := jwt.GetSuperuser(token)
|
||||
So(err, ShouldBeNil)
|
||||
So(superuser, ShouldBeFalse)
|
||||
})
|
||||
})
|
||||
|
@ -458,9 +486,11 @@ func TestLocalMysqlJWT(t *testing.T) {
|
|||
testTopic1 := `test/topic/1`
|
||||
testTopic2 := `test/topic/2`
|
||||
|
||||
tt1 := jwt.CheckAcl(token, testTopic1, clientID, MOSQ_ACL_READ)
|
||||
tt2 := jwt.CheckAcl(token, testTopic2, clientID, MOSQ_ACL_READ)
|
||||
tt1, err1 := jwt.CheckAcl(token, testTopic1, clientID, MOSQ_ACL_READ)
|
||||
tt2, err2 := jwt.CheckAcl(token, testTopic2, clientID, MOSQ_ACL_READ)
|
||||
|
||||
So(err1, ShouldBeNil)
|
||||
So(err2, ShouldBeNil)
|
||||
So(tt1, ShouldBeTrue)
|
||||
So(tt2, ShouldBeFalse)
|
||||
|
||||
|
@ -469,16 +499,19 @@ func TestLocalMysqlJWT(t *testing.T) {
|
|||
Convey("Given read only privileges, a pub check should fail", func() {
|
||||
|
||||
testTopic1 := "test/topic/1"
|
||||
tt1 := jwt.CheckAcl(token, testTopic1, clientID, MOSQ_ACL_WRITE)
|
||||
tt1, err1 := jwt.CheckAcl(token, testTopic1, clientID, MOSQ_ACL_WRITE)
|
||||
So(err1, ShouldBeNil)
|
||||
So(tt1, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given wildcard subscriptions against strict db acl, acl checks should fail", func() {
|
||||
|
||||
tt1 := jwt.CheckAcl(token, singleLevelACL, clientID, MOSQ_ACL_READ)
|
||||
tt2 := jwt.CheckAcl(token, hierarchyACL, clientID, MOSQ_ACL_READ)
|
||||
tt1, err1 := jwt.CheckAcl(token, singleLevelACL, clientID, MOSQ_ACL_READ)
|
||||
tt2, err2 := jwt.CheckAcl(token, hierarchyACL, clientID, MOSQ_ACL_READ)
|
||||
|
||||
So(err1, ShouldBeNil)
|
||||
So(err2, ShouldBeNil)
|
||||
So(tt1, ShouldBeFalse)
|
||||
So(tt2, ShouldBeFalse)
|
||||
|
||||
|
@ -490,7 +523,8 @@ func TestLocalMysqlJWT(t *testing.T) {
|
|||
So(err, ShouldBeNil)
|
||||
|
||||
Convey("Given a topic not strictly present that matches a db single level wildcard, acl check should pass", func() {
|
||||
tt1 := jwt.CheckAcl(token, "test/topic/whatever", clientID, MOSQ_ACL_READ)
|
||||
tt1, err1 := jwt.CheckAcl(token, "test/topic/whatever", clientID, MOSQ_ACL_READ)
|
||||
So(err1, ShouldBeNil)
|
||||
So(tt1, ShouldBeTrue)
|
||||
})
|
||||
|
||||
|
@ -500,7 +534,8 @@ func TestLocalMysqlJWT(t *testing.T) {
|
|||
So(err, ShouldBeNil)
|
||||
|
||||
Convey("Given a topic not strictly present that matches a hierarchy wildcard, acl check should pass", func() {
|
||||
tt1 := jwt.CheckAcl(token, "test/what/ever", clientID, MOSQ_ACL_READ)
|
||||
tt1, err1 := jwt.CheckAcl(token, "test/what/ever", clientID, MOSQ_ACL_READ)
|
||||
So(err1, ShouldBeNil)
|
||||
So(tt1, ShouldBeTrue)
|
||||
})
|
||||
|
||||
|
@ -514,13 +549,16 @@ func TestLocalMysqlJWT(t *testing.T) {
|
|||
|
||||
Convey("So checking against them should give false and true for any user", func() {
|
||||
|
||||
tt1 := jwt.CheckAcl(token, singleLevelACL, clientID, MOSQ_ACL_READ)
|
||||
tt2 := jwt.CheckAcl(token, hierarchyACL, clientID, MOSQ_ACL_READ)
|
||||
tt1, err1 := jwt.CheckAcl(token, singleLevelACL, clientID, MOSQ_ACL_READ)
|
||||
tt2, err2 := jwt.CheckAcl(token, hierarchyACL, clientID, MOSQ_ACL_READ)
|
||||
|
||||
So(err1, ShouldBeNil)
|
||||
So(err2, ShouldBeNil)
|
||||
So(tt1, ShouldBeTrue)
|
||||
So(tt2, ShouldBeTrue)
|
||||
|
||||
superuser := jwt.GetSuperuser(token)
|
||||
superuser, err := jwt.GetSuperuser(token)
|
||||
So(err, ShouldBeNil)
|
||||
So(superuser, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
@ -626,21 +664,24 @@ func TestJWTAllJsonServer(t *testing.T) {
|
|||
|
||||
Convey("Given correct password/username, get user should return true", func() {
|
||||
|
||||
authenticated := hb.GetUser(token, "", "")
|
||||
authenticated, err := hb.GetUser(token, "", "")
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeTrue)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given incorrect password/username, get user should return false", func() {
|
||||
|
||||
authenticated := hb.GetUser(wrongToken, "", "")
|
||||
authenticated, err := hb.GetUser(wrongToken, "", "")
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given correct username, get superuser should return true", func() {
|
||||
|
||||
authenticated := hb.GetSuperuser(token)
|
||||
authenticated, err := hb.GetSuperuser(token)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeTrue)
|
||||
|
||||
Convey("But disabling superusers by removing superuri should now return false", func() {
|
||||
|
@ -648,7 +689,8 @@ func TestJWTAllJsonServer(t *testing.T) {
|
|||
hb, err := NewJWT(authOpts, log.DebugLevel, hashing.NewHasher(authOpts, ""))
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
superuser := hb.GetSuperuser(username)
|
||||
superuser, err := hb.GetSuperuser(username)
|
||||
So(err, ShouldBeNil)
|
||||
So(superuser, ShouldBeFalse)
|
||||
})
|
||||
|
||||
|
@ -656,35 +698,40 @@ func TestJWTAllJsonServer(t *testing.T) {
|
|||
|
||||
Convey("Given incorrect username, get superuser should return false", func() {
|
||||
|
||||
authenticated := hb.GetSuperuser(wrongToken)
|
||||
authenticated, err := hb.GetSuperuser(wrongToken)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given correct topic, username, client id and acc, acl check should return true", func() {
|
||||
|
||||
authenticated := hb.CheckAcl(token, topic, clientID, MOSQ_ACL_READ)
|
||||
authenticated, err := hb.CheckAcl(token, topic, clientID, MOSQ_ACL_READ)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeTrue)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given an acc that requires more privileges than the user has, check acl should return false", func() {
|
||||
|
||||
authenticated := hb.CheckAcl(token, topic, clientID, MOSQ_ACL_WRITE)
|
||||
authenticated, err := hb.CheckAcl(token, topic, clientID, MOSQ_ACL_WRITE)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given a topic not present in acls, check acl should return false", func() {
|
||||
|
||||
authenticated := hb.CheckAcl(token, "fake/topic", clientID, MOSQ_ACL_READ)
|
||||
authenticated, err := hb.CheckAcl(token, "fake/topic", clientID, MOSQ_ACL_READ)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given a clientID that doesn't match, check acl should return false", func() {
|
||||
|
||||
authenticated := hb.CheckAcl(token, topic, "fake_client_id", MOSQ_ACL_READ)
|
||||
authenticated, err := hb.CheckAcl(token, topic, "fake_client_id", MOSQ_ACL_READ)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
@ -758,21 +805,24 @@ func TestJWTJsonStatusOnlyServer(t *testing.T) {
|
|||
|
||||
Convey("Given correct password/username, get user should return true", func() {
|
||||
|
||||
authenticated := hb.GetUser(token, "", "")
|
||||
authenticated, err := hb.GetUser(token, "", "")
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeTrue)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given incorrect password/username, get user should return false", func() {
|
||||
|
||||
authenticated := hb.GetUser(wrongToken, "", "")
|
||||
authenticated, err := hb.GetUser(wrongToken, "", "")
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given correct username, get superuser should return true", func() {
|
||||
|
||||
authenticated := hb.GetSuperuser(token)
|
||||
authenticated, err := hb.GetSuperuser(token)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeTrue)
|
||||
|
||||
Convey("But disabling superusers by removing superuri should now return false", func() {
|
||||
|
@ -780,7 +830,8 @@ func TestJWTJsonStatusOnlyServer(t *testing.T) {
|
|||
hb, err := NewJWT(authOpts, log.DebugLevel, hashing.NewHasher(authOpts, ""))
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
superuser := hb.GetSuperuser(username)
|
||||
superuser, err := hb.GetSuperuser(username)
|
||||
So(err, ShouldBeNil)
|
||||
So(superuser, ShouldBeFalse)
|
||||
})
|
||||
|
||||
|
@ -788,35 +839,40 @@ func TestJWTJsonStatusOnlyServer(t *testing.T) {
|
|||
|
||||
Convey("Given incorrect username, get superuser should return false", func() {
|
||||
|
||||
authenticated := hb.GetSuperuser(wrongToken)
|
||||
authenticated, err := hb.GetSuperuser(wrongToken)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given correct topic, username, client id and acc, acl check should return true", func() {
|
||||
|
||||
authenticated := hb.CheckAcl(token, topic, clientID, MOSQ_ACL_READ)
|
||||
authenticated, err := hb.CheckAcl(token, topic, clientID, MOSQ_ACL_READ)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeTrue)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given an acc that requires more privileges than the user has, check acl should return false", func() {
|
||||
|
||||
authenticated := hb.CheckAcl(token, topic, clientID, MOSQ_ACL_WRITE)
|
||||
authenticated, err := hb.CheckAcl(token, topic, clientID, MOSQ_ACL_WRITE)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given a topic not present in acls, check acl should return false", func() {
|
||||
|
||||
authenticated := hb.CheckAcl(token, "fake/topic", clientID, MOSQ_ACL_READ)
|
||||
authenticated, err := hb.CheckAcl(token, "fake/topic", clientID, MOSQ_ACL_READ)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given a clientID that doesn't match, check acl should return false", func() {
|
||||
|
||||
authenticated := hb.CheckAcl(token, topic, "fake_client_id", MOSQ_ACL_READ)
|
||||
authenticated, err := hb.CheckAcl(token, topic, "fake_client_id", MOSQ_ACL_READ)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
@ -892,21 +948,24 @@ func TestJWTJsonTextResponseServer(t *testing.T) {
|
|||
|
||||
Convey("Given correct password/username, get user should return true", func() {
|
||||
|
||||
authenticated := hb.GetUser(token, "", "")
|
||||
authenticated, err := hb.GetUser(token, "", "")
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeTrue)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given incorrect password/username, get user should return false", func() {
|
||||
|
||||
authenticated := hb.GetUser(wrongToken, "", "")
|
||||
authenticated, err := hb.GetUser(wrongToken, "", "")
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given correct username, get superuser should return true", func() {
|
||||
|
||||
authenticated := hb.GetSuperuser(token)
|
||||
authenticated, err := hb.GetSuperuser(token)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeTrue)
|
||||
|
||||
Convey("But disabling superusers by removing superuri should now return false", func() {
|
||||
|
@ -914,7 +973,8 @@ func TestJWTJsonTextResponseServer(t *testing.T) {
|
|||
hb, err := NewJWT(authOpts, log.DebugLevel, hashing.NewHasher(authOpts, ""))
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
superuser := hb.GetSuperuser(username)
|
||||
superuser, err := hb.GetSuperuser(username)
|
||||
So(err, ShouldBeNil)
|
||||
So(superuser, ShouldBeFalse)
|
||||
})
|
||||
|
||||
|
@ -922,35 +982,40 @@ func TestJWTJsonTextResponseServer(t *testing.T) {
|
|||
|
||||
Convey("Given incorrect username, get superuser should return false", func() {
|
||||
|
||||
authenticated := hb.GetSuperuser(wrongToken)
|
||||
authenticated, err := hb.GetSuperuser(wrongToken)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given correct topic, username, client id and acc, acl check should return true", func() {
|
||||
|
||||
authenticated := hb.CheckAcl(token, topic, clientID, MOSQ_ACL_READ)
|
||||
authenticated, err := hb.CheckAcl(token, topic, clientID, MOSQ_ACL_READ)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeTrue)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given an acc that requires more privileges than the user has, check acl should return false", func() {
|
||||
|
||||
authenticated := hb.CheckAcl(token, topic, clientID, MOSQ_ACL_WRITE)
|
||||
authenticated, err := hb.CheckAcl(token, topic, clientID, MOSQ_ACL_WRITE)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given a topic not present in acls, check acl should return false", func() {
|
||||
|
||||
authenticated := hb.CheckAcl(token, "fake/topic", clientID, MOSQ_ACL_READ)
|
||||
authenticated, err := hb.CheckAcl(token, "fake/topic", clientID, MOSQ_ACL_READ)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given a clientID that doesn't match, check acl should return false", func() {
|
||||
|
||||
authenticated := hb.CheckAcl(token, topic, "fake_client_id", MOSQ_ACL_READ)
|
||||
authenticated, err := hb.CheckAcl(token, topic, "fake_client_id", MOSQ_ACL_READ)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
@ -1036,21 +1101,24 @@ func TestJWTFormJsonResponseServer(t *testing.T) {
|
|||
|
||||
Convey("Given correct password/username, get user should return true", func() {
|
||||
|
||||
authenticated := hb.GetUser(token, "", "")
|
||||
authenticated, err := hb.GetUser(token, "", "")
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeTrue)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given incorrect password/username, get user should return false", func() {
|
||||
|
||||
authenticated := hb.GetUser(wrongToken, "", "")
|
||||
authenticated, err := hb.GetUser(wrongToken, "", "")
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given correct username, get superuser should return true", func() {
|
||||
|
||||
authenticated := hb.GetSuperuser(token)
|
||||
authenticated, err := hb.GetSuperuser(token)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeTrue)
|
||||
|
||||
Convey("But disabling superusers by removing superuri should now return false", func() {
|
||||
|
@ -1058,7 +1126,8 @@ func TestJWTFormJsonResponseServer(t *testing.T) {
|
|||
hb, err := NewJWT(authOpts, log.DebugLevel, hashing.NewHasher(authOpts, ""))
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
superuser := hb.GetSuperuser(username)
|
||||
superuser, err := hb.GetSuperuser(username)
|
||||
So(err, ShouldBeNil)
|
||||
So(superuser, ShouldBeFalse)
|
||||
})
|
||||
|
||||
|
@ -1066,35 +1135,40 @@ func TestJWTFormJsonResponseServer(t *testing.T) {
|
|||
|
||||
Convey("Given incorrect username, get superuser should return false", func() {
|
||||
|
||||
authenticated := hb.GetSuperuser(wrongToken)
|
||||
authenticated, err := hb.GetSuperuser(wrongToken)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given correct topic, username, client id and acc, acl check should return true", func() {
|
||||
|
||||
authenticated := hb.CheckAcl(token, topic, clientID, MOSQ_ACL_READ)
|
||||
authenticated, err := hb.CheckAcl(token, topic, clientID, MOSQ_ACL_READ)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeTrue)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given an acc that requires more privileges than the user has, check acl should return false", func() {
|
||||
|
||||
authenticated := hb.CheckAcl(token, topic, clientID, MOSQ_ACL_WRITE)
|
||||
authenticated, err := hb.CheckAcl(token, topic, clientID, MOSQ_ACL_WRITE)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given a topic not present in acls, check acl should return false", func() {
|
||||
|
||||
authenticated := hb.CheckAcl(token, "fake/topic", clientID, MOSQ_ACL_READ)
|
||||
authenticated, err := hb.CheckAcl(token, "fake/topic", clientID, MOSQ_ACL_READ)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given a clientID that doesn't match, check acl should return false", func() {
|
||||
|
||||
authenticated := hb.CheckAcl(token, topic, "fake_client_id", MOSQ_ACL_READ)
|
||||
authenticated, err := hb.CheckAcl(token, topic, "fake_client_id", MOSQ_ACL_READ)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
@ -1162,21 +1236,24 @@ func TestJWTFormStatusOnlyServer(t *testing.T) {
|
|||
|
||||
Convey("Given correct password/username, get user should return true", func() {
|
||||
|
||||
authenticated := hb.GetUser(token, "", "")
|
||||
authenticated, err := hb.GetUser(token, "", "")
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeTrue)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given incorrect password/username, get user should return false", func() {
|
||||
|
||||
authenticated := hb.GetUser(wrongToken, "", "")
|
||||
authenticated, err := hb.GetUser(wrongToken, "", "")
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given correct username, get superuser should return true", func() {
|
||||
|
||||
authenticated := hb.GetSuperuser(token)
|
||||
authenticated, err := hb.GetSuperuser(token)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeTrue)
|
||||
|
||||
Convey("But disabling superusers by removing superuri should now return false", func() {
|
||||
|
@ -1184,7 +1261,8 @@ func TestJWTFormStatusOnlyServer(t *testing.T) {
|
|||
hb, err := NewJWT(authOpts, log.DebugLevel, hashing.NewHasher(authOpts, ""))
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
superuser := hb.GetSuperuser(username)
|
||||
superuser, err := hb.GetSuperuser(username)
|
||||
So(err, ShouldBeNil)
|
||||
So(superuser, ShouldBeFalse)
|
||||
})
|
||||
|
||||
|
@ -1192,35 +1270,40 @@ func TestJWTFormStatusOnlyServer(t *testing.T) {
|
|||
|
||||
Convey("Given incorrect username, get superuser should return false", func() {
|
||||
|
||||
authenticated := hb.GetSuperuser(wrongToken)
|
||||
authenticated, err := hb.GetSuperuser(wrongToken)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given correct topic, username, client id and acc, acl check should return true", func() {
|
||||
|
||||
authenticated := hb.CheckAcl(token, topic, clientID, MOSQ_ACL_READ)
|
||||
authenticated, err := hb.CheckAcl(token, topic, clientID, MOSQ_ACL_READ)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeTrue)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given an acc that requires more privileges than the user has, check acl should return false", func() {
|
||||
|
||||
authenticated := hb.CheckAcl(token, topic, clientID, MOSQ_ACL_WRITE)
|
||||
authenticated, err := hb.CheckAcl(token, topic, clientID, MOSQ_ACL_WRITE)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given a topic not present in acls, check acl should return false", func() {
|
||||
|
||||
authenticated := hb.CheckAcl(token, "fake/topic", clientID, MOSQ_ACL_READ)
|
||||
authenticated, err := hb.CheckAcl(token, "fake/topic", clientID, MOSQ_ACL_READ)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given a clientID that doesn't match, check acl should return false", func() {
|
||||
|
||||
authenticated := hb.CheckAcl(token, topic, "fake_client_id", MOSQ_ACL_READ)
|
||||
authenticated, err := hb.CheckAcl(token, topic, "fake_client_id", MOSQ_ACL_READ)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
@ -1291,21 +1374,24 @@ func TestJWTFormTextResponseServer(t *testing.T) {
|
|||
|
||||
Convey("Given correct password/username, get user should return true", func() {
|
||||
|
||||
authenticated := hb.GetUser(token, "", "")
|
||||
authenticated, err := hb.GetUser(token, "", "")
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeTrue)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given incorrect password/username, get user should return false", func() {
|
||||
|
||||
authenticated := hb.GetUser(wrongToken, "", "")
|
||||
authenticated, err := hb.GetUser(wrongToken, "", "")
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given correct username, get superuser should return true", func() {
|
||||
|
||||
authenticated := hb.GetSuperuser(token)
|
||||
authenticated, err := hb.GetSuperuser(token)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeTrue)
|
||||
|
||||
Convey("But disabling superusers by removing superuri should now return false", func() {
|
||||
|
@ -1313,7 +1399,8 @@ func TestJWTFormTextResponseServer(t *testing.T) {
|
|||
hb, err := NewJWT(authOpts, log.DebugLevel, hashing.NewHasher(authOpts, ""))
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
superuser := hb.GetSuperuser(username)
|
||||
superuser, err := hb.GetSuperuser(username)
|
||||
So(err, ShouldBeNil)
|
||||
So(superuser, ShouldBeFalse)
|
||||
})
|
||||
|
||||
|
@ -1321,35 +1408,40 @@ func TestJWTFormTextResponseServer(t *testing.T) {
|
|||
|
||||
Convey("Given incorrect username, get superuser should return false", func() {
|
||||
|
||||
authenticated := hb.GetSuperuser(wrongToken)
|
||||
authenticated, err := hb.GetSuperuser(wrongToken)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given correct topic, username, client id and acc, acl check should return true", func() {
|
||||
|
||||
authenticated := hb.CheckAcl(token, topic, clientID, MOSQ_ACL_READ)
|
||||
authenticated, err := hb.CheckAcl(token, topic, clientID, MOSQ_ACL_READ)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeTrue)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given an acc that requires more privileges than the user has, check acl should return false", func() {
|
||||
|
||||
authenticated := hb.CheckAcl(token, topic, clientID, MOSQ_ACL_WRITE)
|
||||
authenticated, err := hb.CheckAcl(token, topic, clientID, MOSQ_ACL_WRITE)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given a topic not present in acls, check acl should return false", func() {
|
||||
|
||||
authenticated := hb.CheckAcl(token, "fake/topic", clientID, MOSQ_ACL_READ)
|
||||
authenticated, err := hb.CheckAcl(token, "fake/topic", clientID, MOSQ_ACL_READ)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given a clientID that doesn't match, check acl should return false", func() {
|
||||
|
||||
authenticated := hb.CheckAcl(token, topic, "fake_client_id", MOSQ_ACL_READ)
|
||||
authenticated, err := hb.CheckAcl(token, topic, "fake_client_id", MOSQ_ACL_READ)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
|
|
@ -128,7 +128,7 @@ func NewMongo(authOpts map[string]string, logLevel log.Level, hasher hashing.Has
|
|||
}
|
||||
|
||||
//GetUser checks that the username exists and the given password hashes to the same password.
|
||||
func (o Mongo) GetUser(username, password, clientid string) bool {
|
||||
func (o Mongo) GetUser(username, password, clientid string) (bool, error) {
|
||||
|
||||
uc := o.Conn.Database(o.DBName).Collection(o.UsersCollection)
|
||||
|
||||
|
@ -136,23 +136,28 @@ func (o Mongo) GetUser(username, password, clientid string) bool {
|
|||
|
||||
err := uc.FindOne(context.TODO(), bson.M{"username": username}).Decode(&user)
|
||||
if err != nil {
|
||||
if err == mongo.ErrNoDocuments {
|
||||
// avoid leaking the fact that user exists or not though error.
|
||||
return false, nil
|
||||
}
|
||||
|
||||
log.Debugf("Mongo get user error: %s", err)
|
||||
return false
|
||||
return false, err
|
||||
}
|
||||
|
||||
if o.hasher.Compare(password, user.PasswordHash) {
|
||||
return true
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return false
|
||||
return false, nil
|
||||
|
||||
}
|
||||
|
||||
//GetSuperuser checks that the key username:su exists and has value "true".
|
||||
func (o Mongo) GetSuperuser(username string) bool {
|
||||
func (o Mongo) GetSuperuser(username string) (bool, error) {
|
||||
|
||||
if o.disableSuperuser {
|
||||
return false
|
||||
return false, nil
|
||||
}
|
||||
|
||||
uc := o.Conn.Database(o.DBName).Collection(o.UsersCollection)
|
||||
|
@ -161,16 +166,21 @@ func (o Mongo) GetSuperuser(username string) bool {
|
|||
|
||||
err := uc.FindOne(context.TODO(), bson.M{"username": username}).Decode(&user)
|
||||
if err != nil {
|
||||
if err == mongo.ErrNoDocuments {
|
||||
// avoid leaking the fact that user exists or not though error.
|
||||
return false, nil
|
||||
}
|
||||
|
||||
log.Debugf("Mongo get superuser error: %s", err)
|
||||
return false
|
||||
return false, err
|
||||
}
|
||||
|
||||
return user.Superuser
|
||||
return user.Superuser, nil
|
||||
|
||||
}
|
||||
|
||||
//CheckAcl gets all acls for the username and tries to match against topic, acc, and username/clientid if needed.
|
||||
func (o Mongo) CheckAcl(username, topic, clientid string, acc int32) bool {
|
||||
func (o Mongo) CheckAcl(username, topic, clientid string, acc int32) (bool, error) {
|
||||
|
||||
//Get user and check his acls.
|
||||
uc := o.Conn.Database(o.DBName).Collection(o.UsersCollection)
|
||||
|
@ -179,13 +189,18 @@ func (o Mongo) CheckAcl(username, topic, clientid string, acc int32) bool {
|
|||
|
||||
err := uc.FindOne(context.TODO(), bson.M{"username": username}).Decode(&user)
|
||||
if err != nil {
|
||||
if err == mongo.ErrNoDocuments {
|
||||
// avoid leaking the fact that user exists or not though error.
|
||||
return false, nil
|
||||
}
|
||||
|
||||
log.Debugf("Mongo get superuser error: %s", err)
|
||||
return false
|
||||
return false, err
|
||||
}
|
||||
|
||||
for _, acl := range user.Acls {
|
||||
if (acl.Acc == acc || acl.Acc == 3) && TopicsMatch(acl.Topic, topic) {
|
||||
return true
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -196,7 +211,7 @@ func (o Mongo) CheckAcl(username, topic, clientid string, acc int32) bool {
|
|||
|
||||
if err != nil {
|
||||
log.Debugf("Mongo check acl error: %s", err)
|
||||
return false
|
||||
return false, err
|
||||
}
|
||||
|
||||
defer cur.Close(context.TODO())
|
||||
|
@ -208,14 +223,14 @@ func (o Mongo) CheckAcl(username, topic, clientid string, acc int32) bool {
|
|||
aclTopic := strings.Replace(acl.Topic, "%c", clientid, -1)
|
||||
aclTopic = strings.Replace(aclTopic, "%u", username, -1)
|
||||
if TopicsMatch(aclTopic, topic) {
|
||||
return true
|
||||
return true, nil
|
||||
}
|
||||
} else {
|
||||
log.Errorf("mongo cursor decode error: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
return false, nil
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@ func TestMongoRaw(t *testing.T) {
|
|||
const username2 = "test2"
|
||||
const userPass2 = "testpw"
|
||||
const userPassHash2 = "PBKDF2$sha512$100000$os24lcPr9cJt2QDVWssblQ==$dEOwgFUoMNt+Q8FHWXl03pZTg/RY47JdSTAx/KjhYKpbugOYg1WWG0tW0V2aqBnSCDLYJdRrkNf3p/PUoKLvkA=="
|
||||
const wrongUsername = "not_present"
|
||||
|
||||
//Define Common Mongo Configuration
|
||||
var authOpts = make(map[string]string)
|
||||
|
@ -81,38 +82,57 @@ func TestMongoRaw(t *testing.T) {
|
|||
So(err, ShouldBeNil)
|
||||
|
||||
Convey("Given username1 and a correct password, it should correctly authenticate it", func() {
|
||||
authenticated := mongo.GetUser(username1, userPass1, "")
|
||||
authenticated, err := mongo.GetUser(username1, userPass1, "")
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeTrue)
|
||||
})
|
||||
Convey("Given username1 and an incorrect password, it should not authenticate it", func() {
|
||||
authenticated := mongo.GetUser(username1, "wrong_password", "")
|
||||
authenticated, err := mongo.GetUser(username1, "wrong_password", "")
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
})
|
||||
Convey("Given wrongusername, it should not authenticate it and don't return error", func() {
|
||||
authenticated, err := mongo.GetUser(wrongUsername, "whatever_password", "")
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
})
|
||||
Convey("Given username1 that is superuser, super user check should pass", func() {
|
||||
superuser := mongo.GetSuperuser(username1)
|
||||
superuser, err := mongo.GetSuperuser(username1)
|
||||
So(err, ShouldBeNil)
|
||||
So(superuser, ShouldBeTrue)
|
||||
Convey("But disabling superusers should now return false", func() {
|
||||
mongo.disableSuperuser = true
|
||||
superuser := mongo.GetSuperuser(username1)
|
||||
superuser, err := mongo.GetSuperuser(username1)
|
||||
So(err, ShouldBeNil)
|
||||
So(superuser, ShouldBeFalse)
|
||||
})
|
||||
})
|
||||
Convey("Given wrongusername, super check should no pass and don't return error", func() {
|
||||
authenticated, err := mongo.GetSuperuser(wrongUsername)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
})
|
||||
Convey("Given correct username2 password, but using wrong salt format, user should not authenticate", func() {
|
||||
authenticated := mongo.GetUser(username2, userPass2, "")
|
||||
authenticated, err := mongo.GetUser(username2, userPass2, "")
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
})
|
||||
clientID := "test_client"
|
||||
Convey("Given acls in db, an exact match should work and and inexact one not matching wildcards not", func() {
|
||||
testTopic1 := `test/topic/1`
|
||||
testTopic2 := `not/matching/topic`
|
||||
tt1 := mongo.CheckAcl(username1, testTopic1, clientID, MOSQ_ACL_READ)
|
||||
tt2 := mongo.CheckAcl(username1, testTopic2, clientID, MOSQ_ACL_READ)
|
||||
tt1, err1 := mongo.CheckAcl(username1, testTopic1, clientID, MOSQ_ACL_READ)
|
||||
tt2, err2 := mongo.CheckAcl(username1, testTopic2, clientID, MOSQ_ACL_READ)
|
||||
So(err1, ShouldBeNil)
|
||||
So(err2, ShouldBeNil)
|
||||
So(tt1, ShouldBeTrue)
|
||||
So(tt2, ShouldBeFalse)
|
||||
})
|
||||
Convey("Given wildcard subscriptions that don't match user acls, acl checks should fail", func() {
|
||||
tt1 := mongo.CheckAcl(username1, "not/matching/+", clientID, MOSQ_ACL_READ)
|
||||
tt2 := mongo.CheckAcl(username1, "not/matching/#", clientID, MOSQ_ACL_READ)
|
||||
tt1, err1 := mongo.CheckAcl(username1, "not/matching/+", clientID, MOSQ_ACL_READ)
|
||||
tt2, err2 := mongo.CheckAcl(username1, "not/matching/#", clientID, MOSQ_ACL_READ)
|
||||
So(err1, ShouldBeNil)
|
||||
So(err2, ShouldBeNil)
|
||||
So(tt1, ShouldBeFalse)
|
||||
So(tt2, ShouldBeFalse)
|
||||
})
|
||||
|
@ -127,40 +147,55 @@ func TestMongoRaw(t *testing.T) {
|
|||
aclsColl.InsertOne(context.TODO(), &userAcl)
|
||||
aclsColl.InsertOne(context.TODO(), &clientAcl)
|
||||
Convey("Given a topic that mentions username and subscribes to it, acl check should pass", func() {
|
||||
tt1 := mongo.CheckAcl(username1, "pattern/test", clientID, MOSQ_ACL_READ)
|
||||
tt1, err1 := mongo.CheckAcl(username1, "pattern/test", clientID, MOSQ_ACL_READ)
|
||||
So(err1, ShouldBeNil)
|
||||
So(tt1, ShouldBeTrue)
|
||||
})
|
||||
Convey("Given a topic that mentions clientid, acl check should pass", func() {
|
||||
tt1 := mongo.CheckAcl(username1, "pattern/test_client", clientID, MOSQ_ACL_READ)
|
||||
tt1, err1 := mongo.CheckAcl(username1, "pattern/test_client", clientID, MOSQ_ACL_READ)
|
||||
So(err1, ShouldBeNil)
|
||||
So(tt1, ShouldBeTrue)
|
||||
})
|
||||
Convey("Given a topic not strictly present that matches a db single level wildcard, acl check should pass", func() {
|
||||
tt1 := mongo.CheckAcl(username1, "single/topic/whatever", clientID, MOSQ_ACL_READ)
|
||||
tt1, err1 := mongo.CheckAcl(username1, "single/topic/whatever", clientID, MOSQ_ACL_READ)
|
||||
So(err1, ShouldBeNil)
|
||||
So(tt1, ShouldBeTrue)
|
||||
})
|
||||
Convey("Given a topic that matches single level but has more levels, acl check should not pass", func() {
|
||||
tt1 := mongo.CheckAcl(username1, "single/topic/whatever/extra", clientID, MOSQ_ACL_READ)
|
||||
tt1, err1 := mongo.CheckAcl(username1, "single/topic/whatever/extra", clientID, MOSQ_ACL_READ)
|
||||
So(err1, ShouldBeNil)
|
||||
So(tt1, ShouldBeFalse)
|
||||
})
|
||||
Convey("Given a topic not strictly present that matches a hierarchy wildcard, acl check should pass", func() {
|
||||
tt1 := mongo.CheckAcl(username1, "hierarchy/what/ever", clientID, MOSQ_ACL_READ)
|
||||
tt1, err1 := mongo.CheckAcl(username1, "hierarchy/what/ever", clientID, MOSQ_ACL_READ)
|
||||
So(err1, ShouldBeNil)
|
||||
So(tt1, ShouldBeTrue)
|
||||
})
|
||||
//Now test against a publish subscription
|
||||
Convey("Given a publish attempt for a read only acl, acl check should fail", func() {
|
||||
tt1 := mongo.CheckAcl(username1, strictAcl, clientID, MOSQ_ACL_WRITE)
|
||||
tt1, err1 := mongo.CheckAcl(username1, strictAcl, clientID, MOSQ_ACL_WRITE)
|
||||
So(err1, ShouldBeNil)
|
||||
So(tt1, ShouldBeFalse)
|
||||
})
|
||||
Convey("Given a subscription attempt on a write only acl, acl check should fail", func() {
|
||||
tt1 := mongo.CheckAcl(username1, writeAcl, clientID, MOSQ_ACL_READ)
|
||||
tt1, err1 := mongo.CheckAcl(username1, writeAcl, clientID, MOSQ_ACL_READ)
|
||||
So(err1, ShouldBeNil)
|
||||
So(tt1, ShouldBeFalse)
|
||||
})
|
||||
Convey("Given a sub/pub attempt on a readwrite acl, acl check should pass for both", func() {
|
||||
tt1 := mongo.CheckAcl(username1, readWriteAcl, clientID, MOSQ_ACL_READ)
|
||||
tt2 := mongo.CheckAcl(username1, readWriteAcl, clientID, MOSQ_ACL_WRITE)
|
||||
tt1, err1 := mongo.CheckAcl(username1, readWriteAcl, clientID, MOSQ_ACL_READ)
|
||||
tt2, err2 := mongo.CheckAcl(username1, readWriteAcl, clientID, MOSQ_ACL_WRITE)
|
||||
So(err1, ShouldBeNil)
|
||||
So(err2, ShouldBeNil)
|
||||
So(tt1, ShouldBeTrue)
|
||||
So(tt2, ShouldBeTrue)
|
||||
})
|
||||
Convey("Given a bad username, acl check should not return error", func() {
|
||||
testTopic1 := `test/topic/1`
|
||||
tt1, err1 := mongo.CheckAcl(wrongUsername, testTopic1, clientID, MOSQ_ACL_READ)
|
||||
So(err1, ShouldBeNil)
|
||||
So(tt1, ShouldBeFalse)
|
||||
})
|
||||
|
||||
mongoDb.Drop(context.TODO())
|
||||
mongo.Halt()
|
||||
|
@ -242,19 +277,23 @@ func TestMongoUtf8(t *testing.T) {
|
|||
So(err, ShouldBeNil)
|
||||
|
||||
Convey("Given username2 and a correct password, it should correctly authenticate it", func() {
|
||||
authenticated := mongo.GetUser(username2, userPass2, "")
|
||||
authenticated, err := mongo.GetUser(username2, userPass2, "")
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeTrue)
|
||||
})
|
||||
Convey("Given username2 and an incorrect password, it should not authenticate it", func() {
|
||||
authenticated := mongo.GetUser(username2, "wrong_password", "")
|
||||
authenticated, err := mongo.GetUser(username2, "wrong_password", "")
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
})
|
||||
Convey("Given username2 that is superuser, super user check should pass", func() {
|
||||
superuser := mongo.GetSuperuser(username2)
|
||||
superuser, err := mongo.GetSuperuser(username2)
|
||||
So(err, ShouldBeNil)
|
||||
So(superuser, ShouldBeTrue)
|
||||
})
|
||||
Convey("Given correct username1 password, but using wrong salt format, user should not authenticate", func() {
|
||||
authenticated := mongo.GetUser(username1, userPass1, "")
|
||||
authenticated, err := mongo.GetUser(username1, userPass1, "")
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
})
|
||||
|
||||
|
|
|
@ -215,63 +215,73 @@ func NewMysql(authOpts map[string]string, logLevel log.Level, hasher hashing.Has
|
|||
}
|
||||
|
||||
//GetUser checks that the username exists and the given password hashes to the same password.
|
||||
func (o Mysql) GetUser(username, password, clientid string) bool {
|
||||
func (o Mysql) GetUser(username, password, clientid string) (bool, error) {
|
||||
|
||||
var pwHash sql.NullString
|
||||
err := o.DB.Get(&pwHash, o.UserQuery, username)
|
||||
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
// avoid leaking the fact that user exists or not though error.
|
||||
return false, nil
|
||||
}
|
||||
|
||||
log.Debugf("MySql get user error: %s", err)
|
||||
return false
|
||||
return false, err
|
||||
}
|
||||
|
||||
if !pwHash.Valid {
|
||||
log.Debugf("MySql get user error: user %s not found", username)
|
||||
return false
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if o.hasher.Compare(password, pwHash.String) {
|
||||
return true
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return false
|
||||
return false, nil
|
||||
|
||||
}
|
||||
|
||||
//GetSuperuser checks that the username meets the superuser query.
|
||||
func (o Mysql) GetSuperuser(username string) bool {
|
||||
func (o Mysql) GetSuperuser(username string) (bool, error) {
|
||||
|
||||
//If there's no superuser query, return false.
|
||||
if o.SuperuserQuery == "" {
|
||||
return false
|
||||
return false, nil
|
||||
}
|
||||
|
||||
var count sql.NullInt64
|
||||
err := o.DB.Get(&count, o.SuperuserQuery, username)
|
||||
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
// avoid leaking the fact that user exists or not though error.
|
||||
return false, nil
|
||||
}
|
||||
|
||||
log.Debugf("MySql get superuser error: %s", err)
|
||||
return false
|
||||
return false, err
|
||||
}
|
||||
|
||||
if !count.Valid {
|
||||
log.Debugf("MySql get superuser error: user %s not found", username)
|
||||
return false
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if count.Int64 > 0 {
|
||||
return true
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return false
|
||||
return false, nil
|
||||
|
||||
}
|
||||
|
||||
//CheckAcl gets all acls for the username and tries to match against topic, acc, and username/clientid if needed.
|
||||
func (o Mysql) CheckAcl(username, topic, clientid string, acc int32) bool {
|
||||
func (o Mysql) CheckAcl(username, topic, clientid string, acc int32) (bool, error) {
|
||||
//If there's no acl query, assume all privileges for all users.
|
||||
if o.AclQuery == "" {
|
||||
return true
|
||||
return true, nil
|
||||
}
|
||||
|
||||
var acls []string
|
||||
|
@ -280,18 +290,18 @@ func (o Mysql) CheckAcl(username, topic, clientid string, acc int32) bool {
|
|||
|
||||
if err != nil {
|
||||
log.Debugf("MySql check acl error: %s", err)
|
||||
return false
|
||||
return false, err
|
||||
}
|
||||
|
||||
for _, acl := range acls {
|
||||
aclTopic := strings.Replace(acl, "%c", clientid, -1)
|
||||
aclTopic = strings.Replace(aclTopic, "%u", username, -1)
|
||||
if TopicsMatch(aclTopic, topic) {
|
||||
return true
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
return false, nil
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@ func TestMysql(t *testing.T) {
|
|||
userPass := "testpw"
|
||||
//Hash generated by the pw utility
|
||||
userPassHash := "PBKDF2$sha512$100000$os24lcPr9cJt2QDVWssblQ==$BK1BQ2wbwU1zNxv3Ml3wLuu5//hPop3/LvaPYjjCwdBvnpwusnukJPpcXQzyyjOlZdieXTx6sXAcX4WnZRZZnw=="
|
||||
wrongUsername := "not_present"
|
||||
|
||||
insertQuery := "INSERT INTO test_user(username, password_hash, is_admin) values(?, ?, ?)"
|
||||
|
||||
|
@ -58,23 +59,40 @@ func TestMysql(t *testing.T) {
|
|||
|
||||
Convey("Given a username and a correct password, it should correctly authenticate it", func() {
|
||||
|
||||
authenticated := mysql.GetUser(username, userPass, "")
|
||||
authenticated, err := mysql.GetUser(username, userPass, "")
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeTrue)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given a username and an incorrect password, it should not authenticate it", func() {
|
||||
|
||||
authenticated := mysql.GetUser(username, "wrong_password", "")
|
||||
authenticated, err := mysql.GetUser(username, "wrong_password", "")
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given a wrong username, it should not authenticate it and not return error", func() {
|
||||
|
||||
authenticated, err := mysql.GetUser(wrongUsername, "whatever_password", "")
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given a username that is admin, super user should pass", func() {
|
||||
superuser := mysql.GetSuperuser(username)
|
||||
superuser, err := mysql.GetSuperuser(username)
|
||||
So(err, ShouldBeNil)
|
||||
So(superuser, ShouldBeTrue)
|
||||
})
|
||||
|
||||
Convey("Given a wrong username, super user should not return error", func() {
|
||||
superuser, err := mysql.GetSuperuser(wrongUsername)
|
||||
So(err, ShouldBeNil)
|
||||
So(superuser, ShouldBeFalse)
|
||||
})
|
||||
|
||||
//Now create some acls and test topics
|
||||
|
||||
strictAcl := "test/topic/1"
|
||||
|
@ -100,9 +118,11 @@ func TestMysql(t *testing.T) {
|
|||
testTopic1 := `test/topic/1`
|
||||
testTopic2 := `test/topic/2`
|
||||
|
||||
tt1 := mysql.CheckAcl(username, testTopic1, clientID, MOSQ_ACL_READ)
|
||||
tt2 := mysql.CheckAcl(username, testTopic2, clientID, MOSQ_ACL_READ)
|
||||
tt1, err1 := mysql.CheckAcl(username, testTopic1, clientID, MOSQ_ACL_READ)
|
||||
tt2, err2 := mysql.CheckAcl(username, testTopic2, clientID, MOSQ_ACL_READ)
|
||||
|
||||
So(err1, ShouldBeNil)
|
||||
So(err2, ShouldBeNil)
|
||||
So(tt1, ShouldBeTrue)
|
||||
So(tt2, ShouldBeFalse)
|
||||
|
||||
|
@ -111,16 +131,19 @@ func TestMysql(t *testing.T) {
|
|||
Convey("Given read only privileges, a pub check should fail", func() {
|
||||
|
||||
testTopic1 := "test/topic/1"
|
||||
tt1 := mysql.CheckAcl(username, testTopic1, clientID, MOSQ_ACL_WRITE)
|
||||
tt1, err1 := mysql.CheckAcl(username, testTopic1, clientID, MOSQ_ACL_WRITE)
|
||||
So(err1, ShouldBeNil)
|
||||
So(tt1, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given wildcard subscriptions against strict db acl, acl checks should fail", func() {
|
||||
|
||||
tt1 := mysql.CheckAcl(username, singleLevelAcl, clientID, MOSQ_ACL_READ)
|
||||
tt2 := mysql.CheckAcl(username, hierarchyAcl, clientID, MOSQ_ACL_READ)
|
||||
tt1, err1 := mysql.CheckAcl(username, singleLevelAcl, clientID, MOSQ_ACL_READ)
|
||||
tt2, err2 := mysql.CheckAcl(username, hierarchyAcl, clientID, MOSQ_ACL_READ)
|
||||
|
||||
So(err1, ShouldBeNil)
|
||||
So(err2, ShouldBeNil)
|
||||
So(tt1, ShouldBeFalse)
|
||||
So(tt2, ShouldBeFalse)
|
||||
|
||||
|
@ -132,7 +155,8 @@ func TestMysql(t *testing.T) {
|
|||
So(err, ShouldBeNil)
|
||||
|
||||
Convey("Given a topic that mentions username, acl check should pass", func() {
|
||||
tt1 := mysql.CheckAcl(username, "test/test", clientID, MOSQ_ACL_READ)
|
||||
tt1, err1 := mysql.CheckAcl(username, "test/test", clientID, MOSQ_ACL_READ)
|
||||
So(err1, ShouldBeNil)
|
||||
So(tt1, ShouldBeTrue)
|
||||
})
|
||||
|
||||
|
@ -140,7 +164,8 @@ func TestMysql(t *testing.T) {
|
|||
So(err, ShouldBeNil)
|
||||
|
||||
Convey("Given a topic that mentions clientid, acl check should pass", func() {
|
||||
tt1 := mysql.CheckAcl(username, "test/test_client", clientID, MOSQ_ACL_READ)
|
||||
tt1, err1 := mysql.CheckAcl(username, "test/test_client", clientID, MOSQ_ACL_READ)
|
||||
So(err1, ShouldBeNil)
|
||||
So(tt1, ShouldBeTrue)
|
||||
})
|
||||
|
||||
|
@ -150,7 +175,8 @@ func TestMysql(t *testing.T) {
|
|||
So(err, ShouldBeNil)
|
||||
|
||||
Convey("Given a topic not strictly present that matches a db single level wildcard, acl check should pass", func() {
|
||||
tt1 := mysql.CheckAcl(username, "test/topic/whatever", clientID, MOSQ_ACL_READ)
|
||||
tt1, err1 := mysql.CheckAcl(username, "test/topic/whatever", clientID, MOSQ_ACL_READ)
|
||||
So(err1, ShouldBeNil)
|
||||
So(tt1, ShouldBeTrue)
|
||||
})
|
||||
|
||||
|
@ -160,10 +186,18 @@ func TestMysql(t *testing.T) {
|
|||
So(err, ShouldBeNil)
|
||||
|
||||
Convey("Given a topic not strictly present that matches a hierarchy wildcard, acl check should pass", func() {
|
||||
tt1 := mysql.CheckAcl(username, "test/what/ever", clientID, MOSQ_ACL_READ)
|
||||
tt1, err1 := mysql.CheckAcl(username, "test/what/ever", clientID, MOSQ_ACL_READ)
|
||||
So(err1, ShouldBeNil)
|
||||
So(tt1, ShouldBeTrue)
|
||||
})
|
||||
|
||||
Convey("Given a bad username, acl check should not return error", func() {
|
||||
testTopic1 := `test/topic/1`
|
||||
tt1, err1 := mysql.CheckAcl(wrongUsername, testTopic1, clientID, MOSQ_ACL_READ)
|
||||
So(err1, ShouldBeNil)
|
||||
So(tt1, ShouldBeFalse)
|
||||
})
|
||||
|
||||
//Empty db
|
||||
mysql.DB.MustExec("delete from test_user where 1 = 1")
|
||||
mysql.DB.MustExec("delete from test_acl where 1 = 1")
|
||||
|
|
|
@ -160,64 +160,74 @@ func NewPostgres(authOpts map[string]string, logLevel log.Level, hasher hashing.
|
|||
}
|
||||
|
||||
//GetUser checks that the username exists and the given password hashes to the same password.
|
||||
func (o Postgres) GetUser(username, password, clientid string) bool {
|
||||
func (o Postgres) GetUser(username, password, clientid string) (bool, error) {
|
||||
|
||||
var pwHash sql.NullString
|
||||
err := o.DB.Get(&pwHash, o.UserQuery, username)
|
||||
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
// avoid leaking the fact that user exists or not though error.
|
||||
return false, nil
|
||||
}
|
||||
|
||||
log.Debugf("PG get user error: %s", err)
|
||||
return false
|
||||
return false, err
|
||||
}
|
||||
|
||||
if !pwHash.Valid {
|
||||
log.Debugf("PG get user error: user %s not found", username)
|
||||
return false
|
||||
return false, err
|
||||
}
|
||||
|
||||
if o.hasher.Compare(password, pwHash.String) {
|
||||
return true
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return false
|
||||
return false, nil
|
||||
|
||||
}
|
||||
|
||||
//GetSuperuser checks that the username meets the superuser query.
|
||||
func (o Postgres) GetSuperuser(username string) bool {
|
||||
func (o Postgres) GetSuperuser(username string) (bool, error) {
|
||||
|
||||
//If there's no superuser query, return false.
|
||||
if o.SuperuserQuery == "" {
|
||||
return false
|
||||
return false, nil
|
||||
}
|
||||
|
||||
var count sql.NullInt64
|
||||
err := o.DB.Get(&count, o.SuperuserQuery, username)
|
||||
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
// avoid leaking the fact that user exists or not though error.
|
||||
return false, nil
|
||||
}
|
||||
|
||||
log.Debugf("PG get superuser error: %s", err)
|
||||
return false
|
||||
return false, err
|
||||
}
|
||||
|
||||
if !count.Valid {
|
||||
log.Debugf("PG get superuser error: user %s not found", username)
|
||||
return false
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if count.Int64 > 0 {
|
||||
return true
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return false
|
||||
return false, nil
|
||||
|
||||
}
|
||||
|
||||
//CheckAcl gets all acls for the username and tries to match against topic, acc, and username/clientid if needed.
|
||||
func (o Postgres) CheckAcl(username, topic, clientid string, acc int32) bool {
|
||||
func (o Postgres) CheckAcl(username, topic, clientid string, acc int32) (bool, error) {
|
||||
|
||||
//If there's no acl query, assume all privileges for all users.
|
||||
if o.AclQuery == "" {
|
||||
return true
|
||||
return true, nil
|
||||
}
|
||||
|
||||
var acls []string
|
||||
|
@ -226,18 +236,18 @@ func (o Postgres) CheckAcl(username, topic, clientid string, acc int32) bool {
|
|||
|
||||
if err != nil {
|
||||
log.Debugf("PG check acl error: %s", err)
|
||||
return false
|
||||
return false, err
|
||||
}
|
||||
|
||||
for _, acl := range acls {
|
||||
aclTopic := strings.Replace(acl, "%c", clientid, -1)
|
||||
aclTopic = strings.Replace(aclTopic, "%u", username, -1)
|
||||
if TopicsMatch(aclTopic, topic) {
|
||||
return true
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
return false, nil
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@ func TestPostgres(t *testing.T) {
|
|||
userPass := "testpw"
|
||||
//Hash generated by the pw utility
|
||||
userPassHash := "PBKDF2$sha512$100000$os24lcPr9cJt2QDVWssblQ==$BK1BQ2wbwU1zNxv3Ml3wLuu5//hPop3/LvaPYjjCwdBvnpwusnukJPpcXQzyyjOlZdieXTx6sXAcX4WnZRZZnw=="
|
||||
wrongUsername := "not_present"
|
||||
|
||||
insertQuery := "INSERT INTO test_user(username, password_hash, is_admin) values($1, $2, $3) returning id"
|
||||
|
||||
|
@ -53,23 +54,40 @@ func TestPostgres(t *testing.T) {
|
|||
|
||||
Convey("Given a username and a correct password, it should correctly authenticate it", func() {
|
||||
|
||||
authenticated := postgres.GetUser(username, userPass, "")
|
||||
authenticated, err := postgres.GetUser(username, userPass, "")
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeTrue)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given a username and an incorrect password, it should not authenticate it", func() {
|
||||
|
||||
authenticated := postgres.GetUser(username, "wrong_password", "")
|
||||
authenticated, err := postgres.GetUser(username, "wrong_password", "")
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given a wrong username, it should not authenticate it and not return error", func() {
|
||||
|
||||
authenticated, err := postgres.GetUser(wrongUsername, "whatever_password", "")
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given a username that is admin, super user should pass", func() {
|
||||
superuser := postgres.GetSuperuser(username)
|
||||
superuser, err := postgres.GetSuperuser(username)
|
||||
So(err, ShouldBeNil)
|
||||
So(superuser, ShouldBeTrue)
|
||||
})
|
||||
|
||||
Convey("Given a wrong username, super user should not return error", func() {
|
||||
superuser, err := postgres.GetSuperuser(wrongUsername)
|
||||
So(err, ShouldBeNil)
|
||||
So(superuser, ShouldBeFalse)
|
||||
})
|
||||
|
||||
//Now create some acls and test topics
|
||||
|
||||
strictAcl := "test/topic/1"
|
||||
|
@ -91,9 +109,11 @@ func TestPostgres(t *testing.T) {
|
|||
testTopic1 := `test/topic/1`
|
||||
testTopic2 := `test/topic/2`
|
||||
|
||||
tt1 := postgres.CheckAcl(username, testTopic1, clientID, MOSQ_ACL_READ)
|
||||
tt2 := postgres.CheckAcl(username, testTopic2, clientID, MOSQ_ACL_READ)
|
||||
tt1, err1 := postgres.CheckAcl(username, testTopic1, clientID, MOSQ_ACL_READ)
|
||||
tt2, err2 := postgres.CheckAcl(username, testTopic2, clientID, MOSQ_ACL_READ)
|
||||
|
||||
So(err1, ShouldBeNil)
|
||||
So(err2, ShouldBeNil)
|
||||
So(tt1, ShouldBeTrue)
|
||||
So(tt2, ShouldBeFalse)
|
||||
|
||||
|
@ -102,16 +122,19 @@ func TestPostgres(t *testing.T) {
|
|||
Convey("Given read only privileges, a pub check should fail", func() {
|
||||
|
||||
testTopic1 := "test/topic/1"
|
||||
tt1 := postgres.CheckAcl(username, testTopic1, clientID, MOSQ_ACL_WRITE)
|
||||
tt1, err1 := postgres.CheckAcl(username, testTopic1, clientID, MOSQ_ACL_WRITE)
|
||||
So(err1, ShouldBeNil)
|
||||
So(tt1, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given wildcard subscriptions against strict db acl, acl checks should fail", func() {
|
||||
|
||||
tt1 := postgres.CheckAcl(username, singleLevelAcl, clientID, MOSQ_ACL_READ)
|
||||
tt2 := postgres.CheckAcl(username, hierarchyAcl, clientID, MOSQ_ACL_READ)
|
||||
tt1, err1 := postgres.CheckAcl(username, singleLevelAcl, clientID, MOSQ_ACL_READ)
|
||||
tt2, err2 := postgres.CheckAcl(username, hierarchyAcl, clientID, MOSQ_ACL_READ)
|
||||
|
||||
So(err1, ShouldBeNil)
|
||||
So(err2, ShouldBeNil)
|
||||
So(tt1, ShouldBeFalse)
|
||||
So(tt2, ShouldBeFalse)
|
||||
|
||||
|
@ -123,7 +146,8 @@ func TestPostgres(t *testing.T) {
|
|||
So(err, ShouldBeNil)
|
||||
|
||||
Convey("Given a topic that mentions username, acl check should pass", func() {
|
||||
tt1 := postgres.CheckAcl(username, "test/test", clientID, MOSQ_ACL_READ)
|
||||
tt1, err1 := postgres.CheckAcl(username, "test/test", clientID, MOSQ_ACL_READ)
|
||||
So(err1, ShouldBeNil)
|
||||
So(tt1, ShouldBeTrue)
|
||||
})
|
||||
|
||||
|
@ -131,7 +155,8 @@ func TestPostgres(t *testing.T) {
|
|||
So(err, ShouldBeNil)
|
||||
|
||||
Convey("Given a topic that mentions clientid, acl check should pass", func() {
|
||||
tt1 := postgres.CheckAcl(username, "test/test_client", clientID, MOSQ_ACL_READ)
|
||||
tt1, err1 := postgres.CheckAcl(username, "test/test_client", clientID, MOSQ_ACL_READ)
|
||||
So(err1, ShouldBeNil)
|
||||
So(tt1, ShouldBeTrue)
|
||||
})
|
||||
|
||||
|
@ -141,7 +166,8 @@ func TestPostgres(t *testing.T) {
|
|||
So(err, ShouldBeNil)
|
||||
|
||||
Convey("Given a topic not strictly present that matches a db single level wildcard, acl check should pass", func() {
|
||||
tt1 := postgres.CheckAcl(username, "test/topic/whatever", clientID, MOSQ_ACL_READ)
|
||||
tt1, err1 := postgres.CheckAcl(username, "test/topic/whatever", clientID, MOSQ_ACL_READ)
|
||||
So(err1, ShouldBeNil)
|
||||
So(tt1, ShouldBeTrue)
|
||||
})
|
||||
|
||||
|
@ -151,10 +177,18 @@ func TestPostgres(t *testing.T) {
|
|||
So(err, ShouldBeNil)
|
||||
|
||||
Convey("Given a topic not strictly present that matches a hierarchy wildcard, acl check should pass", func() {
|
||||
tt1 := postgres.CheckAcl(username, "test/what/ever", clientID, MOSQ_ACL_READ)
|
||||
tt1, err1 := postgres.CheckAcl(username, "test/what/ever", clientID, MOSQ_ACL_READ)
|
||||
So(err1, ShouldBeNil)
|
||||
So(tt1, ShouldBeTrue)
|
||||
})
|
||||
|
||||
Convey("Given a bad username, acl check should not return error", func() {
|
||||
testTopic1 := `test/topic/1`
|
||||
tt1, err1 := postgres.CheckAcl(wrongUsername, testTopic1, clientID, MOSQ_ACL_READ)
|
||||
So(err1, ShouldBeNil)
|
||||
So(tt1, ShouldBeFalse)
|
||||
})
|
||||
|
||||
//Empty db
|
||||
postgres.DB.MustExec("delete from test_user where 1 = 1")
|
||||
postgres.DB.MustExec("delete from test_acl where 1 = 1")
|
||||
|
|
|
@ -137,10 +137,10 @@ func isMovedError(err error) bool {
|
|||
}
|
||||
|
||||
//GetUser checks that the username exists and the given password hashes to the same password.
|
||||
func (o Redis) GetUser(username, password, _ string) bool {
|
||||
func (o Redis) GetUser(username, password, _ string) (bool, error) {
|
||||
ok, err := o.getUser(username, password)
|
||||
if err == nil {
|
||||
return ok
|
||||
return ok, nil
|
||||
}
|
||||
|
||||
//If using Redis Cluster, reload state and attempt once more.
|
||||
|
@ -148,7 +148,7 @@ func (o Redis) GetUser(username, password, _ string) bool {
|
|||
err = o.conn.ReloadState(o.ctx)
|
||||
if err != nil {
|
||||
log.Debugf("redis reload state error: %s", err)
|
||||
return false
|
||||
return false, err
|
||||
}
|
||||
|
||||
//Retry once.
|
||||
|
@ -158,7 +158,7 @@ func (o Redis) GetUser(username, password, _ string) bool {
|
|||
if err != nil {
|
||||
log.Debugf("redis get user error: %s", err)
|
||||
}
|
||||
return ok
|
||||
return ok, err
|
||||
}
|
||||
|
||||
func (o Redis) getUser(username, password string) (bool, error) {
|
||||
|
@ -175,14 +175,14 @@ func (o Redis) getUser(username, password string) (bool, error) {
|
|||
}
|
||||
|
||||
//GetSuperuser checks that the key username:su exists and has value "true".
|
||||
func (o Redis) GetSuperuser(username string) bool {
|
||||
func (o Redis) GetSuperuser(username string) (bool, error) {
|
||||
if o.disableSuperuser {
|
||||
return false
|
||||
return false, nil
|
||||
}
|
||||
|
||||
ok, err := o.getSuperuser(username)
|
||||
if err == nil {
|
||||
return ok
|
||||
return ok, nil
|
||||
}
|
||||
|
||||
//If using Redis Cluster, reload state and attempt once more.
|
||||
|
@ -190,7 +190,7 @@ func (o Redis) GetSuperuser(username string) bool {
|
|||
err = o.conn.ReloadState(o.ctx)
|
||||
if err != nil {
|
||||
log.Debugf("redis reload state error: %s", err)
|
||||
return false
|
||||
return false, err
|
||||
}
|
||||
|
||||
//Retry once.
|
||||
|
@ -200,7 +200,7 @@ func (o Redis) GetSuperuser(username string) bool {
|
|||
if err != nil {
|
||||
log.Debugf("redis get superuser error: %s", err)
|
||||
}
|
||||
return ok
|
||||
return ok, err
|
||||
}
|
||||
|
||||
func (o Redis) getSuperuser(username string) (bool, error) {
|
||||
|
@ -216,10 +216,10 @@ func (o Redis) getSuperuser(username string) (bool, error) {
|
|||
return false, nil
|
||||
}
|
||||
|
||||
func (o Redis) CheckAcl(username, topic, clientid string, acc int32) bool {
|
||||
func (o Redis) CheckAcl(username, topic, clientid string, acc int32) (bool, error) {
|
||||
ok, err := o.checkAcl(username, topic, clientid, acc)
|
||||
if err == nil {
|
||||
return ok
|
||||
return ok, nil
|
||||
}
|
||||
|
||||
//If using Redis Cluster, reload state and attempt once more.
|
||||
|
@ -227,7 +227,7 @@ func (o Redis) CheckAcl(username, topic, clientid string, acc int32) bool {
|
|||
err = o.conn.ReloadState(o.ctx)
|
||||
if err != nil {
|
||||
log.Debugf("redis reload state error: %s", err)
|
||||
return false
|
||||
return false, err
|
||||
}
|
||||
|
||||
//Retry once.
|
||||
|
@ -237,7 +237,7 @@ func (o Redis) CheckAcl(username, topic, clientid string, acc int32) bool {
|
|||
if err != nil {
|
||||
log.Debugf("redis check acl error: %s", err)
|
||||
}
|
||||
return ok
|
||||
return ok, err
|
||||
}
|
||||
|
||||
//CheckAcl gets all acls for the username and tries to match against topic, acc, and username/clientid if needed.
|
||||
|
|
|
@ -49,18 +49,22 @@ func testRedis(ctx context.Context, t *testing.T, authOpts map[string]string) {
|
|||
userPassHash := "PBKDF2$sha512$100000$os24lcPr9cJt2QDVWssblQ==$BK1BQ2wbwU1zNxv3Ml3wLuu5//hPop3/LvaPYjjCwdBvnpwusnukJPpcXQzyyjOlZdieXTx6sXAcX4WnZRZZnw=="
|
||||
redis.conn.Set(ctx, username, userPassHash, 0)
|
||||
|
||||
authenticated := redis.GetUser(username, userPass, "")
|
||||
authenticated, err := redis.GetUser(username, userPass, "")
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, authenticated)
|
||||
|
||||
authenticated = redis.GetUser(username, "wrong_password", "")
|
||||
authenticated, err = redis.GetUser(username, "wrong_password", "")
|
||||
assert.Nil(t, err)
|
||||
assert.False(t, authenticated)
|
||||
|
||||
redis.conn.Set(ctx, username+":su", "true", 0)
|
||||
superuser := redis.GetSuperuser(username)
|
||||
superuser, err := redis.GetSuperuser(username)
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, superuser)
|
||||
|
||||
redis.disableSuperuser = true
|
||||
superuser = redis.GetSuperuser(username)
|
||||
superuser, err = redis.GetSuperuser(username)
|
||||
assert.Nil(t, err)
|
||||
assert.False(t, superuser)
|
||||
|
||||
redis.disableSuperuser = false
|
||||
|
@ -82,79 +86,99 @@ func testRedis(ctx context.Context, t *testing.T, authOpts map[string]string) {
|
|||
testTopic1 := `test/topic/1`
|
||||
testTopic2 := `test/topic/2`
|
||||
|
||||
tt1 := redis.CheckAcl(username, testTopic1, clientID, MOSQ_ACL_READ)
|
||||
tt2 := redis.CheckAcl(username, testTopic2, clientID, MOSQ_ACL_READ)
|
||||
tt1, err1 := redis.CheckAcl(username, testTopic1, clientID, MOSQ_ACL_READ)
|
||||
tt2, err2 := redis.CheckAcl(username, testTopic2, clientID, MOSQ_ACL_READ)
|
||||
|
||||
assert.Nil(t, err1)
|
||||
assert.Nil(t, err2)
|
||||
assert.True(t, tt1)
|
||||
assert.False(t, tt2)
|
||||
|
||||
tt1 = redis.CheckAcl(username, singleLevelAcl, clientID, MOSQ_ACL_READ)
|
||||
tt2 = redis.CheckAcl(username, hierarchyAcl, clientID, MOSQ_ACL_READ)
|
||||
tt1, err1 = redis.CheckAcl(username, singleLevelAcl, clientID, MOSQ_ACL_READ)
|
||||
tt2, err2 = redis.CheckAcl(username, hierarchyAcl, clientID, MOSQ_ACL_READ)
|
||||
|
||||
assert.Nil(t, err1)
|
||||
assert.Nil(t, err2)
|
||||
assert.False(t, tt1)
|
||||
assert.False(t, tt2)
|
||||
|
||||
//Now check against common patterns.
|
||||
redis.conn.SAdd(ctx, "common:racls", userPattern)
|
||||
tt1 = redis.CheckAcl(username, "test/test", clientID, MOSQ_ACL_READ)
|
||||
tt1, err1 = redis.CheckAcl(username, "test/test", clientID, MOSQ_ACL_READ)
|
||||
assert.Nil(t, err1)
|
||||
assert.True(t, tt1)
|
||||
|
||||
redis.conn.SAdd(ctx, "common:racls", clientPattern)
|
||||
|
||||
tt1 = redis.CheckAcl(username, "test/test_client", clientID, MOSQ_ACL_READ)
|
||||
tt1, err1 = redis.CheckAcl(username, "test/test_client", clientID, MOSQ_ACL_READ)
|
||||
assert.Nil(t, err1)
|
||||
assert.True(t, tt1)
|
||||
|
||||
redis.conn.SAdd(ctx, username+":racls", singleLevelAcl)
|
||||
tt1 = redis.CheckAcl(username, "test/topic/whatever", clientID, MOSQ_ACL_READ)
|
||||
tt1, err1 = redis.CheckAcl(username, "test/topic/whatever", clientID, MOSQ_ACL_READ)
|
||||
assert.Nil(t, err1)
|
||||
assert.True(t, tt1)
|
||||
|
||||
redis.conn.SAdd(ctx, username+":racls", hierarchyAcl)
|
||||
|
||||
tt1 = redis.CheckAcl(username, "test/what/ever", clientID, MOSQ_ACL_READ)
|
||||
tt1, err1 = redis.CheckAcl(username, "test/what/ever", clientID, MOSQ_ACL_READ)
|
||||
assert.Nil(t, err1)
|
||||
assert.True(t, tt1)
|
||||
|
||||
tt1 = redis.CheckAcl(username, "test/test", clientID, MOSQ_ACL_WRITE)
|
||||
tt1, err1 = redis.CheckAcl(username, "test/test", clientID, MOSQ_ACL_WRITE)
|
||||
assert.Nil(t, err1)
|
||||
assert.False(t, tt1)
|
||||
|
||||
//Add a write only acl and check for subscription.
|
||||
redis.conn.SAdd(ctx, username+":wacls", writeAcl)
|
||||
tt1 = redis.CheckAcl(username, writeAcl, clientID, MOSQ_ACL_READ)
|
||||
tt2 = redis.CheckAcl(username, writeAcl, clientID, MOSQ_ACL_WRITE)
|
||||
tt1, err1 = redis.CheckAcl(username, writeAcl, clientID, MOSQ_ACL_READ)
|
||||
tt2, err2 = redis.CheckAcl(username, writeAcl, clientID, MOSQ_ACL_WRITE)
|
||||
assert.Nil(t, err1)
|
||||
assert.Nil(t, err2)
|
||||
assert.False(t, tt1)
|
||||
assert.True(t, tt2)
|
||||
|
||||
//Add a readwrite acl and check for subscription.
|
||||
redis.conn.SAdd(ctx, username+":rwacls", readWriteAcl)
|
||||
tt1 = redis.CheckAcl(username, readWriteAcl, clientID, MOSQ_ACL_READ)
|
||||
tt2 = redis.CheckAcl(username, readWriteAcl, clientID, MOSQ_ACL_WRITE)
|
||||
tt1, err1 = redis.CheckAcl(username, readWriteAcl, clientID, MOSQ_ACL_READ)
|
||||
tt2, err2 = redis.CheckAcl(username, readWriteAcl, clientID, MOSQ_ACL_WRITE)
|
||||
assert.Nil(t, err1)
|
||||
assert.Nil(t, err2)
|
||||
assert.True(t, tt1)
|
||||
assert.True(t, tt2)
|
||||
|
||||
//Now add a common read acl to check against.
|
||||
redis.conn.SAdd(ctx, "common:racls", commonTopic)
|
||||
tt1 = redis.CheckAcl("unknown", commonTopic, clientID, MOSQ_ACL_READ)
|
||||
tt1, err1 = redis.CheckAcl("unknown", commonTopic, clientID, MOSQ_ACL_READ)
|
||||
assert.Nil(t, err1)
|
||||
assert.True(t, tt1)
|
||||
|
||||
// Assert that only read works for a given topic in racls.
|
||||
topic := "readable/topic"
|
||||
redis.conn.SAdd(ctx, username+":racls", topic)
|
||||
tt1 = redis.CheckAcl(username, topic, clientID, MOSQ_ACL_SUBSCRIBE)
|
||||
tt2 = redis.CheckAcl(username, topic, clientID, MOSQ_ACL_READ)
|
||||
tt1, err1 = redis.CheckAcl(username, topic, clientID, MOSQ_ACL_SUBSCRIBE)
|
||||
tt2, err2 = redis.CheckAcl(username, topic, clientID, MOSQ_ACL_READ)
|
||||
assert.Nil(t, err1)
|
||||
assert.Nil(t, err2)
|
||||
assert.False(t, tt1)
|
||||
assert.True(t, tt2)
|
||||
|
||||
// Assert that only subscribe works for a given topic in sacls.
|
||||
topic = "subscribable/topic"
|
||||
redis.conn.SAdd(ctx, username+":sacls", topic)
|
||||
tt1 = redis.CheckAcl(username, topic, clientID, MOSQ_ACL_SUBSCRIBE)
|
||||
tt2 = redis.CheckAcl(username, topic, clientID, MOSQ_ACL_READ)
|
||||
tt1, err1 = redis.CheckAcl(username, topic, clientID, MOSQ_ACL_SUBSCRIBE)
|
||||
tt2, err2 = redis.CheckAcl(username, topic, clientID, MOSQ_ACL_READ)
|
||||
assert.Nil(t, err1)
|
||||
assert.Nil(t, err2)
|
||||
assert.True(t, tt1)
|
||||
assert.False(t, tt2)
|
||||
|
||||
topic = "commonsubscribable/topic"
|
||||
redis.conn.SAdd(ctx, "common:sacls", topic)
|
||||
tt1 = redis.CheckAcl(username, topic, clientID, MOSQ_ACL_SUBSCRIBE)
|
||||
tt2 = redis.CheckAcl(username, topic, clientID, MOSQ_ACL_READ)
|
||||
tt1, err1 = redis.CheckAcl(username, topic, clientID, MOSQ_ACL_SUBSCRIBE)
|
||||
tt2, err2 = redis.CheckAcl(username, topic, clientID, MOSQ_ACL_READ)
|
||||
assert.Nil(t, err1)
|
||||
assert.Nil(t, err2)
|
||||
assert.True(t, tt1)
|
||||
assert.False(t, tt2)
|
||||
|
||||
|
|
|
@ -94,63 +94,73 @@ func NewSqlite(authOpts map[string]string, logLevel log.Level, hasher hashing.Ha
|
|||
}
|
||||
|
||||
//GetUser checks that the username exists and the given password hashes to the same password.
|
||||
func (o Sqlite) GetUser(username, password, clientid string) bool {
|
||||
func (o Sqlite) GetUser(username, password, clientid string) (bool, error) {
|
||||
|
||||
var pwHash sql.NullString
|
||||
err := o.DB.Get(&pwHash, o.UserQuery, username)
|
||||
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
// avoid leaking the fact that user exists or not though error.
|
||||
return false, nil
|
||||
}
|
||||
|
||||
log.Debugf("SQlite get user error: %s", err)
|
||||
return false
|
||||
return false, err
|
||||
}
|
||||
|
||||
if !pwHash.Valid {
|
||||
log.Debugf("SQlite get user error: user %s not found.", username)
|
||||
return false
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if o.hasher.Compare(password, pwHash.String) {
|
||||
return true
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return false
|
||||
return false, nil
|
||||
|
||||
}
|
||||
|
||||
//GetSuperuser checks that the username meets the superuser query.
|
||||
func (o Sqlite) GetSuperuser(username string) bool {
|
||||
func (o Sqlite) GetSuperuser(username string) (bool, error) {
|
||||
|
||||
//If there's no superuser query, return false.
|
||||
if o.SuperuserQuery == "" {
|
||||
return false
|
||||
return false, nil
|
||||
}
|
||||
|
||||
var count sql.NullInt64
|
||||
err := o.DB.Get(&count, o.SuperuserQuery, username)
|
||||
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
// avoid leaking the fact that user exists or not though error.
|
||||
return false, nil
|
||||
}
|
||||
|
||||
log.Debugf("sqlite get superuser error: %s", err)
|
||||
return false
|
||||
return false, err
|
||||
}
|
||||
|
||||
if !count.Valid {
|
||||
log.Debugf("sqlite get superuser error: user %s not found", username)
|
||||
return false
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if count.Int64 > 0 {
|
||||
return true
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return false
|
||||
return false, nil
|
||||
|
||||
}
|
||||
|
||||
//CheckAcl gets all acls for the username and tries to match against topic, acc, and username/clientid if needed.
|
||||
func (o Sqlite) CheckAcl(username, topic, clientid string, acc int32) bool {
|
||||
func (o Sqlite) CheckAcl(username, topic, clientid string, acc int32) (bool, error) {
|
||||
//If there's no acl query, assume all privileges for all users.
|
||||
if o.AclQuery == "" {
|
||||
return true
|
||||
return true, nil
|
||||
}
|
||||
|
||||
var acls []string
|
||||
|
@ -159,18 +169,18 @@ func (o Sqlite) CheckAcl(username, topic, clientid string, acc int32) bool {
|
|||
|
||||
if err != nil {
|
||||
log.Debugf("sqlite check acl error: %s", err)
|
||||
return false
|
||||
return false, err
|
||||
}
|
||||
|
||||
for _, acl := range acls {
|
||||
aclTopic := strings.Replace(acl, "%c", clientid, -1)
|
||||
aclTopic = strings.Replace(aclTopic, "%u", username, -1)
|
||||
if TopicsMatch(aclTopic, topic) {
|
||||
return true
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
return false, nil
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -73,6 +73,8 @@ func TestFileSqlite(t *testing.T) {
|
|||
//Hash generated by the pw utility
|
||||
userPassHash := "PBKDF2$sha512$100000$os24lcPr9cJt2QDVWssblQ==$BK1BQ2wbwU1zNxv3Ml3wLuu5//hPop3/LvaPYjjCwdBvnpwusnukJPpcXQzyyjOlZdieXTx6sXAcX4WnZRZZnw=="
|
||||
|
||||
wrongUsername := "not_present"
|
||||
|
||||
insertQuery := "INSERT INTO test_user(username, password_hash, is_admin) values(?, ?, ?)"
|
||||
|
||||
userID := int64(0)
|
||||
|
@ -87,22 +89,38 @@ func TestFileSqlite(t *testing.T) {
|
|||
|
||||
Convey("Given a username and a correct password, it should correctly authenticate it", func() {
|
||||
|
||||
authenticated := sqlite.GetUser(username, userPass, "")
|
||||
authenticated, err := sqlite.GetUser(username, userPass, "")
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeTrue)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given a username and an incorrect password, it should not authenticate it", func() {
|
||||
|
||||
authenticated := sqlite.GetUser(username, "wrong_password", "")
|
||||
authenticated, err := sqlite.GetUser(username, "wrong_password", "")
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given wrongusername, it should not authenticate it and don't return error", func() {
|
||||
|
||||
authenticated, err := sqlite.GetUser(wrongUsername, "whatever_password", "")
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given a username that is admin, super user should pass", func() {
|
||||
superuser := sqlite.GetSuperuser(username)
|
||||
superuser, err := sqlite.GetSuperuser(username)
|
||||
So(err, ShouldBeNil)
|
||||
So(superuser, ShouldBeTrue)
|
||||
})
|
||||
Convey("Given wrongusername, super check should no pass and don't return error", func() {
|
||||
authenticated, err := sqlite.GetSuperuser(wrongUsername)
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
})
|
||||
|
||||
//Now create some acls and test topics
|
||||
|
||||
|
@ -128,9 +146,11 @@ func TestFileSqlite(t *testing.T) {
|
|||
testTopic1 := `test/topic/1`
|
||||
testTopic2 := `test/topic/2`
|
||||
|
||||
tt1 := sqlite.CheckAcl(username, testTopic1, clientID, MOSQ_ACL_READ)
|
||||
tt2 := sqlite.CheckAcl(username, testTopic2, clientID, MOSQ_ACL_READ)
|
||||
tt1, err1 := sqlite.CheckAcl(username, testTopic1, clientID, MOSQ_ACL_READ)
|
||||
tt2, err2 := sqlite.CheckAcl(username, testTopic2, clientID, MOSQ_ACL_READ)
|
||||
|
||||
So(err1, ShouldBeNil)
|
||||
So(err2, ShouldBeNil)
|
||||
So(tt1, ShouldBeTrue)
|
||||
So(tt2, ShouldBeFalse)
|
||||
|
||||
|
@ -139,16 +159,19 @@ func TestFileSqlite(t *testing.T) {
|
|||
Convey("Given read only privileges, a pub check should fail", func() {
|
||||
|
||||
testTopic1 := "test/topic/1"
|
||||
tt1 := sqlite.CheckAcl(username, testTopic1, clientID, MOSQ_ACL_WRITE)
|
||||
tt1, err1 := sqlite.CheckAcl(username, testTopic1, clientID, MOSQ_ACL_WRITE)
|
||||
So(err1, ShouldBeNil)
|
||||
So(tt1, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given wildcard subscriptions against strict db acl, acl checks should fail", func() {
|
||||
|
||||
tt1 := sqlite.CheckAcl(username, singleLevelAcl, clientID, MOSQ_ACL_READ)
|
||||
tt2 := sqlite.CheckAcl(username, hierarchyAcl, clientID, MOSQ_ACL_READ)
|
||||
tt1, err1 := sqlite.CheckAcl(username, singleLevelAcl, clientID, MOSQ_ACL_READ)
|
||||
tt2, err2 := sqlite.CheckAcl(username, hierarchyAcl, clientID, MOSQ_ACL_READ)
|
||||
|
||||
So(err1, ShouldBeNil)
|
||||
So(err2, ShouldBeNil)
|
||||
So(tt1, ShouldBeFalse)
|
||||
So(tt2, ShouldBeFalse)
|
||||
|
||||
|
@ -160,7 +183,8 @@ func TestFileSqlite(t *testing.T) {
|
|||
So(err, ShouldBeNil)
|
||||
|
||||
Convey("Given a topic that mentions username, acl check should pass", func() {
|
||||
tt1 := sqlite.CheckAcl(username, "test/test", clientID, MOSQ_ACL_READ)
|
||||
tt1, err1 := sqlite.CheckAcl(username, "test/test", clientID, MOSQ_ACL_READ)
|
||||
So(err1, ShouldBeNil)
|
||||
So(tt1, ShouldBeTrue)
|
||||
})
|
||||
|
||||
|
@ -168,7 +192,8 @@ func TestFileSqlite(t *testing.T) {
|
|||
So(err, ShouldBeNil)
|
||||
|
||||
Convey("Given a topic that mentions clientid, acl check should pass", func() {
|
||||
tt1 := sqlite.CheckAcl(username, "test/test_client", clientID, MOSQ_ACL_READ)
|
||||
tt1, err1 := sqlite.CheckAcl(username, "test/test_client", clientID, MOSQ_ACL_READ)
|
||||
So(err1, ShouldBeNil)
|
||||
So(tt1, ShouldBeTrue)
|
||||
})
|
||||
|
||||
|
@ -178,7 +203,8 @@ func TestFileSqlite(t *testing.T) {
|
|||
So(err, ShouldBeNil)
|
||||
|
||||
Convey("Given a topic not strictly present that matches a db single level wildcard, acl check should pass", func() {
|
||||
tt1 := sqlite.CheckAcl(username, "test/topic/whatever", clientID, MOSQ_ACL_READ)
|
||||
tt1, err1 := sqlite.CheckAcl(username, "test/topic/whatever", clientID, MOSQ_ACL_READ)
|
||||
So(err1, ShouldBeNil)
|
||||
So(tt1, ShouldBeTrue)
|
||||
})
|
||||
|
||||
|
@ -188,10 +214,17 @@ func TestFileSqlite(t *testing.T) {
|
|||
So(err, ShouldBeNil)
|
||||
|
||||
Convey("Given a topic not strictly present that matches a hierarchy wildcard, acl check should pass", func() {
|
||||
tt1 := sqlite.CheckAcl(username, "test/what/ever", clientID, MOSQ_ACL_READ)
|
||||
tt1, err1 := sqlite.CheckAcl(username, "test/what/ever", clientID, MOSQ_ACL_READ)
|
||||
So(err1, ShouldBeNil)
|
||||
So(tt1, ShouldBeTrue)
|
||||
})
|
||||
|
||||
Convey("Given a bad username, acl check should not return error", func() {
|
||||
tt1, err1 := sqlite.CheckAcl(wrongUsername, "test/test", clientID, MOSQ_ACL_READ)
|
||||
So(err1, ShouldBeNil)
|
||||
So(tt1, ShouldBeFalse)
|
||||
})
|
||||
|
||||
//Empty db
|
||||
sqlite.DB.MustExec("delete from test_user where 1 = 1")
|
||||
sqlite.DB.MustExec("delete from test_acl where 1 = 1")
|
||||
|
@ -255,20 +288,23 @@ func TestMemorySqlite(t *testing.T) {
|
|||
|
||||
Convey("Given a username and a correct password, it should correctly authenticate it", func() {
|
||||
|
||||
authenticated := sqlite.GetUser(username, userPass, "")
|
||||
authenticated, err := sqlite.GetUser(username, userPass, "")
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeTrue)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given a username and an incorrect password, it should not authenticate it", func() {
|
||||
|
||||
authenticated := sqlite.GetUser(username, "wrong_password", "")
|
||||
authenticated, err := sqlite.GetUser(username, "wrong_password", "")
|
||||
So(err, ShouldBeNil)
|
||||
So(authenticated, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given a username that is admin, super user should pass", func() {
|
||||
superuser := sqlite.GetSuperuser(username)
|
||||
superuser, err := sqlite.GetSuperuser(username)
|
||||
So(err, ShouldBeNil)
|
||||
So(superuser, ShouldBeTrue)
|
||||
})
|
||||
|
||||
|
@ -297,9 +333,11 @@ func TestMemorySqlite(t *testing.T) {
|
|||
testTopic1 := `test/topic/1`
|
||||
testTopic2 := `test/topic/2`
|
||||
|
||||
tt1 := sqlite.CheckAcl(username, testTopic1, clientID, MOSQ_ACL_READ)
|
||||
tt2 := sqlite.CheckAcl(username, testTopic2, clientID, MOSQ_ACL_READ)
|
||||
tt1, err1 := sqlite.CheckAcl(username, testTopic1, clientID, MOSQ_ACL_READ)
|
||||
tt2, err2 := sqlite.CheckAcl(username, testTopic2, clientID, MOSQ_ACL_READ)
|
||||
|
||||
So(err1, ShouldBeNil)
|
||||
So(err2, ShouldBeNil)
|
||||
So(tt1, ShouldBeTrue)
|
||||
So(tt2, ShouldBeFalse)
|
||||
|
||||
|
@ -308,16 +346,19 @@ func TestMemorySqlite(t *testing.T) {
|
|||
Convey("Given read only privileges, a pub check should fail", func() {
|
||||
|
||||
testTopic1 := "test/topic/1"
|
||||
tt1 := sqlite.CheckAcl(username, testTopic1, clientID, MOSQ_ACL_WRITE)
|
||||
tt1, err1 := sqlite.CheckAcl(username, testTopic1, clientID, MOSQ_ACL_WRITE)
|
||||
So(err1, ShouldBeNil)
|
||||
So(tt1, ShouldBeFalse)
|
||||
|
||||
})
|
||||
|
||||
Convey("Given wildcard subscriptions against strict db acl, acl checks should fail", func() {
|
||||
|
||||
tt1 := sqlite.CheckAcl(username, singleLevelAcl, clientID, MOSQ_ACL_READ)
|
||||
tt2 := sqlite.CheckAcl(username, hierarchyAcl, clientID, MOSQ_ACL_READ)
|
||||
tt1, err1 := sqlite.CheckAcl(username, singleLevelAcl, clientID, MOSQ_ACL_READ)
|
||||
tt2, err2 := sqlite.CheckAcl(username, hierarchyAcl, clientID, MOSQ_ACL_READ)
|
||||
|
||||
So(err1, ShouldBeNil)
|
||||
So(err2, ShouldBeNil)
|
||||
So(tt1, ShouldBeFalse)
|
||||
So(tt2, ShouldBeFalse)
|
||||
|
||||
|
@ -329,7 +370,8 @@ func TestMemorySqlite(t *testing.T) {
|
|||
So(err, ShouldBeNil)
|
||||
|
||||
Convey("Given a topic that mentions username, acl check should pass", func() {
|
||||
tt1 := sqlite.CheckAcl(username, "test/test", clientID, MOSQ_ACL_READ)
|
||||
tt1, err1 := sqlite.CheckAcl(username, "test/test", clientID, MOSQ_ACL_READ)
|
||||
So(err1, ShouldBeNil)
|
||||
So(tt1, ShouldBeTrue)
|
||||
})
|
||||
|
||||
|
@ -337,7 +379,8 @@ func TestMemorySqlite(t *testing.T) {
|
|||
So(err, ShouldBeNil)
|
||||
|
||||
Convey("Given a topic that mentions clientid, acl check should pass", func() {
|
||||
tt1 := sqlite.CheckAcl(username, "test/test_client", clientID, MOSQ_ACL_READ)
|
||||
tt1, err1 := sqlite.CheckAcl(username, "test/test_client", clientID, MOSQ_ACL_READ)
|
||||
So(err1, ShouldBeNil)
|
||||
So(tt1, ShouldBeTrue)
|
||||
})
|
||||
|
||||
|
@ -347,7 +390,8 @@ func TestMemorySqlite(t *testing.T) {
|
|||
So(err, ShouldBeNil)
|
||||
|
||||
Convey("Given a topic not strictly present that matches a db single level wildcard, acl check should pass", func() {
|
||||
tt1 := sqlite.CheckAcl(username, "test/topic/whatever", clientID, MOSQ_ACL_READ)
|
||||
tt1, err1 := sqlite.CheckAcl(username, "test/topic/whatever", clientID, MOSQ_ACL_READ)
|
||||
So(err1, ShouldBeNil)
|
||||
So(tt1, ShouldBeTrue)
|
||||
})
|
||||
|
||||
|
@ -357,7 +401,8 @@ func TestMemorySqlite(t *testing.T) {
|
|||
So(err, ShouldBeNil)
|
||||
|
||||
Convey("Given a topic not strictly present that matches a hierarchy wildcard, acl check should pass", func() {
|
||||
tt1 := sqlite.CheckAcl(username, "test/what/ever", clientID, MOSQ_ACL_READ)
|
||||
tt1, err1 := sqlite.CheckAcl(username, "test/what/ever", clientID, MOSQ_ACL_READ)
|
||||
So(err1, ShouldBeNil)
|
||||
So(tt1, ShouldBeTrue)
|
||||
})
|
||||
|
||||
|
|
213
go-auth.go
213
go-auth.go
|
@ -17,9 +17,9 @@ import (
|
|||
)
|
||||
|
||||
type Backend interface {
|
||||
GetUser(username, password, clientid string) bool
|
||||
GetSuperuser(username string) bool
|
||||
CheckAcl(username, topic, clientId string, acc int32) bool
|
||||
GetUser(username, password, clientid string) (bool, error)
|
||||
GetSuperuser(username string) (bool, error)
|
||||
CheckAcl(username, topic, clientId string, acc int32) (bool, error)
|
||||
GetName() string
|
||||
Halt()
|
||||
}
|
||||
|
@ -29,9 +29,9 @@ type AuthPlugin struct {
|
|||
customPlugin *plugin.Plugin
|
||||
PInit func(map[string]string, log.Level) error
|
||||
customPluginGetName func() string
|
||||
customPluginGetUser func(username, password, clientid string) bool
|
||||
customPluginGetSuperuser func(username string) bool
|
||||
customPluginCheckAcl func(username, topic, clientid string, acc int) bool
|
||||
customPluginGetUser func(username, password, clientid string) (bool, error)
|
||||
customPluginGetSuperuser func(username string) (bool, error)
|
||||
customPluginCheckAcl func(username, topic, clientid string, acc int) (bool, error)
|
||||
customPluginHalt func()
|
||||
useCache bool
|
||||
checkPrefix bool
|
||||
|
@ -58,6 +58,10 @@ const (
|
|||
pluginBackend = "plugin"
|
||||
grpcBackend = "grpc"
|
||||
jsBackend = "js"
|
||||
|
||||
AuthRejected = 0
|
||||
AuthGranted = 1
|
||||
AuthError = 2
|
||||
)
|
||||
|
||||
// Serves s a check for allowed backends and a map from backend to expected opts prefix.
|
||||
|
@ -215,7 +219,13 @@ func AuthPluginInit(keys []string, values []string, authOptsNum int) {
|
|||
continue
|
||||
}
|
||||
|
||||
getUserFunc := plGetUser.(func(username, password, clientid string) bool)
|
||||
getUserFunc, ok := plGetUser.(func(username, password, clientid string) (bool, error))
|
||||
if !ok {
|
||||
tmp := plGetUser.(func(username, password, clientid string) bool)
|
||||
getUserFunc = func(username, password, clientid string) (bool, error) {
|
||||
return tmp(username, password, clientid), nil
|
||||
}
|
||||
}
|
||||
authPlugin.customPluginGetUser = getUserFunc
|
||||
|
||||
plGetSuperuser, err := authPlugin.customPlugin.Lookup("GetSuperuser")
|
||||
|
@ -226,7 +236,13 @@ func AuthPluginInit(keys []string, values []string, authOptsNum int) {
|
|||
continue
|
||||
}
|
||||
|
||||
getSuperuserFunc := plGetSuperuser.(func(username string) bool)
|
||||
getSuperuserFunc, ok := plGetSuperuser.(func(username string) (bool, error))
|
||||
if !ok {
|
||||
tmp := plGetSuperuser.(func(username string) bool)
|
||||
getSuperuserFunc = func(username string) (bool, error) {
|
||||
return tmp(username), nil
|
||||
}
|
||||
}
|
||||
authPlugin.customPluginGetSuperuser = getSuperuserFunc
|
||||
|
||||
plCheckAcl, err := authPlugin.customPlugin.Lookup("CheckAcl")
|
||||
|
@ -237,7 +253,13 @@ func AuthPluginInit(keys []string, values []string, authOptsNum int) {
|
|||
continue
|
||||
}
|
||||
|
||||
checkAclFunc := plCheckAcl.(func(username, topic, clientid string, acc int) bool)
|
||||
checkAclFunc, ok := plCheckAcl.(func(username, topic, clientid string, acc int) (bool, error))
|
||||
if !ok {
|
||||
tmp := plCheckAcl.(func(username, topic, clientid string, acc int) bool)
|
||||
checkAclFunc = func(username, topic, clientid string, acc int) (bool, error) {
|
||||
return tmp(username, topic, clientid, acc), nil
|
||||
}
|
||||
}
|
||||
authPlugin.customPluginCheckAcl = checkAclFunc
|
||||
|
||||
plHalt, err := authPlugin.customPlugin.Lookup("Halt")
|
||||
|
@ -497,16 +519,31 @@ func setCache(authOpts map[string]string) {
|
|||
}
|
||||
|
||||
//export AuthUnpwdCheck
|
||||
func AuthUnpwdCheck(username, password, clientid string) bool {
|
||||
func AuthUnpwdCheck(username, password, clientid string) uint8 {
|
||||
ok, err := authUnpwdCheck(username, password, clientid)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return AuthError
|
||||
}
|
||||
|
||||
if ok {
|
||||
return AuthGranted
|
||||
}
|
||||
|
||||
return AuthRejected
|
||||
}
|
||||
|
||||
func authUnpwdCheck(username, password, clientid string) (bool, error) {
|
||||
var authenticated bool
|
||||
var cached bool
|
||||
var granted bool
|
||||
var err error
|
||||
if authPlugin.useCache {
|
||||
log.Debugf("checking auth cache for %s", username)
|
||||
cached, granted = authPlugin.cache.CheckAuthRecord(authPlugin.ctx, username, password)
|
||||
if cached {
|
||||
log.Debugf("found in cache: %s", username)
|
||||
return granted
|
||||
return granted, nil
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -515,7 +552,7 @@ func AuthUnpwdCheck(username, password, clientid string) bool {
|
|||
validPrefix, bename := CheckPrefix(username)
|
||||
if validPrefix {
|
||||
if bename == pluginBackend {
|
||||
authenticated = CheckPluginAuth(username, password, clientid)
|
||||
authenticated, err = CheckPluginAuth(username, password, clientid)
|
||||
} else {
|
||||
// If the backend is JWT and the token was prefixed, then strip the token. If the token was passed without a prefix it will be handled in the common case.
|
||||
if bename == jwtBackend {
|
||||
|
@ -524,52 +561,77 @@ func AuthUnpwdCheck(username, password, clientid string) bool {
|
|||
}
|
||||
var backend = authPlugin.backends[bename]
|
||||
|
||||
if backend.GetUser(username, password, clientid) {
|
||||
authenticated = true
|
||||
authenticated, err = backend.GetUser(username, password, clientid)
|
||||
if authenticated && err == nil {
|
||||
log.Debugf("user %s authenticated with backend %s", username, backend.GetName())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//If there's no valid prefix, check all backends.
|
||||
authenticated = CheckBackendsAuth(username, password, clientid)
|
||||
authenticated, err = CheckBackendsAuth(username, password, clientid)
|
||||
//If not authenticated, check for a present plugin
|
||||
if !authenticated {
|
||||
authenticated = CheckPluginAuth(username, password, clientid)
|
||||
if ok, checkAuthErr := CheckPluginAuth(username, password, clientid); ok && checkAuthErr == nil {
|
||||
authenticated = true
|
||||
err = nil
|
||||
} else if checkAuthErr != nil && err == nil {
|
||||
err = checkAuthErr
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
authenticated = CheckBackendsAuth(username, password, clientid)
|
||||
authenticated, err = CheckBackendsAuth(username, password, clientid)
|
||||
//If not authenticated, check for a present plugin
|
||||
if !authenticated {
|
||||
authenticated = CheckPluginAuth(username, password, clientid)
|
||||
if ok, checkAuthErr := CheckPluginAuth(username, password, clientid); ok && checkAuthErr == nil {
|
||||
authenticated = true
|
||||
err = nil
|
||||
} else if checkAuthErr != nil && err == nil {
|
||||
err = checkAuthErr
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if authPlugin.useCache {
|
||||
if authPlugin.useCache && err == nil {
|
||||
authGranted := "false"
|
||||
if authenticated {
|
||||
authGranted = "true"
|
||||
}
|
||||
log.Debugf("setting auth cache for %s", username)
|
||||
if err := authPlugin.cache.SetAuthRecord(authPlugin.ctx, username, password, authGranted); err != nil {
|
||||
log.Errorf("set auth cache: %s", err)
|
||||
return false
|
||||
if setAuthErr := authPlugin.cache.SetAuthRecord(authPlugin.ctx, username, password, authGranted); setAuthErr != nil {
|
||||
log.Errorf("set auth cache: %s", setAuthErr)
|
||||
return false, setAuthErr
|
||||
}
|
||||
}
|
||||
return authenticated
|
||||
return authenticated, err
|
||||
}
|
||||
|
||||
//export AuthAclCheck
|
||||
func AuthAclCheck(clientid, username, topic string, acc int) bool {
|
||||
func AuthAclCheck(clientid, username, topic string, acc int) uint8 {
|
||||
ok, err := authAclCheck(clientid, username, topic, acc)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return AuthError
|
||||
}
|
||||
|
||||
if ok {
|
||||
return AuthGranted
|
||||
}
|
||||
|
||||
return AuthRejected
|
||||
}
|
||||
|
||||
func authAclCheck(clientid, username, topic string, acc int) (bool, error) {
|
||||
var aclCheck bool
|
||||
var cached bool
|
||||
var granted bool
|
||||
var err error
|
||||
if authPlugin.useCache {
|
||||
log.Debugf("checking acl cache for %s", username)
|
||||
cached, granted = authPlugin.cache.CheckACLRecord(authPlugin.ctx, username, topic, clientid, acc)
|
||||
if cached {
|
||||
log.Debugf("found in cache: %s", username)
|
||||
return granted
|
||||
return granted, nil
|
||||
}
|
||||
}
|
||||
//If prefixes are enabled, check if username has a valid prefix and use the correct backend if so.
|
||||
|
@ -578,7 +640,7 @@ func AuthAclCheck(clientid, username, topic string, acc int) bool {
|
|||
validPrefix, bename := CheckPrefix(username)
|
||||
if validPrefix {
|
||||
if bename == pluginBackend {
|
||||
aclCheck = CheckPluginAcl(username, topic, clientid, acc)
|
||||
aclCheck, err = CheckPluginAcl(username, topic, clientid, acc)
|
||||
} else {
|
||||
// If the backend is JWT and the token was prefixed, then strip the token. If the token was passed without a prefix then it be handled in the common case.
|
||||
if bename == jwtBackend {
|
||||
|
@ -588,49 +650,62 @@ func AuthAclCheck(clientid, username, topic string, acc int) bool {
|
|||
var backend = authPlugin.backends[bename]
|
||||
log.Debugf("Superuser check with backend %s", backend.GetName())
|
||||
// Short circuit checks when superusers are disabled.
|
||||
if !authPlugin.disableSuperuser && backend.GetSuperuser(username) {
|
||||
log.Debugf("superuser %s acl authenticated with backend %s", username, backend.GetName())
|
||||
aclCheck = true
|
||||
if !authPlugin.disableSuperuser {
|
||||
aclCheck, err = backend.GetSuperuser(username)
|
||||
|
||||
if aclCheck && err == nil {
|
||||
log.Debugf("superuser %s acl authenticated with backend %s", username, backend.GetName())
|
||||
}
|
||||
}
|
||||
//If not superuser, check acl.
|
||||
if !aclCheck {
|
||||
log.Debugf("Acl check with backend %s", backend.GetName())
|
||||
if backend.CheckAcl(username, topic, clientid, int32(acc)) {
|
||||
log.Debugf("user %s acl authenticated with backend %s", username, backend.GetName())
|
||||
if ok, checkACLErr := backend.CheckAcl(username, topic, clientid, int32(acc)); ok && checkACLErr == nil {
|
||||
aclCheck = true
|
||||
log.Debugf("user %s acl authenticated with backend %s", username, backend.GetName())
|
||||
} else if checkACLErr != nil && err == nil {
|
||||
err = checkACLErr
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//If there's no valid prefix, check all backends.
|
||||
aclCheck = CheckBackendsAcl(username, topic, clientid, acc)
|
||||
aclCheck, err = CheckBackendsAcl(username, topic, clientid, acc)
|
||||
//If acl hasn't passed, check for plugin.
|
||||
if !aclCheck {
|
||||
aclCheck = CheckPluginAcl(username, topic, clientid, acc)
|
||||
if ok, checkACLErr := CheckPluginAcl(username, topic, clientid, acc); ok && checkACLErr == nil {
|
||||
aclCheck = true
|
||||
} else if checkACLErr != nil && err == nil {
|
||||
err = checkACLErr
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
aclCheck = CheckBackendsAcl(username, topic, clientid, acc)
|
||||
aclCheck, err = CheckBackendsAcl(username, topic, clientid, acc)
|
||||
//If acl hasn't passed, check for plugin.
|
||||
if !aclCheck {
|
||||
aclCheck = CheckPluginAcl(username, topic, clientid, acc)
|
||||
if ok, checkACLErr := CheckPluginAcl(username, topic, clientid, acc); ok && checkACLErr == nil {
|
||||
aclCheck = true
|
||||
} else if checkACLErr != nil && err == nil {
|
||||
err = checkACLErr
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if authPlugin.useCache {
|
||||
if authPlugin.useCache && err == nil {
|
||||
authGranted := "false"
|
||||
if aclCheck {
|
||||
authGranted = "true"
|
||||
}
|
||||
log.Debugf("setting acl cache (granted = %s) for %s", authGranted, username)
|
||||
if err := authPlugin.cache.SetACLRecord(authPlugin.ctx, username, topic, clientid, acc, authGranted); err != nil {
|
||||
log.Errorf("set acl cache: %s", err)
|
||||
return false
|
||||
if setACLErr := authPlugin.cache.SetACLRecord(authPlugin.ctx, username, topic, clientid, acc, authGranted); setACLErr != nil {
|
||||
log.Errorf("set acl cache: %s", setACLErr)
|
||||
return false, setACLErr
|
||||
}
|
||||
}
|
||||
|
||||
log.Debugf("Acl is %t for user %s", aclCheck, username)
|
||||
return aclCheck
|
||||
return aclCheck, err
|
||||
}
|
||||
|
||||
//export AuthPskKeyGet
|
||||
|
@ -661,8 +736,8 @@ func getPrefixForBackend(backend string) string {
|
|||
}
|
||||
|
||||
//CheckBackendsAuth checks for all backends if a username is authenticated and sets the authenticated param.
|
||||
func CheckBackendsAuth(username, password, clientid string) bool {
|
||||
|
||||
func CheckBackendsAuth(username, password, clientid string) (bool, error) {
|
||||
var err error
|
||||
authenticated := false
|
||||
|
||||
for _, bename := range backends {
|
||||
|
@ -675,20 +750,29 @@ func CheckBackendsAuth(username, password, clientid string) bool {
|
|||
|
||||
log.Debugf("checking user %s with backend %s", username, backend.GetName())
|
||||
|
||||
if backend.GetUser(username, password, clientid) {
|
||||
if ok, getUserErr := backend.GetUser(username, password, clientid); ok && getUserErr == nil {
|
||||
authenticated = true
|
||||
log.Debugf("user %s authenticated with backend %s", username, backend.GetName())
|
||||
break
|
||||
} else if getUserErr != nil && err == nil {
|
||||
err = getUserErr
|
||||
}
|
||||
}
|
||||
|
||||
return authenticated
|
||||
// If authenticated is true, it means at least one backend didn't failed and
|
||||
// accepted the user. In this case trust this backend and clear the error.
|
||||
if authenticated {
|
||||
err = nil
|
||||
}
|
||||
|
||||
return authenticated, err
|
||||
|
||||
}
|
||||
|
||||
//CheckBackendsAcl checks for all backends if a username is superuser or has acl rights and sets the aclCheck param.
|
||||
func CheckBackendsAcl(username, topic, clientid string, acc int) bool {
|
||||
func CheckBackendsAcl(username, topic, clientid string, acc int) (bool, error) {
|
||||
//Check superusers first
|
||||
var err error
|
||||
aclCheck := false
|
||||
if !authPlugin.disableSuperuser {
|
||||
for _, bename := range backends {
|
||||
|
@ -697,10 +781,12 @@ func CheckBackendsAcl(username, topic, clientid string, acc int) bool {
|
|||
}
|
||||
var backend = authPlugin.backends[bename]
|
||||
log.Debugf("Superuser check with backend %s", backend.GetName())
|
||||
if backend.GetSuperuser(username) {
|
||||
if ok, getSuperuserErr := backend.GetSuperuser(username); ok && getSuperuserErr == nil {
|
||||
log.Debugf("superuser %s acl authenticated with backend %s", username, backend.GetName())
|
||||
aclCheck = true
|
||||
break
|
||||
} else if getSuperuserErr != nil && err == nil {
|
||||
err = getSuperuserErr
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -712,36 +798,51 @@ func CheckBackendsAcl(username, topic, clientid string, acc int) bool {
|
|||
}
|
||||
var backend = authPlugin.backends[bename]
|
||||
log.Debugf("Acl check with backend %s", backend.GetName())
|
||||
if backend.CheckAcl(username, topic, clientid, int32(acc)) {
|
||||
if ok, checkACLErr := backend.CheckAcl(username, topic, clientid, int32(acc)); ok && checkACLErr == nil {
|
||||
log.Debugf("user %s acl authenticated with backend %s", username, backend.GetName())
|
||||
aclCheck = true
|
||||
break
|
||||
} else if checkACLErr != nil && err == nil {
|
||||
err = checkACLErr
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return aclCheck
|
||||
// If aclCheck is true, it means at least one backend didn't fail and
|
||||
// accepted the access. In this case trust this backend and clear the error.
|
||||
if aclCheck {
|
||||
err = nil
|
||||
}
|
||||
|
||||
return aclCheck, err
|
||||
}
|
||||
|
||||
//CheckPluginAuth checks that the plugin is not nil and returns the plugins auth response.
|
||||
func CheckPluginAuth(username, password, clientid string) bool {
|
||||
func CheckPluginAuth(username, password, clientid string) (bool, error) {
|
||||
if authPlugin.customPlugin == nil {
|
||||
return false
|
||||
return false, nil
|
||||
}
|
||||
return authPlugin.customPluginGetUser(username, password, clientid)
|
||||
}
|
||||
|
||||
//CheckPluginAcl checks that the plugin is not nil and returns the superuser/acl response.
|
||||
func CheckPluginAcl(username, topic, clientid string, acc int) bool {
|
||||
func CheckPluginAcl(username, topic, clientid string, acc int) (bool, error) {
|
||||
var aclCheck bool
|
||||
var err error
|
||||
if authPlugin.customPlugin == nil {
|
||||
return false
|
||||
return false, nil
|
||||
}
|
||||
//If superuser, authorize it unless superusers are disabled.
|
||||
if !authPlugin.disableSuperuser && authPlugin.customPluginGetSuperuser(username) {
|
||||
return true
|
||||
if !authPlugin.disableSuperuser {
|
||||
aclCheck, err = authPlugin.customPluginGetSuperuser(username)
|
||||
}
|
||||
//Check against the plugin's check acl function.
|
||||
return authPlugin.customPluginCheckAcl(username, topic, clientid, acc)
|
||||
|
||||
if !aclCheck && err == nil {
|
||||
//Check against the plugin's check acl function.
|
||||
aclCheck, err = authPlugin.customPluginCheckAcl(username, topic, clientid, acc)
|
||||
}
|
||||
|
||||
return aclCheck, err
|
||||
}
|
||||
|
||||
//export AuthPluginCleanup
|
||||
|
|
Loading…
Reference in New Issue