Skip to content

Commit 06698f6

Browse files
committed
Migrate nuget handler to OIDCRegistry
Replace manual OIDC credential map and mutex with the shared OIDCRegistry type. Nuget uses Register() for the primary feed URL and RegisterURL() for HTTP-discovered resource URLs. The old code stored OIDC credentials by url-with-host-fallback. OIDCRegistry preserves the full URL with path-prefix matching, fixing potential collisions when multiple nuget feeds share a host. Test log lines updated: RegisterURL uses consistent log format without the leading indent that the old code used.
1 parent 5328230 commit 06698f6

2 files changed

Lines changed: 92 additions & 93 deletions

File tree

internal/handlers/nuget_feed.go

Lines changed: 88 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import (
99
"net/http"
1010
"net/url"
1111
"strings"
12-
"sync"
1312
"time"
1413

1514
"github.com/elazarl/goproxy"
@@ -36,9 +35,8 @@ type nugetV3IndexResponse struct {
3635

3736
// NugetFeedHandler handles requests to nuget feeds, adding auth.
3837
type NugetFeedHandler struct {
39-
credentials []nugetFeedCredentials
40-
oidcCredentials map[string]*oidc.OIDCCredential
41-
mutex sync.RWMutex
38+
credentials []nugetFeedCredentials
39+
oidcRegistry *oidc.OIDCRegistry
4240
}
4341

4442
type nugetFeedCredentials struct {
@@ -52,8 +50,8 @@ type nugetFeedCredentials struct {
5250
// NewNugetFeedHandler returns a new NugetFeedHandler.
5351
func NewNugetFeedHandler(creds config.Credentials) *NugetFeedHandler {
5452
handler := NugetFeedHandler{
55-
credentials: []nugetFeedCredentials{},
56-
oidcCredentials: make(map[string]*oidc.OIDCCredential),
53+
credentials: []nugetFeedCredentials{},
54+
oidcRegistry: oidc.NewOIDCRegistry(),
5755
}
5856

5957
httpClient := &http.Client{
@@ -72,56 +70,53 @@ func NewNugetFeedHandler(creds config.Credentials) *NugetFeedHandler {
7270
username := cred.GetString("username")
7371
password := cred.GetString("password")
7472

75-
oidcCredential, _ := oidc.CreateOIDCCredential(cred)
76-
if oidcCredential != nil {
77-
key := url
78-
if key == "" {
79-
key = host
80-
}
81-
82-
if key != "" {
83-
handler.oidcCredentials[key] = oidcCredential
84-
logging.RequestLogf(nil, "registered %s OIDC credentials for nuget feed: %s", oidcCredential.Provider(), key)
85-
86-
// now query all resources to add to the authentication list
73+
oidcCredential, key, ok := handler.oidcRegistry.Register(cred, []string{"url"}, "nuget feed")
74+
if ok {
75+
// Discover additional resource URLs from the nuget feed index.
76+
// Wrapped in a closure so defer runs promptly for each credential,
77+
// ensuring the HTTP response body is always closed (pre-existing
78+
// leak fixed here: the body was previously leaked on ReadAll error
79+
// and on early-return status code paths).
80+
func() {
8781
req, err := http.NewRequestWithContext(context.Background(), "GET", key, nil)
8882
if err != nil {
8983
logging.RequestLogf(nil, "error creating http request (%s): %v", key, err)
90-
continue
84+
return
9185
}
9286

93-
if oidc.TryAuthOIDCRequestWithPrefix(&handler.mutex, handler.oidcCredentials, req, nil) {
94-
rawRsp, err := httpClient.Do(req)
95-
if err != nil {
96-
logging.RequestLogf(nil, "error retrieving http response (%s): %v", key, err)
97-
continue
98-
}
87+
if !handler.oidcRegistry.TryAuth(req, nil) {
88+
return
89+
}
9990

100-
body, err := io.ReadAll(rawRsp.Body)
101-
if err != nil {
102-
logging.RequestLogf(nil, "error reading http response body")
103-
continue
104-
}
105-
rawRsp.Body.Close()
91+
rawRsp, err := httpClient.Do(req)
92+
if err != nil {
93+
logging.RequestLogf(nil, "error retrieving http response (%s): %v", key, err)
94+
return
95+
}
96+
defer rawRsp.Body.Close()
10697

107-
switch rawRsp.StatusCode {
108-
case 401, 403:
109-
logging.RequestLogf(nil, "unauthorized for nuget feed %s", key)
110-
continue
111-
}
98+
body, err := io.ReadAll(rawRsp.Body)
99+
if err != nil {
100+
logging.RequestLogf(nil, "error reading http response body (%s): %v", key, err)
101+
return
102+
}
112103

113-
if rawRsp.StatusCode >= 400 {
114-
logging.RequestLogf(nil, "unexpected http response %d for nuget feed %s", rawRsp.StatusCode, key)
115-
continue
116-
}
104+
switch rawRsp.StatusCode {
105+
case 401, 403:
106+
logging.RequestLogf(nil, "unauthorized for nuget feed %s", key)
107+
return
108+
}
117109

118-
urlsToAuthenticate := extraUrlsFromSourceResponse(body, key)
119-
for _, url := range urlsToAuthenticate {
120-
handler.oidcCredentials[url] = oidcCredential
121-
logging.RequestLogf(nil, " registered %s OIDC credentials for nuget resource: %s", oidcCredential.Provider(), url)
122-
}
110+
if rawRsp.StatusCode >= 400 {
111+
logging.RequestLogf(nil, "unexpected http response %d for nuget feed %s", rawRsp.StatusCode, key)
112+
return
113+
}
114+
115+
urlsToAuthenticate := extraUrlsFromSourceResponse(body, key)
116+
for _, discoveredURL := range urlsToAuthenticate {
117+
handler.oidcRegistry.RegisterURL(discoveredURL, oidcCredential, "nuget resource")
123118
}
124-
}
119+
}()
125120
continue
126121
}
127122

@@ -138,48 +133,52 @@ func NewNugetFeedHandler(creds config.Credentials) *NugetFeedHandler {
138133
// and authenticate them all
139134
if url != "" {
140135
logging.RequestLogf(nil, "fetching service index for nuget feed %s", url)
141-
req, err := http.NewRequestWithContext(context.Background(), "GET", url, nil)
142-
authenticateNugetRequest(req, feedCred, nil)
143-
if err != nil {
144-
logging.RequestLogf(nil, "error creating http request (%s): %v", url, err)
145-
continue
146-
}
147-
148-
rawRsp, err := httpClient.Do(req)
149-
if err != nil {
150-
logging.RequestLogf(nil, "error retrieving http response (%s): %v", url, err)
151-
continue
152-
}
153-
154-
body, err := io.ReadAll(rawRsp.Body)
155-
if err != nil {
156-
logging.RequestLogf(nil, "error reading http response body")
157-
continue
158-
}
159-
rawRsp.Body.Close()
160-
161-
switch rawRsp.StatusCode {
162-
case 401, 403:
163-
logging.RequestLogf(nil, "unauthorized for nuget feed %s", url)
164-
continue
165-
}
166-
167-
if rawRsp.StatusCode >= 400 {
168-
logging.RequestLogf(nil, "unexpected http response %d for nuget feed %s", rawRsp.StatusCode, url)
169-
continue
170-
}
171-
172-
urlsToAuthenticate := extraUrlsFromSourceResponse(body, url)
173-
for _, url := range urlsToAuthenticate {
174-
feedCred := nugetFeedCredentials{
175-
url: url,
176-
token: token,
177-
username: username,
178-
password: password,
136+
// Same closure pattern as the OIDC block above — ensures the
137+
// HTTP response body is always closed via defer.
138+
func() {
139+
req, err := http.NewRequestWithContext(context.Background(), "GET", url, nil)
140+
if err != nil {
141+
logging.RequestLogf(nil, "error creating http request (%s): %v", url, err)
142+
return
143+
}
144+
authenticateNugetRequest(req, feedCred, nil)
145+
146+
rawRsp, err := httpClient.Do(req)
147+
if err != nil {
148+
logging.RequestLogf(nil, "error retrieving http response (%s): %v", url, err)
149+
return
150+
}
151+
defer rawRsp.Body.Close()
152+
153+
body, err := io.ReadAll(rawRsp.Body)
154+
if err != nil {
155+
logging.RequestLogf(nil, "error reading http response body (%s): %v", url, err)
156+
return
157+
}
158+
159+
switch rawRsp.StatusCode {
160+
case 401, 403:
161+
logging.RequestLogf(nil, "unauthorized for nuget feed %s", url)
162+
return
163+
}
164+
165+
if rawRsp.StatusCode >= 400 {
166+
logging.RequestLogf(nil, "unexpected http response %d for nuget feed %s", rawRsp.StatusCode, url)
167+
return
168+
}
169+
170+
urlsToAuthenticate := extraUrlsFromSourceResponse(body, url)
171+
for _, discoveredURL := range urlsToAuthenticate {
172+
feedCred := nugetFeedCredentials{
173+
url: discoveredURL,
174+
token: token,
175+
username: username,
176+
password: password,
177+
}
178+
handler.credentials = append(handler.credentials, feedCred)
179+
logging.RequestLogf(nil, " added url to authentication list: %s", discoveredURL)
179180
}
180-
handler.credentials = append(handler.credentials, feedCred)
181-
logging.RequestLogf(nil, " added url to authentication list: %s", url)
182-
}
181+
}()
183182
}
184183
}
185184

@@ -261,8 +260,8 @@ func (h *NugetFeedHandler) HandleRequest(req *http.Request, ctx *goproxy.ProxyCt
261260
return req, nil
262261
}
263262

264-
// Try OIDC credentials first
265-
if oidc.TryAuthOIDCRequestWithPrefix(&h.mutex, h.oidcCredentials, req, ctx) {
263+
// Try OIDC credentials first (HTTPS only to avoid leaking tokens over plaintext)
264+
if req.URL.Scheme == "https" && h.oidcRegistry.TryAuth(req, ctx) {
266265
return req, nil
267266
}
268267

internal/handlers/oidc_handling_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -822,7 +822,7 @@ func TestOIDCURLsAreAuthenticated(t *testing.T) {
822822
},
823823
expectedLogLines: []string{
824824
"registered aws OIDC credentials for nuget feed: https://nuget.example.com/index.json",
825-
" registered aws OIDC credentials for nuget resource: https://nuget.example.com/v3/packages",
825+
"registered aws OIDC credentials for nuget resource: https://nuget.example.com/v3/packages",
826826
},
827827
urlsToAuthenticate: []string{
828828
"https://nuget.example.com/index.json", // base url
@@ -852,7 +852,7 @@ func TestOIDCURLsAreAuthenticated(t *testing.T) {
852852
},
853853
expectedLogLines: []string{
854854
"registered azure OIDC credentials for nuget feed: https://nuget.example.com/index.json",
855-
" registered azure OIDC credentials for nuget resource: https://nuget.example.com/v3/packages",
855+
"registered azure OIDC credentials for nuget resource: https://nuget.example.com/v3/packages",
856856
},
857857
urlsToAuthenticate: []string{
858858
"https://nuget.example.com/index.json", // base url
@@ -881,7 +881,7 @@ func TestOIDCURLsAreAuthenticated(t *testing.T) {
881881
},
882882
expectedLogLines: []string{
883883
"registered jfrog OIDC credentials for nuget feed: https://jfrog.example.com/index.json",
884-
" registered jfrog OIDC credentials for nuget resource: https://jfrog.example.com/v3/packages",
884+
"registered jfrog OIDC credentials for nuget resource: https://jfrog.example.com/v3/packages",
885885
},
886886
urlsToAuthenticate: []string{
887887
"https://jfrog.example.com/index.json", // base url
@@ -912,7 +912,7 @@ func TestOIDCURLsAreAuthenticated(t *testing.T) {
912912
},
913913
expectedLogLines: []string{
914914
"registered cloudsmith OIDC credentials for nuget feed: https://cloudsmith.example.com/v3/index.json",
915-
" registered cloudsmith OIDC credentials for nuget resource: https://cloudsmith.example.com/v3/packages",
915+
"registered cloudsmith OIDC credentials for nuget resource: https://cloudsmith.example.com/v3/packages",
916916
},
917917
urlsToAuthenticate: []string{
918918
"https://cloudsmith.example.com/v3/index.json", // base url

0 commit comments

Comments
 (0)