token expires

This commit is contained in:
Wenkai Yin 2016-04-29 14:59:00 +08:00
parent fbe341bf5d
commit 545ca4135c
5 changed files with 58 additions and 27 deletions

View File

@ -108,7 +108,7 @@ func FilterAccess(username string, authenticated bool, a *token.ResourceActions)
} }
// GenTokenForUI is for the UI process to call, so it won't establish a https connection from UI to proxy. // GenTokenForUI is for the UI process to call, so it won't establish a https connection from UI to proxy.
func GenTokenForUI(username string, service string, scopes []string) (string, error) { func GenTokenForUI(username string, service string, scopes []string) (token string, expiresIn int, issuedAt *time.Time, err error) {
access := GetResourceActions(scopes) access := GetResourceActions(scopes)
for _, a := range access { for _, a := range access {
FilterAccess(username, true, a) FilterAccess(username, true, a)
@ -117,22 +117,22 @@ func GenTokenForUI(username string, service string, scopes []string) (string, er
} }
// MakeToken makes a valid jwt token based on parms. // MakeToken makes a valid jwt token based on parms.
func MakeToken(username, service string, access []*token.ResourceActions) (string, error) { func MakeToken(username, service string, access []*token.ResourceActions) (token string, expiresIn int, issuedAt *time.Time, err error) {
pk, err := libtrust.LoadKeyFile(privateKey) pk, err := libtrust.LoadKeyFile(privateKey)
if err != nil { if err != nil {
return "", err return "", 0, nil, err
} }
tk, err := makeTokenCore(issuer, username, service, expiration, access, pk) tk, expiresIn, issuedAt, err := makeTokenCore(issuer, username, service, expiration, access, pk)
if err != nil { if err != nil {
return "", err return "", 0, nil, err
} }
rs := fmt.Sprintf("%s.%s", tk.Raw, base64UrlEncode(tk.Signature)) rs := fmt.Sprintf("%s.%s", tk.Raw, base64UrlEncode(tk.Signature))
return rs, nil return rs, expiresIn, issuedAt, nil
} }
//make token core //make token core
func makeTokenCore(issuer, subject, audience string, expiration int, func makeTokenCore(issuer, subject, audience string, expiration int,
access []*token.ResourceActions, signingKey libtrust.PrivateKey) (*token.Token, error) { access []*token.ResourceActions, signingKey libtrust.PrivateKey) (t *token.Token, expiresIn int, issuedAt *time.Time, err error) {
joseHeader := &token.Header{ joseHeader := &token.Header{
Type: "JWT", Type: "JWT",
@ -142,10 +142,12 @@ func makeTokenCore(issuer, subject, audience string, expiration int,
jwtID, err := randString(16) jwtID, err := randString(16)
if err != nil { if err != nil {
return nil, fmt.Errorf("Error to generate jwt id: %s", err) return nil, 0, nil, fmt.Errorf("Error to generate jwt id: %s", err)
} }
now := time.Now() now := time.Now().UTC()
issuedAt = &now
expiresIn = expiration * 60
claimSet := &token.ClaimSet{ claimSet := &token.ClaimSet{
Issuer: issuer, Issuer: issuer,
@ -161,10 +163,10 @@ func makeTokenCore(issuer, subject, audience string, expiration int,
var joseHeaderBytes, claimSetBytes []byte var joseHeaderBytes, claimSetBytes []byte
if joseHeaderBytes, err = json.Marshal(joseHeader); err != nil { if joseHeaderBytes, err = json.Marshal(joseHeader); err != nil {
return nil, fmt.Errorf("unable to marshal jose header: %s", err) return nil, 0, nil, fmt.Errorf("unable to marshal jose header: %s", err)
} }
if claimSetBytes, err = json.Marshal(claimSet); err != nil { if claimSetBytes, err = json.Marshal(claimSet); err != nil {
return nil, fmt.Errorf("unable to marshal claim set: %s", err) return nil, 0, nil, fmt.Errorf("unable to marshal claim set: %s", err)
} }
encodedJoseHeader := base64UrlEncode(joseHeaderBytes) encodedJoseHeader := base64UrlEncode(joseHeaderBytes)
@ -173,12 +175,13 @@ func makeTokenCore(issuer, subject, audience string, expiration int,
var signatureBytes []byte var signatureBytes []byte
if signatureBytes, _, err = signingKey.Sign(strings.NewReader(payload), crypto.SHA256); err != nil { if signatureBytes, _, err = signingKey.Sign(strings.NewReader(payload), crypto.SHA256); err != nil {
return nil, fmt.Errorf("unable to sign jwt payload: %s", err) return nil, 0, nil, fmt.Errorf("unable to sign jwt payload: %s", err)
} }
signature := base64UrlEncode(signatureBytes) signature := base64UrlEncode(signatureBytes)
tokenString := fmt.Sprintf("%s.%s", payload, signature) tokenString := fmt.Sprintf("%s.%s", payload, signature)
return token.NewToken(tokenString) t, err = token.NewToken(tokenString)
return
} }
func randString(length int) (string, error) { func randString(length int) (string, error) {

View File

@ -17,6 +17,7 @@ package token
import ( import (
"net/http" "net/http"
"time"
"github.com/vmware/harbor/auth" "github.com/vmware/harbor/auth"
"github.com/vmware/harbor/models" "github.com/vmware/harbor/models"
@ -59,14 +60,16 @@ func (h *Handler) Get() {
func (h *Handler) serveToken(username, service string, access []*token.ResourceActions) { func (h *Handler) serveToken(username, service string, access []*token.ResourceActions) {
writer := h.Ctx.ResponseWriter writer := h.Ctx.ResponseWriter
//create token //create token
rawToken, err := MakeToken(username, service, access) rawToken, expiresIn, issuedAt, err := MakeToken(username, service, access)
if err != nil { if err != nil {
log.Errorf("Failed to make token, error: %v", err) log.Errorf("Failed to make token, error: %v", err)
writer.WriteHeader(http.StatusInternalServerError) writer.WriteHeader(http.StatusInternalServerError)
return return
} }
tk := make(map[string]string) tk := make(map[string]interface{})
tk["token"] = rawToken tk["token"] = rawToken
tk["expires_in"] = expiresIn
tk["issued_at"] = issuedAt.Format(time.RFC3339)
h.Data["json"] = tk h.Data["json"] = tk
h.ServeJSON() h.ServeJSON()
} }

View File

@ -29,7 +29,8 @@ type Handler interface {
AuthorizeRequest(req *http.Request, params map[string]string) error AuthorizeRequest(req *http.Request, params map[string]string) error
} }
// RequestAuthorizer holds a handler list, which will authorize request // RequestAuthorizer holds a handler list, which will authorize request.
// Implements interface RequestModifier
type RequestAuthorizer struct { type RequestAuthorizer struct {
handlers []Handler handlers []Handler
challenges []au.Challenge challenges []au.Challenge

View File

@ -25,6 +25,7 @@ type Credential interface {
AddAuthorization(req *http.Request) AddAuthorization(req *http.Request)
} }
// Implements interface Credential
type basicAuthCredential struct { type basicAuthCredential struct {
username string username string
password string password string

View File

@ -21,6 +21,7 @@ import (
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"net/url" "net/url"
"strconv"
"strings" "strings"
"time" "time"
@ -41,6 +42,7 @@ func (s *scope) string() string {
type tokenGenerator func(realm, service string, scopes []string) (token string, expiresIn int, issuedAt *time.Time, err error) type tokenGenerator func(realm, service string, scopes []string) (token string, expiresIn int, issuedAt *time.Time, err error)
// Implements interface Handler
type tokenHandler struct { type tokenHandler struct {
scope *scope scope *scope
tg tokenGenerator tg tokenGenerator
@ -92,6 +94,7 @@ func (t *tokenHandler) AuthorizeRequest(req *http.Request, params map[string]str
return nil return nil
} }
// Implements interface Handler
type standardTokenHandler struct { type standardTokenHandler struct {
tokenHandler tokenHandler
client *http.Client client *http.Client
@ -119,10 +122,10 @@ func NewStandardTokenHandler(credential Credential, scopeType, scopeName string,
return handler return handler
} }
func (s *standardTokenHandler) generateToken(realm, service string, scopes []string) (string, int, *time.Time, error) { func (s *standardTokenHandler) generateToken(realm, service string, scopes []string) (token string, expiresIn int, issuedAt *time.Time, err error) {
u, err := url.Parse(realm) u, err := url.Parse(realm)
if err != nil { if err != nil {
return "", 0, nil, err return
} }
q := u.Query() q := u.Query()
q.Add("service", service) q.Add("service", service)
@ -132,41 +135,61 @@ func (s *standardTokenHandler) generateToken(realm, service string, scopes []str
u.RawQuery = q.Encode() u.RawQuery = q.Encode()
r, err := http.NewRequest("GET", u.String(), nil) r, err := http.NewRequest("GET", u.String(), nil)
if err != nil { if err != nil {
return "", 0, nil, err return
} }
s.credential.AddAuthorization(r) s.credential.AddAuthorization(r)
resp, err := s.client.Do(r) resp, err := s.client.Do(r)
if err != nil { if err != nil {
return "", 0, nil, err return
} }
defer resp.Body.Close() defer resp.Body.Close()
b, err := ioutil.ReadAll(resp.Body) b, err := ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
return "", 0, nil, err return
} }
if resp.StatusCode != http.StatusOK { if resp.StatusCode != http.StatusOK {
return "", 0, nil, registry_errors.Error{ err = registry_errors.Error{
StatusCode: resp.StatusCode, StatusCode: resp.StatusCode,
Message: string(b), Message: string(b),
} }
return
} }
// TODO
tk := struct { tk := struct {
Token string `json:"token"` Token string `json:"token"`
ExpiresIn string `json:"expires_in"`
IssuedAt string `json:"issued_at"`
}{} }{}
if err = json.Unmarshal(b, &tk); err != nil { if err = json.Unmarshal(b, &tk); err != nil {
return "", 0, nil, err return
}
token = tk.Token
expiresIn, err = strconv.Atoi(tk.ExpiresIn)
if err != nil {
expiresIn = 0
log.Errorf("error occurred while converting expires_in: %v", err)
err = nil
} else {
t, err := time.Parse(time.RFC3339, tk.IssuedAt)
if err != nil {
log.Errorf("error occurred while parsing issued_at: %v", err)
err = nil
} else {
issuedAt = &t
}
} }
log.Debug("get token from token server") log.Debug("get token from token server")
return tk.Token, 0, nil, nil return
} }
// Implements interface Handler
type usernameTokenHandler struct { type usernameTokenHandler struct {
tokenHandler tokenHandler
username string username string
@ -192,7 +215,7 @@ func NewUsernameTokenHandler(username string, scopeType, scopeName string, scope
func (u *usernameTokenHandler) generateToken(realm, service string, scopes []string) (token string, expiresIn int, issuedAt *time.Time, err error) { func (u *usernameTokenHandler) generateToken(realm, service string, scopes []string) (token string, expiresIn int, issuedAt *time.Time, err error) {
// TODO // TODO
token, err = token_util.GenTokenForUI(u.username, service, scopes) token, expiresIn, issuedAt, err = token_util.GenTokenForUI(u.username, service, scopes)
log.Debug("get token by calling GenTokenForUI directly") log.Debug("get token by calling GenTokenForUI directly")
return return
} }