diff --git a/auth.go b/auth.go index ba5836b..0a4e36d 100644 --- a/auth.go +++ b/auth.go @@ -210,8 +210,7 @@ func (s *Service) Middleware() middleware.Authenticator { // AddProvider adds provider for given name func (s *Service) AddProvider(name, cid, csecret string) { - - p := provider.Params{ + s.addProviderWithParams(name, provider.Params{ URL: s.opts.URL, JwtService: s.jwtService, Issuer: s.issuer, @@ -219,8 +218,25 @@ func (s *Service) AddProvider(name, cid, csecret string) { Cid: cid, Csecret: csecret, L: s.logger, - } + }) +} + +// AddProviderWithOptions adds provider for given name with extra options +func (s *Service) AddProviderWithOptions(name, cid, csecret string, extraScopes []string, extraUserInfoFn provider.ExtraUserInfoFunc) { + s.addProviderWithParams(name, provider.Params{ + URL: s.opts.URL, + JwtService: s.jwtService, + Issuer: s.issuer, + AvatarSaver: s.avatarProxy, + Cid: cid, + Csecret: csecret, + ExtraScopes: extraScopes, + ExtraUserInfoFn: extraUserInfoFn, + L: s.logger, + }) +} +func (s *Service) addProviderWithParams(name string, p provider.Params) { switch strings.ToLower(name) { case "github": s.providers = append(s.providers, provider.NewService(provider.NewGithub(p))) diff --git a/provider/oauth2.go b/provider/oauth2.go index 644de4a..9767985 100644 --- a/provider/oauth2.go +++ b/provider/oauth2.go @@ -33,11 +33,14 @@ type Oauth2Handler struct { // Params to make initialized and ready to use provider type Params struct { logger.L - URL string - JwtService TokenService - Cid string - Csecret string - Issuer string + URL string + JwtService TokenService + Cid string + Csecret string + Issuer string + ExtraScopes []string + ExtraUserInfoFn ExtraUserInfoFunc + AvatarSaver AvatarSaver Port int // relevant for providers supporting port customization, for example dev oauth2 @@ -46,6 +49,9 @@ type Params struct { // UserData is type for user information returned from oauth2 providers /info API method type UserData map[string]interface{} +// ExtraUserInfoFunc allows to provide extra user info using the authenticated http client +type ExtraUserInfoFunc func(c *http.Client, u token.User) token.User + // Value returns value for key or empty string if not found func (u UserData) Value(key string) string { // json.Unmarshal converts json "null" value to go's "nil", in this case return empty string @@ -65,7 +71,7 @@ func initOauth2Handler(p Params, service Oauth2Handler) Oauth2Handler { service.conf = oauth2.Config{ ClientID: service.Cid, ClientSecret: service.Csecret, - Scopes: service.scopes, + Scopes: append(service.scopes, p.ExtraScopes...), Endpoint: service.endpoint, } @@ -195,6 +201,10 @@ func (p Oauth2Handler) AuthHandler(w http.ResponseWriter, r *http.Request) { return } + if p.ExtraUserInfoFn != nil { + u = p.ExtraUserInfoFn(client, u) + } + cid, err := randToken() if err != nil { rest.SendErrorJSON(w, r, p.L, http.StatusInternalServerError, err, "failed to make claim's id") diff --git a/provider/oauth2_test.go b/provider/oauth2_test.go index b838a59..7832766 100644 --- a/provider/oauth2_test.go +++ b/provider/oauth2_test.go @@ -177,13 +177,14 @@ func TestOauth2Logout(t *testing.T) { } func TestOauth2InitProvider(t *testing.T) { - params := Params{URL: "url", Cid: "cid", Csecret: "csecret", Issuer: "app-test"} - provider := Oauth2Handler{name: "test"} + params := Params{URL: "url", Cid: "cid", Csecret: "csecret", Issuer: "app-test", ExtraScopes: []string{"extra-scope"}} + provider := Oauth2Handler{name: "test", scopes: []string{"minimal-scope"}} res := initOauth2Handler(params, provider) assert.Equal(t, "cid", res.conf.ClientID) assert.Equal(t, "csecret", res.conf.ClientSecret) assert.Equal(t, "test", res.name) assert.Equal(t, "app-test", res.Issuer) + assert.Equal(t, []string{"minimal-scope", "extra-scope"}, res.conf.Scopes) } func TestOauth2InvalidHandler(t *testing.T) {