|
| 1 | +test_authorization_scriptlet() { |
| 2 | + incus config set core.https_address "${INCUS_ADDR}" |
| 3 | + ensure_has_localhost_remote "${INCUS_ADDR}" |
| 4 | + ensure_import_testimage |
| 5 | + |
| 6 | + # Check only valid scriptlets are accepted. |
| 7 | + ! incus config set authorization.scriptlet=foo || false |
| 8 | + |
| 9 | + # Prevent user1 from doing anything, except viewing the server |
| 10 | + cat << EOF | incus config set authorization.scriptlet=- |
| 11 | +def authorize(details, object, entitlement): |
| 12 | + if details.UserName == 'user1': |
| 13 | + return object == 'server:incus' and entitlement == 'can_view' |
| 14 | + return True |
| 15 | +EOF |
| 16 | + |
| 17 | + # Run OIDC server. |
| 18 | + spawn_oidc |
| 19 | + set_oidc user1 |
| 20 | + |
| 21 | + incus config set "oidc.issuer=http://127.0.0.1:$(cat "${TEST_DIR}/oidc.port")/" |
| 22 | + incus config set "oidc.client.id=device" |
| 23 | + |
| 24 | + BROWSER=curl incus remote add --accept-certificate oidc-authorization-scriptlet "${INCUS_ADDR}" --auth-type oidc |
| 25 | + [ "$(incus info oidc-authorization-scriptlet: | grep ^auth_user_name | sed "s/.*: //g")" = "user1" ] |
| 26 | + |
| 27 | + # user1 can’t see anything yet |
| 28 | + [ "$(incus project list oidc-authorization-scriptlet: -f csv | wc -l)" = 0 ] |
| 29 | + [ "$(incus list oidc-authorization-scriptlet: -f csv | wc -l)" = 0 ] |
| 30 | + |
| 31 | + # Let’s fix that |
| 32 | + cat << EOF | incus config set authorization.scriptlet=- |
| 33 | +def authorize(details, object, entitlement): |
| 34 | + if details.UserName == 'user1': |
| 35 | + return object in ['server:incus', 'project:default'] and entitlement == 'can_view' |
| 36 | + return True |
| 37 | +EOF |
| 38 | + |
| 39 | + # user1 can see the project but not create an instance |
| 40 | + [ "$(incus project list oidc-authorization-scriptlet: -f csv | wc -l)" = 1 ] |
| 41 | + [ "$(incus list oidc-authorization-scriptlet: -f csv | wc -l)" = 0 ] |
| 42 | + ! incus init oidc-authorization-scriptlet:testimage oidc-authorization-scriptlet:c1 |
| 43 | + |
| 44 | + # Let’s fix that |
| 45 | + cat << EOF | incus config set authorization.scriptlet=- |
| 46 | +def authorize(details, object, entitlement): |
| 47 | + if details.UserName == 'user1': |
| 48 | + if (object in ['server:incus', 'image_alias:default/testimage'] or object.startswith('image:default/') or object.startswith('instance:default/')): |
| 49 | + return entitlement == 'can_view' |
| 50 | + elif object == 'project:default': |
| 51 | + return entitlement in ['can_view', 'can_create_instances', 'can_view_events'] |
| 52 | + return False |
| 53 | + return True |
| 54 | +EOF |
| 55 | + |
| 56 | + # user1 can create an instance, but not interact with it |
| 57 | + incus init oidc-authorization-scriptlet:testimage oidc-authorization-scriptlet:c1 |
| 58 | + [ "$(incus list oidc-authorization-scriptlet: -f csv | wc -l)" = 1 ] |
| 59 | + ! incus exec oidc-authorization-scriptlet:c1 -- ls -al |
| 60 | + |
| 61 | + # Let’s fix that |
| 62 | + cat << EOF | incus config set authorization.scriptlet=- |
| 63 | +def authorize(details, object, entitlement): |
| 64 | + if details.UserName == 'user1': |
| 65 | + if object == 'instance:default/c1': |
| 66 | + return entitlement in ['can_view', 'can_update_state', 'can_exec'] |
| 67 | + elif (object in ['server:incus', 'image_alias:default/testimage'] or object.startswith('image:default/') or object.startswith('instance:default/')): |
| 68 | + return entitlement == 'can_view' |
| 69 | + elif object == 'project:default': |
| 70 | + return entitlement in ['can_view', 'can_create_instances', 'can_view_events'] |
| 71 | + return False |
| 72 | + return True |
| 73 | +EOF |
| 74 | + |
| 75 | + # user1 can execute commands on c1 but cannot do anything outside of the default project |
| 76 | + incus start oidc-authorization-scriptlet:c1 |
| 77 | + incus exec oidc-authorization-scriptlet:c1 -- ls -al |
| 78 | + ! incus project create oidc-authorization-scriptlet:p1 |
| 79 | + |
| 80 | + # Let’s fix that |
| 81 | + cat << EOF | incus config set authorization.scriptlet=- |
| 82 | +def authorize(details, object, entitlement): |
| 83 | + if details.UserName == 'user1': |
| 84 | + if object == 'instance:default/c1': |
| 85 | + return entitlement in ['can_view', 'can_update_state', 'can_exec'] |
| 86 | + elif object == 'server:incus': |
| 87 | + return entitlement in ['can_view', 'can_create_projects'] |
| 88 | + elif (object == 'image_alias:default/testimage' or object.startswith('image:default/') or object.startswith('instance:default/')): |
| 89 | + return entitlement == 'can_view' |
| 90 | + elif object in ['project:default', 'project:p1']: |
| 91 | + return entitlement in ['can_view', 'can_create_instances', 'can_view_events'] |
| 92 | + return False |
| 93 | + return True |
| 94 | +EOF |
| 95 | + |
| 96 | + incus project create oidc-authorization-scriptlet:p1 |
| 97 | + [ "$(incus project list oidc-authorization-scriptlet: -f csv | wc -l)" = 2 ] |
| 98 | + |
| 99 | + # Let’s now test the two optional scriptlet functions |
| 100 | + cat << EOF | incus config set authorization.scriptlet=- |
| 101 | +def authorize(details, object, entitlement): |
| 102 | + return True |
| 103 | +
|
| 104 | +def get_project_access(project_name): |
| 105 | + if project_name == 'default': |
| 106 | + return ['foo', 'bar'] |
| 107 | + return ['foo'] |
| 108 | +
|
| 109 | +def get_instance_access(project_name, instance_name): |
| 110 | + if project_name == 'default' and instance_name == 'c1': |
| 111 | + return ['foo', 'bar'] |
| 112 | + return ['foo'] |
| 113 | +EOF |
| 114 | + |
| 115 | + [ "$(incus project info default --show-access | wc -l)" = 6 ] |
| 116 | + [ "$(incus project info p1 --show-access | wc -l)" = 3 ] |
| 117 | + [ "$(incus info c1 --show-access | wc -l)" = 6 ] |
| 118 | + incus init testimage c2 |
| 119 | + [ "$(incus info c2 --show-access | wc -l)" = 3 ] |
| 120 | + |
| 121 | + # Cleanup. |
| 122 | + incus delete c1 --force |
| 123 | + incus delete c2 --force |
| 124 | + incus project delete p1 |
| 125 | + |
| 126 | + # Unset config keys. |
| 127 | + kill_oidc |
| 128 | + incus config unset oidc.issuer |
| 129 | + incus config unset oidc.client.id |
| 130 | + incus config unset authorization.scriptlet |
| 131 | + incus remote remove oidc-authorization-scriptlet |
| 132 | +} |
0 commit comments