@@ -16,6 +16,7 @@ package http
1616import (
1717 "context"
1818 "crypto/sha256"
19+ "encoding/base64"
1920 "encoding/hex"
2021 "errors"
2122 "fmt"
@@ -29,6 +30,12 @@ import (
2930 pipelinev1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1"
3031 "github.com/tektoncd/pipeline/pkg/resolution/common"
3132 "github.com/tektoncd/pipeline/pkg/resolution/resolver/framework"
33+ "go.uber.org/zap"
34+ apierrors "k8s.io/apimachinery/pkg/api/errors"
35+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
36+ "k8s.io/client-go/kubernetes"
37+ kubeclient "knative.dev/pkg/client/injection/kube/client"
38+ "knative.dev/pkg/logging"
3239)
3340
3441const (
@@ -41,17 +48,25 @@ const (
4148 // httpResolverName The name of the resolver
4249 httpResolverName = "Http"
4350
44- // ConfigMapName is the http resolver's config map
51+ // configMapName is the http resolver's config map
4552 configMapName = "http-resolver-config"
4653
4754 // default Timeout value when fetching http resources in seconds
4855 defaultHttpTimeoutValue = "1m"
56+
57+ // default key in the HTTP password secret
58+ defaultBasicAuthSecretKey = "password"
4959)
5060
5161// Resolver implements a framework.Resolver that can fetch files from an HTTP URL
52- type Resolver struct {}
62+ type Resolver struct {
63+ kubeClient kubernetes.Interface
64+ logger * zap.SugaredLogger
65+ }
5366
54- func (r * Resolver ) Initialize (context.Context ) error {
67+ func (r * Resolver ) Initialize (ctx context.Context ) error {
68+ r .kubeClient = kubeclient .Get (ctx )
69+ r .logger = logging .FromContext (ctx )
5570 return nil
5671}
5772
@@ -95,7 +110,7 @@ func (r *Resolver) Resolve(ctx context.Context, oParams []pipelinev1.Param) (fra
95110 return nil , err
96111 }
97112
98- return fetchHttpResource (ctx , params )
113+ return r . fetchHttpResource (ctx , params )
99114}
100115
101116func (r * Resolver ) isDisabled (ctx context.Context ) bool {
@@ -144,15 +159,33 @@ func populateDefaultParams(ctx context.Context, params []pipelinev1.Param) (map[
144159
145160 var missingParams []string
146161
147- if _ , ok := paramsMap [urlParam ]; ! ok {
148- missingParams = append (missingParams , urlParam )
162+ if _ , ok := paramsMap [urlParamType ]; ! ok {
163+ missingParams = append (missingParams , urlParamType )
149164 } else {
150- u , err := url .ParseRequestURI (paramsMap [urlParam ])
165+ u , err := url .ParseRequestURI (paramsMap [urlParamType ])
151166 if err != nil {
152- return nil , fmt .Errorf ("cannot parse url %s: %w" , paramsMap [urlParam ], err )
167+ return nil , fmt .Errorf ("cannot parse url %s: %w" , paramsMap [urlParamType ], err )
153168 }
154169 if u .Scheme != "http" && u .Scheme != "https" {
155- return nil , fmt .Errorf ("url %s is not a valid http(s) url" , paramsMap [urlParam ])
170+ return nil , fmt .Errorf ("url %s is not a valid http(s) url" , paramsMap [urlParamType ])
171+ }
172+ }
173+
174+ if username , ok := paramsMap [httpBasicAuthUsername ]; ok {
175+ if _ , ok := paramsMap [httpBasicAuthSecret ]; ! ok {
176+ return nil , fmt .Errorf ("missing required param %s when using %s" , httpBasicAuthSecret , httpBasicAuthUsername )
177+ }
178+ if username == "" {
179+ return nil , fmt .Errorf ("value %s cannot be empty" , httpBasicAuthUsername )
180+ }
181+ }
182+
183+ if secret , ok := paramsMap [httpBasicAuthSecret ]; ok {
184+ if _ , ok := paramsMap [httpBasicAuthUsername ]; ! ok {
185+ return nil , fmt .Errorf ("missing required param %s when using %s" , httpBasicAuthUsername , httpBasicAuthSecret )
186+ }
187+ if secret == "" {
188+ return nil , fmt .Errorf ("value %s cannot be empty" , httpBasicAuthSecret )
156189 }
157190 }
158191
@@ -178,7 +211,7 @@ func makeHttpClient(ctx context.Context) (*http.Client, error) {
178211 }, nil
179212}
180213
181- func fetchHttpResource (ctx context.Context , params map [string ]string ) (framework.ResolvedResource , error ) {
214+ func ( r * Resolver ) fetchHttpResource (ctx context.Context , params map [string ]string ) (framework.ResolvedResource , error ) {
182215 var targetURL string
183216 var ok bool
184217
@@ -187,15 +220,24 @@ func fetchHttpResource(ctx context.Context, params map[string]string) (framework
187220 return nil , err
188221 }
189222
190- if targetURL , ok = params [urlParam ]; ! ok {
191- return nil , fmt .Errorf ("missing required params: %s" , urlParam )
223+ if targetURL , ok = params [urlParamType ]; ! ok {
224+ return nil , fmt .Errorf ("missing required params: %s" , urlParamType )
192225 }
193226
194227 req , err := http .NewRequestWithContext (ctx , http .MethodGet , targetURL , nil )
195228 if err != nil {
196229 return nil , fmt .Errorf ("constructing request: %w" , err )
197230 }
198231
232+ // NOTE(chmouel): We already made sure that username and secret was specified by the user
233+ if secret , ok := params [httpBasicAuthSecret ]; ok && secret != "" {
234+ if encodedSecret , err := r .getBasicAuthSecret (ctx , params ); err != nil {
235+ return nil , err
236+ } else {
237+ req .Header .Set ("Authorization" , encodedSecret )
238+ }
239+ }
240+
199241 resp , err := httpClient .Do (req )
200242 if err != nil {
201243 return nil , fmt .Errorf ("error fetching URL: %w" , err )
@@ -216,3 +258,34 @@ func fetchHttpResource(ctx context.Context, params map[string]string) (framework
216258 URL : targetURL ,
217259 }, nil
218260}
261+
262+ func (r * Resolver ) getBasicAuthSecret (ctx context.Context , params map [string ]string ) (string , error ) {
263+ secretName := params [httpBasicAuthSecret ]
264+ userName := params [httpBasicAuthUsername ]
265+ tokenSecretKey := defaultBasicAuthSecretKey
266+ if v , ok := params [httpBasicAuthSecretKey ]; ok {
267+ if v != "" {
268+ tokenSecretKey = v
269+ }
270+ }
271+ secretNS := common .RequestNamespace (ctx )
272+ secret , err := r .kubeClient .CoreV1 ().Secrets (secretNS ).Get (ctx , secretName , metav1.GetOptions {})
273+ if err != nil {
274+ if apierrors .IsNotFound (err ) {
275+ notFoundErr := fmt .Errorf ("cannot get API token, secret %s not found in namespace %s" , secretName , secretNS )
276+ r .logger .Info (notFoundErr )
277+ return "" , notFoundErr
278+ }
279+ wrappedErr := fmt .Errorf ("error reading API token from secret %s in namespace %s: %w" , secretName , secretNS , err )
280+ r .logger .Info (wrappedErr )
281+ return "" , wrappedErr
282+ }
283+ secretVal , ok := secret .Data [tokenSecretKey ]
284+ if ! ok {
285+ err := fmt .Errorf ("cannot get API token, key %s not found in secret %s in namespace %s" , tokenSecretKey , secretName , secretNS )
286+ r .logger .Info (err )
287+ return "" , err
288+ }
289+ return fmt .Sprintf ("Basic %s" , base64 .StdEncoding .EncodeToString (
290+ []byte (fmt .Sprintf ("%s:%s" , userName , secretVal )))), nil
291+ }
0 commit comments