Fix Python scoping issue: rename html variable to avoid conflict

The variable 'html' was being assigned to store HTML content, which
caused Python to treat 'html' as a local variable throughout the
function. This prevented access to the 'html' module (imported at
the top) within f-strings that referenced html.escape().

Renamed the HTML content variable to 'html_content' to avoid the
naming conflict with the html module.
This commit is contained in:
Olivier Dumont
2025-12-30 12:52:53 +01:00
parent 5b5799ab62
commit cd068d16c2
5 changed files with 88 additions and 7 deletions

View File

@@ -0,0 +1,2 @@
DROP TABLE IF EXISTS "oidc_keys";

View File

@@ -0,0 +1,7 @@
CREATE TABLE IF NOT EXISTS "oidc_keys" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"private_key" TEXT NOT NULL,
"created_at" INTEGER NOT NULL,
"updated_at" INTEGER NOT NULL
);

View File

@@ -0,0 +1,13 @@
package model
type OIDCKey struct {
ID int `gorm:"column:id;primaryKey;autoIncrement"`
PrivateKey string `gorm:"column:private_key;not null"`
CreatedAt int64 `gorm:"column:created_at"`
UpdatedAt int64 `gorm:"column:updated_at"`
}
func (OIDCKey) TableName() string {
return "oidc_keys"
}

View File

@@ -44,16 +44,75 @@ func NewOIDCService(config OIDCServiceConfig) *OIDCService {
}
func (oidc *OIDCService) Init() error {
// Generate RSA key pair for signing tokens
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
// Try to load existing key from database
var keyRecord model.OIDCKey
err := oidc.config.Database.First(&keyRecord).Error
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
return fmt.Errorf("failed to query for existing RSA key: %w", err)
}
var privateKey *rsa.PrivateKey
if err == nil && keyRecord.PrivateKey != "" {
// Load existing key
block, _ := pem.Decode([]byte(keyRecord.PrivateKey))
if block == nil {
return fmt.Errorf("failed to decode PEM block from stored key")
}
parsedKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return fmt.Errorf("failed to generate RSA key: %w", err)
// Try PKCS8 format as fallback
key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
return fmt.Errorf("failed to parse stored private key: %w", err)
}
var ok bool
privateKey, ok = key.(*rsa.PrivateKey)
if !ok {
return fmt.Errorf("stored key is not an RSA private key")
}
} else {
privateKey = parsedKey
}
oidc.privateKey = privateKey
oidc.publicKey = &privateKey.PublicKey
log.Info().Msg("OIDC service initialized with new RSA key pair")
log.Info().Msg("OIDC service initialized with existing RSA key pair from database")
return nil
}
// No existing key found, generate new one
privateKey, err = rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return fmt.Errorf("failed to generate RSA key: %w", err)
}
// Encode private key to PEM format
privateKeyBytes := x509.MarshalPKCS1PrivateKey(privateKey)
privateKeyPEM := pem.EncodeToMemory(&pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: privateKeyBytes,
})
// Save to database
now := time.Now().Unix()
keyRecord = model.OIDCKey{
PrivateKey: string(privateKeyPEM),
CreatedAt: now,
UpdatedAt: now,
}
if err := oidc.config.Database.Create(&keyRecord).Error; err != nil {
return fmt.Errorf("failed to save RSA key to database: %w", err)
}
oidc.privateKey = privateKey
oidc.publicKey = &privateKey.PublicKey
log.Info().Msg("OIDC service initialized with new RSA key pair (saved to database)")
return nil
}

View File

@@ -117,7 +117,7 @@ class CallbackHandler(BaseHTTPRequestHandler):
self.send_response(200)
self.send_header("Content-type", "text/html")
self.end_headers()
html = f"""
html_content = f"""
<!DOCTYPE html>
<html>
<head>
@@ -182,14 +182,14 @@ class CallbackHandler(BaseHTTPRequestHandler):
</body>
</html>
"""
self.wfile.write(html.encode())
self.wfile.write(html_content.encode())
return
# Not logged in - show login page
self.send_response(200)
self.send_header("Content-type", "text/html")
self.end_headers()
html = f"""
html_content = f"""
<!DOCTYPE html>
<html>
<head><title>OIDC Test Client</title></head>
@@ -202,7 +202,7 @@ class CallbackHandler(BaseHTTPRequestHandler):
</body>
</html>
"""
self.wfile.write(html.encode())
self.wfile.write(html_content.encode())
return
# Handle logout