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:
parent
16726a55bf
commit
d284a8bc77
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
)
|
||||||
)
|
)
|
||||||
''
|
''
|
||||||
];
|
];
|
||||||
|
|
Loading…
Reference in a new issue