NOISSUE - Change Share Client To Be AddPolicy (#1825)

* Change Share Client To Be AddPolicy

Signed-off-by: rodneyosodo <blackd0t@protonmail.com>

* Remove  from API endpoint as it is a duplicate of

Signed-off-by: rodneyosodo <blackd0t@protonmail.com>

* Fix typo

Signed-off-by: rodneyosodo <blackd0t@protonmail.com>

---------

Signed-off-by: rodneyosodo <blackd0t@protonmail.com>
This commit is contained in:
b1ackd0t 2023-06-20 16:48:25 +03:00 committed by GitHub
parent 2673b34c6a
commit fce91bb652
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 345 additions and 227 deletions

View File

@ -8,7 +8,6 @@ import (
"crypto/tls"
"crypto/x509"
"encoding/pem"
"io/ioutil"
"os"
"github.com/mainflux/mainflux/pkg/errors"
@ -62,7 +61,7 @@ func LoadCertificates(caPath, caKeyPath string) (tls.Certificate, *x509.Certific
return tlsCert, &x509.Certificate{}, err
}
b, err := ioutil.ReadFile(caPath)
b, err := os.ReadFile(caPath)
if err != nil {
return tlsCert, &x509.Certificate{}, err
}

109
certs/mocks/channels.go Normal file
View File

@ -0,0 +1,109 @@
// Copyright (c) Mainflux
// SPDX-License-Identifier: Apache-2.0
package mocks
import (
"context"
"strconv"
"sync"
mfclients "github.com/mainflux/mainflux/pkg/clients"
"github.com/mainflux/mainflux/pkg/errors"
mfgroups "github.com/mainflux/mainflux/pkg/groups"
"github.com/mainflux/mainflux/things/groups"
upolicies "github.com/mainflux/mainflux/users/policies"
)
var _ groups.Service = (*mainfluxChannels)(nil)
type mainfluxChannels struct {
mu sync.Mutex
counter uint64
channels map[string]mfgroups.Group
auth upolicies.AuthServiceClient
}
// NewChannelsService returns Mainflux Channels service mock.
// Only methods used by SDK are mocked.
func NewChannelsService(channels map[string]mfgroups.Group, auth upolicies.AuthServiceClient) groups.Service {
return &mainfluxChannels{
channels: channels,
auth: auth,
}
}
func (svc *mainfluxChannels) CreateGroups(ctx context.Context, token string, chs ...mfgroups.Group) ([]mfgroups.Group, error) {
svc.mu.Lock()
defer svc.mu.Unlock()
userID, err := svc.auth.Identify(ctx, &upolicies.Token{Value: token})
if err != nil {
return []mfgroups.Group{}, errors.ErrAuthentication
}
for i := range chs {
svc.counter++
chs[i].Owner = userID.GetId()
chs[i].ID = strconv.FormatUint(svc.counter, 10)
svc.channels[chs[i].ID] = chs[i]
}
return chs, nil
}
func (svc *mainfluxChannels) ViewGroup(_ context.Context, owner, id string) (mfgroups.Group, error) {
if c, ok := svc.channels[id]; ok {
return c, nil
}
return mfgroups.Group{}, errors.ErrNotFound
}
func (svc *mainfluxChannels) ListGroups(context.Context, string, mfgroups.GroupsPage) (mfgroups.GroupsPage, error) {
panic("not implemented")
}
func (svc *mainfluxChannels) ListMemberships(context.Context, string, string, mfgroups.GroupsPage) (mfgroups.MembershipsPage, error) {
panic("not implemented")
}
func (svc *mainfluxChannels) UpdateGroup(context.Context, string, mfgroups.Group) (mfgroups.Group, error) {
panic("not implemented")
}
func (svc *mainfluxChannels) EnableGroup(ctx context.Context, token, id string) (mfgroups.Group, error) {
svc.mu.Lock()
defer svc.mu.Unlock()
userID, err := svc.auth.Identify(ctx, &upolicies.Token{Value: token})
if err != nil {
return mfgroups.Group{}, errors.ErrAuthentication
}
if t, ok := svc.channels[id]; !ok || t.Owner != userID.GetId() {
return mfgroups.Group{}, errors.ErrNotFound
}
if t, ok := svc.channels[id]; ok && t.Owner == userID.GetId() {
t.Status = mfclients.EnabledStatus
return t, nil
}
return mfgroups.Group{}, nil
}
func (svc *mainfluxChannels) DisableGroup(ctx context.Context, token, id string) (mfgroups.Group, error) {
svc.mu.Lock()
defer svc.mu.Unlock()
userID, err := svc.auth.Identify(ctx, &upolicies.Token{Value: token})
if err != nil {
return mfgroups.Group{}, errors.ErrAuthentication
}
if t, ok := svc.channels[id]; !ok || t.Owner != userID.GetId() {
return mfgroups.Group{}, errors.ErrNotFound
}
if t, ok := svc.channels[id]; ok && t.Owner == userID.GetId() {
t.Status = mfclients.DisabledStatus
return t, nil
}
return mfgroups.Group{}, nil
}

71
certs/mocks/policies.go Normal file
View File

@ -0,0 +1,71 @@
// Copyright (c) Mainflux
// SPDX-License-Identifier: Apache-2.0
package mocks
import (
"context"
"fmt"
"sync"
"github.com/mainflux/mainflux/pkg/errors"
tpolicies "github.com/mainflux/mainflux/things/policies"
upolicies "github.com/mainflux/mainflux/users/policies"
)
var _ tpolicies.Service = (*mainfluxPolicies)(nil)
type mainfluxPolicies struct {
mu sync.Mutex
auth upolicies.AuthServiceClient
connections map[string]tpolicies.Policy
}
// NewPoliciesService returns Mainflux Things Policies service mock.
// Only methods used by SDK are mocked.
func NewPoliciesService(auth upolicies.AuthServiceClient) tpolicies.Service {
return &mainfluxPolicies{
auth: auth,
connections: make(map[string]tpolicies.Policy),
}
}
func (svc *mainfluxPolicies) AddPolicy(ctx context.Context, token string, p tpolicies.Policy) (tpolicies.Policy, error) {
svc.mu.Lock()
defer svc.mu.Unlock()
if _, err := svc.auth.Identify(ctx, &upolicies.Token{Value: token}); err != nil {
return tpolicies.Policy{}, errors.ErrAuthentication
}
svc.connections[fmt.Sprintf("%s:%s", p.Subject, p.Object)] = p
return p, nil
}
func (svc *mainfluxPolicies) DeletePolicy(ctx context.Context, token string, p tpolicies.Policy) error {
svc.mu.Lock()
defer svc.mu.Unlock()
if _, err := svc.auth.Identify(context.Background(), &upolicies.Token{Value: token}); err != nil {
return errors.ErrAuthentication
}
for _, pol := range svc.connections {
if pol.Subject == p.Subject && pol.Object == p.Object {
delete(svc.connections, fmt.Sprintf("%s:%s", p.Subject, p.Object))
}
}
return nil
}
func (svc *mainfluxPolicies) UpdatePolicy(context.Context, string, tpolicies.Policy) (tpolicies.Policy, error) {
panic("not implemented")
}
func (svc *mainfluxPolicies) Authorize(context.Context, tpolicies.AccessRequest) (tpolicies.Policy, error) {
panic("not implemented")
}
func (svc *mainfluxPolicies) ListPolicies(context.Context, string, tpolicies.Page) (tpolicies.PolicyPage, error) {
panic("not implemented")
}

139
certs/mocks/things.go Normal file
View File

@ -0,0 +1,139 @@
// Copyright (c) Mainflux
// SPDX-License-Identifier: Apache-2.0
package mocks
import (
"context"
"strconv"
"sync"
mfclients "github.com/mainflux/mainflux/pkg/clients"
"github.com/mainflux/mainflux/pkg/errors"
"github.com/mainflux/mainflux/things/clients"
upolicies "github.com/mainflux/mainflux/users/policies"
)
var _ clients.Service = (*mainfluxThings)(nil)
type mainfluxThings struct {
mu sync.Mutex
counter uint64
things map[string]mfclients.Client
auth upolicies.AuthServiceClient
}
// NewThingsService returns Mainflux Things service mock.
// Only methods used by SDK are mocked.
func NewThingsService(things map[string]mfclients.Client, auth upolicies.AuthServiceClient) clients.Service {
return &mainfluxThings{
things: things,
auth: auth,
}
}
func (svc *mainfluxThings) CreateThings(_ context.Context, owner string, ths ...mfclients.Client) ([]mfclients.Client, error) {
svc.mu.Lock()
defer svc.mu.Unlock()
userID, err := svc.auth.Identify(context.Background(), &upolicies.Token{Value: owner})
if err != nil {
return []mfclients.Client{}, errors.ErrAuthentication
}
for i := range ths {
svc.counter++
ths[i].Owner = userID.GetId()
ths[i].ID = strconv.FormatUint(svc.counter, 10)
ths[i].Credentials.Secret = ths[i].ID
svc.things[ths[i].ID] = ths[i]
}
return ths, nil
}
func (svc *mainfluxThings) ViewClient(_ context.Context, owner, id string) (mfclients.Client, error) {
svc.mu.Lock()
defer svc.mu.Unlock()
userID, err := svc.auth.Identify(context.Background(), &upolicies.Token{Value: owner})
if err != nil {
return mfclients.Client{}, errors.ErrAuthentication
}
if t, ok := svc.things[id]; ok && t.Owner == userID.GetId() {
return t, nil
}
return mfclients.Client{}, errors.ErrNotFound
}
func (svc *mainfluxThings) EnableClient(ctx context.Context, token, id string) (mfclients.Client, error) {
svc.mu.Lock()
defer svc.mu.Unlock()
userID, err := svc.auth.Identify(context.Background(), &upolicies.Token{Value: token})
if err != nil {
return mfclients.Client{}, errors.ErrAuthentication
}
if t, ok := svc.things[id]; !ok || t.Owner != userID.GetId() {
return mfclients.Client{}, errors.ErrNotFound
}
if t, ok := svc.things[id]; ok && t.Owner == userID.GetId() {
t.Status = mfclients.EnabledStatus
return t, nil
}
return mfclients.Client{}, nil
}
func (svc *mainfluxThings) DisableClient(ctx context.Context, token, id string) (mfclients.Client, error) {
svc.mu.Lock()
defer svc.mu.Unlock()
userID, err := svc.auth.Identify(context.Background(), &upolicies.Token{Value: token})
if err != nil {
return mfclients.Client{}, errors.ErrAuthentication
}
if t, ok := svc.things[id]; !ok || t.Owner != userID.GetId() {
return mfclients.Client{}, errors.ErrNotFound
}
if t, ok := svc.things[id]; ok && t.Owner == userID.GetId() {
t.Status = mfclients.DisabledStatus
return t, nil
}
return mfclients.Client{}, nil
}
func (svc *mainfluxThings) UpdateClient(context.Context, string, mfclients.Client) (mfclients.Client, error) {
panic("not implemented")
}
func (svc *mainfluxThings) UpdateClientSecret(context.Context, string, string, string) (mfclients.Client, error) {
panic("not implemented")
}
func (svc *mainfluxThings) UpdateClientOwner(context.Context, string, mfclients.Client) (mfclients.Client, error) {
panic("not implemented")
}
func (svc *mainfluxThings) UpdateClientTags(context.Context, string, mfclients.Client) (mfclients.Client, error) {
panic("not implemented")
}
func (svc *mainfluxThings) ListClients(context.Context, string, mfclients.Page) (mfclients.ClientsPage, error) {
panic("not implemented")
}
func (svc *mainfluxThings) ListClientsByGroup(context.Context, string, string, mfclients.Page) (mfclients.MembersPage, error) {
panic("not implemented")
}
func (svc *mainfluxThings) Identify(context.Context, string) (string, error) {
panic("not implemented")
}
func (svc *mainfluxThings) ShareClient(ctx context.Context, token, userID, groupID, thingID string, actions []string) error {
panic("not implemented")
}

View File

@ -23,7 +23,7 @@ import (
"github.com/mainflux/mainflux/things/clients"
httpapi "github.com/mainflux/mainflux/things/clients/api"
thmocks "github.com/mainflux/mainflux/things/clients/mocks"
"github.com/mainflux/mainflux/users/policies"
upolicies "github.com/mainflux/mainflux/users/policies"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@ -47,6 +47,7 @@ const (
func newService(tokens map[string]string) (certs.Service, error) {
ac := bsmocks.NewAuthClient(map[string]string{token: email})
server := newThingsServer(newThingsService(ac))
policies := []thmocks.MockSubjectSet{{Object: "token", Relation: clients.AdminRelationKey}}
@ -74,7 +75,7 @@ func newService(tokens map[string]string) (certs.Service, error) {
return certs.New(auth, repo, sdk, pki), nil
}
func newThingsService(auth policies.AuthServiceClient) clients.Service {
func newThingsService(auth upolicies.AuthServiceClient) clients.Service {
ths := make(map[string]mfclients.Client, thingsNum)
for i := 0; i < thingsNum; i++ {
id := strconv.Itoa(i + 1)

View File

@ -215,23 +215,23 @@ var cmdThings = []cobra.Command{
},
},
{
Use: "share <thing_id> <group_id> <user_id> <allowed_actions> <user_auth_token>",
Use: "share <channel_id> <user_id> <allowed_actions> <user_auth_token>",
Short: "Share thing with a user",
Long: "Share thing with a user\n" +
"Usage:\n" +
"\tmainflux-cli things share <thing_id> <group_id> <user_id> '[\"c_list\", \"c_delete\"]' $USERTOKEN\n",
"\tmainflux-cli things share <channel_id> <user_id> '[\"c_list\", \"c_delete\"]' $USERTOKEN\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 5 {
if len(args) != 4 {
logUsage(cmd.Use)
return
}
var actions []string
if err := json.Unmarshal([]byte(args[3]), &actions); err != nil {
if err := json.Unmarshal([]byte(args[2]), &actions); err != nil {
logError(err)
return
}
err := sdk.ShareThing(args[0], args[1], args[2], actions, args[4])
err := sdk.ShareThing(args[0], args[1], actions, args[3])
if err != nil {
logError(err)
return

View File

@ -39,7 +39,7 @@ func TestPublisher(t *testing.T) {
client, err := newClient(address, "clientID1", brokerTimeout)
assert.Nil(t, err, fmt.Sprintf("got unexpected error: %s", err))
token := client.Subscribe(topic, qos, func(c mqtt.Client, m mqtt.Message) {
token := client.Subscribe(topic, qos, func(_ mqtt.Client, m mqtt.Message) {
msgChan <- m.Payload()
})
if ok := token.WaitTimeout(tokenTimeout); !ok {
@ -47,7 +47,7 @@ func TestPublisher(t *testing.T) {
}
assert.Nil(t, token.Error(), fmt.Sprintf("got unexpected error: %s", token.Error()))
token = client.Subscribe(fmt.Sprintf("%s.%s", topic, subtopic), qos, func(c mqtt.Client, m mqtt.Message) {
token = client.Subscribe(fmt.Sprintf("%s.%s", topic, subtopic), qos, func(_ mqtt.Client, m mqtt.Message) {
msgChan <- m.Payload()
})
if ok := token.WaitTimeout(tokenTimeout); !ok {

View File

@ -38,12 +38,6 @@ type tokenReq struct {
Secret string `json:"secret"`
}
type shareThingReq struct {
GroupID string `json:"group_id"`
UserID string `json:"user_id"`
Actions []string `json:"actions"`
}
type canAccessReq struct {
ClientSecret string `json:"secret"`
GroupID string `json:"group_id"`

View File

@ -370,12 +370,17 @@ type SDK interface {
// fmt.Println(id)
IdentifyThing(key string) (string, errors.SDKError)
// ShareThing shares thing with other user.
// ShareThing shares thing with other user. It assumes that you have
// already created a group and added things to it. It also assumes that
// you have required policy to share a thing with the specified user.
//
// The `ShareThing` method calls the `Connect` method with the
// subject as `userID` rather than `thingID`.
//
// example:
// err := sdk.ShareThing("thingID", "groupID", "userID", []string{"c_list", "c_delete"}, "token")
// err := sdk.ShareThing("channelID", "userID", []string{"c_list", "c_delete"}, "token")
// fmt.Println(err)
ShareThing(thingID, groupID, userID string, actions []string, token string) errors.SDKError
ShareThing(channelID, userID string, actions []string, token string) errors.SDKError
// CreateGroup creates new group and returns its id.
//

View File

@ -250,18 +250,12 @@ func (sdk mfSDK) IdentifyThing(key string) (string, errors.SDKError) {
return i.ID, nil
}
func (sdk mfSDK) ShareThing(thingID, groupID, userID string, actions []string, token string) errors.SDKError {
sreq := shareThingReq{GroupID: groupID, UserID: userID, Actions: actions}
data, err := json.Marshal(sreq)
if err != nil {
return errors.NewSDKError(err)
func (sdk mfSDK) ShareThing(groupID, userID string, actions []string, token string) errors.SDKError {
policy := ConnectionIDs{
ChannelIDs: []string{groupID},
ThingIDs: []string{userID},
Actions: actions,
}
url := fmt.Sprintf("%s/%s/%s/%s", sdk.thingsURL, thingsEndpoint, thingID, shareEndpoint)
_, _, sdkerr := sdk.processRequest(http.MethodPost, url, token, string(CTJSON), data, http.StatusOK)
if sdkerr != nil {
return sdkerr
}
return nil
return sdk.Connect(policy, token)
}

View File

@ -1383,7 +1383,6 @@ func TestShareThing(t *testing.T) {
cases := []struct {
desc string
thingID string
groupID string
userID string
token string
@ -1391,7 +1390,6 @@ func TestShareThing(t *testing.T) {
}{
{
desc: "share thing with valid token",
thingID: generateUUID(t),
groupID: generateUUID(t),
userID: generateUUID(t),
token: adminToken,
@ -1399,7 +1397,6 @@ func TestShareThing(t *testing.T) {
},
{
desc: "share thing with invalid token",
thingID: generateUUID(t),
groupID: generateUUID(t),
userID: generateUUID(t),
token: invalidToken,
@ -1412,7 +1409,7 @@ func TestShareThing(t *testing.T) {
repoCall1 := pRepo.On("EvaluateThingAccess", mock.Anything, mock.Anything).Return(policies.Policy{}, nil)
repoCall3 := pRepo.On("Retrieve", mock.Anything, mock.Anything).Return(policies.PolicyPage{}, nil)
repoCall4 := pRepo.On("Save", mock.Anything, mock.Anything).Return(policies.Policy{}, nil)
err := mfsdk.ShareThing(tc.thingID, tc.groupID, tc.userID, []string{"c_list", "c_delete"}, tc.token)
err := mfsdk.ShareThing(tc.groupID, tc.userID, []string{"c_list", "c_delete"}, tc.token)
assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected error %s, got %s", tc.desc, tc.err, err))
if tc.err == nil {
ok := repoCall4.Parent.AssertCalled(t, "Save", mock.Anything, mock.Anything)

View File

@ -159,19 +159,6 @@ func updateClientTagsEndpoint(svc clients.Service) endpoint.Endpoint {
}
}
func shareClientEndpoint(svc clients.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
req := request.(shareClientReq)
if err := req.validate(); err != nil {
return nil, err
}
if err := svc.ShareClient(ctx, req.token, req.UserID, req.GroupID, req.clientID, req.Actions); err != nil {
return nil, err
}
return shareClientRes{}, nil
}
}
func updateClientSecretEndpoint(svc clients.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
req := request.(updateClientCredentialsReq)

View File

@ -144,18 +144,6 @@ func (lm *loggingMiddleware) ListClientsByGroup(ctx context.Context, token, chan
return lm.svc.ListClientsByGroup(ctx, token, channelID, cp)
}
func (lm *loggingMiddleware) ShareClient(ctx context.Context, token, userID, groupID, thingID string, actions []string) (err error) {
defer func(begin time.Time) {
message := fmt.Sprintf("Method share_thing for thing with id %s using token %s took %s to complete", thingID, token, time.Since(begin))
if err != nil {
lm.logger.Warn(fmt.Sprintf("%s with error: %s.", message, err))
return
}
lm.logger.Info(fmt.Sprintf("%s without errors.", message))
}(time.Now())
return lm.svc.ShareClient(ctx, token, userID, groupID, thingID, actions)
}
func (lm *loggingMiddleware) Identify(ctx context.Context, key string) (id string, err error) {
defer func(begin time.Time) {
message := fmt.Sprintf("Method identify for thing with id %s and key %s took %s to complete", id, key, time.Since(begin))

View File

@ -69,14 +69,6 @@ func (ms *metricsMiddleware) UpdateClientTags(ctx context.Context, token string,
return ms.svc.UpdateClientTags(ctx, token, client)
}
func (ms *metricsMiddleware) ShareClient(ctx context.Context, token, userID, groupID, thingID string, actions []string) error {
defer func(begin time.Time) {
ms.counter.With("method", "share_thing").Add(1)
ms.latency.With("method", "share_thing").Observe(time.Since(begin).Seconds())
}(time.Now())
return ms.svc.ShareClient(ctx, token, userID, groupID, thingID, actions)
}
func (ms *metricsMiddleware) UpdateClientSecret(ctx context.Context, token, oldSecret, newSecret string) (mfclients.Client, error) {
defer func(begin time.Time) {
ms.counter.With("method", "update_thing_secret").Add(1)

View File

@ -208,27 +208,3 @@ func (req changeClientStatusReq) validate() error {
}
return nil
}
type shareClientReq struct {
token string
clientID string
GroupID string `json:"group_id"`
UserID string `json:"user_id"`
Actions []string `json:"actions"`
}
func (req shareClientReq) validate() error {
if req.token == "" {
return apiutil.ErrBearerToken
}
if req.clientID == "" || req.GroupID == "" || req.UserID == "" {
return apiutil.ErrMissingID
}
if len(req.Actions) == 0 {
return apiutil.ErrEmptyList
}
return nil
}

View File

@ -18,7 +18,6 @@ var (
_ mainflux.Response = (*clientsPageRes)(nil)
_ mainflux.Response = (*viewMembersRes)(nil)
_ mainflux.Response = (*memberPageRes)(nil)
_ mainflux.Response = (*shareClientRes)(nil)
)
type pageRes struct {
@ -151,17 +150,3 @@ func (res deleteClientRes) Headers() map[string]string {
func (res deleteClientRes) Empty() bool {
return false
}
type shareClientRes struct{}
func (res shareClientRes) Code() int {
return http.StatusOK
}
func (res shareClientRes) Headers() map[string]string {
return map[string]string{}
}
func (res shareClientRes) Empty() bool {
return false
}

View File

@ -77,13 +77,6 @@ func MakeHandler(svc clients.Service, mux *bone.Mux, logger mflog.Logger) http.H
opts...,
))
mux.Post("/things/:thingID/share", kithttp.NewServer(
otelkit.EndpointMiddleware(otelkit.WithOperation("share_thing"))(shareClientEndpoint(svc)),
decodeShareClient,
api.EncodeResponse,
opts...,
))
mux.Patch("/things/:thingID/secret", kithttp.NewServer(
otelkit.EndpointMiddleware(otelkit.WithOperation("update_thing_secret"))(updateClientSecretEndpoint(svc)),
decodeUpdateClientCredentials,
@ -126,22 +119,6 @@ func decodeViewClient(_ context.Context, r *http.Request) (interface{}, error) {
return req, nil
}
func decodeShareClient(_ context.Context, r *http.Request) (interface{}, error) {
if !strings.Contains(r.Header.Get("Content-Type"), api.ContentType) {
return nil, errors.ErrUnsupportedContentType
}
req := shareClientReq{
token: apiutil.ExtractBearerToken(r),
clientID: bone.GetValue(r, "thingID"),
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
return nil, errors.Wrap(errors.ErrMalformedEntity, err)
}
return req, nil
}
func decodeListClients(_ context.Context, r *http.Request) (interface{}, error) {
var sid, oid string
s, err := apiutil.ReadStringQuery(r, api.StatusKey, api.DefClientStatus)

View File

@ -45,11 +45,6 @@ type Service interface {
// DisableClient logically disables the client identified with the provided ID
DisableClient(ctx context.Context, token, id string) (clients.Client, error)
// ShareClient gives actions associated with the thing to the given user IDs.
// The requester user identified by the token has to have a "write" relation
// on the thing in order to share the thing.
ShareClient(ctx context.Context, token, userID, groupID, thingID string, actions []string) error
// Identify returns thing ID for given thing key.
Identify(ctx context.Context, key string) (string, error)
}

View File

@ -17,7 +17,6 @@ const (
clientCreate = clientPrefix + "create"
clientUpdate = clientPrefix + "update"
clientRemove = clientPrefix + "remove"
clientShare = clientPrefix + "share"
clientView = clientPrefix + "view"
clientList = clientPrefix + "list"
clientListByGroup = clientPrefix + "list_by_group"
@ -32,7 +31,6 @@ var (
_ event = (*createClientEvent)(nil)
_ event = (*updateClientEvent)(nil)
_ event = (*removeClientEvent)(nil)
_ event = (*shareClientEvent)(nil)
_ event = (*viewClientEvent)(nil)
_ event = (*listClientEvent)(nil)
_ event = (*listClientByGroupEvent)(nil)
@ -136,23 +134,6 @@ func (rce removeClientEvent) Encode() (map[string]interface{}, error) {
}, nil
}
type shareClientEvent struct {
thingID string
actions string
userID string
groupID string
}
func (sce shareClientEvent) Encode() (map[string]interface{}, error) {
return map[string]interface{}{
"operation": clientShare,
"thing_id": sce.thingID,
"actions": sce.actions,
"user_id": sce.userID,
"group_id": sce.groupID,
}, nil
}
type viewClientEvent struct {
mfclients.Client
}

View File

@ -5,8 +5,6 @@ package redis
import (
"context"
"fmt"
"strings"
"github.com/go-redis/redis/v8"
mfclients "github.com/mainflux/mainflux/pkg/clients"
@ -116,32 +114,6 @@ func (es eventStore) update(ctx context.Context, operation string, cli mfclients
return cli, nil
}
func (es eventStore) ShareClient(ctx context.Context, token, userID, groupID, thingID string, actions []string) error {
if err := es.svc.ShareClient(ctx, token, userID, groupID, thingID, actions); err != nil {
return err
}
event := shareClientEvent{
thingID: thingID,
userID: userID,
groupID: groupID,
actions: fmt.Sprintf("[%s]", strings.Join(actions, ",")),
}
values, err := event.Encode()
if err != nil {
return err
}
record := &redis.XAddArgs{
Stream: streamID,
MaxLenApprox: streamLen,
Values: values,
}
if err := es.client.XAdd(ctx, record).Err(); err != nil {
return err
}
return nil
}
func (es eventStore) ViewClient(ctx context.Context, token, id string) (mfclients.Client, error) {
cli, err := es.svc.ViewClient(ctx, token, id)
if err != nil {

View File

@ -4,7 +4,6 @@ package clients
import (
"context"
"fmt"
"time"
"github.com/mainflux/mainflux"
@ -280,36 +279,6 @@ func (svc service) Identify(ctx context.Context, key string) (string, error) {
return client.ID, nil
}
// ShareClient shares a thing with a user.
// We assume the user has already created the things anf group.
func (svc service) ShareClient(ctx context.Context, token, userID, groupID, thingID string, actions []string) error {
id, err := svc.identify(ctx, token)
if err != nil {
return err
}
areq := tpolicies.AccessRequest{Subject: id, Object: groupID, Action: addRelationKey, Entity: groupEntityType}
if _, err := svc.policies.Authorize(ctx, areq); err != nil {
return fmt.Errorf("cannot share things using group %s to user %s: %s", groupID, userID, err)
}
areq = tpolicies.AccessRequest{Subject: id, Object: thingID, Action: addRelationKey, Entity: clientEntityType}
if _, err := svc.policies.Authorize(ctx, areq); err != nil {
return fmt.Errorf("cannot share thing %s with user %s: %s", thingID, userID, err)
}
policy := tpolicies.Policy{
Subject: userID,
Object: groupID,
Actions: actions,
}
if _, err = svc.policies.AddPolicy(ctx, token, policy); err != nil {
return err
}
return nil
}
func (svc service) identify(ctx context.Context, token string) (string, error) {
req := &upolicies.Token{Value: token}
res, err := svc.uauth.Identify(ctx, req)

View File

@ -110,19 +110,6 @@ func (tm *tracingMiddleware) ListClientsByGroup(ctx context.Context, token, grou
}
// ShareClient traces the "ShareClient" operation of the wrapped policies.Service.
func (tm *tracingMiddleware) ShareClient(ctx context.Context, token, userID, groupID, thingID string, actions []string) error {
ctx, span := tm.tracer.Start(ctx, "svc_share_client", trace.WithAttributes(
attribute.String("userID", userID),
attribute.String("groupID", groupID),
attribute.String("thingID", thingID),
attribute.StringSlice("actions", actions),
))
defer span.End()
return tm.svc.ShareClient(ctx, token, userID, groupID, thingID, actions)
}
// ListMemberships traces the "ListMemberships" operation of the wrapped policies.Service.
func (tm *tracingMiddleware) Identify(ctx context.Context, key string) (string, error) {
ctx, span := tm.tracer.Start(ctx, "svc_identify", trace.WithAttributes(attribute.String("key", key)))