Skip to content

Commit

Permalink
SNRGY-3300 add device owner id handling
Browse files Browse the repository at this point in the history
  • Loading branch information
IngoRoessner committed May 27, 2024
1 parent 9c54fe6 commit 1954c08
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 11 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ require (
)

require (
github.com/SENERGY-Platform/models/go v0.0.0-20230824080159-16585960df38
github.com/SENERGY-Platform/models/go v0.0.0-20240527081255-52b6a0f84955
github.com/SENERGY-Platform/permission-search v0.0.13
github.com/SENERGY-Platform/service-commons v0.0.0-20240423132428-8eccbc027e71
github.com/testcontainers/testcontainers-go v0.31.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERo
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
github.com/Microsoft/hcsshim v0.12.3 h1:LS9NXqXhMoqNCplK1ApmVSfB4UnVLRDWRapB6EIlxE0=
github.com/Microsoft/hcsshim v0.12.3/go.mod h1:Iyl1WVpZzr+UkzjekHZbV8o5Z9ZkxNGx6CtY2Qg/JVQ=
github.com/SENERGY-Platform/models/go v0.0.0-20230824080159-16585960df38 h1:PDvFwIJBnFyKt1KeepkABNIS57+WhVj4vBw7X5JGZJw=
github.com/SENERGY-Platform/models/go v0.0.0-20230824080159-16585960df38/go.mod h1:bCREPNRN4P8oxLgpC3/ZKK4jXSy4MSPXoiomhohE+aw=
github.com/SENERGY-Platform/models/go v0.0.0-20240527081255-52b6a0f84955 h1:F2/npODU4ODkrkZ7mVmRKjHW1KJFgtaFOKq+rI1XwDM=
github.com/SENERGY-Platform/models/go v0.0.0-20240527081255-52b6a0f84955/go.mod h1:bCREPNRN4P8oxLgpC3/ZKK4jXSy4MSPXoiomhohE+aw=
github.com/SENERGY-Platform/permission-search v0.0.13 h1:MCmdcMXsMCsvS1uEIzhrYb0WfAvGkrnTPxwS9dr7ZWo=
github.com/SENERGY-Platform/permission-search v0.0.13/go.mod h1:TL+tg9zvYGjBWmdjOhfT10oRBnbdDvHSml1p1U/eeNI=
github.com/SENERGY-Platform/service-commons v0.0.0-20240423132428-8eccbc027e71 h1:Z3Vj9ImRERXQE5fprE/KGkAsS/dgX0dMesM/cDSN9Tw=
Expand Down
21 changes: 21 additions & 0 deletions lib/controller/com/permission.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,27 @@ func (this *Com) GetResourceOwner(token auth.Token, kind string, id string, righ
return temp[0].Creator, true, nil
}

func (this *Com) GetResourceRights(token auth.Token, kind string, id string, rights string) (result permmodel.EntryResult, found bool, err error) {
temp, _, err := client.Query[[]permmodel.EntryResult](this.perm, token.Jwt(), client.QueryMessage{
Resource: kind,
ListIds: &permmodel.QueryListIds{
QueryListCommons: permmodel.QueryListCommons{
Limit: 1,
Offset: 0,
Rights: rights,
},
Ids: []string{id},
},
})
if err != nil {
return result, false, err
}
if len(temp) == 0 {
return result, false, nil
}
return temp[0], true, nil
}

func (this *Com) PermissionCheckForDeviceList(token auth.Token, ids []string, rights string) (result map[string]bool, err error, code int) {
ids = append(ids, removeIdModifiers(ids)...)
ids = RemoveDuplicates(ids)
Expand Down
1 change: 1 addition & 0 deletions lib/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ type Publisher interface {
type Com interface {
ResourcesEffectedByUserDelete(token auth.Token, resource string) (deleteResourceIds []string, deleteUserFromResourceIds []string, err error)
GetResourceOwner(token auth.Token, kind string, id string, rights string) (owner string, found bool, err error)
GetResourceRights(token auth.Token, kind string, id string, rights string) (result permmodel.EntryResult, found bool, err error)
GetPermissions(token auth.Token, kind string, id string) (permmodel.ResourceRights, error)

GetTechnicalDeviceGroup(token auth.Token, id string) (dt models.DeviceGroup, err error, code int)
Expand Down
47 changes: 40 additions & 7 deletions lib/controller/device.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"log"
"net/http"
"runtime/debug"
"slices"
)

func (this *Controller) DeviceLocalIdToId(token auth.Token, localId string) (id string, err error, errCode int) {
Expand All @@ -43,6 +44,11 @@ func (this *Controller) ReadDevice(token auth.Token, id string) (device models.D

func (this *Controller) PublishDeviceCreate(token auth.Token, device models.Device, options model.DeviceCreateOptions) (models.Device, error, int) {
device.GenerateId()
if device.OwnerId != "" && device.OwnerId != token.GetUserId() {
return device, errors.New("new devices must be initialised with the requesting user as owner-id"), http.StatusBadRequest
}
device.OwnerId = token.GetUserId()

err, code := this.com.ValidateDevice(token, device)
if err != nil {
return device, err, code
Expand Down Expand Up @@ -80,27 +86,54 @@ func (this *Controller) PublishDeviceUpdate(token auth.Token, id string, device
}
}

var original models.Device
original, err, code = this.com.GetDevice(token, device.Id)
if err != nil && code != http.StatusNotFound {
return device, err, code
} else {
//device does not exist, but we want to continue to enable admins to create devices with a predetermined id
err, code = nil, 200
}
if len(options.UpdateOnlySameOriginAttributes) > 0 {
var original models.Device
original, err, code = this.com.GetDevice(token, device.Id)
if err != nil {
return device, err, code
}
device.Attributes = updateSameOriginAttributes(original.Attributes, device.Attributes, options.UpdateOnlySameOriginAttributes)
}

//set device owner-id if none is given
//prefer existing owner, fallback to requesting user
if device.OwnerId == "" {
device.OwnerId = original.OwnerId //may be empty for new devices
}
if device.OwnerId == "" {
device.OwnerId = token.GetUserId()
}

//only old owner or system-admin may set new owner
if original.OwnerId != device.OwnerId && //change happened
original.OwnerId != "" && //is not a new device
!token.IsAdmin() &&
original.OwnerId != token.GetUserId() {
return device, errors.New("only old owner or system-admin may set new owner"), http.StatusBadRequest
}

err, code = this.com.ValidateDevice(token, device)
if err != nil {
return device, err, code
}

//ensure retention of original owner
owner, found, err := this.com.GetResourceOwner(token, this.config.DeviceTopic, device.Id, "w")
rights, found, err := this.com.GetResourceRights(token, this.config.DeviceTopic, device.Id, "w")
if err != nil {
log.Println("ERROR:", err)
debug.PrintStack()
return device, err, http.StatusInternalServerError
}

//new device owner-id must be existing admin user (ignore for new devices or devices with unchanged owner)
if found && device.OwnerId != original.OwnerId && !slices.Contains(rights.PermissionHolders.AdminUsers, device.OwnerId) {
return device, errors.New("new owner must have existing user admin rights"), http.StatusBadRequest
}

//ensure retention of original owner
owner := rights.Creator
if !found || owner == "" {
owner = token.GetUserId()
}
Expand Down
6 changes: 5 additions & 1 deletion lib/tests/device_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package tests
import (
"encoding/json"
"errors"
"fmt"
"github.com/SENERGY-Platform/device-manager/lib/api"
"github.com/SENERGY-Platform/device-manager/lib/tests/helper"
"github.com/SENERGY-Platform/models/go/models"
Expand Down Expand Up @@ -684,6 +685,7 @@ func testDevice(t *testing.T, port string) {

func tryDeviceDisplayNameUpdate(port string, deviceId string, displayName string, expectedDevice models.Device) func(t *testing.T) {
return func(t *testing.T) {
expectedDevice.OwnerId = userjwtUser
resp, err := helper.Jwtput(userjwt, "http://localhost:"+port+"/devices/"+url.PathEscape(deviceId)+"/display_name", displayName)
if err != nil {
t.Fatal(err)
Expand Down Expand Up @@ -811,14 +813,16 @@ func initDevice(port string, dt models.DeviceType) (models.Device, error) {
return models.Device{}, err
}
if resp.StatusCode != http.StatusOK {
return models.Device{}, errors.New(resp.Status)
temp, _ := io.ReadAll(resp.Body)
return models.Device{}, fmt.Errorf("%v %v", resp.Status, string(temp))
}
result := models.Device{}
err = json.NewDecoder(resp.Body).Decode(&result)
if err != nil {
return models.Device{}, err
}
device.Id = result.Id
device.OwnerId = userjwtUser
if !reflect.DeepEqual(result, device) {
log.Printf("ERROR: \n%#v\n!=\n%#v\n", result, device)
return models.Device{}, errors.New("returned device != expected device")
Expand Down
1 change: 1 addition & 0 deletions lib/tests/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (

const adminjwt = "Bearer eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICIzaUtabW9aUHpsMmRtQnBJdS1vSkY4ZVVUZHh4OUFIckVOcG5CcHM5SjYwIn0.eyJqdGkiOiJiOGUyNGZkNy1jNjJlLTRhNWQtOTQ4ZC1mZGI2ZWVkM2JmYzYiLCJleHAiOjE1MzA1MzIwMzIsIm5iZiI6MCwiaWF0IjoxNTMwNTI4NDMyLCJpc3MiOiJodHRwczovL2F1dGguc2VwbC5pbmZhaS5vcmcvYXV0aC9yZWFsbXMvbWFzdGVyIiwiYXVkIjoiZnJvbnRlbmQiLCJzdWIiOiJkZDY5ZWEwZC1mNTUzLTQzMzYtODBmMy03ZjQ1NjdmODVjN2IiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJmcm9udGVuZCIsIm5vbmNlIjoiMjJlMGVjZjgtZjhhMS00NDQ1LWFmMjctNGQ1M2JmNWQxOGI5IiwiYXV0aF90aW1lIjoxNTMwNTI4NDIzLCJzZXNzaW9uX3N0YXRlIjoiMWQ3NWE5ODQtNzM1OS00MWJlLTgxYjktNzMyZDgyNzRjMjNlIiwiYWNyIjoiMCIsImFsbG93ZWQtb3JpZ2lucyI6WyIqIl0sInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJjcmVhdGUtcmVhbG0iLCJhZG1pbiIsImRldmVsb3BlciIsInVtYV9hdXRob3JpemF0aW9uIiwidXNlciJdfSwicmVzb3VyY2VfYWNjZXNzIjp7Im1hc3Rlci1yZWFsbSI6eyJyb2xlcyI6WyJ2aWV3LWlkZW50aXR5LXByb3ZpZGVycyIsInZpZXctcmVhbG0iLCJtYW5hZ2UtaWRlbnRpdHktcHJvdmlkZXJzIiwiaW1wZXJzb25hdGlvbiIsImNyZWF0ZS1jbGllbnQiLCJtYW5hZ2UtdXNlcnMiLCJxdWVyeS1yZWFsbXMiLCJ2aWV3LWF1dGhvcml6YXRpb24iLCJxdWVyeS1jbGllbnRzIiwicXVlcnktdXNlcnMiLCJtYW5hZ2UtZXZlbnRzIiwibWFuYWdlLXJlYWxtIiwidmlldy1ldmVudHMiLCJ2aWV3LXVzZXJzIiwidmlldy1jbGllbnRzIiwibWFuYWdlLWF1dGhvcml6YXRpb24iLCJtYW5hZ2UtY2xpZW50cyIsInF1ZXJ5LWdyb3VwcyJdfSwiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19fSwicm9sZXMiOlsidW1hX2F1dGhvcml6YXRpb24iLCJhZG1pbiIsImNyZWF0ZS1yZWFsbSIsImRldmVsb3BlciIsInVzZXIiLCJvZmZsaW5lX2FjY2VzcyJdLCJuYW1lIjoiZGYgZGZmZmYiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJzZXBsIiwiZ2l2ZW5fbmFtZSI6ImRmIiwiZmFtaWx5X25hbWUiOiJkZmZmZiIsImVtYWlsIjoic2VwbEBzZXBsLmRlIn0.eOwKV7vwRrWr8GlfCPFSq5WwR_p-_rSJURXCV1K7ClBY5jqKQkCsRL2V4YhkP1uS6ECeSxF7NNOLmElVLeFyAkvgSNOUkiuIWQpMTakNKynyRfH0SrdnPSTwK2V1s1i4VjoYdyZWXKNjeT2tUUX9eCyI5qOf_Dzcai5FhGCSUeKpV0ScUj5lKrn56aamlW9IdmbFJ4VwpQg2Y843Vc0TqpjK9n_uKwuRcQd9jkKHkbwWQ-wyJEbFWXHjQ6LnM84H0CQ2fgBqPPfpQDKjGSUNaCS-jtBcbsBAWQSICwol95BuOAqVFMucx56Wm-OyQOuoQ1jaLt2t-Uxtr-C9wKJWHQ"
const userjwt = "Bearer eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICIzaUtabW9aUHpsMmRtQnBJdS1vSkY4ZVVUZHh4OUFIckVOcG5CcHM5SjYwIn0.eyJqdGkiOiIzMmE1OTljZC0zNDgxLTQzYWUtYWY0NC04YTVmNjU4NzYxZTUiLCJleHAiOjE1NjI5MjAwMDUsIm5iZiI6MCwiaWF0IjoxNTYyOTE2NDA1LCJpc3MiOiJodHRwczovL2F1dGguc2VwbC5pbmZhaS5vcmcvYXV0aC9yZWFsbXMvbWFzdGVyIiwiYXVkIjoiZnJvbnRlbmQiLCJzdWIiOiJlYmJhZDkyNy00YzM5LTRkMTItODY5MC04OWIwNjdkZDRjZTciLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJmcm9udGVuZCIsIm5vbmNlIjoiNTVlMzA4N2UtZjljNi00MmQ2LWE0MmEtMGZiMjcxNWE4OTkyIiwiYXV0aF90aW1lIjoxNTYyOTE2NDA0LCJzZXNzaW9uX3N0YXRlIjoiYmU5MDQ2MmYtOGE3Yy00NWU4LTg1MjAtMGRlYzViZWI1ZWZlIiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyIqIl0sInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJ1bWFfYXV0aG9yaXphdGlvbiIsInVzZXIiXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJyb2xlcyI6WyJ1bWFfYXV0aG9yaXphdGlvbiIsInVzZXIiLCJvZmZsaW5lX2FjY2VzcyJdLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJpbmdvIn0.pggKYb3V0VxFINWBqpFE_t14MKhSM7bhw8YqrYBRvOzh8ft7zu_-bOvLOYbJBwo0GU1D68U2d_eerkYEIt-mc0dNtdFasy5DG_GtvnWA4nsbf0BVsYKSZcRiDK4d4qbHu9NMjBdEwSkP9KDGEtou0yHtOnVzB1eHHNm_uSUO-O_kz2LWsXOPK2sbL1LTiCKS0XToJPdlaNczDMZB0nXR3sHbyi3Lwk-Va2ATS6Kke5M1KmFMowK-Y0jK2urt8GnCBIXvZMT6gUW9-dvlv4w_lAuVXQ9hFg_r0sBnoWzZOUR_xlrz2T-syjrZzmXlAkJrcD8KWPH-lCs0jD9pdiROhQ"
const userjwtUser = "ebbad927-4c39-4d12-8690-89b067dd4ce7"

const userid = "dd69ea0d-f553-4336-80f3-7f4567f85c7b"

Expand Down

0 comments on commit 1954c08

Please sign in to comment.