Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
90.00% covered (success)
90.00%
27 / 30
75.00% covered (warning)
75.00%
3 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
PolicyAuthorizationService
90.00% covered (success)
90.00%
27 / 30
75.00% covered (warning)
75.00%
3 / 4
15.22
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 canUserManageGroupPolicies
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
3
 getManageablePolicyGroupIds
87.50% covered (warning)
87.50%
21 / 24
0.00% covered (danger)
0.00%
0 / 1
10.20
 wasGroupPolicyCreatedBySystemAdmin
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3declare(strict_types=1);
4/**
5 * SPDX-FileCopyrightText: 2026 LibreCode coop and contributors
6 * SPDX-License-Identifier: AGPL-3.0-or-later
7 */
8
9namespace OCA\Libresign\Service\Policy;
10
11use OCA\Libresign\Service\Policy\Model\PolicyLayer;
12use OCA\Libresign\Service\Policy\Provider\RequestSignGroups\RequestSignGroupsPolicy;
13use OCP\Group\ISubAdmin;
14use OCP\IGroup;
15use OCP\IGroupManager;
16use OCP\IUser;
17
18final class PolicyAuthorizationService implements IPolicyAuthorizationService {
19    public function __construct(
20        private IGroupManager $groupManager,
21        private ISubAdmin $subAdmin,
22        private PolicyService $policyService,
23    ) {
24    }
25
26    /**
27     * Check if the user can manage group policies.
28     *
29     * Instance admins and subadmins can manage group policies.
30     * Regular users cannot.
31     */
32    #[\Override]
33    public function canUserManageGroupPolicies(?IUser $user): bool {
34        if ($user === null) {
35            return false;
36        }
37
38        return $this->groupManager->isAdmin($user->getUID())
39            || $this->subAdmin->isSubAdmin($user);
40    }
41
42    /**
43     * Get list of group IDs manageable by the given user.
44     *
45     * For instance admins: returns empty (all groups are manageable).
46     * For subadmins: returns all groups they subadmin-manage, but only after the
47     * request-sign policy itself has been explicitly delegated by the system
48     * administrator (exposed as editable for the current actor).
49     * For regular users: returns empty.
50     *
51     * @return list<string>
52     */
53    #[\Override]
54    public function getManageablePolicyGroupIds(?IUser $user): array {
55        if ($user === null) {
56            return [];
57        }
58
59        // Instance admins do not need a restricted group list
60        // (they have access to all groups at the policy layer)
61        if ($this->groupManager->isAdmin($user->getUID())) {
62            return [];
63        }
64
65        if (!$this->subAdmin->isSubAdmin($user)) {
66            return [];
67        }
68
69        $managedGroupIds = array_values(array_unique(array_filter(array_map(
70            static fn (IGroup $group): string => trim($group->getGID()),
71            $this->subAdmin->getSubAdminsGroups($user),
72        ), static fn (string $groupId): bool => $groupId !== '')));
73
74        if ($managedGroupIds === []) {
75            return [];
76        }
77
78        $requestSignPolicy = $this->policyService->resolveForUser(RequestSignGroupsPolicy::KEY, $user);
79        if (!$requestSignPolicy->isEditableByCurrentActor()) {
80            foreach ($this->policyService->listGroupPoliciesForTargets(RequestSignGroupsPolicy::KEY, $managedGroupIds) as $record) {
81                $policy = $record['policy'] ?? null;
82                if (!$policy instanceof PolicyLayer) {
83                    continue;
84                }
85
86                if (!$this->wasGroupPolicyCreatedBySystemAdmin($policy)) {
87                    return $managedGroupIds;
88                }
89
90                if ($policy->isAllowChildOverride()) {
91                    return $managedGroupIds;
92                }
93            }
94
95            return [];
96        }
97
98        return $managedGroupIds;
99    }
100
101    private function wasGroupPolicyCreatedBySystemAdmin(PolicyLayer $policy): bool {
102        return $policy->isCreatedBySystemAdmin();
103    }
104}