|
|
|
@ -1,8 +1,6 @@
|
|
|
|
package auth
|
|
|
|
package auth
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
|
|
|
|
"crypto/rand"
|
|
|
|
|
|
|
|
"crypto/rsa"
|
|
|
|
"crypto/rsa"
|
|
|
|
"crypto/sha256"
|
|
|
|
"crypto/sha256"
|
|
|
|
"crypto/x509"
|
|
|
|
"crypto/x509"
|
|
|
|
@ -11,13 +9,9 @@ import (
|
|
|
|
"fmt"
|
|
|
|
"fmt"
|
|
|
|
"math/big"
|
|
|
|
"math/big"
|
|
|
|
|
|
|
|
|
|
|
|
"github.com/cloudreve/Cloudreve/v4/ent"
|
|
|
|
|
|
|
|
"github.com/cloudreve/Cloudreve/v4/inventory"
|
|
|
|
|
|
|
|
"github.com/golang-jwt/jwt/v5"
|
|
|
|
"github.com/golang-jwt/jwt/v5"
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
const OIDCSigningPrivateKeySetting = "oidc_signing_private_key"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
type OIDCIDTokenClaims struct {
|
|
|
|
type OIDCIDTokenClaims struct {
|
|
|
|
jwt.RegisteredClaims
|
|
|
|
jwt.RegisteredClaims
|
|
|
|
Nonce string `json:"nonce,omitempty"`
|
|
|
|
Nonce string `json:"nonce,omitempty"`
|
|
|
|
@ -42,55 +36,27 @@ type JWK struct {
|
|
|
|
E string `json:"e"`
|
|
|
|
E string `json:"e"`
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func SignOIDCIDToken(ctx context.Context, settingClient inventory.SettingClient, claims *OIDCIDTokenClaims) (string, error) {
|
|
|
|
func SignOIDCIDToken(privateKeyRaw string, claims *OIDCIDTokenClaims) (string, error) {
|
|
|
|
key, kid, err := loadOrCreateOIDCSigningKey(ctx, settingClient)
|
|
|
|
key, err := parseRSAPrivateKey(privateKeyRaw)
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
|
|
|
|
token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
|
|
|
|
token.Header["kid"] = kid
|
|
|
|
token.Header["kid"] = oidcSigningKeyID(&key.PublicKey)
|
|
|
|
return token.SignedString(key)
|
|
|
|
return token.SignedString(key)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func OIDCJWKSet(ctx context.Context, settingClient inventory.SettingClient) (*JWKSet, error) {
|
|
|
|
func OIDCJWKSet(privateKeyRaw string) (*JWKSet, error) {
|
|
|
|
key, kid, err := loadOrCreateOIDCSigningKey(ctx, settingClient)
|
|
|
|
key, err := parseRSAPrivateKey(privateKeyRaw)
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
kid := oidcSigningKeyID(&key.PublicKey)
|
|
|
|
return &JWKSet{Keys: []JWK{buildJWK(&key.PublicKey, kid)}}, nil
|
|
|
|
return &JWKSet{Keys: []JWK{buildJWK(&key.PublicKey, kid)}}, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func loadOrCreateOIDCSigningKey(ctx context.Context, settingClient inventory.SettingClient) (*rsa.PrivateKey, string, error) {
|
|
|
|
|
|
|
|
privateKeyRaw, err := settingClient.Get(ctx, OIDCSigningPrivateKeySetting)
|
|
|
|
|
|
|
|
if err != nil && !ent.IsNotFound(err) {
|
|
|
|
|
|
|
|
return nil, "", fmt.Errorf("failed to load OIDC signing key: %w", err)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if privateKeyRaw != "" {
|
|
|
|
|
|
|
|
key, err := parseRSAPrivateKey(privateKeyRaw)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
return nil, "", err
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return key, oidcSigningKeyID(&key.PublicKey), nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
key, err := rsa.GenerateKey(rand.Reader, 2048)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
return nil, "", fmt.Errorf("failed to generate OIDC signing key: %w", err)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
privateKeyRaw = string(pem.EncodeToMemory(&pem.Block{
|
|
|
|
|
|
|
|
Type: "RSA PRIVATE KEY",
|
|
|
|
|
|
|
|
Bytes: x509.MarshalPKCS1PrivateKey(key),
|
|
|
|
|
|
|
|
}))
|
|
|
|
|
|
|
|
if err := settingClient.Set(ctx, map[string]string{OIDCSigningPrivateKeySetting: privateKeyRaw}); err != nil {
|
|
|
|
|
|
|
|
return nil, "", fmt.Errorf("failed to persist OIDC signing key: %w", err)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return key, oidcSigningKeyID(&key.PublicKey), nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func parseRSAPrivateKey(privateKeyRaw string) (*rsa.PrivateKey, error) {
|
|
|
|
func parseRSAPrivateKey(privateKeyRaw string) (*rsa.PrivateKey, error) {
|
|
|
|
block, _ := pem.Decode([]byte(privateKeyRaw))
|
|
|
|
block, _ := pem.Decode([]byte(privateKeyRaw))
|
|
|
|
if block == nil {
|
|
|
|
if block == nil {
|
|
|
|
|