From 2837563147d18dba263ed4c7a1b87571474220c4 Mon Sep 17 00:00:00 2001 From: techknowlogick Date: Thu, 12 Sep 2019 22:15:36 -0400 Subject: [PATCH] oauth2 with remote Gitea - Fix #8093 (#8149) --- go.mod | 2 +- go.sum | 4 +- models/oauth2.go | 8 + modules/auth/oauth2/oauth2.go | 23 +++ options/locale/locale_en-US.ini | 1 + public/img/auth/gitea.png | Bin 0 -> 5576 bytes public/js/index.js | 2 + templates/admin/auth/new.tmpl | 2 + vendor/github.com/markbates/goth/.travis.yml | 1 + vendor/github.com/markbates/goth/README.md | 5 + .../markbates/goth/gothic/gothic.go | 24 ++- .../markbates/goth/providers/gitea/gitea.go | 186 ++++++++++++++++++ .../markbates/goth/providers/gitea/session.go | 63 ++++++ vendor/modules.txt | 3 +- 14 files changed, 307 insertions(+), 17 deletions(-) create mode 100644 public/img/auth/gitea.png create mode 100644 vendor/github.com/markbates/goth/providers/gitea/gitea.go create mode 100644 vendor/github.com/markbates/goth/providers/gitea/session.go diff --git a/go.mod b/go.mod index d72269abdd..41e2297934 100644 --- a/go.mod +++ b/go.mod @@ -68,8 +68,8 @@ require ( github.com/lib/pq v1.2.0 github.com/lunny/dingtalk_webhook v0.0.0-20171025031554-e3534c89ef96 github.com/lunny/levelqueue v0.0.0-20190217115915-02b525a4418e + github.com/markbates/goth v1.56.0 github.com/mailru/easyjson v0.7.0 // indirect - github.com/markbates/goth v1.49.0 github.com/mattn/go-isatty v0.0.7 github.com/mattn/go-oci8 v0.0.0-20190320171441-14ba190cf52d // indirect github.com/mattn/go-sqlite3 v1.11.0 diff --git a/go.sum b/go.sum index 425a83c314..a0eff427da 100644 --- a/go.sum +++ b/go.sum @@ -408,8 +408,8 @@ github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM= github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= github.com/markbates/going v1.0.0/go.mod h1:I6mnB4BPnEeqo85ynXIx1ZFLLbtiLHNXVgWeFO9OGOA= -github.com/markbates/goth v1.49.0 h1:qQ4Ti4WaqAxNAggOC+4s5M85sMVfMJwQn/Xkp73wfgI= -github.com/markbates/goth v1.49.0/go.mod h1:zZmAw0Es0Dpm7TT/4AdN14QrkiWLMrrU9Xei1o+/mdA= +github.com/markbates/goth v1.56.0 h1:XEYedCgMNz5pi3ojXI8z2XUmXtBnMeuKUpx4Z6HlNj8= +github.com/markbates/goth v1.56.0/go.mod h1:zZmAw0Es0Dpm7TT/4AdN14QrkiWLMrrU9Xei1o+/mdA= github.com/mattn/go-isatty v0.0.7 h1:UvyT9uN+3r7yLEYSlJsbQGdsaB/a0DlgWP3pql6iwOc= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-oci8 v0.0.0-20190320171441-14ba190cf52d h1:m+dSK37rFf2fqppZhg15yI2IwC9BtucBiRwSDm9VL8g= diff --git a/models/oauth2.go b/models/oauth2.go index bf4446229a..c82c1cbadb 100644 --- a/models/oauth2.go +++ b/models/oauth2.go @@ -44,6 +44,13 @@ var OAuth2Providers = map[string]OAuth2Provider{ "openidConnect": {Name: "openidConnect", DisplayName: "OpenID Connect", Image: "/img/auth/openid_connect.png"}, "twitter": {Name: "twitter", DisplayName: "Twitter", Image: "/img/auth/twitter.png"}, "discord": {Name: "discord", DisplayName: "Discord", Image: "/img/auth/discord.png"}, + "gitea": {Name: "gitea", DisplayName: "Gitea", Image: "/img/auth/gitea.png", + CustomURLMapping: &oauth2.CustomURLMapping{ + TokenURL: oauth2.GetDefaultTokenURL("gitea"), + AuthURL: oauth2.GetDefaultAuthURL("gitea"), + ProfileURL: oauth2.GetDefaultProfileURL("gitea"), + }, + }, } // OAuth2DefaultCustomURLMappings contains the map of default URL's for OAuth2 providers that are allowed to have custom urls @@ -52,6 +59,7 @@ var OAuth2Providers = map[string]OAuth2Provider{ var OAuth2DefaultCustomURLMappings = map[string]*oauth2.CustomURLMapping{ "github": OAuth2Providers["github"].CustomURLMapping, "gitlab": OAuth2Providers["gitlab"].CustomURLMapping, + "gitea": OAuth2Providers["gitea"].CustomURLMapping, } // GetActiveOAuth2ProviderLoginSources returns all actived LoginOAuth2 sources diff --git a/modules/auth/oauth2/oauth2.go b/modules/auth/oauth2/oauth2.go index a2d7116211..de2efd0463 100644 --- a/modules/auth/oauth2/oauth2.go +++ b/modules/auth/oauth2/oauth2.go @@ -19,6 +19,7 @@ import ( "github.com/markbates/goth/providers/discord" "github.com/markbates/goth/providers/dropbox" "github.com/markbates/goth/providers/facebook" + "github.com/markbates/goth/providers/gitea" "github.com/markbates/goth/providers/github" "github.com/markbates/goth/providers/gitlab" "github.com/markbates/goth/providers/gplus" @@ -175,6 +176,22 @@ func createProvider(providerName, providerType, clientID, clientSecret, openIDCo provider = twitter.NewAuthenticate(clientID, clientSecret, callbackURL) case "discord": provider = discord.New(clientID, clientSecret, callbackURL, discord.ScopeIdentify, discord.ScopeEmail) + case "gitea": + authURL := gitea.AuthURL + tokenURL := gitea.TokenURL + profileURL := gitea.ProfileURL + if customURLMapping != nil { + if len(customURLMapping.AuthURL) > 0 { + authURL = customURLMapping.AuthURL + } + if len(customURLMapping.TokenURL) > 0 { + tokenURL = customURLMapping.TokenURL + } + if len(customURLMapping.ProfileURL) > 0 { + profileURL = customURLMapping.ProfileURL + } + } + provider = gitea.NewCustomisedURL(clientID, clientSecret, callbackURL, authURL, tokenURL, profileURL) } // always set the name if provider is created so we can support multiple setups of 1 provider @@ -192,6 +209,8 @@ func GetDefaultTokenURL(provider string) string { return github.TokenURL case "gitlab": return gitlab.TokenURL + case "gitea": + return gitea.TokenURL } return "" } @@ -203,6 +222,8 @@ func GetDefaultAuthURL(provider string) string { return github.AuthURL case "gitlab": return gitlab.AuthURL + case "gitea": + return gitea.AuthURL } return "" } @@ -214,6 +235,8 @@ func GetDefaultProfileURL(provider string) string { return github.ProfileURL case "gitlab": return gitlab.ProfileURL + case "gitea": + return gitea.ProfileURL } return "" } diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 36fabb5b4a..45e71e0595 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1706,6 +1706,7 @@ auths.tip.google_plus = Obtain OAuth2 client credentials from the Google API con auths.tip.openid_connect = Use the OpenID Connect Discovery URL (/.well-known/openid-configuration) to specify the endpoints auths.tip.twitter = Go to https://dev.twitter.com/apps, create an application and ensure that the “Allow this application to be used to Sign in with Twitter” option is enabled auths.tip.discord = Register a new application on https://discordapp.com/developers/applications/me +auths.tip.gitea = Register a new OAuth2 application. Guide can be found at https://docs.gitea.io/en-us/oauth2-provider/ auths.edit = Edit Authentication Source auths.activated = This Authentication Source is Activated auths.new_success = The authentication '%s' has been added. diff --git a/public/img/auth/gitea.png b/public/img/auth/gitea.png new file mode 100644 index 0000000000000000000000000000000000000000..30d331359463fb0d5e21f0faf9ea14a5f41e12e2 GIT binary patch literal 5576 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 K&t;ucLK6VNHo&a_ literal 0 HcmV?d00001 diff --git a/public/js/index.js b/public/js/index.js index 882f19e13d..d99457514b 100644 --- a/public/js/index.js +++ b/public/js/index.js @@ -1576,6 +1576,7 @@ function initAdmin() { switch (provider) { case 'github': case 'gitlab': + case 'gitea': $('.oauth2_use_custom_url').show(); break; case 'openidConnect': @@ -1609,6 +1610,7 @@ function initAdmin() { $('.oauth2_token_url input, .oauth2_auth_url input, .oauth2_profile_url input, .oauth2_email_url input').attr('required', 'required'); $('.oauth2_token_url, .oauth2_auth_url, .oauth2_profile_url, .oauth2_email_url').show(); break; + case 'gitea': case 'gitlab': $('.oauth2_token_url input, .oauth2_auth_url input, .oauth2_profile_url input').attr('required', 'required'); $('.oauth2_token_url, .oauth2_auth_url, .oauth2_profile_url').show(); diff --git a/templates/admin/auth/new.tmpl b/templates/admin/auth/new.tmpl index 91d3cde308..bf33dedd19 100644 --- a/templates/admin/auth/new.tmpl +++ b/templates/admin/auth/new.tmpl @@ -110,6 +110,8 @@ {{.i18n.Tr "admin.auths.tip.twitter"}}
  • Discord
  • {{.i18n.Tr "admin.auths.tip.discord"}} +
  • Gitea
  • + {{.i18n.Tr "admin.auths.tip.gitea"}} diff --git a/vendor/github.com/markbates/goth/.travis.yml b/vendor/github.com/markbates/goth/.travis.yml index 5b2f9fe132..7fd29cde8d 100644 --- a/vendor/github.com/markbates/goth/.travis.yml +++ b/vendor/github.com/markbates/goth/.travis.yml @@ -8,6 +8,7 @@ go: - 1.9 - "1.10" - "1.11" + - "1.12" - tip matrix: diff --git a/vendor/github.com/markbates/goth/README.md b/vendor/github.com/markbates/goth/README.md index c74f8773c6..a35746e4e1 100644 --- a/vendor/github.com/markbates/goth/README.md +++ b/vendor/github.com/markbates/goth/README.md @@ -31,6 +31,7 @@ $ go get github.com/markbates/goth * Eve Online * Facebook * Fitbit +* Gitea * GitHub * Gitlab * Google @@ -41,13 +42,17 @@ $ go get github.com/markbates/goth * Intercom * Lastfm * Linkedin +* LINE +* Mailru * Meetup * MicrosoftOnline * Naver +* Nextcloud * OneDrive * OpenID Connect (auto discovery) * Paypal * SalesForce +* Shopify * Slack * Soundcloud * Spotify diff --git a/vendor/github.com/markbates/goth/gothic/gothic.go b/vendor/github.com/markbates/goth/gothic/gothic.go index bea87d963d..ea4e1e0db8 100644 --- a/vendor/github.com/markbates/goth/gothic/gothic.go +++ b/vendor/github.com/markbates/goth/gothic/gothic.go @@ -245,19 +245,6 @@ var GetProviderName = getProviderName func getProviderName(req *http.Request) (string, error) { - // get all the used providers - providers := goth.GetProviders() - - // loop over the used providers, if we already have a valid session for any provider (ie. user is already logged-in with a provider), then return that provider name - for _, provider := range providers { - p := provider.Name() - session, _ := Store.Get(req, p+SessionName) - value := session.Values[p] - if _, ok := value.(string); ok { - return p, nil - } - } - // try to get it from the url param "provider" if p := req.URL.Query().Get("provider"); p != "" { return p, nil @@ -278,6 +265,17 @@ func getProviderName(req *http.Request) (string, error) { return p, nil } + // As a fallback, loop over the used providers, if we already have a valid session for any provider (ie. user has already begun authentication with a provider), then return that provider name + providers := goth.GetProviders() + session, _ := Store.Get(req, SessionName) + for _, provider := range providers { + p := provider.Name() + value := session.Values[p] + if _, ok := value.(string); ok { + return p, nil + } + } + // if not found then return an empty string with the corresponding error return "", errors.New("you must select a provider") } diff --git a/vendor/github.com/markbates/goth/providers/gitea/gitea.go b/vendor/github.com/markbates/goth/providers/gitea/gitea.go new file mode 100644 index 0000000000..44887720c5 --- /dev/null +++ b/vendor/github.com/markbates/goth/providers/gitea/gitea.go @@ -0,0 +1,186 @@ +// Package gitea implements the OAuth2 protocol for authenticating users through gitea. +// This package can be used as a reference implementation of an OAuth2 provider for Goth. +package gitea + +import ( + "bytes" + "encoding/json" + "io" + "io/ioutil" + "net/http" + "net/url" + "strconv" + + "fmt" + "github.com/markbates/goth" + "golang.org/x/oauth2" +) + +// These vars define the default Authentication, Token, and Profile URLS for Gitea. +// +// Examples: +// gitea.AuthURL = "https://gitea.acme.com/oauth/authorize +// gitea.TokenURL = "https://gitea.acme.com/oauth/token +// gitea.ProfileURL = "https://gitea.acme.com/api/v3/user +var ( + AuthURL = "https://gitea.com/login/oauth/authorize" + TokenURL = "https://gitea.com/login/oauth/access_token" + ProfileURL = "https://gitea.com/api/v1/user" +) + +// Provider is the implementation of `goth.Provider` for accessing Gitea. +type Provider struct { + ClientKey string + Secret string + CallbackURL string + HTTPClient *http.Client + config *oauth2.Config + providerName string + authURL string + tokenURL string + profileURL string +} + +// New creates a new Gitea provider and sets up important connection details. +// You should always call `gitea.New` to get a new provider. Never try to +// create one manually. +func New(clientKey, secret, callbackURL string, scopes ...string) *Provider { + return NewCustomisedURL(clientKey, secret, callbackURL, AuthURL, TokenURL, ProfileURL, scopes...) +} + +// NewCustomisedURL is similar to New(...) but can be used to set custom URLs to connect to +func NewCustomisedURL(clientKey, secret, callbackURL, authURL, tokenURL, profileURL string, scopes ...string) *Provider { + p := &Provider{ + ClientKey: clientKey, + Secret: secret, + CallbackURL: callbackURL, + providerName: "gitea", + profileURL: profileURL, + } + p.config = newConfig(p, authURL, tokenURL, scopes) + return p +} + +// Name is the name used to retrieve this provider later. +func (p *Provider) Name() string { + return p.providerName +} + +// SetName is to update the name of the provider (needed in case of multiple providers of 1 type) +func (p *Provider) SetName(name string) { + p.providerName = name +} + +func (p *Provider) Client() *http.Client { + return goth.HTTPClientWithFallBack(p.HTTPClient) +} + +// Debug is a no-op for the gitea package. +func (p *Provider) Debug(debug bool) {} + +// BeginAuth asks Gitea for an authentication end-point. +func (p *Provider) BeginAuth(state string) (goth.Session, error) { + return &Session{ + AuthURL: p.config.AuthCodeURL(state), + }, nil +} + +// FetchUser will go to Gitea and access basic information about the user. +func (p *Provider) FetchUser(session goth.Session) (goth.User, error) { + sess := session.(*Session) + user := goth.User{ + AccessToken: sess.AccessToken, + Provider: p.Name(), + RefreshToken: sess.RefreshToken, + ExpiresAt: sess.ExpiresAt, + } + + if user.AccessToken == "" { + // data is not yet retrieved since accessToken is still empty + return user, fmt.Errorf("%s cannot get user information without accessToken", p.providerName) + } + + response, err := p.Client().Get(p.profileURL + "?access_token=" + url.QueryEscape(sess.AccessToken)) + if err != nil { + if response != nil { + response.Body.Close() + } + return user, err + } + + defer response.Body.Close() + + if response.StatusCode != http.StatusOK { + return user, fmt.Errorf("%s responded with a %d trying to fetch user information", p.providerName, response.StatusCode) + } + + bits, err := ioutil.ReadAll(response.Body) + if err != nil { + return user, err + } + + err = json.NewDecoder(bytes.NewReader(bits)).Decode(&user.RawData) + if err != nil { + return user, err + } + + err = userFromReader(bytes.NewReader(bits), &user) + + return user, err +} + +func newConfig(provider *Provider, authURL, tokenURL string, scopes []string) *oauth2.Config { + c := &oauth2.Config{ + ClientID: provider.ClientKey, + ClientSecret: provider.Secret, + RedirectURL: provider.CallbackURL, + Endpoint: oauth2.Endpoint{ + AuthURL: authURL, + TokenURL: tokenURL, + }, + Scopes: []string{}, + } + + if len(scopes) > 0 { + for _, scope := range scopes { + c.Scopes = append(c.Scopes, scope) + } + } + return c +} + +func userFromReader(r io.Reader, user *goth.User) error { + u := struct { + Name string `json:"full_name"` + Email string `json:"email"` + NickName string `json:"login"` + ID int `json:"id"` + AvatarURL string `json:"avatar_url"` + }{} + err := json.NewDecoder(r).Decode(&u) + if err != nil { + return err + } + user.Email = u.Email + user.Name = u.Name + user.NickName = u.NickName + user.UserID = strconv.Itoa(u.ID) + user.AvatarURL = u.AvatarURL + return nil +} + +//RefreshTokenAvailable refresh token is provided by auth provider or not +func (p *Provider) RefreshTokenAvailable() bool { + return true +} + +//RefreshToken get new access token based on the refresh token +func (p *Provider) RefreshToken(refreshToken string) (*oauth2.Token, error) { + token := &oauth2.Token{RefreshToken: refreshToken} + ts := p.config.TokenSource(goth.ContextForClient(p.Client()), token) + newToken, err := ts.Token() + if err != nil { + return nil, err + } + return newToken, err +} diff --git a/vendor/github.com/markbates/goth/providers/gitea/session.go b/vendor/github.com/markbates/goth/providers/gitea/session.go new file mode 100644 index 0000000000..18c3fff7e1 --- /dev/null +++ b/vendor/github.com/markbates/goth/providers/gitea/session.go @@ -0,0 +1,63 @@ +package gitea + +import ( + "encoding/json" + "errors" + "strings" + "time" + + "github.com/markbates/goth" +) + +// Session stores data during the auth process with Gitea. +type Session struct { + AuthURL string + AccessToken string + RefreshToken string + ExpiresAt time.Time +} + +var _ goth.Session = &Session{} + +// GetAuthURL will return the URL set by calling the `BeginAuth` function on the Gitea provider. +func (s Session) GetAuthURL() (string, error) { + if s.AuthURL == "" { + return "", errors.New(goth.NoAuthUrlErrorMessage) + } + return s.AuthURL, nil +} + +// Authorize the session with Gitea and return the access token to be stored for future use. +func (s *Session) Authorize(provider goth.Provider, params goth.Params) (string, error) { + p := provider.(*Provider) + token, err := p.config.Exchange(goth.ContextForClient(p.Client()), params.Get("code")) + if err != nil { + return "", err + } + + if !token.Valid() { + return "", errors.New("Invalid token received from provider") + } + + s.AccessToken = token.AccessToken + s.RefreshToken = token.RefreshToken + s.ExpiresAt = token.Expiry + return token.AccessToken, err +} + +// Marshal the session into a string +func (s Session) Marshal() string { + b, _ := json.Marshal(s) + return string(b) +} + +func (s Session) String() string { + return s.Marshal() +} + +// UnmarshalSession wil unmarshal a JSON string into a session. +func (p *Provider) UnmarshalSession(data string) (goth.Session, error) { + s := &Session{} + err := json.NewDecoder(strings.NewReader(data)).Decode(s) + return s, err +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 7aa34911c8..c505448a41 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -303,13 +303,14 @@ github.com/magiconair/properties github.com/mailru/easyjson/buffer github.com/mailru/easyjson/jlexer github.com/mailru/easyjson/jwriter -# github.com/markbates/goth v1.49.0 +# github.com/markbates/goth v1.56.0 github.com/markbates/goth github.com/markbates/goth/gothic github.com/markbates/goth/providers/bitbucket github.com/markbates/goth/providers/discord github.com/markbates/goth/providers/dropbox github.com/markbates/goth/providers/facebook +github.com/markbates/goth/providers/gitea github.com/markbates/goth/providers/github github.com/markbates/goth/providers/gitlab github.com/markbates/goth/providers/gplus