mirror of
https://git.yoctoproject.org/poky
synced 2026-02-08 01:36:38 +01:00
Adds support for the hashserver to have per-user permissions. User management is done via a new "auth" RPC API where a client can authenticate itself with the server using a randomly generated token. The user can then be given permissions to read, report, manage the database, or manage other users. In addition to explicit user logins, the server supports anonymous users which is what all users start as before they make the "auth" RPC call. Anonymous users can be assigned a set of permissions by the server, making it unnecessary for users to authenticate to use the server. The set of Anonymous permissions defines the default behavior of the server, for example if set to "@read", Anonymous users are unable to report equivalent hashes with authenticating. Similarly, setting the Anonymous permissions to "@none" would require authentication for users to perform any action. User creation and management is entirely manual (although bitbake-hashclient is very useful as a front end). There are many different mechanisms that could be implemented to allow user self-registration (e.g. OAuth, LDAP, etc.), and implementing these is outside the scope of the server. Instead, it is recommended to implement a registration service that validates users against the necessary service, then adds them as a user in the hash equivalence server. (Bitbake rev: 69e5417413ee2414fffaa7dd38057573bac56e35) Signed-off-by: Joshua Watt <JPEWhacker@gmail.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
132 lines
2.9 KiB
Python
132 lines
2.9 KiB
Python
# Copyright (C) 2018-2019 Garmin Ltd.
|
|
#
|
|
# SPDX-License-Identifier: GPL-2.0-only
|
|
#
|
|
|
|
import asyncio
|
|
from contextlib import closing
|
|
import re
|
|
import itertools
|
|
import json
|
|
from collections import namedtuple
|
|
from urllib.parse import urlparse
|
|
|
|
UNIX_PREFIX = "unix://"
|
|
WS_PREFIX = "ws://"
|
|
WSS_PREFIX = "wss://"
|
|
|
|
ADDR_TYPE_UNIX = 0
|
|
ADDR_TYPE_TCP = 1
|
|
ADDR_TYPE_WS = 2
|
|
|
|
User = namedtuple("User", ("username", "permissions"))
|
|
|
|
|
|
def parse_address(addr):
|
|
if addr.startswith(UNIX_PREFIX):
|
|
return (ADDR_TYPE_UNIX, (addr[len(UNIX_PREFIX) :],))
|
|
elif addr.startswith(WS_PREFIX) or addr.startswith(WSS_PREFIX):
|
|
return (ADDR_TYPE_WS, (addr,))
|
|
else:
|
|
m = re.match(r"\[(?P<host>[^\]]*)\]:(?P<port>\d+)$", addr)
|
|
if m is not None:
|
|
host = m.group("host")
|
|
port = m.group("port")
|
|
else:
|
|
host, port = addr.split(":")
|
|
|
|
return (ADDR_TYPE_TCP, (host, int(port)))
|
|
|
|
|
|
def create_server(
|
|
addr,
|
|
dbname,
|
|
*,
|
|
sync=True,
|
|
upstream=None,
|
|
read_only=False,
|
|
db_username=None,
|
|
db_password=None,
|
|
anon_perms=None,
|
|
admin_username=None,
|
|
admin_password=None,
|
|
):
|
|
def sqlite_engine():
|
|
from .sqlite import DatabaseEngine
|
|
|
|
return DatabaseEngine(dbname, sync)
|
|
|
|
def sqlalchemy_engine():
|
|
from .sqlalchemy import DatabaseEngine
|
|
|
|
return DatabaseEngine(dbname, db_username, db_password)
|
|
|
|
from . import server
|
|
|
|
if "://" in dbname:
|
|
db_engine = sqlalchemy_engine()
|
|
else:
|
|
db_engine = sqlite_engine()
|
|
|
|
if anon_perms is None:
|
|
anon_perms = server.DEFAULT_ANON_PERMS
|
|
|
|
s = server.Server(
|
|
db_engine,
|
|
upstream=upstream,
|
|
read_only=read_only,
|
|
anon_perms=anon_perms,
|
|
admin_username=admin_username,
|
|
admin_password=admin_password,
|
|
)
|
|
|
|
(typ, a) = parse_address(addr)
|
|
if typ == ADDR_TYPE_UNIX:
|
|
s.start_unix_server(*a)
|
|
elif typ == ADDR_TYPE_WS:
|
|
url = urlparse(a[0])
|
|
s.start_websocket_server(url.hostname, url.port)
|
|
else:
|
|
s.start_tcp_server(*a)
|
|
|
|
return s
|
|
|
|
|
|
def create_client(addr, username=None, password=None):
|
|
from . import client
|
|
|
|
c = client.Client(username, password)
|
|
|
|
try:
|
|
(typ, a) = parse_address(addr)
|
|
if typ == ADDR_TYPE_UNIX:
|
|
c.connect_unix(*a)
|
|
elif typ == ADDR_TYPE_WS:
|
|
c.connect_websocket(*a)
|
|
else:
|
|
c.connect_tcp(*a)
|
|
return c
|
|
except Exception as e:
|
|
c.close()
|
|
raise e
|
|
|
|
|
|
async def create_async_client(addr, username=None, password=None):
|
|
from . import client
|
|
|
|
c = client.AsyncClient(username, password)
|
|
|
|
try:
|
|
(typ, a) = parse_address(addr)
|
|
if typ == ADDR_TYPE_UNIX:
|
|
await c.connect_unix(*a)
|
|
elif typ == ADDR_TYPE_WS:
|
|
await c.connect_websocket(*a)
|
|
else:
|
|
await c.connect_tcp(*a)
|
|
|
|
return c
|
|
except Exception as e:
|
|
await c.close()
|
|
raise e
|