1
0
mirror of https://github.com/lfkeitel/docker-registry-auth.git synced 2025-04-19 00:24:02 +03:00

90 lines
2.0 KiB
Go

package dockerauth
import (
"crypto"
"crypto/rand"
"crypto/rsa"
"encoding/base64"
"encoding/json"
"fmt"
"time"
)
type jwtHeader struct {
Alg string `json:"alg"`
Typ string `json:"typ"`
Kid string `json:"kid"`
}
type jwtPayload struct {
Iss string `json:"iss"`
Aud string `json:"aud"`
Sub string `json:"sub"`
Nbf int64 `json:"nbf"`
Exp int64 `json:"exp"`
Iat int64 `json:"iat"`
Jti string `json:"jti"`
Access []*AccessControl `json:"access"`
}
func GenerateToken(username string, accessClaims []*AccessControl) (string, error) {
key, err := getPrivateKey()
if err != nil {
return "", err
}
now := time.Now()
header := &jwtHeader{
Alg: "RS256",
Typ: "JWT",
Kid: getRSAKeyID(key),
}
payload := &jwtPayload{
Iss: config.Registry.Auth.Issuer,
Aud: config.Registry.Name,
Sub: username,
Nbf: now.Add(-30 * time.Second).Unix(),
Exp: now.Add(time.Hour).Unix(),
Iat: now.Unix(),
Access: accessClaims,
}
uuid, err := generateUUID()
if err != nil {
return "", err
}
payload.Jti = uuid
headerEncoded := jsonEncodeJWTSection(header)
payloadEncoded := jsonEncodeJWTSection(payload)
signature, err := signJWT(headerEncoded, payloadEncoded, key)
if err != nil {
return "", err
}
signature = base64Encode(signature)
return fmt.Sprintf("%s.%s.%s", headerEncoded, payloadEncoded, signature), nil
}
func jsonEncodeJWTSection(i interface{}) []byte {
JSON, _ := json.Marshal(i)
return base64Encode(JSON)
}
func base64Encode(src []byte) []byte {
encoded := make([]byte, base64.RawURLEncoding.EncodedLen(len(src)))
base64.RawURLEncoding.Encode(encoded, src)
return encoded
}
func signJWT(header, payload []byte, key *rsa.PrivateKey) ([]byte, error) {
hasher := crypto.SHA256.New()
message := append(header, '.')
message = append(message, payload...)
hasher.Write(message)
sigBytes, err := rsa.SignPKCS1v15(rand.Reader, key, crypto.SHA256, hasher.Sum(nil))
return sigBytes, err
}