diff --git a/.github/workflows/check-generated-files.yml b/.github/workflows/check-generated-files.yml index d55e2d3a6b..9773002293 100644 --- a/.github/workflows/check-generated-files.yml +++ b/.github/workflows/check-generated-files.yml @@ -49,6 +49,7 @@ jobs: - "auth/domains.go" - "auth/keys.go" - "auth/policies.go" + - "auth/service.go" - "pkg/events/events.go" - "provision/service.go" - "pkg/groups/groups.go" @@ -109,6 +110,7 @@ jobs: mv ./auth/mocks/authz.go ./auth/mocks/authz.go.tmp mv ./auth/mocks/domains.go ./auth/mocks/domains.go.tmp mv ./auth/mocks/keys.go ./auth/mocks/keys.go.tmp + mv ./auth/mocks/service.go ./auth/mocks/service.go.tmp mv ./pkg/events/mocks/publisher.go ./pkg/events/mocks/publisher.go.tmp mv ./pkg/events/mocks/subscriber.go ./pkg/events/mocks/subscriber.go.tmp mv ./provision/mocks/service.go ./provision/mocks/service.go.tmp @@ -140,6 +142,7 @@ jobs: check_mock_changes ./auth/mocks/authz.go "Auth Authz ./auth/mocks/authz.go" check_mock_changes ./auth/mocks/domains.go "Auth Domains ./auth/mocks/domains.go" check_mock_changes ./auth/mocks/keys.go "Auth Keys ./auth/mocks/keys.go" + check_mock_changes ./auth/mocks/service.go "Auth Service ./auth/mocks/service.go" check_mock_changes ./pkg/events/mocks/publisher.go "ES Publisher ./pkg/events/mocks/publisher.go" check_mock_changes ./pkg/events/mocks/subscriber.go "EE Subscriber ./pkg/events/mocks/subscriber.go" check_mock_changes ./provision/mocks/service.go "Provision Service ./provision/mocks/service.go" diff --git a/auth.pb.go b/auth.pb.go index 76e29a55ea..fc9b881932 100644 --- a/auth.pb.go +++ b/auth.pb.go @@ -654,7 +654,7 @@ type AddPolicyRes struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Authorized bool `protobuf:"varint,1,opt,name=authorized,proto3" json:"authorized,omitempty"` + Added bool `protobuf:"varint,1,opt,name=added,proto3" json:"added,omitempty"` } func (x *AddPolicyRes) Reset() { @@ -689,9 +689,9 @@ func (*AddPolicyRes) Descriptor() ([]byte, []int) { return file_auth_proto_rawDescGZIP(), []int{9} } -func (x *AddPolicyRes) GetAuthorized() bool { +func (x *AddPolicyRes) GetAdded() bool { if x != nil { - return x.Authorized + return x.Added } return false } @@ -701,7 +701,7 @@ type AddPoliciesRes struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Authorized bool `protobuf:"varint,1,opt,name=authorized,proto3" json:"authorized,omitempty"` + Added bool `protobuf:"varint,1,opt,name=added,proto3" json:"added,omitempty"` } func (x *AddPoliciesRes) Reset() { @@ -736,9 +736,9 @@ func (*AddPoliciesRes) Descriptor() ([]byte, []int) { return file_auth_proto_rawDescGZIP(), []int{10} } -func (x *AddPoliciesRes) GetAuthorized() bool { +func (x *AddPoliciesRes) GetAdded() bool { if x != nil { - return x.Authorized + return x.Added } return false } @@ -1938,119 +1938,45 @@ var file_auth_proto_rawDesc = []byte{ 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x71, 0x52, 0x0e, 0x61, 0x64, 0x64, - 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x22, 0x2e, 0x0a, 0x0c, 0x41, - 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x61, - 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x0a, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x22, 0x30, 0x0a, 0x0e, 0x41, - 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x12, 0x1e, 0x0a, - 0x0a, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x0a, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x22, 0xca, 0x02, - 0x0a, 0x0f, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, - 0x71, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x75, 0x62, - 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0b, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x29, 0x0a, 0x10, - 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, - 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6a, 0x65, - 0x63, 0x74, 0x5f, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, - 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, - 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x62, - 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x07, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, - 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x62, 0x6a, 0x65, - 0x63, 0x74, 0x5f, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6f, - 0x62, 0x6a, 0x65, 0x63, 0x74, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x62, 0x6a, - 0x65, 0x63, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, - 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x22, 0x5e, 0x0a, 0x11, 0x44, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x12, - 0x49, 0x0a, 0x11, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, - 0x73, 0x52, 0x65, 0x71, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6d, 0x61, 0x67, - 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, - 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x71, 0x52, 0x11, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, - 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x22, 0x2b, 0x0a, 0x0f, 0x44, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x12, 0x18, 0x0a, - 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, - 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x22, 0x2d, 0x0a, 0x11, 0x44, 0x65, 0x6c, 0x65, 0x74, - 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, - 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x64, - 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x22, 0xc1, 0x02, 0x0a, 0x0e, 0x4c, 0x69, 0x73, 0x74, 0x4f, - 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, - 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, - 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x74, 0x79, 0x70, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, - 0x54, 0x79, 0x70, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, - 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, - 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, - 0x18, 0x0a, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x6c, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x6c, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, - 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x65, 0x72, 0x6d, 0x69, - 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, - 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1f, 0x0a, - 0x0b, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x08, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0a, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x24, - 0x0a, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, - 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, - 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x0a, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0x52, 0x0a, 0x0e, 0x4c, 0x69, - 0x73, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, - 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, - 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x6e, 0x65, 0x78, 0x74, - 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0xac, - 0x02, 0x0a, 0x0f, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, - 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x75, - 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0b, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x29, 0x0a, - 0x10, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, - 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x62, 0x6a, - 0x65, 0x63, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, - 0x63, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1e, - 0x0a, 0x0a, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0a, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, - 0x0a, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, - 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, - 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6f, 0x62, 0x6a, - 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, - 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, - 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x27, 0x0a, - 0x0f, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, - 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0xc2, 0x02, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x53, - 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, - 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, - 0x69, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x74, 0x79, - 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, - 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, - 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0f, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, - 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, - 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, - 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x65, 0x72, 0x6d, - 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, - 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1f, - 0x0a, 0x0b, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x08, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, - 0x24, 0x0a, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, - 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, - 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x0a, - 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0x53, 0x0a, 0x0f, 0x4c, - 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x12, 0x1a, - 0x0a, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, - 0x52, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x6e, 0x65, - 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, - 0x22, 0xad, 0x02, 0x0a, 0x10, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, + 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x22, 0x24, 0x0a, 0x0c, 0x41, + 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x61, + 0x64, 0x64, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x61, 0x64, 0x64, 0x65, + 0x64, 0x22, 0x26, 0x0a, 0x0e, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, + 0x52, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, 0x22, 0xca, 0x02, 0x0a, 0x0f, 0x44, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, + 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, + 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x75, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x73, 0x75, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0f, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x6c, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6b, + 0x69, 0x6e, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x75, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, + 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0a, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, + 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6b, + 0x69, 0x6e, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6f, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, + 0x74, 0x79, 0x70, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6f, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x22, 0x5e, 0x0a, 0x11, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x12, 0x49, 0x0a, 0x11, 0x64, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, + 0x61, 0x6c, 0x61, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, + 0x52, 0x65, 0x71, 0x52, 0x11, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, + 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x22, 0x2b, 0x0a, 0x0f, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x64, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x64, 0x22, 0x2d, 0x0a, 0x11, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, + 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x64, 0x22, 0xc1, 0x02, 0x0a, 0x0e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, @@ -2069,10 +1995,61 @@ var file_auth_proto_rawDesc = []byte{ 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, - 0x22, 0x28, 0x0a, 0x10, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, - 0x73, 0x52, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0xfc, 0x01, 0x0a, 0x12, 0x4c, - 0x69, 0x73, 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, + 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0x52, 0x0a, 0x0e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6f, 0x6c, 0x69, + 0x63, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6f, 0x6c, 0x69, + 0x63, 0x69, 0x65, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, + 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, + 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0xac, 0x02, 0x0a, 0x0f, 0x43, + 0x6f, 0x75, 0x6e, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x12, 0x16, + 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x75, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x73, 0x75, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x6c, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1a, + 0x0a, 0x08, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x65, + 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, + 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x74, 0x79, 0x70, + 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x54, + 0x79, 0x70, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, + 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, + 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x27, 0x0a, 0x0f, 0x43, 0x6f, 0x75, + 0x6e, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x22, 0xc2, 0x02, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x21, + 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, + 0x65, 0x12, 0x29, 0x0a, 0x10, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x72, 0x65, 0x6c, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x75, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, + 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, + 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x07, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0a, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x6e, + 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x09, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, + 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0x53, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x53, + 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6f, + 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6f, + 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, + 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, + 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0xad, 0x02, 0x0a, + 0x10, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, @@ -2081,103 +2058,125 @@ var file_auth_proto_rawDesc = []byte{ 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, - 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x62, 0x6a, - 0x65, 0x63, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, - 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x2d, 0x0a, 0x12, 0x66, 0x69, - 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, - 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x11, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x50, 0x65, - 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xef, 0x01, 0x0a, 0x12, 0x4c, 0x69, - 0x73, 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, - 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6a, - 0x65, 0x63, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, - 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x73, - 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, - 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, - 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, - 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x62, 0x6a, 0x65, - 0x63, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6f, - 0x62, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x65, 0x72, - 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, - 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x32, 0x51, 0x0a, 0x0c, 0x41, - 0x75, 0x74, 0x68, 0x7a, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x41, 0x0a, 0x09, 0x41, - 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x12, 0x18, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, - 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x52, - 0x65, 0x71, 0x1a, 0x18, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, - 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x73, 0x22, 0x00, 0x32, 0xc6, - 0x08, 0x0a, 0x0b, 0x41, 0x75, 0x74, 0x68, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x32, - 0x0a, 0x05, 0x49, 0x73, 0x73, 0x75, 0x65, 0x12, 0x14, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, - 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x49, 0x73, 0x73, 0x75, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x11, 0x2e, - 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, - 0x22, 0x00, 0x12, 0x36, 0x0a, 0x07, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x12, 0x16, 0x2e, - 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x52, 0x65, 0x66, 0x72, 0x65, - 0x73, 0x68, 0x52, 0x65, 0x71, 0x1a, 0x11, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, - 0x6c, 0x61, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x00, 0x12, 0x3e, 0x0a, 0x08, 0x49, 0x64, - 0x65, 0x6e, 0x74, 0x69, 0x66, 0x79, 0x12, 0x17, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, - 0x61, 0x6c, 0x61, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x1a, - 0x17, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x49, 0x64, 0x65, - 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x41, 0x0a, 0x09, 0x41, 0x75, - 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x12, 0x18, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, - 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x52, 0x65, - 0x71, 0x1a, 0x18, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, - 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x41, 0x0a, - 0x09, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x18, 0x2e, 0x6d, 0x61, 0x67, - 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, - 0x79, 0x52, 0x65, 0x71, 0x1a, 0x18, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, - 0x61, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x22, 0x00, - 0x12, 0x47, 0x0a, 0x0b, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x12, - 0x1a, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x64, 0x64, - 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1a, 0x2e, 0x6d, 0x61, + 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, + 0x0a, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0a, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, + 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, + 0x74, 0x79, 0x70, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6f, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, + 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, + 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x28, 0x0a, 0x10, + 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, + 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0xfc, 0x01, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x50, + 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, + 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, + 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x75, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x73, 0x75, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0f, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x6c, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x16, 0x0a, + 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, + 0x74, 0x79, 0x70, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6f, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x2d, 0x0a, 0x12, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, + 0x5f, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x07, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x11, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xef, 0x01, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, + 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x12, 0x16, 0x0a, 0x06, + 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, + 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, + 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x75, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x73, 0x75, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0f, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x16, 0x0a, 0x06, + 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x74, + 0x79, 0x70, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6f, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, + 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x65, 0x72, 0x6d, + 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x32, 0x51, 0x0a, 0x0c, 0x41, 0x75, 0x74, 0x68, 0x7a, + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x41, 0x0a, 0x09, 0x41, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x69, 0x7a, 0x65, 0x12, 0x18, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, + 0x61, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x18, + 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x75, 0x74, 0x68, + 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x73, 0x22, 0x00, 0x32, 0xc6, 0x08, 0x0a, 0x0b, 0x41, + 0x75, 0x74, 0x68, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x32, 0x0a, 0x05, 0x49, 0x73, + 0x73, 0x75, 0x65, 0x12, 0x14, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, + 0x2e, 0x49, 0x73, 0x73, 0x75, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x11, 0x2e, 0x6d, 0x61, 0x67, 0x69, + 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x00, 0x12, 0x36, + 0x0a, 0x07, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x12, 0x16, 0x2e, 0x6d, 0x61, 0x67, 0x69, + 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x52, 0x65, + 0x71, 0x1a, 0x11, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x54, + 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x00, 0x12, 0x3e, 0x0a, 0x08, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x66, 0x79, 0x12, 0x17, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, + 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x1a, 0x17, 0x2e, 0x6d, 0x61, + 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, + 0x79, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x41, 0x0a, 0x09, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, + 0x69, 0x7a, 0x65, 0x12, 0x18, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, + 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x18, 0x2e, + 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x41, 0x0a, 0x09, 0x41, 0x64, 0x64, + 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x18, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, + 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x71, + 0x1a, 0x18, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x64, + 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x47, 0x0a, 0x0b, + 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x12, 0x1a, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, - 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x4a, 0x0a, 0x0c, 0x44, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, - 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, - 0x69, 0x63, 0x79, 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, - 0x61, 0x6c, 0x61, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, - 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x50, 0x0a, 0x0e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, - 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x12, 0x1d, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, - 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, - 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1d, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, - 0x61, 0x6c, 0x61, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, - 0x65, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x47, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x4f, - 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x1a, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, - 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, - 0x65, 0x71, 0x1a, 0x1a, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, - 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, - 0x12, 0x4a, 0x0a, 0x0e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x6c, 0x6c, 0x4f, 0x62, 0x6a, 0x65, 0x63, + 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1a, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, + 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, + 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x4a, 0x0a, 0x0c, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, + 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, + 0x6c, 0x61, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, + 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x22, + 0x00, 0x12, 0x50, 0x0a, 0x0e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, + 0x69, 0x65, 0x73, 0x12, 0x1d, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, + 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, + 0x65, 0x71, 0x1a, 0x1d, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, + 0x73, 0x22, 0x00, 0x12, 0x47, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x1a, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1a, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, - 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x4a, 0x0a, 0x0c, - 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x1b, 0x2e, 0x6d, - 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x4f, - 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, - 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x4f, 0x62, 0x6a, 0x65, - 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x4a, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, - 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, - 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, + 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x4a, 0x0a, 0x0e, + 0x4c, 0x69, 0x73, 0x74, 0x41, 0x6c, 0x6c, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x1a, + 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, + 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1a, 0x2e, 0x6d, 0x61, 0x67, + 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x4a, 0x0a, 0x0c, 0x43, 0x6f, 0x75, 0x6e, + 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, + 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, - 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, - 0x65, 0x73, 0x22, 0x00, 0x12, 0x4d, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x6c, 0x6c, 0x53, - 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, - 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, - 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, + 0x6c, 0x61, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, + 0x65, 0x73, 0x22, 0x00, 0x12, 0x4a, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x73, 0x12, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, - 0x73, 0x22, 0x00, 0x12, 0x4d, 0x0a, 0x0d, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x6a, - 0x65, 0x63, 0x74, 0x73, 0x12, 0x1c, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, - 0x61, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, - 0x65, 0x71, 0x1a, 0x1c, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, - 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, - 0x22, 0x00, 0x12, 0x53, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, - 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1e, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, - 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1e, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, - 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x42, 0x0e, 0x5a, 0x0c, 0x2e, 0x2f, 0x6d, 0x61, 0x67, - 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x71, 0x1a, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, + 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, + 0x12, 0x4d, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x6c, 0x6c, 0x53, 0x75, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x73, 0x12, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, + 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, + 0x1a, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, + 0x73, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, + 0x4d, 0x0a, 0x0d, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, + 0x12, 0x1c, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x43, 0x6f, + 0x75, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1c, + 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x43, 0x6f, 0x75, 0x6e, + 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x53, + 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x73, 0x12, 0x1e, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, + 0x69, 0x73, 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, + 0x71, 0x1a, 0x1e, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, + 0x69, 0x73, 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, + 0x73, 0x22, 0x00, 0x42, 0x0e, 0x5a, 0x0c, 0x2e, 0x2f, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, + 0x61, 0x6c, 0x61, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/auth.proto b/auth.proto index 80732096e5..3b370b995b 100644 --- a/auth.proto +++ b/auth.proto @@ -98,9 +98,9 @@ message AddPoliciesReq{ repeated AddPolicyReq addPoliciesReq= 1; } -message AddPolicyRes { bool authorized = 1; } +message AddPolicyRes { bool added = 1; } -message AddPoliciesRes { bool authorized = 1; } +message AddPoliciesRes { bool added = 1; } message DeletePolicyReq { string domain = 1; diff --git a/auth/api/grpc/client.go b/auth/api/grpc/client.go index bdae9eea99..ff0b3418c6 100644 --- a/auth/api/grpc/client.go +++ b/auth/api/grpc/client.go @@ -292,12 +292,12 @@ func (client grpcClient) AddPolicy(ctx context.Context, in *magistrala.AddPolicy } apr := res.(addPolicyRes) - return &magistrala.AddPolicyRes{Authorized: apr.authorized}, nil + return &magistrala.AddPolicyRes{Added: apr.added}, nil } func decodeAddPolicyResponse(_ context.Context, grpcRes interface{}) (interface{}, error) { res := grpcRes.(*magistrala.AddPolicyRes) - return addPolicyRes{authorized: res.Authorized}, nil + return addPolicyRes{added: res.Added}, nil } func encodeAddPolicyRequest(_ context.Context, grpcReq interface{}) (interface{}, error) { @@ -341,12 +341,12 @@ func (client grpcClient) AddPolicies(ctx context.Context, in *magistrala.AddPoli } apr := res.(addPoliciesRes) - return &magistrala.AddPoliciesRes{Authorized: apr.authorized}, nil + return &magistrala.AddPoliciesRes{Added: apr.added}, nil } func decodeAddPoliciesResponse(_ context.Context, grpcRes interface{}) (interface{}, error) { res := grpcRes.(*magistrala.AddPoliciesRes) - return addPoliciesRes{authorized: res.Authorized}, nil + return addPoliciesRes{added: res.Added}, nil } func encodeAddPoliciesRequest(_ context.Context, grpcReq interface{}) (interface{}, error) { @@ -532,7 +532,7 @@ func (client grpcClient) CountObjects(ctx context.Context, in *magistrala.CountO ctx, cancel := context.WithTimeout(ctx, client.timeout) defer cancel() - res, err := client.countObjects(ctx, listObjectsReq{ + res, err := client.countObjects(ctx, countObjectsReq{ Domain: in.GetDomain(), SubjectType: in.GetSubjectType(), Subject: in.GetSubject(), @@ -712,11 +712,12 @@ func decodeListPermissionsResponse(_ context.Context, grpcRes interface{}) (inte func encodeListPermissionsRequest(_ context.Context, grpcReq interface{}) (interface{}, error) { req := grpcReq.(listPermissionsReq) return &magistrala.ListPermissionsReq{ - Domain: req.Domain, - SubjectType: req.SubjectType, - Subject: req.Subject, - ObjectType: req.ObjectType, - Object: req.Object, + Domain: req.Domain, + SubjectType: req.SubjectType, + Subject: req.Subject, + ObjectType: req.ObjectType, + Object: req.Object, + FilterPermissions: req.FilterPermissions, }, nil } diff --git a/auth/api/grpc/endpoint.go b/auth/api/grpc/endpoint.go index e15f7fdfb1..c691ea732e 100644 --- a/auth/api/grpc/endpoint.go +++ b/auth/api/grpc/endpoint.go @@ -117,7 +117,7 @@ func addPolicyEndpoint(svc auth.Service) endpoint.Endpoint { if err != nil { return addPolicyRes{}, err } - return addPolicyRes{authorized: true}, err + return addPolicyRes{added: true}, err } } @@ -147,7 +147,7 @@ func addPoliciesEndpoint(svc auth.Service) endpoint.Endpoint { if err := svc.AddPolicies(ctx, prs); err != nil { return addPoliciesRes{}, err } - return addPoliciesRes{authorized: true}, nil + return addPoliciesRes{added: true}, nil } } diff --git a/auth/api/grpc/endpoint_test.go b/auth/api/grpc/endpoint_test.go index 318161e465..699777a817 100644 --- a/auth/api/grpc/endpoint_test.go +++ b/auth/api/grpc/endpoint_test.go @@ -13,7 +13,10 @@ import ( "github.com/absmach/magistrala" "github.com/absmach/magistrala/auth" grpcapi "github.com/absmach/magistrala/auth/api/grpc" + "github.com/absmach/magistrala/internal/apiutil" + "github.com/absmach/magistrala/internal/testsutil" "github.com/absmach/magistrala/pkg/errors" + svcerr "github.com/absmach/magistrala/pkg/errors/service" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "google.golang.org/grpc" @@ -38,6 +41,15 @@ const ( loginDuration = 30 * time.Minute refreshDuration = 24 * time.Hour invalidDuration = 7 * 24 * time.Hour + validToken = "valid" + inValidToken = "invalid" + validPolicy = "valid" +) + +var ( + validID = testsutil.GenerateUUID(&testing.T{}) + domainID = testsutil.GenerateUUID(&testing.T{}) + authAddr = fmt.Sprintf("localhost:%d", port) ) func startGRPCServer(svc auth.Service, port int) { @@ -45,333 +57,956 @@ func startGRPCServer(svc auth.Service, port int) { server := grpc.NewServer() magistrala.RegisterAuthServiceServer(server, grpcapi.NewServer(svc)) go func() { - if err := server.Serve(listener); err != nil { - panic(fmt.Sprintf("failed to serve: %s", err)) - } + err := server.Serve(listener) + assert.Nil(&testing.T{}, err, fmt.Sprintf(`"Unexpected error creating server %s"`, err)) }() } func TestIssue(t *testing.T) { - authAddr := fmt.Sprintf("localhost:%d", port) - conn, _ := grpc.Dial(authAddr, grpc.WithTransportCredentials(insecure.NewCredentials())) + conn, err := grpc.Dial(authAddr, grpc.WithTransportCredentials(insecure.NewCredentials())) + assert.Nil(t, err, fmt.Sprintf("Unexpected error creating client connection %s", err)) client := grpcapi.NewClient(conn, time.Second) cases := []struct { - desc string - id string - email string - kind auth.KeyType - err error - code codes.Code + desc string + userId string + domainID string + kind auth.KeyType + issueResponse auth.Token + err error }{ { - desc: "issue for user with valid token", - id: id, - email: email, - kind: auth.AccessKey, - err: nil, - code: codes.OK, + desc: "issue for user with valid token", + userId: validID, + domainID: domainID, + kind: auth.AccessKey, + issueResponse: auth.Token{ + AccessToken: validToken, + RefreshToken: validToken, + }, + err: nil, }, { - desc: "issue recovery key", - id: id, - email: email, - kind: auth.RecoveryKey, - err: nil, - code: codes.OK, + desc: "issue recovery key", + userId: validID, + domainID: domainID, + kind: auth.RecoveryKey, + issueResponse: auth.Token{ + AccessToken: validToken, + RefreshToken: validToken, + }, + err: nil, }, { - desc: "issue API key unauthenticated", - id: id, - email: email, - kind: auth.APIKey, - err: errors.ErrAuthentication, - code: codes.Unauthenticated, + desc: "issue API key unauthenticated", + userId: validID, + domainID: domainID, + kind: auth.APIKey, + issueResponse: auth.Token{}, + err: errors.ErrAuthentication, }, { - desc: "issue for invalid key type", - id: id, - email: email, - kind: 32, - err: errors.ErrMalformedEntity, - code: codes.InvalidArgument, + desc: "issue for invalid key type", + userId: validID, + domainID: domainID, + kind: 32, + issueResponse: auth.Token{}, + err: errors.ErrMalformedEntity, }, { - desc: "issue for user that exist", - id: "", - email: "", - kind: auth.APIKey, - err: errors.ErrAuthentication, - code: codes.Unauthenticated, + desc: "issue for user that does notexist", + userId: "", + domainID: "", + kind: auth.APIKey, + issueResponse: auth.Token{}, + err: errors.ErrAuthentication, }, } for _, tc := range cases { - _, err := client.Issue(context.Background(), &magistrala.IssueReq{UserId: tc.id, Type: uint32(tc.kind)}) + repoCall := svc.On("Issue", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.issueResponse, tc.err) + _, err := client.Issue(context.Background(), &magistrala.IssueReq{UserId: tc.userId, DomainId: &tc.domainID, Type: uint32(tc.kind)}) assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) + repoCall.Unset() } } -func TestIdentify(t *testing.T) { - repocall := prepo.On("CheckPolicy", mock.Anything, mock.Anything).Return(nil) - loginToken, err := svc.Issue(context.Background(), "", auth.Key{Type: auth.AccessKey, User: id, IssuedAt: time.Now(), Domain: groupName}) - assert.Nil(t, err, fmt.Sprintf("Issuing user key expected to succeed: %s", err)) - repocall.Unset() - - recoveryToken, err := svc.Issue(context.Background(), "", auth.Key{Type: auth.RecoveryKey, IssuedAt: time.Now(), Subject: id}) - assert.Nil(t, err, fmt.Sprintf("Issuing recovery key expected to succeed: %s", err)) - - repocall1 := krepo.On("Save", mock.Anything, mock.Anything).Return(mock.Anything, nil) - apiToken, err := svc.Issue(context.Background(), loginToken.AccessToken, auth.Key{Type: auth.APIKey, IssuedAt: time.Now(), ExpiresAt: time.Now().Add(time.Minute), Subject: id}) - assert.Nil(t, err, fmt.Sprintf("Issuing API key expected to succeed: %s", err)) - repocall1.Unset() - - authAddr := fmt.Sprintf("localhost:%d", port) - conn, _ := grpc.Dial(authAddr, grpc.WithTransportCredentials(insecure.NewCredentials())) +func TestRefresh(t *testing.T) { + conn, err := grpc.Dial(authAddr, grpc.WithTransportCredentials(insecure.NewCredentials())) + assert.Nil(t, err, fmt.Sprintf("Unexpected error creating client connection %s", err)) client := grpcapi.NewClient(conn, time.Second) cases := []struct { - desc string - token string - idt *magistrala.IdentityRes - err error - code codes.Code + desc string + token string + domainID string + issueResponse auth.Token + err error }{ { - desc: "identify user with user token", - token: loginToken.AccessToken, - idt: &magistrala.IdentityRes{Id: id, UserId: id, DomainId: groupName}, - err: nil, - code: codes.OK, + desc: "refresh token with valid token", + token: validToken, + domainID: domainID, + issueResponse: auth.Token{ + AccessToken: validToken, + RefreshToken: validToken, + }, + err: nil, }, { - desc: "identify user with recovery token", - token: recoveryToken.AccessToken, - idt: &magistrala.IdentityRes{Id: id}, - err: nil, - code: codes.OK, + desc: "refresh token with invalid token", + token: inValidToken, + domainID: domainID, + issueResponse: auth.Token{}, + err: errors.ErrAuthentication, + }, + { + desc: "refresh token with empty token", + token: "", + domainID: domainID, + issueResponse: auth.Token{}, + err: apiutil.ErrMissingSecret, }, + } + + for _, tc := range cases { + repoCall := svc.On("Issue", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.issueResponse, tc.err) + _, err := client.Refresh(context.Background(), &magistrala.RefreshReq{DomainId: &tc.domainID, RefreshToken: tc.token}) + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) + repoCall.Unset() + } +} + +func TestIdentify(t *testing.T) { + conn, err := grpc.Dial(authAddr, grpc.WithTransportCredentials(insecure.NewCredentials())) + assert.Nil(t, err, fmt.Sprintf("Unexpected error creating client connection %s", err)) + client := grpcapi.NewClient(conn, time.Second) + + cases := []struct { + desc string + token string + idt *magistrala.IdentityRes + svcErr error + err error + }{ { - desc: "identify user with API token", - token: apiToken.AccessToken, - idt: &magistrala.IdentityRes{Id: id}, + desc: "identify user with valid user token", + token: validToken, + idt: &magistrala.IdentityRes{Id: id, UserId: email, DomainId: domainID}, err: nil, - code: codes.OK, }, { - desc: "identify user with invalid user token", - token: "invalid", - idt: &magistrala.IdentityRes{}, - err: status.Error(codes.Unauthenticated, "unauthenticated access"), - code: codes.Unauthenticated, + desc: "identify user with invalid user token", + token: "invalid", + idt: &magistrala.IdentityRes{}, + svcErr: svcerr.ErrAuthentication, + err: svcerr.ErrAuthentication, }, { desc: "identify user with empty token", token: "", idt: &magistrala.IdentityRes{}, - err: status.Error(codes.InvalidArgument, "received invalid token request"), - code: codes.Unauthenticated, + err: apiutil.ErrBearerToken, }, } for _, tc := range cases { - repocall := krepo.On("Retrieve", mock.Anything, mock.Anything, mock.Anything).Return(auth.Key{Subject: id}, nil) - idt, _ := client.Identify(context.Background(), &magistrala.IdentityReq{Token: tc.token}) + repoCall := svc.On("Identify", mock.Anything, mock.Anything, mock.Anything).Return(auth.Key{Subject: id, User: email, Domain: domainID}, tc.svcErr) + idt, err := client.Identify(context.Background(), &magistrala.IdentityReq{Token: tc.token}) if idt != nil { assert.Equal(t, tc.idt, idt, fmt.Sprintf("%s: expected %v got %v", tc.desc, tc.idt, idt)) } - repocall.Unset() + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) + repoCall.Unset() } } func TestAuthorize(t *testing.T) { - repocall := prepo.On("CheckPolicy", mock.Anything, mock.Anything).Return(nil) - token, err := svc.Issue(context.Background(), "", auth.Key{Type: auth.AccessKey, IssuedAt: time.Now(), Subject: id, User: id, Domain: groupName}) - assert.Nil(t, err, fmt.Sprintf("Issuing user key expected to succeed: %s", err)) - repocall.Unset() - - authAddr := fmt.Sprintf("localhost:%d", port) - conn, _ := grpc.Dial(authAddr, grpc.WithTransportCredentials(insecure.NewCredentials())) + conn, err := grpc.Dial(authAddr, grpc.WithTransportCredentials(insecure.NewCredentials())) + assert.Nil(t, err, fmt.Sprintf("Unexpected error creating client connection %s", err)) client := grpcapi.NewClient(conn, time.Second) cases := []struct { - desc string - token string - subject string - subjecttype string - object string - objecttype string - relation string - permission string - ar *magistrala.AuthorizeRes - err error - code codes.Code + desc string + token string + authRequest *magistrala.AuthorizeReq + authResponse *magistrala.AuthorizeRes + err error }{ { - desc: "authorize user with authorized token", - token: token.AccessToken, - subject: id, - subjecttype: usersType, - object: authoritiesObj, - objecttype: usersType, - relation: memberRelation, - permission: adminpermission, - ar: &magistrala.AuthorizeRes{Authorized: true}, - err: nil, - code: codes.OK, - }, - { - desc: "authorize user with unauthorized relation", - token: token.AccessToken, - subject: id, - object: authoritiesObj, - relation: "unauthorizedRelation", - ar: &magistrala.AuthorizeRes{Authorized: false}, - err: nil, - code: codes.PermissionDenied, - }, - { - desc: "authorize user with unauthorized object", - token: token.AccessToken, - subject: id, - object: "unauthorizedobject", - relation: memberRelation, - ar: &magistrala.AuthorizeRes{Authorized: false}, - err: nil, - code: codes.PermissionDenied, - }, - { - desc: "authorize user with unauthorized subject", - token: token.AccessToken, - subject: "unauthorizedSubject", - object: authoritiesObj, - relation: memberRelation, - ar: &magistrala.AuthorizeRes{Authorized: false}, - err: nil, - code: codes.PermissionDenied, - }, - { - desc: "authorize user with invalid ACL", - token: token.AccessToken, - subject: "", - object: "", - relation: "", - ar: &magistrala.AuthorizeRes{Authorized: false}, - err: nil, - code: codes.InvalidArgument, + desc: "authorize user with authorized token", + token: validToken, + authRequest: &magistrala.AuthorizeReq{ + Subject: id, + SubjectType: usersType, + Object: authoritiesObj, + ObjectType: usersType, + Relation: memberRelation, + Permission: adminpermission, + }, + authResponse: &magistrala.AuthorizeRes{Authorized: true}, + err: nil, + }, + { + desc: "authorize user with unauthorized token", + token: inValidToken, + authRequest: &magistrala.AuthorizeReq{ + Subject: id, + SubjectType: usersType, + Object: authoritiesObj, + ObjectType: usersType, + Relation: memberRelation, + Permission: adminpermission, + }, + authResponse: &magistrala.AuthorizeRes{Authorized: false}, + err: svcerr.ErrAuthorization, + }, + { + desc: "authorize user with empty subject", + token: validToken, + authRequest: &magistrala.AuthorizeReq{ + Subject: "", + SubjectType: usersType, + Object: authoritiesObj, + ObjectType: usersType, + Relation: memberRelation, + Permission: adminpermission, + }, + authResponse: &magistrala.AuthorizeRes{Authorized: false}, + err: apiutil.ErrMissingPolicySub, + }, + { + desc: "authorize user with empty subject type", + token: validToken, + authRequest: &magistrala.AuthorizeReq{ + Subject: id, + SubjectType: "", + Object: authoritiesObj, + ObjectType: usersType, + Relation: memberRelation, + Permission: adminpermission, + }, + authResponse: &magistrala.AuthorizeRes{Authorized: false}, + err: apiutil.ErrMissingPolicySub, + }, + { + desc: "authorize user with empty object", + token: validToken, + authRequest: &magistrala.AuthorizeReq{ + Subject: id, + SubjectType: usersType, + Object: "", + ObjectType: usersType, + Relation: memberRelation, + Permission: adminpermission, + }, + authResponse: &magistrala.AuthorizeRes{Authorized: false}, + err: apiutil.ErrMissingPolicyObj, + }, + { + desc: "authorize user with empty object type", + token: validToken, + authRequest: &magistrala.AuthorizeReq{ + Subject: id, + SubjectType: usersType, + Object: authoritiesObj, + ObjectType: "", + Relation: memberRelation, + Permission: adminpermission, + }, + authResponse: &magistrala.AuthorizeRes{Authorized: false}, + err: apiutil.ErrMissingPolicyObj, + }, + { + desc: "authorize user with empty permission", + token: validToken, + authRequest: &magistrala.AuthorizeReq{ + Subject: id, + SubjectType: usersType, + Object: authoritiesObj, + ObjectType: usersType, + Relation: memberRelation, + Permission: "", + }, + authResponse: &magistrala.AuthorizeRes{Authorized: false}, + err: apiutil.ErrMalformedPolicyPer, }, } for _, tc := range cases { - repocall := prepo.On("CheckPolicy", mock.Anything, mock.Anything).Return(nil) - ar, _ := client.Authorize(context.Background(), &magistrala.AuthorizeReq{Subject: tc.subject, SubjectType: tc.subjecttype, Object: tc.object, ObjectType: tc.objecttype, Relation: tc.relation, Permission: tc.permission}) + repocall := svc.On("Authorize", mock.Anything, mock.Anything).Return(tc.err) + ar, err := client.Authorize(context.Background(), tc.authRequest) if ar != nil { - assert.Equal(t, tc.ar, ar, fmt.Sprintf("%s: expected %v got %v", tc.desc, tc.ar, ar)) + assert.Equal(t, tc.authResponse, ar, fmt.Sprintf("%s: expected %v got %v", tc.desc, tc.authResponse, ar)) } + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) repocall.Unset() } } func TestAddPolicy(t *testing.T) { - token, err := svc.Issue(context.Background(), "", auth.Key{Type: auth.AccessKey, IssuedAt: time.Now(), Subject: id}) - assert.Nil(t, err, fmt.Sprintf("Issuing user key expected to succeed: %s", err)) + conn, err := grpc.Dial(authAddr, grpc.WithTransportCredentials(insecure.NewCredentials())) + assert.Nil(t, err, fmt.Sprintf("Unexpected error creating client connection %s", err)) + client := grpcapi.NewClient(conn, time.Second) + + groupAdminObj := "groupadmin" + + cases := []struct { + desc string + token string + addPolicyReq *magistrala.AddPolicyReq + addPolicyRes *magistrala.AddPolicyRes + err error + }{ + { + desc: "add groupadmin policy to user", + token: validToken, + addPolicyReq: &magistrala.AddPolicyReq{ + Subject: id, + SubjectType: usersType, + Object: groupAdminObj, + ObjectType: usersType, + Relation: memberRelation, + Permission: adminpermission, + }, + addPolicyRes: &magistrala.AddPolicyRes{Added: true}, + err: nil, + }, + { + desc: "add groupadmin policy to user with invalid token", + token: inValidToken, + addPolicyReq: &magistrala.AddPolicyReq{ + Subject: id, + SubjectType: usersType, + Object: groupAdminObj, + ObjectType: usersType, + Relation: memberRelation, + Permission: adminpermission, + }, + addPolicyRes: &magistrala.AddPolicyRes{Added: false}, + err: svcerr.ErrAuthorization, + }, + } + for _, tc := range cases { + repoCall := svc.On("AddPolicy", mock.Anything, mock.Anything).Return(tc.err) + apr, err := client.AddPolicy(context.Background(), tc.addPolicyReq) + if apr != nil { + assert.Equal(t, tc.addPolicyRes, apr, fmt.Sprintf("%s: expected %v got %v", tc.desc, tc.addPolicyRes, apr)) + } + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) + repoCall.Unset() + } +} - authAddr := fmt.Sprintf("localhost:%d", port) - conn, _ := grpc.Dial(authAddr, grpc.WithTransportCredentials(insecure.NewCredentials())) +func TestAddPolicies(t *testing.T) { + conn, err := grpc.Dial(authAddr, grpc.WithTransportCredentials(insecure.NewCredentials())) + assert.Nil(t, err, fmt.Sprintf("Unexpected error creating client connection %s", err)) client := grpcapi.NewClient(conn, time.Second) groupAdminObj := "groupadmin" cases := []struct { - desc string - token string - subject string - subjecttype string - object string - objecttype string - relation string - permission string - ar *magistrala.AddPolicyRes - err error - code codes.Code + desc string + token string + pr *magistrala.AddPoliciesReq + ar *magistrala.AddPoliciesRes + err error }{ { - desc: "add groupadmin policy to user", - token: token.AccessToken, - subject: id, - subjecttype: usersType, - object: groupAdminObj, - objecttype: usersType, - relation: memberRelation, - permission: adminpermission, - ar: &magistrala.AddPolicyRes{Authorized: true}, - err: nil, - code: codes.OK, + desc: "add groupadmin policy to user", + token: validToken, + pr: &magistrala.AddPoliciesReq{ + AddPoliciesReq: []*magistrala.AddPolicyReq{ + { + Subject: id, + SubjectType: usersType, + Object: groupAdminObj, + ObjectType: usersType, + Relation: memberRelation, + Permission: adminpermission, + }, + }, + }, + ar: &magistrala.AddPoliciesRes{Added: true}, + err: nil, + }, + { + desc: "add groupadmin policy to user with invalid token", + token: inValidToken, + pr: &magistrala.AddPoliciesReq{ + AddPoliciesReq: []*magistrala.AddPolicyReq{ + { + Subject: id, + SubjectType: usersType, + Object: groupAdminObj, + ObjectType: usersType, + Relation: memberRelation, + Permission: adminpermission, + }, + }, + }, + ar: &magistrala.AddPoliciesRes{Added: false}, + err: svcerr.ErrAuthorization, }, } for _, tc := range cases { - repocall := prepo.On("AddPolicy", mock.Anything, mock.Anything).Return(nil) - apr, err := client.AddPolicy(context.Background(), &magistrala.AddPolicyReq{Subject: tc.subject, SubjectType: tc.subjecttype, Object: tc.object, ObjectType: tc.objecttype, Relation: tc.relation, Permission: tc.permission}) + repoCall := svc.On("AddPolicies", mock.Anything, mock.Anything).Return(tc.err) + apr, err := client.AddPolicies(context.Background(), tc.pr) if apr != nil { assert.Equal(t, tc.ar, apr, fmt.Sprintf("%s: expected %v got %v", tc.desc, tc.ar, apr)) } - repocall.Unset() - - e, ok := status.FromError(err) - assert.True(t, ok, "gRPC status can't be extracted from the error") - assert.Equal(t, tc.code, e.Code(), fmt.Sprintf("%s: expected %s got %s", tc.desc, tc.code, e.Code())) + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) + repoCall.Unset() } } func TestDeletePolicy(t *testing.T) { - token, err := svc.Issue(context.Background(), "", auth.Key{Type: auth.AccessKey, IssuedAt: time.Now(), Subject: id}) - assert.Nil(t, err, fmt.Sprintf("Issuing user key expected to succeed: %s", err)) + conn, err := grpc.Dial(authAddr, grpc.WithTransportCredentials(insecure.NewCredentials())) + assert.Nil(t, err, fmt.Sprintf("Unexpected error creating client connection %s", err)) + client := grpcapi.NewClient(conn, time.Second) + + readRelation := "read" + thingID := "thing" + + cases := []struct { + desc string + token string + deletePolicyReq *magistrala.DeletePolicyReq + deletePolicyRes *magistrala.DeletePolicyRes + err error + }{ + { + desc: "delete valid policy", + token: validToken, + deletePolicyReq: &magistrala.DeletePolicyReq{ + Subject: id, + SubjectType: usersType, + Object: thingID, + ObjectType: thingsType, + Relation: readRelation, + Permission: readRelation, + }, + deletePolicyRes: &magistrala.DeletePolicyRes{Deleted: true}, + err: nil, + }, + { + desc: "delete invalid policy with invalid token", + token: inValidToken, + deletePolicyReq: &magistrala.DeletePolicyReq{ + Subject: id, + SubjectType: usersType, + Object: thingID, + ObjectType: thingsType, + Relation: readRelation, + Permission: readRelation, + }, + deletePolicyRes: &magistrala.DeletePolicyRes{Deleted: false}, + err: svcerr.ErrAuthorization, + }, + } + for _, tc := range cases { + repoCall := svc.On("DeletePolicy", mock.Anything, mock.Anything).Return(tc.err) + dpr, err := client.DeletePolicy(context.Background(), tc.deletePolicyReq) + assert.Equal(t, tc.deletePolicyRes.GetDeleted(), dpr.GetDeleted(), fmt.Sprintf("%s: expected %v got %v", tc.desc, tc.deletePolicyRes.GetDeleted(), dpr.GetDeleted())) + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) + repoCall.Unset() + } +} - authAddr := fmt.Sprintf("localhost:%d", port) - conn, _ := grpc.Dial(authAddr, grpc.WithTransportCredentials(insecure.NewCredentials())) +func TestDeletePolicies(t *testing.T) { + conn, err := grpc.Dial(authAddr, grpc.WithTransportCredentials(insecure.NewCredentials())) + assert.Nil(t, err, fmt.Sprintf("Unexpected error creating client connection %s", err)) client := grpcapi.NewClient(conn, time.Second) readRelation := "read" thingID := "thing" - repocall := prepo.On("AddPolicy", mock.Anything, mock.Anything).Return(nil) - apr, err := client.AddPolicy(context.Background(), &magistrala.AddPolicyReq{Domain: groupName, Subject: id, SubjectType: usersType, Object: thingID, ObjectType: thingsType, Permission: readRelation}) - assert.Nil(t, err, fmt.Sprintf("Adding read policy to user expected to succeed: %s", err)) - assert.True(t, apr.GetAuthorized(), fmt.Sprintf("Adding read policy expected to make user authorized, expected %v got %v", true, apr.GetAuthorized())) - repocall.Unset() + cases := []struct { + desc string + token string + deletePoliciesReq *magistrala.DeletePoliciesReq + deletePoliciesRes *magistrala.DeletePoliciesRes + err error + }{ + { + desc: "delete policies with valid token", + token: validToken, + deletePoliciesReq: &magistrala.DeletePoliciesReq{ + DeletePoliciesReq: []*magistrala.DeletePolicyReq{ + { + Subject: id, + SubjectType: usersType, + Object: thingID, + ObjectType: thingsType, + Relation: readRelation, + Permission: readRelation, + }, + }, + }, + deletePoliciesRes: &magistrala.DeletePoliciesRes{Deleted: true}, + err: nil, + }, + { + desc: "delete policies with invalid token", + token: inValidToken, + deletePoliciesReq: &magistrala.DeletePoliciesReq{ + DeletePoliciesReq: []*magistrala.DeletePolicyReq{ + { + Subject: id, + SubjectType: usersType, + Object: thingID, + ObjectType: thingsType, + Relation: readRelation, + Permission: readRelation, + }, + }, + }, + deletePoliciesRes: &magistrala.DeletePoliciesRes{Deleted: false}, + err: svcerr.ErrAuthorization, + }, + } + for _, tc := range cases { + repoCall := svc.On("DeletePolicies", mock.Anything, mock.Anything).Return(tc.err) + apr, err := client.DeletePolicies(context.Background(), tc.deletePoliciesReq) + if apr != nil { + assert.Equal(t, tc.deletePoliciesRes, apr, fmt.Sprintf("%s: expected %v got %v", tc.desc, tc.deletePoliciesRes, apr)) + } + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) + repoCall.Unset() + } +} + +func TestListObjects(t *testing.T) { + conn, err := grpc.Dial(authAddr, grpc.WithTransportCredentials(insecure.NewCredentials())) + assert.Nil(t, err, fmt.Sprintf("Unexpected error creating client connection %s", err)) + client := grpcapi.NewClient(conn, time.Second) + + cases := []struct { + desc string + token string + listObjectsReq *magistrala.ListObjectsReq + listObjectsRes *magistrala.ListObjectsRes + err error + }{ + { + desc: "list objects with valid token", + token: validToken, + listObjectsReq: &magistrala.ListObjectsReq{ + Domain: domainID, + ObjectType: thingsType, + Relation: memberRelation, + Permission: adminpermission, + }, + listObjectsRes: &magistrala.ListObjectsRes{ + Policies: []string{validPolicy}, + }, + err: nil, + }, + { + desc: "list objects with invalid token", + token: inValidToken, + listObjectsReq: &magistrala.ListObjectsReq{ + Domain: domainID, + ObjectType: thingsType, + Relation: memberRelation, + Permission: adminpermission, + }, + listObjectsRes: &magistrala.ListObjectsRes{}, + err: svcerr.ErrAuthorization, + }, + } + for _, tc := range cases { + repoCall := svc.On("ListObjects", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(auth.PolicyPage{Policies: tc.listObjectsRes.Policies}, tc.err) + apr, err := client.ListObjects(context.Background(), tc.listObjectsReq) + if apr != nil { + assert.Equal(t, tc.listObjectsRes, apr, fmt.Sprintf("%s: expected %v got %v", tc.desc, tc.listObjectsRes, apr)) + } + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) + repoCall.Unset() + } +} + +func TestListAllObjects(t *testing.T) { + conn, err := grpc.Dial(authAddr, grpc.WithTransportCredentials(insecure.NewCredentials())) + assert.Nil(t, err, fmt.Sprintf("Unexpected error creating client connection %s", err)) + client := grpcapi.NewClient(conn, time.Second) cases := []struct { - desc string - token string - subject string - subjecttype string - object string - objecttype string - relation string - permission string - dpr *magistrala.DeletePolicyRes - code codes.Code + desc string + token string + listAllObjectsReq *magistrala.ListObjectsReq + listAllObjectsRes *magistrala.ListObjectsRes + err error }{ { - desc: "delete valid policy", - token: token.AccessToken, - subject: id, - subjecttype: usersType, - object: thingID, - objecttype: thingsType, - relation: readRelation, - permission: readRelation, - dpr: &magistrala.DeletePolicyRes{Deleted: true}, - code: codes.OK, + desc: "list all objects with valid token", + token: validToken, + listAllObjectsReq: &magistrala.ListObjectsReq{ + Domain: domainID, + ObjectType: thingsType, + Relation: memberRelation, + Permission: adminpermission, + }, + listAllObjectsRes: &magistrala.ListObjectsRes{ + Policies: []string{validPolicy}, + }, + err: nil, + }, + { + desc: "list all objects with invalid token", + token: inValidToken, + listAllObjectsReq: &magistrala.ListObjectsReq{ + Domain: domainID, + ObjectType: thingsType, + Relation: memberRelation, + Permission: adminpermission, + }, + listAllObjectsRes: &magistrala.ListObjectsRes{}, + err: svcerr.ErrAuthorization, }, } for _, tc := range cases { - repocall := prepo.On("DeletePolicy", mock.Anything, mock.Anything).Return(nil) - dpr, err := client.DeletePolicy(context.Background(), &magistrala.DeletePolicyReq{Subject: tc.subject, SubjectType: tc.subjecttype, Object: tc.object, ObjectType: tc.objecttype, Relation: tc.relation}) - e, ok := status.FromError(err) - repocall.Unset() + repoCall := svc.On("ListAllObjects", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(auth.PolicyPage{Policies: tc.listAllObjectsRes.Policies}, tc.err) + apr, err := client.ListAllObjects(context.Background(), tc.listAllObjectsReq) + if apr != nil { + assert.Equal(t, tc.listAllObjectsRes, apr, fmt.Sprintf("%s: expected %v got %v", tc.desc, tc.listAllObjectsRes, apr)) + } + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) + repoCall.Unset() + } +} + +func TestCountObects(t *testing.T) { + conn, err := grpc.Dial(authAddr, grpc.WithTransportCredentials(insecure.NewCredentials())) + assert.Nil(t, err, fmt.Sprintf("Unexpected error creating client connection %s", err)) + client := grpcapi.NewClient(conn, time.Second) + + cases := []struct { + desc string + token string + countObjectsReq *magistrala.CountObjectsReq + countObjectsRes *magistrala.CountObjectsRes + err error + }{ + { + desc: "count objects with valid token", + token: validToken, + countObjectsReq: &magistrala.CountObjectsReq{ + Domain: domainID, + ObjectType: thingsType, + Relation: memberRelation, + Permission: adminpermission, + }, + countObjectsRes: &magistrala.CountObjectsRes{ + Count: 1, + }, + err: nil, + }, + { + desc: "count objects with invalid token", + token: inValidToken, + countObjectsReq: &magistrala.CountObjectsReq{ + Domain: domainID, + ObjectType: thingsType, + Relation: memberRelation, + Permission: adminpermission, + }, + countObjectsRes: &magistrala.CountObjectsRes{}, + err: svcerr.ErrAuthorization, + }, + } + for _, tc := range cases { + repoCall := svc.On("CountObjects", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(int(tc.countObjectsRes.Count), tc.err) + apr, err := client.CountObjects(context.Background(), tc.countObjectsReq) + if apr != nil { + assert.Equal(t, tc.countObjectsRes, apr, fmt.Sprintf("%s: expected %v got %v", tc.desc, tc.countObjectsRes, apr)) + } + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) + repoCall.Unset() + } +} + +func TestListSubjects(t *testing.T) { + conn, err := grpc.Dial(authAddr, grpc.WithTransportCredentials(insecure.NewCredentials())) + assert.Nil(t, err, fmt.Sprintf("Unexpected error creating client connection %s", err)) + client := grpcapi.NewClient(conn, time.Second) + + cases := []struct { + desc string + token string + listSubjectsReq *magistrala.ListSubjectsReq + listSubjectsRes *magistrala.ListSubjectsRes + err error + }{ + { + desc: "list subjects with valid token", + token: validToken, + listSubjectsReq: &magistrala.ListSubjectsReq{ + Domain: domainID, + SubjectType: usersType, + Relation: memberRelation, + Permission: adminpermission, + }, + listSubjectsRes: &magistrala.ListSubjectsRes{ + Policies: []string{validPolicy}, + }, + err: nil, + }, + { + desc: "list subjects with invalid token", + token: inValidToken, + listSubjectsReq: &magistrala.ListSubjectsReq{ + Domain: domainID, + SubjectType: usersType, + Relation: memberRelation, + Permission: adminpermission, + }, + listSubjectsRes: &magistrala.ListSubjectsRes{}, + err: svcerr.ErrAuthorization, + }, + } + for _, tc := range cases { + repoCall := svc.On("ListSubjects", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(auth.PolicyPage{Policies: tc.listSubjectsRes.Policies}, tc.err) + apr, err := client.ListSubjects(context.Background(), tc.listSubjectsReq) + if apr != nil { + assert.Equal(t, tc.listSubjectsRes, apr, fmt.Sprintf("%s: expected %v got %v", tc.desc, tc.listSubjectsRes, apr)) + } + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) + repoCall.Unset() + } +} + +func TestListAllSubjects(t *testing.T) { + conn, err := grpc.Dial(authAddr, grpc.WithTransportCredentials(insecure.NewCredentials())) + assert.Nil(t, err, fmt.Sprintf(`"Unexpected error creating client connection %s"`, err)) + client := grpcapi.NewClient(conn, time.Second) + cases := []struct { + desc string + token string + listSubjectsReq *magistrala.ListSubjectsReq + listSubjectsRes *magistrala.ListSubjectsRes + err error + }{ + { + desc: "list all subjects with valid token", + token: validToken, + listSubjectsReq: &magistrala.ListSubjectsReq{ + Domain: domainID, + SubjectType: auth.UserType, + Relation: memberRelation, + Permission: adminpermission, + }, + listSubjectsRes: &magistrala.ListSubjectsRes{ + Policies: []string{validPolicy}, + }, + err: nil, + }, + { + desc: "list all subjects with invalid token", + token: inValidToken, + listSubjectsReq: &magistrala.ListSubjectsReq{ + Domain: domainID, + SubjectType: usersType, + Relation: memberRelation, + Permission: adminpermission, + }, + listSubjectsRes: &magistrala.ListSubjectsRes{}, + err: svcerr.ErrAuthorization, + }, + } + for _, tc := range cases { + repoCall := svc.On("ListAllSubjects", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(auth.PolicyPage{Policies: tc.listSubjectsRes.Policies}, tc.err) + apr, err := client.ListAllSubjects(context.Background(), tc.listSubjectsReq) + if apr != nil { + assert.Equal(t, tc.listSubjectsRes, apr, fmt.Sprintf("%s: expected %v got %v", tc.desc, tc.listSubjectsRes, apr)) + } + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) + repoCall.Unset() + } +} + +func TestCountSubjects(t *testing.T) { + conn, err := grpc.Dial(authAddr, grpc.WithTransportCredentials(insecure.NewCredentials())) + assert.Nil(t, err, fmt.Sprintf("Unexpected error creating client connection %s", err)) + client := grpcapi.NewClient(conn, time.Second) + + cases := []struct { + desc string + token string + countSubjectsReq *magistrala.CountSubjectsReq + countSubjectsRes *magistrala.CountSubjectsRes + err error + code codes.Code + }{ + { + desc: "count subjects with valid token", + token: validToken, + countSubjectsReq: &magistrala.CountSubjectsReq{ + Domain: domainID, + SubjectType: usersType, + Relation: memberRelation, + Permission: adminpermission, + }, + countSubjectsRes: &magistrala.CountSubjectsRes{ + Count: 1, + }, + code: codes.OK, + err: nil, + }, + { + desc: "count subjects with invalid token", + token: inValidToken, + countSubjectsReq: &magistrala.CountSubjectsReq{ + Domain: domainID, + SubjectType: usersType, + Relation: memberRelation, + Permission: adminpermission, + }, + countSubjectsRes: &magistrala.CountSubjectsRes{}, + err: svcerr.ErrAuthentication, + code: codes.Unauthenticated, + }, + } + for _, tc := range cases { + repoCall := svc.On("CountSubjects", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(int(tc.countSubjectsRes.Count), tc.err) + apr, err := client.CountSubjects(context.Background(), tc.countSubjectsReq) + if apr != nil { + assert.Equal(t, tc.countSubjectsRes, apr, fmt.Sprintf("%s: expected %v got %v", tc.desc, tc.countSubjectsRes, apr)) + } + e, ok := status.FromError(err) assert.True(t, ok, "gRPC status can't be extracted from the error") assert.Equal(t, tc.code, e.Code(), fmt.Sprintf("%s: expected %s got %s", tc.desc, tc.code, e.Code())) - assert.Equal(t, tc.dpr.GetDeleted(), dpr.GetDeleted(), fmt.Sprintf("%s: expected %v got %v", tc.desc, tc.dpr.GetDeleted(), dpr.GetDeleted())) + repoCall.Unset() + } +} + +func TestListPermissions(t *testing.T) { + conn, err := grpc.Dial(authAddr, grpc.WithTransportCredentials(insecure.NewCredentials())) + assert.Nil(t, err, fmt.Sprintf("Unexpected error creating client connection %s", err)) + client := grpcapi.NewClient(conn, time.Second) + + cases := []struct { + desc string + token string + listPermissionsReq *magistrala.ListPermissionsReq + listPermissionsRes *magistrala.ListPermissionsRes + err error + }{ + { + desc: "list permissions of thing type with valid token", + token: validToken, + listPermissionsReq: &magistrala.ListPermissionsReq{ + Domain: domainID, + SubjectType: auth.UserType, + Subject: id, + ObjectType: auth.ThingType, + Object: validID, + FilterPermissions: []string{"view"}, + }, + listPermissionsRes: &magistrala.ListPermissionsRes{ + SubjectType: auth.UserType, + Subject: id, + ObjectType: auth.ThingType, + Object: validID, + Permissions: []string{"view"}, + }, + err: nil, + }, + { + desc: "list permissions of group type with valid token", + token: validToken, + listPermissionsReq: &magistrala.ListPermissionsReq{ + Domain: domainID, + SubjectType: auth.UserType, + Subject: id, + ObjectType: auth.GroupType, + Object: validID, + FilterPermissions: []string{"view"}, + }, + listPermissionsRes: &magistrala.ListPermissionsRes{ + SubjectType: auth.UserType, + Subject: id, + ObjectType: auth.GroupType, + Object: validID, + Permissions: []string{"view"}, + }, + err: nil, + }, + { + desc: "list permissions of platform type with valid token", + token: validToken, + listPermissionsReq: &magistrala.ListPermissionsReq{ + Domain: domainID, + SubjectType: auth.UserType, + Subject: id, + ObjectType: auth.PlatformType, + Object: validID, + FilterPermissions: []string{"view"}, + }, + listPermissionsRes: &magistrala.ListPermissionsRes{ + SubjectType: auth.UserType, + Subject: id, + ObjectType: auth.PlatformType, + Object: validID, + Permissions: []string{"view"}, + }, + err: nil, + }, + { + desc: "list permissions of domain type with valid token", + token: validToken, + listPermissionsReq: &magistrala.ListPermissionsReq{ + Domain: domainID, + SubjectType: auth.UserType, + Subject: id, + ObjectType: auth.DomainType, + Object: validID, + FilterPermissions: []string{"view"}, + }, + listPermissionsRes: &magistrala.ListPermissionsRes{ + SubjectType: auth.UserType, + Subject: id, + ObjectType: auth.DomainType, + Object: validID, + Permissions: []string{"view"}, + }, + err: nil, + }, + { + desc: "list permissions of thing type with invalid token", + token: inValidToken, + listPermissionsReq: &magistrala.ListPermissionsReq{ + Domain: domainID, + SubjectType: auth.UserType, + Subject: id, + ObjectType: auth.ThingType, + Object: validID, + FilterPermissions: []string{"view"}, + }, + listPermissionsRes: &magistrala.ListPermissionsRes{}, + err: svcerr.ErrAuthentication, + }, + { + desc: "list permissions with invalid object type", + token: validToken, + listPermissionsReq: &magistrala.ListPermissionsReq{ + Domain: domainID, + SubjectType: auth.UserType, + Subject: id, + ObjectType: "invalid", + Object: validID, + }, + listPermissionsRes: &magistrala.ListPermissionsRes{}, + err: apiutil.ErrMalformedPolicy, + }, + } + for _, tc := range cases { + repoCall := svc.On("ListPermissions", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(auth.Permissions{"view"}, tc.err) + apr, err := client.ListPermissions(context.Background(), tc.listPermissionsReq) + if apr != nil { + assert.Equal(t, tc.listPermissionsRes, apr, fmt.Sprintf("%s: expected %v got %v", tc.desc, tc.listPermissionsRes, apr)) + } + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) + repoCall.Unset() } } diff --git a/auth/api/grpc/requests.go b/auth/api/grpc/requests.go index 2bb2a89f60..7df318cee2 100644 --- a/auth/api/grpc/requests.go +++ b/auth/api/grpc/requests.go @@ -100,11 +100,6 @@ func (req policyReq) validate() error { type policiesReq []policyReq func (prs policiesReq) validate() error { - for _, pr := range prs { - if err := pr.validate(); err != nil { - return nil - } - } return nil } diff --git a/auth/api/grpc/responses.go b/auth/api/grpc/responses.go index ded31a7aac..9d6c0785ce 100644 --- a/auth/api/grpc/responses.go +++ b/auth/api/grpc/responses.go @@ -21,10 +21,10 @@ type authorizeRes struct { } type addPolicyRes struct { - authorized bool + added bool } type addPoliciesRes struct { - authorized bool + added bool } type deletePolicyRes struct { diff --git a/auth/api/grpc/server.go b/auth/api/grpc/server.go index e50c032996..89c2a2add9 100644 --- a/auth/api/grpc/server.go +++ b/auth/api/grpc/server.go @@ -337,7 +337,7 @@ func decodeAddPolicyRequest(_ context.Context, grpcReq interface{}) (interface{} func encodeAddPolicyResponse(_ context.Context, grpcRes interface{}) (interface{}, error) { res := grpcRes.(addPolicyRes) - return &magistrala.AddPolicyRes{Authorized: res.authorized}, nil + return &magistrala.AddPolicyRes{Added: res.added}, nil } func decodeAddPoliciesRequest(_ context.Context, grpcReq interface{}) (interface{}, error) { @@ -361,7 +361,7 @@ func decodeAddPoliciesRequest(_ context.Context, grpcReq interface{}) (interface func encodeAddPoliciesResponse(_ context.Context, grpcRes interface{}) (interface{}, error) { res := grpcRes.(addPoliciesRes) - return &magistrala.AddPoliciesRes{Authorized: res.authorized}, nil + return &magistrala.AddPoliciesRes{Added: res.added}, nil } func decodeDeletePolicyRequest(_ context.Context, grpcReq interface{}) (interface{}, error) { @@ -478,8 +478,8 @@ func decodeCountSubjectsRequest(_ context.Context, grpcReq interface{}) (interfa } func encodeCountSubjectsResponse(_ context.Context, grpcRes interface{}) (interface{}, error) { - res := grpcRes.(countObjectsRes) - return &magistrala.CountObjectsRes{Count: int64(res.count)}, nil + res := grpcRes.(countSubjectsRes) + return &magistrala.CountSubjectsRes{Count: int64(res.count)}, nil } func decodeListPermissionsRequest(_ context.Context, grpcReq interface{}) (interface{}, error) { diff --git a/auth/api/grpc/setup_test.go b/auth/api/grpc/setup_test.go index 0793eb8074..df3e2f2543 100644 --- a/auth/api/grpc/setup_test.go +++ b/auth/api/grpc/setup_test.go @@ -7,27 +7,13 @@ import ( "os" "testing" - "github.com/absmach/magistrala/auth" - "github.com/absmach/magistrala/auth/jwt" "github.com/absmach/magistrala/auth/mocks" - "github.com/absmach/magistrala/pkg/uuid" ) -var ( - svc auth.Service - krepo *mocks.KeyRepository - prepo *mocks.PolicyAgent -) +var svc *mocks.Service func TestMain(m *testing.M) { - krepo = new(mocks.KeyRepository) - prepo = new(mocks.PolicyAgent) - drepo := new(mocks.DomainsRepository) - idProvider := uuid.NewMock() - - t := jwt.New([]byte(secret)) - - svc = auth.New(krepo, drepo, idProvider, t, prepo, loginDuration, refreshDuration, invalidDuration) + svc = new(mocks.Service) startGRPCServer(svc, port) code := m.Run() diff --git a/auth/api/http/domains/endpoint_test.go b/auth/api/http/domains/endpoint_test.go new file mode 100644 index 0000000000..4a53418b47 --- /dev/null +++ b/auth/api/http/domains/endpoint_test.go @@ -0,0 +1,1331 @@ +// Copyright (c) Abstract Machines +// SPDX-License-Identifier: Apache-2.0 + +package domains_test + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + "net/http/httptest" + "strings" + "testing" + "time" + + "github.com/absmach/magistrala/auth" + httpapi "github.com/absmach/magistrala/auth/api/http/domains" + "github.com/absmach/magistrala/auth/mocks" + "github.com/absmach/magistrala/internal/apiutil" + "github.com/absmach/magistrala/internal/testsutil" + mglog "github.com/absmach/magistrala/logger" + mgclients "github.com/absmach/magistrala/pkg/clients" + "github.com/absmach/magistrala/pkg/errors" + svcerr "github.com/absmach/magistrala/pkg/errors/service" + "github.com/go-chi/chi/v5" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +var ( + validCMetadata = mgclients.Metadata{"role": "client"} + ID = testsutil.GenerateUUID(&testing.T{}) + domain = auth.Domain{ + ID: ID, + Name: "domainname", + Tags: []string{"tag1", "tag2"}, + Metadata: validCMetadata, + Status: auth.EnabledStatus, + Alias: "mydomain", + } + validToken = "token" + inValidToken = "invalid" + validID = "d4ebb847-5d0e-4e46-bdd9-b6aceaaa3a22" + + id = "testID" +) + +const ( + contentType = "application/json" + refreshDuration = 24 * time.Hour + invalidDuration = 7 * 24 * time.Hour +) + +type testRequest struct { + client *http.Client + method string + url string + contentType string + token string + body io.Reader +} + +func (tr testRequest) make() (*http.Response, error) { + req, err := http.NewRequest(tr.method, tr.url, tr.body) + if err != nil { + return nil, err + } + + if tr.token != "" { + req.Header.Set("Authorization", apiutil.BearerPrefix+tr.token) + } + + if tr.contentType != "" { + req.Header.Set("Content-Type", tr.contentType) + } + + req.Header.Set("Referer", "http://localhost") + + return tr.client.Do(req) +} + +func toJSON(data interface{}) string { + jsonData, err := json.Marshal(data) + if err != nil { + return "" + } + return string(jsonData) +} + +func newDomainsServer() (*httptest.Server, *mocks.Service) { + logger := mglog.NewMock() + mux := chi.NewRouter() + svc := new(mocks.Service) + httpapi.MakeHandler(svc, mux, logger) + return httptest.NewServer(mux), svc +} + +func TestCreateDomain(t *testing.T) { + ds, svc := newDomainsServer() + defer ds.Close() + + cases := []struct { + desc string + domain auth.Domain + token string + contentType string + svcErr error + status int + err error + }{ + { + desc: "register a new domain successfully", + domain: auth.Domain{ + ID: ID, + Name: "test", + Metadata: mgclients.Metadata{"role": "domain"}, + Tags: []string{"tag1", "tag2"}, + Alias: "test", + }, + token: validToken, + contentType: contentType, + status: http.StatusOK, + err: nil, + }, + { + desc: "register a new domain with empty token", + domain: auth.Domain{ + ID: ID, + Name: "test", + Metadata: mgclients.Metadata{"role": "domain"}, + Tags: []string{"tag1", "tag2"}, + Alias: "test", + }, + token: "", + contentType: contentType, + status: http.StatusUnauthorized, + err: apiutil.ErrBearerToken, + }, + { + desc: "register a new domain with invalid token", + domain: auth.Domain{ + ID: ID, + Name: "test", + Metadata: mgclients.Metadata{"role": "domain"}, + Tags: []string{"tag1", "tag2"}, + Alias: "test", + }, + token: inValidToken, + contentType: contentType, + status: http.StatusUnauthorized, + svcErr: svcerr.ErrAuthentication, + err: svcerr.ErrAuthentication, + }, + { + desc: "register a new domain with an empty name", + domain: auth.Domain{ + ID: ID, + Name: "", + Metadata: mgclients.Metadata{"role": "domain"}, + Tags: []string{"tag1", "tag2"}, + Alias: "test", + }, + token: validToken, + contentType: contentType, + status: http.StatusInternalServerError, + err: apiutil.ErrMissingName, + }, + { + desc: "register a new domain with invalid content type", + domain: auth.Domain{ + ID: ID, + Name: "test", + Metadata: mgclients.Metadata{"role": "domain"}, + Tags: []string{"tag1", "tag2"}, + Alias: "test", + }, + token: validToken, + contentType: "application/xml", + status: http.StatusUnsupportedMediaType, + err: apiutil.ErrUnsupportedContentType, + }, + { + desc: "register a new domain that cant be marshalled", + domain: auth.Domain{ + ID: ID, + Name: "test", + Metadata: map[string]interface{}{ + "test": make(chan int), + }, + Tags: []string{"tag1", "tag2"}, + Alias: "test", + }, + token: validToken, + contentType: contentType, + status: http.StatusBadRequest, + err: apiutil.ErrValidation, + }, + } + + for _, tc := range cases { + data := toJSON(tc.domain) + req := testRequest{ + client: ds.Client(), + method: http.MethodPost, + url: fmt.Sprintf("%s/domains", ds.URL), + contentType: tc.contentType, + token: tc.token, + body: strings.NewReader(data), + } + + svcCall := svc.On("CreateDomain", mock.Anything, mock.Anything, mock.Anything).Return(auth.Domain{}, tc.svcErr) + res, err := req.make() + assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) + var errRes respBody + err = json.NewDecoder(res.Body).Decode(&errRes) + assert.Nil(t, err, fmt.Sprintf("%s: unexpected error while decoding response body: %s", tc.desc, err)) + if errRes.Err != "" || errRes.Message != "" { + err = errors.Wrap(errors.New(errRes.Err), errors.New(errRes.Message)) + } + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) + assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) + svcCall.Unset() + } +} + +func TestListDomains(t *testing.T) { + ds, svc := newDomainsServer() + defer ds.Close() + + cases := []struct { + desc string + token string + query string + listDomainsRequest auth.DomainsPage + status int + svcErr error + err error + }{ + { + desc: "list domains with valid token", + token: validToken, + status: http.StatusOK, + listDomainsRequest: auth.DomainsPage{ + Page: auth.Page{ + Total: 1, + }, + Domains: []auth.Domain{domain}, + }, + err: nil, + }, + { + desc: "list domains with empty token", + token: "", + status: http.StatusUnauthorized, + err: apiutil.ErrBearerToken, + }, + { + desc: "list domains with invalid token", + token: inValidToken, + status: http.StatusUnauthorized, + svcErr: svcerr.ErrAuthentication, + err: svcerr.ErrAuthentication, + }, + { + desc: "list domains with offset", + token: validToken, + listDomainsRequest: auth.DomainsPage{ + Page: auth.Page{ + Total: 1, + }, + Domains: []auth.Domain{domain}, + }, + query: "offset=1", + status: http.StatusOK, + err: nil, + }, + { + desc: "list domains with invalid offset", + token: validToken, + query: "offset=invalid", + status: http.StatusBadRequest, + err: apiutil.ErrValidation, + }, + { + desc: "list domains with limit", + token: validToken, + listDomainsRequest: auth.DomainsPage{ + Page: auth.Page{ + Total: 1, + }, + Domains: []auth.Domain{domain}, + }, + query: "limit=1", + status: http.StatusOK, + err: nil, + }, + { + desc: "list domains with invalid limit", + token: validToken, + query: "limit=invalid", + status: http.StatusBadRequest, + err: apiutil.ErrValidation, + }, + { + desc: "list domains with name", + token: validToken, + listDomainsRequest: auth.DomainsPage{ + Page: auth.Page{ + Total: 1, + }, + Domains: []auth.Domain{domain}, + }, + query: "name=domainname", + status: http.StatusOK, + err: nil, + }, + { + desc: "list domains with empty name", + token: validToken, + query: "name= ", + status: http.StatusBadRequest, + err: apiutil.ErrValidation, + }, + { + desc: "list domains with duplicate name", + token: validToken, + query: "name=1&name=2", + status: http.StatusBadRequest, + err: apiutil.ErrInvalidQueryParams, + }, + { + desc: "list domains with status", + token: validToken, + listDomainsRequest: auth.DomainsPage{ + Page: auth.Page{ + Total: 1, + }, + Domains: []auth.Domain{domain}, + }, + query: "status=enabled", + status: http.StatusOK, + err: nil, + }, + { + desc: "list domains with invalid status", + token: validToken, + query: "status=invalid", + status: http.StatusBadRequest, + err: apiutil.ErrValidation, + }, + { + desc: "list domains with duplicate status", + token: validToken, + query: "status=enabled&status=disabled", + status: http.StatusBadRequest, + err: apiutil.ErrInvalidQueryParams, + }, + { + desc: "list domains with tags", + token: validToken, + listDomainsRequest: auth.DomainsPage{ + Page: auth.Page{ + Total: 1, + }, + Domains: []auth.Domain{domain}, + }, + query: "tag=tag1,tag2", + status: http.StatusOK, + err: nil, + }, + { + desc: "list domains with empty tags", + token: validToken, + query: "tag= ", + status: http.StatusBadRequest, + err: apiutil.ErrValidation, + }, + { + desc: "list domains with duplicate tags", + token: validToken, + query: "tag=tag1&tag=tag2", + status: http.StatusBadRequest, + err: apiutil.ErrInvalidQueryParams, + }, + { + desc: "list domains with metadata", + token: validToken, + listDomainsRequest: auth.DomainsPage{ + Page: auth.Page{ + Total: 1, + }, + Domains: []auth.Domain{domain}, + }, + query: "metadata=%7B%22domain%22%3A%20%22example.com%22%7D&", + status: http.StatusOK, + err: nil, + }, + { + desc: "list domains with invalid metadata", + token: validToken, + query: "metadata=invalid", + status: http.StatusBadRequest, + err: apiutil.ErrValidation, + }, + { + desc: "list domains with duplicate metadata", + token: validToken, + query: "metadata=%7B%22domain%22%3A%20%22example.com%22%7D&metadata=%7B%22domain%22%3A%20%22example.com%22%7D", + status: http.StatusBadRequest, + err: apiutil.ErrInvalidQueryParams, + }, + { + desc: "list domains with permissions", + token: validToken, + listDomainsRequest: auth.DomainsPage{ + Page: auth.Page{ + Total: 1, + }, + Domains: []auth.Domain{domain}, + }, + query: "permission=view", + status: http.StatusOK, + err: nil, + }, + { + desc: "list domains with invalid permissions", + token: validToken, + query: "permission= ", + status: http.StatusBadRequest, + err: apiutil.ErrValidation, + }, + { + desc: "list domains with duplicate permissions", + token: validToken, + query: "permission=view&permission=view", + status: http.StatusBadRequest, + err: apiutil.ErrInvalidQueryParams, + }, + { + desc: "list domains with order", + token: validToken, + listDomainsRequest: auth.DomainsPage{ + Page: auth.Page{ + Total: 1, + }, + Domains: []auth.Domain{domain}, + }, + query: "order=name", + status: http.StatusOK, + }, + { + desc: "list domains with invalid order", + token: validToken, + query: "order= ", + status: http.StatusBadRequest, + err: apiutil.ErrValidation, + }, + { + desc: "list domains with duplicate order", + token: validToken, + query: "order=name&order=name", + status: http.StatusBadRequest, + err: apiutil.ErrInvalidQueryParams, + }, + { + desc: "list domains with dir", + token: validToken, + listDomainsRequest: auth.DomainsPage{ + Page: auth.Page{ + Total: 1, + }, + Domains: []auth.Domain{domain}, + }, + query: "dir=asc", + status: http.StatusOK, + }, + { + desc: "list domains with invalid dir", + token: validToken, + query: "dir= ", + status: http.StatusBadRequest, + err: apiutil.ErrValidation, + }, + { + desc: "list domains with duplicate dir", + token: validToken, + query: "dir=asc&dir=asc", + status: http.StatusBadRequest, + err: apiutil.ErrInvalidQueryParams, + }, + } + + for _, tc := range cases { + req := testRequest{ + client: ds.Client(), + method: http.MethodGet, + url: fmt.Sprintf("%s/domains?", ds.URL) + tc.query, + token: tc.token, + } + + svcCall := svc.On("ListDomains", mock.Anything, mock.Anything, mock.Anything).Return(tc.listDomainsRequest, tc.svcErr) + res, err := req.make() + assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) + assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) + svcCall.Unset() + } +} + +func TestViewDomain(t *testing.T) { + ds, svc := newDomainsServer() + defer ds.Close() + + cases := []struct { + desc string + token string + domainID string + status int + svcErr error + err error + }{ + { + desc: "view domain successfully", + token: validToken, + domainID: id, + status: http.StatusOK, + err: nil, + }, + { + desc: "view domain with empty token", + token: "", + domainID: id, + status: http.StatusUnauthorized, + err: apiutil.ErrBearerToken, + }, + { + desc: "view domain with invalid token", + token: inValidToken, + domainID: id, + status: http.StatusUnauthorized, + svcErr: svcerr.ErrAuthentication, + err: svcerr.ErrAuthentication, + }, + } + + for _, tc := range cases { + req := testRequest{ + client: ds.Client(), + method: http.MethodGet, + url: fmt.Sprintf("%s/domains/%s", ds.URL, tc.domainID), + token: tc.token, + } + + svcCall := svc.On("RetrieveDomain", mock.Anything, mock.Anything, mock.Anything).Return(auth.Domain{}, tc.svcErr) + res, err := req.make() + assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) + var errRes respBody + err = json.NewDecoder(res.Body).Decode(&errRes) + assert.Nil(t, err, fmt.Sprintf("%s: unexpected error while decoding response body: %s", tc.desc, err)) + if errRes.Err != "" || errRes.Message != "" { + err = errors.Wrap(errors.New(errRes.Err), errors.New(errRes.Message)) + } + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) + assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) + svcCall.Unset() + } +} + +func TestViewDomainPermissions(t *testing.T) { + ds, svc := newDomainsServer() + defer ds.Close() + + cases := []struct { + desc string + token string + domainID string + status int + svcErr error + err error + }{ + { + desc: "view domain permissions successfully", + token: validToken, + domainID: id, + status: http.StatusOK, + err: nil, + }, + { + desc: "view domain permissions with empty token", + token: "", + domainID: id, + status: http.StatusUnauthorized, + err: apiutil.ErrBearerToken, + }, + { + desc: "view domain permissions with invalid token", + token: inValidToken, + domainID: id, + status: http.StatusUnauthorized, + svcErr: svcerr.ErrAuthentication, + err: svcerr.ErrAuthentication, + }, + { + desc: "view domain permissions with empty domainID", + token: validToken, + domainID: "", + status: http.StatusBadRequest, + err: apiutil.ErrMissingID, + }, + } + + for _, tc := range cases { + req := testRequest{ + client: ds.Client(), + method: http.MethodGet, + url: fmt.Sprintf("%s/domains/%s/permissions", ds.URL, tc.domainID), + token: tc.token, + } + + svcCall := svc.On("RetrieveDomainPermissions", mock.Anything, mock.Anything, mock.Anything).Return(auth.Permissions{}, tc.svcErr) + res, err := req.make() + assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) + var errRes respBody + err = json.NewDecoder(res.Body).Decode(&errRes) + assert.Nil(t, err, fmt.Sprintf("%s: unexpected error while decoding response body: %s", tc.desc, err)) + if errRes.Err != "" || errRes.Message != "" { + err = errors.Wrap(errors.New(errRes.Err), errors.New(errRes.Message)) + } + + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) + assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) + svcCall.Unset() + } +} + +func TestUpdateDomain(t *testing.T) { + ds, svc := newDomainsServer() + defer ds.Close() + + cases := []struct { + desc string + token string + domain auth.Domain + contentType string + status int + svcErr error + err error + }{ + { + desc: "update domain successfully", + token: validToken, + domain: auth.Domain{ + ID: ID, + Name: "test", + Metadata: mgclients.Metadata{"role": "domain"}, + Tags: []string{"tag1", "tag2"}, + Alias: "test", + }, + contentType: contentType, + status: http.StatusOK, + err: nil, + }, + { + desc: "update domain with empty token", + token: "", + domain: auth.Domain{ + ID: ID, + Name: "test", + Metadata: mgclients.Metadata{"role": "domain"}, + Tags: []string{"tag1", "tag2"}, + Alias: "test", + }, + contentType: contentType, + status: http.StatusUnauthorized, + err: apiutil.ErrBearerToken, + }, + { + desc: "update domain with invalid token", + token: inValidToken, + domain: auth.Domain{ + ID: ID, + Name: "test", + Metadata: mgclients.Metadata{"role": "domain"}, + Tags: []string{"tag1", "tag2"}, + Alias: "test", + }, + contentType: contentType, + status: http.StatusUnauthorized, + svcErr: svcerr.ErrAuthentication, + err: svcerr.ErrAuthentication, + }, + { + desc: "update domain with invalid content type", + token: validToken, + domain: auth.Domain{ + ID: ID, + Name: "test", + Metadata: mgclients.Metadata{"role": "domain"}, + Tags: []string{"tag1", "tag2"}, + Alias: "test", + }, + contentType: "application/xml", + status: http.StatusUnsupportedMediaType, + err: apiutil.ErrUnsupportedContentType, + }, + { + desc: "update domain with data that cant be marshalled", + token: validToken, + domain: auth.Domain{ + ID: ID, + Name: "test", + Metadata: map[string]interface{}{ + "test": make(chan int), + }, + Tags: []string{"tag1", "tag2"}, + Alias: "test", + }, + contentType: contentType, + status: http.StatusBadRequest, + err: apiutil.ErrValidation, + }, + } + + for _, tc := range cases { + data := toJSON(tc.domain) + req := testRequest{ + client: ds.Client(), + method: http.MethodPatch, + url: fmt.Sprintf("%s/domains/%s", ds.URL, tc.domain.ID), + body: strings.NewReader(data), + contentType: tc.contentType, + token: tc.token, + } + + svcCall := svc.On("UpdateDomain", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(auth.Domain{}, tc.svcErr) + res, err := req.make() + assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) + var errRes respBody + err = json.NewDecoder(res.Body).Decode(&errRes) + assert.Nil(t, err, fmt.Sprintf("%s: unexpected error while decoding response body: %s", tc.desc, err)) + if errRes.Err != "" || errRes.Message != "" { + err = errors.Wrap(errors.New(errRes.Err), errors.New(errRes.Message)) + } + + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) + assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) + svcCall.Unset() + } +} + +func TestEnableDomain(t *testing.T) { + ds, svc := newDomainsServer() + defer ds.Close() + + disabledDomain := domain + disabledDomain.Status = auth.DisabledStatus + + cases := []struct { + desc string + domain auth.Domain + response auth.Domain + token string + status int + svcErr error + err error + }{ + { + desc: "enable domain with valid token", + domain: disabledDomain, + response: auth.Domain{ + ID: domain.ID, + Status: auth.EnabledStatus, + }, + token: validToken, + status: http.StatusOK, + err: nil, + }, + { + desc: "enable domain with invalid token", + domain: disabledDomain, + token: inValidToken, + status: http.StatusUnauthorized, + svcErr: svcerr.ErrAuthentication, + err: svcerr.ErrAuthentication, + }, + { + desc: "enable domain with empty token", + domain: disabledDomain, + token: "", + status: http.StatusUnauthorized, + err: apiutil.ErrBearerToken, + }, + { + desc: "enable domain with empty id", + domain: auth.Domain{ + ID: "", + }, + token: validToken, + status: http.StatusBadRequest, + err: apiutil.ErrMissingID, + }, + { + desc: "enable domain with invalid id", + domain: auth.Domain{ + ID: "invalid", + }, + token: validToken, + status: http.StatusForbidden, + svcErr: svcerr.ErrAuthorization, + err: svcerr.ErrAuthorization, + }, + } + + for _, tc := range cases { + data := toJSON(tc.domain) + req := testRequest{ + client: ds.Client(), + method: http.MethodPost, + url: fmt.Sprintf("%s/domains/%s/enable", ds.URL, tc.domain.ID), + contentType: contentType, + token: tc.token, + body: strings.NewReader(data), + } + svcCall := svc.On("ChangeDomainStatus", mock.Anything, tc.token, tc.domain.ID, mock.Anything).Return(tc.response, tc.svcErr) + res, err := req.make() + assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) + assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) + svcCall.Unset() + } +} + +func TestDisableDomain(t *testing.T) { + ds, svc := newDomainsServer() + defer ds.Close() + + cases := []struct { + desc string + domain auth.Domain + response auth.Domain + token string + status int + svcErr error + err error + }{ + { + desc: "disable domain with valid token", + domain: domain, + response: auth.Domain{ + ID: domain.ID, + Status: auth.DisabledStatus, + }, + token: validToken, + status: http.StatusOK, + err: nil, + }, + { + desc: "disable domain with invalid token", + domain: domain, + token: inValidToken, + status: http.StatusUnauthorized, + svcErr: svcerr.ErrAuthentication, + err: svcerr.ErrAuthentication, + }, + { + desc: "disable domain with empty token", + domain: domain, + token: "", + status: http.StatusUnauthorized, + err: apiutil.ErrBearerToken, + }, + { + desc: "disable domain with empty id", + domain: auth.Domain{ + ID: "", + }, + token: validToken, + status: http.StatusBadRequest, + err: apiutil.ErrMissingID, + }, + { + desc: "disable domain with invalid id", + domain: auth.Domain{ + ID: "invalid", + }, + token: validToken, + status: http.StatusForbidden, + svcErr: svcerr.ErrAuthorization, + err: svcerr.ErrAuthorization, + }, + } + + for _, tc := range cases { + data := toJSON(tc.domain) + req := testRequest{ + client: ds.Client(), + method: http.MethodPost, + url: fmt.Sprintf("%s/domains/%s/disable", ds.URL, tc.domain.ID), + contentType: contentType, + token: tc.token, + body: strings.NewReader(data), + } + svcCall := svc.On("ChangeDomainStatus", mock.Anything, tc.token, tc.domain.ID, mock.Anything).Return(tc.response, tc.svcErr) + res, err := req.make() + assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) + assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) + svcCall.Unset() + } +} + +func TestFreezeDomain(t *testing.T) { + ds, svc := newDomainsServer() + defer ds.Close() + + cases := []struct { + desc string + domain auth.Domain + response auth.Domain + token string + status int + svcErr error + err error + }{ + { + desc: "freeze domain with valid token", + domain: domain, + response: auth.Domain{ + ID: domain.ID, + Status: auth.FreezeStatus, + }, + token: validToken, + status: http.StatusOK, + err: nil, + }, + { + desc: "freeze domain with invalid token", + domain: domain, + token: inValidToken, + status: http.StatusUnauthorized, + svcErr: svcerr.ErrAuthentication, + err: svcerr.ErrAuthentication, + }, + { + desc: "freeze domain with empty token", + domain: domain, + token: "", + status: http.StatusUnauthorized, + err: apiutil.ErrBearerToken, + }, + { + desc: "freeze domain with empty id", + domain: auth.Domain{ + ID: "", + }, + token: validToken, + status: http.StatusBadRequest, + err: apiutil.ErrMissingID, + }, + { + desc: "freeze domain with invalid id", + domain: auth.Domain{ + ID: "invalid", + }, + token: validToken, + status: http.StatusForbidden, + svcErr: svcerr.ErrAuthorization, + err: svcerr.ErrAuthorization, + }, + } + + for _, tc := range cases { + data := toJSON(tc.domain) + req := testRequest{ + client: ds.Client(), + method: http.MethodPost, + url: fmt.Sprintf("%s/domains/%s/freeze", ds.URL, tc.domain.ID), + contentType: contentType, + token: tc.token, + body: strings.NewReader(data), + } + svcCall := svc.On("ChangeDomainStatus", mock.Anything, tc.token, tc.domain.ID, mock.Anything).Return(tc.response, tc.svcErr) + res, err := req.make() + assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) + assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) + svcCall.Unset() + } +} + +func TestAssignDomainUsers(t *testing.T) { + ds, svc := newDomainsServer() + defer ds.Close() + + cases := []struct { + desc string + data string + domainID string + contentType string + token string + status int + err error + }{ + { + desc: "assign domain users with valid token", + data: fmt.Sprintf(`{"relation": "%s", "user_ids" : ["%s", "%s"]}`, "editor", validID, validID), + domainID: domain.ID, + contentType: contentType, + token: validToken, + status: http.StatusCreated, + err: nil, + }, + { + desc: "assign domain users with invalid token", + data: fmt.Sprintf(`{"relation": "%s", "user_ids" : ["%s", "%s"]}`, "editor", validID, validID), + domainID: domain.ID, + contentType: contentType, + token: inValidToken, + status: http.StatusUnauthorized, + err: svcerr.ErrAuthentication, + }, + { + desc: "assign domain users with empty token", + data: fmt.Sprintf(`{"relation": "%s", "user_ids" : ["%s", "%s"]}`, "editor", validID, validID), + domainID: domain.ID, + contentType: contentType, + token: "", + status: http.StatusUnauthorized, + err: apiutil.ErrBearerToken, + }, + { + desc: "assign domain users with empty id", + data: fmt.Sprintf(`{"relation": "%s", "user_ids" : ["%s", "%s"]}`, "editor", validID, validID), + domainID: "", + contentType: contentType, + token: validToken, + status: http.StatusBadRequest, + err: apiutil.ErrMissingID, + }, + { + desc: "assign domain users with invalid id", + data: fmt.Sprintf(`{"relation": "%s", "user_ids" : ["%s", "%s"]}`, "editor", validID, validID), + domainID: "invalid", + contentType: contentType, + token: validToken, + status: http.StatusForbidden, + err: svcerr.ErrAuthorization, + }, + { + desc: "assign domain users with malformed data", + data: fmt.Sprintf(`{"relation": "%s", user_ids : ["%s", "%s"]}`, "editor", validID, validID), + domainID: domain.ID, + contentType: contentType, + token: validToken, + status: http.StatusBadRequest, + err: apiutil.ErrValidation, + }, + { + desc: "assign domain users with invalid content type", + data: fmt.Sprintf(`{"relation": "%s", "user_ids" : ["%s", "%s"]}`, "editor", validID, validID), + domainID: domain.ID, + contentType: "application/xml", + token: validToken, + status: http.StatusUnsupportedMediaType, + err: apiutil.ErrUnsupportedContentType, + }, + { + desc: "assign domain users with empty user ids", + data: fmt.Sprintf(`{"relation": "%s", "user_ids" : []}`, "editor"), + domainID: domain.ID, + contentType: contentType, + token: validToken, + status: http.StatusInternalServerError, + err: apiutil.ErrValidation, + }, + { + desc: "assign domain users with empty relation", + data: fmt.Sprintf(`{"relation": "%s", "user_ids" : ["%s", "%s"]}`, "", validID, validID), + domainID: domain.ID, + contentType: contentType, + token: validToken, + status: http.StatusInternalServerError, + err: apiutil.ErrValidation, + }, + } + + for _, tc := range cases { + req := testRequest{ + client: ds.Client(), + method: http.MethodPost, + url: fmt.Sprintf("%s/domains/%s/users/assign", ds.URL, tc.domainID), + contentType: tc.contentType, + token: tc.token, + body: strings.NewReader(tc.data), + } + + svcCall := svc.On("AssignUsers", mock.Anything, tc.token, tc.domainID, mock.Anything, mock.Anything).Return(tc.err) + res, err := req.make() + assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) + assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) + svcCall.Unset() + } +} + +func TestUnassignDomainUsers(t *testing.T) { + ds, svc := newDomainsServer() + defer ds.Close() + + cases := []struct { + desc string + data string + domainID string + contentType string + token string + status int + err error + }{ + { + desc: "unassign domain users with valid token", + data: fmt.Sprintf(`{"relation": "%s", "user_ids" : ["%s", "%s"]}`, "editor", validID, validID), + domainID: domain.ID, + contentType: contentType, + token: validToken, + status: http.StatusNoContent, + err: nil, + }, + { + desc: "unassign domain users with invalid token", + data: fmt.Sprintf(`{"relation": "%s", "user_ids" : ["%s", "%s"]}`, "editor", validID, validID), + domainID: domain.ID, + contentType: contentType, + token: inValidToken, + status: http.StatusUnauthorized, + err: svcerr.ErrAuthentication, + }, + { + desc: "unassign domain users with empty token", + data: fmt.Sprintf(`{"relation": "%s", "user_ids" : ["%s", "%s"]}`, "editor", validID, validID), + domainID: domain.ID, + contentType: contentType, + token: "", + status: http.StatusUnauthorized, + err: apiutil.ErrBearerToken, + }, + { + desc: "unassign domain users with empty domain id", + data: fmt.Sprintf(`{"relation": "%s", "user_ids" : ["%s", "%s"]}`, "editor", validID, validID), + domainID: "", + contentType: contentType, + token: validToken, + status: http.StatusBadRequest, + err: apiutil.ErrMissingID, + }, + { + desc: "unassign domain users with invalid id", + data: fmt.Sprintf(`{"relation": "%s", "user_ids" : ["%s", "%s"]}`, "editor", validID, validID), + domainID: "invalid", + contentType: contentType, + token: validToken, + status: http.StatusForbidden, + err: svcerr.ErrAuthorization, + }, + { + desc: "unassign domain users with malformed data", + data: fmt.Sprintf(`{"relation": "%s", user_ids : ["%s", "%s"]}`, "editor", validID, validID), + domainID: domain.ID, + contentType: contentType, + token: validToken, + status: http.StatusBadRequest, + err: apiutil.ErrValidation, + }, + { + desc: "unassign domain users with invalid content type", + data: fmt.Sprintf(`{"relation": "%s", "user_ids" : ["%s", "%s"]}`, "editor", validID, validID), + domainID: domain.ID, + contentType: "application/xml", + token: validToken, + status: http.StatusUnsupportedMediaType, + err: apiutil.ErrUnsupportedContentType, + }, + { + desc: "unassign domain users with empty user ids", + data: fmt.Sprintf(`{"relation": "%s", "user_ids" : []}`, "editor"), + domainID: domain.ID, + contentType: contentType, + token: validToken, + status: http.StatusInternalServerError, + err: apiutil.ErrValidation, + }, + { + desc: "unassign domain users with empty relation", + data: fmt.Sprintf(`{"relation": "%s", "user_ids" : ["%s", "%s"]}`, "", validID, validID), + domainID: domain.ID, + contentType: contentType, + token: validToken, + status: http.StatusInternalServerError, + err: apiutil.ErrValidation, + }, + } + + for _, tc := range cases { + req := testRequest{ + client: ds.Client(), + method: http.MethodPost, + url: fmt.Sprintf("%s/domains/%s/users/unassign", ds.URL, tc.domainID), + contentType: tc.contentType, + token: tc.token, + body: strings.NewReader(tc.data), + } + + svcCall := svc.On("UnassignUsers", mock.Anything, tc.token, tc.domainID, mock.Anything, mock.Anything).Return(tc.err) + res, err := req.make() + assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) + assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) + svcCall.Unset() + } +} + +func TestListDomainsByUserID(t *testing.T) { + ds, svc := newDomainsServer() + defer ds.Close() + + cases := []struct { + desc string + token string + query string + listDomainsRequest auth.DomainsPage + userID string + status int + svcErr error + err error + }{ + { + desc: "list domains by user id with valid token", + token: validToken, + status: http.StatusOK, + listDomainsRequest: auth.DomainsPage{ + Page: auth.Page{ + Total: 1, + }, + Domains: []auth.Domain{domain}, + }, + userID: validID, + err: nil, + }, + { + desc: "list domains by user id with empty user id", + token: validToken, + status: http.StatusBadRequest, + err: apiutil.ErrMissingID, + }, + { + desc: "list domains by user id with empty token", + token: "", + userID: validID, + status: http.StatusUnauthorized, + err: apiutil.ErrBearerToken, + }, + { + desc: "list domains by user id with invalid token", + token: inValidToken, + userID: validID, + status: http.StatusUnauthorized, + svcErr: svcerr.ErrAuthentication, + err: svcerr.ErrAuthentication, + }, + { + desc: "list domains by user id with offset", + token: validToken, + listDomainsRequest: auth.DomainsPage{ + Page: auth.Page{ + Total: 1, + }, + Domains: []auth.Domain{domain}, + }, + query: "offset=1", + userID: validID, + status: http.StatusOK, + err: nil, + }, + { + desc: "list domains by user id with invalid offset", + token: validToken, + query: "offset=invalid", + status: http.StatusBadRequest, + err: apiutil.ErrValidation, + }, + { + desc: "list domains by user id with limit", + token: validToken, + listDomainsRequest: auth.DomainsPage{ + Page: auth.Page{ + Total: 1, + }, + Domains: []auth.Domain{domain}, + }, + query: "limit=1", + userID: validID, + status: http.StatusOK, + err: nil, + }, + { + desc: "list domains by user id with invalid limit", + token: validToken, + query: "limit=invalid", + userID: validID, + status: http.StatusBadRequest, + err: apiutil.ErrValidation, + }, + } + for _, tc := range cases { + req := testRequest{ + client: ds.Client(), + method: http.MethodGet, + url: fmt.Sprintf("%s/users/%s/domains?", ds.URL, tc.userID) + tc.query, + token: tc.token, + } + + svcCall := svc.On("ListUserDomains", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.listDomainsRequest, tc.svcErr) + res, err := req.make() + assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) + assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) + svcCall.Unset() + } +} + +type respBody struct { + Err string `json:"error"` + Message string `json:"message"` + Total int `json:"total"` + Permissions []string `json:"permissions"` + ID string `json:"id"` + Tags []string `json:"tags"` + Status mgclients.Status `json:"status"` +} diff --git a/auth/api/http/keys/endpoint_test.go b/auth/api/http/keys/endpoint_test.go index 65ed1237be..ae46d02b2a 100644 --- a/auth/api/http/keys/endpoint_test.go +++ b/auth/api/http/keys/endpoint_test.go @@ -218,13 +218,20 @@ func TestRetrieve(t *testing.T) { desc string id string token string + key auth.Key status int err error }{ { - desc: "retrieve an existing key", - id: k.AccessToken, - token: token.AccessToken, + desc: "retrieve an existing key", + id: k.AccessToken, + token: token.AccessToken, + key: auth.Key{ + Subject: id, + Type: auth.AccessKey, + IssuedAt: time.Now(), + ExpiresAt: time.Now().Add(refreshDuration), + }, status: http.StatusOK, err: nil, }, @@ -242,6 +249,13 @@ func TestRetrieve(t *testing.T) { status: http.StatusUnauthorized, err: errors.ErrAuthentication, }, + { + desc: "retrieve a key with an empty token", + token: "", + id: k.AccessToken, + status: http.StatusUnauthorized, + err: errors.ErrAuthentication, + }, } for _, tc := range cases { @@ -251,7 +265,7 @@ func TestRetrieve(t *testing.T) { url: fmt.Sprintf("%s/keys/%s", ts.URL, tc.id), token: tc.token, } - repocall := krepo.On("Retrieve", mock.Anything, mock.Anything, mock.Anything).Return(auth.Key{}, tc.err) + repocall := krepo.On("Retrieve", mock.Anything, mock.Anything, mock.Anything).Return(tc.key, tc.err) res, err := req.make() assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) @@ -298,6 +312,12 @@ func TestRevoke(t *testing.T) { token: "wrong", status: http.StatusUnauthorized, }, + { + desc: "revoke key with empty token", + id: k.AccessToken, + token: "", + status: http.StatusUnauthorized, + }, } for _, tc := range cases { diff --git a/auth/api/http/keys/requests_test.go b/auth/api/http/keys/requests_test.go new file mode 100644 index 0000000000..7ab8ae7041 --- /dev/null +++ b/auth/api/http/keys/requests_test.go @@ -0,0 +1,88 @@ +// Copyright (c) Abstract Machines +// SPDX-License-Identifier: Apache-2.0 + +package keys + +import ( + "testing" + + "github.com/absmach/magistrala/auth" + "github.com/absmach/magistrala/internal/apiutil" + "github.com/stretchr/testify/assert" +) + +var valid = "valid" + +func TestIssueKeyReqValidate(t *testing.T) { + cases := []struct { + desc string + req issueKeyReq + err error + }{ + { + desc: "valid request", + req: issueKeyReq{ + token: valid, + Type: auth.AccessKey, + }, + err: nil, + }, + { + desc: "empty token", + req: issueKeyReq{ + token: "", + Type: auth.AccessKey, + }, + err: apiutil.ErrBearerToken, + }, + { + desc: "invalid key type", + req: issueKeyReq{ + token: valid, + Type: auth.KeyType(100), + }, + err: apiutil.ErrInvalidAPIKey, + }, + } + for _, tc := range cases { + err := tc.req.validate() + assert.Equal(t, tc.err, err) + } +} + +func TestKeyReqValidate(t *testing.T) { + cases := []struct { + desc string + req keyReq + err error + }{ + { + desc: "valid request", + req: keyReq{ + token: valid, + id: valid, + }, + err: nil, + }, + { + desc: "empty token", + req: keyReq{ + token: "", + id: valid, + }, + err: apiutil.ErrBearerToken, + }, + { + desc: "empty id", + req: keyReq{ + token: valid, + id: "", + }, + err: apiutil.ErrMissingID, + }, + } + for _, tc := range cases { + err := tc.req.validate() + assert.Equal(t, tc.err, err) + } +} diff --git a/auth/api/http/keys/transport.go b/auth/api/http/keys/transport.go index cbd2afd317..c66c15c0e4 100644 --- a/auth/api/http/keys/transport.go +++ b/auth/api/http/keys/transport.go @@ -10,8 +10,8 @@ import ( "net/http" "strings" - "github.com/absmach/magistrala" "github.com/absmach/magistrala/auth" + "github.com/absmach/magistrala/internal/api" "github.com/absmach/magistrala/internal/apiutil" "github.com/absmach/magistrala/pkg/errors" "github.com/go-chi/chi/v5" @@ -23,27 +23,27 @@ const contentType = "application/json" // MakeHandler returns a HTTP handler for API endpoints. func MakeHandler(svc auth.Service, mux *chi.Mux, logger *slog.Logger) *chi.Mux { opts := []kithttp.ServerOption{ - kithttp.ServerErrorEncoder(apiutil.LoggingErrorEncoder(logger, encodeError)), + kithttp.ServerErrorEncoder(apiutil.LoggingErrorEncoder(logger, api.EncodeError)), } mux.Route("/keys", func(r chi.Router) { r.Post("/", kithttp.NewServer( issueEndpoint(svc), decodeIssue, - encodeResponse, + api.EncodeResponse, opts..., ).ServeHTTP) r.Get("/{id}", kithttp.NewServer( (retrieveEndpoint(svc)), decodeKeyReq, - encodeResponse, + api.EncodeResponse, opts..., ).ServeHTTP) r.Delete("/{id}", kithttp.NewServer( (revokeEndpoint(svc)), decodeKeyReq, - encodeResponse, + api.EncodeResponse, opts..., ).ServeHTTP) }) @@ -52,7 +52,7 @@ func MakeHandler(svc auth.Service, mux *chi.Mux, logger *slog.Logger) *chi.Mux { func decodeIssue(_ context.Context, r *http.Request) (interface{}, error) { if !strings.Contains(r.Header.Get("Content-Type"), contentType) { - return nil, errors.ErrUnsupportedContentType + return nil, apiutil.ErrUnsupportedContentType } req := issueKeyReq{token: apiutil.ExtractBearerToken(r)} @@ -70,48 +70,3 @@ func decodeKeyReq(_ context.Context, r *http.Request) (interface{}, error) { } return req, nil } - -func encodeResponse(_ context.Context, w http.ResponseWriter, response interface{}) error { - w.Header().Set("Content-Type", contentType) - - if ar, ok := response.(magistrala.Response); ok { - for k, v := range ar.Headers() { - w.Header().Set(k, v) - } - - w.WriteHeader(ar.Code()) - - if ar.Empty() { - return nil - } - } - - return json.NewEncoder(w).Encode(response) -} - -func encodeError(_ context.Context, err error, w http.ResponseWriter) { - switch { - case errors.Contains(err, errors.ErrMalformedEntity), - err == apiutil.ErrMissingID, - err == apiutil.ErrInvalidAPIKey: - w.WriteHeader(http.StatusBadRequest) - case errors.Contains(err, errors.ErrAuthentication), - err == apiutil.ErrBearerToken: - w.WriteHeader(http.StatusUnauthorized) - case errors.Contains(err, errors.ErrNotFound): - w.WriteHeader(http.StatusNotFound) - case errors.Contains(err, errors.ErrConflict): - w.WriteHeader(http.StatusConflict) - case errors.Contains(err, errors.ErrUnsupportedContentType): - w.WriteHeader(http.StatusUnsupportedMediaType) - default: - w.WriteHeader(http.StatusInternalServerError) - } - - if errorVal, ok := err.(errors.Error); ok { - w.Header().Set("Content-Type", contentType) - if err := json.NewEncoder(w).Encode(apiutil.ErrorRes{Err: errorVal.Msg()}); err != nil { - w.WriteHeader(http.StatusInternalServerError) - } - } -} diff --git a/auth/domains.go b/auth/domains.go index a7b9febaac..c4ac9a3329 100644 --- a/auth/domains.go +++ b/auth/domains.go @@ -183,4 +183,7 @@ type DomainsRepository interface { // ListDomains list all the domains ListDomains(ctx context.Context, pm Page) (DomainsPage, error) + + // CheckPolicy check policy in domains database. + CheckPolicy(ctx context.Context, pc Policy) error } diff --git a/auth/domains_test.go b/auth/domains_test.go new file mode 100644 index 0000000000..f24a18ff6e --- /dev/null +++ b/auth/domains_test.go @@ -0,0 +1,186 @@ +// Copyright (c) Abstract Machines +// SPDX-License-Identifier: Apache-2.0 + +package auth_test + +import ( + "testing" + + "github.com/absmach/magistrala/auth" + "github.com/absmach/magistrala/internal/apiutil" + "github.com/stretchr/testify/assert" +) + +func TestStatusString(t *testing.T) { + cases := []struct { + desc string + status auth.Status + expected string + }{ + { + desc: "Enabled", + status: auth.EnabledStatus, + expected: "enabled", + }, + { + desc: "Disabled", + status: auth.DisabledStatus, + expected: "disabled", + }, + { + desc: "Freezed", + status: auth.FreezeStatus, + expected: "freezed", + }, + { + desc: "All", + status: auth.AllStatus, + expected: "all", + }, + { + desc: "Unknown", + status: auth.Status(100), + expected: "unknown", + }, + } + + for _, tc := range cases { + t.Run(tc.desc, func(t *testing.T) { + got := tc.status.String() + assert.Equal(t, tc.expected, got, "String() = %v, expected %v", got, tc.expected) + }) + } +} + +func TestToStatus(t *testing.T) { + cases := []struct { + desc string + status string + expetcted auth.Status + err error + }{ + { + desc: "Enabled", + status: "enabled", + expetcted: auth.EnabledStatus, + err: nil, + }, + { + desc: "Disabled", + status: "disabled", + expetcted: auth.DisabledStatus, + err: nil, + }, + { + desc: "Freezed", + status: "freezed", + expetcted: auth.FreezeStatus, + err: nil, + }, + { + desc: "All", + status: "all", + expetcted: auth.AllStatus, + err: nil, + }, + { + desc: "Unknown", + status: "unknown", + expetcted: auth.Status(0), + err: apiutil.ErrInvalidStatus, + }, + } + + for _, tc := range cases { + t.Run(tc.desc, func(t *testing.T) { + got, err := auth.ToStatus(tc.status) + assert.Equal(t, tc.err, err, "ToStatus() error = %v, expected %v", err, tc.err) + assert.Equal(t, tc.expetcted, got, "ToStatus() = %v, expected %v", got, tc.expetcted) + }) + } +} + +func TestStatusMarshalJSON(t *testing.T) { + cases := []struct { + desc string + expected []byte + status auth.Status + err error + }{ + { + desc: "Enabled", + expected: []byte(`"enabled"`), + status: auth.EnabledStatus, + err: nil, + }, + { + desc: "Disabled", + expected: []byte(`"disabled"`), + status: auth.DisabledStatus, + err: nil, + }, + { + desc: "All", + expected: []byte(`"all"`), + status: auth.AllStatus, + err: nil, + }, + { + desc: "Unknown", + expected: []byte(`"unknown"`), + status: auth.Status(100), + err: nil, + }, + } + + for _, tc := range cases { + t.Run(tc.desc, func(t *testing.T) { + got, err := tc.status.MarshalJSON() + assert.Equal(t, tc.err, err, "MarshalJSON() error = %v, expected %v", err, tc.err) + assert.Equal(t, tc.expected, got, "MarshalJSON() = %v, expected %v", got, tc.expected) + }) + } +} + +func TestStatusUnmarshalJSON(t *testing.T) { + cases := []struct { + desc string + expected auth.Status + status []byte + err error + }{ + { + desc: "Enabled", + expected: auth.EnabledStatus, + status: []byte(`"enabled"`), + err: nil, + }, + { + desc: "Disabled", + expected: auth.DisabledStatus, + status: []byte(`"disabled"`), + err: nil, + }, + { + desc: "All", + expected: auth.AllStatus, + status: []byte(`"all"`), + err: nil, + }, + { + desc: "Unknown", + expected: auth.Status(0), + status: []byte(`"unknown"`), + err: apiutil.ErrInvalidStatus, + }, + } + + for _, tc := range cases { + t.Run(tc.desc, func(t *testing.T) { + var s auth.Status + err := s.UnmarshalJSON(tc.status) + assert.Equal(t, tc.err, err, "UnmarshalJSON() error = %v, expected %v", err, tc.err) + assert.Equal(t, tc.expected, s, "UnmarshalJSON() = %v, expected %v", s, tc.expected) + }) + } +} diff --git a/auth/jwt/token_test.go b/auth/jwt/token_test.go index a0e324a390..d441727f69 100644 --- a/auth/jwt/token_test.go +++ b/auth/jwt/token_test.go @@ -9,13 +9,26 @@ import ( "time" "github.com/absmach/magistrala/auth" - "github.com/absmach/magistrala/auth/jwt" + authjwt "github.com/absmach/magistrala/auth/jwt" "github.com/absmach/magistrala/pkg/errors" + "github.com/lestrrat-go/jwx/v2/jwa" + "github.com/lestrrat-go/jwx/v2/jwt" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) -const secret = "test" +const ( + tokenType = "type" + userField = "user" + domainField = "domain" + issuerName = "magistrala.auth" + secret = "test" +) + +var ( + errInvalidIssuer = errors.New("invalid token issuer value") + reposecret = []byte("test") +) func key() auth.Key { exp := time.Now().UTC().Add(10 * time.Minute).Round(time.Second) @@ -29,8 +42,26 @@ func key() auth.Key { } } +func newToken(issuerName string, key auth.Key) string { + builder := jwt.NewBuilder() + builder. + Issuer(issuerName). + IssuedAt(key.IssuedAt). + Subject(key.Subject). + Claim(tokenType, "r"). + Expiration(key.ExpiresAt) + builder.Claim(userField, key.User) + builder.Claim(domainField, key.Domain) + if key.ID != "" { + builder.JwtID(key.ID) + } + tkn, _ := builder.Build() + tokn, _ := jwt.Sign(tkn, jwt.WithKey(jwa.HS512, reposecret)) + return string(tokn) +} + func TestIssue(t *testing.T) { - tokenizer := jwt.New([]byte(secret)) + tokenizer := authjwt.New([]byte(secret)) cases := []struct { desc string @@ -54,7 +85,7 @@ func TestIssue(t *testing.T) { } func TestParse(t *testing.T) { - tokenizer := jwt.New([]byte(secret)) + tokenizer := authjwt.New([]byte(secret)) token, err := tokenizer.Issue(key()) require.Nil(t, err, fmt.Sprintf("issuing key expected to succeed: %s", err)) @@ -70,6 +101,8 @@ func TestParse(t *testing.T) { expToken, err := tokenizer.Issue(expKey) require.Nil(t, err, fmt.Sprintf("issuing expired key expected to succeed: %s", err)) + inValidToken := newToken("invalid", key()) + cases := []struct { desc string key auth.Key @@ -83,7 +116,7 @@ func TestParse(t *testing.T) { err: nil, }, { - desc: "parse ivalid key", + desc: "parse invalid key", key: auth.Key{}, token: "invalid", err: errors.ErrAuthentication, @@ -92,13 +125,25 @@ func TestParse(t *testing.T) { desc: "parse expired key", key: auth.Key{}, token: expToken, - err: jwt.ErrExpiry, + err: authjwt.ErrExpiry, }, { desc: "parse expired API key", key: apiKey, token: apiToken, - err: jwt.ErrExpiry, + err: authjwt.ErrExpiry, + }, + { + desc: "parse token with invalid issuer", + key: auth.Key{}, + token: inValidToken, + err: errInvalidIssuer, + }, + { + desc: "parse token with invalid content", + key: auth.Key{}, + token: newToken(issuerName, key()), + err: authjwt.ErrJSONHandle, }, } diff --git a/auth/mocks/auth_client.go b/auth/mocks/auth_client.go new file mode 100644 index 0000000000..0d166cb3b5 --- /dev/null +++ b/auth/mocks/auth_client.go @@ -0,0 +1,127 @@ +// Copyright (c) Abstract Machines +// SPDX-License-Identifier: Apache-2.0 + +package mocks + +import ( + context "context" + + "github.com/absmach/magistrala" + "github.com/absmach/magistrala/pkg/errors" + svcerr "github.com/absmach/magistrala/pkg/errors/service" + "github.com/stretchr/testify/mock" + "google.golang.org/grpc" +) + +const InvalidValue = "invalid" + +var _ magistrala.AuthServiceClient = (*AuthClient)(nil) + +type AuthClient struct { + mock.Mock +} + +func (m *AuthClient) Issue(ctx context.Context, in *magistrala.IssueReq, opts ...grpc.CallOption) (*magistrala.Token, error) { + ret := m.Called(ctx, in) + if in.GetUserId() == InvalidValue || in.GetUserId() == "" { + return &magistrala.Token{}, svcerr.ErrAuthentication + } + + return ret.Get(0).(*magistrala.Token), ret.Error(1) +} + +func (m *AuthClient) Refresh(ctx context.Context, in *magistrala.RefreshReq, opts ...grpc.CallOption) (*magistrala.Token, error) { + ret := m.Called(ctx, in) + if in.GetRefreshToken() == InvalidValue || in.GetRefreshToken() == "" { + return &magistrala.Token{}, svcerr.ErrAuthentication + } + + return ret.Get(0).(*magistrala.Token), ret.Error(1) +} + +func (m *AuthClient) Identify(ctx context.Context, in *magistrala.IdentityReq, opts ...grpc.CallOption) (*magistrala.IdentityRes, error) { + ret := m.Called(ctx, in) + if in.GetToken() == InvalidValue || in.GetToken() == "" { + return &magistrala.IdentityRes{}, svcerr.ErrAuthentication + } + + return ret.Get(0).(*magistrala.IdentityRes), ret.Error(1) +} + +func (m *AuthClient) Authorize(ctx context.Context, in *magistrala.AuthorizeReq, opts ...grpc.CallOption) (*magistrala.AuthorizeRes, error) { + ret := m.Called(ctx, in) + if in.GetSubject() == InvalidValue || in.GetSubject() == "" { + return &magistrala.AuthorizeRes{Authorized: false}, svcerr.ErrAuthorization + } + if in.GetObject() == InvalidValue || in.GetObject() == "" { + return &magistrala.AuthorizeRes{Authorized: false}, errors.ErrAuthorization + } + + return ret.Get(0).(*magistrala.AuthorizeRes), ret.Error(1) +} + +func (m *AuthClient) AddPolicy(ctx context.Context, in *magistrala.AddPolicyReq, opts ...grpc.CallOption) (*magistrala.AddPolicyRes, error) { + ret := m.Called(ctx, in) + + return ret.Get(0).(*magistrala.AddPolicyRes), ret.Error(1) +} + +func (m *AuthClient) AddPolicies(ctx context.Context, in *magistrala.AddPoliciesReq, opts ...grpc.CallOption) (*magistrala.AddPoliciesRes, error) { + ret := m.Called(ctx, in) + + return ret.Get(0).(*magistrala.AddPoliciesRes), ret.Error(1) +} + +func (m *AuthClient) DeletePolicy(ctx context.Context, in *magistrala.DeletePolicyReq, opts ...grpc.CallOption) (*magistrala.DeletePolicyRes, error) { + ret := m.Called(ctx, in) + + return ret.Get(0).(*magistrala.DeletePolicyRes), ret.Error(1) +} + +func (m *AuthClient) DeletePolicies(ctx context.Context, in *magistrala.DeletePoliciesReq, opts ...grpc.CallOption) (*magistrala.DeletePoliciesRes, error) { + ret := m.Called(ctx, in) + + return ret.Get(0).(*magistrala.DeletePoliciesRes), ret.Error(1) +} + +func (m *AuthClient) ListObjects(ctx context.Context, in *magistrala.ListObjectsReq, opts ...grpc.CallOption) (*magistrala.ListObjectsRes, error) { + ret := m.Called(ctx, in) + + return ret.Get(0).(*magistrala.ListObjectsRes), ret.Error(1) +} + +func (m *AuthClient) ListAllObjects(ctx context.Context, in *magistrala.ListObjectsReq, opts ...grpc.CallOption) (*magistrala.ListObjectsRes, error) { + ret := m.Called(ctx, in) + + return ret.Get(0).(*magistrala.ListObjectsRes), ret.Error(1) +} + +func (m *AuthClient) CountObjects(ctx context.Context, in *magistrala.CountObjectsReq, opts ...grpc.CallOption) (*magistrala.CountObjectsRes, error) { + ret := m.Called(ctx, in) + + return ret.Get(0).(*magistrala.CountObjectsRes), ret.Error(1) +} + +func (m *AuthClient) ListSubjects(ctx context.Context, in *magistrala.ListSubjectsReq, opts ...grpc.CallOption) (*magistrala.ListSubjectsRes, error) { + ret := m.Called(ctx, in) + + return ret.Get(0).(*magistrala.ListSubjectsRes), ret.Error(1) +} + +func (m *AuthClient) ListAllSubjects(ctx context.Context, in *magistrala.ListSubjectsReq, opts ...grpc.CallOption) (*magistrala.ListSubjectsRes, error) { + ret := m.Called(ctx, in) + + return ret.Get(0).(*magistrala.ListSubjectsRes), ret.Error(1) +} + +func (m *AuthClient) CountSubjects(ctx context.Context, in *magistrala.CountSubjectsReq, opts ...grpc.CallOption) (*magistrala.CountSubjectsRes, error) { + ret := m.Called(ctx, in) + + return ret.Get(0).(*magistrala.CountSubjectsRes), ret.Error(1) +} + +func (m *AuthClient) ListPermissions(ctx context.Context, in *magistrala.ListPermissionsReq, opts ...grpc.CallOption) (*magistrala.ListPermissionsRes, error) { + ret := m.Called(ctx, in) + + return ret.Get(0).(*magistrala.ListPermissionsRes), ret.Error(1) +} diff --git a/auth/mocks/domains.go b/auth/mocks/domains.go index 7973b91c58..42a8c73f6c 100644 --- a/auth/mocks/domains.go +++ b/auth/mocks/domains.go @@ -17,6 +17,24 @@ type DomainsRepository struct { mock.Mock } +// CheckPolicy provides a mock function with given fields: ctx, pc +func (_m *DomainsRepository) CheckPolicy(ctx context.Context, pc auth.Policy) error { + ret := _m.Called(ctx, pc) + + if len(ret) == 0 { + panic("no return value specified for CheckPolicy") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, auth.Policy) error); ok { + r0 = rf(ctx, pc) + } else { + r0 = ret.Error(0) + } + + return r0 +} + // Delete provides a mock function with given fields: ctx, id func (_m *DomainsRepository) Delete(ctx context.Context, id string) error { ret := _m.Called(ctx, id) diff --git a/auth/mocks/service.go b/auth/mocks/service.go index 3991463ded..daa26c9b28 100644 --- a/auth/mocks/service.go +++ b/auth/mocks/service.go @@ -1,127 +1,656 @@ +// Code generated by mockery v2.38.0. DO NOT EDIT. + // Copyright (c) Abstract Machines -// SPDX-License-Identifier: Apache-2.0 package mocks import ( context "context" - "github.com/absmach/magistrala" - "github.com/absmach/magistrala/pkg/errors" - svcerr "github.com/absmach/magistrala/pkg/errors/service" - "github.com/stretchr/testify/mock" - "google.golang.org/grpc" -) - -const InvalidValue = "invalid" + auth "github.com/absmach/magistrala/auth" -var _ magistrala.AuthServiceClient = (*Service)(nil) + mock "github.com/stretchr/testify/mock" +) +// Service is an autogenerated mock type for the Service type type Service struct { mock.Mock } -func (m *Service) Issue(ctx context.Context, in *magistrala.IssueReq, opts ...grpc.CallOption) (*magistrala.Token, error) { - ret := m.Called(ctx, in) - if in.GetUserId() == InvalidValue || in.GetUserId() == "" { - return &magistrala.Token{}, svcerr.ErrAuthentication +// AddPolicies provides a mock function with given fields: ctx, prs +func (_m *Service) AddPolicies(ctx context.Context, prs []auth.PolicyReq) error { + ret := _m.Called(ctx, prs) + + if len(ret) == 0 { + panic("no return value specified for AddPolicies") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, []auth.PolicyReq) error); ok { + r0 = rf(ctx, prs) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// AddPolicy provides a mock function with given fields: ctx, pr +func (_m *Service) AddPolicy(ctx context.Context, pr auth.PolicyReq) error { + ret := _m.Called(ctx, pr) + + if len(ret) == 0 { + panic("no return value specified for AddPolicy") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, auth.PolicyReq) error); ok { + r0 = rf(ctx, pr) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// AssignUsers provides a mock function with given fields: ctx, token, id, userIds, relation +func (_m *Service) AssignUsers(ctx context.Context, token string, id string, userIds []string, relation string) error { + ret := _m.Called(ctx, token, id, userIds, relation) + + if len(ret) == 0 { + panic("no return value specified for AssignUsers") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, string, []string, string) error); ok { + r0 = rf(ctx, token, id, userIds, relation) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Authorize provides a mock function with given fields: ctx, pr +func (_m *Service) Authorize(ctx context.Context, pr auth.PolicyReq) error { + ret := _m.Called(ctx, pr) + + if len(ret) == 0 { + panic("no return value specified for Authorize") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, auth.PolicyReq) error); ok { + r0 = rf(ctx, pr) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// ChangeDomainStatus provides a mock function with given fields: ctx, token, id, d +func (_m *Service) ChangeDomainStatus(ctx context.Context, token string, id string, d auth.DomainReq) (auth.Domain, error) { + ret := _m.Called(ctx, token, id, d) + + if len(ret) == 0 { + panic("no return value specified for ChangeDomainStatus") + } + + var r0 auth.Domain + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, string, auth.DomainReq) (auth.Domain, error)); ok { + return rf(ctx, token, id, d) + } + if rf, ok := ret.Get(0).(func(context.Context, string, string, auth.DomainReq) auth.Domain); ok { + r0 = rf(ctx, token, id, d) + } else { + r0 = ret.Get(0).(auth.Domain) + } + + if rf, ok := ret.Get(1).(func(context.Context, string, string, auth.DomainReq) error); ok { + r1 = rf(ctx, token, id, d) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// CountObjects provides a mock function with given fields: ctx, pr +func (_m *Service) CountObjects(ctx context.Context, pr auth.PolicyReq) (int, error) { + ret := _m.Called(ctx, pr) + + if len(ret) == 0 { + panic("no return value specified for CountObjects") + } + + var r0 int + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, auth.PolicyReq) (int, error)); ok { + return rf(ctx, pr) + } + if rf, ok := ret.Get(0).(func(context.Context, auth.PolicyReq) int); ok { + r0 = rf(ctx, pr) + } else { + r0 = ret.Get(0).(int) + } + + if rf, ok := ret.Get(1).(func(context.Context, auth.PolicyReq) error); ok { + r1 = rf(ctx, pr) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// CountSubjects provides a mock function with given fields: ctx, pr +func (_m *Service) CountSubjects(ctx context.Context, pr auth.PolicyReq) (int, error) { + ret := _m.Called(ctx, pr) + + if len(ret) == 0 { + panic("no return value specified for CountSubjects") + } + + var r0 int + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, auth.PolicyReq) (int, error)); ok { + return rf(ctx, pr) + } + if rf, ok := ret.Get(0).(func(context.Context, auth.PolicyReq) int); ok { + r0 = rf(ctx, pr) + } else { + r0 = ret.Get(0).(int) + } + + if rf, ok := ret.Get(1).(func(context.Context, auth.PolicyReq) error); ok { + r1 = rf(ctx, pr) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// CreateDomain provides a mock function with given fields: ctx, token, d +func (_m *Service) CreateDomain(ctx context.Context, token string, d auth.Domain) (auth.Domain, error) { + ret := _m.Called(ctx, token, d) + + if len(ret) == 0 { + panic("no return value specified for CreateDomain") + } + + var r0 auth.Domain + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, auth.Domain) (auth.Domain, error)); ok { + return rf(ctx, token, d) + } + if rf, ok := ret.Get(0).(func(context.Context, string, auth.Domain) auth.Domain); ok { + r0 = rf(ctx, token, d) + } else { + r0 = ret.Get(0).(auth.Domain) + } + + if rf, ok := ret.Get(1).(func(context.Context, string, auth.Domain) error); ok { + r1 = rf(ctx, token, d) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// DeletePolicies provides a mock function with given fields: ctx, prs +func (_m *Service) DeletePolicies(ctx context.Context, prs []auth.PolicyReq) error { + ret := _m.Called(ctx, prs) + + if len(ret) == 0 { + panic("no return value specified for DeletePolicies") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, []auth.PolicyReq) error); ok { + r0 = rf(ctx, prs) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// DeletePolicy provides a mock function with given fields: ctx, pr +func (_m *Service) DeletePolicy(ctx context.Context, pr auth.PolicyReq) error { + ret := _m.Called(ctx, pr) + + if len(ret) == 0 { + panic("no return value specified for DeletePolicy") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, auth.PolicyReq) error); ok { + r0 = rf(ctx, pr) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Identify provides a mock function with given fields: ctx, token +func (_m *Service) Identify(ctx context.Context, token string) (auth.Key, error) { + ret := _m.Called(ctx, token) + + if len(ret) == 0 { + panic("no return value specified for Identify") + } + + var r0 auth.Key + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) (auth.Key, error)); ok { + return rf(ctx, token) + } + if rf, ok := ret.Get(0).(func(context.Context, string) auth.Key); ok { + r0 = rf(ctx, token) + } else { + r0 = ret.Get(0).(auth.Key) + } + + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, token) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Issue provides a mock function with given fields: ctx, token, key +func (_m *Service) Issue(ctx context.Context, token string, key auth.Key) (auth.Token, error) { + ret := _m.Called(ctx, token, key) + + if len(ret) == 0 { + panic("no return value specified for Issue") + } + + var r0 auth.Token + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, auth.Key) (auth.Token, error)); ok { + return rf(ctx, token, key) + } + if rf, ok := ret.Get(0).(func(context.Context, string, auth.Key) auth.Token); ok { + r0 = rf(ctx, token, key) + } else { + r0 = ret.Get(0).(auth.Token) + } + + if rf, ok := ret.Get(1).(func(context.Context, string, auth.Key) error); ok { + r1 = rf(ctx, token, key) + } else { + r1 = ret.Error(1) } - return ret.Get(0).(*magistrala.Token), ret.Error(1) + return r0, r1 } -func (m *Service) Refresh(ctx context.Context, in *magistrala.RefreshReq, opts ...grpc.CallOption) (*magistrala.Token, error) { - ret := m.Called(ctx, in) - if in.GetRefreshToken() == InvalidValue || in.GetRefreshToken() == "" { - return &magistrala.Token{}, svcerr.ErrAuthentication +// ListAllObjects provides a mock function with given fields: ctx, pr +func (_m *Service) ListAllObjects(ctx context.Context, pr auth.PolicyReq) (auth.PolicyPage, error) { + ret := _m.Called(ctx, pr) + + if len(ret) == 0 { + panic("no return value specified for ListAllObjects") } - return ret.Get(0).(*magistrala.Token), ret.Error(1) + var r0 auth.PolicyPage + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, auth.PolicyReq) (auth.PolicyPage, error)); ok { + return rf(ctx, pr) + } + if rf, ok := ret.Get(0).(func(context.Context, auth.PolicyReq) auth.PolicyPage); ok { + r0 = rf(ctx, pr) + } else { + r0 = ret.Get(0).(auth.PolicyPage) + } + + if rf, ok := ret.Get(1).(func(context.Context, auth.PolicyReq) error); ok { + r1 = rf(ctx, pr) + } else { + r1 = ret.Error(1) + } + + return r0, r1 } -func (m *Service) Identify(ctx context.Context, in *magistrala.IdentityReq, opts ...grpc.CallOption) (*magistrala.IdentityRes, error) { - ret := m.Called(ctx, in) - if in.GetToken() == InvalidValue || in.GetToken() == "" { - return &magistrala.IdentityRes{}, svcerr.ErrAuthentication +// ListAllSubjects provides a mock function with given fields: ctx, pr +func (_m *Service) ListAllSubjects(ctx context.Context, pr auth.PolicyReq) (auth.PolicyPage, error) { + ret := _m.Called(ctx, pr) + + if len(ret) == 0 { + panic("no return value specified for ListAllSubjects") } - return ret.Get(0).(*magistrala.IdentityRes), ret.Error(1) + var r0 auth.PolicyPage + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, auth.PolicyReq) (auth.PolicyPage, error)); ok { + return rf(ctx, pr) + } + if rf, ok := ret.Get(0).(func(context.Context, auth.PolicyReq) auth.PolicyPage); ok { + r0 = rf(ctx, pr) + } else { + r0 = ret.Get(0).(auth.PolicyPage) + } + + if rf, ok := ret.Get(1).(func(context.Context, auth.PolicyReq) error); ok { + r1 = rf(ctx, pr) + } else { + r1 = ret.Error(1) + } + + return r0, r1 } -func (m *Service) Authorize(ctx context.Context, in *magistrala.AuthorizeReq, opts ...grpc.CallOption) (*magistrala.AuthorizeRes, error) { - ret := m.Called(ctx, in) - if in.GetSubject() == InvalidValue || in.GetSubject() == "" { - return &magistrala.AuthorizeRes{Authorized: false}, svcerr.ErrAuthorization +// ListDomains provides a mock function with given fields: ctx, token, page +func (_m *Service) ListDomains(ctx context.Context, token string, page auth.Page) (auth.DomainsPage, error) { + ret := _m.Called(ctx, token, page) + + if len(ret) == 0 { + panic("no return value specified for ListDomains") } - if in.GetObject() == InvalidValue || in.GetObject() == "" { - return &magistrala.AuthorizeRes{Authorized: false}, errors.ErrAuthorization + + var r0 auth.DomainsPage + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, auth.Page) (auth.DomainsPage, error)); ok { + return rf(ctx, token, page) + } + if rf, ok := ret.Get(0).(func(context.Context, string, auth.Page) auth.DomainsPage); ok { + r0 = rf(ctx, token, page) + } else { + r0 = ret.Get(0).(auth.DomainsPage) + } + + if rf, ok := ret.Get(1).(func(context.Context, string, auth.Page) error); ok { + r1 = rf(ctx, token, page) + } else { + r1 = ret.Error(1) } - return ret.Get(0).(*magistrala.AuthorizeRes), ret.Error(1) + return r0, r1 } -func (m *Service) AddPolicy(ctx context.Context, in *magistrala.AddPolicyReq, opts ...grpc.CallOption) (*magistrala.AddPolicyRes, error) { - ret := m.Called(ctx, in) +// ListObjects provides a mock function with given fields: ctx, pr, nextPageToken, limit +func (_m *Service) ListObjects(ctx context.Context, pr auth.PolicyReq, nextPageToken string, limit int32) (auth.PolicyPage, error) { + ret := _m.Called(ctx, pr, nextPageToken, limit) + + if len(ret) == 0 { + panic("no return value specified for ListObjects") + } + + var r0 auth.PolicyPage + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, auth.PolicyReq, string, int32) (auth.PolicyPage, error)); ok { + return rf(ctx, pr, nextPageToken, limit) + } + if rf, ok := ret.Get(0).(func(context.Context, auth.PolicyReq, string, int32) auth.PolicyPage); ok { + r0 = rf(ctx, pr, nextPageToken, limit) + } else { + r0 = ret.Get(0).(auth.PolicyPage) + } + + if rf, ok := ret.Get(1).(func(context.Context, auth.PolicyReq, string, int32) error); ok { + r1 = rf(ctx, pr, nextPageToken, limit) + } else { + r1 = ret.Error(1) + } - return ret.Get(0).(*magistrala.AddPolicyRes), ret.Error(1) + return r0, r1 } -func (m *Service) AddPolicies(ctx context.Context, in *magistrala.AddPoliciesReq, opts ...grpc.CallOption) (*magistrala.AddPoliciesRes, error) { - ret := m.Called(ctx, in) +// ListPermissions provides a mock function with given fields: ctx, pr, filterPermission +func (_m *Service) ListPermissions(ctx context.Context, pr auth.PolicyReq, filterPermission []string) (auth.Permissions, error) { + ret := _m.Called(ctx, pr, filterPermission) - return ret.Get(0).(*magistrala.AddPoliciesRes), ret.Error(1) + if len(ret) == 0 { + panic("no return value specified for ListPermissions") + } + + var r0 auth.Permissions + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, auth.PolicyReq, []string) (auth.Permissions, error)); ok { + return rf(ctx, pr, filterPermission) + } + if rf, ok := ret.Get(0).(func(context.Context, auth.PolicyReq, []string) auth.Permissions); ok { + r0 = rf(ctx, pr, filterPermission) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(auth.Permissions) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, auth.PolicyReq, []string) error); ok { + r1 = rf(ctx, pr, filterPermission) + } else { + r1 = ret.Error(1) + } + + return r0, r1 } -func (m *Service) DeletePolicy(ctx context.Context, in *magistrala.DeletePolicyReq, opts ...grpc.CallOption) (*magistrala.DeletePolicyRes, error) { - ret := m.Called(ctx, in) +// ListSubjects provides a mock function with given fields: ctx, pr, nextPageToken, limit +func (_m *Service) ListSubjects(ctx context.Context, pr auth.PolicyReq, nextPageToken string, limit int32) (auth.PolicyPage, error) { + ret := _m.Called(ctx, pr, nextPageToken, limit) + + if len(ret) == 0 { + panic("no return value specified for ListSubjects") + } + + var r0 auth.PolicyPage + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, auth.PolicyReq, string, int32) (auth.PolicyPage, error)); ok { + return rf(ctx, pr, nextPageToken, limit) + } + if rf, ok := ret.Get(0).(func(context.Context, auth.PolicyReq, string, int32) auth.PolicyPage); ok { + r0 = rf(ctx, pr, nextPageToken, limit) + } else { + r0 = ret.Get(0).(auth.PolicyPage) + } + + if rf, ok := ret.Get(1).(func(context.Context, auth.PolicyReq, string, int32) error); ok { + r1 = rf(ctx, pr, nextPageToken, limit) + } else { + r1 = ret.Error(1) + } - return ret.Get(0).(*magistrala.DeletePolicyRes), ret.Error(1) + return r0, r1 } -func (m *Service) DeletePolicies(ctx context.Context, in *magistrala.DeletePoliciesReq, opts ...grpc.CallOption) (*magistrala.DeletePoliciesRes, error) { - ret := m.Called(ctx, in) +// ListUserDomains provides a mock function with given fields: ctx, token, userID, page +func (_m *Service) ListUserDomains(ctx context.Context, token string, userID string, page auth.Page) (auth.DomainsPage, error) { + ret := _m.Called(ctx, token, userID, page) + + if len(ret) == 0 { + panic("no return value specified for ListUserDomains") + } + + var r0 auth.DomainsPage + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, string, auth.Page) (auth.DomainsPage, error)); ok { + return rf(ctx, token, userID, page) + } + if rf, ok := ret.Get(0).(func(context.Context, string, string, auth.Page) auth.DomainsPage); ok { + r0 = rf(ctx, token, userID, page) + } else { + r0 = ret.Get(0).(auth.DomainsPage) + } + + if rf, ok := ret.Get(1).(func(context.Context, string, string, auth.Page) error); ok { + r1 = rf(ctx, token, userID, page) + } else { + r1 = ret.Error(1) + } - return ret.Get(0).(*magistrala.DeletePoliciesRes), ret.Error(1) + return r0, r1 } -func (m *Service) ListObjects(ctx context.Context, in *magistrala.ListObjectsReq, opts ...grpc.CallOption) (*magistrala.ListObjectsRes, error) { - ret := m.Called(ctx, in) +// RetrieveDomain provides a mock function with given fields: ctx, token, id +func (_m *Service) RetrieveDomain(ctx context.Context, token string, id string) (auth.Domain, error) { + ret := _m.Called(ctx, token, id) - return ret.Get(0).(*magistrala.ListObjectsRes), ret.Error(1) + if len(ret) == 0 { + panic("no return value specified for RetrieveDomain") + } + + var r0 auth.Domain + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, string) (auth.Domain, error)); ok { + return rf(ctx, token, id) + } + if rf, ok := ret.Get(0).(func(context.Context, string, string) auth.Domain); ok { + r0 = rf(ctx, token, id) + } else { + r0 = ret.Get(0).(auth.Domain) + } + + if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok { + r1 = rf(ctx, token, id) + } else { + r1 = ret.Error(1) + } + + return r0, r1 } -func (m *Service) ListAllObjects(ctx context.Context, in *magistrala.ListObjectsReq, opts ...grpc.CallOption) (*magistrala.ListObjectsRes, error) { - ret := m.Called(ctx, in) +// RetrieveDomainPermissions provides a mock function with given fields: ctx, token, id +func (_m *Service) RetrieveDomainPermissions(ctx context.Context, token string, id string) (auth.Permissions, error) { + ret := _m.Called(ctx, token, id) + + if len(ret) == 0 { + panic("no return value specified for RetrieveDomainPermissions") + } + + var r0 auth.Permissions + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, string) (auth.Permissions, error)); ok { + return rf(ctx, token, id) + } + if rf, ok := ret.Get(0).(func(context.Context, string, string) auth.Permissions); ok { + r0 = rf(ctx, token, id) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(auth.Permissions) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok { + r1 = rf(ctx, token, id) + } else { + r1 = ret.Error(1) + } - return ret.Get(0).(*magistrala.ListObjectsRes), ret.Error(1) + return r0, r1 } -func (m *Service) CountObjects(ctx context.Context, in *magistrala.CountObjectsReq, opts ...grpc.CallOption) (*magistrala.CountObjectsRes, error) { - ret := m.Called(ctx, in) +// RetrieveKey provides a mock function with given fields: ctx, token, id +func (_m *Service) RetrieveKey(ctx context.Context, token string, id string) (auth.Key, error) { + ret := _m.Called(ctx, token, id) - return ret.Get(0).(*magistrala.CountObjectsRes), ret.Error(1) + if len(ret) == 0 { + panic("no return value specified for RetrieveKey") + } + + var r0 auth.Key + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, string) (auth.Key, error)); ok { + return rf(ctx, token, id) + } + if rf, ok := ret.Get(0).(func(context.Context, string, string) auth.Key); ok { + r0 = rf(ctx, token, id) + } else { + r0 = ret.Get(0).(auth.Key) + } + + if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok { + r1 = rf(ctx, token, id) + } else { + r1 = ret.Error(1) + } + + return r0, r1 } -func (m *Service) ListSubjects(ctx context.Context, in *magistrala.ListSubjectsReq, opts ...grpc.CallOption) (*magistrala.ListSubjectsRes, error) { - ret := m.Called(ctx, in) +// Revoke provides a mock function with given fields: ctx, token, id +func (_m *Service) Revoke(ctx context.Context, token string, id string) error { + ret := _m.Called(ctx, token, id) + + if len(ret) == 0 { + panic("no return value specified for Revoke") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok { + r0 = rf(ctx, token, id) + } else { + r0 = ret.Error(0) + } - return ret.Get(0).(*magistrala.ListSubjectsRes), ret.Error(1) + return r0 } -func (m *Service) ListAllSubjects(ctx context.Context, in *magistrala.ListSubjectsReq, opts ...grpc.CallOption) (*magistrala.ListSubjectsRes, error) { - ret := m.Called(ctx, in) +// UnassignUsers provides a mock function with given fields: ctx, token, id, userIds, relation +func (_m *Service) UnassignUsers(ctx context.Context, token string, id string, userIds []string, relation string) error { + ret := _m.Called(ctx, token, id, userIds, relation) - return ret.Get(0).(*magistrala.ListSubjectsRes), ret.Error(1) + if len(ret) == 0 { + panic("no return value specified for UnassignUsers") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, string, []string, string) error); ok { + r0 = rf(ctx, token, id, userIds, relation) + } else { + r0 = ret.Error(0) + } + + return r0 } -func (m *Service) CountSubjects(ctx context.Context, in *magistrala.CountSubjectsReq, opts ...grpc.CallOption) (*magistrala.CountSubjectsRes, error) { - ret := m.Called(ctx, in) +// UpdateDomain provides a mock function with given fields: ctx, token, id, d +func (_m *Service) UpdateDomain(ctx context.Context, token string, id string, d auth.DomainReq) (auth.Domain, error) { + ret := _m.Called(ctx, token, id, d) - return ret.Get(0).(*magistrala.CountSubjectsRes), ret.Error(1) + if len(ret) == 0 { + panic("no return value specified for UpdateDomain") + } + + var r0 auth.Domain + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, string, auth.DomainReq) (auth.Domain, error)); ok { + return rf(ctx, token, id, d) + } + if rf, ok := ret.Get(0).(func(context.Context, string, string, auth.DomainReq) auth.Domain); ok { + r0 = rf(ctx, token, id, d) + } else { + r0 = ret.Get(0).(auth.Domain) + } + + if rf, ok := ret.Get(1).(func(context.Context, string, string, auth.DomainReq) error); ok { + r1 = rf(ctx, token, id, d) + } else { + r1 = ret.Error(1) + } + + return r0, r1 } -func (m *Service) ListPermissions(ctx context.Context, in *magistrala.ListPermissionsReq, opts ...grpc.CallOption) (*magistrala.ListPermissionsRes, error) { - ret := m.Called(ctx, in) +// NewService creates a new instance of Service. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewService(t interface { + mock.TestingT + Cleanup(func()) +}) *Service { + mock := &Service{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) - return ret.Get(0).(*magistrala.ListPermissionsRes), ret.Error(1) + return mock } diff --git a/auth/postgres/domains.go b/auth/postgres/domains.go index b0e5556525..b3fe875668 100644 --- a/auth/postgres/domains.go +++ b/auth/postgres/domains.go @@ -40,7 +40,7 @@ func (repo domainRepo) Save(ctx context.Context, d auth.Domain) (ad auth.Domain, VALUES (:id, :name, :tags, :alias, :metadata, :created_at, :updated_at, :updated_by, :created_by, :status) RETURNING id, name, tags, alias, metadata, created_at, updated_at, updated_by, created_by, status;` - dbd, err := toDBDomains(d) + dbd, err := toDBDomain(d) if err != nil { return auth.Domain{}, errors.Wrap(repoerr.ErrCreateEntity, repoerr.ErrRollbackTx) } @@ -74,22 +74,26 @@ func (repo domainRepo) RetrieveByID(ctx context.Context, id string) (auth.Domain ID: id, } - row, err := repo.db.NamedQueryContext(ctx, q, dbdp) + rows, err := repo.db.NamedQueryContext(ctx, q, dbdp) if err != nil { - if err == sql.ErrNoRows { - return auth.Domain{}, errors.Wrap(errors.ErrNotFound, err) - } - return auth.Domain{}, errors.Wrap(errors.ErrViewEntity, err) + return auth.Domain{}, postgres.HandleError(repoerr.ErrViewEntity, err) } + defer rows.Close() - defer row.Close() - row.Next() dbd := dbDomain{} - if err := row.StructScan(&dbd); err != nil { - return auth.Domain{}, errors.Wrap(errors.ErrNotFound, err) - } + if rows.Next() { + if err = rows.StructScan(&dbd); err != nil { + return auth.Domain{}, postgres.HandleError(repoerr.ErrViewEntity, err) + } + + domain, err := toDomain(dbd) + if err != nil { + return auth.Domain{}, errors.Wrap(repoerr.ErrFailedOpDB, err) + } - return toDomain(dbd) + return domain, nil + } + return auth.Domain{}, repoerr.ErrNotFound } func (repo domainRepo) RetrievePermissions(ctx context.Context, subject, id string) ([]string, error) { @@ -131,9 +135,6 @@ func (repo domainRepo) RetrieveAllByIDs(ctx context.Context, pm auth.Page) (auth if err != nil { return auth.DomainsPage{}, errors.Wrap(repoerr.ErrFailedOpDB, err) } - if query == "" { - return auth.DomainsPage{}, nil - } q = `SELECT d.id as id, d.name as name, d.tags as tags, d.alias as alias, d.metadata as metadata, d.created_at as created_at, d.updated_at as updated_at, d.updated_by as updated_by, d.created_by as created_by, d.status as status FROM domains d` @@ -179,9 +180,6 @@ func (repo domainRepo) ListDomains(ctx context.Context, pm auth.Page) (auth.Doma if err != nil { return auth.DomainsPage{}, errors.Wrap(repoerr.ErrFailedOpDB, err) } - if query == "" { - return auth.DomainsPage{}, nil - } q = `SELECT d.id as id, d.name as name, d.tags as tags, d.alias as alias, d.metadata as metadata, d.created_at as created_at, d.updated_at as updated_at, d.updated_by as updated_by, d.created_by as created_by, d.status as status, pc.relation as relation FROM domains as d @@ -269,7 +267,7 @@ func (repo domainRepo) Update(ctx context.Context, id, userID string, dr auth.Do RETURNING id, name, tags, alias, metadata, created_at, updated_at, updated_by, created_by, status;`, upq, ws) - dbd, err := toDBDomains(d) + dbd, err := toDBDomain(d) if err != nil { return auth.Domain{}, errors.Wrap(errors.ErrUpdateEntity, err) } @@ -295,18 +293,15 @@ func (repo domainRepo) Update(ctx context.Context, id, userID string, dr auth.Do // Delete delete domain from database. func (repo domainRepo) Delete(ctx context.Context, id string) error { - q := fmt.Sprintf(` - DELETE FROM - domains - WHERE - id = '%s' - ;`, id) + q := "DELETE FROM domains WHERE id = $1;" - row, err := repo.db.NamedQueryContext(ctx, q, nil) + res, err := repo.db.ExecContext(ctx, q, id) if err != nil { return postgres.HandleError(repoerr.ErrRemoveEntity, err) } - defer row.Close() + if rows, _ := res.RowsAffected(); rows == 0 { + return repoerr.ErrNotFound + } return nil } @@ -349,7 +344,7 @@ func (repo domainRepo) CheckPolicy(ctx context.Context, pc auth.Policy) error { defer row.Close() row.Next() if err := row.StructScan(&dbpc); err != nil { - return err + return errors.Wrap(repoerr.ErrNotFound, err) } return nil } @@ -421,7 +416,7 @@ type dbDomain struct { UpdatedAt sql.NullTime `db:"updated_at,omitempty"` } -func toDBDomains(d auth.Domain) (dbDomain, error) { +func toDBDomain(d auth.Domain) (dbDomain, error) { data := []byte("{}") if len(d.Metadata) > 0 { b, err := json.Marshal(d.Metadata) diff --git a/auth/postgres/domains_test.go b/auth/postgres/domains_test.go index 32c2a69b8f..4ecf721854 100644 --- a/auth/postgres/domains_test.go +++ b/auth/postgres/domains_test.go @@ -7,11 +7,25 @@ import ( "context" "fmt" "testing" + "time" "github.com/absmach/magistrala/auth" "github.com/absmach/magistrala/auth/postgres" + "github.com/absmach/magistrala/internal/testsutil" + "github.com/absmach/magistrala/pkg/clients" "github.com/absmach/magistrala/pkg/errors" + repoerr "github.com/absmach/magistrala/pkg/errors/repository" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +const ( + inValid = "invalid" +) + +var ( + domainID = testsutil.GenerateUUID(&testing.T{}) + userID = testsutil.GenerateUUID(&testing.T{}) ) func TestAddPolicyCopy(t *testing.T) { @@ -76,3 +90,1061 @@ func TestDeletePolicyCopy(t *testing.T) { assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.err, err)) } } + +func TestSave(t *testing.T) { + t.Cleanup(func() { + _, err := db.Exec("DELETE FROM domains") + require.Nil(t, err, fmt.Sprintf("clean domains unexpected error: %s", err)) + }) + + repo := postgres.NewDomainRepository(database) + + cases := []struct { + desc string + domain auth.Domain + err error + }{ + { + desc: "add new domain with all fields successfully", + domain: auth.Domain{ + ID: domainID, + Name: "test", + Alias: "test", + Tags: []string{"test"}, + Metadata: map[string]interface{}{ + "test": "test", + }, + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + CreatedBy: userID, + UpdatedBy: userID, + Status: auth.EnabledStatus, + }, + err: nil, + }, + { + desc: "add the same domain again", + domain: auth.Domain{ + ID: domainID, + Name: "test", + Alias: "test", + Tags: []string{"test"}, + Metadata: map[string]interface{}{ + "test": "test", + }, + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + CreatedBy: userID, + UpdatedBy: userID, + Status: auth.EnabledStatus, + }, + err: repoerr.ErrConflict, + }, + { + desc: "add domain with empty ID", + domain: auth.Domain{ + ID: "", + Name: "test1", + Alias: "test1", + Tags: []string{"test"}, + Metadata: map[string]interface{}{ + "test": "test", + }, + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + CreatedBy: userID, + UpdatedBy: userID, + Status: auth.EnabledStatus, + }, + err: nil, + }, + { + desc: "add domain with malformed metadata", + domain: auth.Domain{ + ID: domainID, + Name: "test1", + Alias: "test1", + Tags: []string{"test"}, + Metadata: map[string]interface{}{ + "key": make(chan int), + }, + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + CreatedBy: userID, + UpdatedBy: userID, + Status: auth.EnabledStatus, + }, + err: errors.ErrCreateEntity, + }, + } + + for _, tc := range cases { + _, err := repo.Save(context.Background(), tc.domain) + { + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) + } + } +} + +func TestRetrieveByID(t *testing.T) { + t.Cleanup(func() { + _, err := db.Exec("DELETE FROM domains") + require.Nil(t, err, fmt.Sprintf("clean domains unexpected error: %s", err)) + }) + + repo := postgres.NewDomainRepository(database) + + domain := auth.Domain{ + ID: domainID, + Name: "test", + Alias: "test", + Tags: []string{"test"}, + Metadata: map[string]interface{}{ + "test": "test", + }, + CreatedBy: userID, + UpdatedBy: userID, + Status: auth.EnabledStatus, + } + + _, err := repo.Save(context.Background(), domain) + require.Nil(t, err, fmt.Sprintf("failed to save client %s", domain.ID)) + + cases := []struct { + desc string + domainID string + response auth.Domain + err error + }{ + { + desc: "retrieve existing client", + domainID: domain.ID, + response: domain, + err: nil, + }, + { + desc: "retrieve non-existing client", + domainID: inValid, + response: auth.Domain{}, + err: errors.ErrNotFound, + }, + { + desc: "retrieve with empty client id", + domainID: "", + response: auth.Domain{}, + err: errors.ErrNotFound, + }, + } + + for _, tc := range cases { + d, err := repo.RetrieveByID(context.Background(), tc.domainID) + assert.Equal(t, tc.response, d, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.response, d)) + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.err, err)) + } +} + +func TestRetreivePermissions(t *testing.T) { + t.Cleanup(func() { + _, err := db.Exec("DELETE FROM domains") + require.Nil(t, err, fmt.Sprintf("clean domains unexpected error: %s", err)) + _, err = db.Exec("DELETE FROM policies") + require.Nil(t, err, fmt.Sprintf("clean policies unexpected error: %s", err)) + }) + + repo := postgres.NewDomainRepository(database) + + domain := auth.Domain{ + ID: domainID, + Name: "test", + Alias: "test", + Tags: []string{"test"}, + Metadata: map[string]interface{}{ + "test": "test", + }, + CreatedBy: userID, + UpdatedBy: userID, + Status: auth.EnabledStatus, + Permission: "admin", + } + + policy := auth.Policy{ + SubjectType: auth.UserType, + SubjectID: userID, + SubjectRelation: "admin", + Relation: "admin", + ObjectType: auth.DomainType, + ObjectID: domainID, + } + + _, err := repo.Save(context.Background(), domain) + require.Nil(t, err, fmt.Sprintf("failed to save domain %s", domain.ID)) + + err = repo.SavePolicies(context.Background(), policy) + require.Nil(t, err, fmt.Sprintf("failed to save policy %s", policy.SubjectID)) + + cases := []struct { + desc string + domainID string + policySubject string + response []string + err error + }{ + { + desc: "retrieve existing permissions with valid domaiinID and policySubject", + domainID: domain.ID, + policySubject: userID, + response: []string{"admin"}, + err: nil, + }, + { + desc: "retreieve permissions with invalid domainID", + domainID: inValid, + policySubject: userID, + response: []string{}, + err: nil, + }, + { + desc: "retreieve permissions with invalid policySubject", + domainID: domain.ID, + policySubject: inValid, + response: []string{}, + err: nil, + }, + } + + for _, tc := range cases { + d, err := repo.RetrievePermissions(context.Background(), tc.policySubject, tc.domainID) + assert.Equal(t, tc.response, d, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.response, d)) + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.err, err)) + } +} + +func TestRetrieveAllByIDs(t *testing.T) { + t.Cleanup(func() { + _, err := db.Exec("DELETE FROM domains") + require.Nil(t, err, fmt.Sprintf("clean domains unexpected error: %s", err)) + }) + + repo := postgres.NewDomainRepository(database) + + items := []auth.Domain{} + for i := 0; i < 10; i++ { + domain := auth.Domain{ + ID: testsutil.GenerateUUID(t), + Name: fmt.Sprintf(`"test%d"`, i), + Alias: fmt.Sprintf(`"test%d"`, i), + Tags: []string{"test"}, + Metadata: map[string]interface{}{ + "test": "test", + }, + CreatedBy: userID, + UpdatedBy: userID, + Status: auth.EnabledStatus, + } + if i%5 == 0 { + domain.Status = auth.DisabledStatus + domain.Tags = []string{"test", "admin"} + domain.Metadata = map[string]interface{}{ + "test1": "test1", + } + } + _, err := repo.Save(context.Background(), domain) + require.Nil(t, err, fmt.Sprintf("save domain unexpected error: %s", err)) + items = append(items, domain) + } + + cases := []struct { + desc string + pm auth.Page + response auth.DomainsPage + err error + }{ + { + desc: "retrieve by ids successfully", + pm: auth.Page{ + Offset: 0, + Limit: 10, + IDs: []string{items[1].ID, items[2].ID}, + }, + response: auth.DomainsPage{ + Page: auth.Page{ + Total: 2, + Offset: 0, + Limit: 10, + IDs: []string{items[1].ID, items[2].ID}, + }, + Domains: []auth.Domain{items[1], items[2]}, + }, + err: nil, + }, + { + desc: "retrieve by ids with empty ids", + pm: auth.Page{ + Offset: 0, + Limit: 10, + IDs: []string{}, + }, + response: auth.DomainsPage{ + Page: auth.Page{ + Total: 0, + Offset: 0, + Limit: 0, + }, + }, + err: nil, + }, + { + desc: "retrieve by ids with invalid ids", + pm: auth.Page{ + Offset: 0, + Limit: 10, + IDs: []string{inValid}, + }, + response: auth.DomainsPage{ + Page: auth.Page{ + Total: 0, + Offset: 0, + Limit: 10, + IDs: []string{inValid}, + }, + }, + err: nil, + }, + { + desc: "retrieve by ids and status", + pm: auth.Page{ + Offset: 0, + Limit: 10, + IDs: []string{items[0].ID, items[1].ID}, + Status: auth.DisabledStatus, + }, + response: auth.DomainsPage{ + Page: auth.Page{ + Total: 1, + Offset: 0, + Limit: 10, + Status: auth.DisabledStatus, + IDs: []string{items[0].ID, items[1].ID}, + }, + Domains: []auth.Domain{items[0]}, + }, + }, + { + desc: "retrieve by ids and status with invalid status", + pm: auth.Page{ + Offset: 0, + Limit: 10, + IDs: []string{items[0].ID, items[1].ID}, + Status: 5, + }, + response: auth.DomainsPage{ + Page: auth.Page{ + Total: 2, + Offset: 0, + Limit: 10, + Status: 5, + IDs: []string{items[0].ID, items[1].ID}, + }, + Domains: []auth.Domain{items[0], items[1]}, + }, + }, + { + desc: "retrieve by ids and tags", + pm: auth.Page{ + Offset: 0, + Limit: 10, + IDs: []string{items[0].ID, items[1].ID}, + Tag: "test", + }, + response: auth.DomainsPage{ + Page: auth.Page{ + Total: 1, + Offset: 0, + Limit: 10, + Tag: "test", + IDs: []string{items[0].ID, items[1].ID}, + }, + Domains: []auth.Domain{items[1]}, + }, + }, + { + desc: " retrieve by ids and metadata", + pm: auth.Page{ + Offset: 0, + Limit: 10, + IDs: []string{items[1].ID, items[2].ID}, + Metadata: map[string]interface{}{ + "test": "test", + }, + Status: auth.EnabledStatus, + }, + response: auth.DomainsPage{ + Page: auth.Page{ + Total: 2, + Offset: 0, + Limit: 10, + IDs: []string{items[1].ID, items[2].ID}, + Metadata: map[string]interface{}{ + "test": "test", + }, + Status: auth.EnabledStatus, + }, + Domains: items[1:3], + }, + }, + { + desc: "retrieve by ids and metadata with invalid metadata", + pm: auth.Page{ + Offset: 0, + Limit: 10, + IDs: []string{items[1].ID, items[2].ID}, + Metadata: map[string]interface{}{ + "test1": "test1", + }, + Status: auth.EnabledStatus, + }, + response: auth.DomainsPage{ + Page: auth.Page{ + Total: 0, + Offset: 0, + Limit: 10, + IDs: []string{items[1].ID, items[2].ID}, + Metadata: map[string]interface{}{ + "test1": "test1", + }, + Status: auth.EnabledStatus, + }, + }, + }, + { + desc: "retrieve by ids and malfomed metadata", + pm: auth.Page{ + Offset: 0, + Limit: 10, + IDs: []string{items[1].ID, items[2].ID}, + Metadata: map[string]interface{}{ + "key": make(chan int), + }, + Status: auth.EnabledStatus, + }, + response: auth.DomainsPage{ + Page: auth.Page{}, + }, + err: errors.ErrViewEntity, + }, + { + desc: "retrieve all by ids and id", + pm: auth.Page{ + Offset: 0, + Limit: 10, + ID: items[1].ID, + IDs: []string{items[1].ID, items[2].ID}, + }, + response: auth.DomainsPage{ + Page: auth.Page{ + Total: 1, + Offset: 0, + Limit: 10, + ID: items[1].ID, + IDs: []string{items[1].ID, items[2].ID}, + }, + Domains: []auth.Domain{items[1]}, + }, + }, + { + desc: "retrieve all by ids and id with invalid id", + pm: auth.Page{ + Offset: 0, + Limit: 10, + ID: inValid, + IDs: []string{items[1].ID, items[2].ID}, + }, + response: auth.DomainsPage{ + Page: auth.Page{ + Total: 0, + Offset: 0, + Limit: 10, + ID: inValid, + IDs: []string{items[1].ID, items[2].ID}, + }, + }, + }, + { + desc: "retrieve all by ids and name", + pm: auth.Page{ + Offset: 0, + Limit: 10, + Name: items[1].Name, + IDs: []string{items[1].ID, items[2].ID}, + }, + response: auth.DomainsPage{ + Page: auth.Page{ + Total: 1, + Offset: 0, + Limit: 10, + Name: items[1].Name, + IDs: []string{items[1].ID, items[2].ID}, + }, + Domains: []auth.Domain{items[1]}, + }, + }, + { + desc: "retrieve all by ids with empty page", + pm: auth.Page{}, + response: auth.DomainsPage{}, + }, + } + + for _, tc := range cases { + d, err := repo.RetrieveAllByIDs(context.Background(), tc.pm) + assert.Equal(t, tc.response, d, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.response, d)) + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.err, err)) + } +} + +func TestListDomains(t *testing.T) { + t.Cleanup(func() { + _, err := db.Exec("DELETE FROM domains") + require.Nil(t, err, fmt.Sprintf("clean domains unexpected error: %s", err)) + }) + + repo := postgres.NewDomainRepository(database) + + items := []auth.Domain{} + rDomains := []auth.Domain{} + policies := []auth.Policy{} + for i := 0; i < 10; i++ { + domain := auth.Domain{ + ID: testsutil.GenerateUUID(t), + Name: fmt.Sprintf(`"test%d"`, i), + Alias: fmt.Sprintf(`"test%d"`, i), + Tags: []string{"test"}, + Metadata: map[string]interface{}{ + "test": "test", + }, + CreatedBy: userID, + UpdatedBy: userID, + Status: auth.EnabledStatus, + } + if i%5 == 0 { + domain.Status = auth.DisabledStatus + domain.Tags = []string{"test", "admin"} + domain.Metadata = map[string]interface{}{ + "test1": "test1", + } + } + policy := auth.Policy{ + SubjectType: auth.UserType, + SubjectID: userID, + SubjectRelation: auth.AdministratorRelation, + Relation: auth.DomainRelation, + ObjectType: auth.DomainType, + ObjectID: domain.ID, + } + _, err := repo.Save(context.Background(), domain) + require.Nil(t, err, fmt.Sprintf("save domain unexpected error: %s", err)) + items = append(items, domain) + policies = append(policies, policy) + rDomain := domain + rDomain.Permission = "domain" + rDomains = append(rDomains, rDomain) + } + + err := repo.SavePolicies(context.Background(), policies...) + require.Nil(t, err, fmt.Sprintf("failed to save policies %s", policies)) + + cases := []struct { + desc string + pm auth.Page + response auth.DomainsPage + err error + }{ + { + desc: "list all domains successfully", + pm: auth.Page{ + Offset: 0, + Limit: 10, + Status: auth.AllStatus, + }, + response: auth.DomainsPage{ + Page: auth.Page{ + Total: 10, + Offset: 0, + Limit: 10, + Status: auth.AllStatus, + }, + Domains: items, + }, + err: nil, + }, + { + desc: "list domains with empty page", + pm: auth.Page{ + Offset: 0, + Limit: 0, + }, + response: auth.DomainsPage{ + Page: auth.Page{ + Total: 8, + Offset: 0, + Limit: 0, + }, + }, + err: nil, + }, + { + desc: "list domains with enabled status", + pm: auth.Page{ + Offset: 0, + Limit: 10, + Status: auth.EnabledStatus, + }, + response: auth.DomainsPage{ + Page: auth.Page{ + Total: 8, + Offset: 0, + Limit: 10, + Status: auth.EnabledStatus, + }, + Domains: []auth.Domain{items[1], items[2], items[3], items[4], items[6], items[7], items[8], items[9]}, + }, + err: nil, + }, + { + desc: "list domains with disabled status", + pm: auth.Page{ + Offset: 0, + Limit: 10, + Status: auth.DisabledStatus, + }, + response: auth.DomainsPage{ + Page: auth.Page{ + Total: 2, + Offset: 0, + Limit: 10, + Status: auth.DisabledStatus, + }, + Domains: []auth.Domain{items[0], items[5]}, + }, + err: nil, + }, + { + desc: "list domains with subject ID", + pm: auth.Page{ + Offset: 0, + Limit: 10, + SubjectID: userID, + Status: auth.AllStatus, + }, + response: auth.DomainsPage{ + Page: auth.Page{ + Total: 10, + Offset: 0, + Limit: 10, + Status: auth.AllStatus, + SubjectID: userID, + }, + Domains: rDomains, + }, + err: nil, + }, + { + desc: "list domains with subject ID and status", + pm: auth.Page{ + Offset: 0, + Limit: 10, + SubjectID: userID, + Status: auth.EnabledStatus, + }, + response: auth.DomainsPage{ + Page: auth.Page{ + Total: 8, + Offset: 0, + Limit: 10, + Status: auth.EnabledStatus, + SubjectID: userID, + }, + Domains: []auth.Domain{rDomains[1], rDomains[2], rDomains[3], rDomains[4], rDomains[6], rDomains[7], rDomains[8], rDomains[9]}, + }, + err: nil, + }, + { + desc: "list domains with subject Id and permission", + pm: auth.Page{ + Offset: 0, + Limit: 10, + SubjectID: userID, + Permission: "domain", + Status: auth.AllStatus, + }, + response: auth.DomainsPage{ + Page: auth.Page{ + Total: 10, + Offset: 0, + Limit: 10, + Status: auth.AllStatus, + SubjectID: userID, + Permission: "domain", + }, + Domains: rDomains, + }, + err: nil, + }, + { + desc: "list domains with subject id and tags", + pm: auth.Page{ + Offset: 0, + Limit: 10, + SubjectID: userID, + Tag: "test", + Status: auth.AllStatus, + }, + response: auth.DomainsPage{ + Page: auth.Page{ + Total: 10, + Offset: 0, + Limit: 10, + Status: auth.AllStatus, + SubjectID: userID, + Tag: "test", + }, + Domains: rDomains, + }, + err: nil, + }, + { + desc: "list domains with subject id and metadata", + pm: auth.Page{ + Offset: 0, + Limit: 10, + SubjectID: userID, + Metadata: map[string]interface{}{ + "test": "test", + }, + Status: auth.AllStatus, + }, + response: auth.DomainsPage{ + Page: auth.Page{ + Total: 8, + Offset: 0, + Limit: 10, + Status: auth.AllStatus, + SubjectID: userID, + Metadata: map[string]interface{}{ + "test": "test", + }, + }, + Domains: []auth.Domain{rDomains[1], rDomains[2], rDomains[3], rDomains[4], rDomains[6], rDomains[7], rDomains[8], rDomains[9]}, + }, + }, + { + desc: "list domains with subject id and metadata with malforned metadata", + pm: auth.Page{ + Offset: 0, + Limit: 10, + SubjectID: userID, + Metadata: map[string]interface{}{ + "key": make(chan int), + }, + Status: auth.AllStatus, + }, + response: auth.DomainsPage{ + Page: auth.Page{}, + }, + err: errors.ErrViewEntity, + }, + } + + for _, tc := range cases { + d, err := repo.ListDomains(context.Background(), tc.pm) + assert.Equal(t, tc.response, d, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.response, d)) + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.err, err)) + } +} + +func TestUpdate(t *testing.T) { + t.Cleanup(func() { + _, err := db.Exec("DELETE FROM domains") + require.Nil(t, err, fmt.Sprintf("clean domains unexpected error: %s", err)) + }) + + updatedName := "test1" + updatedMetadata := clients.Metadata{ + "test1": "test1", + } + updatedTags := []string{"test1"} + updatedStatus := auth.DisabledStatus + updatedAlias := "test1" + + repo := postgres.NewDomainRepository(database) + + domain := auth.Domain{ + ID: domainID, + Name: "test", + Alias: "test", + Tags: []string{"test"}, + Metadata: map[string]interface{}{ + "test": "test", + }, + CreatedBy: userID, + UpdatedBy: userID, + Status: auth.EnabledStatus, + } + + _, err := repo.Save(context.Background(), domain) + require.Nil(t, err, fmt.Sprintf("failed to save client %s", domain.ID)) + + cases := []struct { + desc string + domainID string + d auth.DomainReq + response auth.Domain + err error + }{ + { + desc: "update existing domain name and metadata", + domainID: domain.ID, + d: auth.DomainReq{ + Name: &updatedName, + Metadata: &updatedMetadata, + }, + response: auth.Domain{ + ID: domainID, + Name: "test1", + Alias: "test", + Tags: []string{"test"}, + Metadata: map[string]interface{}{ + "test1": "test1", + }, + CreatedBy: userID, + UpdatedBy: userID, + Status: auth.EnabledStatus, + UpdatedAt: time.Now(), + }, + err: nil, + }, + { + desc: "update existing domain name, metadata, tags, status and alias", + domainID: domain.ID, + d: auth.DomainReq{ + Name: &updatedName, + Metadata: &updatedMetadata, + Tags: &updatedTags, + Status: &updatedStatus, + Alias: &updatedAlias, + }, + response: auth.Domain{ + ID: domainID, + Name: "test1", + Alias: "test1", + Tags: []string{"test1"}, + Metadata: map[string]interface{}{ + "test1": "test1", + }, + CreatedBy: userID, + UpdatedBy: userID, + Status: auth.DisabledStatus, + UpdatedAt: time.Now(), + }, + err: nil, + }, + { + desc: "update non-existing domain", + domainID: inValid, + d: auth.DomainReq{ + Name: &updatedName, + Metadata: &updatedMetadata, + }, + response: auth.Domain{}, + err: repoerr.ErrFailedOpDB, + }, + { + desc: "update domain with empty ID", + domainID: "", + d: auth.DomainReq{ + Name: &updatedName, + Metadata: &updatedMetadata, + }, + response: auth.Domain{}, + err: repoerr.ErrFailedOpDB, + }, + { + desc: "update domain with malformed metadata", + domainID: domainID, + d: auth.DomainReq{ + Name: &updatedName, + Metadata: &clients.Metadata{"key": make(chan int)}, + }, + response: auth.Domain{}, + err: errors.ErrUpdateEntity, + }, + } + + for _, tc := range cases { + d, err := repo.Update(context.Background(), tc.domainID, userID, tc.d) + d.UpdatedAt = tc.response.UpdatedAt + assert.Equal(t, tc.response, d, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.response, d)) + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) + } +} + +func TestDelete(t *testing.T) { + t.Cleanup(func() { + _, err := db.Exec("DELETE FROM domains") + require.Nil(t, err, fmt.Sprintf("clean domains unexpected error: %s", err)) + }) + + repo := postgres.NewDomainRepository(database) + + domain := auth.Domain{ + ID: domainID, + Name: "test", + Alias: "test", + Tags: []string{"test"}, + Metadata: map[string]interface{}{ + "test": "test", + }, + CreatedBy: userID, + UpdatedBy: userID, + Status: auth.EnabledStatus, + } + + _, err := repo.Save(context.Background(), domain) + require.Nil(t, err, fmt.Sprintf("failed to save client %s", domain.ID)) + + cases := []struct { + desc string + domainID string + err error + }{ + { + desc: "delete existing domain", + domainID: domain.ID, + err: nil, + }, + { + desc: "delete non-existing domain", + domainID: inValid, + err: repoerr.ErrNotFound, + }, + { + desc: "delete domain with empty ID", + domainID: "", + err: repoerr.ErrNotFound, + }, + } + + for _, tc := range cases { + err := repo.Delete(context.Background(), tc.domainID) + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) + } +} + +func TestCheckPolicy(t *testing.T) { + t.Cleanup(func() { + _, err := db.Exec("DELETE FROM policies") + require.Nil(t, err, fmt.Sprintf("clean policies unexpected error: %s", err)) + }) + + repo := postgres.NewDomainRepository(database) + + policy := auth.Policy{ + SubjectType: auth.UserType, + SubjectID: userID, + SubjectRelation: auth.AdministratorRelation, + Relation: auth.DomainRelation, + ObjectType: auth.DomainType, + ObjectID: domainID, + } + + err := repo.SavePolicies(context.Background(), policy) + require.Nil(t, err, fmt.Sprintf("failed to save policy %s", policy.SubjectID)) + + cases := []struct { + desc string + policy auth.Policy + err error + }{ + { + desc: "check valid policy", + policy: policy, + err: nil, + }, + { + desc: "check policy with invalid subject type", + policy: auth.Policy{ + SubjectType: inValid, + SubjectID: userID, + SubjectRelation: auth.AdministratorRelation, + Relation: auth.DomainRelation, + ObjectType: auth.DomainType, + ObjectID: domainID, + }, + err: repoerr.ErrNotFound, + }, + { + desc: "check policy with invalid subject id", + policy: auth.Policy{ + SubjectType: auth.UserType, + SubjectID: inValid, + SubjectRelation: auth.AdministratorRelation, + Relation: auth.DomainRelation, + ObjectType: auth.DomainType, + ObjectID: domainID, + }, + err: repoerr.ErrNotFound, + }, + { + desc: "check policy with invalid subject relation", + policy: auth.Policy{ + SubjectType: auth.UserType, + SubjectID: userID, + SubjectRelation: inValid, + Relation: auth.DomainRelation, + ObjectType: auth.DomainType, + ObjectID: domainID, + }, + err: repoerr.ErrNotFound, + }, + { + desc: "check policy with invalid relation", + policy: auth.Policy{ + SubjectType: auth.UserType, + SubjectID: userID, + SubjectRelation: auth.AdministratorRelation, + Relation: inValid, + ObjectType: auth.DomainType, + ObjectID: domainID, + }, + err: repoerr.ErrNotFound, + }, + { + desc: "check policy with invalid object type", + policy: auth.Policy{ + SubjectType: auth.UserType, + SubjectID: userID, + SubjectRelation: auth.AdministratorRelation, + Relation: auth.DomainRelation, + ObjectType: inValid, + ObjectID: domainID, + }, + err: repoerr.ErrNotFound, + }, + { + desc: "check policy with invalid object id", + policy: auth.Policy{ + SubjectType: auth.UserType, + SubjectID: userID, + SubjectRelation: auth.AdministratorRelation, + Relation: auth.DomainRelation, + ObjectType: auth.DomainType, + ObjectID: inValid, + }, + err: repoerr.ErrNotFound, + }, + } + for _, tc := range cases { + err := repo.CheckPolicy(context.Background(), tc.policy) + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.err, err)) + } +} diff --git a/auth/service.go b/auth/service.go index a277a0ebea..8a1700a133 100644 --- a/auth/service.go +++ b/auth/service.go @@ -39,6 +39,9 @@ var ( // ErrFailedToRetrieveChildren failed to retrieve groups. ErrFailedToRetrieveChildren = errors.New("failed to retrieve all groups") + // ErrExpiry indicates that the token is expired. + ErrExpiry = errors.New("token is expired") + errIssueUser = errors.New("failed to issue new login key") errIssueTmp = errors.New("failed to issue new temporary key") errRevoke = errors.New("failed to remove key") @@ -76,6 +79,8 @@ type Authn interface { // implementation, and all of its decorators (e.g. logging & metrics). // Token is a string value of the actual Key and is used to authenticate // an Auth service request. + +//go:generate mockery --name Service --output=./mocks --filename service.go --quiet --note "Copyright (c) Abstract Machines" type Service interface { Authn Authz @@ -151,9 +156,9 @@ func (svc service) RetrieveKey(ctx context.Context, token, id string) (Key, erro func (svc service) Identify(ctx context.Context, token string) (Key, error) { key, err := svc.tokenizer.Parse(token) - if err == ErrAPIKeyExpired { + if errors.Contains(err, ErrExpiry) { err = svc.keys.Remove(ctx, key.Issuer, key.ID) - return Key{}, errors.Wrap(ErrAPIKeyExpired, err) + return Key{}, errors.Wrap(ErrKeyExpired, err) } if err != nil { return Key{}, errors.Wrap(svcerr.ErrAuthentication, errors.Wrap(errIdentify, err)) diff --git a/auth/service_test.go b/auth/service_test.go index 3125474f23..c8a56f52eb 100644 --- a/auth/service_test.go +++ b/auth/service_test.go @@ -13,11 +13,11 @@ import ( "github.com/absmach/magistrala/auth/jwt" "github.com/absmach/magistrala/auth/mocks" "github.com/absmach/magistrala/pkg/errors" + repoerr "github.com/absmach/magistrala/pkg/errors/repository" svcerr "github.com/absmach/magistrala/pkg/errors/service" "github.com/absmach/magistrala/pkg/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" ) const ( @@ -32,18 +32,41 @@ const ( loginDuration = 30 * time.Minute refreshDuration = 24 * time.Hour invalidDuration = 7 * 24 * time.Hour + validID = "d4ebb847-5d0e-4e46-bdd9-b6aceaaa3a22" ) var ( - errIssueUser = errors.New("failed to issue new login key") - // ErrExpiry indicates that the token is expired. - ErrExpiry = errors.New("token is expired") + errIssueUser = errors.New("failed to issue new login key") + errCreateDomainPolicy = errors.New("failed to create domain policy") + errRetrieve = errors.New("failed to retrieve key data") + ErrExpiry = errors.New("token is expired") + errRollbackPolicy = errors.New("failed to rollback policy") + errAddPolicies = errors.New("failed to add policies") + errPlatform = errors.New("invalid platform id") + inValidToken = "invalid" + inValid = "invalid" + valid = "valid" + domain = auth.Domain{ + ID: validID, + Name: groupName, + Tags: []string{"tag1", "tag2"}, + Alias: "test", + Permission: auth.AdminPermission, + CreatedBy: validID, + UpdatedBy: validID, + } +) + +var ( + krepo *mocks.KeyRepository + prepo *mocks.PolicyAgent + drepo *mocks.DomainsRepository ) -func newService() (auth.Service, *mocks.KeyRepository, string, *mocks.PolicyAgent) { - krepo := new(mocks.KeyRepository) - prepo := new(mocks.PolicyAgent) - drepo := new(mocks.DomainsRepository) +func newService() (auth.Service, string) { + krepo = new(mocks.KeyRepository) + prepo = new(mocks.PolicyAgent) + drepo = new(mocks.DomainsRepository) idProvider := uuid.NewMock() t := jwt.New([]byte(secret)) @@ -57,17 +80,70 @@ func newService() (auth.Service, *mocks.KeyRepository, string, *mocks.PolicyAgen } token, _ := t.Issue(key) - return auth.New(krepo, drepo, idProvider, t, prepo, loginDuration, refreshDuration, invalidDuration), krepo, token, prepo + return auth.New(krepo, drepo, idProvider, t, prepo, loginDuration, refreshDuration, invalidDuration), token } func TestIssue(t *testing.T) { - svc, krepo, accessToken, _ := newService() + svc, accessToken := newService() + + n := jwt.New([]byte(secret)) + apikey := auth.Key{ + IssuedAt: time.Now(), + ExpiresAt: time.Now().Add(refreshDuration), + Subject: id, + Type: auth.APIKey, + User: email, + Domain: groupName, + } + apiToken, err := n.Issue(apikey) + assert.Nil(t, err, fmt.Sprintf("Issuing API key expected to succeed: %s", err)) + + refreshkey := auth.Key{ + IssuedAt: time.Now(), + ExpiresAt: time.Now().Add(refreshDuration), + Subject: id, + Type: auth.RefreshKey, + User: email, + Domain: groupName, + } + refreshToken, err := n.Issue(refreshkey) + assert.Nil(t, err, fmt.Sprintf("Issuing refresh key expected to succeed: %s", err)) cases := []struct { desc string key auth.Key token string err error + }{ + { + desc: "issue recovery key", + key: auth.Key{ + Type: auth.RecoveryKey, + IssuedAt: time.Now(), + }, + token: "", + err: nil, + }, + } + + for _, tc := range cases { + _, err := svc.Issue(context.Background(), tc.token, tc.key) + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s expected %s got %s\n", tc.desc, tc.err, err)) + } + + cases2 := []struct { + desc string + key auth.Key + saveResponse auth.Key + retrieveByIDResponse auth.Domain + token string + saveErr error + checkPolicyRequest auth.PolicyReq + checkPolicyRequest1 auth.PolicyReq + checkPolicyErr error + checkPolicyErr1 error + retreiveByIDErr error + err error }{ { desc: "issue login key", @@ -75,9 +151,172 @@ func TestIssue(t *testing.T) { Type: auth.AccessKey, IssuedAt: time.Now(), }, + checkPolicyRequest: auth.PolicyReq{ + Subject: "", + SubjectType: auth.UserType, + SubjectKind: "", + Object: auth.MagistralaObject, + ObjectKind: "", + ObjectType: auth.PlatformType, + Permission: auth.AdminPermission, + }, + token: accessToken, + err: nil, + }, + { + desc: "issue login key with domain", + key: auth.Key{ + Type: auth.AccessKey, + IssuedAt: time.Now(), + Domain: groupName, + }, + checkPolicyRequest: auth.PolicyReq{ + Subject: "", + SubjectType: auth.UserType, + SubjectKind: "", + Object: auth.MagistralaObject, + ObjectKind: "", + ObjectType: auth.PlatformType, + Permission: auth.AdminPermission, + }, token: accessToken, err: nil, }, + { + desc: "issue login key with failed check on platform admin", + key: auth.Key{ + Type: auth.AccessKey, + IssuedAt: time.Now(), + Domain: groupName, + }, + token: accessToken, + checkPolicyRequest: auth.PolicyReq{ + Subject: "", + SubjectType: auth.UserType, + SubjectKind: "", + Object: auth.MagistralaObject, + ObjectKind: "", + ObjectType: auth.PlatformType, + Permission: auth.AdminPermission, + }, + checkPolicyErr: errors.ErrNotFound, + retrieveByIDResponse: auth.Domain{}, + retreiveByIDErr: repoerr.ErrNotFound, + err: errors.ErrNotFound, + }, + { + desc: "issue login key with failed check on platform admin with enabled status", + key: auth.Key{ + Type: auth.AccessKey, + IssuedAt: time.Now(), + Domain: groupName, + }, + token: accessToken, + checkPolicyRequest: auth.PolicyReq{ + Subject: "", + SubjectType: auth.UserType, + SubjectKind: "", + Object: auth.MagistralaObject, + ObjectKind: "", + ObjectType: auth.PlatformType, + Permission: auth.AdminPermission, + }, + checkPolicyRequest1: auth.PolicyReq{ + Subject: "", + SubjectType: auth.UserType, + SubjectKind: "", + Object: groupName, + ObjectKind: "", + ObjectType: auth.DomainType, + Permission: auth.MembershipPermission, + }, + checkPolicyErr: svcerr.ErrAuthorization, + retrieveByIDResponse: auth.Domain{Status: auth.EnabledStatus}, + err: nil, + }, + { + desc: "issue login key with membership permission", + key: auth.Key{ + Type: auth.AccessKey, + IssuedAt: time.Now(), + Domain: groupName, + }, + token: accessToken, + checkPolicyRequest: auth.PolicyReq{ + Subject: "", + SubjectType: auth.UserType, + SubjectKind: "", + Object: auth.MagistralaObject, + ObjectKind: "", + ObjectType: auth.PlatformType, + Permission: auth.AdminPermission, + }, + checkPolicyRequest1: auth.PolicyReq{ + Subject: "", + SubjectType: auth.UserType, + SubjectKind: "", + Object: groupName, + ObjectKind: "", + ObjectType: auth.DomainType, + Permission: auth.MembershipPermission, + }, + checkPolicyErr: svcerr.ErrAuthorization, + checkPolicyErr1: nil, + retrieveByIDResponse: auth.Domain{Status: auth.EnabledStatus}, + err: nil, + }, + { + desc: "issue login key with membership permission with failed to authorize", + key: auth.Key{ + Type: auth.AccessKey, + IssuedAt: time.Now(), + Domain: groupName, + }, + token: accessToken, + checkPolicyRequest: auth.PolicyReq{ + Subject: "", + SubjectType: auth.UserType, + SubjectKind: "", + Object: auth.MagistralaObject, + ObjectKind: "", + ObjectType: auth.PlatformType, + Permission: auth.AdminPermission, + }, + checkPolicyRequest1: auth.PolicyReq{ + Subject: "", + SubjectType: auth.UserType, + SubjectKind: "", + Object: groupName, + ObjectKind: "", + ObjectType: auth.DomainType, + Permission: auth.MembershipPermission, + }, + checkPolicyErr: svcerr.ErrAuthorization, + checkPolicyErr1: svcerr.ErrAuthorization, + retrieveByIDResponse: auth.Domain{Status: auth.EnabledStatus}, + err: svcerr.ErrAuthorization, + }, + } + for _, tc := range cases2 { + repoCall := krepo.On("Save", mock.Anything, mock.Anything).Return(mock.Anything, tc.saveErr) + repoCall1 := prepo.On("CheckPolicy", mock.Anything, tc.checkPolicyRequest).Return(tc.checkPolicyErr) + repoCall2 := prepo.On("CheckPolicy", mock.Anything, tc.checkPolicyRequest1).Return(tc.checkPolicyErr1) + repoCall3 := drepo.On("RetrieveByID", mock.Anything, mock.Anything).Return(tc.retrieveByIDResponse, tc.retreiveByIDErr) + _, err := svc.Issue(context.Background(), tc.token, tc.key) + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s expected %s got %s\n", tc.desc, tc.err, err)) + repoCall.Unset() + repoCall1.Unset() + repoCall2.Unset() + repoCall3.Unset() + } + + cases3 := []struct { + desc string + key auth.Key + token string + saveErr error + err error + }{ { desc: "issue API key", key: auth.Key{ @@ -97,26 +336,149 @@ func TestIssue(t *testing.T) { err: svcerr.ErrAuthentication, }, { - desc: "issue recovery key", + desc: " issue API key with invalid key request", key: auth.Key{ - Type: auth.RecoveryKey, + Type: auth.APIKey, + IssuedAt: time.Now(), + }, + token: apiToken, + err: svcerr.ErrAuthentication, + }, + { + desc: "issue API key with failed to save", + key: auth.Key{ + Type: auth.APIKey, + IssuedAt: time.Now(), + }, + token: accessToken, + saveErr: errors.ErrNotFound, + err: errors.ErrNotFound, + }, + } + for _, tc := range cases3 { + repoCall := krepo.On("Save", mock.Anything, mock.Anything).Return(mock.Anything, tc.saveErr) + _, err := svc.Issue(context.Background(), tc.token, tc.key) + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s expected %s got %s\n", tc.desc, tc.err, err)) + repoCall.Unset() + } + + cases4 := []struct { + desc string + key auth.Key + token string + checkPolicyRequest auth.PolicyReq + checkPolicyErr error + retrieveByIDErr error + err error + }{ + { + desc: "issue refresh key", + key: auth.Key{ + Type: auth.RefreshKey, + IssuedAt: time.Now(), + }, + checkPolicyRequest: auth.PolicyReq{ + Subject: email, + SubjectType: auth.UserType, + SubjectKind: "", + Object: auth.MagistralaObject, + ObjectKind: "", + ObjectType: auth.PlatformType, + Permission: auth.AdminPermission, + }, + token: refreshToken, + err: nil, + }, + { + desc: "issue refresh token with invalid policy", + key: auth.Key{ + Type: auth.RefreshKey, + IssuedAt: time.Now(), + }, + checkPolicyRequest: auth.PolicyReq{ + Subject: email, + SubjectType: auth.UserType, + SubjectKind: "", + Object: auth.MagistralaObject, + ObjectKind: "", + ObjectType: auth.PlatformType, + Permission: auth.AdminPermission, + }, + token: refreshToken, + checkPolicyErr: svcerr.ErrAuthorization, + retrieveByIDErr: errors.ErrNotFound, + err: svcerr.ErrAuthorization, + }, + { + desc: "issue refresh key with invalid token", + key: auth.Key{ + Type: auth.RefreshKey, + IssuedAt: time.Now(), + }, + token: accessToken, + err: errIssueUser, + }, + { + desc: "issue refresh key with empty token", + key: auth.Key{ + Type: auth.RefreshKey, + IssuedAt: time.Now(), + }, + token: "", + err: errRetrieve, + }, + { + desc: "issue invitation key", + key: auth.Key{ + Type: auth.InvitationKey, IssuedAt: time.Now(), }, + checkPolicyRequest: auth.PolicyReq{ + Subject: email, + SubjectType: auth.UserType, + SubjectKind: "", + Object: auth.MagistralaObject, + ObjectKind: "", + ObjectType: auth.PlatformType, + Permission: auth.AdminPermission, + }, token: "", err: nil, }, + { + desc: "issue invitation key with invalid policy", + key: auth.Key{ + Type: auth.InvitationKey, + IssuedAt: time.Now(), + Domain: groupName, + }, + checkPolicyRequest: auth.PolicyReq{ + Subject: "", + SubjectType: auth.UserType, + SubjectKind: "", + Object: auth.MagistralaObject, + ObjectKind: "", + ObjectType: auth.PlatformType, + Permission: auth.AdminPermission, + }, + token: refreshToken, + checkPolicyErr: svcerr.ErrAuthorization, + retrieveByIDErr: errors.ErrNotFound, + err: svcerr.ErrNotFound, + }, } - - for _, tc := range cases { - repocall := krepo.On("Save", mock.Anything, mock.Anything).Return(mock.Anything, tc.err) + for _, tc := range cases4 { + repoCall := prepo.On("CheckPolicy", mock.Anything, tc.checkPolicyRequest).Return(tc.checkPolicyErr) + repoCall1 := drepo.On("RetrieveByID", mock.Anything, mock.Anything).Return(auth.Domain{}, tc.retrieveByIDErr) _, err := svc.Issue(context.Background(), tc.token, tc.key) assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s expected %s got %s\n", tc.desc, tc.err, err)) - repocall.Unset() + repoCall.Unset() + repoCall1.Unset() } } func TestRevoke(t *testing.T) { - svc, krepo, _, _ := newService() + svc, _ := newService() repocall := krepo.On("Save", mock.Anything, mock.Anything).Return(mock.Anything, errIssueUser) secret, err := svc.Issue(context.Background(), "", auth.Key{Type: auth.AccessKey, IssuedAt: time.Now(), Subject: id}) repocall.Unset() @@ -138,23 +500,26 @@ func TestRevoke(t *testing.T) { err error }{ { - desc: "revoke login key", - // id: newKey.ID, + desc: "revoke login key", token: secret.AccessToken, err: nil, }, { - desc: "revoke non-existing login key", - // id: newKey.ID, + desc: "revoke non-existing login key", token: secret.AccessToken, err: nil, }, { - desc: "revoke with empty login key", - // id: newKey.ID, + desc: "revoke with empty login key", token: "", err: svcerr.ErrAuthentication, }, + { + desc: "revoke login key with failed to remove", + id: "invalidID", + token: secret.AccessToken, + err: svcerr.ErrNotFound, + }, } for _, tc := range cases { @@ -166,7 +531,7 @@ func TestRevoke(t *testing.T) { } func TestRetrieve(t *testing.T) { - svc, krepo, _, _ := newService() + svc, _ := newService() repocall := krepo.On("Save", mock.Anything, mock.Anything).Return(mock.Anything, nil) secret, err := svc.Issue(context.Background(), "", auth.Key{Type: auth.AccessKey, IssuedAt: time.Now(), Subject: id}) assert.Nil(t, err, fmt.Sprintf("Issuing login key expected to succeed: %s", err)) @@ -200,8 +565,7 @@ func TestRetrieve(t *testing.T) { err error }{ { - desc: "retrieve login key", - // id: apiKey.ID, + desc: "retrieve login key", token: userToken.AccessToken, err: nil, }, @@ -212,20 +576,17 @@ func TestRetrieve(t *testing.T) { err: svcerr.ErrNotFound, }, { - desc: "retrieve with wrong login key", - // id: apiKey.ID, + desc: "retrieve with wrong login key", token: "wrong", err: svcerr.ErrAuthentication, }, { - desc: "retrieve with API token", - // id: apiKey.ID, + desc: "retrieve with API token", token: apiToken.AccessToken, err: svcerr.ErrAuthentication, }, { - desc: "retrieve with reset token", - // id: apiKey.ID, + desc: "retrieve with reset token", token: resetToken.AccessToken, err: svcerr.ErrAuthentication, }, @@ -240,7 +601,7 @@ func TestRetrieve(t *testing.T) { } func TestIdentify(t *testing.T) { - svc, krepo, _, prepo := newService() + svc, _ := newService() repocall := krepo.On("Save", mock.Anything, mock.Anything).Return(mock.Anything, nil) repocall1 := prepo.On("CheckPolicy", mock.Anything, mock.Anything).Return(nil) @@ -260,11 +621,23 @@ func TestIdentify(t *testing.T) { repocall3.Unset() repocall4 := krepo.On("Save", mock.Anything, mock.Anything).Return(mock.Anything, nil) - exp1 := time.Now().Add(-2 * time.Second) - expSecret, err := svc.Issue(context.Background(), loginSecret.AccessToken, auth.Key{Type: auth.APIKey, IssuedAt: time.Now(), ExpiresAt: exp1}) + exp0 := time.Now().UTC().Add(-10 * time.Second).Round(time.Second) + exp1 := time.Now().UTC().Add(-1 * time.Minute).Round(time.Second) + expSecret, err := svc.Issue(context.Background(), loginSecret.AccessToken, auth.Key{Type: auth.APIKey, IssuedAt: exp0, ExpiresAt: exp1}) assert.Nil(t, err, fmt.Sprintf("Issuing expired login key expected to succeed: %s", err)) repocall4.Unset() + te := jwt.New([]byte(secret)) + key := auth.Key{ + IssuedAt: time.Now(), + ExpiresAt: time.Now().Add(refreshDuration), + Subject: id, + Type: 7, + User: email, + Domain: groupName, + } + invalidTokenType, _ := te.Issue(key) + cases := []struct { desc string key string @@ -293,7 +666,13 @@ func TestIdentify(t *testing.T) { desc: "identify expired API key", key: expSecret.AccessToken, idt: "", - err: ErrExpiry, + err: auth.ErrKeyExpired, + }, + { + desc: "identify API key with failed to retrieve", + key: apiSecret.AccessToken, + idt: "", + err: svcerr.ErrAuthentication, }, { desc: "identify invalid key", @@ -301,78 +680,2023 @@ func TestIdentify(t *testing.T) { idt: "", err: errors.ErrAuthentication, }, + { + desc: "identify invalid key type", + key: invalidTokenType, + idt: "", + err: svcerr.ErrAuthentication, + }, } for _, tc := range cases { repocall := krepo.On("Retrieve", mock.Anything, mock.Anything, mock.Anything).Return(auth.Key{}, tc.err) + repocall1 := krepo.On("Remove", mock.Anything, mock.Anything, mock.Anything).Return(tc.err) idt, err := svc.Identify(context.Background(), tc.key) assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s expected %s got %s\n", tc.desc, tc.err, err)) assert.Equal(t, tc.idt, idt.Subject, fmt.Sprintf("%s expected %s got %s\n", tc.desc, tc.idt, idt)) repocall.Unset() + repocall1.Unset() } } func TestAuthorize(t *testing.T) { - svc, _, _, prepo := newService() + svc, accessToken := newService() - repocall := prepo.On("CheckPolicy", mock.Anything, mock.Anything).Return(nil) - pr := auth.PolicyReq{Object: authoritiesObj, Relation: memberRelation, Subject: id} - err := svc.Authorize(context.Background(), pr) - require.Nil(t, err, fmt.Sprintf("authorizing initial %v policy expected to succeed: %s", pr, err)) + repocall := krepo.On("Save", mock.Anything, mock.Anything).Return(mock.Anything, nil) + repocall1 := prepo.On("CheckPolicy", mock.Anything, mock.Anything).Return(nil) + loginSecret, err := svc.Issue(context.Background(), "", auth.Key{Type: auth.AccessKey, User: id, IssuedAt: time.Now(), Domain: groupName}) + assert.Nil(t, err, fmt.Sprintf("Issuing login key expected to succeed: %s", err)) repocall.Unset() -} + repocall1.Unset() + saveCall := krepo.On("Save", mock.Anything, mock.Anything).Return(mock.Anything, nil) + exp1 := time.Now().Add(-2 * time.Second) + expSecret, err := svc.Issue(context.Background(), loginSecret.AccessToken, auth.Key{Type: auth.APIKey, IssuedAt: time.Now(), ExpiresAt: exp1}) + assert.Nil(t, err, fmt.Sprintf("Issuing expired login key expected to succeed: %s", err)) + saveCall.Unset() -func TestAddPolicy(t *testing.T) { - svc, _, _, prepo := newService() + repocall2 := krepo.On("Save", mock.Anything, mock.Anything).Return(mock.Anything, nil) + repocall3 := prepo.On("CheckPolicy", mock.Anything, mock.Anything).Return(nil) + emptySubject, err := svc.Issue(context.Background(), "", auth.Key{Type: auth.AccessKey, User: "", IssuedAt: time.Now(), Domain: groupName}) + assert.Nil(t, err, fmt.Sprintf("Issuing login key expected to succeed: %s", err)) + repocall2.Unset() + repocall3.Unset() - repocall := prepo.On("AddPolicies", mock.Anything, mock.Anything).Return(nil) - prs := []auth.PolicyReq{{Object: "obj", ObjectType: "object", Relation: "rel", Subject: "sub", SubjectType: "subject"}} - err := svc.AddPolicies(context.Background(), prs) - require.Nil(t, err, fmt.Sprintf("adding %v policies expected to succeed: %v", prs, err)) - repocall.Unset() - for _, pr := range prs { - repocall := prepo.On("CheckPolicy", mock.Anything, mock.Anything).Return(nil) - err = svc.Authorize(context.Background(), pr) - require.Nil(t, err, fmt.Sprintf("checking shared %v policy expected to be succeed: %#v", pr, err)) - repocall.Unset() + te := jwt.New([]byte(secret)) + key := auth.Key{ + IssuedAt: time.Now(), + ExpiresAt: time.Now().Add(refreshDuration), + Subject: id, + Type: auth.AccessKey, + User: email, } -} + emptyDomain, _ := te.Issue(key) -func TestDeletePolicies(t *testing.T) { - svc, _, _, prepo := newService() + cases := []struct { + desc string + policyReq auth.PolicyReq + retrieveDomainRes auth.Domain + checkPolicyReq auth.PolicyReq + checkPolicyReq1 auth.PolicyReq + checkPolicyReq2 auth.PolicyReq + checkPolicyErr error + checkPolicyErr1 error + checkPolicyErr2 error + err error + }{ + { + desc: "authorize token successfully", + policyReq: auth.PolicyReq{ + Subject: accessToken, + SubjectType: auth.UserType, + SubjectKind: auth.TokenKind, + Object: auth.MagistralaObject, + ObjectType: auth.PlatformType, + Permission: auth.AdminPermission, + }, + checkPolicyReq: auth.PolicyReq{ + Domain: groupName, + Subject: id, + SubjectType: auth.UserType, + SubjectKind: auth.TokenKind, + Object: auth.MagistralaObject, + ObjectType: auth.PlatformType, + Permission: auth.AdminPermission, + }, + err: nil, + }, + { + desc: "authorize token for group type with empty domain", + policyReq: auth.PolicyReq{ + Subject: emptyDomain, + SubjectType: auth.UserType, + SubjectKind: auth.TokenKind, + Object: "", + ObjectType: auth.GroupType, + Permission: auth.AdminPermission, + }, + checkPolicyReq: auth.PolicyReq{ + Subject: id, + SubjectType: auth.UserType, + SubjectKind: auth.TokenKind, + Object: "", + ObjectType: auth.GroupType, + Permission: auth.AdminPermission, + }, + err: errors.ErrDomainAuthorization, + }, + { + desc: "authorize token with disabled domain", + policyReq: auth.PolicyReq{ + Subject: emptyDomain, + SubjectType: auth.UserType, + SubjectKind: auth.TokenKind, + Object: validID, + ObjectType: auth.DomainType, + Permission: auth.AdminPermission, + }, + checkPolicyReq: auth.PolicyReq{ + Subject: id, + SubjectType: auth.UserType, + SubjectKind: auth.TokenKind, + Object: validID, + ObjectType: auth.DomainType, + Permission: auth.AdminPermission, + }, + checkPolicyReq1: auth.PolicyReq{ + Subject: id, + SubjectType: auth.UserType, + Permission: auth.AdminPermission, + Object: validID, + ObjectType: auth.DomainType, + }, - repocall := prepo.On("DeletePolicies", mock.Anything, mock.Anything).Return(nil) - prs := []auth.PolicyReq{{Object: "obj", ObjectType: "object", Relation: "rel", Subject: "sub", SubjectType: "subject"}} - err := svc.DeletePolicies(context.Background(), prs) - require.Nil(t, err, fmt.Sprintf("adding %v policies expected to succeed: %v", prs, err)) - repocall.Unset() -} + retrieveDomainRes: auth.Domain{ + ID: validID, + Name: groupName, + Status: auth.DisabledStatus, + }, + err: nil, + }, + { + desc: "authorize token with disabled domain with failed to authorize", + policyReq: auth.PolicyReq{ + Subject: emptyDomain, + SubjectType: auth.UserType, + SubjectKind: auth.TokenKind, + Object: validID, + ObjectType: auth.DomainType, + Permission: auth.AdminPermission, + }, + checkPolicyReq: auth.PolicyReq{ + Subject: id, + SubjectType: auth.UserType, + SubjectKind: auth.TokenKind, + Object: validID, + ObjectType: auth.DomainType, + Permission: auth.AdminPermission, + }, + checkPolicyReq1: auth.PolicyReq{ + Subject: id, + SubjectType: auth.UserType, + Permission: auth.AdminPermission, + Object: validID, + ObjectType: auth.DomainType, + }, -func TestListPolicies(t *testing.T) { - svc, _, _, prepo := newService() + retrieveDomainRes: auth.Domain{ + ID: validID, + Name: groupName, + Status: auth.DisabledStatus, + }, + checkPolicyErr1: errors.ErrDomainAuthorization, + err: errors.ErrDomainAuthorization, + }, + { + desc: "authorize token with frozen domain", + policyReq: auth.PolicyReq{ + Subject: emptyDomain, + SubjectType: auth.UserType, + SubjectKind: auth.TokenKind, + Object: validID, + ObjectType: auth.DomainType, + Permission: auth.AdminPermission, + }, + checkPolicyReq: auth.PolicyReq{ + Subject: id, + SubjectType: auth.UserType, + SubjectKind: auth.TokenKind, + Object: validID, + ObjectType: auth.DomainType, + Permission: auth.AdminPermission, + }, + checkPolicyReq1: auth.PolicyReq{ + Subject: id, + SubjectType: auth.UserType, + Permission: auth.AdminPermission, + Object: auth.MagistralaObject, + ObjectType: auth.PlatformType, + }, - pageLen := 15 + retrieveDomainRes: auth.Domain{ + ID: validID, + Name: groupName, + Status: auth.FreezeStatus, + }, + err: nil, + }, + { + desc: "authorize token with frozen domain with failed to authorize", + policyReq: auth.PolicyReq{ + Subject: emptyDomain, + SubjectType: auth.UserType, + SubjectKind: auth.TokenKind, + Object: validID, + ObjectType: auth.DomainType, + Permission: auth.AdminPermission, + }, + checkPolicyReq: auth.PolicyReq{ + Subject: id, + SubjectType: auth.UserType, + SubjectKind: auth.TokenKind, + Object: validID, + ObjectType: auth.DomainType, + Permission: auth.AdminPermission, + }, + checkPolicyReq1: auth.PolicyReq{ + Subject: id, + SubjectType: auth.UserType, + Permission: auth.AdminPermission, + Object: auth.MagistralaObject, + ObjectType: auth.PlatformType, + }, - // Add arbitrary policies to the user. - var prs []auth.PolicyReq - for i := 0; i < pageLen; i++ { - prs = append(prs, auth.PolicyReq{ - Subject: id, - SubjectType: auth.UserType, - Relation: auth.ViewerRelation, - Object: fmt.Sprintf("thing-%d", i), - ObjectType: auth.ThingType, - }) - } - repocall := prepo.On("AddPolicies", mock.Anything, mock.Anything).Return(nil) - err := svc.AddPolicies(context.Background(), prs) - assert.Nil(t, err, fmt.Sprintf("adding policies expected to succeed: %s", err)) - repocall.Unset() + retrieveDomainRes: auth.Domain{ + ID: validID, + Name: groupName, + Status: auth.FreezeStatus, + }, + checkPolicyErr1: errors.ErrDomainAuthorization, + err: errors.ErrDomainAuthorization, + }, + { + desc: "authorize token with domain with invalid status", + policyReq: auth.PolicyReq{ + Subject: emptyDomain, + SubjectType: auth.UserType, + SubjectKind: auth.TokenKind, + Object: validID, + ObjectType: auth.DomainType, + Permission: auth.AdminPermission, + }, + checkPolicyReq: auth.PolicyReq{ + Subject: id, + SubjectType: auth.UserType, + SubjectKind: auth.TokenKind, + Object: validID, + ObjectType: auth.DomainType, + Permission: auth.AdminPermission, + }, + checkPolicyReq1: auth.PolicyReq{ + Subject: id, + SubjectType: auth.UserType, + Permission: auth.AdminPermission, + Object: auth.MagistralaObject, + ObjectType: auth.PlatformType, + }, - expectedPolicies := make([]auth.PolicyRes, pageLen) - repocall2 := prepo.On("RetrieveObjects", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(expectedPolicies, mock.Anything, nil) - page, err := svc.ListObjects(context.Background(), auth.PolicyReq{Subject: id, SubjectType: auth.UserType, ObjectType: auth.ThingType, Permission: auth.ViewPermission}, "", 100) - assert.Nil(t, err, fmt.Sprintf("listing policies expected to succeed: %s", err)) - assert.Equal(t, pageLen, len(page.Policies), fmt.Sprintf("unexpected listing page size, expected %d, got %d: %v", pageLen, len(page.Policies), err)) - repocall2.Unset() + retrieveDomainRes: auth.Domain{ + ID: validID, + Name: groupName, + Status: auth.AllStatus, + }, + err: errors.ErrDomainAuthorization, + }, + + { + desc: "authorize an expired token", + policyReq: auth.PolicyReq{ + Subject: expSecret.AccessToken, + SubjectType: auth.UserType, + SubjectKind: auth.TokenKind, + Object: auth.MagistralaObject, + ObjectType: auth.PlatformType, + Permission: auth.AdminPermission, + }, + checkPolicyReq: auth.PolicyReq{ + Subject: id, + SubjectType: auth.UserType, + SubjectKind: "", + Object: auth.MagistralaObject, + ObjectType: auth.PlatformType, + Permission: auth.AdminPermission, + }, + err: svcerr.ErrAuthentication, + }, + { + desc: "authorize a token with an empty subject", + policyReq: auth.PolicyReq{ + Subject: emptySubject.AccessToken, + SubjectType: auth.UserType, + SubjectKind: auth.TokenKind, + Object: auth.MagistralaObject, + ObjectType: auth.PlatformType, + Permission: auth.AdminPermission, + }, + checkPolicyReq: auth.PolicyReq{ + SubjectType: auth.UserType, + Object: auth.MagistralaObject, + ObjectType: auth.PlatformType, + Permission: auth.AdminPermission, + }, + err: svcerr.ErrAuthentication, + }, + { + desc: "authorize a token with an empty secret and invalid type", + policyReq: auth.PolicyReq{ + Subject: emptySubject.AccessToken, + SubjectType: auth.UserType, + SubjectKind: auth.TokenKind, + Object: auth.MagistralaObject, + ObjectType: auth.DomainType, + Permission: auth.AdminPermission, + }, + checkPolicyReq: auth.PolicyReq{ + SubjectType: auth.UserType, + Object: auth.MagistralaObject, + ObjectType: auth.PlatformKind, + Permission: auth.AdminPermission, + }, + err: errors.ErrDomainAuthorization, + }, + { + desc: "authorize a user key successfully", + policyReq: auth.PolicyReq{ + Subject: "", + SubjectType: auth.UserType, + SubjectKind: auth.UsersKind, + Object: auth.MagistralaObject, + ObjectType: auth.PlatformType, + Permission: auth.AdminPermission, + }, + checkPolicyReq: auth.PolicyReq{ + SubjectType: auth.UserType, + SubjectKind: auth.UsersKind, + Object: auth.MagistralaObject, + ObjectType: auth.PlatformType, + Permission: auth.AdminPermission, + }, + err: nil, + }, + { + desc: "authorize token with empty subject and domain object type", + policyReq: auth.PolicyReq{ + Subject: emptySubject.AccessToken, + SubjectType: auth.UserType, + SubjectKind: auth.TokenKind, + Object: auth.MagistralaObject, + ObjectType: auth.DomainType, + Permission: auth.AdminPermission, + }, + checkPolicyReq: auth.PolicyReq{ + SubjectType: auth.UserType, + Object: auth.MagistralaObject, + ObjectType: auth.PlatformType, + Permission: auth.AdminPermission, + }, + err: errors.ErrDomainAuthorization, + }, + } + for _, tc := range cases { + repoCall := prepo.On("CheckPolicy", mock.Anything, tc.checkPolicyReq).Return(tc.checkPolicyErr) + repoCall1 := drepo.On("RetrieveByID", mock.Anything, mock.Anything).Return(tc.retrieveDomainRes, nil) + repoCall2 := prepo.On("CheckPolicy", mock.Anything, tc.checkPolicyReq1).Return(tc.checkPolicyErr1) + repoCall3 := krepo.On("Remove", mock.Anything, mock.Anything, mock.Anything).Return(nil) + err := svc.Authorize(context.Background(), tc.policyReq) + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s expected %s got %s\n", tc.desc, tc.err, err)) + repoCall.Unset() + repoCall1.Unset() + repoCall2.Unset() + repoCall3.Unset() + } + + cases2 := []struct { + desc string + policyReq auth.PolicyReq + err error + }{ + { + desc: "authorize token with invalid platform validation", + policyReq: auth.PolicyReq{ + Subject: "", + SubjectType: auth.UserType, + SubjectKind: auth.UsersKind, + Object: validID, + ObjectType: auth.PlatformType, + Permission: auth.AdminPermission, + }, + err: errPlatform, + }, + } + for _, tc := range cases2 { + err := svc.Authorize(context.Background(), tc.policyReq) + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s expected %s got %s\n", tc.desc, tc.err, err)) + } +} + +func TestAddPolicy(t *testing.T) { + svc, _ := newService() + + cases := []struct { + desc string + pr auth.PolicyReq + err error + }{ + { + desc: "add policy successfully", + pr: auth.PolicyReq{ + Subject: id, + SubjectType: auth.UserType, + SubjectKind: auth.UsersKind, + Object: auth.MagistralaObject, + ObjectType: auth.PlatformType, + Permission: auth.AdminPermission, + }, + err: nil, + }, + { + desc: "add policy with invalid object", + pr: auth.PolicyReq{ + Subject: id, + SubjectType: auth.UserType, + SubjectKind: auth.UsersKind, + Object: inValid, + ObjectType: auth.PlatformType, + Permission: auth.AdminPermission, + }, + err: svcerr.ErrInvalidPolicy, + }, + } + + for _, tc := range cases { + repocall := prepo.On("AddPolicy", mock.Anything, mock.Anything).Return(tc.err) + err := svc.AddPolicy(context.Background(), tc.pr) + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s expected %s got %s\n", tc.desc, tc.err, err)) + repocall.Unset() + } +} + +func TestAddPolicies(t *testing.T) { + svc, _ := newService() + + cases := []struct { + desc string + pr []auth.PolicyReq + err error + }{ + { + desc: "add policy successfully", + pr: []auth.PolicyReq{ + { + Subject: id, + SubjectType: auth.UserType, + SubjectKind: auth.UsersKind, + Object: auth.MagistralaObject, + ObjectType: auth.PlatformType, + Permission: auth.AdminPermission, + }, + { + Subject: id, + SubjectType: auth.UserType, + SubjectKind: auth.UsersKind, + Object: auth.MagistralaObject, + ObjectType: auth.PlatformType, + Permission: auth.AdminPermission, + }, + }, + err: nil, + }, + { + desc: "add policy with invalid object", + pr: []auth.PolicyReq{ + { + Subject: id, + SubjectType: auth.UserType, + SubjectKind: auth.UsersKind, + Object: inValid, + ObjectType: auth.PlatformType, + Permission: auth.AdminPermission, + }, + { + Subject: id, + SubjectType: auth.UserType, + SubjectKind: auth.UsersKind, + Object: auth.MagistralaObject, + ObjectType: auth.PlatformType, + Permission: auth.AdminPermission, + }, + }, + err: svcerr.ErrInvalidPolicy, + }, + } + + for _, tc := range cases { + repocall := prepo.On("AddPolicies", mock.Anything, mock.Anything).Return(tc.err) + err := svc.AddPolicies(context.Background(), tc.pr) + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s expected %s got %s\n", tc.desc, tc.err, err)) + repocall.Unset() + } +} + +func TestDeletePolicy(t *testing.T) { + svc, _ := newService() + + cases := []struct { + desc string + pr auth.PolicyReq + err error + }{ + { + desc: "delete policy successfully", + pr: auth.PolicyReq{ + Subject: id, + SubjectType: auth.UserType, + SubjectKind: auth.UsersKind, + Object: auth.MagistralaObject, + ObjectType: auth.PlatformType, + Permission: auth.AdminPermission, + }, + err: nil, + }, + { + desc: "delete policy with invalid object", + pr: auth.PolicyReq{ + Subject: id, + SubjectType: auth.UserType, + SubjectKind: auth.UsersKind, + Object: inValid, + ObjectType: auth.PlatformType, + Permission: auth.AdminPermission, + }, + err: svcerr.ErrInvalidPolicy, + }, + } + + for _, tc := range cases { + repocall := prepo.On("DeletePolicy", mock.Anything, mock.Anything).Return(tc.err) + err := svc.DeletePolicy(context.Background(), tc.pr) + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s expected %s got %s\n", tc.desc, tc.err, err)) + repocall.Unset() + } +} + +func TestDeletePolicies(t *testing.T) { + svc, _ := newService() + + cases := []struct { + desc string + pr []auth.PolicyReq + err error + }{ + { + desc: "delete policy successfully", + pr: []auth.PolicyReq{ + { + Subject: id, + SubjectType: auth.UserType, + SubjectKind: auth.UsersKind, + Object: auth.MagistralaObject, + ObjectType: auth.PlatformType, + Permission: auth.AdminPermission, + }, + { + Subject: id, + SubjectType: auth.UserType, + SubjectKind: auth.UsersKind, + Object: auth.MagistralaObject, + ObjectType: auth.PlatformType, + Permission: auth.AdminPermission, + }, + }, + err: nil, + }, + { + desc: "delete policy with invalid object", + pr: []auth.PolicyReq{ + { + Subject: id, + SubjectType: auth.UserType, + SubjectKind: auth.UsersKind, + Object: inValid, + ObjectType: auth.PlatformType, + Permission: auth.AdminPermission, + }, + { + Subject: id, + SubjectType: auth.UserType, + SubjectKind: auth.UsersKind, + Object: auth.MagistralaObject, + ObjectType: auth.PlatformType, + Permission: auth.AdminPermission, + }, + }, + err: svcerr.ErrInvalidPolicy, + }, + } + + for _, tc := range cases { + repocall := prepo.On("DeletePolicies", mock.Anything, mock.Anything).Return(tc.err) + err := svc.DeletePolicies(context.Background(), tc.pr) + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s expected %s got %s\n", tc.desc, tc.err, err)) + repocall.Unset() + } +} + +func TestListObjects(t *testing.T) { + svc, accessToken := newService() + + pageLen := 15 + expectedPolicies := make([]auth.PolicyRes, pageLen) + + cases := []struct { + desc string + pr auth.PolicyReq + nextPageToken string + limit int32 + err error + }{ + { + desc: "list objects successfully", + pr: auth.PolicyReq{ + Subject: id, + SubjectType: auth.UserType, + Relation: auth.ViewerRelation, + ObjectType: auth.ThingType, + ObjectKind: auth.ThingsKind, + Object: "", + }, + nextPageToken: accessToken, + limit: 10, + err: nil, + }, + { + desc: "list objects with invalid request", + pr: auth.PolicyReq{ + Subject: inValid, + SubjectType: inValid, + Relation: auth.ViewerRelation, + ObjectType: auth.ThingType, + ObjectKind: auth.ThingsKind, + Object: inValid, + }, + nextPageToken: accessToken, + limit: 10, + err: svcerr.ErrInvalidPolicy, + }, + { + desc: "list objects with limit less than zero", + pr: auth.PolicyReq{ + Subject: id, + SubjectType: auth.UserType, + Relation: auth.ViewerRelation, + ObjectType: auth.ThingType, + ObjectKind: auth.ThingsKind, + Object: "", + }, + nextPageToken: accessToken, + limit: -1, + err: nil, + }, + } + for _, tc := range cases { + repocall2 := prepo.On("RetrieveObjects", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(expectedPolicies, mock.Anything, tc.err) + page, err := svc.ListObjects(context.Background(), tc.pr, tc.nextPageToken, tc.limit) + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("listing policies expected to succeed: %s", err)) + if err == nil { + assert.Equal(t, pageLen, len(page.Policies), fmt.Sprintf("unexpected listing page size, expected %d, got %d: %v", pageLen, len(page.Policies), err)) + } + repocall2.Unset() + } +} + +func TestListAllObjects(t *testing.T) { + svc, accessToken := newService() + + pageLen := 15 + expectedPolicies := make([]auth.PolicyRes, pageLen) + + cases := []struct { + desc string + pr auth.PolicyReq + nextPageToken string + limit int32 + err error + }{ + { + desc: "list all objects successfully", + pr: auth.PolicyReq{ + Subject: id, + SubjectType: auth.UserType, + Relation: auth.ViewerRelation, + ObjectType: auth.ThingType, + ObjectKind: auth.ThingsKind, + Object: "", + }, + nextPageToken: accessToken, + limit: 10, + err: nil, + }, + { + desc: "list all objects with invalid request", + pr: auth.PolicyReq{ + Subject: inValid, + SubjectType: inValid, + Relation: auth.ViewerRelation, + ObjectType: auth.ThingType, + ObjectKind: auth.ThingsKind, + Object: inValid, + }, + nextPageToken: accessToken, + limit: 10, + err: svcerr.ErrInvalidPolicy, + }, + } + for _, tc := range cases { + repocall2 := prepo.On("RetrieveAllObjects", mock.Anything, mock.Anything).Return(expectedPolicies, tc.err) + page, err := svc.ListAllObjects(context.Background(), tc.pr) + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("listing policies expected to succeed: %s", err)) + if err == nil { + assert.Equal(t, pageLen, len(page.Policies), fmt.Sprintf("unexpected listing page size, expected %d, got %d: %v", pageLen, len(page.Policies), err)) + } + repocall2.Unset() + } +} + +func TestCountObjects(t *testing.T) { + svc, _ := newService() + + pageLen := 15 + + repocall2 := prepo.On("RetrieveAllObjectsCount", mock.Anything, mock.Anything, mock.Anything).Return(pageLen, nil) + count, err := svc.CountObjects(context.Background(), auth.PolicyReq{Subject: id, SubjectType: auth.UserType, ObjectType: auth.ThingType, Permission: auth.ViewPermission}) + assert.Nil(t, err, fmt.Sprintf("counting policies expected to succeed: %s", err)) + assert.Equal(t, pageLen, count, fmt.Sprintf("unexpected listing page size, expected %d, got %d: %v", pageLen, count, err)) + repocall2.Unset() +} + +func TestListSubjects(t *testing.T) { + svc, accessToken := newService() + + pageLen := 15 + expectedPolicies := make([]auth.PolicyRes, pageLen) + + cases := []struct { + desc string + pr auth.PolicyReq + nextPageToken string + limit int32 + err error + }{ + { + desc: "list subjects successfully", + pr: auth.PolicyReq{ + Subject: id, + SubjectType: auth.UserType, + Relation: auth.ViewerRelation, + ObjectType: auth.ThingType, + ObjectKind: auth.ThingsKind, + Object: "", + }, + nextPageToken: accessToken, + limit: 10, + err: nil, + }, + { + desc: "list subjects with invalid request", + pr: auth.PolicyReq{ + Subject: inValid, + SubjectType: inValid, + Relation: auth.ViewerRelation, + ObjectType: auth.ThingType, + ObjectKind: auth.ThingsKind, + Object: inValid, + }, + nextPageToken: accessToken, + limit: 10, + err: svcerr.ErrInvalidPolicy, + }, + { + desc: "list subjects with limit less than zero", + pr: auth.PolicyReq{ + Subject: id, + SubjectType: auth.UserType, + Relation: auth.ViewerRelation, + ObjectType: auth.ThingType, + ObjectKind: auth.ThingsKind, + Object: "", + }, + nextPageToken: accessToken, + limit: -1, + err: nil, + }, + } + for _, tc := range cases { + repocall2 := prepo.On("RetrieveSubjects", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(expectedPolicies, mock.Anything, tc.err) + page, err := svc.ListSubjects(context.Background(), tc.pr, tc.nextPageToken, tc.limit) + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("listing policies expected to succeed: %s", err)) + if err == nil { + assert.Equal(t, pageLen, len(page.Policies), fmt.Sprintf("unexpected listing page size, expected %d, got %d: %v", pageLen, len(page.Policies), err)) + } + repocall2.Unset() + } +} + +func TestListAllSubjects(t *testing.T) { + svc, accessToken := newService() + + pageLen := 15 + expectedPolicies := make([]auth.PolicyRes, pageLen) + + cases := []struct { + desc string + pr auth.PolicyReq + nextPageToken string + limit int32 + err error + }{ + { + desc: "list all subjects successfully", + pr: auth.PolicyReq{ + Subject: id, + SubjectType: auth.UserType, + Relation: auth.ViewerRelation, + ObjectType: auth.ThingType, + ObjectKind: auth.ThingsKind, + Object: "", + }, + nextPageToken: accessToken, + limit: 10, + err: nil, + }, + { + desc: "list all subjects with invalid request", + pr: auth.PolicyReq{ + Subject: inValid, + SubjectType: inValid, + Relation: auth.ViewerRelation, + ObjectType: auth.ThingType, + ObjectKind: auth.ThingsKind, + Object: inValid, + }, + nextPageToken: accessToken, + limit: 10, + err: svcerr.ErrInvalidPolicy, + }, + } + for _, tc := range cases { + repocall2 := prepo.On("RetrieveAllSubjects", mock.Anything, mock.Anything).Return(expectedPolicies, tc.err) + page, err := svc.ListAllSubjects(context.Background(), tc.pr) + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("listing policies expected to succeed: %s", err)) + if err == nil { + assert.Equal(t, pageLen, len(page.Policies), fmt.Sprintf("unexpected listing page size, expected %d, got %d: %v", pageLen, len(page.Policies), err)) + } + repocall2.Unset() + } +} + +func TestCountSubjects(t *testing.T) { + svc, _ := newService() + pageLen := 15 + + repocall2 := prepo.On("RetrieveAllSubjectsCount", mock.Anything, mock.Anything, mock.Anything).Return(pageLen, nil) + count, err := svc.CountSubjects(context.Background(), auth.PolicyReq{Object: id, ObjectType: auth.ThingType, Permission: auth.ViewPermission}) + assert.Nil(t, err, fmt.Sprintf("counting policies expected to succeed: %s", err)) + assert.Equal(t, pageLen, count, fmt.Sprintf("unexpected listing page size, expected %d, got %d: %v", pageLen, count, err)) + repocall2.Unset() +} + +func TestListPermissions(t *testing.T) { + svc, _ := newService() + + pr := auth.PolicyReq{ + Subject: id, + SubjectType: auth.UserType, + Relation: auth.ViewerRelation, + ObjectType: auth.ThingType, + ObjectKind: auth.ThingsKind, + Object: "", + } + filterPermisions := []string{auth.ViewPermission, auth.AdminPermission} + + repoCall1 := prepo.On("RetrievePermissions", mock.Anything, pr, filterPermisions).Return(auth.Permissions{}, nil) + _, err := svc.ListPermissions(context.Background(), pr, filterPermisions) + assert.Nil(t, err, fmt.Sprintf("listing policies expected to succeed: %s", err)) + repoCall1.Unset() +} + +func TestSwitchToPermission(t *testing.T) { + cases := []struct { + desc string + relation string + result string + }{ + { + desc: "switch to admin permission", + relation: auth.AdministratorRelation, + result: auth.AdminPermission, + }, + { + desc: "switch to editor permission", + relation: auth.EditorRelation, + result: auth.EditPermission, + }, + { + desc: "switch to viewer permission", + relation: auth.ViewerRelation, + result: auth.ViewPermission, + }, + { + desc: "switch to member permission", + relation: auth.MemberRelation, + result: auth.MembershipPermission, + }, + { + desc: "switch to group permission", + relation: auth.GroupRelation, + result: auth.GroupRelation, + }, + } + for _, tc := range cases { + result := auth.SwitchToPermission(tc.relation) + assert.Equal(t, tc.result, result, fmt.Sprintf("switching to permission expected to succeed: %s", result)) + } +} + +func TestCreateDomain(t *testing.T) { + svc, accessToken := newService() + + cases := []struct { + desc string + d auth.Domain + token string + userID string + addPolicyErr error + savePolicyErr error + saveDomainErr error + deleteDomainErr error + deletePoliciesErr error + err error + }{ + { + desc: "create domain successfully", + d: auth.Domain{ + Status: auth.EnabledStatus, + }, + token: accessToken, + err: nil, + }, + { + desc: "create domain with invalid token", + d: auth.Domain{ + Status: auth.EnabledStatus, + }, + token: inValidToken, + err: svcerr.ErrAuthentication, + }, + { + desc: "create domain with invalid status", + d: auth.Domain{ + Status: auth.AllStatus, + }, + token: accessToken, + err: svcerr.ErrInvalidStatus, + }, + { + desc: "create domain with failed policy request", + d: auth.Domain{ + Status: auth.EnabledStatus, + }, + token: accessToken, + addPolicyErr: errors.ErrMalformedEntity, + err: errors.ErrMalformedEntity, + }, + { + desc: "create domain with failed save policy request", + d: auth.Domain{ + Status: auth.EnabledStatus, + }, + token: accessToken, + savePolicyErr: errors.ErrMalformedEntity, + err: errCreateDomainPolicy, + }, + { + desc: "create domain with failed save domain request", + d: auth.Domain{ + Status: auth.EnabledStatus, + }, + token: accessToken, + saveDomainErr: errors.ErrMalformedEntity, + err: svcerr.ErrCreateEntity, + }, + { + desc: "create domain with rollback error", + d: auth.Domain{ + Status: auth.EnabledStatus, + }, + token: accessToken, + savePolicyErr: errors.ErrMalformedEntity, + deleteDomainErr: errors.ErrMalformedEntity, + err: errors.ErrMalformedEntity, + }, + { + desc: "create domain with rollback error and failed to delete policies", + d: auth.Domain{ + Status: auth.EnabledStatus, + }, + token: accessToken, + savePolicyErr: errors.ErrMalformedEntity, + deleteDomainErr: errors.ErrMalformedEntity, + deletePoliciesErr: errors.ErrMalformedEntity, + err: errors.ErrMalformedEntity, + }, + { + desc: "create domain with failed to create and failed rollback", + d: auth.Domain{ + Status: auth.EnabledStatus, + }, + token: accessToken, + saveDomainErr: errors.ErrMalformedEntity, + deletePoliciesErr: errors.ErrMalformedEntity, + err: errRollbackPolicy, + }, + { + desc: "create domain with failed to create and failed rollback", + d: auth.Domain{ + Status: auth.EnabledStatus, + }, + token: accessToken, + saveDomainErr: errors.ErrMalformedEntity, + deleteDomainErr: errors.ErrMalformedEntity, + err: errors.ErrMalformedEntity, + }, + } + + for _, tc := range cases { + repoCall := prepo.On("AddPolicies", mock.Anything, mock.Anything).Return(tc.addPolicyErr) + repoCall1 := drepo.On("SavePolicies", mock.Anything, mock.Anything).Return(tc.savePolicyErr) + repoCall2 := prepo.On("DeletePolicies", mock.Anything, mock.Anything).Return(tc.deletePoliciesErr) + repoCall3 := drepo.On("DeletePolicies", mock.Anything, mock.Anything).Return(tc.deleteDomainErr) + repoCall4 := drepo.On("Save", mock.Anything, mock.Anything).Return(auth.Domain{}, tc.saveDomainErr) + _, err := svc.CreateDomain(context.Background(), tc.token, tc.d) + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s expected %s got %s\n", tc.desc, tc.err, err)) + repoCall.Unset() + repoCall1.Unset() + repoCall2.Unset() + repoCall3.Unset() + repoCall4.Unset() + } +} + +func TestRetrieveDomain(t *testing.T) { + svc, accessToken := newService() + + cases := []struct { + desc string + token string + domainID string + domainRepoErr error + domainRepoErr1 error + checkPolicyErr error + err error + }{ + { + desc: "retrieve domain successfully", + token: accessToken, + domainID: validID, + err: nil, + }, + { + desc: "retrieve domain with invalid token", + token: inValidToken, + domainID: validID, + err: svcerr.ErrAuthentication, + }, + { + desc: "retrieve domain with empty domainID", + token: accessToken, + domainID: "", + err: nil, + }, + { + desc: "retrieve non-existing domain", + token: accessToken, + domainID: inValid, + domainRepoErr: errors.ErrNotFound, + err: svcerr.ErrAuthorization, + }, + { + desc: "retrieve domain with failed to retrieve by id", + token: accessToken, + domainID: validID, + domainRepoErr1: errors.ErrNotFound, + err: svcerr.ErrNotFound, + }, + } + + for _, tc := range cases { + repoCall := drepo.On("RetrieveByID", mock.Anything, groupName).Return(auth.Domain{}, tc.domainRepoErr) + repoCall1 := prepo.On("CheckPolicy", mock.Anything, mock.Anything).Return(tc.checkPolicyErr) + repoCall2 := drepo.On("RetrieveByID", mock.Anything, tc.domainID).Return(auth.Domain{}, tc.domainRepoErr1) + _, err := svc.RetrieveDomain(context.Background(), tc.token, tc.domainID) + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s expected %s got %s\n", tc.desc, tc.err, err)) + repoCall.Unset() + repoCall1.Unset() + repoCall2.Unset() + } +} + +func TestRetrieveDomainPermissions(t *testing.T) { + svc, accessToken := newService() + + cases := []struct { + desc string + token string + domainID string + retreivePermissionsErr error + retreiveByIDErr error + checkPolicyErr error + err error + }{ + { + desc: "retrieve domain permissions successfully", + token: accessToken, + domainID: validID, + err: nil, + }, + { + desc: "retrieve domain permissions with invalid token", + token: inValidToken, + domainID: validID, + err: svcerr.ErrAuthentication, + }, + { + desc: "retrieve domain permissions with empty domainID", + token: accessToken, + domainID: "", + checkPolicyErr: svcerr.ErrAuthorization, + err: svcerr.ErrAuthorization, + }, + { + desc: "retrieve domain permissions with failed to retrieve permissions", + token: accessToken, + domainID: validID, + retreivePermissionsErr: errors.ErrNotFound, + err: svcerr.ErrNotFound, + }, + { + desc: "retrieve domain permissions with failed to retrieve by id", + token: accessToken, + domainID: validID, + retreiveByIDErr: errors.ErrNotFound, + err: svcerr.ErrNotFound, + }, + } + + for _, tc := range cases { + repoCall := prepo.On("RetrievePermissions", mock.Anything, mock.Anything, mock.Anything).Return(auth.Permissions{}, tc.retreivePermissionsErr) + repoCall1 := drepo.On("RetrieveByID", mock.Anything, mock.Anything).Return(auth.Domain{}, tc.retreiveByIDErr) + repoCall2 := prepo.On("CheckPolicy", mock.Anything, mock.Anything).Return(tc.checkPolicyErr) + _, err := svc.RetrieveDomainPermissions(context.Background(), tc.token, tc.domainID) + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s expected %s got %s\n", tc.desc, tc.err, err)) + repoCall.Unset() + repoCall1.Unset() + repoCall2.Unset() + } +} + +func TestUpdateDomain(t *testing.T) { + svc, accessToken := newService() + + cases := []struct { + desc string + token string + domainID string + domReq auth.DomainReq + checkPolicyErr error + retrieveByIDErr error + updateErr error + err error + }{ + { + desc: "update domain successfully", + token: accessToken, + domainID: validID, + domReq: auth.DomainReq{ + Name: &valid, + Alias: &valid, + }, + err: nil, + }, + { + desc: "update domain with invalid token", + token: inValidToken, + domainID: validID, + domReq: auth.DomainReq{ + Name: &valid, + Alias: &valid, + }, + err: svcerr.ErrAuthentication, + }, + { + desc: "update domain with empty domainID", + token: accessToken, + domainID: "", + domReq: auth.DomainReq{ + Name: &valid, + Alias: &valid, + }, + checkPolicyErr: svcerr.ErrAuthorization, + err: svcerr.ErrAuthorization, + }, + { + desc: "update domain with failed to retrieve by id", + token: accessToken, + domainID: validID, + domReq: auth.DomainReq{ + Name: &valid, + Alias: &valid, + }, + retrieveByIDErr: errors.ErrNotFound, + err: svcerr.ErrNotFound, + }, + { + desc: "update domain with failed to update", + token: accessToken, + domainID: validID, + domReq: auth.DomainReq{ + Name: &valid, + Alias: &valid, + }, + updateErr: errors.ErrMalformedEntity, + err: errors.ErrMalformedEntity, + }, + } + + for _, tc := range cases { + repoCall := prepo.On("CheckPolicy", mock.Anything, mock.Anything).Return(tc.checkPolicyErr) + repoCall1 := drepo.On("RetrieveByID", mock.Anything, mock.Anything).Return(auth.Domain{}, tc.retrieveByIDErr) + repoCall2 := drepo.On("Update", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(auth.Domain{}, tc.updateErr) + _, err := svc.UpdateDomain(context.Background(), tc.token, tc.domainID, tc.domReq) + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s expected %s got %s\n", tc.desc, tc.err, err)) + repoCall.Unset() + repoCall1.Unset() + repoCall2.Unset() + } +} + +func TestChangeDomainStatus(t *testing.T) { + svc, accessToken := newService() + + disabledStatus := auth.DisabledStatus + + cases := []struct { + desc string + token string + domainID string + domainReq auth.DomainReq + retreieveByIDErr error + checkPolicyErr error + updateErr error + err error + }{ + { + desc: "change domain status successfully", + token: accessToken, + domainID: validID, + domainReq: auth.DomainReq{ + Status: &disabledStatus, + }, + err: nil, + }, + { + desc: "change domain status with invalid token", + token: inValidToken, + domainID: validID, + domainReq: auth.DomainReq{ + Status: &disabledStatus, + }, + err: svcerr.ErrAuthentication, + }, + { + desc: "change domain status with empty domainID", + token: accessToken, + domainID: "", + domainReq: auth.DomainReq{ + Status: &disabledStatus, + }, + retreieveByIDErr: errors.ErrNotFound, + err: svcerr.ErrAuthorization, + }, + { + desc: "change domain status with unauthorized domain ID", + token: accessToken, + domainID: validID, + domainReq: auth.DomainReq{ + Status: &disabledStatus, + }, + checkPolicyErr: svcerr.ErrAuthorization, + err: svcerr.ErrAuthorization, + }, + { + desc: "change domain status with repository error on update", + token: accessToken, + domainID: validID, + domainReq: auth.DomainReq{ + Status: &disabledStatus, + }, + updateErr: errors.ErrMalformedEntity, + err: errors.ErrMalformedEntity, + }, + } + + for _, tc := range cases { + repoCall := drepo.On("RetrieveByID", mock.Anything, mock.Anything).Return(auth.Domain{}, tc.retreieveByIDErr) + repoCall1 := prepo.On("CheckPolicy", mock.Anything, mock.Anything).Return(tc.checkPolicyErr) + repoCall2 := drepo.On("Update", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(auth.Domain{}, tc.updateErr) + _, err := svc.ChangeDomainStatus(context.Background(), tc.token, tc.domainID, tc.domainReq) + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s expected %s got %s\n", tc.desc, tc.err, err)) + repoCall.Unset() + repoCall1.Unset() + repoCall2.Unset() + } +} + +func TestListDomains(t *testing.T) { + svc, accessToken := newService() + + cases := []struct { + desc string + token string + domainID string + authReq auth.Page + listDomainsRes auth.DomainsPage + retreiveByIDErr error + checkPolicyErr error + listDomainErr error + err error + }{ + { + desc: "list domains successfully", + token: accessToken, + domainID: validID, + authReq: auth.Page{ + Offset: 0, + Limit: 10, + Permission: auth.AdminPermission, + Status: auth.EnabledStatus, + }, + listDomainsRes: auth.DomainsPage{ + Domains: []auth.Domain{domain}, + }, + err: nil, + }, + { + desc: "list domains with invalid token", + token: inValidToken, + domainID: validID, + authReq: auth.Page{ + Offset: 0, + Limit: 10, + Permission: auth.AdminPermission, + Status: auth.EnabledStatus, + }, + err: svcerr.ErrAuthentication, + }, + { + desc: "list domains with repository error on list domains", + token: accessToken, + domainID: validID, + authReq: auth.Page{ + Offset: 0, + Limit: 10, + Permission: auth.AdminPermission, + Status: auth.EnabledStatus, + }, + listDomainErr: errors.ErrMalformedEntity, + err: svcerr.ErrViewEntity, + }, + } + + for _, tc := range cases { + repoCall := prepo.On("CheckPolicy", mock.Anything, mock.Anything).Return(tc.checkPolicyErr) + repoCall1 := drepo.On("ListDomains", mock.Anything, mock.Anything).Return(tc.listDomainsRes, tc.listDomainErr) + _, err := svc.ListDomains(context.Background(), tc.token, auth.Page{}) + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s expected %s got %s\n", tc.desc, tc.err, err)) + repoCall.Unset() + repoCall1.Unset() + } +} + +func TestAssignUsers(t *testing.T) { + svc, accessToken := newService() + + cases := []struct { + desc string + token string + domainID string + userIDs []string + relation string + checkPolicyReq auth.PolicyReq + checkPolicyReq1 auth.PolicyReq + checkPolicyReq2 auth.PolicyReq + checkpolicyErr error + checkPolicyErr1 error + checkPolicyErr2 error + addPoliciesErr error + savePoliciesErr error + deletePoliciesErr error + err error + }{ + { + desc: "assign users successfully", + token: accessToken, + domainID: validID, + userIDs: []string{validID}, + relation: auth.ViewerRelation, + checkPolicyReq: auth.PolicyReq{ + Domain: groupName, + Subject: "testID", + SubjectType: auth.UserType, + SubjectKind: auth.TokenKind, + Object: validID, + ObjectKind: "", + ObjectType: auth.DomainType, + Permission: auth.SharePermission, + }, + checkPolicyReq1: auth.PolicyReq{ + Domain: groupName, + Subject: "testID", + SubjectType: auth.UserType, + SubjectKind: auth.TokenKind, + Object: validID, + ObjectKind: "", + ObjectType: auth.DomainType, + Permission: auth.ViewPermission, + }, + checkPolicyReq2: auth.PolicyReq{ + Subject: validID, + SubjectType: auth.UserType, + SubjectKind: "", + Object: auth.MagistralaObject, + ObjectKind: "", + ObjectType: auth.PlatformType, + Permission: auth.MembershipPermission, + }, + + err: nil, + }, + { + desc: "assign users with invalid token", + token: inValidToken, + domainID: validID, + userIDs: []string{validID}, + relation: auth.ViewerRelation, + checkPolicyReq: auth.PolicyReq{ + Domain: groupName, + Subject: "testID", + SubjectType: auth.UserType, + SubjectKind: auth.TokenKind, + Object: validID, + ObjectKind: "", + ObjectType: auth.DomainType, + Permission: auth.SharePermission, + }, + checkPolicyReq1: auth.PolicyReq{ + Domain: groupName, + Subject: "testID", + SubjectType: auth.UserType, + SubjectKind: auth.TokenKind, + Object: validID, + ObjectKind: "", + ObjectType: auth.DomainType, + Permission: auth.ViewPermission, + }, + checkPolicyReq2: auth.PolicyReq{ + Subject: validID, + SubjectType: auth.UserType, + SubjectKind: "", + Object: auth.MagistralaObject, + ObjectKind: "", + ObjectType: auth.PlatformType, + Permission: auth.MembershipPermission, + }, + err: svcerr.ErrAuthentication, + }, + { + desc: "assign users with invalid domainID", + token: accessToken, + domainID: inValid, + relation: auth.ViewerRelation, + checkPolicyReq: auth.PolicyReq{ + Domain: groupName, + Subject: "testID", + SubjectType: auth.UserType, + SubjectKind: auth.TokenKind, + Object: inValid, + ObjectKind: "", + ObjectType: auth.DomainType, + Permission: auth.SharePermission, + }, + checkPolicyReq1: auth.PolicyReq{ + Domain: groupName, + Subject: "testID", + SubjectType: auth.UserType, + SubjectKind: auth.TokenKind, + Object: inValid, + ObjectKind: "", + ObjectType: auth.DomainType, + Permission: auth.ViewPermission, + }, + checkPolicyErr1: svcerr.ErrAuthorization, + err: svcerr.ErrAuthorization, + }, + { + desc: "assign users with invalid userIDs", + token: accessToken, + userIDs: []string{inValid}, + domainID: validID, + relation: auth.ViewerRelation, + checkPolicyReq: auth.PolicyReq{ + Domain: groupName, + Subject: "testID", + SubjectType: auth.UserType, + SubjectKind: auth.TokenKind, + Object: validID, + ObjectKind: "", + ObjectType: auth.DomainType, + Permission: auth.SharePermission, + }, + checkPolicyReq1: auth.PolicyReq{ + Domain: groupName, + Subject: "testID", + SubjectType: auth.UserType, + SubjectKind: auth.TokenKind, + Object: validID, + ObjectKind: "", + ObjectType: auth.DomainType, + Permission: auth.ViewPermission, + }, + checkPolicyReq2: auth.PolicyReq{ + Subject: inValid, + SubjectType: auth.UserType, + SubjectKind: "", + Object: auth.MagistralaObject, + ObjectKind: "", + ObjectType: auth.PlatformType, + Permission: auth.MembershipPermission, + }, + checkPolicyErr2: svcerr.ErrMalformedEntity, + err: svcerr.ErrMalformedEntity, + }, + { + desc: "assign users with failed to add policies to agent", + token: accessToken, + domainID: validID, + userIDs: []string{validID}, + relation: auth.ViewerRelation, + checkPolicyReq: auth.PolicyReq{ + Domain: groupName, + Subject: "testID", + SubjectType: auth.UserType, + SubjectKind: auth.TokenKind, + Object: validID, + ObjectKind: "", + ObjectType: auth.DomainType, + Permission: auth.SharePermission, + }, + checkPolicyReq1: auth.PolicyReq{ + Domain: groupName, + Subject: "testID", + SubjectType: auth.UserType, + SubjectKind: auth.TokenKind, + Object: validID, + ObjectKind: "", + ObjectType: auth.DomainType, + Permission: auth.ViewPermission, + }, + checkPolicyReq2: auth.PolicyReq{ + Subject: validID, + SubjectType: auth.UserType, + SubjectKind: "", + Object: auth.MagistralaObject, + ObjectKind: "", + ObjectType: auth.PlatformType, + Permission: auth.MembershipPermission, + }, + addPoliciesErr: svcerr.ErrAuthorization, + err: errAddPolicies, + }, + { + desc: "assign users with failed to save policies to domain", + token: accessToken, + domainID: validID, + userIDs: []string{validID}, + relation: auth.ViewerRelation, + checkPolicyReq: auth.PolicyReq{ + Domain: groupName, + Subject: "testID", + SubjectType: auth.UserType, + SubjectKind: auth.TokenKind, + Object: validID, + ObjectKind: "", + ObjectType: auth.DomainType, + Permission: auth.SharePermission, + }, + checkPolicyReq1: auth.PolicyReq{ + Domain: groupName, + Subject: "testID", + SubjectType: auth.UserType, + SubjectKind: auth.TokenKind, + Object: validID, + ObjectKind: "", + ObjectType: auth.DomainType, + Permission: auth.ViewPermission, + }, + checkPolicyReq2: auth.PolicyReq{ + Subject: validID, + SubjectType: auth.UserType, + SubjectKind: "", + Object: auth.MagistralaObject, + ObjectKind: "", + ObjectType: auth.PlatformType, + Permission: auth.MembershipPermission, + }, + savePoliciesErr: repoerr.ErrCreateEntity, + err: errAddPolicies, + }, + { + desc: "assign users with failed to save policies to domain and failed to delete", + token: accessToken, + domainID: validID, + userIDs: []string{validID}, + relation: auth.ViewerRelation, + checkPolicyReq: auth.PolicyReq{ + Domain: groupName, + Subject: "testID", + SubjectType: auth.UserType, + SubjectKind: auth.TokenKind, + Object: validID, + ObjectKind: "", + ObjectType: auth.DomainType, + Permission: auth.SharePermission, + }, + checkPolicyReq1: auth.PolicyReq{ + Domain: groupName, + Subject: "testID", + SubjectType: auth.UserType, + SubjectKind: auth.TokenKind, + Object: validID, + ObjectKind: "", + ObjectType: auth.DomainType, + Permission: auth.ViewPermission, + }, + checkPolicyReq2: auth.PolicyReq{ + Subject: validID, + SubjectType: auth.UserType, + SubjectKind: "", + Object: auth.MagistralaObject, + ObjectKind: "", + ObjectType: auth.PlatformType, + Permission: auth.MembershipPermission, + }, + savePoliciesErr: repoerr.ErrCreateEntity, + deletePoliciesErr: errors.ErrMalformedEntity, + err: errAddPolicies, + }, + } + + for _, tc := range cases { + repoCall := drepo.On("RetrieveByID", mock.Anything, groupName).Return(auth.Domain{}, nil) + repoCall1 := prepo.On("CheckPolicy", mock.Anything, tc.checkPolicyReq).Return(tc.checkpolicyErr) + repoCall2 := prepo.On("CheckPolicy", mock.Anything, tc.checkPolicyReq1).Return(tc.checkPolicyErr1) + repoCall3 := prepo.On("CheckPolicy", mock.Anything, tc.checkPolicyReq2).Return(tc.checkPolicyErr2) + repoCall4 := prepo.On("AddPolicies", mock.Anything, mock.Anything).Return(tc.addPoliciesErr) + repoCall5 := drepo.On("SavePolicies", mock.Anything, mock.Anything, mock.Anything).Return(tc.savePoliciesErr) + repoCall6 := prepo.On("DeletePolicies", mock.Anything, mock.Anything).Return(tc.deletePoliciesErr) + err := svc.AssignUsers(context.Background(), tc.token, tc.domainID, tc.userIDs, tc.relation) + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s expected %s got %s\n", tc.desc, tc.err, err)) + repoCall.Unset() + repoCall1.Unset() + repoCall2.Unset() + repoCall3.Unset() + repoCall4.Unset() + repoCall5.Unset() + repoCall6.Unset() + } +} + +func TestUnassignUsers(t *testing.T) { + svc, accessToken := newService() + + cases := []struct { + desc string + token string + domainID string + checkPolicyReq auth.PolicyReq + checkPolicyReq1 auth.PolicyReq + checkPolicyErr error + checkPolicyErr1 error + deletePoliciesErr error + deletePoliciesErr1 error + err error + }{ + { + desc: "unassign users successfully", + token: accessToken, + domainID: validID, + checkPolicyReq: auth.PolicyReq{ + Domain: groupName, + Subject: "testID", + SubjectType: auth.UserType, + SubjectKind: auth.TokenKind, + Object: validID, + ObjectKind: "", + ObjectType: auth.DomainType, + Permission: auth.SharePermission, + }, + checkPolicyReq1: auth.PolicyReq{ + Domain: groupName, + Subject: "testID", + SubjectType: auth.UserType, + SubjectKind: auth.TokenKind, + Object: validID, + ObjectKind: "", + ObjectType: auth.DomainType, + Permission: auth.AdminPermission, + }, + err: nil, + }, + { + desc: "unassign users with invalid token", + token: inValidToken, + domainID: validID, + checkPolicyReq: auth.PolicyReq{ + Domain: groupName, + Subject: "testID", + SubjectType: auth.UserType, + SubjectKind: auth.TokenKind, + Object: validID, + ObjectKind: "", + ObjectType: auth.DomainType, + Permission: auth.SharePermission, + }, + checkPolicyReq1: auth.PolicyReq{ + Domain: groupName, + Subject: "testID", + SubjectType: auth.UserType, + SubjectKind: auth.TokenKind, + Object: validID, + ObjectKind: "", + ObjectType: auth.DomainType, + Permission: auth.AdminPermission, + }, + err: svcerr.ErrAuthentication, + }, + { + desc: "unassign users with invalid domainID", + token: accessToken, + domainID: inValid, + checkPolicyReq: auth.PolicyReq{ + Domain: groupName, + Subject: "testID", + SubjectType: auth.UserType, + SubjectKind: auth.TokenKind, + Object: inValid, + ObjectKind: "", + ObjectType: auth.DomainType, + Permission: auth.SharePermission, + }, + checkPolicyReq1: auth.PolicyReq{ + Domain: groupName, + Subject: "testID", + SubjectType: auth.UserType, + SubjectKind: auth.TokenKind, + Object: inValid, + ObjectKind: "", + ObjectType: auth.DomainType, + Permission: auth.AdminPermission, + }, + checkPolicyErr1: svcerr.ErrAuthorization, + err: svcerr.ErrAuthorization, + }, + { + desc: "unassign users with failed to delete policies from agant", + token: accessToken, + domainID: validID, + checkPolicyReq: auth.PolicyReq{ + Domain: groupName, + Subject: "testID", + SubjectType: auth.UserType, + SubjectKind: auth.TokenKind, + Object: validID, + ObjectKind: "", + ObjectType: auth.DomainType, + Permission: auth.SharePermission, + }, + checkPolicyReq1: auth.PolicyReq{ + Domain: groupName, + Subject: "testID", + SubjectType: auth.UserType, + SubjectKind: auth.TokenKind, + Object: validID, + ObjectKind: "", + ObjectType: auth.DomainType, + Permission: auth.AdminPermission, + }, + deletePoliciesErr: errors.ErrMalformedEntity, + err: errors.ErrMalformedEntity, + }, + { + desc: "unassign users with failed to delete policies from domain", + token: accessToken, + domainID: validID, + checkPolicyReq: auth.PolicyReq{ + Domain: groupName, + Subject: "testID", + SubjectType: auth.UserType, + SubjectKind: auth.TokenKind, + Object: validID, + ObjectKind: "", + ObjectType: auth.DomainType, + Permission: auth.SharePermission, + }, + checkPolicyReq1: auth.PolicyReq{ + Domain: groupName, + Subject: "testID", + SubjectType: auth.UserType, + SubjectKind: auth.TokenKind, + Object: validID, + ObjectKind: "", + ObjectType: auth.DomainType, + Permission: auth.AdminPermission, + }, + deletePoliciesErr1: errors.ErrMalformedEntity, + err: errors.ErrMalformedEntity, + }, + } + + for _, tc := range cases { + repoCall := drepo.On("RetrieveByID", mock.Anything, mock.Anything).Return(auth.Domain{}, nil) + repoCall1 := prepo.On("CheckPolicy", mock.Anything, tc.checkPolicyReq).Return(tc.checkPolicyErr) + repoCall2 := prepo.On("CheckPolicy", mock.Anything, tc.checkPolicyReq1).Return(tc.checkPolicyErr1) + repoCall3 := prepo.On("DeletePolicies", mock.Anything, mock.Anything, mock.Anything).Return(tc.deletePoliciesErr) + repoCall4 := drepo.On("DeletePolicies", mock.Anything, mock.Anything, mock.Anything).Return(tc.deletePoliciesErr1) + err := svc.UnassignUsers(context.Background(), tc.token, tc.domainID, []string{" ", " "}, auth.AdministratorRelation) + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s expected %s got %s\n", tc.desc, tc.err, err)) + repoCall.Unset() + repoCall1.Unset() + repoCall2.Unset() + repoCall3.Unset() + repoCall4.Unset() + } +} + +func TestListUsersDomains(t *testing.T) { + svc, accessToken := newService() + + cases := []struct { + desc string + token string + userID string + page auth.Page + retreiveByIDErr error + checkPolicyErr error + listDomainErr error + err error + }{ + { + desc: "list users domains successfully", + token: accessToken, + userID: validID, + page: auth.Page{ + Offset: 0, + Limit: 10, + Permission: auth.AdminPermission, + }, + err: nil, + }, + { + desc: "list users domains successfully was admin", + token: accessToken, + userID: email, + page: auth.Page{ + Offset: 0, + Limit: 10, + Permission: auth.AdminPermission, + }, + err: nil, + }, + { + desc: "list users domains with invalid token", + token: inValidToken, + userID: validID, + page: auth.Page{ + Offset: 0, + Limit: 10, + Permission: auth.AdminPermission, + }, + err: svcerr.ErrAuthentication, + }, + { + desc: "list users domains with invalid domainID", + token: accessToken, + userID: inValid, + page: auth.Page{ + Offset: 0, + Limit: 10, + Permission: auth.AdminPermission, + }, + checkPolicyErr: svcerr.ErrAuthorization, + err: svcerr.ErrAuthorization, + }, + { + desc: "list users domains with repository error on list domains", + token: accessToken, + userID: validID, + page: auth.Page{ + Offset: 0, + Limit: 10, + Permission: auth.AdminPermission, + }, + listDomainErr: errors.ErrNotFound, + err: svcerr.ErrViewEntity, + }, + } + + for _, tc := range cases { + repoCall := prepo.On("CheckPolicy", mock.Anything, mock.Anything).Return(tc.checkPolicyErr) + repoCall1 := drepo.On("ListDomains", mock.Anything, mock.Anything).Return(auth.DomainsPage{}, tc.listDomainErr) + _, err := svc.ListUserDomains(context.Background(), tc.token, tc.userID, tc.page) + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s expected %s got %s\n", tc.desc, tc.err, err)) + repoCall.Unset() + repoCall1.Unset() + } +} + +func TestEncodeDomainUserID(t *testing.T) { + cases := []struct { + desc string + domainID string + userID string + response string + }{ + { + desc: "encode domain user id successfully", + domainID: validID, + userID: validID, + response: validID + "_" + validID, + }, + { + desc: "encode domain user id with empty userID", + domainID: validID, + userID: "", + response: "", + }, + { + desc: "encode domain user id with empty domain ID", + domainID: "", + userID: validID, + response: "", + }, + { + desc: "encode domain user id with empty domain ID and userID", + domainID: "", + userID: "", + response: "", + }, + } + + for _, tc := range cases { + ar := auth.EncodeDomainUserID(tc.domainID, tc.userID) + assert.Equal(t, tc.response, ar, fmt.Sprintf("%s expected %s got %s\n", tc.desc, tc.response, ar)) + } +} + +func TestDecodeDomainUserID(t *testing.T) { + cases := []struct { + desc string + domainUserID string + respDomainID string + respUserID string + }{ + { + desc: "decode domain user id successfully", + domainUserID: validID + "_" + validID, + respDomainID: validID, + respUserID: validID, + }, + { + desc: "decode domain user id with empty domainUserID", + domainUserID: "", + respDomainID: "", + respUserID: "", + }, + { + desc: "decode domain user id with empty UserID", + domainUserID: validID, + respDomainID: validID, + respUserID: "", + }, + { + desc: "decode domain user id with invalid domainuserId", + domainUserID: validID + "_" + validID + "_" + validID + "_" + validID, + respDomainID: "", + respUserID: "", + }, + } + + for _, tc := range cases { + ar, er := auth.DecodeDomainUserID(tc.domainUserID) + assert.Equal(t, tc.respUserID, er, fmt.Sprintf("%s expected %s got %s\n", tc.desc, tc.respUserID, er)) + assert.Equal(t, tc.respDomainID, ar, fmt.Sprintf("%s expected %s got %s\n", tc.desc, tc.respDomainID, ar)) + } } diff --git a/bootstrap/api/endpoint_test.go b/bootstrap/api/endpoint_test.go index 2101f6c3da..0129494eb0 100644 --- a/bootstrap/api/endpoint_test.go +++ b/bootstrap/api/endpoint_test.go @@ -176,9 +176,9 @@ func dec(in []byte) ([]byte, error) { return in, nil } -func newService() (bootstrap.Service, *authmocks.Service, *sdkmocks.SDK) { +func newService() (bootstrap.Service, *authmocks.AuthClient, *sdkmocks.SDK) { things := mocks.NewConfigsRepository() - auth := new(authmocks.Service) + auth := new(authmocks.AuthClient) sdk := new(sdkmocks.SDK) return bootstrap.New(auth, things, sdk, encKey), auth, sdk @@ -720,7 +720,7 @@ func TestUpdateConnections(t *testing.T) { repoCall1 := sdk.On("Thing", mock.Anything, mock.Anything).Return(mgsdk.Thing{ID: c.ThingID, Credentials: mgsdk.Credentials{Secret: c.ThingKey}}, nil) repoCall2 := sdk.On("Channel", mock.Anything, mock.Anything).Return(mgsdk.Channel{}, nil) repoCall3 := auth.On("DeletePolicy", mock.Anything, mock.Anything).Return(&magistrala.DeletePolicyRes{Deleted: true}, nil) - repoCall4 := auth.On("AddPolicy", mock.Anything, mock.Anything).Return(&magistrala.AddPolicyRes{Authorized: true}, nil) + repoCall4 := auth.On("AddPolicy", mock.Anything, mock.Anything).Return(&magistrala.AddPolicyRes{Added: true}, nil) req := testRequest{ client: bs.Client(), method: http.MethodPut, diff --git a/bootstrap/events/producer/streams_test.go b/bootstrap/events/producer/streams_test.go index d1feb8ce95..ea2abc0670 100644 --- a/bootstrap/events/producer/streams_test.go +++ b/bootstrap/events/producer/streams_test.go @@ -77,9 +77,9 @@ var ( } ) -func newService(t *testing.T, url string) (bootstrap.Service, *authmocks.Service, *sdkmocks.SDK) { +func newService(t *testing.T, url string) (bootstrap.Service, *authmocks.AuthClient, *sdkmocks.SDK) { things := mocks.NewConfigsRepository() - auth := new(authmocks.Service) + auth := new(authmocks.AuthClient) sdk := new(sdkmocks.SDK) svc := bootstrap.New(auth, things, sdk, encKey) diff --git a/bootstrap/service_test.go b/bootstrap/service_test.go index 84b330642c..fb6f65c010 100644 --- a/bootstrap/service_test.go +++ b/bootstrap/service_test.go @@ -56,9 +56,9 @@ var ( } ) -func newService() (bootstrap.Service, *authmocks.Service, *sdkmocks.SDK) { +func newService() (bootstrap.Service, *authmocks.AuthClient, *sdkmocks.SDK) { things := mocks.NewConfigsRepository() - auth := new(authmocks.Service) + auth := new(authmocks.AuthClient) sdk := new(sdkmocks.SDK) return bootstrap.New(auth, things, sdk, encKey), auth, sdk diff --git a/certs/service_test.go b/certs/service_test.go index 9efbd7d210..cb10740278 100644 --- a/certs/service_test.go +++ b/certs/service_test.go @@ -42,8 +42,8 @@ const ( instanceID = "5de9b29a-feb9-11ed-be56-0242ac120002" ) -func newService(t *testing.T) (certs.Service, *authmocks.Service, *sdkmocks.SDK) { - auth := new(authmocks.Service) +func newService(t *testing.T) (certs.Service, *authmocks.AuthClient, *sdkmocks.SDK) { + auth := new(authmocks.AuthClient) sdk := new(sdkmocks.SDK) repo := mocks.NewCertsRepository() diff --git a/cmd/users/main.go b/cmd/users/main.go index 1b53de1f10..938833ba24 100644 --- a/cmd/users/main.go +++ b/cmd/users/main.go @@ -297,7 +297,7 @@ func createAdminPolicy(ctx context.Context, clientID string, authClient magistra if err != nil { return err } - if !addPolicyRes.Authorized { + if !addPolicyRes.Added { return errors.ErrAuthorization } } diff --git a/consumers/notifiers/api/endpoint_test.go b/consumers/notifiers/api/endpoint_test.go index 7d536b563a..aab51f8d83 100644 --- a/consumers/notifiers/api/endpoint_test.go +++ b/consumers/notifiers/api/endpoint_test.go @@ -67,8 +67,8 @@ func (tr testRequest) make() (*http.Response, error) { return tr.client.Do(req) } -func newService() (notifiers.Service, *authmocks.Service) { - auth := new(authmocks.Service) +func newService() (notifiers.Service, *authmocks.AuthClient) { + auth := new(authmocks.AuthClient) repo := mocks.NewRepo(make(map[string]notifiers.Subscription)) idp := uuid.NewMock() notif := mocks.NewNotifier() diff --git a/consumers/notifiers/service_test.go b/consumers/notifiers/service_test.go index 32f928f3c9..1cd8546e75 100644 --- a/consumers/notifiers/service_test.go +++ b/consumers/notifiers/service_test.go @@ -29,9 +29,9 @@ const ( validID = "d4ebb847-5d0e-4e46-bdd9-b6aceaaa3a22" ) -func newService() (notifiers.Service, *authmocks.Service) { +func newService() (notifiers.Service, *authmocks.AuthClient) { repo := mocks.NewRepo(make(map[string]notifiers.Subscription)) - auth := new(authmocks.Service) + auth := new(authmocks.AuthClient) notifier := mocks.NewNotifier() idp := uuid.NewMock() from := "exampleFrom" diff --git a/http/api/endpoint_test.go b/http/api/endpoint_test.go index 90cfcd9752..325e4ba100 100644 --- a/http/api/endpoint_test.go +++ b/http/api/endpoint_test.go @@ -73,7 +73,7 @@ func (tr testRequest) make() (*http.Response, error) { } func TestPublish(t *testing.T) { - auth := new(authmocks.Service) + auth := new(authmocks.AuthClient) chanID := "1" ctSenmlJSON := "application/senml+json" ctSenmlCBOR := "application/senml+cbor" diff --git a/internal/groups/service_test.go b/internal/groups/service_test.go index 481482b5f4..c6a3ecf70f 100644 --- a/internal/groups/service_test.go +++ b/internal/groups/service_test.go @@ -47,7 +47,7 @@ var ( func TestCreateGroup(t *testing.T) { repo := new(mocks.Repository) - authsvc := new(authmocks.Service) + authsvc := new(authmocks.AuthClient) svc := groups.NewService(repo, idProvider, authsvc) cases := []struct { @@ -88,7 +88,7 @@ func TestCreateGroup(t *testing.T) { Owner: testsutil.GenerateUUID(t), }, addPolResp: &magistrala.AddPoliciesRes{ - Authorized: true, + Added: true, }, }, { @@ -183,7 +183,7 @@ func TestCreateGroup(t *testing.T) { Parent: testsutil.GenerateUUID(t), }, addPolResp: &magistrala.AddPoliciesRes{ - Authorized: true, + Added: true, }, }, { @@ -210,7 +210,7 @@ func TestCreateGroup(t *testing.T) { Parent: testsutil.GenerateUUID(t), }, addPolResp: &magistrala.AddPoliciesRes{ - Authorized: true, + Added: true, }, err: errors.ErrAuthorization, }, @@ -299,7 +299,7 @@ func TestCreateGroup(t *testing.T) { func TestViewGroup(t *testing.T) { repo := new(mocks.Repository) - authsvc := new(authmocks.Service) + authsvc := new(authmocks.AuthClient) svc := groups.NewService(repo, idProvider, authsvc) cases := []struct { @@ -367,7 +367,7 @@ func TestViewGroup(t *testing.T) { func TestViewGroupPerms(t *testing.T) { repo := new(mocks.Repository) - authsvc := new(authmocks.Service) + authsvc := new(authmocks.AuthClient) svc := groups.NewService(repo, idProvider, authsvc) cases := []struct { @@ -451,7 +451,7 @@ func TestViewGroupPerms(t *testing.T) { func TestUpdateGroup(t *testing.T) { repo := new(mocks.Repository) - authsvc := new(authmocks.Service) + authsvc := new(authmocks.AuthClient) svc := groups.NewService(repo, idProvider, authsvc) cases := []struct { @@ -528,7 +528,7 @@ func TestUpdateGroup(t *testing.T) { func TestEnableGroup(t *testing.T) { repo := new(mocks.Repository) - authsvc := new(authmocks.Service) + authsvc := new(authmocks.AuthClient) svc := groups.NewService(repo, idProvider, authsvc) cases := []struct { @@ -628,7 +628,7 @@ func TestEnableGroup(t *testing.T) { func TestDisableGroup(t *testing.T) { repo := new(mocks.Repository) - authsvc := new(authmocks.Service) + authsvc := new(authmocks.AuthClient) svc := groups.NewService(repo, idProvider, authsvc) cases := []struct { @@ -728,7 +728,7 @@ func TestDisableGroup(t *testing.T) { func TestListMembers(t *testing.T) { repo := new(mocks.Repository) - authsvc := new(authmocks.Service) + authsvc := new(authmocks.AuthClient) svc := groups.NewService(repo, idProvider, authsvc) cases := []struct { @@ -864,7 +864,7 @@ func TestListMembers(t *testing.T) { func TestListGroups(t *testing.T) { repo := new(mocks.Repository) - authsvc := new(authmocks.Service) + authsvc := new(authmocks.AuthClient) svc := groups.NewService(repo, idProvider, authsvc) cases := []struct { @@ -1616,7 +1616,7 @@ func TestListGroups(t *testing.T) { func TestAssign(t *testing.T) { repo := new(mocks.Repository) - authsvc := new(authmocks.Service) + authsvc := new(authmocks.AuthClient) svc := groups.NewService(repo, idProvider, authsvc) cases := []struct { @@ -1656,7 +1656,7 @@ func TestAssign(t *testing.T) { Authorized: true, }, addPoliciesRes: &magistrala.AddPoliciesRes{ - Authorized: true, + Added: true, }, }, { @@ -1674,7 +1674,7 @@ func TestAssign(t *testing.T) { Authorized: true, }, addPoliciesRes: &magistrala.AddPoliciesRes{ - Authorized: true, + Added: true, }, }, { @@ -1699,7 +1699,7 @@ func TestAssign(t *testing.T) { }, }, addPoliciesRes: &magistrala.AddPoliciesRes{ - Authorized: true, + Added: true, }, repoParentGroupErr: nil, }, @@ -1718,7 +1718,7 @@ func TestAssign(t *testing.T) { Authorized: true, }, addPoliciesRes: &magistrala.AddPoliciesRes{ - Authorized: true, + Added: true, }, }, { @@ -1804,7 +1804,7 @@ func TestAssign(t *testing.T) { }, }, addPoliciesRes: &magistrala.AddPoliciesRes{ - Authorized: false, + Added: false, }, addPoliciesErr: errors.ErrAuthorization, err: errors.ErrAuthorization, @@ -1831,7 +1831,7 @@ func TestAssign(t *testing.T) { }, }, addPoliciesRes: &magistrala.AddPoliciesRes{ - Authorized: true, + Added: true, }, repoParentGroupErr: errors.ErrConflict, err: errors.ErrConflict, @@ -1858,7 +1858,7 @@ func TestAssign(t *testing.T) { }, }, addPoliciesRes: &magistrala.AddPoliciesRes{ - Authorized: true, + Added: true, }, deleteParentPoliciesRes: &magistrala.DeletePoliciesRes{ Deleted: false, @@ -1926,7 +1926,7 @@ func TestAssign(t *testing.T) { Authorized: true, }, addPoliciesRes: &magistrala.AddPoliciesRes{ - Authorized: false, + Added: false, }, addPoliciesErr: errors.ErrAuthorization, err: errors.ErrAuthorization, @@ -2025,7 +2025,7 @@ func TestAssign(t *testing.T) { func TestUnassign(t *testing.T) { repo := new(mocks.Repository) - authsvc := new(authmocks.Service) + authsvc := new(authmocks.AuthClient) svc := groups.NewService(repo, idProvider, authsvc) cases := []struct { @@ -2271,7 +2271,7 @@ func TestUnassign(t *testing.T) { }, repoParentGroupErr: errors.ErrConflict, addParentPoliciesRes: &magistrala.AddPoliciesRes{ - Authorized: false, + Added: false, }, addParentPoliciesErr: errors.ErrAuthorization, err: errors.ErrConflict, @@ -2434,7 +2434,7 @@ func TestUnassign(t *testing.T) { func TestDeleteGroup(t *testing.T) { repo := new(mocks.Repository) - authsvc := new(authmocks.Service) + authsvc := new(authmocks.AuthClient) svc := groups.NewService(repo, idProvider, authsvc) cases := []struct { diff --git a/invitations/service_test.go b/invitations/service_test.go index c1c1da521b..87fda2ef7e 100644 --- a/invitations/service_test.go +++ b/invitations/service_test.go @@ -32,7 +32,7 @@ var ( func TestSendInvitation(t *testing.T) { repo := new(mocks.Repository) - authsvc := new(authmocks.Service) + authsvc := new(authmocks.AuthClient) svc := invitations.NewService(repo, authsvc, nil) cases := []struct { @@ -187,7 +187,7 @@ func TestSendInvitation(t *testing.T) { func TestViewInvitation(t *testing.T) { repo := new(mocks.Repository) - authsvc := new(authmocks.Service) + authsvc := new(authmocks.AuthClient) svc := invitations.NewService(repo, authsvc, nil) validInvitation := invitations.Invitation{ @@ -364,7 +364,7 @@ func TestViewInvitation(t *testing.T) { func TestListInvitations(t *testing.T) { repo := new(mocks.Repository) - authsvc := new(authmocks.Service) + authsvc := new(authmocks.AuthClient) svc := invitations.NewService(repo, authsvc, nil) validPage := invitations.Page{ @@ -542,7 +542,7 @@ func TestListInvitations(t *testing.T) { func TestAcceptInvitation(t *testing.T) { repo := new(mocks.Repository) - authsvc := new(authmocks.Service) + authsvc := new(authmocks.AuthClient) svc := invitations.NewService(repo, authsvc, nil) userID := testsutil.GenerateUUID(t) @@ -615,7 +615,7 @@ func TestAcceptInvitation(t *testing.T) { func TestDeleteInvitation(t *testing.T) { repo := new(mocks.Repository) - authsvc := new(authmocks.Service) + authsvc := new(authmocks.AuthClient) svc := invitations.NewService(repo, authsvc, nil) cases := []struct { diff --git a/mqtt/handler_test.go b/mqtt/handler_test.go index d53d09788b..c46219cb01 100644 --- a/mqtt/handler_test.go +++ b/mqtt/handler_test.go @@ -441,12 +441,12 @@ func TestDisconnect(t *testing.T) { } } -func newHandler() (session.Handler, *authmocks.Service) { +func newHandler() (session.Handler, *authmocks.AuthClient) { logger, err := mglog.New(&logBuffer, "debug") if err != nil { log.Fatalf("failed to create logger: %s", err) } - auth := new(authmocks.Service) + auth := new(authmocks.AuthClient) eventStore := mocks.NewEventStore() return mqtt.NewHandler(mocks.NewPublisher(), eventStore, logger, auth), auth } diff --git a/pkg/sdk/go/certs_test.go b/pkg/sdk/go/certs_test.go index 04ede686fb..742f8a0ba0 100644 --- a/pkg/sdk/go/certs_test.go +++ b/pkg/sdk/go/certs_test.go @@ -37,7 +37,7 @@ var ( cfgSignHoursValid = "24h" ) -func setupCerts() (*httptest.Server, *authmocks.Service, *thmocks.Repository, error) { +func setupCerts() (*httptest.Server, *authmocks.AuthClient, *thmocks.Repository, error) { server, trepo, _, auth, _ := setupThings() config := sdk.Config{ ThingsURL: server.URL, diff --git a/pkg/sdk/go/channels_test.go b/pkg/sdk/go/channels_test.go index 7cc2bad9fb..b4232344f5 100644 --- a/pkg/sdk/go/channels_test.go +++ b/pkg/sdk/go/channels_test.go @@ -32,12 +32,12 @@ import ( "github.com/stretchr/testify/mock" ) -func setupChannels() (*httptest.Server, *mocks.Repository, *authmocks.Service) { +func setupChannels() (*httptest.Server, *mocks.Repository, *authmocks.AuthClient) { cRepo := new(thmocks.Repository) grepo := new(mocks.Repository) thingCache := new(thmocks.Cache) - auth := new(authmocks.Service) + auth := new(authmocks.AuthClient) csvc := things.NewService(auth, cRepo, grepo, thingCache, idProvider) gsvc := groups.NewService(grepo, idProvider, auth) @@ -148,7 +148,7 @@ func TestCreateChannel(t *testing.T) { } for _, tc := range cases { repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: validID, DomainId: testsutil.GenerateUUID(t)}, nil) - repoCall1 := auth.On("AddPolicies", mock.Anything, mock.Anything).Return(&magistrala.AddPoliciesRes{Authorized: true}, nil) + repoCall1 := auth.On("AddPolicies", mock.Anything, mock.Anything).Return(&magistrala.AddPoliciesRes{Added: true}, nil) repoCall2 := auth.On("Authorize", mock.Anything, mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: true}, nil) repoCall3 := grepo.On("Save", mock.Anything, mock.Anything).Return(convertChannel(sdk.Channel{}), tc.err) rChannel, err := mgsdk.CreateChannel(tc.channel, validToken) diff --git a/pkg/sdk/go/consumers_test.go b/pkg/sdk/go/consumers_test.go index 5a22d8686b..70e1de4825 100644 --- a/pkg/sdk/go/consumers_test.go +++ b/pkg/sdk/go/consumers_test.go @@ -34,9 +34,9 @@ var ( exampleUser1 = "email1@example.com" ) -func setupSubscriptions() (*httptest.Server, *authmocks.Service) { +func setupSubscriptions() (*httptest.Server, *authmocks.AuthClient) { repo := mocks.NewRepo(make(map[string]notifiers.Subscription)) - auth := new(authmocks.Service) + auth := new(authmocks.AuthClient) notifier := mocks.NewNotifier() idp := uuid.NewMock() from := "exampleFrom" diff --git a/pkg/sdk/go/groups_test.go b/pkg/sdk/go/groups_test.go index 62760e1d8d..9e251cba1a 100644 --- a/pkg/sdk/go/groups_test.go +++ b/pkg/sdk/go/groups_test.go @@ -30,11 +30,11 @@ import ( "github.com/stretchr/testify/mock" ) -func setupGroups() (*httptest.Server, *mocks.Repository, *authmocks.Service) { +func setupGroups() (*httptest.Server, *mocks.Repository, *authmocks.AuthClient) { crepo := new(umocks.Repository) grepo := new(mocks.Repository) - auth := new(authmocks.Service) + auth := new(authmocks.AuthClient) csvc := users.NewService(crepo, auth, emailer, phasher, idProvider, passRegex, true) gsvc := groups.NewService(grepo, idProvider, auth) @@ -146,7 +146,7 @@ func TestCreateGroup(t *testing.T) { } for _, tc := range cases { repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: validID, DomainId: testsutil.GenerateUUID(t)}, nil) - repoCall1 := auth.On("AddPolicies", mock.Anything, mock.Anything).Return(&magistrala.AddPoliciesRes{Authorized: true}, nil) + repoCall1 := auth.On("AddPolicies", mock.Anything, mock.Anything).Return(&magistrala.AddPoliciesRes{Added: true}, nil) repoCall2 := auth.On("Authorize", mock.Anything, mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: true}, nil) repoCall3 := grepo.On("Save", mock.Anything, mock.Anything).Return(convertGroup(sdk.Group{}), tc.err) rGroup, err := mgsdk.CreateGroup(tc.group, tc.token) diff --git a/pkg/sdk/go/message_test.go b/pkg/sdk/go/message_test.go index 49061b35a3..474c04e5c6 100644 --- a/pkg/sdk/go/message_test.go +++ b/pkg/sdk/go/message_test.go @@ -24,8 +24,8 @@ import ( "github.com/stretchr/testify/mock" ) -func setupMessages() (*httptest.Server, *authmocks.Service) { - auth := new(authmocks.Service) +func setupMessages() (*httptest.Server, *authmocks.AuthClient) { + auth := new(authmocks.AuthClient) pub := mocks.NewPublisher() handler := adapter.NewHandler(pub, mglog.NewMock(), auth) diff --git a/pkg/sdk/go/things_test.go b/pkg/sdk/go/things_test.go index f0f64fec46..17fa2f8973 100644 --- a/pkg/sdk/go/things_test.go +++ b/pkg/sdk/go/things_test.go @@ -30,12 +30,12 @@ import ( "github.com/stretchr/testify/mock" ) -func setupThings() (*httptest.Server, *mocks.Repository, *gmocks.Repository, *authmocks.Service, *mocks.Cache) { +func setupThings() (*httptest.Server, *mocks.Repository, *gmocks.Repository, *authmocks.AuthClient, *mocks.Cache) { cRepo := new(mocks.Repository) gRepo := new(gmocks.Repository) thingCache := new(mocks.Cache) - auth := new(authmocks.Service) + auth := new(authmocks.AuthClient) csvc := things.NewService(auth, cRepo, gRepo, thingCache, idProvider) gsvc := groups.NewService(gRepo, idProvider, auth) @@ -46,12 +46,12 @@ func setupThings() (*httptest.Server, *mocks.Repository, *gmocks.Repository, *au return httptest.NewServer(mux), cRepo, gRepo, auth, thingCache } -func setupThingsMinimal() (*httptest.Server, *authmocks.Service) { +func setupThingsMinimal() (*httptest.Server, *authmocks.AuthClient) { cRepo := new(mocks.Repository) gRepo := new(gmocks.Repository) thingCache := new(mocks.Cache) - auth := new(authmocks.Service) + auth := new(authmocks.AuthClient) csvc := things.NewService(auth, cRepo, gRepo, thingCache, idProvider) gsvc := groups.NewService(gRepo, idProvider, auth) @@ -187,7 +187,7 @@ func TestCreateThing(t *testing.T) { } for _, tc := range cases { repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: validID, DomainId: testsutil.GenerateUUID(t)}, nil) - repoCall1 := auth.On("AddPolicies", mock.Anything, mock.Anything).Return(&magistrala.AddPoliciesRes{Authorized: true}, nil) + repoCall1 := auth.On("AddPolicies", mock.Anything, mock.Anything).Return(&magistrala.AddPoliciesRes{Added: true}, nil) repoCall2 := auth.On("Authorize", mock.Anything, mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: true}, nil) repoCall3 := cRepo.On("Save", mock.Anything, mock.Anything).Return(convertThings(tc.response), tc.repoErr) rThing, err := mgsdk.CreateThing(tc.client, tc.token) @@ -275,7 +275,7 @@ func TestCreateThings(t *testing.T) { } for _, tc := range cases { repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: validID, DomainId: testsutil.GenerateUUID(t)}, nil) - repoCall1 := auth.On("AddPolicies", mock.Anything, mock.Anything).Return(&magistrala.AddPoliciesRes{Authorized: true}, nil) + repoCall1 := auth.On("AddPolicies", mock.Anything, mock.Anything).Return(&magistrala.AddPoliciesRes{Added: true}, nil) repoCall2 := auth.On("Authorize", mock.Anything, mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: true}, nil) repoCall3 := cRepo.On("Save", mock.Anything, mock.Anything).Return(convertThings(tc.response...), tc.err) if len(tc.things) > 0 { @@ -1263,11 +1263,11 @@ func TestShareThing(t *testing.T) { for _, tc := range cases { repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: validID, DomainId: testsutil.GenerateUUID(t)}, nil) repoCall1 := auth.On("Authorize", mock.Anything, mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: true}, tc.repoErr) - repoCall2 := auth.On("AddPolicies", mock.Anything, mock.Anything).Return(&magistrala.AddPoliciesRes{Authorized: true}, nil) + repoCall2 := auth.On("AddPolicies", mock.Anything, mock.Anything).Return(&magistrala.AddPoliciesRes{Added: true}, nil) if tc.token != validToken { repoCall1 = auth.On("Authorize", mock.Anything, mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: false}, errors.ErrAuthorization) } - repoCall3 := auth.On("AddPolicy", mock.Anything, mock.Anything).Return(&magistrala.AddPolicyRes{Authorized: true}, nil) + repoCall3 := auth.On("AddPolicy", mock.Anything, mock.Anything).Return(&magistrala.AddPolicyRes{Added: true}, nil) req := sdk.UsersRelationRequest{ Relation: "viewer", UserIDs: []string{tc.channelID}, diff --git a/pkg/sdk/go/users_test.go b/pkg/sdk/go/users_test.go index f65dc037fc..97a2e5a172 100644 --- a/pkg/sdk/go/users_test.go +++ b/pkg/sdk/go/users_test.go @@ -37,11 +37,11 @@ var ( wrongID = testsutil.GenerateUUID(&testing.T{}) ) -func setupUsers() (*httptest.Server, *umocks.Repository, *gmocks.Repository, *authmocks.Service) { +func setupUsers() (*httptest.Server, *umocks.Repository, *gmocks.Repository, *authmocks.AuthClient) { crepo := new(umocks.Repository) gRepo := new(gmocks.Repository) - auth := new(authmocks.Service) + auth := new(authmocks.AuthClient) csvc := users.NewService(crepo, auth, emailer, phasher, idProvider, passRegex, true) gsvc := groups.NewService(gRepo, idProvider, auth) @@ -186,7 +186,7 @@ func TestCreateClient(t *testing.T) { if tc.token != validToken { repoCall = auth.On("Identify", mock.Anything, mock.Anything).Return(&magistrala.IdentityRes{}, errors.ErrAuthentication) } - repoCall1 := auth.On("AddPolicies", mock.Anything, mock.Anything).Return(&magistrala.AddPoliciesRes{Authorized: true}, nil) + repoCall1 := auth.On("AddPolicies", mock.Anything, mock.Anything).Return(&magistrala.AddPoliciesRes{Added: true}, nil) repoCall2 := auth.On("DeletePolicies", mock.Anything, mock.Anything).Return(&magistrala.DeletePoliciesRes{Deleted: true}, nil) repoCall3 := crepo.On("Save", mock.Anything, mock.Anything).Return(convertClient(tc.response), tc.err) rClient, err := mgsdk.CreateUser(tc.client, tc.token) @@ -946,7 +946,7 @@ func TestUpdateClientRole(t *testing.T) { } repoCall1 := auth.On("Authorize", mock.Anything, mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: true}, nil) repoCall2 := auth.On("DeletePolicy", mock.Anything, mock.Anything).Return(&magistrala.DeletePolicyRes{Deleted: true}, nil) - repoCall3 := auth.On("AddPolicy", mock.Anything, mock.Anything).Return(&magistrala.AddPolicyRes{Authorized: true}, nil) + repoCall3 := auth.On("AddPolicy", mock.Anything, mock.Anything).Return(&magistrala.AddPolicyRes{Added: true}, nil) repoCall4 := crepo.On("UpdateRole", mock.Anything, mock.Anything).Return(convertClient(tc.response), tc.err) uClient, err := mgsdk.UpdateUserRole(tc.client, tc.token) assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected error %s, got %s", tc.desc, tc.err, err)) diff --git a/readers/api/endpoint_test.go b/readers/api/endpoint_test.go index aefd1853fa..6c77b46b2a 100644 --- a/readers/api/endpoint_test.go +++ b/readers/api/endpoint_test.go @@ -47,7 +47,7 @@ var ( sum float64 = 42 ) -func newServer(repo readers.MessageRepository, ac *authmocks.Service, tc *thmocks.ThingAuthzService) *httptest.Server { +func newServer(repo readers.MessageRepository, ac *authmocks.AuthClient, tc *thmocks.ThingAuthzService) *httptest.Server { mux := api.MakeHandler(repo, ac, tc, svcName, instanceID) return httptest.NewServer(mux) } @@ -126,7 +126,7 @@ func TestReadAll(t *testing.T) { } repo := mocks.NewMessageRepository(chanID, fromSenml(messages)) - auth := new(authmocks.Service) + auth := new(authmocks.AuthClient) tauth := new(thmocks.ThingAuthzService) ts := newServer(repo, auth, tauth) defer ts.Close() diff --git a/things/api/http/endpoints_test.go b/things/api/http/endpoints_test.go index 463160aabd..fc44c3e5ad 100644 --- a/things/api/http/endpoints_test.go +++ b/things/api/http/endpoints_test.go @@ -91,7 +91,7 @@ func toJSON(data interface{}) string { func newThingsServer() (*httptest.Server, *mocks.Service) { gRepo := new(gmocks.Repository) - auth := new(authmocks.Service) + auth := new(authmocks.AuthClient) svc := new(mocks.Service) gsvc := groups.NewService(gRepo, idProvider, auth) diff --git a/things/service.go b/things/service.go index 1a5c3b5d3b..3799c3b8cd 100644 --- a/things/service.go +++ b/things/service.go @@ -413,7 +413,7 @@ func (svc service) Share(ctx context.Context, token, id, relation string, userid if err != nil { return errors.Wrap(errAddPolicies, err) } - if !res.Authorized { + if !res.Added { return err } return nil diff --git a/things/service_test.go b/things/service_test.go index 8e92c29c45..798a197234 100644 --- a/things/service_test.go +++ b/things/service_test.go @@ -48,8 +48,8 @@ var ( errRemovePolicies = errors.New("failed to remove the policies") ) -func newService() (things.Service, *mocks.Repository, *authmocks.Service, *mocks.Cache) { - auth := new(authmocks.Service) +func newService() (things.Service, *mocks.Repository, *authmocks.AuthClient, *mocks.Cache) { + auth := new(authmocks.AuthClient) thingCache := new(mocks.Cache) idProvider := uuid.NewMock() cRepo := new(mocks.Repository) @@ -100,7 +100,7 @@ func TestCreateThings(t *testing.T) { }, token: validToken, authResponse: &magistrala.AuthorizeRes{Authorized: true}, - addPolicyResponse: &magistrala.AddPoliciesRes{Authorized: true}, + addPolicyResponse: &magistrala.AddPoliciesRes{Added: true}, err: nil, }, { @@ -113,7 +113,7 @@ func TestCreateThings(t *testing.T) { }, }, authResponse: &magistrala.AuthorizeRes{Authorized: true}, - addPolicyResponse: &magistrala.AddPoliciesRes{Authorized: true}, + addPolicyResponse: &magistrala.AddPoliciesRes{Added: true}, token: validToken, err: nil, }, @@ -128,7 +128,7 @@ func TestCreateThings(t *testing.T) { Status: mgclients.EnabledStatus, }, authResponse: &magistrala.AuthorizeRes{Authorized: true}, - addPolicyResponse: &magistrala.AddPoliciesRes{Authorized: true}, + addPolicyResponse: &magistrala.AddPoliciesRes{Added: true}, token: validToken, err: nil, }, @@ -144,7 +144,7 @@ func TestCreateThings(t *testing.T) { }, token: validToken, authResponse: &magistrala.AuthorizeRes{Authorized: true}, - addPolicyResponse: &magistrala.AddPoliciesRes{Authorized: true}, + addPolicyResponse: &magistrala.AddPoliciesRes{Added: true}, err: nil, }, { @@ -159,7 +159,7 @@ func TestCreateThings(t *testing.T) { }, token: validToken, authResponse: &magistrala.AuthorizeRes{Authorized: true}, - addPolicyResponse: &magistrala.AddPoliciesRes{Authorized: true}, + addPolicyResponse: &magistrala.AddPoliciesRes{Added: true}, err: nil, }, { @@ -173,7 +173,7 @@ func TestCreateThings(t *testing.T) { }, token: validToken, authResponse: &magistrala.AuthorizeRes{Authorized: true}, - addPolicyResponse: &magistrala.AddPoliciesRes{Authorized: true}, + addPolicyResponse: &magistrala.AddPoliciesRes{Added: true}, err: nil, }, { @@ -186,7 +186,7 @@ func TestCreateThings(t *testing.T) { }, token: validToken, authResponse: &magistrala.AuthorizeRes{Authorized: true}, - addPolicyResponse: &magistrala.AddPoliciesRes{Authorized: true}, + addPolicyResponse: &magistrala.AddPoliciesRes{Added: true}, err: nil, }, { @@ -200,7 +200,7 @@ func TestCreateThings(t *testing.T) { }, token: validToken, authResponse: &magistrala.AuthorizeRes{Authorized: true}, - addPolicyResponse: &magistrala.AddPoliciesRes{Authorized: true}, + addPolicyResponse: &magistrala.AddPoliciesRes{Added: true}, err: nil, }, { @@ -219,7 +219,7 @@ func TestCreateThings(t *testing.T) { }, token: validToken, authResponse: &magistrala.AuthorizeRes{Authorized: true}, - addPolicyResponse: &magistrala.AddPoliciesRes{Authorized: true}, + addPolicyResponse: &magistrala.AddPoliciesRes{Added: true}, err: nil, }, { @@ -233,7 +233,7 @@ func TestCreateThings(t *testing.T) { }, token: validToken, authResponse: &magistrala.AuthorizeRes{Authorized: true}, - addPolicyResponse: &magistrala.AddPoliciesRes{Authorized: true}, + addPolicyResponse: &magistrala.AddPoliciesRes{Added: true}, saveErr: repoerr.ErrMalformedEntity, err: repoerr.ErrCreateEntity, }, @@ -247,7 +247,7 @@ func TestCreateThings(t *testing.T) { }, token: validToken, authResponse: &magistrala.AuthorizeRes{Authorized: true}, - addPolicyResponse: &magistrala.AddPoliciesRes{Authorized: true}, + addPolicyResponse: &magistrala.AddPoliciesRes{Added: true}, saveErr: repoerr.ErrMissingSecret, err: repoerr.ErrCreateEntity, }, @@ -262,7 +262,7 @@ func TestCreateThings(t *testing.T) { }, token: validToken, authResponse: &magistrala.AuthorizeRes{Authorized: true}, - addPolicyResponse: &magistrala.AddPoliciesRes{Authorized: true}, + addPolicyResponse: &magistrala.AddPoliciesRes{Added: true}, err: svcerr.ErrInvalidStatus, }, { @@ -303,7 +303,7 @@ func TestCreateThings(t *testing.T) { }, token: validToken, authResponse: &magistrala.AuthorizeRes{Authorized: true}, - addPolicyResponse: &magistrala.AddPoliciesRes{Authorized: false}, + addPolicyResponse: &magistrala.AddPoliciesRes{Added: false}, addPolicyErr: svcerr.ErrInvalidPolicy, err: svcerr.ErrInvalidPolicy, }, @@ -1788,7 +1788,7 @@ func TestShare(t *testing.T) { clientID: clientID, identifyResponse: &magistrala.IdentityRes{Id: validID, DomainId: testsutil.GenerateUUID(t)}, authorizeResponse: &magistrala.AuthorizeRes{Authorized: true}, - addPoliciesResponse: &magistrala.AddPoliciesRes{Authorized: true}, + addPoliciesResponse: &magistrala.AddPoliciesRes{Added: true}, err: nil, }, { @@ -1824,7 +1824,7 @@ func TestShare(t *testing.T) { clientID: clientID, identifyResponse: &magistrala.IdentityRes{Id: validID, DomainId: testsutil.GenerateUUID(t)}, authorizeResponse: &magistrala.AuthorizeRes{Authorized: true}, - addPoliciesResponse: &magistrala.AddPoliciesRes{Authorized: false}, + addPoliciesResponse: &magistrala.AddPoliciesRes{Added: false}, err: nil, }, } diff --git a/twins/mocks/service.go b/twins/mocks/service.go index 6e7aef6e4e..c8a0d6fe6c 100644 --- a/twins/mocks/service.go +++ b/twins/mocks/service.go @@ -21,8 +21,8 @@ const publisher = "twins" var id = 0 // NewService use mock dependencies to create real twins service. -func NewService() (twins.Service, *authmocks.Service) { - auth := new(authmocks.Service) +func NewService() (twins.Service, *authmocks.AuthClient) { + auth := new(authmocks.AuthClient) twinsRepo := NewTwinRepository() twinCache := NewTwinCache() statesRepo := NewStateRepository() diff --git a/users/api/endpoint_test.go b/users/api/endpoint_test.go index 4a0d4d663c..742bddff7f 100644 --- a/users/api/endpoint_test.go +++ b/users/api/endpoint_test.go @@ -82,7 +82,7 @@ func (tr testRequest) make() (*http.Response, error) { func newUsersServer() (*httptest.Server, *mocks.Service) { gRepo := new(gmocks.Repository) - auth := new(authmocks.Service) + auth := new(authmocks.AuthClient) svc := new(mocks.Service) gsvc := groups.NewService(gRepo, idProvider, auth) diff --git a/users/service.go b/users/service.go index 7f01083e92..3e059a4a63 100644 --- a/users/service.go +++ b/users/service.go @@ -617,7 +617,7 @@ func (svc service) addClientPolicy(ctx context.Context, userID string, role mgcl if err != nil { return err } - if !resp.Authorized { + if !resp.Added { return errors.ErrAuthorization } return nil @@ -666,7 +666,7 @@ func (svc service) updateClientPolicy(ctx context.Context, userID string, role m if err != nil { return errors.Wrap(errAddPolicies, err) } - if !resp.Authorized { + if !resp.Added { return errors.Wrap(svcerr.ErrAuthorization, err) } return nil diff --git a/users/service_test.go b/users/service_test.go index 93be53385c..2dbbc7580a 100644 --- a/users/service_test.go +++ b/users/service_test.go @@ -50,9 +50,9 @@ var ( errDeletePolicies = errors.New("failed to delete policies") ) -func newService(selfRegister bool) (users.Service, *mocks.Repository, *authmocks.Service, users.Emailer) { +func newService(selfRegister bool) (users.Service, *mocks.Repository, *authmocks.AuthClient, users.Emailer) { cRepo := new(mocks.Repository) - auth := new(authmocks.Service) + auth := new(authmocks.AuthClient) e := mocks.NewEmailer() return users.NewService(cRepo, auth, e, phasher, idProvider, passRegex, selfRegister), cRepo, auth, e } @@ -76,14 +76,14 @@ func TestRegisterClient(t *testing.T) { { desc: "register new client successfully", client: client, - addPoliciesResponse: &magistrala.AddPoliciesRes{Authorized: true}, + addPoliciesResponse: &magistrala.AddPoliciesRes{Added: true}, token: validToken, err: nil, }, { desc: "register existing client", client: client, - addPoliciesResponse: &magistrala.AddPoliciesRes{Authorized: true}, + addPoliciesResponse: &magistrala.AddPoliciesRes{Added: true}, deletePoliciesResponse: &magistrala.DeletePoliciesRes{Deleted: true}, token: validToken, saveErr: repoerr.ErrConflict, @@ -99,7 +99,7 @@ func TestRegisterClient(t *testing.T) { }, Status: mgclients.EnabledStatus, }, - addPoliciesResponse: &magistrala.AddPoliciesRes{Authorized: true}, + addPoliciesResponse: &magistrala.AddPoliciesRes{Added: true}, err: nil, token: validToken, }, @@ -112,7 +112,7 @@ func TestRegisterClient(t *testing.T) { Secret: secret, }, }, - addPoliciesResponse: &magistrala.AddPoliciesRes{Authorized: true}, + addPoliciesResponse: &magistrala.AddPoliciesRes{Added: true}, err: nil, token: validToken, }, @@ -130,7 +130,7 @@ func TestRegisterClient(t *testing.T) { }, Status: mgclients.EnabledStatus, }, - addPoliciesResponse: &magistrala.AddPoliciesRes{Authorized: true}, + addPoliciesResponse: &magistrala.AddPoliciesRes{Added: true}, err: nil, token: validToken, }, @@ -142,7 +142,7 @@ func TestRegisterClient(t *testing.T) { Secret: secret, }, }, - addPoliciesResponse: &magistrala.AddPoliciesRes{Authorized: true}, + addPoliciesResponse: &magistrala.AddPoliciesRes{Added: true}, deletePoliciesResponse: &magistrala.DeletePoliciesRes{Deleted: true}, saveErr: errors.ErrMalformedEntity, err: errors.ErrMalformedEntity, @@ -157,7 +157,7 @@ func TestRegisterClient(t *testing.T) { Secret: "", }, }, - addPoliciesResponse: &magistrala.AddPoliciesRes{Authorized: true}, + addPoliciesResponse: &magistrala.AddPoliciesRes{Added: true}, deletePoliciesResponse: &magistrala.DeletePoliciesRes{Deleted: true}, err: repoerr.ErrMissingSecret, }, @@ -170,7 +170,7 @@ func TestRegisterClient(t *testing.T) { Secret: "weak", }, }, - addPoliciesResponse: &magistrala.AddPoliciesRes{Authorized: true}, + addPoliciesResponse: &magistrala.AddPoliciesRes{Added: true}, deletePoliciesResponse: &magistrala.DeletePoliciesRes{Deleted: true}, err: nil, }, @@ -183,7 +183,7 @@ func TestRegisterClient(t *testing.T) { Secret: strings.Repeat("a", 73), }, }, - addPoliciesResponse: &magistrala.AddPoliciesRes{Authorized: true}, + addPoliciesResponse: &magistrala.AddPoliciesRes{Added: true}, deletePoliciesResponse: &magistrala.DeletePoliciesRes{Deleted: true}, err: repoerr.ErrMalformedEntity, }, @@ -197,7 +197,7 @@ func TestRegisterClient(t *testing.T) { }, Status: mgclients.AllStatus, }, - addPoliciesResponse: &magistrala.AddPoliciesRes{Authorized: true}, + addPoliciesResponse: &magistrala.AddPoliciesRes{Added: true}, deletePoliciesResponse: &magistrala.DeletePoliciesRes{Deleted: true}, err: svcerr.ErrInvalidStatus, }, @@ -211,7 +211,7 @@ func TestRegisterClient(t *testing.T) { }, Role: 2, }, - addPoliciesResponse: &magistrala.AddPoliciesRes{Authorized: true}, + addPoliciesResponse: &magistrala.AddPoliciesRes{Added: true}, deletePoliciesResponse: &magistrala.DeletePoliciesRes{Deleted: true}, err: svcerr.ErrInvalidRole, }, @@ -225,7 +225,7 @@ func TestRegisterClient(t *testing.T) { }, Role: mgclients.AdminRole, }, - addPoliciesResponse: &magistrala.AddPoliciesRes{Authorized: false}, + addPoliciesResponse: &magistrala.AddPoliciesRes{Added: false}, err: errors.ErrAuthorization, }, { @@ -238,7 +238,7 @@ func TestRegisterClient(t *testing.T) { }, Role: mgclients.AdminRole, }, - addPoliciesResponse: &magistrala.AddPoliciesRes{Authorized: true}, + addPoliciesResponse: &magistrala.AddPoliciesRes{Added: true}, addPoliciesResponseErr: errAddPolicies, err: errAddPolicies, }, @@ -252,7 +252,7 @@ func TestRegisterClient(t *testing.T) { }, Role: mgclients.AdminRole, }, - addPoliciesResponse: &magistrala.AddPoliciesRes{Authorized: true}, + addPoliciesResponse: &magistrala.AddPoliciesRes{Added: true}, deletePoliciesResponse: &magistrala.DeletePoliciesRes{Deleted: false}, deletePoliciesResponseErr: errDeletePolicies, saveErr: repoerr.ErrConflict, @@ -268,7 +268,7 @@ func TestRegisterClient(t *testing.T) { }, Role: mgclients.AdminRole, }, - addPoliciesResponse: &magistrala.AddPoliciesRes{Authorized: true}, + addPoliciesResponse: &magistrala.AddPoliciesRes{Added: true}, deletePoliciesResponse: &magistrala.DeletePoliciesRes{Deleted: false}, saveErr: repoerr.ErrConflict, err: svcerr.ErrAuthorization, @@ -320,7 +320,7 @@ func TestRegisterClient(t *testing.T) { client: client, identifyResponse: &magistrala.IdentityRes{UserId: validID}, authorizeResponse: &magistrala.AuthorizeRes{Authorized: true}, - addPoliciesResponse: &magistrala.AddPoliciesRes{Authorized: true}, + addPoliciesResponse: &magistrala.AddPoliciesRes{Added: true}, token: validToken, err: nil, }, @@ -1003,7 +1003,7 @@ func TestUpdateClientRole(t *testing.T) { client: client, identifyResponse: &magistrala.IdentityRes{UserId: client.ID}, authorizeResponse: &magistrala.AuthorizeRes{Authorized: true}, - addPolicyResponse: &magistrala.AddPolicyRes{Authorized: true}, + addPolicyResponse: &magistrala.AddPolicyRes{Added: true}, updateRoleResponse: client, token: validToken, err: nil, @@ -1038,7 +1038,7 @@ func TestUpdateClientRole(t *testing.T) { client: client, identifyResponse: &magistrala.IdentityRes{UserId: client.ID}, authorizeResponse: &magistrala.AuthorizeRes{Authorized: true}, - addPolicyResponse: &magistrala.AddPolicyRes{Authorized: false}, + addPolicyResponse: &magistrala.AddPolicyRes{Added: false}, token: validToken, err: errors.ErrAuthorization, }, @@ -1086,7 +1086,7 @@ func TestUpdateClientRole(t *testing.T) { client: client, identifyResponse: &magistrala.IdentityRes{UserId: client.ID}, authorizeResponse: &magistrala.AuthorizeRes{Authorized: true}, - addPolicyResponse: &magistrala.AddPolicyRes{Authorized: true}, + addPolicyResponse: &magistrala.AddPolicyRes{Added: true}, deletePolicyResponse: &magistrala.DeletePolicyRes{Deleted: true}, updateRoleResponse: mgclients.Client{}, token: validToken, @@ -1098,7 +1098,7 @@ func TestUpdateClientRole(t *testing.T) { client: client, identifyResponse: &magistrala.IdentityRes{UserId: client.ID}, authorizeResponse: &magistrala.AuthorizeRes{Authorized: true}, - addPolicyResponse: &magistrala.AddPolicyRes{Authorized: true}, + addPolicyResponse: &magistrala.AddPolicyRes{Added: true}, deletePolicyResponse: &magistrala.DeletePolicyRes{Deleted: false}, updateRoleResponse: mgclients.Client{}, token: validToken, diff --git a/ws/adapter_test.go b/ws/adapter_test.go index d10954d7b4..8b9361b2b6 100644 --- a/ws/adapter_test.go +++ b/ws/adapter_test.go @@ -34,9 +34,9 @@ var msg = messaging.Message{ Payload: []byte(`[{"n":"current","t":-5,"v":1.2}]`), } -func newService() (ws.Service, *mocks.PubSub, *authmocks.Service) { +func newService() (ws.Service, *mocks.PubSub, *authmocks.AuthClient) { pubsub := new(mocks.PubSub) - auth := new(authmocks.Service) + auth := new(authmocks.AuthClient) return ws.New(auth, pubsub), pubsub, auth } diff --git a/ws/api/endpoint_test.go b/ws/api/endpoint_test.go index 359f6bfaed..25963522d1 100644 --- a/ws/api/endpoint_test.go +++ b/ws/api/endpoint_test.go @@ -90,7 +90,7 @@ func handshake(tsURL, chanID, subtopic, thingKey string, addHeader bool) (*webso } func TestHandshake(t *testing.T) { - auth := new(authmocks.Service) + auth := new(authmocks.AuthClient) svc, pubsub := newService(auth) target := newHTTPServer(svc) defer target.Close()