Skip to content

Conversation

@ptescher
Copy link

@ptescher ptescher commented Jun 2, 2022

Upgrade process:

  1. Run migrations for latest hydra (1.11.8)
  2. Run latest hydra on next branch
  3. Test login flows on next branck
  4. Roll out to x percent of traffic
  5. Watch error rates
  6. Roll out to everyone

This should be run twice, once with a cloned DB as a dry run, and then again with the live DB.

In order to do a zero downtime migration, we need a copy of hydra running that will continue to work after we apply migrations.

This fix should allow for that, just need to build our own docker container.

Then, if we run migrations, we should end up with these changes:

       sid VARCHAR(255) NOT NULL,
       kid VARCHAR(255) NOT NULL,
@@ -44,16 +44,20 @@
       post_logout_redirect_uris STRING NOT NULL DEFAULT '':::STRING,
       backchannel_logout_uri STRING NOT NULL DEFAULT '':::STRING,
       backchannel_logout_session_required BOOL NOT NULL DEFAULT false,
+      metadata STRING NOT NULL DEFAULT '{}':::STRING,
+      token_endpoint_auth_signing_alg VARCHAR(10) NOT NULL DEFAULT '':::STRING,
+      registration_access_token_signature VARCHAR(128) NOT NULL DEFAULT '':::STRING,
       CONSTRAINT "primary" PRIMARY KEY (pk ASC),
       UNIQUE INDEX hydra_client_id_key (id ASC),
