git.iko.soy/typeable/oauth2-proxy
on master help sign in
Migrate all requests to new builder pattern
commit53142455b6ed997ee10f45e05db63cb52c9f5311 authorJoel Speed <joel.speed@hotmail.co.uk> dateFri 3 Jul 2020, 19:27 (6 years ago) parent21ef86b
15 files changed+193−398
pkg/validation/options.go+29−28 providers/azure.go+12−37 providers/bitbucket.go+23−28 providers/digitalocean.go+4−6 providers/facebook.go+7−6 providers/github.go+37−114 providers/gitlab.go+6−26 providers/google.go+19−49 providers/internal_util.go+5−1 providers/keycloak.go+4−9 providers/linkedin.go+5−6 providers/logingov.go+24−60 providers/nextcloud.go+6−11 providers/oidc.go+4−7 providers/provider_default.go+8−10
pkg/validation/options.go+29−28
@@ -83,34 +83,33 @@ func Validate(o *options.Options) error {
8383
8484 logger.Printf("Performing OIDC Discovery...")
8585
86− if req, err := http.NewRequest("GET", strings.TrimSuffix(o.OIDCIssuerURL, "/")+"/.well-known/openid-configuration", nil); err == nil {
87− if body, err := requests.Request(req); err == nil {
88−
89− // Prefer manually configured URLs. It's a bit unclear
90− // why you'd be doing discovery and also providing the URLs
91− // explicitly though...
92− if o.LoginURL == "" {
93− o.LoginURL = body.Get("authorization_endpoint").MustString()
94− }
95−
96− if o.RedeemURL == "" {
97− o.RedeemURL = body.Get("token_endpoint").MustString()
98− }
99−
100− if o.OIDCJwksURL == "" {
101− o.OIDCJwksURL = body.Get("jwks_uri").MustString()
102− }
103−
104− if o.ProfileURL == "" {
105− o.ProfileURL = body.Get("userinfo_endpoint").MustString()
106− }
107−
108− o.SkipOIDCDiscovery = true
109− } else {
110− logger.Printf("error: failed to discover OIDC configuration: %v", err)
111− }
86+ requestURL := strings.TrimSuffix(o.OIDCIssuerURL, "/") + "/.well-known/openid-configuration"
87+ body, err := requests.New(requestURL).
88+ WithContext(ctx).
89+ UnmarshalJSON()
90+ if err != nil {
91+ logger.Printf("error: failed to discover OIDC configuration: %v", err)
11292 } else {
113− logger.Printf("error: failed parsing OIDC discovery URL: %v", err)
93+ // Prefer manually configured URLs. It's a bit unclear
94+ // why you'd be doing discovery and also providing the URLs
95+ // explicitly though...
96+ if o.LoginURL == "" {
97+ o.LoginURL = body.Get("authorization_endpoint").MustString()
98+ }
99+
100+ if o.RedeemURL == "" {
101+ o.RedeemURL = body.Get("token_endpoint").MustString()
102+ }
103+
104+ if o.OIDCJwksURL == "" {
105+ o.OIDCJwksURL = body.Get("jwks_uri").MustString()
106+ }
107+
108+ if o.ProfileURL == "" {
109+ o.ProfileURL = body.Get("userinfo_endpoint").MustString()
110+ }
111+
112+ o.SkipOIDCDiscovery = true
114113 }
115114 }
116115
@@ -385,10 +384,12 @@ func newVerifierFromJwtIssuer(jwtIssuer jwtIssuer) (*oidc.IDTokenVerifier, error
385384 if err != nil {
386385 // Try as JWKS URI
387386 jwksURI := strings.TrimSuffix(jwtIssuer.issuerURI, "/") + "/.well-known/jwks.json"
388− _, err := http.NewRequest("GET", jwksURI, nil)
387+ resp, err := requests.New(jwksURI).Do()
389388 if err != nil {
390389 return nil, err
391390 }
391+ resp.Body.Close()
392+
392393 verifier = oidc.NewVerifier(jwtIssuer.issuerURI, oidc.NewRemoteKeySet(context.Background(), jwksURI), config)
393394 } else {
394395 verifier = provider.Verifier(config)
providers/azure.go+12−37
@@ -3,10 +3,8 @@ package providers
33import (
44 "bytes"
55 "context"
6− "encoding/json"
76 "errors"
87 "fmt"
9− "io/ioutil"
108 "net/http"
119 "net/url"
1210 "time"
@@ -91,39 +89,21 @@ func (p *AzureProvider) Redeem(ctx context.Context, redirectURL, code string) (s
9189 params.Add("resource", p.ProtectedResource.String())
9290 }
9391
94− var req *http.Request
95− req, err = http.NewRequestWithContext(ctx, "POST", p.RedeemURL.String(), bytes.NewBufferString(params.Encode()))
96− if err != nil {
97− return
98− }
99− req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
100−
101− var resp *http.Response
102− resp, err = http.DefaultClient.Do(req)
103− if err != nil {
104− return nil, err
105− }
106− var body []byte
107− body, err = ioutil.ReadAll(resp.Body)
108− resp.Body.Close()
109− if err != nil {
110− return
111− }
112−
113− if resp.StatusCode != 200 {
114− err = fmt.Errorf("got %d from %q %s", resp.StatusCode, p.RedeemURL.String(), body)
115− return
116− }
117−
11892 var jsonResponse struct {
11993 AccessToken string `json:"access_token"`
12094 RefreshToken string `json:"refresh_token"`
12195 ExpiresOn int64 `json:"expires_on,string"`
12296 IDToken string `json:"id_token"`
12397 }
124− err = json.Unmarshal(body, &jsonResponse)
98+
99+ err = requests.New(p.RedeemURL.String()).
100+ WithContext(ctx).
101+ WithMethod("POST").
102+ WithBody(bytes.NewBufferString(params.Encode())).
103+ SetHeader("Content-Type", "application/x-www-form-urlencoded").
104+ UnmarshalInto(&jsonResponse)
125105 if err != nil {
126− return
106+ return nil, err
127107 }
128108
129109 created := time.Now()
@@ -169,26 +149,21 @@ func (p *AzureProvider) GetEmailAddress(ctx context.Context, s *sessions.Session
169149 if s.AccessToken == "" {
170150 return "", errors.New("missing access token")
171151 }
172− req, err := http.NewRequestWithContext(ctx, "GET", p.ProfileURL.String(), nil)
173− if err != nil {
174− return "", err
175− }
176− req.Header = getAzureHeader(s.AccessToken)
177−
178− json, err := requests.Request(req)
179152
153+ json, err := requests.New(p.ProfileURL.String()).
154+ WithContext(ctx).
155+ WithHeaders(getAzureHeader(s.AccessToken)).
156+ UnmarshalJSON()
180157 if err != nil {
181158 return "", err
182159 }
183160
184161 email, err = getEmailFromJSON(json)
185−
186162 if err == nil && email != "" {
187163 return email, err
188164 }
189165
190166 email, err = json.Get("userPrincipalName").String()
191−
192167 if err != nil {
193168 logger.Printf("failed making request %s", err)
194169 return "", err
providers/bitbucket.go+23−28
@@ -2,7 +2,6 @@ package providers
22
33import (
44 "context"
5− "net/http"
65 "net/url"
76 "strings"
87
@@ -85,15 +84,13 @@ func (p *BitbucketProvider) GetEmailAddress(ctx context.Context, s *sessions.Ses
8584 FullName string `json:"full_name"`
8685 }
8786 }
88− req, err := http.NewRequestWithContext(ctx, "GET",
89− p.ValidateURL.String()+"?access_token="+s.AccessToken, nil)
90− if err != nil {
91− logger.Printf("failed building request %s", err)
92− return "", err
93− }
94− err = requests.RequestJSON(req, &emails)
87+
88+ requestURL := p.ValidateURL.String() + "?access_token=" + s.AccessToken
89+ err := requests.New(requestURL).
90+ WithContext(ctx).
91+ UnmarshalInto(&emails)
9592 if err != nil {
96− logger.Printf("failed making request %s", err)
93+ logger.Printf("failed making request: %v", err)
9794 return "", err
9895 }
9996
@@ -101,15 +98,14 @@ func (p *BitbucketProvider) GetEmailAddress(ctx context.Context, s *sessions.Ses
10198 teamURL := &url.URL{}
10299 *teamURL = *p.ValidateURL
103100 teamURL.Path = "/2.0/teams"
104− req, err = http.NewRequestWithContext(ctx, "GET",
105− teamURL.String()+"?role=member&access_token="+s.AccessToken, nil)
106− if err != nil {
107− logger.Printf("failed building request %s", err)
108− return "", err
109− }
110− err = requests.RequestJSON(req, &teams)
101+
102+ requestURL := teamURL.String() + "?role=member&access_token=" + s.AccessToken
103+
104+ err := requests.New(requestURL).
105+ WithContext(ctx).
106+ UnmarshalInto(&teams)
111107 if err != nil {
112− logger.Printf("failed requesting teams membership %s", err)
108+ logger.Printf("failed requesting teams membership: %v", err)
113109 return "", err
114110 }
115111 var found = false
@@ -129,20 +125,19 @@ func (p *BitbucketProvider) GetEmailAddress(ctx context.Context, s *sessions.Ses
129125 repositoriesURL := &url.URL{}
130126 *repositoriesURL = *p.ValidateURL
131127 repositoriesURL.Path = "/2.0/repositories/" + strings.Split(p.Repository, "/")[0]
132− req, err = http.NewRequestWithContext(ctx, "GET",
133− repositoriesURL.String()+"?role=contributor"+
134− "&q=full_name="+url.QueryEscape("\""+p.Repository+"\"")+
135− "&access_token="+s.AccessToken,
136− nil)
137− if err != nil {
138− logger.Printf("failed building request %s", err)
139− return "", err
140− }
141− err = requests.RequestJSON(req, &repositories)
128+
129+ requestURL := repositoriesURL.String() + "?role=contributor" +
130+ "&q=full_name=" + url.QueryEscape("\""+p.Repository+"\"") +
131+ "&access_token=" + s.AccessToken
132+
133+ err := requests.New(requestURL).
134+ WithContext(ctx).
135+ UnmarshalInto(&repositories)
142136 if err != nil {
143− logger.Printf("failed checking repository access %s", err)
137+ logger.Printf("failed checking repository access: %v", err)
144138 return "", err
145139 }
140+
146141 var found = false
147142 for _, repository := range repositories.Values {
148143 if p.Repository == repository.FullName {
providers/digitalocean.go+4−6
@@ -60,13 +60,11 @@ func (p *DigitalOceanProvider) GetEmailAddress(ctx context.Context, s *sessions.
6060 if s.AccessToken == "" {
6161 return "", errors.New("missing access token")
6262 }
63− req, err := http.NewRequestWithContext(ctx, "GET", p.ProfileURL.String(), nil)
64− if err != nil {
65− return "", err
66− }
67− req.Header = getDigitalOceanHeader(s.AccessToken)
6863
69− json, err := requests.Request(req)
64+ json, err := requests.New(p.ProfileURL.String()).
65+ WithContext(ctx).
66+ WithHeaders(getDigitalOceanHeader(s.AccessToken)).
67+ UnmarshalJSON()
7068 if err != nil {
7169 return "", err
7270 }
providers/facebook.go+7−6
@@ -62,20 +62,21 @@ func (p *FacebookProvider) GetEmailAddress(ctx context.Context, s *sessions.Sess
6262 if s.AccessToken == "" {
6363 return "", errors.New("missing access token")
6464 }
65− req, err := http.NewRequestWithContext(ctx, "GET", p.ProfileURL.String()+"?fields=name,email", nil)
66− if err != nil {
67− return "", err
68− }
69− req.Header = getFacebookHeader(s.AccessToken)
7065
7166 type result struct {
7267 Email string
7368 }
7469 var r result
75− err = requests.RequestJSON(req, &r)
70+
71+ requestURL := p.ProfileURL.String() + "?fields=name,email"
72+ err := requests.New(requestURL).
73+ WithContext(ctx).
74+ WithHeaders(getFacebookHeader(s.AccessToken)).
75+ UnmarshalInto(&r)
7676 if err != nil {
7777 return "", err
7878 }
79+
7980 if r.Email == "" {
8081 return "", errors.New("no email")
8182 }
providers/github.go+37−114
@@ -2,7 +2,6 @@ package providers
22
33import (
44 "context"
5− "encoding/json"
65 "errors"
76 "fmt"
87 "io/ioutil"
@@ -15,6 +14,7 @@ import (
1514
1615 "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
1716 "github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
17+ "github.com/oauth2-proxy/oauth2-proxy/pkg/requests"
1818)
1919
2020// GitHubProvider represents an GitHub based Identity Provider
@@ -111,27 +111,16 @@ func (p *GitHubProvider) hasOrg(ctx context.Context, accessToken string) (bool,
111111 Path: path.Join(p.ValidateURL.Path, "/user/orgs"),
112112 RawQuery: params.Encode(),
113113 }
114− req, _ := http.NewRequestWithContext(ctx, "GET", endpoint.String(), nil)
115− req.Header = getGitHubHeader(accessToken)
116− resp, err := http.DefaultClient.Do(req)
117− if err != nil {
118− return false, err
119− }
120114
121− body, err := ioutil.ReadAll(resp.Body)
122− resp.Body.Close()
115+ var op orgsPage
116+ err := requests.New(endpoint.String()).
117+ WithContext(ctx).
118+ WithHeaders(getGitHubHeader(accessToken)).
119+ UnmarshalInto(&op)
123120 if err != nil {
124121 return false, err
125122 }
126− if resp.StatusCode != 200 {
127− return false, fmt.Errorf(
128− "got %d from %q %s", resp.StatusCode, endpoint.String(), body)
129− }
130123
131− var op orgsPage
132− if err := json.Unmarshal(body, &op); err != nil {
133− return false, err
134− }
135124 if len(op) == 0 {
136125 break
137126 }
@@ -187,9 +176,13 @@ func (p *GitHubProvider) hasOrgAndTeam(ctx context.Context, accessToken string)
187176 RawQuery: params.Encode(),
188177 }
189178
190− req, _ := http.NewRequestWithContext(ctx, "GET", endpoint.String(), nil)
191− req.Header = getGitHubHeader(accessToken)
192− resp, err := http.DefaultClient.Do(req)
179+ // bodyclose cannot detect that the body is being closed later in requests.Into,
180+ // so have to skip the linting for the next line.
181+ // nolint:bodyclose
182+ resp, err := requests.New(endpoint.String()).
183+ WithContext(ctx).
184+ WithHeaders(getGitHubHeader(accessToken)).
185+ Do()
193186 if err != nil {
194187 return false, err
195188 }
@@ -217,21 +210,9 @@ func (p *GitHubProvider) hasOrgAndTeam(ctx context.Context, accessToken string)
217210 }
218211 }
219212
220− body, err := ioutil.ReadAll(resp.Body)
221− if err != nil {
222− resp.Body.Close()
223− return false, err
224− }
225− resp.Body.Close()
226−
227− if resp.StatusCode != 200 {
228− return false, fmt.Errorf(
229− "got %d from %q %s", resp.StatusCode, endpoint.String(), body)
230− }
231−
232213 var tp teamsPage
233− if err := json.Unmarshal(body, &tp); err != nil {
234− return false, fmt.Errorf("%s unmarshaling %s", err, body)
214+ if err := requests.UnmarshalInto(resp, &tp); err != nil {
215+ return false, err
235216 }
236217 if len(tp) == 0 {
237218 break
@@ -297,25 +278,12 @@ func (p *GitHubProvider) hasRepo(ctx context.Context, accessToken string) (bool,
297278 Path: path.Join(p.ValidateURL.Path, "/repo/", p.Repo),
298279 }
299280
300− req, _ := http.NewRequestWithContext(ctx, "GET", endpoint.String(), nil)
301− req.Header = getGitHubHeader(accessToken)
302− resp, err := http.DefaultClient.Do(req)
303− if err != nil {
304− return false, err
305− }
306−
307− body, err := ioutil.ReadAll(resp.Body)
308− resp.Body.Close()
309− if err != nil {
310− return false, err
311− }
312− if resp.StatusCode != 200 {
313− return false, fmt.Errorf(
314− "got %d from %q %s", resp.StatusCode, endpoint.String(), body)
315− }
316−
317281 var repo repository
318− if err := json.Unmarshal(body, &repo); err != nil {
282+ err := requests.New(endpoint.String()).
283+ WithContext(ctx).
284+ WithHeaders(getGitHubHeader(accessToken)).
285+ UnmarshalInto(&repo)
286+ if err != nil {
319287 return false, err
320288 }
321289
@@ -337,26 +305,14 @@ func (p *GitHubProvider) hasUser(ctx context.Context, accessToken string) (bool,
337305 Host: p.ValidateURL.Host,
338306 Path: path.Join(p.ValidateURL.Path, "/user"),
339307 }
340− req, _ := http.NewRequestWithContext(ctx, "GET", endpoint.String(), nil)
341− req.Header = getGitHubHeader(accessToken)
342− resp, err := http.DefaultClient.Do(req)
343− if err != nil {
344− return false, err
345− }
346− defer resp.Body.Close()
347308
348− body, err := ioutil.ReadAll(resp.Body)
309+ err := requests.New(endpoint.String()).
310+ WithContext(ctx).
311+ WithHeaders(getGitHubHeader(accessToken)).
312+ UnmarshalInto(&user)
349313 if err != nil {
350314 return false, err
351315 }
352− if resp.StatusCode != 200 {
353− return false, fmt.Errorf("got %d from %q %s",
354− resp.StatusCode, stripToken(endpoint.String()), body)
355− }
356−
357− if err := json.Unmarshal(body, &user); err != nil {
358− return false, err
359− }
360316
361317 if p.isVerifiedUser(user.Login) {
362318 return true, nil
@@ -372,12 +328,14 @@ func (p *GitHubProvider) isCollaborator(ctx context.Context, username, accessTok
372328 Host: p.ValidateURL.Host,
373329 Path: path.Join(p.ValidateURL.Path, "/repos/", p.Repo, "/collaborators/", username),
374330 }
375− req, _ := http.NewRequestWithContext(ctx, "GET", endpoint.String(), nil)
376− req.Header = getGitHubHeader(accessToken)
377− resp, err := http.DefaultClient.Do(req)
331+ resp, err := requests.New(endpoint.String()).
332+ WithContext(ctx).
333+ WithHeaders(getGitHubHeader(accessToken)).
334+ Do()
378335 if err != nil {
379336 return false, err
380337 }
338+
381339 body, err := ioutil.ReadAll(resp.Body)
382340 resp.Body.Close()
383341 if err != nil {
@@ -440,29 +398,14 @@ func (p *GitHubProvider) GetEmailAddress(ctx context.Context, s *sessions.Sessio
440398 Host: p.ValidateURL.Host,
441399 Path: path.Join(p.ValidateURL.Path, "/user/emails"),
442400 }
443− req, _ := http.NewRequestWithContext(ctx, "GET", endpoint.String(), nil)
444− req.Header = getGitHubHeader(s.AccessToken)
445− resp, err := http.DefaultClient.Do(req)
446− if err != nil {
447− return "", err
448− }
449− body, err := ioutil.ReadAll(resp.Body)
450− resp.Body.Close()
401+ err := requests.New(endpoint.String()).
402+ WithContext(ctx).
403+ WithHeaders(getGitHubHeader(s.AccessToken)).
404+ UnmarshalInto(&emails)
451405 if err != nil {
452406 return "", err
453407 }
454408
455− if resp.StatusCode != 200 {
456− return "", fmt.Errorf("got %d from %q %s",
457− resp.StatusCode, endpoint.String(), body)
458− }
459−
460− logger.Printf("got %d from %q %s", resp.StatusCode, endpoint.String(), body)
461−
462− if err := json.Unmarshal(body, &emails); err != nil {
463− return "", fmt.Errorf("%s unmarshaling %s", err, body)
464− }
465−
466409 returnEmail := ""
467410 for _, email := range emails {
468411 if email.Verified {
@@ -489,34 +432,14 @@ func (p *GitHubProvider) GetUserName(ctx context.Context, s *sessions.SessionSta
489432 Path: path.Join(p.ValidateURL.Path, "/user"),
490433 }
491434
492− req, err := http.NewRequestWithContext(ctx, "GET", endpoint.String(), nil)
493− if err != nil {
494− return "", fmt.Errorf("could not create new GET request: %v", err)
495− }
496−
497− req.Header = getGitHubHeader(s.AccessToken)
498− resp, err := http.DefaultClient.Do(req)
499− if err != nil {
500− return "", err
501− }
502−
503− body, err := ioutil.ReadAll(resp.Body)
504− defer resp.Body.Close()
435+ err := requests.New(endpoint.String()).
436+ WithContext(ctx).
437+ WithHeaders(getGitHubHeader(s.AccessToken)).
438+ UnmarshalInto(&user)
505439 if err != nil {
506440 return "", err
507441 }
508442
509− if resp.StatusCode != 200 {
510− return "", fmt.Errorf("got %d from %q %s",
511− resp.StatusCode, endpoint.String(), body)
512− }
513−
514− logger.Printf("got %d from %q %s", resp.StatusCode, endpoint.String(), body)
515−
516− if err := json.Unmarshal(body, &user); err != nil {
517− return "", fmt.Errorf("%s unmarshaling %s", err, body)
518− }
519−
520443 // Now that we have the username we can check collaborator status
521444 if !p.isVerifiedUser(user.Login) && p.Org == "" && p.Repo != "" && p.Token != "" {
522445 if ok, err := p.isCollaborator(ctx, user.Login, p.Token); err != nil || !ok {
providers/gitlab.go+6−26
@@ -2,15 +2,13 @@ package providers
22
33import (
44 "context"
5− "encoding/json"
65 "fmt"
7− "io/ioutil"
8− "net/http"
96 "strings"
107 "time"
118
129 oidc "github.com/coreos/go-oidc"
1310 "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
11+ "github.com/oauth2-proxy/oauth2-proxy/pkg/requests"
1412 "golang.org/x/oauth2"
1513)
1614
@@ -131,31 +129,13 @@ func (p *GitLabProvider) getUserInfo(ctx context.Context, s *sessions.SessionSta
131129 userInfoURL := *p.LoginURL
132130 userInfoURL.Path = "/oauth/userinfo"
133131
134− req, err := http.NewRequestWithContext(ctx, "GET", userInfoURL.String(), nil)
135− if err != nil {
136− return nil, fmt.Errorf("failed to create user info request: %v", err)
137− }
138− req.Header.Set("Authorization", "Bearer "+s.AccessToken)
139−
140− resp, err := http.DefaultClient.Do(req)
141− if err != nil {
142− return nil, fmt.Errorf("failed to perform user info request: %v", err)
143− }
144− var body []byte
145− body, err = ioutil.ReadAll(resp.Body)
146− resp.Body.Close()
147− if err != nil {
148− return nil, fmt.Errorf("failed to read user info response: %v", err)
149− }
150−
151− if resp.StatusCode != 200 {
152− return nil, fmt.Errorf("got %d during user info request: %s", resp.StatusCode, body)
153− }
154−
155132 var userInfo gitlabUserInfo
156− err = json.Unmarshal(body, &userInfo)
133+ err := requests.New(userInfoURL.String()).
134+ WithContext(ctx).
135+ SetHeader("Authorization", "Bearer "+s.AccessToken).
136+ UnmarshalInto(&userInfo)
157137 if err != nil {
158− return nil, fmt.Errorf("failed to parse user info: %v", err)
138+ return nil, fmt.Errorf("error getting user info: %v", err)
159139 }
160140
161141 return &userInfo, nil
providers/google.go+19−49
@@ -9,13 +9,13 @@ import (
99 "fmt"
1010 "io"
1111 "io/ioutil"
12− "net/http"
1312 "net/url"
1413 "strings"
1514 "time"
1615
1716 "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
1817 "github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
18+ "github.com/oauth2-proxy/oauth2-proxy/pkg/requests"
1919 "golang.org/x/oauth2/google"
2020 admin "google.golang.org/api/admin/directory/v1"
2121 "google.golang.org/api/googleapi"
@@ -116,28 +116,6 @@ func (p *GoogleProvider) Redeem(ctx context.Context, redirectURL, code string) (
116116 params.Add("client_secret", clientSecret)
117117 params.Add("code", code)
118118 params.Add("grant_type", "authorization_code")
119− var req *http.Request
120− req, err = http.NewRequestWithContext(ctx, "POST", p.RedeemURL.String(), bytes.NewBufferString(params.Encode()))
121− if err != nil {
122− return
123− }
124− req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
125−
126− resp, err := http.DefaultClient.Do(req)
127− if err != nil {
128− return
129− }
130− var body []byte
131− body, err = ioutil.ReadAll(resp.Body)
132− resp.Body.Close()
133− if err != nil {
134− return
135− }
136−
137− if resp.StatusCode != 200 {
138− err = fmt.Errorf("got %d from %q %s", resp.StatusCode, p.RedeemURL.String(), body)
139− return
140− }
141119
142120 var jsonResponse struct {
143121 AccessToken string `json:"access_token"`
@@ -145,10 +123,17 @@ func (p *GoogleProvider) Redeem(ctx context.Context, redirectURL, code string) (
145123 ExpiresIn int64 `json:"expires_in"`
146124 IDToken string `json:"id_token"`
147125 }
148− err = json.Unmarshal(body, &jsonResponse)
126+
127+ err = requests.New(p.RedeemURL.String()).
128+ WithContext(ctx).
129+ WithMethod("POST").
130+ WithBody(bytes.NewBufferString(params.Encode())).
131+ SetHeader("Content-Type", "application/x-www-form-urlencoded").
132+ UnmarshalInto(&jsonResponse)
149133 if err != nil {
150− return
134+ return nil, err
151135 }
136+
152137 c, err := claimsFromIDToken(jsonResponse.IDToken)
153138 if err != nil {
154139 return
@@ -283,38 +268,23 @@ func (p *GoogleProvider) redeemRefreshToken(ctx context.Context, refreshToken st
283268 params.Add("client_secret", clientSecret)
284269 params.Add("refresh_token", refreshToken)
285270 params.Add("grant_type", "refresh_token")
286− var req *http.Request
287− req, err = http.NewRequestWithContext(ctx, "POST", p.RedeemURL.String(), bytes.NewBufferString(params.Encode()))
288− if err != nil {
289− return
290− }
291− req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
292−
293− resp, err := http.DefaultClient.Do(req)
294− if err != nil {
295− return
296− }
297− var body []byte
298− body, err = ioutil.ReadAll(resp.Body)
299− resp.Body.Close()
300− if err != nil {
301− return
302− }
303−
304− if resp.StatusCode != 200 {
305− err = fmt.Errorf("got %d from %q %s", resp.StatusCode, p.RedeemURL.String(), body)
306− return
307− }
308271
309272 var data struct {
310273 AccessToken string `json:"access_token"`
311274 ExpiresIn int64 `json:"expires_in"`
312275 IDToken string `json:"id_token"`
313276 }
314− err = json.Unmarshal(body, &data)
277+
278+ err = requests.New(p.RedeemURL.String()).
279+ WithContext(ctx).
280+ WithMethod("POST").
281+ WithBody(bytes.NewBufferString(params.Encode())).
282+ SetHeader("Content-Type", "application/x-www-form-urlencoded").
283+ UnmarshalInto(&data)
315284 if err != nil {
316− return
285+ return "", "", 0, err
317286 }
287+
318288 token = data.AccessToken
319289 idToken = data.IDToken
320290 expires = time.Duration(data.ExpiresIn) * time.Second
providers/internal_util.go+5−1
@@ -56,7 +56,11 @@ func validateToken(ctx context.Context, p Provider, accessToken string, header h
5656 params := url.Values{"access_token": {accessToken}}
5757 endpoint = endpoint + "?" + params.Encode()
5858 }
59− resp, err := requests.RequestUnparsedResponse(ctx, endpoint, header)
59+
60+ resp, err := requests.New(endpoint).
61+ WithContext(ctx).
62+ WithHeaders(header).
63+ Do()
6064 if err != nil {
6165 logger.Printf("GET %s", stripToken(endpoint))
6266 logger.Printf("token validation request failed: %s", err)
providers/keycloak.go+4−9
@@ -2,7 +2,6 @@ package providers
22
33import (
44 "context"
5− "net/http"
65 "net/url"
76
87 "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
@@ -51,14 +50,10 @@ func (p *KeycloakProvider) SetGroup(group string) {
5150}
5251
5352func (p *KeycloakProvider) GetEmailAddress(ctx context.Context, s *sessions.SessionState) (string, error) {
54−
55− req, err := http.NewRequestWithContext(ctx, "GET", p.ValidateURL.String(), nil)
56− req.Header.Set("Authorization", "Bearer "+s.AccessToken)
57− if err != nil {
58− logger.Printf("failed building request %s", err)
59− return "", err
60− }
61− json, err := requests.Request(req)
53+ json, err := requests.New(p.ValidateURL.String()).
54+ WithContext(ctx).
55+ SetHeader("Authorization", "Bearer "+s.AccessToken).
56+ UnmarshalJSON()
6257 if err != nil {
6358 logger.Printf("failed making request %s", err)
6459 return "", err
providers/linkedin.go+5−6
@@ -58,13 +58,12 @@ func (p *LinkedInProvider) GetEmailAddress(ctx context.Context, s *sessions.Sess
5858 if s.AccessToken == "" {
5959 return "", errors.New("missing access token")
6060 }
61− req, err := http.NewRequestWithContext(ctx, "GET", p.ProfileURL.String()+"?format=json", nil)
62− if err != nil {
63− return "", err
64− }
65− req.Header = getLinkedInHeader(s.AccessToken)
6661
67− json, err := requests.Request(req)
62+ requestURL := p.ProfileURL.String() + "?format=json"
63+ json, err := requests.New(requestURL).
64+ WithContext(ctx).
65+ WithHeaders(getLinkedInHeader(s.AccessToken)).
66+ UnmarshalJSON()
6867 if err != nil {
6968 return "", err
7069 }
providers/logingov.go+24−60
@@ -15,6 +15,7 @@ import (
1515
1616 "github.com/dgrijalva/jwt-go"
1717 "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
18+ "github.com/oauth2-proxy/oauth2-proxy/pkg/requests"
1819 "gopkg.in/square/go-jose.v2"
1920)
2021
@@ -128,51 +129,33 @@ func checkNonce(idToken string, p *LoginGovProvider) (err error) {
128129 return
129130}
130131
131−func emailFromUserInfo(ctx context.Context, accessToken string, userInfoEndpoint string) (email string, err error) {
132− // query the user info endpoint for user attributes
133− var req *http.Request
134− req, err = http.NewRequestWithContext(ctx, "GET", userInfoEndpoint, nil)
135− if err != nil {
136− return
137− }
138− req.Header.Set("Authorization", "Bearer "+accessToken)
139−
140− resp, err := http.DefaultClient.Do(req)
141− if err != nil {
142− return
143− }
144− var body []byte
145− body, err = ioutil.ReadAll(resp.Body)
146− resp.Body.Close()
147− if err != nil {
148− return
149− }
150−
151− if resp.StatusCode != 200 {
152− err = fmt.Errorf("got %d from %q %s", resp.StatusCode, userInfoEndpoint, body)
153− return
154− }
155−
132+func emailFromUserInfo(ctx context.Context, accessToken string, userInfoEndpoint string) (string, error) {
156133 // parse the user attributes from the data we got and make sure that
157134 // the email address has been validated.
158135 var emailData struct {
159136 Email string `json:"email"`
160137 EmailVerified bool `json:"email_verified"`
161138 }
162− err = json.Unmarshal(body, &emailData)
139+
140+ // query the user info endpoint for user attributes
141+ err := requests.New(userInfoEndpoint).
142+ WithContext(ctx).
143+ SetHeader("Authorization", "Bearer "+accessToken).
144+ UnmarshalInto(&emailData)
163145 if err != nil {
164− return
146+ return "", err
165147 }
166− if emailData.Email == "" {
167− err = fmt.Errorf("missing email")
168− return
148+
149+ email := emailData.Email
150+ if email == "" {
151+ return "", fmt.Errorf("missing email")
169152 }
170− email = emailData.Email
153+
171154 if !emailData.EmailVerified {
172− err = fmt.Errorf("email %s not listed as verified", email)
173− return
155+ return "", fmt.Errorf("email %s not listed as verified", email)
174156 }
175− return
157+
158+ return email, nil
176159}
177160
178161// Redeem exchanges the OAuth2 authentication token for an ID token
@@ -201,30 +184,6 @@ func (p *LoginGovProvider) Redeem(ctx context.Context, redirectURL, code string)
201184 params.Add("code", code)
202185 params.Add("grant_type", "authorization_code")
203186
204− var req *http.Request
205− req, err = http.NewRequestWithContext(ctx, "POST", p.RedeemURL.String(), bytes.NewBufferString(params.Encode()))
206− if err != nil {
207− return
208− }
209− req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
210−
211− var resp *http.Response
212− resp, err = http.DefaultClient.Do(req)
213− if err != nil {
214− return nil, err
215− }
216− var body []byte
217− body, err = ioutil.ReadAll(resp.Body)
218− resp.Body.Close()
219− if err != nil {
220− return
221− }
222−
223− if resp.StatusCode != 200 {
224− err = fmt.Errorf("got %d from %q %s", resp.StatusCode, p.RedeemURL.String(), body)
225− return
226− }
227−
228187 // Get the token from the body that we got from the token endpoint.
229188 var jsonResponse struct {
230189 AccessToken string `json:"access_token"`
@@ -232,9 +191,14 @@ func (p *LoginGovProvider) Redeem(ctx context.Context, redirectURL, code string)
232191 TokenType string `json:"token_type"`
233192 ExpiresIn int64 `json:"expires_in"`
234193 }
235− err = json.Unmarshal(body, &jsonResponse)
194+ err = requests.New(p.RedeemURL.String()).
195+ WithContext(ctx).
196+ WithMethod("POST").
197+ WithBody(bytes.NewBufferString(params.Encode())).
198+ SetHeader("Content-Type", "application/x-www-form-urlencoded").
199+ UnmarshalInto(&jsonResponse)
236200 if err != nil {
237− return
201+ return nil, err
238202 }
239203
240204 // check nonce here
providers/nextcloud.go+6−11
@@ -6,7 +6,6 @@ import (
66 "net/http"
77
88 "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
9− "github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
109 "github.com/oauth2-proxy/oauth2-proxy/pkg/requests"
1110)
1211
@@ -31,18 +30,14 @@ func getNextcloudHeader(accessToken string) http.Header {
3130
3231// GetEmailAddress returns the Account email address
3332func (p *NextcloudProvider) GetEmailAddress(ctx context.Context, s *sessions.SessionState) (string, error) {
34− req, err := http.NewRequestWithContext(ctx, "GET",
35− p.ValidateURL.String(), nil)
33+ json, err := requests.New(p.ValidateURL.String()).
34+ WithContext(ctx).
35+ WithHeaders(getNextcloudHeader(s.AccessToken)).
36+ UnmarshalJSON()
3637 if err != nil {
37− logger.Printf("failed building request %s", err)
38− return "", err
39− }
40− req.Header = getNextcloudHeader(s.AccessToken)
41− json, err := requests.Request(req)
42− if err != nil {
43− logger.Printf("failed making request %s", err)
44− return "", err
38+ return "", fmt.Errorf("error making request: %v", err)
4539 }
40+
4641 email, err := json.Get("ocs").Get("data").Get("email").String()
4742 return email, err
4843}
providers/oidc.go+4−7
@@ -256,13 +256,10 @@ func (p *OIDCProvider) findClaimsFromIDToken(ctx context.Context, idToken *oidc.
256256 // If the userinfo endpoint profileURL is defined, then there is a chance the userinfo
257257 // contents at the profileURL contains the email.
258258 // Make a query to the userinfo endpoint, and attempt to locate the email from there.
259− req, err := http.NewRequestWithContext(ctx, "GET", profileURL, nil)
260− if err != nil {
261− return nil, err
262− }
263− req.Header = getOIDCHeader(accessToken)
264−
265− respJSON, err := requests.Request(req)
259+ respJSON, err := requests.New(profileURL).
260+ WithContext(ctx).
261+ WithHeaders(getOIDCHeader(accessToken)).
262+ UnmarshalJSON()
266263 if err != nil {
267264 return nil, err
268265 }
providers/provider_default.go+8−10
@@ -7,13 +7,13 @@ import (
77 "errors"
88 "fmt"
99 "io/ioutil"
10− "net/http"
1110 "net/url"
1211 "time"
1312
1413 "github.com/coreos/go-oidc"
1514
1615 "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
16+ "github.com/oauth2-proxy/oauth2-proxy/pkg/requests"
1717)
1818
1919var _ Provider = (*ProviderData)(nil)
@@ -39,18 +39,16 @@ func (p *ProviderData) Redeem(ctx context.Context, redirectURL, code string) (s
3939 params.Add("resource", p.ProtectedResource.String())
4040 }
4141
42− var req *http.Request
43− req, err = http.NewRequestWithContext(ctx, "POST", p.RedeemURL.String(), bytes.NewBufferString(params.Encode()))
44− if err != nil {
45− return
46− }
47− req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
48−
49− var resp *http.Response
50− resp, err = http.DefaultClient.Do(req)
42+ resp, err := requests.New(p.RedeemURL.String()).
43+ WithContext(ctx).
44+ WithMethod("POST").
45+ WithBody(bytes.NewBufferString(params.Encode())).
46+ SetHeader("Content-Type", "application/x-www-form-urlencoded").
47+ Do()
5148 if err != nil {
5249 return nil, err
5350 }
51+
5452 var body []byte
5553 body, err = ioutil.ReadAll(resp.Body)
5654 resp.Body.Close()