Skip to content

Commit 268fd75

Browse files
thisthatrenovate[bot]toddbaertaepflichrfwow
authored
feat: Add OAuth support for HTTP Sync (#1791)
<!-- Please use this template for your pull request. --> <!-- Please use the sections that you need and delete other sections --> ## This PR - adds support for OAuth in the HTTP Sync ### Related Issues <!-- add here the GitHub issue that this PR resolves if applicable --> Addresses #1785 ### Notes Properly testing this via unit tests is not possible. The HTTP Sync is built by the `syncbuilder` pkg. This entails that testing any behavior of the HTTP Sync can only be possible as part of the `syncbuilder` module, which IMHO doesn't make much sense. ### Follow-up Tasks Add documentation for the new properties used in the HTTP Sync. Available here: #1805 ### How to test <!-- if applicable, add testing instructions under this section --> Manually create a small mockup server that handles OAuth requests ```go func (h *OAuthHandler) Authorize(w http.ResponseWriter, r *http.Request) { reqDump, _ := httputil.DumpRequest(r, true) fmt.Printf("GOT OAUTH REQUEST:\n%s", string(reqDump)) w.WriteHeader(http.StatusOK) w.Header().Set("Content-Type", "application/x-www-form-urlencoded") w.Write([]byte("access_token=mocktoken&scope=mockscope&token_type=bearer")) } ``` Afterwards, start flagd pointing to the mockup server: ``` go run main.go start --sources='[{ "uri": "http://localhost:8180/flags", "provider": "http", "interval": 1, "bearerToken": "it-will-be-overridden", "oauthConfig": { "clientID": "test", "clientSecret": "test", "tokenUrl": "http://localhost:8180/oauth" }}]' ``` The HTTP request to `http://localhost:8180/flags` will contain the HTTP Header `Authorization: Bearer mocktoken`. --------- Signed-off-by: Todd Baert <[email protected]> Signed-off-by: Giovanni Liva <[email protected]> Signed-off-by: Simon Schrottner <[email protected]> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Todd Baert <[email protected]> Co-authored-by: Simon Schrottner <[email protected]> Co-authored-by: chrfwow <[email protected]>
1 parent 5ff38b4 commit 268fd75

File tree

5 files changed

+532
-99
lines changed

5 files changed

+532
-99
lines changed

core/pkg/sync/builder/syncbuilder.go

Lines changed: 1 addition & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,8 @@ package builder
22

33
import (
44
"fmt"
5-
"net/http"
65
"os"
76
"regexp"
8-
"time"
97

108
"github.com/open-feature/flagd/core/pkg/logger"
119
"github.com/open-feature/flagd/core/pkg/sync"
@@ -112,7 +110,7 @@ func (sb *SyncBuilder) syncFromConfig(sourceConfig sync.SourceConfig, logger *lo
112110
return sb.newK8s(sourceConfig.URI, logger)
113111
case syncProviderHTTP:
114112
logger.Debug(fmt.Sprintf("using remote sync-provider for: %s", sourceConfig.URI))
115-
return sb.newHTTP(sourceConfig, logger), nil
113+
return httpSync.NewHTTP(sourceConfig, logger), nil
116114
case syncProviderGrpc:
117115
logger.Debug(fmt.Sprintf("using grpc sync-provider for: %s", sourceConfig.URI))
118116
return sb.newGRPC(sourceConfig, logger), nil
@@ -186,29 +184,6 @@ func (sb *SyncBuilder) newK8s(uri string, logger *logger.Logger) (*kubernetes.Sy
186184
), nil
187185
}
188186

189-
func (sb *SyncBuilder) newHTTP(config sync.SourceConfig, logger *logger.Logger) *httpSync.Sync {
190-
// Default to 5 seconds
191-
var interval uint32 = 5
192-
if config.Interval != 0 {
193-
interval = config.Interval
194-
}
195-
196-
return &httpSync.Sync{
197-
URI: config.URI,
198-
Client: &http.Client{
199-
Timeout: time.Second * 10,
200-
},
201-
Logger: logger.WithFields(
202-
zap.String("component", "sync"),
203-
zap.String("sync", "remote"),
204-
),
205-
BearerToken: config.BearerToken,
206-
AuthHeader: config.AuthHeader,
207-
Interval: interval,
208-
Cron: cron.New(),
209-
}
210-
}
211-
212187
func (sb *SyncBuilder) newGRPC(config sync.SourceConfig, logger *logger.Logger) *grpc.Sync {
213188
return &grpc.Sync{
214189
URI: config.URI,

core/pkg/sync/builder/utils_test.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,3 +267,61 @@ func TestParseSyncProviderURIs(t *testing.T) {
267267
})
268268
}
269269
}
270+
271+
func TestParseOAuth(t *testing.T) {
272+
test := map[string]struct {
273+
in string
274+
expectErr bool
275+
out []sync.SourceConfig
276+
}{
277+
"noOauth": {
278+
in: "[{\"uri\":\"https://secure-remote\",\"provider\":\"http\",\"authHeader\":\"Bearer bearer-dji34ld2l\"}]",
279+
expectErr: false,
280+
out: []sync.SourceConfig{
281+
{
282+
URI: "https://secure-remote",
283+
Provider: "http",
284+
AuthHeader: "Bearer bearer-dji34ld2l",
285+
},
286+
},
287+
},
288+
"oauth": {
289+
in: `[{
290+
"uri": "https://secure-remote",
291+
"provider":"http",
292+
"oauth": {
293+
"clientID": "myID",
294+
"clientSecret": "mySecret",
295+
"tokenURL": "myTokenUrl"
296+
}}]`,
297+
expectErr: false,
298+
out: []sync.SourceConfig{
299+
{
300+
URI: "https://secure-remote",
301+
Provider: "http",
302+
OAuth: &sync.OAuthCredentialHandler{
303+
ClientID: "myID",
304+
ClientSecret: "mySecret",
305+
TokenURL: "myTokenUrl",
306+
},
307+
},
308+
},
309+
},
310+
}
311+
312+
for name, tt := range test {
313+
t.Run(name, func(t *testing.T) {
314+
out, err := ParseSources(tt.in)
315+
if tt.expectErr {
316+
if err == nil {
317+
t.Error("expected error, got none")
318+
}
319+
} else if err != nil {
320+
t.Errorf("did not expect error: %s", err.Error())
321+
}
322+
if !reflect.DeepEqual(out, tt.out) {
323+
t.Errorf("unexpected output, expected %v, got %v", tt.out, out)
324+
}
325+
})
326+
}
327+
}

0 commit comments

Comments
 (0)