diff --git a/bootstrap/api/endpoint.go b/bootstrap/api/endpoint.go index 03b694aa..138e3513 100644 --- a/bootstrap/api/endpoint.go +++ b/bootstrap/api/endpoint.go @@ -55,7 +55,7 @@ func updateCertEndpoint(svc bootstrap.Service) endpoint.Endpoint { return nil, err } - if err := svc.UpdateCert(ctx, req.key, req.thingID, req.ClientCert, req.ClientKey, req.CACert); err != nil { + if err := svc.UpdateCert(ctx, req.token, req.thingID, req.ClientCert, req.ClientKey, req.CACert); err != nil { return nil, err } @@ -73,7 +73,7 @@ func viewEndpoint(svc bootstrap.Service) endpoint.Endpoint { return nil, err } - config, err := svc.View(ctx, req.key, req.id) + config, err := svc.View(ctx, req.token, req.id) if err != nil { return nil, err } @@ -116,7 +116,7 @@ func updateEndpoint(svc bootstrap.Service) endpoint.Endpoint { Content: req.Content, } - if err := svc.Update(ctx, req.key, config); err != nil { + if err := svc.Update(ctx, req.token, config); err != nil { return nil, err } @@ -137,7 +137,7 @@ func updateConnEndpoint(svc bootstrap.Service) endpoint.Endpoint { return nil, err } - if err := svc.UpdateConnections(ctx, req.key, req.id, req.Channels); err != nil { + if err := svc.UpdateConnections(ctx, req.token, req.id, req.Channels); err != nil { return nil, err } @@ -158,7 +158,7 @@ func listEndpoint(svc bootstrap.Service) endpoint.Endpoint { return nil, err } - page, err := svc.List(ctx, req.key, req.filter, req.offset, req.limit) + page, err := svc.List(ctx, req.token, req.filter, req.offset, req.limit) if err != nil { return nil, err } @@ -204,7 +204,7 @@ func removeEndpoint(svc bootstrap.Service) endpoint.Endpoint { return removeRes{}, err } - if err := svc.Remove(ctx, req.key, req.id); err != nil { + if err := svc.Remove(ctx, req.token, req.id); err != nil { return nil, err } @@ -236,7 +236,7 @@ func stateEndpoint(svc bootstrap.Service) endpoint.Endpoint { return nil, err } - if err := svc.ChangeState(ctx, req.key, req.id, req.State); err != nil { + if err := svc.ChangeState(ctx, req.token, req.id, req.State); err != nil { return nil, err } diff --git a/bootstrap/api/endpoint_test.go b/bootstrap/api/endpoint_test.go index 474a47c1..043902fe 100644 --- a/bootstrap/api/endpoint_test.go +++ b/bootstrap/api/endpoint_test.go @@ -99,6 +99,7 @@ type testRequest struct { url string contentType string token string + key string body io.Reader } @@ -125,6 +126,9 @@ func (tr testRequest) make() (*http.Response, error) { if tr.token != "" { req.Header.Set("Authorization", apiutil.BearerPrefix+tr.token) } + if tr.key != "" { + req.Header.Set("Authorization", apiutil.ThingPrefix+tr.key) + } if tr.contentType != "" { req.Header.Set("Content-Type", tr.contentType) @@ -1147,7 +1151,7 @@ func TestBootstrap(t *testing.T) { client: bs.Client(), method: http.MethodGet, url: fmt.Sprintf("%s/things/bootstrap/%s", bs.URL, tc.externalID), - token: tc.externalKey, + key: tc.externalKey, } res, err := req.make() assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) diff --git a/bootstrap/api/requests.go b/bootstrap/api/requests.go index 18cce4a9..ef6bb5c9 100644 --- a/bootstrap/api/requests.go +++ b/bootstrap/api/requests.go @@ -44,13 +44,13 @@ func (req addReq) validate() error { } type entityReq struct { - key string - id string + token string + id string } func (req entityReq) validate() error { - if req.key == "" { - return apiutil.ErrBearerKey + if req.token == "" { + return apiutil.ErrBearerToken } if req.id == "" { @@ -61,15 +61,15 @@ func (req entityReq) validate() error { } type updateReq struct { - key string + token string id string Name string `json:"name"` Content string `json:"content"` } func (req updateReq) validate() error { - if req.key == "" { - return apiutil.ErrBearerKey + if req.token == "" { + return apiutil.ErrBearerToken } if req.id == "" { @@ -80,7 +80,7 @@ func (req updateReq) validate() error { } type updateCertReq struct { - key string + token string thingID string ClientCert string `json:"client_cert"` ClientKey string `json:"client_key"` @@ -88,8 +88,8 @@ type updateCertReq struct { } func (req updateCertReq) validate() error { - if req.key == "" { - return apiutil.ErrBearerKey + if req.token == "" { + return apiutil.ErrBearerToken } if req.thingID == "" { @@ -100,14 +100,14 @@ func (req updateCertReq) validate() error { } type updateConnReq struct { - key string + token string id string Channels []string `json:"channels"` } func (req updateConnReq) validate() error { - if req.key == "" { - return apiutil.ErrBearerKey + if req.token == "" { + return apiutil.ErrBearerToken } if req.id == "" { @@ -118,15 +118,15 @@ func (req updateConnReq) validate() error { } type listReq struct { - key string + token string filter bootstrap.Filter offset uint64 limit uint64 } func (req listReq) validate() error { - if req.key == "" { - return apiutil.ErrBearerKey + if req.token == "" { + return apiutil.ErrBearerToken } if req.limit > maxLimitSize { @@ -154,14 +154,14 @@ func (req bootstrapReq) validate() error { } type changeStateReq struct { - key string + token string id string State bootstrap.State `json:"state"` } func (req changeStateReq) validate() error { - if req.key == "" { - return apiutil.ErrBearerKey + if req.token == "" { + return apiutil.ErrBearerToken } if req.id == "" { diff --git a/bootstrap/api/requests_test.go b/bootstrap/api/requests_test.go index 66f1a404..4ccaddff 100644 --- a/bootstrap/api/requests_test.go +++ b/bootstrap/api/requests_test.go @@ -54,28 +54,28 @@ func TestAddReqValidation(t *testing.T) { func TestEntityReqValidation(t *testing.T) { cases := []struct { - desc string - key string - id string - err error + desc string + token string + id string + err error }{ { - desc: "empty key", - key: "", - id: "id", - err: apiutil.ErrBearerKey, + desc: "empty token", + token: "", + id: "id", + err: apiutil.ErrBearerToken, }, { - desc: "empty id", - key: "key", - id: "", - err: apiutil.ErrMissingID, + desc: "empty id", + token: "token", + id: "", + err: apiutil.ErrMissingID, }, } for _, tc := range cases { req := entityReq{ - key: tc.key, + token: tc.token, } err := req.validate() @@ -85,29 +85,29 @@ func TestEntityReqValidation(t *testing.T) { func TestUpdateReqValidation(t *testing.T) { cases := []struct { - desc string - key string - id string - err error + desc string + token string + id string + err error }{ { - desc: "empty key", - key: "", - id: "id", - err: apiutil.ErrBearerKey, + desc: "empty token", + token: "", + id: "id", + err: apiutil.ErrBearerToken, }, { - desc: "empty id", - key: "key", - id: "", - err: apiutil.ErrMissingID, + desc: "empty id", + token: "token", + id: "", + err: apiutil.ErrMissingID, }, } for _, tc := range cases { req := updateReq{ - key: tc.key, - id: tc.id, + token: tc.token, + id: tc.id, } err := req.validate() @@ -118,19 +118,19 @@ func TestUpdateReqValidation(t *testing.T) { func TestUpdateCertReqValidation(t *testing.T) { cases := []struct { desc string - key string + token string thingID string err error }{ { - desc: "empty key", - key: "", + desc: "empty token", + token: "", thingID: "thingID", - err: apiutil.ErrBearerKey, + err: apiutil.ErrBearerToken, }, { desc: "empty thing id", - key: "key", + token: "token", thingID: "", err: apiutil.ErrMissingID, }, @@ -138,7 +138,7 @@ func TestUpdateCertReqValidation(t *testing.T) { for _, tc := range cases { req := updateCertReq{ - key: tc.key, + token: tc.token, thingID: tc.thingID, } @@ -149,29 +149,29 @@ func TestUpdateCertReqValidation(t *testing.T) { func TestUpdateConnReqValidation(t *testing.T) { cases := []struct { - desc string - key string - id string - err error + desc string + token string + id string + err error }{ { - desc: "empty key", - key: "", - id: "id", - err: apiutil.ErrBearerKey, + desc: "empty token", + token: "", + id: "id", + err: apiutil.ErrBearerToken, }, { - desc: "empty id", - key: "key", - id: "", - err: apiutil.ErrMissingID, + desc: "empty id", + token: "token", + id: "", + err: apiutil.ErrMissingID, }, } for _, tc := range cases { req := updateReq{ - key: tc.key, - id: tc.id, + token: tc.token, + id: tc.id, } err := req.validate() @@ -183,27 +183,27 @@ func TestListReqValidation(t *testing.T) { cases := []struct { desc string offset uint64 - key string + token string limit uint64 err error }{ { - desc: "empty key", - key: "", + desc: "empty token", + token: "", offset: 0, limit: 1, - err: apiutil.ErrBearerKey, + err: apiutil.ErrBearerToken, }, { desc: "too large limit", - key: "key", + token: "token", offset: 0, limit: maxLimitSize + 1, err: apiutil.ErrLimitSize, }, { desc: "default limit", - key: "key", + token: "token", offset: 0, limit: defLimit, err: nil, @@ -212,7 +212,7 @@ func TestListReqValidation(t *testing.T) { for _, tc := range cases { req := listReq{ - key: tc.key, + token: tc.token, offset: tc.offset, limit: tc.limit, } @@ -257,28 +257,28 @@ func TestBootstrapReqValidation(t *testing.T) { func TestChangeStateReqValidation(t *testing.T) { cases := []struct { desc string - key string + token string id string state bootstrap.State err error }{ { - desc: "empty key", - key: "", + desc: "empty token", + token: "", id: "id", state: bootstrap.State(1), - err: apiutil.ErrBearerKey, + err: apiutil.ErrBearerToken, }, { desc: "empty id", - key: "key", + token: "token", id: "", state: bootstrap.State(0), err: apiutil.ErrMissingID, }, { desc: "invalid state", - key: "key", + token: "token", id: "id", state: bootstrap.State(14), err: apiutil.ErrBootstrapState, @@ -287,7 +287,7 @@ func TestChangeStateReqValidation(t *testing.T) { for _, tc := range cases { req := changeStateReq{ - key: tc.key, + token: tc.token, id: tc.id, State: tc.state, } diff --git a/bootstrap/api/transport.go b/bootstrap/api/transport.go index 445b1b22..c716632e 100644 --- a/bootstrap/api/transport.go +++ b/bootstrap/api/transport.go @@ -125,8 +125,8 @@ func decodeUpdateRequest(_ context.Context, r *http.Request) (interface{}, error } req := updateReq{ - key: apiutil.ExtractBearerToken(r), - id: bone.GetValue(r, "id"), + token: apiutil.ExtractBearerToken(r), + id: bone.GetValue(r, "id"), } if err := json.NewDecoder(r.Body).Decode(&req); err != nil { return nil, errors.Wrap(errors.ErrMalformedEntity, err) @@ -141,7 +141,7 @@ func decodeUpdateCertRequest(_ context.Context, r *http.Request) (interface{}, e } req := updateCertReq{ - key: apiutil.ExtractBearerToken(r), + token: apiutil.ExtractBearerToken(r), thingID: bone.GetValue(r, "id"), } if err := json.NewDecoder(r.Body).Decode(&req); err != nil { @@ -157,8 +157,8 @@ func decodeUpdateConnRequest(_ context.Context, r *http.Request) (interface{}, e } req := updateConnReq{ - key: apiutil.ExtractBearerToken(r), - id: bone.GetValue(r, "id"), + token: apiutil.ExtractBearerToken(r), + id: bone.GetValue(r, "id"), } if err := json.NewDecoder(r.Body).Decode(&req); err != nil { return nil, errors.Wrap(errors.ErrMalformedEntity, err) @@ -184,7 +184,7 @@ func decodeListRequest(_ context.Context, r *http.Request) (interface{}, error) } req := listReq{ - key: apiutil.ExtractBearerToken(r), + token: apiutil.ExtractBearerToken(r), filter: parseFilter(q), offset: o, limit: l, @@ -196,7 +196,7 @@ func decodeListRequest(_ context.Context, r *http.Request) (interface{}, error) func decodeBootstrapRequest(_ context.Context, r *http.Request) (interface{}, error) { req := bootstrapReq{ id: bone.GetValue(r, "external_id"), - key: apiutil.ExtractBearerToken(r), + key: apiutil.ExtractThingKey(r), } return req, nil @@ -208,8 +208,8 @@ func decodeStateRequest(_ context.Context, r *http.Request) (interface{}, error) } req := changeStateReq{ - key: apiutil.ExtractBearerToken(r), - id: bone.GetValue(r, "id"), + token: apiutil.ExtractBearerToken(r), + id: bone.GetValue(r, "id"), } if err := json.NewDecoder(r.Body).Decode(&req); err != nil { return nil, errors.Wrap(errors.ErrMalformedEntity, err) @@ -220,8 +220,8 @@ func decodeStateRequest(_ context.Context, r *http.Request) (interface{}, error) func decodeEntityRequest(_ context.Context, r *http.Request) (interface{}, error) { req := entityReq{ - key: apiutil.ExtractBearerToken(r), - id: bone.GetValue(r, "id"), + token: apiutil.ExtractBearerToken(r), + id: bone.GetValue(r, "id"), } return req, nil diff --git a/certs/api/requests.go b/certs/api/requests.go index 1ba83a56..3ad267a7 100644 --- a/certs/api/requests.go +++ b/certs/api/requests.go @@ -42,7 +42,7 @@ func (req *listReq) validate() error { if req.token == "" { return apiutil.ErrBearerToken } - if req.limit > 1 || req.limit > maxLimitSize { + if req.limit > maxLimitSize { return apiutil.ErrLimitSize } return nil diff --git a/http/api/endpoint_test.go b/http/api/endpoint_test.go index 99e0c022..cdfb29c0 100644 --- a/http/api/endpoint_test.go +++ b/http/api/endpoint_test.go @@ -50,7 +50,7 @@ func (tr testRequest) make() (*http.Response, error) { } if tr.token != "" { - req.Header.Set("Authorization", apiutil.BearerPrefix+tr.token) + req.Header.Set("Authorization", apiutil.ThingPrefix+tr.token) } if tr.basicAuth && tr.token != "" { req.SetBasicAuth("", tr.token) diff --git a/http/api/transport.go b/http/api/transport.go index c3b54d57..f13a9a9c 100644 --- a/http/api/transport.go +++ b/http/api/transport.go @@ -116,7 +116,7 @@ func decodeRequest(ctx context.Context, r *http.Request) (interface{}, error) { case ok: token = pass case !ok: - token = apiutil.ExtractBearerToken(r) + token = apiutil.ExtractThingKey(r) } payload, err := ioutil.ReadAll(r.Body) diff --git a/internal/apiutil/token.go b/internal/apiutil/token.go index 4cd74cf1..ba10d6ee 100644 --- a/internal/apiutil/token.go +++ b/internal/apiutil/token.go @@ -11,6 +11,9 @@ import ( // BearerPrefix represents the token prefix for Bearer authentication scheme. const BearerPrefix = "Bearer " +// ThingPrefix represents the key prefix for Thing authentication scheme. +const ThingPrefix = "Thing " + // ExtractBearerToken returns value of the bearer token. If there is no bearer token - an empty value is returned. func ExtractBearerToken(r *http.Request) string { token := r.Header.Get("Authorization") @@ -21,3 +24,14 @@ func ExtractBearerToken(r *http.Request) string { return strings.TrimPrefix(token, BearerPrefix) } + +// ExtractThingKey returns value of the thing key. If there is no thing key - an empty value is returned. +func ExtractThingKey(r *http.Request) string { + token := r.Header.Get("Authorization") + + if !strings.HasPrefix(token, ThingPrefix) { + return "" + } + + return strings.TrimPrefix(token, ThingPrefix) +} diff --git a/pkg/sdk/go/message.go b/pkg/sdk/go/message.go index ef104b65..3dcf1106 100644 --- a/pkg/sdk/go/message.go +++ b/pkg/sdk/go/message.go @@ -13,7 +13,7 @@ import ( "github.com/mainflux/mainflux/pkg/errors" ) -func (sdk mfSDK) SendMessage(chanName, msg, token string) error { +func (sdk mfSDK) SendMessage(chanName, msg, key string) error { chanNameParts := strings.SplitN(chanName, ".", 2) chanID := chanNameParts[0] subtopicPart := "" @@ -28,7 +28,7 @@ func (sdk mfSDK) SendMessage(chanName, msg, token string) error { return err } - resp, err := sdk.sendRequest(req, token, string(sdk.msgContentType)) + resp, err := sdk.sendThingRequest(req, key, string(sdk.msgContentType)) if err != nil { return err } diff --git a/pkg/sdk/go/sdk.go b/pkg/sdk/go/sdk.go index 25c25ccd..56100fcd 100644 --- a/pkg/sdk/go/sdk.go +++ b/pkg/sdk/go/sdk.go @@ -337,3 +337,15 @@ func (sdk mfSDK) sendRequest(req *http.Request, token, contentType string) (*htt return sdk.client.Do(req) } + +func (sdk mfSDK) sendThingRequest(req *http.Request, key, contentType string) (*http.Response, error) { + if key != "" { + req.Header.Set("Authorization", apiutil.ThingPrefix+key) + } + + if contentType != "" { + req.Header.Add("Content-Type", contentType) + } + + return sdk.client.Do(req) +} diff --git a/readers/api/endpoint_test.go b/readers/api/endpoint_test.go index 83d2aa1c..bebb73cb 100644 --- a/readers/api/endpoint_test.go +++ b/readers/api/endpoint_test.go @@ -13,6 +13,7 @@ import ( "time" "github.com/mainflux/mainflux" + "github.com/mainflux/mainflux/internal/apiutil" "github.com/mainflux/mainflux/logger" "github.com/mainflux/mainflux/pkg/transformers/senml" "github.com/mainflux/mainflux/pkg/uuid" @@ -59,6 +60,7 @@ type testRequest struct { method string url string token string + key string body io.Reader } @@ -68,7 +70,10 @@ func (tr testRequest) make() (*http.Response, error) { return nil, err } if tr.token != "" { - req.Header.Set("Authorization", tr.token) + req.Header.Set("Authorization", apiutil.BearerPrefix+tr.token) + } + if tr.key != "" { + req.Header.Set("Authorization", apiutil.ThingPrefix+tr.key) } return tr.client.Do(req) @@ -141,13 +146,14 @@ func TestReadAll(t *testing.T) { req string url string token string + key string status int res pageRes }{ { desc: "read page with valid offset and limit", url: fmt.Sprintf("%s/channels/%s/messages?offset=0&limit=10", ts.URL, chanID), - token: fmt.Sprintf("Thing %s", thingToken), + key: thingToken, status: http.StatusOK, res: pageRes{ Total: uint64(len(messages)), @@ -157,7 +163,7 @@ func TestReadAll(t *testing.T) { { desc: "read page with valid offset and limit as user", url: fmt.Sprintf("%s/channels/%s/messages?offset=0&limit=10", ts.URL, chanID), - token: fmt.Sprintf("Bearer %s", userToken), + token: userToken, status: http.StatusOK, res: pageRes{ Total: uint64(len(messages)), @@ -167,55 +173,55 @@ func TestReadAll(t *testing.T) { { desc: "read page with negative offset as thing", url: fmt.Sprintf("%s/channels/%s/messages?offset=-1&limit=10", ts.URL, chanID), - token: fmt.Sprintf("Thing %s", thingToken), + key: thingToken, status: http.StatusBadRequest, }, { desc: "read page with negative limit as thing", url: fmt.Sprintf("%s/channels/%s/messages?offset=0&limit=-10", ts.URL, chanID), - token: fmt.Sprintf("Thing %s", thingToken), + key: thingToken, status: http.StatusBadRequest, }, { desc: "read page with zero limit as thing", url: fmt.Sprintf("%s/channels/%s/messages?offset=0&limit=0", ts.URL, chanID), - token: fmt.Sprintf("Thing %s", thingToken), + key: thingToken, status: http.StatusBadRequest, }, { desc: "read page with non-integer offset as thing", url: fmt.Sprintf("%s/channels/%s/messages?offset=abc&limit=10", ts.URL, chanID), - token: fmt.Sprintf("Thing %s", thingToken), + key: thingToken, status: http.StatusBadRequest, }, { desc: "read page with non-integer limit as thing", url: fmt.Sprintf("%s/channels/%s/messages?offset=0&limit=abc", ts.URL, chanID), - token: fmt.Sprintf("Thing %s", thingToken), + key: thingToken, status: http.StatusBadRequest, }, { desc: "read page with invalid channel id as thing", url: fmt.Sprintf("%s/channels//messages?offset=0&limit=10", ts.URL), - token: fmt.Sprintf("Thing %s", thingToken), + key: thingToken, status: http.StatusBadRequest, }, { desc: "read page with invalid token as thing", url: fmt.Sprintf("%s/channels/%s/messages?offset=0&limit=10", ts.URL, chanID), - token: fmt.Sprintf("Thing %s", invalid), + token: invalid, status: http.StatusUnauthorized, }, { desc: "read page with multiple offset as thing", url: fmt.Sprintf("%s/channels/%s/messages?offset=0&offset=1&limit=10", ts.URL, chanID), - token: fmt.Sprintf("Thing %s", thingToken), + key: thingToken, status: http.StatusBadRequest, }, { desc: "read page with multiple limit as thing", url: fmt.Sprintf("%s/channels/%s/messages?offset=0&limit=20&limit=10", ts.URL, chanID), - token: fmt.Sprintf("Thing %s", thingToken), + key: thingToken, status: http.StatusBadRequest, }, { @@ -227,7 +233,7 @@ func TestReadAll(t *testing.T) { { desc: "read page with default offset as thing", url: fmt.Sprintf("%s/channels/%s/messages?limit=10", ts.URL, chanID), - token: fmt.Sprintf("Thing %s", thingToken), + key: thingToken, status: http.StatusOK, res: pageRes{ Total: uint64(len(messages)), @@ -237,7 +243,7 @@ func TestReadAll(t *testing.T) { { desc: "read page with default limit as thing", url: fmt.Sprintf("%s/channels/%s/messages?offset=0", ts.URL, chanID), - token: fmt.Sprintf("Thing %s", thingToken), + key: thingToken, status: http.StatusOK, res: pageRes{ Total: uint64(len(messages)), @@ -247,7 +253,7 @@ func TestReadAll(t *testing.T) { { desc: "read page with senml format as thing", url: fmt.Sprintf("%s/channels/%s/messages?format=messages", ts.URL, chanID), - token: fmt.Sprintf("Thing %s", thingToken), + key: thingToken, status: http.StatusOK, res: pageRes{ Total: uint64(len(messages)), @@ -257,7 +263,7 @@ func TestReadAll(t *testing.T) { { desc: "read page with subtopic as thing", url: fmt.Sprintf("%s/channels/%s/messages?subtopic=%s&protocol=%s", ts.URL, chanID, subtopic, httpProt), - token: fmt.Sprintf("Thing %s", thingToken), + key: thingToken, status: http.StatusOK, res: pageRes{ Total: uint64(len(queryMsgs)), @@ -267,7 +273,7 @@ func TestReadAll(t *testing.T) { { desc: "read page with subtopic and protocol as thing", url: fmt.Sprintf("%s/channels/%s/messages?subtopic=%s&protocol=%s", ts.URL, chanID, subtopic, httpProt), - token: fmt.Sprintf("Thing %s", thingToken), + key: thingToken, status: http.StatusOK, res: pageRes{ Total: uint64(len(queryMsgs)), @@ -277,7 +283,7 @@ func TestReadAll(t *testing.T) { { desc: "read page with publisher as thing", url: fmt.Sprintf("%s/channels/%s/messages?publisher=%s", ts.URL, chanID, pubID2), - token: fmt.Sprintf("Thing %s", thingToken), + key: thingToken, status: http.StatusOK, res: pageRes{ Total: uint64(len(queryMsgs)), @@ -287,7 +293,7 @@ func TestReadAll(t *testing.T) { { desc: "read page with protocol as thing", url: fmt.Sprintf("%s/channels/%s/messages?protocol=http", ts.URL, chanID), - token: fmt.Sprintf("Thing %s", thingToken), + key: thingToken, status: http.StatusOK, res: pageRes{ Total: uint64(len(queryMsgs)), @@ -297,7 +303,7 @@ func TestReadAll(t *testing.T) { { desc: "read page with name as thing", url: fmt.Sprintf("%s/channels/%s/messages?name=%s", ts.URL, chanID, msgName), - token: fmt.Sprintf("Thing %s", thingToken), + key: thingToken, status: http.StatusOK, res: pageRes{ Total: uint64(len(queryMsgs)), @@ -307,7 +313,7 @@ func TestReadAll(t *testing.T) { { desc: "read page with value as thing", url: fmt.Sprintf("%s/channels/%s/messages?v=%f", ts.URL, chanID, v), - token: fmt.Sprintf("Thing %s", thingToken), + key: thingToken, status: http.StatusOK, res: pageRes{ Total: uint64(len(valueMsgs)), @@ -317,7 +323,7 @@ func TestReadAll(t *testing.T) { { desc: "read page with value and equal comparator as thing", url: fmt.Sprintf("%s/channels/%s/messages?v=%f&comparator=%s", ts.URL, chanID, v, readers.EqualKey), - token: fmt.Sprintf("Thing %s", thingToken), + key: thingToken, status: http.StatusOK, res: pageRes{ Total: uint64(len(valueMsgs)), @@ -327,7 +333,7 @@ func TestReadAll(t *testing.T) { { desc: "read page with value and lower-than comparator as thing", url: fmt.Sprintf("%s/channels/%s/messages?v=%f&comparator=%s", ts.URL, chanID, v+1, readers.LowerThanKey), - token: fmt.Sprintf("Thing %s", thingToken), + key: thingToken, status: http.StatusOK, res: pageRes{ Total: uint64(len(valueMsgs)), @@ -337,7 +343,7 @@ func TestReadAll(t *testing.T) { { desc: "read page with value and lower-than-or-equal comparator as thing", url: fmt.Sprintf("%s/channels/%s/messages?v=%f&comparator=%s", ts.URL, chanID, v+1, readers.LowerThanEqualKey), - token: fmt.Sprintf("Thing %s", thingToken), + key: thingToken, status: http.StatusOK, res: pageRes{ Total: uint64(len(valueMsgs)), @@ -347,7 +353,7 @@ func TestReadAll(t *testing.T) { { desc: "read page with value and greater-than comparator as thing", url: fmt.Sprintf("%s/channels/%s/messages?v=%f&comparator=%s", ts.URL, chanID, v-1, readers.GreaterThanKey), - token: fmt.Sprintf("Thing %s", thingToken), + key: thingToken, status: http.StatusOK, res: pageRes{ Total: uint64(len(valueMsgs)), @@ -357,7 +363,7 @@ func TestReadAll(t *testing.T) { { desc: "read page with value and greater-than-or-equal comparator as thing", url: fmt.Sprintf("%s/channels/%s/messages?v=%f&comparator=%s", ts.URL, chanID, v-1, readers.GreaterThanEqualKey), - token: fmt.Sprintf("Thing %s", thingToken), + key: thingToken, status: http.StatusOK, res: pageRes{ Total: uint64(len(valueMsgs)), @@ -367,19 +373,19 @@ func TestReadAll(t *testing.T) { { desc: "read page with non-float value as thing", url: fmt.Sprintf("%s/channels/%s/messages?v=ab01", ts.URL, chanID), - token: fmt.Sprintf("Thing %s", thingToken), + key: thingToken, status: http.StatusBadRequest, }, { desc: "read page with value and wrong comparator as thing", url: fmt.Sprintf("%s/channels/%s/messages?v=%f&comparator=wrong", ts.URL, chanID, v-1), - token: fmt.Sprintf("Thing %s", thingToken), + key: thingToken, status: http.StatusBadRequest, }, { desc: "read page with boolean value as thing", url: fmt.Sprintf("%s/channels/%s/messages?vb=true", ts.URL, chanID), - token: fmt.Sprintf("Thing %s", thingToken), + key: thingToken, status: http.StatusOK, res: pageRes{ Total: uint64(len(boolMsgs)), @@ -389,13 +395,13 @@ func TestReadAll(t *testing.T) { { desc: "read page with non-boolean value as thing", url: fmt.Sprintf("%s/channels/%s/messages?vb=yes", ts.URL, chanID), - token: fmt.Sprintf("Thing %s", thingToken), + key: thingToken, status: http.StatusBadRequest, }, { desc: "read page with string value as thing", url: fmt.Sprintf("%s/channels/%s/messages?vs=%s", ts.URL, chanID, vs), - token: fmt.Sprintf("Thing %s", thingToken), + key: thingToken, status: http.StatusOK, res: pageRes{ Total: uint64(len(stringMsgs)), @@ -405,7 +411,7 @@ func TestReadAll(t *testing.T) { { desc: "read page with data value as thing", url: fmt.Sprintf("%s/channels/%s/messages?vd=%s", ts.URL, chanID, vd), - token: fmt.Sprintf("Thing %s", thingToken), + key: thingToken, status: http.StatusOK, res: pageRes{ Total: uint64(len(dataMsgs)), @@ -415,20 +421,20 @@ func TestReadAll(t *testing.T) { { desc: "read page with non-float from as thing", url: fmt.Sprintf("%s/channels/%s/messages?from=ABCD", ts.URL, chanID), - token: fmt.Sprintf("Thing %s", thingToken), + key: thingToken, status: http.StatusBadRequest, }, { desc: "read page with non-float to as thing", url: fmt.Sprintf("%s/channels/%s/messages?to=ABCD", ts.URL, chanID), - token: fmt.Sprintf("Thing %s", thingToken), + key: thingToken, status: http.StatusBadRequest, }, { desc: "read page with from/to as thing", url: fmt.Sprintf("%s/channels/%s/messages?from=%f&to=%f", ts.URL, chanID, messages[19].Time, messages[4].Time), - token: fmt.Sprintf("Thing %s", thingToken), + key: thingToken, status: http.StatusOK, res: pageRes{ Total: uint64(len(messages[5:20])), @@ -438,7 +444,7 @@ func TestReadAll(t *testing.T) { { desc: "read page with valid offset and limit as user", url: fmt.Sprintf("%s/channels/%s/messages?offset=0&limit=10", ts.URL, chanID), - token: fmt.Sprintf("Bearer %s", userToken), + token: userToken, status: http.StatusOK, res: pageRes{ Total: uint64(len(messages)), @@ -448,55 +454,55 @@ func TestReadAll(t *testing.T) { { desc: "read page with negative offset as user", url: fmt.Sprintf("%s/channels/%s/messages?offset=-1&limit=10", ts.URL, chanID), - token: fmt.Sprintf("Bearer %s", userToken), + token: userToken, status: http.StatusBadRequest, }, { desc: "read page with negative limit as user", url: fmt.Sprintf("%s/channels/%s/messages?offset=0&limit=-10", ts.URL, chanID), - token: fmt.Sprintf("Bearer %s", userToken), + token: userToken, status: http.StatusBadRequest, }, { desc: "read page with zero limit as user", url: fmt.Sprintf("%s/channels/%s/messages?offset=0&limit=0", ts.URL, chanID), - token: fmt.Sprintf("Bearer %s", userToken), + token: userToken, status: http.StatusBadRequest, }, { desc: "read page with non-integer offset as user", url: fmt.Sprintf("%s/channels/%s/messages?offset=abc&limit=10", ts.URL, chanID), - token: fmt.Sprintf("Bearer %s", userToken), + token: userToken, status: http.StatusBadRequest, }, { desc: "read page with non-integer limit as user", url: fmt.Sprintf("%s/channels/%s/messages?offset=0&limit=abc", ts.URL, chanID), - token: fmt.Sprintf("Bearer %s", userToken), + token: userToken, status: http.StatusBadRequest, }, { desc: "read page with invalid channel id as user", url: fmt.Sprintf("%s/channels//messages?offset=0&limit=10", ts.URL), - token: fmt.Sprintf("Bearer %s", userToken), + token: userToken, status: http.StatusBadRequest, }, { desc: "read page with invalid token as user", url: fmt.Sprintf("%s/channels/%s/messages?offset=0&limit=10", ts.URL, chanID), - token: fmt.Sprintf("Bearer %s", invalid), + token: invalid, status: http.StatusUnauthorized, }, { desc: "read page with multiple offset as user", url: fmt.Sprintf("%s/channels/%s/messages?offset=0&offset=1&limit=10", ts.URL, chanID), - token: fmt.Sprintf("Bearer %s", userToken), + token: userToken, status: http.StatusBadRequest, }, { desc: "read page with multiple limit as user", url: fmt.Sprintf("%s/channels/%s/messages?offset=0&limit=20&limit=10", ts.URL, chanID), - token: fmt.Sprintf("Bearer %s", userToken), + token: userToken, status: http.StatusBadRequest, }, { @@ -508,7 +514,7 @@ func TestReadAll(t *testing.T) { { desc: "read page with default offset as user", url: fmt.Sprintf("%s/channels/%s/messages?limit=10", ts.URL, chanID), - token: fmt.Sprintf("Bearer %s", userToken), + token: userToken, status: http.StatusOK, res: pageRes{ Total: uint64(len(messages)), @@ -518,7 +524,7 @@ func TestReadAll(t *testing.T) { { desc: "read page with default limit as user", url: fmt.Sprintf("%s/channels/%s/messages?offset=0", ts.URL, chanID), - token: fmt.Sprintf("Bearer %s", userToken), + token: userToken, status: http.StatusOK, res: pageRes{ Total: uint64(len(messages)), @@ -528,7 +534,7 @@ func TestReadAll(t *testing.T) { { desc: "read page with senml format as user", url: fmt.Sprintf("%s/channels/%s/messages?format=messages", ts.URL, chanID), - token: fmt.Sprintf("Bearer %s", userToken), + token: userToken, status: http.StatusOK, res: pageRes{ Total: uint64(len(messages)), @@ -538,7 +544,7 @@ func TestReadAll(t *testing.T) { { desc: "read page with subtopic as user", url: fmt.Sprintf("%s/channels/%s/messages?subtopic=%s&protocol=%s", ts.URL, chanID, subtopic, httpProt), - token: fmt.Sprintf("Bearer %s", userToken), + token: userToken, status: http.StatusOK, res: pageRes{ Total: uint64(len(queryMsgs)), @@ -548,7 +554,7 @@ func TestReadAll(t *testing.T) { { desc: "read page with subtopic and protocol as user", url: fmt.Sprintf("%s/channels/%s/messages?subtopic=%s&protocol=%s", ts.URL, chanID, subtopic, httpProt), - token: fmt.Sprintf("Bearer %s", userToken), + token: userToken, status: http.StatusOK, res: pageRes{ Total: uint64(len(queryMsgs)), @@ -558,7 +564,7 @@ func TestReadAll(t *testing.T) { { desc: "read page with publisher as user", url: fmt.Sprintf("%s/channels/%s/messages?publisher=%s", ts.URL, chanID, pubID2), - token: fmt.Sprintf("Bearer %s", userToken), + token: userToken, status: http.StatusOK, res: pageRes{ Total: uint64(len(queryMsgs)), @@ -568,7 +574,7 @@ func TestReadAll(t *testing.T) { { desc: "read page with protocol as user", url: fmt.Sprintf("%s/channels/%s/messages?protocol=http", ts.URL, chanID), - token: fmt.Sprintf("Bearer %s", userToken), + token: userToken, status: http.StatusOK, res: pageRes{ Total: uint64(len(queryMsgs)), @@ -578,7 +584,7 @@ func TestReadAll(t *testing.T) { { desc: "read page with name as user", url: fmt.Sprintf("%s/channels/%s/messages?name=%s", ts.URL, chanID, msgName), - token: fmt.Sprintf("Bearer %s", userToken), + token: userToken, status: http.StatusOK, res: pageRes{ Total: uint64(len(queryMsgs)), @@ -588,7 +594,7 @@ func TestReadAll(t *testing.T) { { desc: "read page with value as user", url: fmt.Sprintf("%s/channels/%s/messages?v=%f", ts.URL, chanID, v), - token: fmt.Sprintf("Bearer %s", userToken), + token: userToken, status: http.StatusOK, res: pageRes{ Total: uint64(len(valueMsgs)), @@ -598,7 +604,7 @@ func TestReadAll(t *testing.T) { { desc: "read page with value and equal comparator as user", url: fmt.Sprintf("%s/channels/%s/messages?v=%f&comparator=%s", ts.URL, chanID, v, readers.EqualKey), - token: fmt.Sprintf("Bearer %s", userToken), + token: userToken, status: http.StatusOK, res: pageRes{ Total: uint64(len(valueMsgs)), @@ -608,7 +614,7 @@ func TestReadAll(t *testing.T) { { desc: "read page with value and lower-than comparator as user", url: fmt.Sprintf("%s/channels/%s/messages?v=%f&comparator=%s", ts.URL, chanID, v+1, readers.LowerThanKey), - token: fmt.Sprintf("Bearer %s", userToken), + token: userToken, status: http.StatusOK, res: pageRes{ Total: uint64(len(valueMsgs)), @@ -618,7 +624,7 @@ func TestReadAll(t *testing.T) { { desc: "read page with value and lower-than-or-equal comparator as user", url: fmt.Sprintf("%s/channels/%s/messages?v=%f&comparator=%s", ts.URL, chanID, v+1, readers.LowerThanEqualKey), - token: fmt.Sprintf("Bearer %s", userToken), + token: userToken, status: http.StatusOK, res: pageRes{ Total: uint64(len(valueMsgs)), @@ -628,7 +634,7 @@ func TestReadAll(t *testing.T) { { desc: "read page with value and greater-than comparator as user", url: fmt.Sprintf("%s/channels/%s/messages?v=%f&comparator=%s", ts.URL, chanID, v-1, readers.GreaterThanKey), - token: fmt.Sprintf("Bearer %s", userToken), + token: userToken, status: http.StatusOK, res: pageRes{ Total: uint64(len(valueMsgs)), @@ -638,7 +644,7 @@ func TestReadAll(t *testing.T) { { desc: "read page with value and greater-than-or-equal comparator as user", url: fmt.Sprintf("%s/channels/%s/messages?v=%f&comparator=%s", ts.URL, chanID, v-1, readers.GreaterThanEqualKey), - token: fmt.Sprintf("Bearer %s", userToken), + token: userToken, status: http.StatusOK, res: pageRes{ Total: uint64(len(valueMsgs)), @@ -648,19 +654,19 @@ func TestReadAll(t *testing.T) { { desc: "read page with non-float value as user", url: fmt.Sprintf("%s/channels/%s/messages?v=ab01", ts.URL, chanID), - token: fmt.Sprintf("Bearer %s", userToken), + token: userToken, status: http.StatusBadRequest, }, { desc: "read page with value and wrong comparator as user", url: fmt.Sprintf("%s/channels/%s/messages?v=%f&comparator=wrong", ts.URL, chanID, v-1), - token: fmt.Sprintf("Bearer %s", userToken), + token: userToken, status: http.StatusBadRequest, }, { desc: "read page with boolean value as user", url: fmt.Sprintf("%s/channels/%s/messages?vb=true", ts.URL, chanID), - token: fmt.Sprintf("Bearer %s", userToken), + token: userToken, status: http.StatusOK, res: pageRes{ Total: uint64(len(boolMsgs)), @@ -670,13 +676,13 @@ func TestReadAll(t *testing.T) { { desc: "read page with non-boolean value as user", url: fmt.Sprintf("%s/channels/%s/messages?vb=yes", ts.URL, chanID), - token: fmt.Sprintf("Bearer %s", userToken), + token: userToken, status: http.StatusBadRequest, }, { desc: "read page with string value as user", url: fmt.Sprintf("%s/channels/%s/messages?vs=%s", ts.URL, chanID, vs), - token: fmt.Sprintf("Bearer %s", userToken), + token: userToken, status: http.StatusOK, res: pageRes{ Total: uint64(len(stringMsgs)), @@ -686,7 +692,7 @@ func TestReadAll(t *testing.T) { { desc: "read page with data value as user", url: fmt.Sprintf("%s/channels/%s/messages?vd=%s", ts.URL, chanID, vd), - token: fmt.Sprintf("Bearer %s", userToken), + token: userToken, status: http.StatusOK, res: pageRes{ Total: uint64(len(dataMsgs)), @@ -696,20 +702,20 @@ func TestReadAll(t *testing.T) { { desc: "read page with non-float from as user", url: fmt.Sprintf("%s/channels/%s/messages?from=ABCD", ts.URL, chanID), - token: fmt.Sprintf("Bearer %s", userToken), + token: userToken, status: http.StatusBadRequest, }, { desc: "read page with non-float to as user", url: fmt.Sprintf("%s/channels/%s/messages?to=ABCD", ts.URL, chanID), - token: fmt.Sprintf("Bearer %s", userToken), + token: userToken, status: http.StatusBadRequest, }, { desc: "read page with from/to as user", url: fmt.Sprintf("%s/channels/%s/messages?from=%f&to=%f", ts.URL, chanID, messages[19].Time, messages[4].Time), - token: fmt.Sprintf("Bearer %s", userToken), + token: userToken, status: http.StatusOK, res: pageRes{ Total: uint64(len(messages[5:20])), @@ -724,6 +730,7 @@ func TestReadAll(t *testing.T) { method: http.MethodGet, url: tc.url, token: tc.token, + key: tc.key, } res, err := req.make() assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) diff --git a/readers/api/requests.go b/readers/api/requests.go index b717db7e..b10c9a53 100644 --- a/readers/api/requests.go +++ b/readers/api/requests.go @@ -17,11 +17,12 @@ type apiReq interface { type listMessagesReq struct { chanID string token string + key string pageMeta readers.PageMetadata } func (req listMessagesReq) validate() error { - if req.token == "" { + if req.token == "" && req.key == "" { return apiutil.ErrBearerToken } diff --git a/readers/api/transport.go b/readers/api/transport.go index a764f440..012db886 100644 --- a/readers/api/transport.go +++ b/readers/api/transport.go @@ -7,7 +7,6 @@ import ( "context" "encoding/json" "net/http" - "strings" kithttp "github.com/go-kit/kit/transport/http" "github.com/go-zoo/bone" @@ -22,26 +21,24 @@ import ( ) const ( - contentType = "application/json" - offsetKey = "offset" - limitKey = "limit" - formatKey = "format" - subtopicKey = "subtopic" - publisherKey = "publisher" - protocolKey = "protocol" - nameKey = "name" - valueKey = "v" - stringValueKey = "vs" - dataValueKey = "vd" - boolValueKey = "vb" - comparatorKey = "comparator" - fromKey = "from" - toKey = "to" - defLimit = 10 - defOffset = 0 - defFormat = "messages" - thingTokenPrefix = "Thing " - userTokenPrefix = "Bearer " + contentType = "application/json" + offsetKey = "offset" + limitKey = "limit" + formatKey = "format" + subtopicKey = "subtopic" + publisherKey = "publisher" + protocolKey = "protocol" + nameKey = "name" + valueKey = "v" + stringValueKey = "vs" + dataValueKey = "vd" + boolValueKey = "vb" + comparatorKey = "comparator" + fromKey = "from" + toKey = "to" + defLimit = 10 + defOffset = 0 + defFormat = "messages" ) var ( @@ -142,7 +139,8 @@ func decodeList(ctx context.Context, r *http.Request) (interface{}, error) { req := listMessagesReq{ chanID: bone.GetValue(r, "chanID"), - token: r.Header.Get("Authorization"), + token: apiutil.ExtractBearerToken(r), + key: apiutil.ExtractThingKey(r), pageMeta: readers.PageMetadata{ Offset: offset, Limit: limit, @@ -219,9 +217,8 @@ func encodeError(_ context.Context, err error, w http.ResponseWriter) { func authorize(ctx context.Context, req listMessagesReq, tc mainflux.ThingsServiceClient, ac mainflux.AuthServiceClient) (err error) { switch { - case strings.HasPrefix(req.token, userTokenPrefix): - token := strings.TrimPrefix(req.token, userTokenPrefix) - user, err := usersAuth.Identify(ctx, &mainflux.Token{Value: token}) + case req.token != "": + user, err := usersAuth.Identify(ctx, &mainflux.Token{Value: req.token}) if err != nil { e, ok := status.FromError(err) if ok && e.Code() == codes.PermissionDenied { @@ -238,8 +235,7 @@ func authorize(ctx context.Context, req listMessagesReq, tc mainflux.ThingsServi } return nil default: - token := strings.TrimPrefix(req.token, thingTokenPrefix) - if _, err := thingsAuth.CanAccessByKey(ctx, &mainflux.AccessByKeyReq{Token: token, ChanID: req.chanID}); err != nil { + if _, err := thingsAuth.CanAccessByKey(ctx, &mainflux.AccessByKeyReq{Token: req.key, ChanID: req.chanID}); err != nil { return errors.Wrap(errThingAccess, err) } return nil