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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 U66G;JUimMkAPbYJk}?YXAHg=jtpET3 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