Skip to content

Commit 2a15525

Browse files
authored
Merge pull request #60 from TaskarCenterAtUW/jeff-osm-api-auth
Change stub user to validate OSM rails models
2 parents e81363b + 935d344 commit 2a15525

3 files changed

Lines changed: 61 additions & 2 deletions

File tree

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
"""heal short TDEI-provisioned users.pass_crypt
2+
3+
TDEI users are provisioned by the backend via raw SQL with a placeholder
4+
``pass_crypt``. Older rows used a 4-char value (``"none"``), which violates OSM's
5+
``pass_crypt`` length 8..255 ``User`` validation. That makes the user invalid,
6+
and Rails operations that re-validate the author via ``validates :author,
7+
:associated => true`` (posting a changeset comment or a note comment) then fail
8+
to save. Replace any too-short value with a random throwaway -- TDEI manages
9+
auth, so ``pass_crypt`` is never used to authenticate.
10+
11+
Revision ID: f3a7b9c1d2e4
12+
Revises: 5303f61d7b3a
13+
Create Date: 2026-07-11 00:00:00.000000
14+
15+
"""
16+
17+
from typing import Sequence, Union
18+
19+
from alembic import op
20+
from sqlalchemy import inspect, text
21+
22+
# revision identifiers, used by Alembic.
23+
revision: str = "f3a7b9c1d2e4"
24+
down_revision: Union[str, None] = "5303f61d7b3a"
25+
branch_labels: Union[str, Sequence[str], None] = None
26+
depends_on: Union[str, Sequence[str], None] = None
27+
28+
29+
def upgrade() -> None:
30+
bind = op.get_bind()
31+
# `users` is owned by the OSM Rails website, not this tree; guard so the
32+
# migration is a no-op if it hasn't been created yet.
33+
if not inspect(bind).has_table("users"):
34+
return
35+
36+
# Idempotent: re-running only touches rows that are still too short.
37+
op.execute(
38+
text(
39+
"UPDATE users SET pass_crypt = md5(random()::text) "
40+
"WHERE auth_provider = 'TDEI' AND length(pass_crypt) < 8"
41+
)
42+
)
43+
44+
45+
def downgrade() -> None:
46+
# The original short values are unrecoverable (and were invalid anyway).
47+
pass

api/core/security.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,7 @@ async def _ensure_osm_user(
354354
"INSERT INTO users (auth_uid, email, display_name, auth_provider, "
355355
"status, pass_crypt, data_public, email_valid, terms_seen, "
356356
"creation_time, terms_agreed, tou_agreed) "
357-
"VALUES (:auth_uid, :email, :name, 'TDEI', 'active', 'none', "
357+
"VALUES (:auth_uid, :email, :name, 'TDEI', 'active', :pass_crypt, "
358358
"true, true, true, (now() at time zone 'utc'), "
359359
"(now() at time zone 'utc'), (now() at time zone 'utc')) "
360360
"ON CONFLICT (auth_uid) DO NOTHING"
@@ -363,6 +363,12 @@ async def _ensure_osm_user(
363363
"auth_uid": auth_uid,
364364
"email": email or f"{auth_uid}@tdei.invalid",
365365
"name": display_name,
366+
# OSM's User model validates pass_crypt length 8..255. TDEI manages
367+
# auth, so this is a throwaway that just satisfies that rule (a too-
368+
# short value makes the user invalid and breaks Rails operations
369+
# that re-validate it via `validates :author, :associated => true`,
370+
# e.g. posting a changeset comment).
371+
"pass_crypt": secrets.token_hex(16),
366372
},
367373
)
368374
row = (

api/src/tasking/projects/repository.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from __future__ import annotations
22

33
import json
4+
import secrets
45
from datetime import datetime
56
from typing import Any
67
from uuid import UUID
@@ -313,13 +314,18 @@ async def _provision_users_from_tdei(
313314
await self.session.execute(
314315
text(
315316
"INSERT INTO users (auth_uid, email, display_name, auth_provider, status, pass_crypt, data_public, email_valid, terms_seen, creation_time, terms_agreed, tou_agreed) "
316-
"VALUES (:uid, :email, :name, 'TDEI', 'active', 'none', true, true, true, (now() at time zone 'utc'), (now() at time zone 'utc'), (now() at time zone 'utc')) "
317+
"VALUES (:uid, :email, :name, 'TDEI', 'active', :pass_crypt, true, true, true, (now() at time zone 'utc'), (now() at time zone 'utc'), (now() at time zone 'utc')) "
317318
"ON CONFLICT (auth_uid) DO NOTHING"
318319
),
319320
params={
320321
"uid": uid,
321322
"email": member.email,
322323
"name": member.display_name,
324+
# OSM validates pass_crypt length 8..255; a too-short value
325+
# makes the user invalid and breaks Rails ops that re-validate
326+
# the author (changeset/note comments). TDEI manages auth, so
327+
# this is a throwaway.
328+
"pass_crypt": secrets.token_hex(16),
323329
},
324330
)
325331
resolved.add(uid)

0 commit comments

Comments
 (0)