mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2024-12-23 00:46:30 +00:00
Gitlab oauth login
This commit is contained in:
parent
44c5ca2b55
commit
f47ab27702
9 changed files with 120 additions and 52 deletions
|
@ -116,6 +116,8 @@ secret=""
|
|||
|
||||
[gitlab]
|
||||
url=""
|
||||
client=""
|
||||
secret=""
|
||||
skip_verify=false
|
||||
|
||||
[gogs]
|
||||
|
@ -178,6 +180,8 @@ export DRONE_BITBUCKET_SECRET=""
|
|||
|
||||
# gitlab configuration
|
||||
export DRONE_GITLAB_URL=""
|
||||
export DRONE_GITLAB_CLIENT=""
|
||||
export DRONE_GITLAB_SECRET=""
|
||||
export DRONE_GITLAB_SKIP_VERIFY=false
|
||||
|
||||
# email configuration
|
||||
|
|
|
@ -44,6 +44,8 @@ datasource="/var/lib/drone/drone.sqlite"
|
|||
|
||||
# [gitlab]
|
||||
# url=""
|
||||
# client=""
|
||||
# secret=""
|
||||
# skip_verify=false
|
||||
# open=false
|
||||
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
package gitlab
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
|
@ -14,34 +17,66 @@ type Gitlab struct {
|
|||
url string
|
||||
SkipVerify bool
|
||||
Open bool
|
||||
Client string
|
||||
Secret string
|
||||
}
|
||||
|
||||
func New(url string, skipVerify, open bool) *Gitlab {
|
||||
func New(url string, skipVerify, open bool, client, secret string) *Gitlab {
|
||||
return &Gitlab{
|
||||
url: url,
|
||||
SkipVerify: skipVerify,
|
||||
Open: open,
|
||||
Client: client,
|
||||
Secret: secret,
|
||||
}
|
||||
}
|
||||
|
||||
// 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 username = req.FormValue("username")
|
||||
var password = req.FormValue("password")
|
||||
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()),
|
||||
}
|
||||
|
||||
var client = NewClient(r.url, "", r.SkipVerify)
|
||||
var session, err = client.GetSession(username, password)
|
||||
var code = req.FormValue("code")
|
||||
var state = req.FormValue("state")
|
||||
|
||||
if len(code) == 0 {
|
||||
var random = GetRandom()
|
||||
httputil.SetCookie(res, req, "gitlab_state", random)
|
||||
http.Redirect(res, req, config.AuthCodeURL(random), http.StatusSeeOther)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
cookieState := httputil.GetCookie(req, "gitlab_state")
|
||||
httputil.DelCookie(res, req, "gitlab_state")
|
||||
if cookieState != state {
|
||||
return nil, fmt.Errorf("Error matching state in OAuth2 redirect")
|
||||
}
|
||||
|
||||
var trans = &oauth.Transport{Config: config}
|
||||
var token, err = trans.Exchange(code)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("Error exchanging token. %s", err)
|
||||
}
|
||||
|
||||
var client = NewClient(r.url, token.AccessToken, r.SkipVerify)
|
||||
|
||||
var user, errr = client.CurrentUser()
|
||||
if errr != nil {
|
||||
return nil, fmt.Errorf("Error retrieving current user. %s", errr)
|
||||
}
|
||||
|
||||
var login = new(model.Login)
|
||||
login.ID = int64(session.Id)
|
||||
login.Access = session.PrivateToken
|
||||
login.Login = session.UserName
|
||||
login.Name = session.Name
|
||||
login.Email = session.Email
|
||||
login.ID = int64(user.Id)
|
||||
login.Access = token.AccessToken
|
||||
login.Login = user.Username
|
||||
login.Email = user.Email
|
||||
return login, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
package gitlab
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/drone/drone/plugin/remote/gitlab/testdata"
|
||||
|
@ -14,7 +16,7 @@ func Test_Github(t *testing.T) {
|
|||
var server = testdata.NewServer()
|
||||
defer server.Close()
|
||||
|
||||
var gitlab = New(server.URL, false, false)
|
||||
var gitlab = New(server.URL, false, false, "", "")
|
||||
var user = model.User{
|
||||
Access: "e3b0c44298fc1c149afbf4c8996fb",
|
||||
}
|
||||
|
@ -31,17 +33,6 @@ func Test_Github(t *testing.T) {
|
|||
g := goblin.Goblin(t)
|
||||
g.Describe("Gitlab Plugin", func() {
|
||||
|
||||
g.It("Should authorize user", func() {
|
||||
var req, _ = http.NewRequest("GET", "/login/gitlab", nil)
|
||||
var login, err = gitlab.Authorize(nil, req)
|
||||
g.Assert(err == nil).IsTrue()
|
||||
g.Assert(login.Email).Equal("john@example.com")
|
||||
g.Assert(login.Name).Equal("John Smith")
|
||||
g.Assert(login.Login).Equal("john_smith")
|
||||
g.Assert(login.Access).Equal("dd34asd13as")
|
||||
g.Assert(login.ID).Equal(int64(1))
|
||||
})
|
||||
|
||||
g.It("Should get the repo list", func() {
|
||||
var repos, err = gitlab.GetRepos(&user)
|
||||
g.Assert(err == nil).IsTrue()
|
||||
|
@ -55,6 +46,23 @@ func Test_Github(t *testing.T) {
|
|||
g.Assert(repos[0].Role.Read).Equal(true)
|
||||
g.Assert(repos[0].Role.Write).Equal(true)
|
||||
})
|
||||
|
||||
g.Describe("Authorize", func() {
|
||||
var resp = httptest.NewRecorder()
|
||||
var state = "validstate"
|
||||
var req, _ = http.NewRequest(
|
||||
"GET",
|
||||
fmt.Sprintf("%s/?code=sekret&state=%s", server.URL, state),
|
||||
nil,
|
||||
)
|
||||
req.AddCookie(&http.Cookie{Name: "gitlab_state", Value: state})
|
||||
|
||||
g.It("Should authorize a valid user", func() {
|
||||
var login, err = gitlab.Authorize(resp, req)
|
||||
g.Assert(err == nil).IsTrue()
|
||||
g.Assert(login == nil).IsFalse()
|
||||
})
|
||||
})
|
||||
/*
|
||||
g.It("Should get the build script", func() {
|
||||
var script, err = github.GetScript(&user, &repo, &commit)
|
||||
|
|
|
@ -1,16 +1,20 @@
|
|||
package gitlab
|
||||
|
||||
import (
|
||||
"encoding/base32"
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
"github.com/Bugagazavr/go-gitlab-client"
|
||||
"github.com/gorilla/securecookie"
|
||||
)
|
||||
|
||||
// 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 {
|
||||
return gogitlab.NewGitlabCert(uri, "/api/v3", token, skipVerify)
|
||||
client := gogitlab.NewGitlabCert(uri, "/api/v3", token, skipVerify)
|
||||
client.Bearer = true
|
||||
return client
|
||||
}
|
||||
|
||||
// IsRead is a helper function that returns true if the
|
||||
|
@ -76,3 +80,9 @@ func GetKeyTitle(rawurl string) (string, error) {
|
|||
func ns(owner, name string) string {
|
||||
return fmt.Sprintf("%s%%2F%s", owner, name)
|
||||
}
|
||||
|
||||
// GetRandom is a helper function that generates a 32-bit random
|
||||
// key, base32 encoded as a string value.
|
||||
func GetRandom() string {
|
||||
return base32.StdEncoding.EncodeToString(securecookie.GenerateRandomKey(32))
|
||||
}
|
||||
|
|
|
@ -9,6 +9,9 @@ var (
|
|||
gitlabURL = config.String("gitlab-url", "")
|
||||
gitlabSkipVerify = config.Bool("gitlab-skip-verify", false)
|
||||
gitlabOpen = config.Bool("gitlab-open", false)
|
||||
|
||||
gitlabClient = config.String("gitlab-client", "")
|
||||
gitlabSecret = config.String("gitlab-secret", "")
|
||||
)
|
||||
|
||||
// Registers the Gitlab plugin using the default
|
||||
|
@ -23,6 +26,8 @@ func Register() {
|
|||
*gitlabURL,
|
||||
*gitlabSkipVerify,
|
||||
*gitlabOpen,
|
||||
*gitlabClient,
|
||||
*gitlabSecret,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
31
plugin/remote/gitlab/testdata/testdata.go
vendored
31
plugin/remote/gitlab/testdata/testdata.go
vendored
|
@ -27,6 +27,12 @@ func NewServer() *httptest.Server {
|
|||
case "/api/v3/session":
|
||||
w.Write(sessionPayload)
|
||||
return
|
||||
case "/oauth/token":
|
||||
w.Write(accessTokenPayload)
|
||||
return
|
||||
case "/api/v3/user":
|
||||
w.Write(currentUserPayload)
|
||||
return
|
||||
}
|
||||
|
||||
// else return a 404
|
||||
|
@ -231,3 +237,28 @@ var droneYamlPayload = []byte(`
|
|||
"content": "aW1hZ2U6IGdv"
|
||||
}
|
||||
`)
|
||||
|
||||
var accessTokenPayload = []byte(`access_token=sekret&scope=api&token_type=bearer`)
|
||||
|
||||
var currentUserPayload = []byte(`
|
||||
{
|
||||
"id": 1,
|
||||
"username": "john_smith",
|
||||
"email": "john@example.com",
|
||||
"name": "John Smith",
|
||||
"private_token": "dd34asd13as",
|
||||
"state": "active",
|
||||
"created_at": "2012-05-23T08:00:58Z",
|
||||
"bio": null,
|
||||
"skype": "",
|
||||
"linkedin": "",
|
||||
"twitter": "",
|
||||
"website_url": "",
|
||||
"theme_id": 1,
|
||||
"color_scheme_id": 2,
|
||||
"is_admin": false,
|
||||
"can_create_group": true,
|
||||
"can_create_project": true,
|
||||
"projects_limit": 100
|
||||
}
|
||||
`)
|
||||
|
|
|
@ -11,10 +11,7 @@ minor modifications to the style that only apply to this view
|
|||
<article id="loginpage">
|
||||
<div class="pure-g">
|
||||
<div class="pure-u-1" ng-if="state == 1 && remotes.length != 0" ng-repeat="remote in remotes">
|
||||
<a ng-href="/api/auth/{{ remote.type }}" target="_self" ng-if="remote.type != 'gitlab.com' && remote.type != 'gogs' ">
|
||||
<i class="fa {{ remote.type | remoteIcon }}"></i> {{ remote.type | remoteName }}
|
||||
</a>
|
||||
<a ng-href="/gitlab" ng-if="remote.type == 'gitlab.com' ">
|
||||
<a ng-href="/api/auth/{{ remote.type }}" target="_self" ng-if="remote.type != 'gogs' ">
|
||||
<i class="fa {{ remote.type | remoteIcon }}"></i> {{ remote.type | remoteName }}
|
||||
</a>
|
||||
<a ng-href="/gogs" ng-if="remote.type == 'gogs' ">
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
<!--
|
||||
minor modifications to the style that only apply to this view
|
||||
-->
|
||||
<style>
|
||||
#container { padding-top: 155px; }
|
||||
#header { height: 150px; }
|
||||
#header .user { display:none; }
|
||||
#header .brand { margin-top:55px ; }
|
||||
</style>
|
||||
|
||||
<article id="loginpage">
|
||||
<form class="pure-g" method="POST" action="/api/auth/gitlab.com">
|
||||
<div class="pure-u-1">
|
||||
<input type="text" name="username" placeholder="Email Address" />
|
||||
</div>
|
||||
<div class="pure-u-1">
|
||||
<input type="password" name="password" placeholder="Password" />
|
||||
</div>
|
||||
|
||||
<div class="pure-u-1">
|
||||
<input type="submit" value="Gitlab Login" />
|
||||
</div>
|
||||
</form>
|
||||
</article>
|
Loading…
Reference in a new issue