@@ -17,6 +17,7 @@ package main
1717
1818import (
1919 "bytes"
20+ "context"
2021 "encoding/base64"
2122 "encoding/json"
2223 "errors"
@@ -31,8 +32,8 @@ import (
3132 "strings"
3233 "time"
3334
34- "github.com/coreos/go-oidc/oauth2"
3535 "github.com/coreos/go-oidc/oidc"
36+ "golang.org/x/oauth2"
3637
3738 "github.com/go-chi/chi"
3839 "go.uber.org/zap"
@@ -72,22 +73,17 @@ func (r *oauthProxy) oauthAuthorizationHandler(w http.ResponseWriter, req *http.
7273 w .WriteHeader (http .StatusNotAcceptable )
7374 return
7475 }
75- client , err := r .getOAuthClient (r .getRedirectionURL (w , req ), getClientAuthMethod (r .config .ClientAuthMethod ))
76- if err != nil {
77- r .log .Error ("failed to retrieve the oauth client for authorization" , zap .Error (err ))
78- w .WriteHeader (http .StatusInternalServerError )
79- return
80- }
76+ conf := r .newOAuth2Config (r .getRedirectionURL (w , req ))
8177
8278 // step: set the access type of the session
83- var accessType string
79+ accessType := oauth2 . AccessTypeOnline
8480 if containedIn ("offline" , r .config .Scopes ) {
85- accessType = "offline"
81+ accessType = oauth2 . AccessTypeOffline
8682 }
8783
88- authURL := client .AuthCodeURL (req .URL .Query ().Get ("state" ), accessType , "" )
84+ authURL := conf .AuthCodeURL (req .URL .Query ().Get ("state" ), accessType )
8985 r .log .Debug ("incoming authorization request from client address" ,
90- zap .String ("access_type" , accessType ),
86+ zap .Any ("access_type" , accessType ),
9187 zap .String ("auth_url" , authURL ),
9288 zap .String ("client_ip" , req .RemoteAddr ))
9389
@@ -104,18 +100,6 @@ func (r *oauthProxy) oauthAuthorizationHandler(w http.ResponseWriter, req *http.
104100 r .redirectToURL (authURL , w , req , http .StatusSeeOther )
105101}
106102
107- // getClientAuthMethod maps the config value CLIENT_AUTH_METHOD to valid OAuth2 auth method keys
108- func getClientAuthMethod (authMethod string ) string {
109- switch authMethod {
110- case authMethodBasic :
111- return oauth2 .AuthMethodClientSecretBasic
112- case authMethodBody :
113- return oauth2 .AuthMethodClientSecretPost
114- default :
115- return ""
116- }
117- }
118-
119103// oauthCallbackHandler is responsible for handling the response from oauth service
120104func (r * oauthProxy ) oauthCallbackHandler (w http.ResponseWriter , req * http.Request ) {
121105 if r .config .SkipTokenVerification {
@@ -129,14 +113,9 @@ func (r *oauthProxy) oauthCallbackHandler(w http.ResponseWriter, req *http.Reque
129113 return
130114 }
131115
132- client , err := r .getOAuthClient (r .getRedirectionURL (w , req ), getClientAuthMethod (r .config .ClientAuthMethod ))
133- if err != nil {
134- r .log .Error ("unable to create a oauth2 client" , zap .Error (err ))
135- w .WriteHeader (http .StatusInternalServerError )
136- return
137- }
116+ conf := r .newOAuth2Config (r .getRedirectionURL (w , req ))
138117
139- resp , err := exchangeAuthenticationCode (client , code )
118+ resp , err := exchangeAuthenticationCode (conf , code )
140119 if err != nil {
141120 r .log .Error ("unable to exchange code for access token" , zap .Error (err ))
142121 r .accessForbidden (w , req )
@@ -146,12 +125,20 @@ func (r *oauthProxy) oauthCallbackHandler(w http.ResponseWriter, req *http.Reque
146125 // Flow: once we exchange the authorization code we parse the ID Token; we then check for an access token,
147126 // if an access token is present and we can decode it, we use that as the session token, otherwise we default
148127 // to the ID Token.
149- token , identity , err := parseToken (resp .IDToken )
128+ rawIDToken , ok := resp .Extra ("id_token" ).(string )
129+ if ! ok {
130+ r .log .Error ("unable to obtain id token" , zap .Error (err ))
131+ r .accessForbidden (w , req )
132+ return
133+ }
134+
135+ token , identity , err := parseToken (rawIDToken )
150136 if err != nil {
151137 r .log .Error ("unable to parse id token for identity" , zap .Error (err ))
152138 r .accessForbidden (w , req )
153139 return
154140 }
141+
155142 access , id , err := parseToken (resp .AccessToken )
156143 if err == nil {
157144 token = access
@@ -195,7 +182,7 @@ func (r *oauthProxy) oauthCallbackHandler(w http.ResponseWriter, req *http.Reque
195182 return
196183 }
197184 // drop in the access token - cookie expiration = access token
198- r .dropAccessTokenCookie (req , w , accessToken , r .getAccessCookieExpiration (token , resp .RefreshToken ))
185+ r .dropAccessTokenCookie (req , w , accessToken , r .getAccessCookieExpiration (resp .RefreshToken ))
199186
200187 var expiration time.Duration
201188 // notes: not all idp refresh tokens are readable, google for example, so we attempt to decode into
@@ -235,6 +222,8 @@ func (r *oauthProxy) oauthCallbackHandler(w http.ResponseWriter, req *http.Reque
235222// loginHandler provide's a generic endpoint for clients to perform a user_credentials login to the provider
236223func (r * oauthProxy ) loginHandler (w http.ResponseWriter , req * http.Request ) {
237224 errorMsg , code , err := func () (string , int , error ) {
225+ ctx := context .Background ()
226+
238227 if ! r .config .EnableLoginHandler {
239228 return "attempt to login when login handler is disabled" , http .StatusNotImplemented , errors .New ("login handler disabled" )
240229 }
@@ -244,15 +233,13 @@ func (r *oauthProxy) loginHandler(w http.ResponseWriter, req *http.Request) {
244233 return "request does not have both username and password" , http .StatusBadRequest , errors .New ("no credentials" )
245234 }
246235
247- client , err := r .client .OAuthClient ()
248- if err != nil {
249- return "unable to create the oauth client for user_credentials request" , http .StatusInternalServerError , err
250- }
236+ conf := r .newOAuth2Config (r .getRedirectionURL (w , req ))
251237
252238 start := time .Now ()
253- token , err := client .UserCredsToken (username , password )
239+ token , err := conf .PasswordCredentialsToken (ctx , username , password )
240+
254241 if err != nil {
255- if strings . HasPrefix ( err . Error (), oauth2 . ErrorInvalidGrant ) {
242+ if ! token . Valid ( ) {
256243 return "invalid user credentials provided" , http .StatusUnauthorized , err
257244 }
258245 return "unable to request the access token via grant_type 'password'" , http .StatusInternalServerError , err
@@ -271,12 +258,21 @@ func (r *oauthProxy) loginHandler(w http.ResponseWriter, req *http.Request) {
271258 oauthTokensMetric .WithLabelValues ("login" ).Inc ()
272259
273260 w .Header ().Set ("Content-Type" , "application/json" )
261+ idToken , ok := token .Extra ("id_token" ).(string )
262+ if ! ok {
263+ return "" , http .StatusInternalServerError , fmt .Errorf ("token response does not contain an id_token" )
264+ }
265+ expiresIn , ok := token .Extra ("expires_in" ).(float64 )
266+ if ! ok {
267+ return "" , http .StatusInternalServerError , fmt .Errorf ("token response does not contain expires_in" )
268+ }
269+ scope , _ := token .Extra ("scope" ).(string )
274270 if err := json .NewEncoder (w ).Encode (tokenResponse {
275- IDToken : token . IDToken ,
271+ IDToken : idToken ,
276272 AccessToken : token .AccessToken ,
277273 RefreshToken : token .RefreshToken ,
278- ExpiresIn : token . Expires ,
279- Scope : token . Scope ,
274+ ExpiresIn : expiresIn ,
275+ Scope : scope ,
280276 }); err != nil {
281277 return "" , http .StatusInternalServerError , err
282278 }
@@ -321,6 +317,7 @@ func (r *oauthProxy) logoutHandler(w http.ResponseWriter, req *http.Request) {
321317
322318 // step: can either use the id token or the refresh token
323319 identityToken := user .token .Encode ()
320+ //nolint:vetshadow
324321 if refresh , _ , err := r .retrieveRefreshToken (req , user ); err == nil {
325322 identityToken = refresh
326323 }
@@ -332,7 +329,7 @@ func (r *oauthProxy) logoutHandler(w http.ResponseWriter, req *http.Request) {
332329 // step: check if the user has a state session and if so revoke it
333330 if r .useStore () {
334331 go func () {
335- if err : = r .DeleteRefreshToken (user .token ); err != nil {
332+ if err = r .DeleteRefreshToken (user .token ); err != nil {
336333 r .log .Error ("unable to remove the refresh token from store" , zap .Error (err ))
337334 }
338335 }()
@@ -366,13 +363,12 @@ func (r *oauthProxy) logoutHandler(w http.ResponseWriter, req *http.Request) {
366363
367364 // step: do we have a revocation endpoint?
368365 if revocationURL != "" {
369- client , err := r . client . OAuthClient ()
366+ client := & http. Client { Timeout : 5 * time . Second }
370367 if err != nil {
371368 r .log .Error ("unable to retrieve the openid client" , zap .Error (err ))
372369 w .WriteHeader (http .StatusInternalServerError )
373370 return
374371 }
375-
376372 // step: add the authentication headers
377373 encodedID := url .QueryEscape (r .config .ClientID )
378374 encodedSecret := url .QueryEscape (r .config .ClientSecret )
@@ -390,7 +386,7 @@ func (r *oauthProxy) logoutHandler(w http.ResponseWriter, req *http.Request) {
390386 request .Header .Set ("Content-Type" , "application/x-www-form-urlencoded" )
391387
392388 start := time .Now ()
393- response , err := client .HttpClient (). Do (request )
389+ response , err := client .Do (request )
394390 if err != nil {
395391 r .log .Error ("unable to post to revocation endpoint" , zap .Error (err ))
396392 return
0 commit comments