-      FAMILY "primary" (id, client_name, client_secret, redirect_uris, grant_types, response_types, scope, owner, policy_uri, tos_uri, client_uri, logo_uri, contacts, client_secret_expires_at, sector_identifier_uri, jwks, jwks_uri, request_uris, token_endpoint_auth_method, request_object_signing_alg, userinfo_signed_response_alg, subject_type, allowed_cors_origins, pk, audience, created_at, updated_at, frontchannel_logout_uri, frontchannel_logout_session_required, post_logout_redirect_uris, backchannel_logout_uri, backchannel_logout_session_required)
+      FAMILY "primary" (id, client_name, client_secret, redirect_uris, grant_types, response_types, scope, owner, policy_uri, tos_uri, client_uri, logo_uri, contacts, client_secret_expires_at, sector_identifier_uri, jwks, jwks_uri, request_uris, token_endpoint_auth_method, request_object_signing_alg, userinfo_signed_response_alg, subject_type, allowed_cors_origins, pk, audience, created_at, updated_at, frontchannel_logout_uri, frontchannel_logout_session_required, post_logout_redirect_uris, backchannel_logout_uri, backchannel_logout_session_required, metadata, token_endpoint_auth_signing_alg, registration_access_token_signature)
   );
   CREATE TABLE public.hydra_oauth2_authentication_session (
       id VARCHAR(40) NOT NULL,
-      authenticated_at TIMESTAMP NOT NULL DEFAULT now():::TIMESTAMP,
+      authenticated_at TIMESTAMP NULL,
       subject VARCHAR(255) NOT NULL,
       remember BOOL NOT NULL DEFAULT false,
       CONSTRAINT "primary" PRIMARY KEY (id ASC),
+      INDEX hydra_oauth2_authentication_session_subject_idx (subject ASC),
       FAMILY "primary" (id, authenticated_at, subject, remember)
   );
   CREATE TABLE public.hydra_oauth2_authentication_request (
@@ -95,13 +99,15 @@
       requested_at_audience STRING NULL DEFAULT '':::STRING,
       acr STRING NULL DEFAULT '':::STRING,
       context STRING NOT NULL DEFAULT '{}':::STRING,
+      amr STRING NOT NULL DEFAULT '':::STRING,
       CONSTRAINT "primary" PRIMARY KEY (challenge ASC),
       INDEX hydra_oauth2_consent_request_client_id_idx (client_id ASC),
       INDEX hydra_oauth2_consent_request_subject_idx (subject ASC),
       INDEX hydra_oauth2_consent_request_login_session_id_idx (login_session_id ASC),
       INDEX hydra_oauth2_consent_request_login_challenge_idx (login_challenge ASC),
       UNIQUE INDEX hydra_oauth2_consent_request_verifier_key (verifier ASC),
-      FAMILY "primary" (challenge, verifier, client_id, subject, request_url, skip, requested_scope, csrf, authenticated_at, requested_at, oidc_context, forced_subject_identifier, login_session_id, login_challenge, requested_at_audience, acr, context)
+      INDEX hydra_oauth2_consent_request_client_id_subject_idx (client_id ASC, subject ASC),
+      FAMILY "primary" (challenge, verifier, client_id, subject, request_url, skip, requested_scope, csrf, authenticated_at, requested_at, oidc_context, forced_subject_identifier, login_session_id, login_challenge, requested_at_audience, acr, context, amr)
   );
   CREATE TABLE public.hydra_oauth2_consent_request_handled (
       challenge VARCHAR(40) NOT NULL,
@@ -115,8 +121,9 @@
       authenticated_at TIMESTAMP NULL,
       was_used BOOL NOT NULL,
       granted_at_audience STRING NULL DEFAULT '':::STRING,
+      handled_at TIMESTAMP NULL,
       CONSTRAINT "primary" PRIMARY KEY (challenge ASC),
-      FAMILY "primary" (challenge, granted_scope, remember, remember_for, error, requested_at, session_access_token, session_id_token, authenticated_at, was_used, granted_at_audience)
+      FAMILY "primary" (challenge, granted_scope, remember, remember_for, error, requested_at, session_access_token, session_id_token, authenticated_at, was_used, granted_at_audience, handled_at)
   );
   CREATE TABLE public.hydra_oauth2_authentication_request_handled (
       challenge VARCHAR(40) NOT NULL,
@@ -130,8 +137,9 @@
       was_used BOOL NOT NULL,
       forced_subject_identifier VARCHAR(255) NULL DEFAULT '':::STRING,
       context STRING NOT NULL DEFAULT '{}':::STRING,
+      amr STRING NOT NULL DEFAULT '':::STRING,
       CONSTRAINT "primary" PRIMARY KEY (challenge ASC),
-      FAMILY "primary" (challenge, subject, remember, remember_for, error, acr, requested_at, authenticated_at, was_used, forced_subject_identifier, context)
+      FAMILY "primary" (challenge, subject, remember, remember_for, error, acr, requested_at, authenticated_at, was_used, forced_subject_identifier, context, amr)
   );
   CREATE TABLE public.hydra_oauth2_obfuscated_authentication_session (
       subject VARCHAR(255) NOT NULL,
@@ -173,10 +181,11 @@
       granted_audience STRING NULL DEFAULT '':::STRING,
       challenge_id VARCHAR(40) NULL,
       CONSTRAINT "primary" PRIMARY KEY (signature ASC),
-      UNIQUE INDEX hydra_oauth2_access_request_id_key (request_id ASC),
       INDEX hydra_oauth2_access_requested_at_idx (requested_at ASC),
       INDEX hydra_oauth2_access_client_id_idx (client_id ASC),
       INDEX hydra_oauth2_access_challenge_id_idx (challenge_id ASC),
+      INDEX hydra_oauth2_access_client_id_subject_idx (client_id ASC, subject ASC),
+      INDEX hydra_oauth2_access_request_id_idx (request_id ASC),
       FAMILY "primary" (signature, request_id, requested_at, client_id, scope, granted_scope, form_data, session_data, subject, active, requested_audience, granted_audience, challenge_id)
   );
   CREATE TABLE public.hydra_oauth2_refresh (
@@ -194,9 +203,10 @@
       granted_audience STRING NULL DEFAULT '':::STRING,
       challenge_id VARCHAR(40) NULL,
       CONSTRAINT "primary" PRIMARY KEY (signature ASC),
-      UNIQUE INDEX hydra_oauth2_refresh_request_id_key (request_id ASC),
       INDEX hydra_oauth2_refresh_client_id_idx (client_id ASC),
       INDEX hydra_oauth2_refresh_challenge_id_idx (challenge_id ASC),
+      INDEX hydra_oauth2_refresh_client_id_subject_idx (client_id ASC, subject ASC),
+      INDEX hydra_oauth2_refresh_request_id_idx (request_id ASC),
       FAMILY "primary" (signature, request_id, requested_at, client_id, scope, granted_scope, form_data, session_data, subject, active, requested_audience, granted_audience, challenge_id)
   );
   CREATE TABLE public.hydra_oauth2_code (
@@ -216,6 +226,7 @@
       CONSTRAINT "primary" PRIMARY KEY (signature ASC),
       INDEX hydra_oauth2_code_client_id_idx (client_id ASC),
       INDEX hydra_oauth2_code_challenge_id_idx (challenge_id ASC),
+      INDEX hydra_oauth2_code_request_id_idx (request_id ASC),
       FAMILY "primary" (signature, request_id, requested_at, client_id, scope, granted_scope, form_data, session_data, subject, active, requested_audience, granted_audience, challenge_id)
   );
   CREATE TABLE public.hydra_oauth2_oidc (
@@ -235,6 +246,7 @@
       CONSTRAINT "primary" PRIMARY KEY (signature ASC),
       INDEX hydra_oauth2_oidc_client_id_idx (client_id ASC),
       INDEX hydra_oauth2_oidc_challenge_id_idx (challenge_id ASC),
+      INDEX hydra_oauth2_oidc_request_id_idx (request_id ASC),
       FAMILY "primary" (signature, request_id, requested_at, client_id, scope, granted_scope, form_data, session_data, subject, active, requested_audience, granted_audience, challenge_id)
   );
   CREATE TABLE public.hydra_oauth2_pkce (
@@ -254,15 +266,46 @@
       CONSTRAINT "primary" PRIMARY KEY (signature ASC),
       INDEX hydra_oauth2_pkce_client_id_idx (client_id ASC),
       INDEX hydra_oauth2_pkce_challenge_id_idx (challenge_id ASC),
+      INDEX hydra_oauth2_pkce_request_id_idx (request_id ASC),
       FAMILY "primary" (signature, request_id, requested_at, client_id, scope, granted_scope, form_data, session_data, subject, active, requested_audience, granted_audience, challenge_id)
   );
