From f2d7f25f866da65da717f67be4a739ba06db0dcd Mon Sep 17 00:00:00 2001 From: Raito Bezarius Date: Sun, 9 Jun 2024 17:01:32 +0200 Subject: [PATCH] feat: enable Lix admins to admin the Buildbot properly This removes the need for a proxy and rely on the `groups` property of the `userDetails` passed at the authentication layer. To add a certain role, add the group `buildbot-$role` to that user via Keycloak. Signed-off-by: Raito Bezarius --- buildbot_nix/__init__.py | 44 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/buildbot_nix/__init__.py b/buildbot_nix/__init__.py index 8ccba85..59959f6 100644 --- a/buildbot_nix/__init__.py +++ b/buildbot_nix/__init__.py @@ -9,6 +9,7 @@ from dataclasses import dataclass from pathlib import Path from typing import TYPE_CHECKING, Any +import buildbot from buildbot.configurators import ConfiguratorBase from buildbot.plugins import reporters, schedulers, secrets, steps, util, worker from buildbot.process import buildstep, logobserver, remotecommand @@ -17,7 +18,6 @@ from buildbot.process.properties import Interpolate, Properties from buildbot.process.results import ALL_RESULTS, statusToString from buildbot.steps.trigger import Trigger from buildbot.util import asyncSleep -from buildbot.www.authz.endpointmatchers import EndpointMatcherBase, Match from buildbot.www.oauth2 import OAuth2Auth from buildbot.changes.gerritchangesource import GerritChangeSource from buildbot.reporters.utils import getURLForBuild @@ -27,6 +27,7 @@ from buildbot.process.buildstep import EXCEPTION from buildbot.process.buildstep import SUCCESS from buildbot.process.results import worst_status from buildbot_nix.binary_cache import LocalSigner +import requests if TYPE_CHECKING: from buildbot.process.log import Log @@ -46,11 +47,33 @@ log = Logger() class LixSystemsOAuth2(OAuth2Auth): name = 'Lix' faIcon = 'fa-login' - resourceEndpoint = "https://identity.lix.systems" - # is passing scope necessary? + resourceEndpoint = "https://identity.lix.systems/realms/lix-project/protocol/openid-connect" + sslVerify = True + debug = False authUri = 'https://identity.lix.systems/realms/lix-project/protocol/openid-connect/auth' tokenUri = 'https://identity.lix.systems/realms/lix-project/protocol/openid-connect/token' + def createSessionFromToken(self, token): + s = requests.Session() + s.headers = { + 'Authorization': 'Bearer ' + token['access_token'], + 'User-Agent': f'buildbot/{buildbot.version}', + } + if self.debug: + log.info("Token obtained: {}".format(token)) + s.verify = self.sslVerify + return s + + def getUserInfoFromOAuthClient(self, c): + userinfo_resp = c.get("https://identity.lix.systems/realms/lix-project/protocol/openid-connect/userinfo") + log.info("Userinfo request to Lix OAuth2: {}".format(userinfo_resp.status_code)) + if userinfo_resp.status_code != 200: + log.info("Userinfo failure: {}".format(userinfo_resp.headers["www-authenticate"])) + userinfo_data = userinfo_resp.json() + return { + 'groups': userinfo_data['buildbot_roles'] + } + class BuildbotNixError(Exception): pass @@ -901,3 +924,18 @@ class GerritNixConfigurator(ConfiguratorBase): if "auth" not in config["www"]: config["www"]["auth"] = LixSystemsOAuth2('buildbot', read_secret_file('buildbot-oauth2-secret'), autologin=True) + + if "authz" not in config["www"]: + config["www"]["authz"] = util.Authz( + allowRules=[ + util.AnyEndpointMatcher(role="admin", defaultDeny=False), + util.StopBuildEndpointMatcher(role="owner"), + util.AnyControlEndpointMatcher(role="admin"), + ], + roleMatchers=[ + # A user must have buildbot- to have the role + # e.g. buildbot-admin to be admin. + util.RolesFromGroups(groupPrefix="buildbot-"), + util.RolesFromOwner(role="owner") + ], + )