mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2024-11-27 04:11:03 +00:00
initial work on tokens
This commit is contained in:
parent
0f60073adc
commit
66990a95b4
7 changed files with 52 additions and 50 deletions
|
@ -1,9 +1,16 @@
|
|||
package common
|
||||
|
||||
const (
|
||||
TokenUser = "u"
|
||||
TokenSess = "s"
|
||||
)
|
||||
|
||||
type Token struct {
|
||||
Sha string `json:"-"`
|
||||
Kind string `json:"-"`
|
||||
Login string `json:"-"`
|
||||
Label string `json:"label"`
|
||||
Repos []string `json:"repos,omitempty"`
|
||||
Scopes []string `json:"scopes,omitempty"`
|
||||
Expiry int64 `json:"expiry,omitempty"`
|
||||
Issued int64 `json:"issued_at,omitempty"`
|
||||
}
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
package bolt
|
||||
|
||||
import (
|
||||
"github.com/drone/drone/common"
|
||||
"github.com/boltdb/bolt"
|
||||
"github.com/drone/drone/common"
|
||||
)
|
||||
|
||||
// GetToken gets a token by sha value.
|
||||
func (db *DB) GetToken(sha string) (*common.Token, error) {
|
||||
func (db *DB) GetToken(user, label string) (*common.Token, error) {
|
||||
token := &common.Token{}
|
||||
key := []byte(sha)
|
||||
key := []byte(user + "/" + label)
|
||||
|
||||
err := db.View(func (t *bolt.Tx) error {
|
||||
err := db.View(func(t *bolt.Tx) error {
|
||||
return get(t, bucketTokens, key, token)
|
||||
})
|
||||
|
||||
|
@ -20,8 +20,8 @@ func (db *DB) GetToken(sha string) (*common.Token, error) {
|
|||
// InsertToken inserts a new user token in the datastore.
|
||||
// If the token already exists and error is returned.
|
||||
func (db *DB) InsertToken(token *common.Token) error {
|
||||
key := []byte(token.Sha)
|
||||
return db.Update(func (t *bolt.Tx) error {
|
||||
key := []byte(token.Login + "/" + token.Label)
|
||||
return db.Update(func(t *bolt.Tx) error {
|
||||
return insert(t, bucketTokens, key, token)
|
||||
})
|
||||
// TODO(bradrydzewski) add token to users_token index
|
||||
|
@ -29,8 +29,8 @@ func (db *DB) InsertToken(token *common.Token) error {
|
|||
|
||||
// DeleteUser deletes the token.
|
||||
func (db *DB) DeleteToken(token *common.Token) error {
|
||||
key := []byte(token.Sha)
|
||||
return db.Update(func (t *bolt.Tx) error {
|
||||
key := []byte(token.Login + "/" + token.Label)
|
||||
return db.Update(func(t *bolt.Tx) error {
|
||||
return delete(t, bucketUser, key)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ type Datastore interface {
|
|||
DeleteUser(*common.User) error
|
||||
|
||||
// GetToken gets a token by sha value.
|
||||
GetToken(string) (*common.Token, error)
|
||||
GetToken(string, string) (*common.Token, error)
|
||||
|
||||
// InsertToken inserts a new user token in the datastore.
|
||||
// If the token already exists and error is returned.
|
||||
|
|
|
@ -3,6 +3,7 @@ package server
|
|||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
|
@ -106,8 +107,9 @@ func GetLogin(c *gin.Context) {
|
|||
}
|
||||
|
||||
token := &common.Token{
|
||||
// Expiry: settings.Session.Expires, // TODO add this
|
||||
Login: u.Login,
|
||||
Kind: common.TokenSess,
|
||||
Login: u.Login,
|
||||
Issued: time.Now().UTC().Unix(),
|
||||
}
|
||||
tokenstr, err := session.GenerateToken(c.Request, token)
|
||||
if err != nil {
|
||||
|
|
|
@ -118,6 +118,24 @@ func SetUser(s session.Session) gin.HandlerFunc {
|
|||
if err == nil {
|
||||
c.Set("user", u)
|
||||
}
|
||||
|
||||
// if session token we can proceed, otherwise
|
||||
// we should validate the token hasn't been revoked
|
||||
if token.Kind == common.TokenSess {
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
|
||||
// to verify the token we fetch from the datastore
|
||||
// and check to see if the token issued date matches
|
||||
// what we found in the jwt (in case the label is re-used)
|
||||
t, err := ds.GetToken(token.Login, token.Label)
|
||||
if err != nil || t.Issued != token.Issued {
|
||||
c.AbortWithStatus(403)
|
||||
return
|
||||
}
|
||||
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -39,19 +39,10 @@ func New(s *settings.Session) Session {
|
|||
// facilitate client-based OAuth2.
|
||||
func (s *session) GenerateToken(r *http.Request, t *common.Token) (string, error) {
|
||||
token := jwt.New(jwt.GetSigningMethod("HS256"))
|
||||
token.Claims["login"] = t.Login
|
||||
token.Claims["expiry"] = t.Expiry
|
||||
|
||||
// add optional repos that can be
|
||||
// access from this session.
|
||||
if len(t.Repos) != 0 {
|
||||
token.Claims["repos"] = t.Repos
|
||||
}
|
||||
// add optional scopes that can be
|
||||
// applied to this session.
|
||||
if len(t.Scopes) != 0 {
|
||||
token.Claims["scope"] = t.Scopes
|
||||
}
|
||||
token.Claims["user"] = t.Login
|
||||
token.Claims["kind"] = t.Kind
|
||||
token.Claims["date"] = t.Issued
|
||||
token.Claims["label"] = t.Label
|
||||
return token.SignedString(s.secret)
|
||||
}
|
||||
|
||||
|
@ -65,21 +56,16 @@ func (s *session) GetLogin(r *http.Request) *common.Token {
|
|||
}
|
||||
|
||||
claims := getClaims(t, s.secret)
|
||||
if claims == nil || claims["login"] == nil {
|
||||
if claims == nil || claims["user"] == nil || claims["date"] == nil || claims["label"] == nil || claims["kind"] == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
loginv, ok := claims["login"]
|
||||
if !ok {
|
||||
return nil
|
||||
return &common.Token{
|
||||
Kind: claims["kind"].(string),
|
||||
Login: claims["user"].(string),
|
||||
Label: claims["label"].(string),
|
||||
Issued: int64(claims["date"].(float64)),
|
||||
}
|
||||
|
||||
loginstr, ok := loginv.(string)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &common.Token{Login: loginstr}
|
||||
}
|
||||
|
||||
// getToken is a helper function that extracts the token
|
||||
|
|
|
@ -13,12 +13,12 @@ func PostToken(c *gin.Context) {
|
|||
// 3. return the random password to the UI and instruct the user to copy it
|
||||
}
|
||||
|
||||
// DELETE /api/user/tokens/:sha
|
||||
// DELETE /api/user/tokens/:label
|
||||
func DelToken(c *gin.Context) {
|
||||
store := ToDatastore(c)
|
||||
user := ToUser(c)
|
||||
hash := c.Params.ByName("hash")
|
||||
token, err := store.GetToken(hash)
|
||||
label := c.Params.ByName("label")
|
||||
token, err := store.GetToken(user.Login, label)
|
||||
if err != nil {
|
||||
c.Fail(404, err)
|
||||
}
|
||||
|
@ -26,15 +26,4 @@ func DelToken(c *gin.Context) {
|
|||
if err != nil {
|
||||
c.Fail(400, err)
|
||||
}
|
||||
|
||||
// TODO(bradrydzewski) this should be encapsulated
|
||||
// in our database code, since this feels like a
|
||||
// database-specific implementation.
|
||||
delete(user.Tokens, token.Sha)
|
||||
err = store.UpdateUser(user)
|
||||
if err != nil {
|
||||
c.Fail(400, err)
|
||||
} else {
|
||||
c.Writer.WriteHeader(200)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue