hooks are protected with signed sha

This commit is contained in:
Brad Rydzewski 2015-04-30 14:23:46 -07:00
parent 64cc684295
commit 6fcae7d80a
9 changed files with 59 additions and 21 deletions

View file

@ -1,8 +1,10 @@
package common
const (
TokenUser = "u"
TokenSess = "s"
TokenUser = "u"
TokenSess = "s"
TokenHook = "h"
TokenAgent = "a"
)
type Token struct {

View file

@ -64,6 +64,12 @@ func push(t *bolt.Tx, bucket, index, value []byte) error {
if err != nil && err != ErrKeyNotFound {
return err
}
// we shouldn't add a key that already exists
for _, key := range keys {
if bytes.Equal(key, value) {
return nil
}
}
keys = append(keys, value)
return update(t, bucket, index, &keys)
}

View file

@ -42,12 +42,12 @@ func main() {
api.Use(server.SetRemote(remote))
api.Use(server.SetQueue(queue.New()))
api.Use(server.SetSettings(settings))
api.Use(server.SetSession(session))
api.Use(server.SetUser(session))
user := api.Group("/user")
{
user.Use(server.MustUser())
user.Use(server.SetSession(session))
user.GET("", server.GetUserCurr)
user.PATCH("", server.PutUserCurr)

View file

@ -172,7 +172,7 @@ func GetHook(client *github.Client, owner, name, url string) (*github.Hook, erro
return nil, err
}
for _, hook := range hooks {
if hook.Config["url"] == url {
if strings.HasPrefix(hook.Config["url"].(string), url) {
return &hook, nil
}
}
@ -255,6 +255,9 @@ func DeleteKey(client *github.Client, owner, name, title string) error {
if err != nil {
return err
}
if k == nil {
return nil
}
_, err = client.Repositories.DeleteKey(owner, name, *k.ID)
return err
}

View file

@ -21,6 +21,7 @@ func PostHook(c *gin.Context) {
remote := ToRemote(c)
store := ToDatastore(c)
queue_ := ToQueue(c)
sess := ToSession(c)
hook, err := remote.Hook(c.Request)
if err != nil {
@ -38,6 +39,14 @@ func PostHook(c *gin.Context) {
return
}
// get the token and verify the hook is authorized
token := sess.GetLogin(c.Request)
if token == nil || token.Label != hook.Repo.FullName {
log.Errorf("invalid token sent with hook.")
c.AbortWithStatus(403)
return
}
// a build may be skipped if the text [CI SKIP]
// is found inside the commit message
if hook.Commit != nil && strings.Contains(hook.Commit.Message, "[CI SKIP]") {

View file

@ -166,15 +166,11 @@ func DeleteRepo(c *gin.Context) {
//
func PostRepo(c *gin.Context) {
user := ToUser(c)
sess := ToSession(c)
store := ToDatastore(c)
owner := c.Params.ByName("owner")
name := c.Params.ByName("name")
link := fmt.Sprintf(
"%s/api/hook",
httputil.GetURL(c.Request),
)
// TODO(bradrydzewski) verify repo not exists
// get the repository and user permissions
@ -194,6 +190,21 @@ func PostRepo(c *gin.Context) {
return
}
token := &common.Token{}
token.Kind = common.TokenHook
token.Label = r.FullName
tokenstr, err := sess.GenerateToken(token)
if err != nil {
c.Fail(500, err)
return
}
link := fmt.Sprintf(
"%s/api/hook?access_token=%s",
httputil.GetURL(c.Request),
tokenstr,
)
// set the repository owner to the
// currently authenticated user.
r.User = &common.Owner{Login: user.Login}

View file

@ -125,7 +125,7 @@ func SetUser(s session.Session) gin.HandlerFunc {
return func(c *gin.Context) {
ds := ToDatastore(c)
token := s.GetLogin(c.Request)
if token == nil {
if token == nil || len(token.Login) == 0 {
c.Next()
return
}
@ -137,7 +137,8 @@ func SetUser(s session.Session) gin.HandlerFunc {
// if session token we can proceed, otherwise
// we should validate the token hasn't been revoked
if token.Kind == common.TokenSess {
switch token.Kind {
case common.TokenSess:
c.Next()
return
}

View file

@ -8,7 +8,6 @@ import (
"github.com/dgrijalva/jwt-go"
"github.com/drone/drone/common"
"github.com/drone/drone/settings"
"github.com/gorilla/securecookie"
)
type Session interface {
@ -22,12 +21,8 @@ type session struct {
}
func New(s *settings.Session) Session {
// TODO (bradrydzewski) hook up the Session.Expires
secret := []byte(s.Secret)
expire := time.Hour * 72
if len(secret) == 0 {
securecookie.GenerateRandomKey(32)
}
return &session{
secret: secret,
expire: expire,

View file

@ -1,8 +1,6 @@
package settings
import (
"github.com/BurntSushi/toml"
)
import "github.com/BurntSushi/toml"
// Service represents the configuration details required
// to connect to the revision control system (ie GitHub, Bitbucket)
@ -108,7 +106,7 @@ type Settings struct {
func Parse(path string) (*Settings, error) {
s := &Settings{}
_, err := toml.DecodeFile(path, s)
return s, err
return applyDefaults(s), err
}
// ParseString parses the Drone settings string and unmarshals
@ -116,5 +114,18 @@ func Parse(path string) (*Settings, error) {
func ParseString(data string) (*Settings, error) {
s := &Settings{}
_, err := toml.Decode(data, s)
return s, err
return applyDefaults(s), err
}
func applyDefaults(s *Settings) *Settings {
if s.Session == nil {
s.Session = &Session{}
}
// if no session token is provided we can
// instead use the client secret to sign
// our sessions and tokens.
if len(s.Session.Secret) == 0 {
s.Session.Secret = s.Service.OAuth.Secret
}
return s
}