chore(auth): generalize authentication method to internals of NixOS module

This makes it easier to make it configurable, this is step 1.

Signed-off-by: Raito Bezarius <raito@lix.systems>
This commit is contained in:
raito 2024-05-06 19:52:55 +02:00 committed by Jade Lovelace
parent 16726a55bf
commit d284a8bc77
2 changed files with 54 additions and 16 deletions

View file

@ -15,6 +15,7 @@ from buildbot.process import buildstep, logobserver, remotecommand
from buildbot.process.project import Project from buildbot.process.project import Project
from buildbot.process.properties import Properties from buildbot.process.properties import Properties
from buildbot.process.results import ALL_RESULTS, statusToString from buildbot.process.results import ALL_RESULTS, statusToString
from buildbot.www.auth import AuthBase
from buildbot.www.oauth2 import OAuth2Auth from buildbot.www.oauth2 import OAuth2Auth
from buildbot.changes.gerritchangesource import GerritChangeSource from buildbot.changes.gerritchangesource import GerritChangeSource
from buildbot.reporters.utils import getURLForBuildrequest from buildbot.reporters.utils import getURLForBuildrequest
@ -33,14 +34,22 @@ from .binary_cache import S3BinaryCacheConfig
log = Logger() log = Logger()
class LixSystemsOAuth2(OAuth2Auth): @dataclass
name = 'Lix' class OAuth2Config:
faIcon = 'fa-login' name: str
resourceEndpoint = "https://identity.lix.systems/realms/lix-project/protocol/openid-connect" faIcon: str
sslVerify = True resourceEndpoint: str
debug = False authUri: str
authUri = 'https://identity.lix.systems/realms/lix-project/protocol/openid-connect/auth' tokenUri: str
tokenUri = 'https://identity.lix.systems/realms/lix-project/protocol/openid-connect/token' userinfoUri: str
sslVerify: bool = True
debug: bool = False
class KeycloakOAuth2Auth(OAuth2Auth):
def __init__(self, userinfoUri: str, *args, debug=False, **kwargs):
super().__init__(*args, **kwargs)
self.userinfoUri = userinfoUri
self.debug = debug
def createSessionFromToken(self, token): def createSessionFromToken(self, token):
s = requests.Session() s = requests.Session()
@ -54,15 +63,26 @@ class LixSystemsOAuth2(OAuth2Auth):
return s return s
def getUserInfoFromOAuthClient(self, c): def getUserInfoFromOAuthClient(self, c):
userinfo_resp = c.get("https://identity.lix.systems/realms/lix-project/protocol/openid-connect/userinfo") userinfo_resp = c.get(self.userinfoUri)
log.info("Userinfo request to Lix OAuth2: {}".format(userinfo_resp.status_code)) log.info("Userinfo request to OAuth2: {}".format(userinfo_resp.status_code))
if userinfo_resp.status_code != 200: if userinfo_resp.status_code != 200:
log.info("Userinfo failure: {}".format(userinfo_resp.headers["www-authenticate"])) log.error("Userinfo failure: {}".format(userinfo_resp.headers["www-authenticate"]))
userinfo_resp.raise_for_status()
userinfo_data = userinfo_resp.json() userinfo_data = userinfo_resp.json()
return { return {
'groups': userinfo_data['buildbot_roles'] 'groups': userinfo_data['buildbot_roles']
} }
def make_oauth2_method(oauth2_config: OAuth2Config):
"""
This constructs dynamically a class inheriting
an OAuth2 base configured using a dataclass.
"""
return type(f'{oauth2_config.name}DynamicOAuth2',
(KeycloakOAuth2Auth,),
oauth2_config.__dict__)
class BuildbotNixError(Exception): class BuildbotNixError(Exception):
pass pass
@ -737,6 +757,7 @@ class GerritNixConfigurator(ConfiguratorBase):
signing_keyfile: str | None = None, signing_keyfile: str | None = None,
prometheus_config: dict[str, int | str] | None = None, prometheus_config: dict[str, int | str] | None = None,
binary_cache_config: dict[str, str] | None = None, binary_cache_config: dict[str, str] | None = None,
auth_method: AuthBase | None = None,
) -> None: ) -> None:
super().__init__() super().__init__()
self.gerrit_server = gerrit_server self.gerrit_server = gerrit_server
@ -762,6 +783,8 @@ class GerritNixConfigurator(ConfiguratorBase):
self.signing_keyfile = signing_keyfile self.signing_keyfile = signing_keyfile
self.auth_method = auth_method
def configure(self, config: dict[str, Any]) -> None: def configure(self, config: dict[str, Any]) -> None:
worker_config = json.loads(read_secret_file(self.nix_workers_secret_name)) worker_config = json.loads(read_secret_file(self.nix_workers_secret_name))
worker_names = [] worker_names = []
@ -841,9 +864,6 @@ class GerritNixConfigurator(ConfiguratorBase):
config["www"].setdefault("plugins", {}) config["www"].setdefault("plugins", {})
if "auth" not in config["www"]:
config["www"]["auth"] = LixSystemsOAuth2('buildbot', read_secret_file('buildbot-oauth2-secret'), autologin=False)
if "authz" not in config["www"]: if "authz" not in config["www"]:
config["www"]["authz"] = util.Authz( config["www"]["authz"] = util.Authz(
allowRules=[ allowRules=[
@ -858,3 +878,6 @@ class GerritNixConfigurator(ConfiguratorBase):
util.RolesFromOwner(role="owner") util.RolesFromOwner(role="owner")
], ],
) )
if "auth" not in config["www"] and self.auth_method is not None:
config["www"]["auth"] = self.auth_method

View file

@ -158,13 +158,24 @@ in
home = "/var/lib/buildbot"; home = "/var/lib/buildbot";
extraImports = '' extraImports = ''
from datetime import timedelta from datetime import timedelta
from buildbot_nix import GerritNixConfigurator from buildbot_nix import GerritNixConfigurator, read_secret_file
''; '';
configurators = [ configurators = [
'' ''
util.JanitorConfigurator(logHorizon=timedelta(weeks=4), hour=12, dayOfWeek=6) util.JanitorConfigurator(logHorizon=timedelta(weeks=4), hour=12, dayOfWeek=6)
'' ''
'' ''
# TODO(raito): make me configurable from the NixOS module.
# how?
LixSystemsOAuth2 = make_oauth2_method(OAuth2Config(
name='Lix',
faIcon='fa-login',
resourceEndpoint='https://identity.lix.systems',
authUri='https://identity.lix.systems/realms/lix-project/protocol/openid-connect/auth',
tokenUri='https://identity.lix.systems/realms/lix-project/protocol/openid-connect/token',
userinfoUri='https://identity.lix.systems/realms/lix-project/protocol/openid-connect/userinfo'
)
GerritNixConfigurator( GerritNixConfigurator(
"${cfg.gerrit.domain}", "${cfg.gerrit.domain}",
"${cfg.gerrit.username}", "${cfg.gerrit.username}",
@ -183,7 +194,11 @@ in
binary_cache_config=${if (!cfg.binaryCache.enable) then "None" else builtins.toJSON { binary_cache_config=${if (!cfg.binaryCache.enable) then "None" else builtins.toJSON {
inherit (cfg.binaryCache) bucket region endpoint; inherit (cfg.binaryCache) bucket region endpoint;
profile = "default"; profile = "default";
}} }},
auth_method=LixSystemsOAuth2('buildbot',
read_secret_file('buildbot-oauth2-secret'),
autologin=True
)
) )
'' ''
]; ];