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.
3837type NugetFeedHandler struct {
39- credentials []nugetFeedCredentials
40- oidcCredentials map [string ]* oidc.OIDCCredential
41- mutex sync.RWMutex
38+ credentials []nugetFeedCredentials
39+ oidcRegistry * oidc.OIDCRegistry
4240}
4341
4442type nugetFeedCredentials struct {
@@ -52,8 +50,8 @@ type nugetFeedCredentials struct {
5250// NewNugetFeedHandler returns a new NugetFeedHandler.
5351func 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
0 commit comments