2015-04-08 22:43:59 +00:00
|
|
|
package session
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"net/http"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/dgrijalva/jwt-go"
|
|
|
|
"github.com/drone/drone/common"
|
|
|
|
"github.com/drone/drone/settings"
|
|
|
|
"github.com/gorilla/securecookie"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Session interface {
|
2015-04-13 04:35:16 +00:00
|
|
|
GenerateToken(*http.Request, *common.Token) (string, error)
|
|
|
|
GetLogin(*http.Request) *common.Token
|
2015-04-08 22:43:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type session struct {
|
|
|
|
secret []byte
|
|
|
|
expire time.Duration
|
|
|
|
}
|
|
|
|
|
|
|
|
func New(s *settings.Session) Session {
|
2015-04-08 23:36:56 +00:00
|
|
|
// TODO (bradrydzewski) hook up the Session.Expires
|
2015-04-09 05:18:25 +00:00
|
|
|
secret := []byte(s.Secret)
|
2015-04-08 22:43:59 +00:00
|
|
|
expire := time.Hour * 72
|
2015-04-08 23:36:56 +00:00
|
|
|
if len(secret) == 0 {
|
|
|
|
securecookie.GenerateRandomKey(32)
|
|
|
|
}
|
2015-04-08 22:43:59 +00:00
|
|
|
return &session{
|
|
|
|
secret: secret,
|
|
|
|
expire: expire,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// GenerateToken generates a JWT token for the user session
|
|
|
|
// that can be appended to the #access_token segment to
|
|
|
|
// facilitate client-based OAuth2.
|
2015-04-13 04:35:16 +00:00
|
|
|
func (s *session) GenerateToken(r *http.Request, t *common.Token) (string, error) {
|
2015-04-08 22:43:59 +00:00
|
|
|
token := jwt.New(jwt.GetSigningMethod("HS256"))
|
2015-04-13 04:35:16 +00:00
|
|
|
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
|
|
|
|
}
|
2015-04-08 22:43:59 +00:00
|
|
|
return token.SignedString(s.secret)
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetLogin gets the currently authenticated user for the
|
|
|
|
// http.Request. The user details will be stored as either
|
|
|
|
// a simple API token or JWT bearer token.
|
2015-04-13 04:35:16 +00:00
|
|
|
func (s *session) GetLogin(r *http.Request) *common.Token {
|
|
|
|
t := getToken(r)
|
|
|
|
if len(t) == 0 {
|
|
|
|
return nil
|
2015-04-08 22:43:59 +00:00
|
|
|
}
|
|
|
|
|
2015-04-13 04:35:16 +00:00
|
|
|
claims := getClaims(t, s.secret)
|
|
|
|
if claims == nil || claims["login"] == nil {
|
|
|
|
return nil
|
2015-04-08 22:43:59 +00:00
|
|
|
}
|
|
|
|
|
2015-04-13 04:35:16 +00:00
|
|
|
loginv, ok := claims["login"]
|
2015-04-08 22:43:59 +00:00
|
|
|
if !ok {
|
2015-04-13 04:35:16 +00:00
|
|
|
return nil
|
2015-04-08 22:43:59 +00:00
|
|
|
}
|
|
|
|
|
2015-04-13 04:35:16 +00:00
|
|
|
loginstr, ok := loginv.(string)
|
|
|
|
if !ok {
|
|
|
|
return nil
|
|
|
|
}
|
2015-04-08 22:43:59 +00:00
|
|
|
|
2015-04-13 04:35:16 +00:00
|
|
|
return &common.Token{Login: loginstr}
|
2015-04-08 22:43:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// getToken is a helper function that extracts the token
|
|
|
|
// from the http.Request.
|
|
|
|
func getToken(r *http.Request) string {
|
|
|
|
token := getTokenHeader(r)
|
|
|
|
if len(token) == 0 {
|
|
|
|
token = getTokenParam(r)
|
|
|
|
}
|
|
|
|
return token
|
|
|
|
}
|
|
|
|
|
|
|
|
// getTokenHeader parses the JWT token value from
|
|
|
|
// the http Authorization header.
|
|
|
|
func getTokenHeader(r *http.Request) string {
|
|
|
|
var tokenstr = r.Header.Get("Authorization")
|
|
|
|
fmt.Sscanf(tokenstr, "Bearer %s", &tokenstr)
|
|
|
|
return tokenstr
|
|
|
|
}
|
|
|
|
|
|
|
|
// getTokenParam parses the JWT token value from
|
|
|
|
// the http Request's query parameter.
|
|
|
|
func getTokenParam(r *http.Request) string {
|
|
|
|
return r.FormValue("access_token")
|
|
|
|
}
|
|
|
|
|
|
|
|
// getClaims is a helper function that extracts the token
|
|
|
|
// claims from the JWT token string.
|
|
|
|
func getClaims(token string, secret []byte) map[string]interface{} {
|
|
|
|
t, err := jwt.Parse(token, func(t *jwt.Token) (interface{}, error) {
|
|
|
|
return secret, nil
|
|
|
|
})
|
|
|
|
if err != nil || !t.Valid {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return t.Claims
|
|
|
|
}
|