diff --git a/plugin/remote/bitbucket/bitbucket.go b/plugin/remote/bitbucket/bitbucket.go index c049384a4..8220c9e5b 100644 --- a/plugin/remote/bitbucket/bitbucket.go +++ b/plugin/remote/bitbucket/bitbucket.go @@ -275,3 +275,7 @@ func (r *Bitbucket) ParseHook(req *http.Request) (*model.Hook, error) { func (r *Bitbucket) OpenRegistration() bool { return r.Open } + +func (r *Bitbucket) GetToken(user *model.User) (*model.Token, error) { + return nil, nil +} diff --git a/plugin/remote/github/github.go b/plugin/remote/github/github.go index 3919cae66..6c5bac7a7 100644 --- a/plugin/remote/github/github.go +++ b/plugin/remote/github/github.go @@ -311,3 +311,7 @@ func (r *GitHub) ParsePullRequestHook(req *http.Request) (*model.Hook, error) { func (r *GitHub) OpenRegistration() bool { return r.Open } + +func (r *GitHub) GetToken(user *model.User) (*model.Token, error) { + return nil, nil +} diff --git a/plugin/remote/gitlab/gitlab.go b/plugin/remote/gitlab/gitlab.go index ea1dce516..23a15d433 100644 --- a/plugin/remote/gitlab/gitlab.go +++ b/plugin/remote/gitlab/gitlab.go @@ -6,9 +6,10 @@ import ( "net/http" "net/url" "strconv" + "time" + "code.google.com/p/goauth2/oauth" "github.com/Bugagazavr/go-gitlab-client" - "github.com/drone/drone/plugin/remote/github/oauth" "github.com/drone/drone/shared/httputil" "github.com/drone/drone/shared/model" ) @@ -34,14 +35,8 @@ func New(url string, skipVerify, open bool, client, secret string) *Gitlab { // Authorize handles authentication with thrid party remote systems, // such as github or bitbucket, and returns user data. func (r *Gitlab) Authorize(res http.ResponseWriter, req *http.Request) (*model.Login, error) { - var config = &oauth.Config{ - ClientId: r.Client, - ClientSecret: r.Secret, - Scope: "api", - AuthURL: fmt.Sprintf("%s/oauth/authorize", r.url), - TokenURL: fmt.Sprintf("%s/oauth/token", r.url), - RedirectURL: fmt.Sprintf("%s/api/auth/%s", httputil.GetURL(req), r.GetKind()), - } + host := httputil.GetURL(req) + config := NewOauthConfig(r, host) var code = req.FormValue("code") var state = req.FormValue("state") @@ -75,6 +70,7 @@ func (r *Gitlab) Authorize(res http.ResponseWriter, req *http.Request) (*model.L var login = new(model.Login) login.ID = int64(user.Id) login.Access = token.AccessToken + login.Secret = token.RefreshToken login.Login = user.Username login.Email = user.Email return login, nil @@ -232,3 +228,24 @@ func (r *Gitlab) ParseHook(req *http.Request) (*model.Hook, error) { func (r *Gitlab) OpenRegistration() bool { return r.Open } + +func (r *Gitlab) GetToken(user *model.User) (*model.Token, error) { + expiry := time.Now().Truncate(7200 * time.Second) + t := &oauth.Transport{ + Config: NewOauthConfig(r, ""), + Token: &oauth.Token{ + AccessToken: user.Access, + RefreshToken: user.Secret, + Expiry: expiry, + }, + } + + if err := t.Refresh(); err != nil { + return nil, err + } + + var token = new(model.Token) + token.AccessToken = t.Token.AccessToken + token.RefreshToken = t.Token.RefreshToken + return token, nil +} diff --git a/plugin/remote/gitlab/helper.go b/plugin/remote/gitlab/helper.go index 02ba00cfe..8e67a5d9d 100644 --- a/plugin/remote/gitlab/helper.go +++ b/plugin/remote/gitlab/helper.go @@ -5,14 +5,26 @@ import ( "fmt" "net/url" + "code.google.com/p/goauth2/oauth" "github.com/Bugagazavr/go-gitlab-client" "github.com/gorilla/securecookie" ) +func NewOauthConfig(g *Gitlab, host string) *oauth.Config { + return &oauth.Config{ + ClientId: g.Client, + ClientSecret: g.Secret, + Scope: "api", + AuthURL: fmt.Sprintf("%s/oauth/authorize", g.url), + TokenURL: fmt.Sprintf("%s/oauth/token", g.url), + RedirectURL: fmt.Sprintf("%s/api/auth/%s", host, g.GetKind()), + } +} + // NewClient is a helper function that returns a new GitHub // client using the provided OAuth token. -func NewClient(uri, token string, skipVerify bool) *gogitlab.Gitlab { - client := gogitlab.NewGitlabCert(uri, "/api/v3", token, skipVerify) +func NewClient(url, accessToken string, skipVerify bool) *gogitlab.Gitlab { + client := gogitlab.NewGitlabCert(url, "/api/v3", accessToken, skipVerify) client.Bearer = true return client } diff --git a/plugin/remote/gogs/gogs.go b/plugin/remote/gogs/gogs.go index c1ee50f7c..edc71893d 100644 --- a/plugin/remote/gogs/gogs.go +++ b/plugin/remote/gogs/gogs.go @@ -186,3 +186,7 @@ func (r *Gogs) ParseHook(req *http.Request) (*model.Hook, error) { func (r *Gogs) OpenRegistration() bool { return r.Open } + +func (r *Gogs) GetToken(user *model.User) (*model.Token, error) { + return nil, nil +} diff --git a/plugin/remote/remote.go b/plugin/remote/remote.go index cfba0108e..0d7ad2dc4 100644 --- a/plugin/remote/remote.go +++ b/plugin/remote/remote.go @@ -35,6 +35,9 @@ type Remote interface { // Registration returns true if open registration is allowed OpenRegistration() bool + + // Get token + GetToken(*model.User) (*model.Token, error) } // List of registered plugins. diff --git a/server/handler/commit.go b/server/handler/commit.go index 14628c6f1..edd0b9fae 100644 --- a/server/handler/commit.go +++ b/server/handler/commit.go @@ -4,6 +4,7 @@ import ( "encoding/json" "net/http" + "github.com/drone/drone/plugin/remote" "github.com/drone/drone/server/datastore" "github.com/drone/drone/server/worker" "github.com/drone/drone/shared/httputil" @@ -65,7 +66,9 @@ func PostCommit(c web.C, w http.ResponseWriter, r *http.Request) { var ( branch = c.URLParams["branch"] hash = c.URLParams["commit"] + host = c.URLParams["host"] repo = ToRepo(c) + remote = remote.Lookup(host) ) commit, err := datastore.GetCommitSha(ctx, repo, branch, hash) @@ -95,6 +98,17 @@ func PostCommit(c web.C, w http.ResponseWriter, r *http.Request) { return } + // Request a new token and update + user_token, err := remote.GetToken(owner) + if user_token != nil { + owner.Access = user_token.AccessToken + owner.Secret = user_token.RefreshToken + datastore.PutUser(ctx, owner) + } else if err != nil { + w.WriteHeader(http.StatusBadRequest) + return + } + // drop the items on the queue go worker.Do(ctx, &worker.Work{ User: owner, diff --git a/server/handler/hook.go b/server/handler/hook.go index 66735fcef..e506deb3f 100644 --- a/server/handler/hook.go +++ b/server/handler/hook.go @@ -76,6 +76,17 @@ func PostHook(c web.C, w http.ResponseWriter, r *http.Request) { return } + // Request a new token and update + user_token, err := remote.GetToken(user) + if user_token != nil { + user.Access = user_token.AccessToken + user.Secret = user_token.RefreshToken + datastore.PutUser(ctx, user) + } else if err != nil { + w.WriteHeader(http.StatusBadRequest) + return + } + // featch the .drone.yml file from the database yml, err := remote.GetScript(user, repo, hook) if err != nil { diff --git a/server/handler/repo.go b/server/handler/repo.go index fc989e971..5b2048a50 100644 --- a/server/handler/repo.go +++ b/server/handler/repo.go @@ -104,6 +104,17 @@ func PostRepo(c web.C, w http.ResponseWriter, r *http.Request) { return } + // Request a new token and update + user_token, err := remote.GetToken(user) + if user_token != nil { + user.Access = user_token.AccessToken + user.Secret = user_token.RefreshToken + datastore.PutUser(ctx, user) + } else if err != nil { + w.WriteHeader(http.StatusBadRequest) + return + } + // setup the post-commit hook with the remote system and // if necessary, register the public key var hook = fmt.Sprintf("%s/api/hook/%s/%s", httputil.GetURL(r), repo.Remote, repo.Token) diff --git a/server/handler/user.go b/server/handler/user.go index 3de0833d5..6b21528ae 100644 --- a/server/handler/user.go +++ b/server/handler/user.go @@ -158,6 +158,16 @@ func PostUserSync(c web.C, w http.ResponseWriter, r *http.Request) { return } + // Request a new token and update + user_token, err := remote.GetToken(user) + if user_token != nil { + user.Access = user_token.AccessToken + user.Secret = user_token.RefreshToken + } else if err != nil { + w.WriteHeader(http.StatusNotFound) + return + } + user.Syncing = true if err := datastore.PutUser(ctx, user); err != nil { w.WriteHeader(http.StatusNotFound) diff --git a/shared/model/token.go b/shared/model/token.go new file mode 100644 index 000000000..5b18cac66 --- /dev/null +++ b/shared/model/token.go @@ -0,0 +1,11 @@ +package model + +import ( + "time" +) + +type Token struct { + AccessToken string + RefreshToken string + Expiry time.Time +}