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
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
|
|
}
|