-  CREATE TABLE public.schema_migration (
+  CREATE TABLE public.schema_migration_pop_legacy (
       version VARCHAR(14) NOT NULL,
       rowid INT8 NOT VISIBLE NOT NULL DEFAULT unique_rowid(),
       CONSTRAINT "primary" PRIMARY KEY (rowid ASC),
-      UNIQUE INDEX schema_migration_version_idx (version ASC),
       FAMILY "primary" (version, rowid)
   );
+  CREATE TABLE public.schema_migration (
+      version VARCHAR(48) NOT NULL,
+      version_self INT8 NOT NULL DEFAULT 0:::INT8,
+      rowid INT8 NOT VISIBLE NOT NULL DEFAULT unique_rowid(),
+      CONSTRAINT "primary" PRIMARY KEY (rowid ASC),
+      UNIQUE INDEX schema_migration_version_idx (version ASC),
+      INDEX schema_migration_version_self_idx (version_self ASC),
+      FAMILY "primary" (version, version_self, rowid)
+  );
+  CREATE TABLE public.hydra_oauth2_jti_blacklist (
+      signature VARCHAR(64) NOT NULL,
+      expires_at TIMESTAMP NOT NULL DEFAULT now():::TIMESTAMP,
+      CONSTRAINT "primary" PRIMARY KEY (signature ASC),
+      INDEX hydra_oauth2_jti_blacklist_expires_at_idx (expires_at ASC),
+      FAMILY "primary" (signature, expires_at)
+  );
+  CREATE TABLE public.hydra_oauth2_trusted_jwt_bearer_issuer (
+      id UUID NOT NULL,
+      issuer VARCHAR(255) NOT NULL,
+      subject VARCHAR(255) NOT NULL,
+      scope STRING NOT NULL,
+      key_set VARCHAR(255) NOT NULL,
+      key_id VARCHAR(255) NOT NULL,
+      created_at TIMESTAMP NOT NULL DEFAULT now():::TIMESTAMP,
+      expires_at TIMESTAMP NOT NULL DEFAULT now():::TIMESTAMP,
+      allow_any_subject BOOL NOT NULL DEFAULT false,
+      CONSTRAINT "primary" PRIMARY KEY (id ASC),
+      UNIQUE INDEX hydra_oauth2_trusted_jwt_bearer_issuer_issuer_subject_key_id_key (issuer ASC, subject ASC, key_id ASC),
+      INDEX hydra_oauth2_trusted_jwt_bearer_issuer_expires_at_idx (expires_at ASC),
+      FAMILY "primary" (id, issuer, subject, scope, key_set, key_id, created_at, expires_at, allow_any_subject)
+  );
   ALTER TABLE public.hydra_oauth2_authentication_request ADD CONSTRAINT hydra_oauth2_authentication_request_client_id_fk FOREIGN KEY (client_id) REFERENCES public.hydra_client(id) ON DELETE CASCADE NOT VALID;
   ALTER TABLE public.hydra_oauth2_authentication_request ADD CONSTRAINT hydra_oauth2_authentication_request_login_session_id_fk FOREIGN KEY (login_session_id) REFERENCES public.hydra_oauth2_authentication_session(id) ON DELETE CASCADE NOT VALID;
   ALTER TABLE public.hydra_oauth2_consent_request ADD CONSTRAINT hydra_oauth2_consent_request_client_id_fk FOREIGN KEY (client_id) REFERENCES public.hydra_client(id) ON DELETE CASCADE NOT VALID;
@@ -282,6 +325,7 @@
   ALTER TABLE public.hydra_oauth2_oidc ADD CONSTRAINT hydra_oauth2_oidc_challenge_id_fk FOREIGN KEY (challenge_id) REFERENCES public.hydra_oauth2_consent_request_handled(challenge) ON DELETE CASCADE NOT VALID;
   ALTER TABLE public.hydra_oauth2_pkce ADD CONSTRAINT hydra_oauth2_pkce_client_id_fk FOREIGN KEY (client_id) REFERENCES public.hydra_client(id) ON DELETE CASCADE NOT VALID;
   ALTER TABLE public.hydra_oauth2_pkce ADD CONSTRAINT hydra_oauth2_pkce_challenge_id_fk FOREIGN KEY (challenge_id) REFERENCES public.hydra_oauth2_consent_request_handled(challenge) ON DELETE CASCADE NOT VALID;
+  ALTER TABLE public.hydra_oauth2_trusted_jwt_bearer_issuer ADD CONSTRAINT fk_key_set_ref_hydra_jwk FOREIGN KEY (key_set, key_id) REFERENCES public.hydra_jwk(sid, kid) ON DELETE CASCADE;
   -- Validate foreign key constraints. These can fail if there was unvalidated data during the SHOW CREATE ALL TABLES
   ALTER TABLE public.hydra_oauth2_authentication_request VALIDATE CONSTRAINT hydra_oauth2_authentication_request_client_id_fk;
   ALTER TABLE public.hydra_oauth2_authentication_request VALIDATE CONSTRAINT hydra_oauth2_authentication_request_login_session_id_fk;
@@ -302,3 +346,4 @@
   ALTER TABLE public.hydra_oauth2_oidc VALIDATE CONSTRAINT hydra_oauth2_oidc_challenge_id_fk;
   ALTER TABLE public.hydra_oauth2_pkce VALIDATE CONSTRAINT hydra_oauth2_pkce_client_id_fk;
   ALTER TABLE public.hydra_oauth2_pkce VALIDATE CONSTRAINT hydra_oauth2_pkce_challenge_id_fk;
+  ALTER TABLE public.hydra_oauth2_trusted_jwt_bearer_issuer VALIDATE CONSTRAINT fk_key_set_ref_hydra_jwk;

which should continue to work since no columns are being dropped

@ptescher ptescher requested a review from jtescher June 2, 2022 23:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants