From 6dfcd68e17bd635dc6feb12b1b0dc0c28f0d3dfa Mon Sep 17 00:00:00 2001 From: Benjamin Somers Date: Fri, 6 Dec 2024 15:45:50 +0000 Subject: [PATCH] tests: Authorization scriptlet Signed-off-by: Benjamin Somers --- test/suites/authorization_scriptlet.sh | 132 +++++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 test/suites/authorization_scriptlet.sh diff --git a/test/suites/authorization_scriptlet.sh b/test/suites/authorization_scriptlet.sh new file mode 100644 index 00000000000..7e72f3a446f --- /dev/null +++ b/test/suites/authorization_scriptlet.sh @@ -0,0 +1,132 @@ +test_authorization_scriptlet() { + incus config set core.https_address "${INCUS_ADDR}" + ensure_has_localhost_remote "${INCUS_ADDR}" + ensure_import_testimage + + # Check only valid scriptlets are accepted. + ! incus config set authorization.scriptlet=foo || false + + # Prevent user1 from doing anything, except viewing the server + cat << EOF | incus config set authorization.scriptlet=- +def authorize(details, object, entitlement): + if details.Username == 'user1': + return object == 'server:incus' and entitlement == 'can_view' + return True +EOF + + # Run OIDC server. + spawn_oidc + set_oidc user1 + + incus config set "oidc.issuer=http://127.0.0.1:$(cat "${TEST_DIR}/oidc.port")/" + incus config set "oidc.client.id=device" + + BROWSER=curl incus remote add --accept-certificate oidc-authorization-scriptlet "${INCUS_ADDR}" --auth-type oidc + [ "$(incus info oidc-authorization-scriptlet: | grep ^auth_user_name | sed "s/.*: //g")" = "user1" ] + + # user1 can’t see anything yet + [ "$(incus project list oidc-authorization-scriptlet: -f csv | wc -l)" = 0 ] + [ "$(incus list oidc-authorization-scriptlet: -f csv | wc -l)" = 0 ] + + # Let’s fix that + cat << EOF | incus config set authorization.scriptlet=- +def authorize(details, object, entitlement): + if details.Username == 'user1': + return object in ['server:incus', 'project:default'] and entitlement == 'can_view' + return True +EOF + + # user1 can see the project but not create an instance + [ "$(incus project list oidc-authorization-scriptlet: -f csv | wc -l)" = 1 ] + [ "$(incus list oidc-authorization-scriptlet: -f csv | wc -l)" = 0 ] + ! incus init oidc-authorization-scriptlet:testimage oidc-authorization-scriptlet:c1 + + # Let’s fix that + cat << EOF | incus config set authorization.scriptlet=- +def authorize(details, object, entitlement): + if details.Username == 'user1': + if (object in ['server:incus', 'image_alias:default/testimage'] or object.startswith('image:default/') or object.startswith('instance:default/')): + return entitlement == 'can_view' + elif object == 'project:default': + return entitlement in ['can_view', 'can_create_instances', 'can_view_events'] + return False + return True +EOF + + # user1 can create an instance, but not interact with it + incus init oidc-authorization-scriptlet:testimage oidc-authorization-scriptlet:c1 + [ "$(incus list oidc-authorization-scriptlet: -f csv | wc -l)" = 1 ] + ! incus exec oidc-authorization-scriptlet:c1 -- ls -al + + # Let’s fix that + cat << EOF | incus config set authorization.scriptlet=- +def authorize(details, object, entitlement): + if details.Username == 'user1': + if object == 'instance:default/c1': + return entitlement in ['can_view', 'can_update_state', 'can_exec'] + elif (object in ['server:incus', 'image_alias:default/testimage'] or object.startswith('image:default/') or object.startswith('instance:default/')): + return entitlement == 'can_view' + elif object == 'project:default': + return entitlement in ['can_view', 'can_create_instances', 'can_view_events'] + return False + return True +EOF + + # user1 can execute commands on c1 but cannot do anything outside of the default project + incus start oidc-authorization-scriptlet:c1 + incus exec oidc-authorization-scriptlet:c1 -- ls -al + ! incus project create oidc-authorization-scriptlet:p1 + + # Let’s fix that + cat << EOF | incus config set authorization.scriptlet=- +def authorize(details, object, entitlement): + if details.Username == 'user1': + if object == 'instance:default/c1': + return entitlement in ['can_view', 'can_update_state', 'can_exec'] + elif object == 'server:incus': + return entitlement in ['can_view', 'can_create_projects'] + elif (object == 'image_alias:default/testimage' or object.startswith('image:default/') or object.startswith('instance:default/')): + return entitlement == 'can_view' + elif object in ['project:default', 'project:p1']: + return entitlement in ['can_view', 'can_create_instances', 'can_view_events'] + return False + return True +EOF + + incus project create oidc-authorization-scriptlet:p1 + [ "$(incus project list oidc-authorization-scriptlet: -f csv | wc -l)" = 2 ] + + # Let’s now test the two optional scriptlet functions + cat << EOF | incus config set authorization.scriptlet=- +def authorize(details, object, entitlement): + return True + +def get_project_access(project_name): + if project_name == 'default': + return ['foo', 'bar'] + return ['foo'] + +def get_instance_access(project_name, instance_name): + if project_name == 'default' and instance_name == 'c1': + return ['foo', 'bar'] + return ['foo'] +EOF + + [ "$(incus project info default --show-access | wc -l)" = 6 ] + [ "$(incus project info p1 --show-access | wc -l)" = 3 ] + [ "$(incus info c1 --show-access | wc -l)" = 6 ] + incus init testimage c2 + [ "$(incus info c2 --show-access | wc -l)" = 3 ] + + # Cleanup. + incus delete c1 --force + incus delete c2 --force + incus project delete p1 + + # Unset config keys. + kill_oidc + incus config unset oidc.issuer + incus config unset oidc.client.id + incus config unset authorization.scriptlet + incus remote remove oidc-authorization-scriptlet +}