@@ -394,6 +394,9 @@ func (f *FakeIDP) ExternalLogin(t testing.TB, client *codersdk.Client, opts ...f
394
394
res ,err := cli .Do (req )
395
395
require .NoError (t ,err )
396
396
require .Equal (t ,http .StatusOK ,res .StatusCode ,"client failed to login" )
397
+ t .Cleanup (func () {
398
+ res .Body .Close ()
399
+ })
397
400
return res
398
401
}
399
402
@@ -690,23 +693,31 @@ func (f *FakeIDP) httpHandler(t testing.TB) http.Handler {
690
693
_ = json .NewEncoder (rw ).Encode (token )
691
694
}))
692
695
693
- mux . Handle ( userInfoPath , http . HandlerFunc ( func (rw http.ResponseWriter ,r * http.Request ) {
696
+ validateMW := func (rw http.ResponseWriter ,r * http.Request ) ( email string , ok bool ) {
694
697
token ,err := f .authenticateBearerTokenRequest (t ,r )
695
698
f .logger .Info (r .Context (),"http call idp user info" ,
696
699
slog .Error (err ),
697
700
slog .F ("url" ,r .URL .String ()),
698
701
)
699
702
if err != nil {
700
703
http .Error (rw ,fmt .Sprintf ("invalid user info request: %s" ,err .Error ()),http .StatusBadRequest )
701
- return
704
+ return "" , false
702
705
}
703
706
704
- email ,ok : =f .accessTokens .Load (token )
707
+ email ,ok = f .accessTokens .Load (token )
705
708
if ! ok {
706
709
t .Errorf ("access token user for user_info has no email to indicate which user" )
707
710
http .Error (rw ,"invalid access token, missing user info" ,http .StatusBadRequest )
711
+ return "" ,false
712
+ }
713
+ return email ,true
714
+ }
715
+ mux .Handle (userInfoPath ,http .HandlerFunc (func (rw http.ResponseWriter ,r * http.Request ) {
716
+ email ,ok := validateMW (rw ,r )
717
+ if ! ok {
708
718
return
709
719
}
720
+
710
721
claims ,err := f .hookUserInfo (email )
711
722
if err != nil {
712
723
http .Error (rw ,fmt .Sprintf ("user info hook returned error: %s" ,err .Error ()),httpErrorCode (http .StatusBadRequest ,err ))
@@ -715,21 +726,12 @@ func (f *FakeIDP) httpHandler(t testing.TB) http.Handler {
715
726
_ = json .NewEncoder (rw ).Encode (claims )
716
727
}))
717
728
729
+ // There is almost no difference between this and /userinfo.
730
+ // The main tweak is that this route is "mounted" vs "handle" because "/userinfo"
731
+ // should be strict, and this one needs to handle sub routes.
718
732
mux .Mount ("/external-auth-validate/" ,http .HandlerFunc (func (rw http.ResponseWriter ,r * http.Request ) {
719
- token ,err := f .authenticateBearerTokenRequest (t ,r )
720
- f .logger .Info (r .Context (),"http call idp external auth validate" ,
721
- slog .Error (err ),
722
- slog .F ("url" ,r .URL .String ()),
723
- )
724
- if err != nil {
725
- http .Error (rw ,fmt .Sprintf ("invalid user info request: %s" ,err .Error ()),http .StatusBadRequest )
726
- return
727
- }
728
-
729
- email ,ok := f .accessTokens .Load (token )
733
+ email ,ok := validateMW (rw ,r )
730
734
if ! ok {
731
- t .Errorf ("access token user for external auth validate has no email to indicate which user" )
732
- http .Error (rw ,"invalid access token" ,http .StatusBadRequest )
733
735
return
734
736
}
735
737
@@ -844,6 +846,9 @@ func (f *FakeIDP) SetCoderdCallbackHandler(handler http.HandlerFunc) {
844
846
})
845
847
}
846
848
849
+ // ExternalAuthConfigOptions exists to provide additional functionality ontop
850
+ // of the standard "validate" url. Some providers like github we actually parse
851
+ // the response from the validate URL to gain additional information.
847
852
type ExternalAuthConfigOptions struct {
848
853
// ValidatePayload is the payload that is used when the user calls the
849
854
// equivalent of "userinfo" for oauth2. This is not standardized, so is
@@ -870,8 +875,7 @@ func (o *ExternalAuthConfigOptions) AddRoute(route string, handle func(email str
870
875
return o
871
876
}
872
877
873
- // ExternalAuthConfig takes a validatePayload, which should be the user data in a parseable format based
874
- // on the type. Or just omitted if the user info is not important.
878
+ // ExternalAuthConfig is the config for external auth providers.
875
879
func (f * FakeIDP )ExternalAuthConfig (t testing.TB ,id string ,custom * ExternalAuthConfigOptions ,opts ... func (cfg * externalauth.Config ))* externalauth.Config {
876
880
if custom == nil {
877
881
custom = & ExternalAuthConfigOptions {}