enable policies

This commit is contained in:
2026-01-16 17:31:20 +10:30
parent b2e084db33
commit d063a0ca81
28 changed files with 4296 additions and 224 deletions
-150
View File
@@ -1,150 +0,0 @@
"""Database migration: Create OIDC tables.
Revision ID: 001
Revises:
Create Date: 2024-01-01 00:00:00
This migration creates all OIDC-related tables for the authorization code flow,
refresh token management, OIDC session tracking, token metadata, and audit logging.
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql
# Revision identifiers
revision = '001'
down_revision = None
branch_labels = None
depends_on = None
def upgrade():
"""Create OIDC tables."""
# OIDC Authorization Codes table
op.create_table(
'oidc_authorization_codes',
sa.Column('id', sa.String(36), primary_key=True),
sa.Column('created_at', sa.DateTime, nullable=False),
sa.Column('updated_at', sa.DateTime, nullable=False),
sa.Column('deleted_at', sa.DateTime, nullable=True),
sa.Column('client_id', sa.String(255), sa.ForeignKey('oidc_clients.id'), nullable=False),
sa.Column('user_id', sa.String(36), sa.ForeignKey('users.id'), nullable=False),
sa.Column('code_hash', sa.String(255), nullable=False),
sa.Column('redirect_uri', sa.String(512), nullable=False),
sa.Column('scope', postgresql.JSON, nullable=True),
sa.Column('nonce', sa.String(255), nullable=True),
sa.Column('code_verifier', sa.String(255), nullable=True),
sa.Column('expires_at', sa.DateTime, nullable=False),
sa.Column('used_at', sa.DateTime, nullable=True),
sa.Column('is_used', sa.Boolean, default=False, nullable=False),
sa.Column('ip_address', sa.String(45), nullable=True),
sa.Column('user_agent', sa.Text, nullable=True),
)
op.create_index('ix_oidc_authorization_codes_client_id', 'oidc_authorization_codes', ['client_id'])
op.create_index('ix_oidc_authorization_codes_user_id', 'oidc_authorization_codes', ['user_id'])
op.create_index('ix_oidc_authorization_codes_expires_at', 'oidc_authorization_codes', ['expires_at'])
# OIDC Refresh Tokens table
op.create_table(
'oidc_refresh_tokens',
sa.Column('id', sa.String(36), primary_key=True),
sa.Column('created_at', sa.DateTime, nullable=False),
sa.Column('updated_at', sa.DateTime, nullable=False),
sa.Column('deleted_at', sa.DateTime, nullable=True),
sa.Column('client_id', sa.String(255), sa.ForeignKey('oidc_clients.id'), nullable=False),
sa.Column('user_id', sa.String(36), sa.ForeignKey('users.id'), nullable=False),
sa.Column('token_hash', sa.String(255), nullable=False),
sa.Column('access_token_id', sa.String(36), sa.ForeignKey('sessions.id'), nullable=True),
sa.Column('scope', postgresql.JSON, nullable=True),
sa.Column('expires_at', sa.DateTime, nullable=False),
sa.Column('revoked_at', sa.DateTime, nullable=True),
sa.Column('revoked_reason', sa.String(255), nullable=True),
sa.Column('previous_token_hash', sa.String(255), nullable=True),
sa.Column('rotation_count', sa.Integer, default=0, nullable=False),
sa.Column('ip_address', sa.String(45), nullable=True),
sa.Column('user_agent', sa.Text, nullable=True),
)
op.create_index('ix_oidc_refresh_tokens_client_id', 'oidc_refresh_tokens', ['client_id'])
op.create_index('ix_oidc_refresh_tokens_user_id', 'oidc_refresh_tokens', ['user_id'])
op.create_index('ix_oidc_refresh_tokens_token_hash', 'oidc_refresh_tokens', ['token_hash'], unique=True)
op.create_index('ix_oidc_refresh_tokens_access_token_id', 'oidc_refresh_tokens', ['access_token_id'])
op.create_index('ix_oidc_refresh_tokens_expires_at', 'oidc_refresh_tokens', ['expires_at'])
# OIDC Sessions table
op.create_table(
'oidc_sessions',
sa.Column('id', sa.String(36), primary_key=True),
sa.Column('created_at', sa.DateTime, nullable=False),
sa.Column('updated_at', sa.DateTime, nullable=False),
sa.Column('deleted_at', sa.DateTime, nullable=True),
sa.Column('user_id', sa.String(36), sa.ForeignKey('users.id'), nullable=False),
sa.Column('client_id', sa.String(255), sa.ForeignKey('oidc_clients.id'), nullable=False),
sa.Column('state', sa.String(255), nullable=False),
sa.Column('nonce', sa.String(255), nullable=True),
sa.Column('redirect_uri', sa.String(512), nullable=False),
sa.Column('scope', postgresql.JSON, nullable=True),
sa.Column('code_challenge', sa.String(255), nullable=True),
sa.Column('code_challenge_method', sa.String(10), nullable=True),
sa.Column('expires_at', sa.DateTime, nullable=False),
sa.Column('authenticated_at', sa.DateTime, nullable=True),
)
op.create_index('ix_oidc_sessions_user_id', 'oidc_sessions', ['user_id'])
op.create_index('ix_oidc_sessions_client_id', 'oidc_sessions', ['client_id'])
op.create_index('ix_oidc_sessions_state', 'oidc_sessions', ['state'])
op.create_index('ix_oidc_sessions_expires_at', 'oidc_sessions', ['expires_at'])
# OIDC Token Metadata table
op.create_table(
'oidc_token_metadata',
sa.Column('id', sa.String(36), primary_key=True),
sa.Column('created_at', sa.DateTime, nullable=False),
sa.Column('updated_at', sa.DateTime, nullable=False),
sa.Column('deleted_at', sa.DateTime, nullable=True),
sa.Column('client_id', sa.String(255), sa.ForeignKey('oidc_clients.id'), nullable=False),
sa.Column('user_id', sa.String(36), sa.ForeignKey('users.id'), nullable=False),
sa.Column('token_type', sa.String(50), nullable=False),
sa.Column('token_jti', sa.String(255), nullable=False),
sa.Column('expires_at', sa.DateTime, nullable=False),
sa.Column('revoked_at', sa.DateTime, nullable=True),
sa.Column('revoked_reason', sa.String(255), nullable=True),
)
op.create_index('ix_oidc_token_metadata_client_id', 'oidc_token_metadata', ['client_id'])
op.create_index('ix_oidc_token_metadata_user_id', 'oidc_token_metadata', ['user_id'])
op.create_index('ix_oidc_token_metadata_token_jti', 'oidc_token_metadata', ['token_jti'])
op.create_index('ix_oidc_token_metadata_expires_at', 'oidc_token_metadata', ['expires_at'])
# OIDC Audit Logs table
op.create_table(
'oidc_audit_logs',
sa.Column('id', sa.String(36), primary_key=True),
sa.Column('created_at', sa.DateTime, nullable=False),
sa.Column('updated_at', sa.DateTime, nullable=False),
sa.Column('deleted_at', sa.DateTime, nullable=True),
sa.Column('event_type', sa.String(100), nullable=False),
sa.Column('client_id', sa.String(255), sa.ForeignKey('oidc_clients.id'), nullable=True),
sa.Column('user_id', sa.String(36), sa.ForeignKey('users.id'), nullable=True),
sa.Column('success', sa.Boolean, default=True, nullable=False),
sa.Column('error_code', sa.String(100), nullable=True),
sa.Column('error_description', sa.Text, nullable=True),
sa.Column('ip_address', sa.String(45), nullable=True),
sa.Column('user_agent', sa.Text, nullable=True),
sa.Column('request_id', sa.String(36), nullable=True),
sa.Column('event_metadata', postgresql.JSON, nullable=True),
)
op.create_index('ix_oidc_audit_logs_event_type', 'oidc_audit_logs', ['event_type'])
op.create_index('ix_oidc_audit_logs_client_id', 'oidc_audit_logs', ['client_id'])
op.create_index('ix_oidc_audit_logs_user_id', 'oidc_audit_logs', ['user_id'])
op.create_index('ix_oidc_audit_logs_success', 'oidc_audit_logs', ['success'])
op.create_index('ix_oidc_audit_logs_ip_address', 'oidc_audit_logs', ['ip_address'])
op.create_index('ix_oidc_audit_logs_request_id', 'oidc_audit_logs', ['request_id'])
def downgrade():
"""Drop OIDC tables."""
op.drop_table('oidc_audit_logs')
op.drop_table('oidc_token_metadata')
op.drop_table('oidc_sessions')
op.drop_table('oidc_refresh_tokens')
op.drop_table('oidc_authorization_codes')
-44
View File
@@ -1,44 +0,0 @@
"""Database migration: Add WebAuthn support.
Revision ID: 002
Revises: 001
Create Date: 2024-01-15 00:00:00
This migration adds support for WebAuthn passkey authentication by:
- Adding WEBAUTHN to the AuthMethodType enum (handled in application code)
- No schema changes required (uses existing provider_data JSON field)
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql
# Revision identifiers
revision = '002'
down_revision = '001'
branch_labels = None
depends_on = None
def upgrade():
"""Add WebAuthn support - no schema changes needed."""
# WebAuthn credentials are stored in the existing provider_data JSON field
# of the authentication_methods table. No schema changes are required.
# Create an index for faster lookups of WebAuthn credentials by user
# This is optional but recommended for performance
# op.create_index(
# 'ix_authentication_methods_webauthn_user',
# 'authentication_methods',
# ['user_id'],
# postgresql_where=(sa.text("method_type = 'webauthn'")),
# if_not_exists=True
# )
pass
def downgrade():
"""Remove WebAuthn support - no schema changes needed."""
# No schema changes to revert
pass