You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
cloudreve/pkg/auth/oidc.go

90 lines
2.1 KiB

package auth
import (
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"fmt"
"math/big"
"github.com/golang-jwt/jwt/v5"
)
type OIDCIDTokenClaims struct {
jwt.RegisteredClaims
Nonce string `json:"nonce,omitempty"`
Name string `json:"name,omitempty"`
PreferredUsername string `json:"preferred_username,omitempty"`
Picture string `json:"picture,omitempty"`
UpdatedAt int64 `json:"updated_at,omitempty"`
Email string `json:"email,omitempty"`
EmailVerified bool `json:"email_verified,omitempty"`
}
type JWKSet struct {
Keys []JWK `json:"keys"`
}
type JWK struct {
Kty string `json:"kty"`
Use string `json:"use"`
Alg string `json:"alg"`
Kid string `json:"kid"`
N string `json:"n"`
E string `json:"e"`
}
func SignOIDCIDToken(privateKeyRaw string, claims *OIDCIDTokenClaims) (string, error) {
key, err := parseRSAPrivateKey(privateKeyRaw)
if err != nil {
return "", err
}
token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
token.Header["kid"] = oidcSigningKeyID(&key.PublicKey)
return token.SignedString(key)
}
func OIDCJWKSet(privateKeyRaw string) (*JWKSet, error) {
key, err := parseRSAPrivateKey(privateKeyRaw)
if err != nil {
return nil, err
}
kid := oidcSigningKeyID(&key.PublicKey)
return &JWKSet{Keys: []JWK{buildJWK(&key.PublicKey, kid)}}, nil
}
func parseRSAPrivateKey(privateKeyRaw string) (*rsa.PrivateKey, error) {
block, _ := pem.Decode([]byte(privateKeyRaw))
if block == nil {
return nil, fmt.Errorf("invalid OIDC signing key PEM")
}
key, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return nil, fmt.Errorf("invalid OIDC signing key: %w", err)
}
return key, nil
}
func oidcSigningKeyID(key *rsa.PublicKey) string {
der, _ := x509.MarshalPKIXPublicKey(key)
sum := sha256.Sum256(der)
return base64.RawURLEncoding.EncodeToString(sum[:])
}
func buildJWK(key *rsa.PublicKey, kid string) JWK {
return JWK{
Kty: "RSA",
Use: "sig",
Alg: "RS256",
Kid: kid,
N: base64.RawURLEncoding.EncodeToString(key.N.Bytes()),
E: base64.RawURLEncoding.EncodeToString(big.NewInt(int64(key.E)).Bytes()),
}
}