Skip to content

Commit 2f34b10

Browse files
committed
don't look for device data provenance without a JWT
If a request uses a service secret, then there can be no extraction of provenance information, as that's only carried in a JWT, so don't try. While failed attempts weren't hurting anything, they were adding noise to the logs. BACK-2995
1 parent 2d52339 commit 2f34b10

File tree

4 files changed

+321
-24
lines changed

4 files changed

+321
-24
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ format-write-changed:
112112
imports: goimports
113113
@echo "goimports -d -e -local 'github.com/tidepool-org/platform'"
114114
@cd $(ROOT_DIRECTORY) && \
115-
O=`find . -not -path './.gvm_local/*' -not -path './vendor/*' -not -path '**/test/mock.go' -name '*.go' -type f -exec goimports -d -e -local 'github.com/tidepool-org/platform' {} \; 2>&1` && \
115+
O=`find . -not -path './.gvm_local/*' -not -path './vendor/*' -not -path '**/test/mock.go' -not -name '**_gen.go' -name '*.go' -type f -exec goimports -d -e -local 'github.com/tidepool-org/platform' {} \; 2>&1` && \
116116
[ -z "$${O}" ] || (echo "$${O}" && exit 1)
117117

118118
imports-write: goimports

data/service/api/v1/datasets_data_create.go

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import (
1010
"github.com/ant0ine/go-json-rest/rest"
1111
"github.com/golang-jwt/jwt/v4"
1212

13-
"github.com/tidepool-org/platform/auth"
1413
"github.com/tidepool-org/platform/data"
1514
dataNormalizer "github.com/tidepool-org/platform/data/normalizer"
1615
dataService "github.com/tidepool-org/platform/data/service"
@@ -46,10 +45,10 @@ func DataSetsDataCreate(dataServiceContext dataService.Context) {
4645
return
4746
}
4847

49-
var details request.AuthDetails
50-
if details = request.GetAuthDetails(ctx); !details.IsService() {
48+
var authDetails request.AuthDetails
49+
if authDetails = request.GetAuthDetails(ctx); !authDetails.IsService() {
5150
var permissions permission.Permissions
52-
permissions, err = dataServiceContext.PermissionClient().GetUserPermissions(ctx, details.UserID(), *dataSet.UserID)
51+
permissions, err = dataServiceContext.PermissionClient().GetUserPermissions(ctx, authDetails.UserID(), *dataSet.UserID)
5352
if err != nil {
5453
if request.IsErrorUnauthorized(err) {
5554
dataServiceContext.RespondWithError(service.ErrorUnauthorized())
@@ -106,7 +105,7 @@ func DataSetsDataCreate(dataServiceContext dataService.Context) {
106105
for _, datum := range datumArray {
107106
datum.SetUserID(dataSet.UserID)
108107
datum.SetDataSetID(dataSet.UploadID)
109-
datum.SetProvenance(CollectProvenanceInfo(ctx, req, details))
108+
datum.SetProvenance(CollectProvenanceInfo(ctx, req, authDetails))
110109
}
111110

112111
if deduplicator, getErr := dataServiceContext.DataDeduplicatorFactory().Get(dataSet); getErr != nil {
@@ -136,28 +135,24 @@ func DataSetsDataCreate(dataServiceContext dataService.Context) {
136135
// CollectProvenanceInfo from a request and its auth details.
137136
//
138137
// All work is done as a best effort right now.
139-
func CollectProvenanceInfo(ctx context.Context, req *rest.Request, details request.AuthDetails) *data.Provenance {
138+
func CollectProvenanceInfo(ctx context.Context, req *rest.Request, authDetails request.AuthDetails) *data.Provenance {
140139
lgr := log.LoggerFromContext(ctx)
141140
provenance := &data.Provenance{}
142141

143-
token := req.Header.Get(auth.TidepoolSessionTokenHeaderKey)
144-
if token == "" {
145-
token = req.Header.Get(auth.TidepoolAuthorizationHeaderKey)
146-
if token != "" {
147-
if strings.EqualFold(token[:len("bearer ")], "bearer ") {
148-
token = token[len("bearer "):]
149-
}
150-
}
142+
token := authDetails.Token()
143+
if strings.HasPrefix(strings.ToLower(token), "bearer ") {
144+
token = token[len("bearer "):]
151145
}
146+
152147
if token != "" {
153148
claims := &TokenClaims{}
154149
if _, _, err := jwt.NewParser().ParseUnverified(token, claims); err != nil {
155150
lgr.WithError(err).Warn("Unable to parse access token for provenance")
156151
} else {
157152
provenance.ClientID = claims.ClientID
158153
}
159-
} else {
160-
lgr.Warn("Unable to find access token for provenance")
154+
} else if !authDetails.IsService() {
155+
lgr.Warn("Unable to read ClientID: The request's access token is blank")
161156
}
162157

163158
if xff := SelectXFF(req.Header); xff != "" {
@@ -170,7 +165,7 @@ func CollectProvenanceInfo(ctx context.Context, req *rest.Request, details reque
170165
}
171166
}
172167

173-
if userID := details.UserID(); userID == "" {
168+
if userID := authDetails.UserID(); userID == "" {
174169
lgr.Warnf("Unable to read the request's userID for provenance: userID is empty")
175170
} else {
176171
provenance.ByUserID = userID

data/service/api/v1/datasets_data_create_provenance_test.go

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,20 @@ import (
88
"strings"
99

1010
"github.com/ant0ine/go-json-rest/rest"
11+
"github.com/golang/mock/gomock"
1112
. "github.com/onsi/ginkgo/v2"
1213
. "github.com/onsi/gomega"
1314

1415
v1 "github.com/tidepool-org/platform/data/service/api/v1"
16+
"github.com/tidepool-org/platform/data/service/api/v1/mocks"
1517
"github.com/tidepool-org/platform/log"
1618
"github.com/tidepool-org/platform/log/null"
1719
"github.com/tidepool-org/platform/request"
1820
)
1921

22+
//go:generate mockgen -destination mocks/mocklogger_test_gen.go -package mocks github.com/tidepool-org/platform/log Logger
23+
2024
var _ = Describe("collectProvenanceInfo", func() {
21-
// logger, err := logJson.NewLogger(os.Stderr, log.DefaultLevelRanks(), log.DefaultLevel())
22-
// Expect(err).ShouldNot(HaveOccurred())
2325
logger := null.NewLogger()
2426
ctx := log.NewContextWithLogger(context.Background(), logger)
2527

@@ -50,6 +52,36 @@ var _ = Describe("collectProvenanceInfo", func() {
5052
It("handles a missing ClientID", func() {
5153
req, details := newTestReqAndDetails("", "bar", "192.0.2.1")
5254
prov := v1.CollectProvenanceInfo(ctx, req, details)
55+
Expect(prov).ToNot(BeNil())
56+
Expect(prov.ByUserID).To(Equal("bar"))
57+
Expect(prov.SourceIP).To(Equal("192.0.2.1"))
58+
Expect(prov.ClientID).To(Equal(""))
59+
})
60+
61+
It("logs missing ClientIDs when expected, but not found", func() {
62+
ctrl := gomock.NewController(GinkgoT())
63+
defer ctrl.Finish()
64+
mockLogger := mocks.NewMockLogger(ctrl)
65+
mockLogger.EXPECT().Warn("Unable to read ClientID: The request's access token is blank")
66+
ctx := log.NewContextWithLogger(context.Background(), mockLogger)
67+
req, _ := newTestReqAndDetails("", "", "192.0.2.1")
68+
details := request.NewAuthDetails(request.MethodSessionToken, "bar", "")
69+
prov := v1.CollectProvenanceInfo(ctx, req, details)
70+
Expect(prov).ToNot(BeNil())
71+
Expect(prov.ByUserID).To(Equal("bar"))
72+
Expect(prov.SourceIP).To(Equal("192.0.2.1"))
73+
Expect(prov.ClientID).To(Equal(""))
74+
})
75+
76+
It("doesn't log missing ClientIDs for service secret authenticated requests", func() {
77+
ctrl := gomock.NewController(GinkgoT())
78+
defer ctrl.Finish()
79+
mockLogger := mocks.NewMockLogger(ctrl)
80+
ctx := log.NewContextWithLogger(context.Background(), mockLogger)
81+
req, _ := newTestReqAndDetails("", "", "192.0.2.1")
82+
details := request.NewAuthDetails(request.MethodServiceSecret, "bar", "")
83+
prov := v1.CollectProvenanceInfo(ctx, req, details)
84+
Expect(prov).ToNot(BeNil())
5385
Expect(prov.ByUserID).To(Equal("bar"))
5486
Expect(prov.SourceIP).To(Equal("192.0.2.1"))
5587
Expect(prov.ClientID).To(Equal(""))
@@ -58,18 +90,27 @@ var _ = Describe("collectProvenanceInfo", func() {
5890

5991
func newTestReqAndDetails(clientID, userID, sourceIP string) (*rest.Request, request.AuthDetails) {
6092
remoteAddr := ""
93+
headers := http.Header{}
6194
if sourceIP != "" {
6295
remoteAddr = sourceIP + ":1234"
96+
headers.Set("X-Forwarded-For", sourceIP)
97+
}
98+
token := ""
99+
if clientID != "" {
100+
token = newTestToken(clientID)
101+
headers.Set("X-Tidepool-Session-Token", token)
63102
}
64103
req := &rest.Request{
65104
Request: &http.Request{
66105
RemoteAddr: remoteAddr,
67-
Header: http.Header{
68-
"X-Tidepool-Session-Token": {newTestToken(clientID)},
69-
"X-Forwarded-For": {sourceIP}},
106+
Header: headers,
70107
},
71108
}
72-
details := request.NewAuthDetails("", userID, "token")
109+
method := request.MethodSessionToken
110+
if userID == "" {
111+
method = request.MethodServiceSecret
112+
}
113+
details := request.NewAuthDetails(method, userID, token)
73114
return req, details
74115
}
75116

0 commit comments

Comments
 (0)