From 92de7591dae83f658d8937025a28451a5e1444d8 Mon Sep 17 00:00:00 2001 From: Simone Gotti Date: Thu, 9 May 2019 14:14:13 +0200 Subject: [PATCH] gitsources: implement gitea oauth2 auth As from https://github.com/go-gitea/gitea/pull/5378 gitea is an oauth2 provider. --- internal/gitsources/gitea/gitea.go | 59 +++++++++++++++++-- internal/services/gateway/common/gitsource.go | 10 +++- internal/services/types/types.go | 2 +- 3 files changed, 62 insertions(+), 9 deletions(-) diff --git a/internal/gitsources/gitea/gitea.go b/internal/gitsources/gitea/gitea.go index c6c46d3..356fcb0 100644 --- a/internal/gitsources/gitea/gitea.go +++ b/internal/gitsources/gitea/gitea.go @@ -15,6 +15,7 @@ package gitea import ( + "context" "crypto/tls" "fmt" "net" @@ -25,6 +26,7 @@ import ( "time" gitsource "github.com/sorintlab/agola/internal/gitsources" + "golang.org/x/oauth2" "code.gitea.io/sdk/gitea" "github.com/pkg/errors" @@ -37,14 +39,24 @@ const ( ClientNotFound = "404 Not Found" ) +var ( + // gitea corrently doesn't have any auth scope + GiteaOauth2Scopes = []string{""} +) + type Opts struct { - URL string - Token string - SkipVerify bool + URL string + Token string + SkipVerify bool + Oauth2ClientID string + Oauth2Secret string } type Client struct { - client *gitea.Client + client *gitea.Client + URL string + oauth2ClientID string + oauth2Secret string } // fromCommitStatus converts a gitsource commit status to a gitea commit status @@ -90,10 +102,47 @@ func New(opts Opts) (*Client, error) { client.SetHTTPClient(httpClient) return &Client{ - client: client, + client: client, + URL: opts.URL, + oauth2ClientID: opts.Oauth2ClientID, + oauth2Secret: opts.Oauth2Secret, }, nil } +func (c *Client) oauth2Config(callbackURL string) *oauth2.Config { + return &oauth2.Config{ + ClientID: c.oauth2ClientID, + ClientSecret: c.oauth2Secret, + Scopes: GiteaOauth2Scopes, + Endpoint: oauth2.Endpoint{ + AuthURL: fmt.Sprintf("%s/login/oauth/authorize", c.URL), + TokenURL: fmt.Sprintf("%s/login/oauth/access_token", c.URL), + }, + RedirectURL: callbackURL, + } +} + +func (c *Client) GetOauth2AuthorizationURL(callbackURL, state string) (string, error) { + var config = c.oauth2Config(callbackURL) + return config.AuthCodeURL(state), nil +} + +func (c *Client) RequestOauth2Token(callbackURL, code string) (*oauth2.Token, error) { + var config = c.oauth2Config(callbackURL) + token, err := config.Exchange(context.TODO(), code) + if err != nil { + return nil, errors.Wrapf(err, "cannot get oauth2 token") + } + return token, nil +} + +func (c *Client) RefreshOauth2Token(refreshToken string) (*oauth2.Token, error) { + var config = c.oauth2Config("") + token := &oauth2.Token{RefreshToken: refreshToken} + ts := config.TokenSource(context.TODO(), token) + return ts.Token() +} + func (c *Client) LoginPassword(username, password, tokenName string) (string, error) { // try to get agola access token if it already exists var accessToken string diff --git a/internal/services/gateway/common/gitsource.go b/internal/services/gateway/common/gitsource.go index 575f120..135571c 100644 --- a/internal/services/gateway/common/gitsource.go +++ b/internal/services/gateway/common/gitsource.go @@ -25,9 +25,11 @@ import ( func newGitea(rs *types.RemoteSource, accessToken string) (*gitea.Client, error) { return gitea.New(gitea.Opts{ - URL: rs.APIURL, - SkipVerify: rs.SkipVerify, - Token: accessToken, + URL: rs.APIURL, + SkipVerify: rs.SkipVerify, + Token: accessToken, + Oauth2ClientID: rs.Oauth2ClientID, + Oauth2Secret: rs.Oauth2ClientSecret, }) } @@ -95,6 +97,8 @@ func GetOauth2Source(rs *types.RemoteSource, accessToken string) (gitsource.Oaut var oauth2Source gitsource.Oauth2Source var err error switch rs.Type { + case types.RemoteSourceTypeGitea: + oauth2Source, err = newGitea(rs, accessToken) case types.RemoteSourceTypeGitlab: oauth2Source, err = newGitlab(rs, accessToken) default: diff --git a/internal/services/types/types.go b/internal/services/types/types.go index 2a979e9..898a97e 100644 --- a/internal/services/types/types.go +++ b/internal/services/types/types.go @@ -168,7 +168,7 @@ type RemoteSource struct { func SourceSupportedAuthTypes(rsType RemoteSourceType) []RemoteSourceAuthType { switch rsType { case RemoteSourceTypeGitea: - return []RemoteSourceAuthType{RemoteSourceAuthTypePassword} + return []RemoteSourceAuthType{RemoteSourceAuthTypeOauth2, RemoteSourceAuthTypePassword} case RemoteSourceTypeGithub: fallthrough case RemoteSourceTypeGitlab: