1914e6f28e
Creates or updates a user from an OAuth2 provider: new users are inserted with an empty password_hash (OAuth-only login); existing users have their display name and avatar refreshed while all other attributes (admin flag, password_hash, notification_channels) are preserved. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
119 lines
3.1 KiB
Python
119 lines
3.1 KiB
Python
import time as time_mod
|
|
|
|
import pytest
|
|
|
|
from hbd.server import oauth
|
|
|
|
|
|
CFG_OFF = {}
|
|
CFG_ON = {
|
|
"oauth": {
|
|
"gitea": {
|
|
"url": "https://git.example.com",
|
|
"client_id": "cid",
|
|
"client_secret": "csec",
|
|
}
|
|
}
|
|
}
|
|
CFG_PARTIAL = {"oauth": {"gitea": {"url": "https://git.example.com"}}}
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def clear_oauth_states():
|
|
oauth._states.clear()
|
|
yield
|
|
oauth._states.clear()
|
|
|
|
|
|
def test_is_enabled_when_all_keys_present():
|
|
assert oauth.is_enabled(CFG_ON) is True
|
|
|
|
|
|
def test_is_enabled_false_when_no_oauth_key():
|
|
assert oauth.is_enabled(CFG_OFF) is False
|
|
|
|
|
|
def test_is_enabled_false_when_partial_config():
|
|
assert oauth.is_enabled(CFG_PARTIAL) is False
|
|
|
|
|
|
def test_make_state_returns_unique_tokens():
|
|
s1 = oauth.make_state()
|
|
s2 = oauth.make_state()
|
|
assert s1 != s2
|
|
assert len(s1) == 64 # 32 bytes hex
|
|
|
|
|
|
def test_validate_state_valid():
|
|
state = oauth.make_state()
|
|
assert oauth.validate_state(state) is True
|
|
|
|
|
|
def test_validate_state_consumed_on_use():
|
|
state = oauth.make_state()
|
|
oauth.validate_state(state)
|
|
assert oauth.validate_state(state) is False # replay rejected
|
|
|
|
|
|
def test_validate_state_unknown():
|
|
assert oauth.validate_state("notastate") is False
|
|
|
|
|
|
def test_validate_state_expired(monkeypatch):
|
|
state = oauth.make_state()
|
|
# Wind expiry into the past
|
|
monkeypatch.setitem(oauth._states, state, time_mod.time() - 1000)
|
|
assert oauth.validate_state(state) is False
|
|
|
|
|
|
from hbd.server import users as users_mod
|
|
from hbd.server.users import User
|
|
|
|
|
|
def _reset_users(entries=None):
|
|
users_mod.users = entries or {}
|
|
|
|
|
|
def test_provision_oauth_user_new():
|
|
_reset_users()
|
|
user = users_mod.provision_oauth_user("gituser", "Git User", "https://example.com/avatar.png")
|
|
assert user.username == "gituser"
|
|
assert user.full_name == "Git User"
|
|
assert user.avatar == "https://example.com/avatar.png"
|
|
assert user.admin is False
|
|
assert user.password_hash == ""
|
|
assert "gituser" in users_mod.users
|
|
|
|
|
|
def test_provision_oauth_user_no_password_login():
|
|
_reset_users()
|
|
user = users_mod.provision_oauth_user("gituser", "Git User", "")
|
|
assert user.check_password("anything") is False
|
|
|
|
|
|
def test_provision_oauth_user_existing_updates_profile():
|
|
existing = User(
|
|
username="alice",
|
|
full_name="Old Name",
|
|
avatar="old.png",
|
|
password_hash="pbkdf2:sha256:1:salt:abc",
|
|
admin=True,
|
|
notification_channels=["chan1"],
|
|
)
|
|
_reset_users({"alice": existing})
|
|
user = users_mod.provision_oauth_user("alice", "New Name", "new.png")
|
|
assert user.full_name == "New Name"
|
|
assert user.avatar == "new.png"
|
|
# Preserved
|
|
assert user.admin is True
|
|
assert user.password_hash == "pbkdf2:sha256:1:salt:abc"
|
|
assert user.notification_channels == ["chan1"]
|
|
|
|
|
|
def test_provision_oauth_user_does_not_overwrite_with_empty():
|
|
existing = User(username="bob", full_name="Bob", avatar="bob.png")
|
|
_reset_users({"bob": existing})
|
|
user = users_mod.provision_oauth_user("bob", "", "")
|
|
assert user.full_name == "Bob"
|
|
assert user.avatar == "bob.png"
|