Resolve "User stuck in 2FA setup page even if group disable 2FA enforce"
What does this MR do?
In #220433 (closed) was shown a problem, that was fixed in !46432 (merged), but we need also to take care of records in the database that needs fixing.
Here is prepared migration, that picks users which have a field require_two_factor_authentication_from_group
set to true, even though they don't belong to any group that requires it, and updates require_two_factor_authentication_from_group
field on this records.
Screenshots (strongly suggested)
== 20201030121314 ScheduleUpdateExistingUsersThatRequireTwoFactorAuth: migrating
-- transaction_open?()
-> 0.0000s
-- index_exists?(:users, :require_two_factor_authentication_from_group, {:where=>"require_two_factor_authentication_from_group = TRUE", :name=>"index_users_on_require_two_factor_authentication_from_group", :algorithm=>:concurrently})
-> 0.0094s
== 20201030121314 ScheduleUpdateExistingUsersThatRequireTwoFactorAuth: migrated (0.0807s)
explain SELECT users.* FROM users WHERE users.require_two_factor_authentication_from_group = TRUE
Index Scan using index_users_on_require_two_factor_authentication_from_group on public.users (cost=0.43..23950.81 rows=83475 width=4) (actual time=3.949..31893.991 rows=84127 loops=1)
Index Cond: (users.require_two_factor_authentication_from_group = true)
Filter: (users.require_two_factor_authentication_from_group IS TRUE)
Rows Removed by Filter: 0
Buffers: shared hit=12387 read=62987
I/O Timings: read=31206.404
UPDATE
users
SET
require_two_factor_authentication_from_group = FALSE
WHERE
users.id BETWEEN 1
AND 1000
AND users.require_two_factor_authentication_from_group = TRUE
AND users.id NOT IN ( SELECT DISTINCT
users_groups_query.user_id
FROM (
SELECT
users.id AS user_id,
members.source_id AS group_ids
FROM
users
LEFT JOIN members ON members.source_type = 'Namespace'
AND members.requested_at IS NULL
AND members.user_id = users.id
AND members.type = 'GroupMember'
WHERE
users.require_two_factor_authentication_from_group = TRUE
AND users.id BETWEEN 1
AND 1000) AS users_groups_query
INNER JOIN LATERAL ( WITH RECURSIVE "base_and_ancestors" AS (
(
SELECT
"namespaces"."type",
"namespaces"."id",
"namespaces"."parent_id",
"namespaces"."require_two_factor_authentication"
FROM
"namespaces"
WHERE
"namespaces"."type" = 'Group'
AND "namespaces"."id" = users_groups_query.group_ids)
UNION (
SELECT
"namespaces"."type",
"namespaces"."id",
"namespaces"."parent_id",
"namespaces"."require_two_factor_authentication"
FROM
"namespaces",
"base_and_ancestors"
WHERE
"namespaces"."type" = 'Group'
AND "namespaces"."id" = "base_and_ancestors"."parent_id")),
"base_and_descendants" AS (
(
SELECT
"namespaces"."type",
"namespaces"."id",
"namespaces"."parent_id",
"namespaces"."require_two_factor_authentication"
FROM
"namespaces"
WHERE
"namespaces"."type" = 'Group'
AND "namespaces"."id" = users_groups_query.group_ids)
UNION (
SELECT
"namespaces"."type",
"namespaces"."id",
"namespaces"."parent_id",
"namespaces"."require_two_factor_authentication"
FROM
"namespaces",
"base_and_descendants"
WHERE
"namespaces"."type" = 'Group'
AND "namespaces"."parent_id" = "base_and_descendants"."id"))
SELECT
"namespaces".*
FROM ((
SELECT
"namespaces"."type",
"namespaces"."id",
"namespaces"."parent_id",
"namespaces"."require_two_factor_authentication"
FROM
"base_and_ancestors" AS "namespaces"
WHERE
"namespaces"."type" = 'Group')
UNION (
SELECT
"namespaces"."type",
"namespaces"."id",
"namespaces"."parent_id",
"namespaces"."require_two_factor_authentication"
FROM
"base_and_descendants" AS "namespaces"
WHERE
"namespaces"."type" = 'Group')) namespaces
WHERE
"namespaces"."type" = 'Group'
AND "namespaces"."require_two_factor_authentication" = TRUE) AS hierarchy_tree ON TRUE);
https://explain.depesz.com/s/Yjfh
Time: 108.377 ms
- planning: 2.623 ms
- execution: 105.754 ms
- I/O read: 23.515 ms
- I/O write: 0.000 ms
Shared buffers:
- hits: 16727 (~130.70 MiB) from the buffer pool
- reads: 233 (~1.80 MiB) from the OS file cache, including disk I/O
- dirtied: 0
- writes: 0
Background Migration Details:
84127 items to iterate batch size = 1000 84127 / 1000 = 85 loops
Estimated times per batch:
- 109ms for update statement with 1000 items Total: ~110msec per batch
2 mins delay per loop (safe for the given total time per batch)
85 * 2 min = 170 min (2h 50 min) to run all the scheduled jobs
Does this MR meet the acceptance criteria?
Conformity
-
Changelog entry -
Documentation (if required) -
Code review guidelines -
Merge request performance guidelines -
Style guides -
Database guides -
Separation of EE specific content
Availability and Testing
-
Review and add/update tests for this feature/bug. Consider all test levels. See the Test Planning Process. -
Tested in all supported browsers -
Informed Infrastructure department of a default or new setting change, if applicable per definition of done
Security
If this MR contains changes to processing or storing of credentials or tokens, authorization and authentication methods and other items described in the security review guidelines:
-
Label as security and @ mention @gitlab-com/gl-security/appsec
-
The MR includes necessary changes to maintain consistency between UI, API, email, or other methods -
Security reports checked/validated by a reviewer from the AppSec team
Related to #220433 (closed)