blob: 705d9c365f8f1ffb001d4ceb0d6e2049efefcb23 [file] [log] [blame]
Thomas Lea87f62772024-08-27 13:27:10 -05001/*
2 *
3 * Copyright (c) 2024 Project CHIP Authors
4 * All rights reserved.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19#pragma once
20
21#include "Privilege.h"
22#include "RequestPath.h"
23#include "SubjectDescriptor.h"
24#include <algorithm>
25#include <app-common/zap-generated/cluster-objects.h>
26#include <cstdint>
27#include <lib/core/CHIPError.h>
28#include <lib/core/DataModelTypes.h>
29#include <lib/core/Optional.h>
30#include <lib/support/CHIPMem.h>
31#include <map>
32#include <memory>
33#include <protocols/interaction_model/Constants.h>
34#include <vector>
35
36namespace chip {
37namespace Access {
38
39class AccessRestrictionProvider
40{
41public:
42 static constexpr size_t kNumberOfFabrics = CHIP_CONFIG_MAX_FABRICS;
43 static constexpr size_t kEntriesPerFabric = CHIP_CONFIG_ACCESS_RESTRICTION_MAX_ENTRIES_PER_FABRIC;
44 static constexpr size_t kRestrictionsPerEntry = CHIP_CONFIG_ACCESS_RESTRICTION_MAX_RESTRICTIONS_PER_ENTRY;
45
46 /**
47 * Defines the type of access restriction, which is used to determine the meaning of the restriction's id.
48 */
49 enum class Type : uint8_t
50 {
51 kAttributeAccessForbidden = 0,
52 kAttributeWriteForbidden = 1,
53 kCommandForbidden = 2,
54 kEventForbidden = 3
55 };
56
57 /**
58 * Defines a single restriction on an attribute, command, or event.
59 *
60 * If id is not set, the restriction applies to all attributes, commands, or events of the given type (wildcard).
61 */
62 struct Restriction
63 {
64 Type restrictionType;
65 Optional<uint32_t> id;
66 };
67
68 /**
69 * Defines a single entry in the access restriction list, which contains a list of restrictions
70 * for a cluster on an endpoint.
71 */
72 struct Entry
73 {
74 FabricIndex fabricIndex;
75 EndpointId endpointNumber;
76 ClusterId clusterId;
77 std::vector<Restriction> restrictions;
78 };
79
80 /**
81 * Defines the interface for a checker for access restriction exceptions.
82 */
83 class AccessRestrictionExceptionChecker
84 {
85 public:
86 virtual ~AccessRestrictionExceptionChecker() = default;
87
88 /**
89 * Check if any restrictions are allowed to be applied on the given endpoint and cluster
90 * because of constraints against their use in ARLs.
91 *
92 * @retval true if ARL checks are allowed to be applied to the cluster on the endpoint, false otherwise
93 */
94 virtual bool AreRestrictionsAllowed(EndpointId endpoint, ClusterId cluster) = 0;
95 };
96
97 /**
98 * Define a standard implementation of the AccessRestrictionExceptionChecker interface
99 * which is the default implementation used by AccessResrictionProvider.
100 */
101 class StandardAccessRestrictionExceptionChecker : public AccessRestrictionExceptionChecker
102 {
103 public:
104 StandardAccessRestrictionExceptionChecker() = default;
105 ~StandardAccessRestrictionExceptionChecker() = default;
106
107 bool AreRestrictionsAllowed(EndpointId endpoint, ClusterId cluster) override;
108 };
109
110 /**
111 * Used to notify of changes in the access restriction list and active reviews.
112 */
113 class Listener
114 {
115 public:
116 virtual ~Listener() = default;
117
118 /**
119 * Notifies of a change in the commissioning access restriction list.
120 */
121 virtual void MarkCommissioningRestrictionListChanged() = 0;
122
123 /**
124 * Notifies of a change in the access restriction list.
125 *
126 * @param [in] fabricIndex The index of the fabric in which the list has changed.
127 */
128 virtual void MarkRestrictionListChanged(FabricIndex fabricIndex) = 0;
129
130 /**
131 * Notifies of an update to an active review with instructions and an optional redirect URL.
132 *
133 * @param [in] fabricIndex The index of the fabric in which the entry has changed.
134 * @param [in] token The token of the review being updated (obtained from ReviewFabricRestrictionsResponse)
135 * @param [in] instruction Optional instructions to be displayed to the user.
136 * @param [in] redirectUrl An optional URL to redirect the user to for more information.
137 */
138 virtual void OnFabricRestrictionReviewUpdate(FabricIndex fabricIndex, uint64_t token, Optional<CharSpan> instruction,
139 Optional<CharSpan> redirectUrl) = 0;
140
141 private:
142 Listener * mNext = nullptr;
143
144 friend class AccessRestrictionProvider;
145 };
146
147 AccessRestrictionProvider() = default;
148 virtual ~AccessRestrictionProvider() = default;
149
150 AccessRestrictionProvider(const AccessRestrictionProvider &) = delete;
151 AccessRestrictionProvider & operator=(const AccessRestrictionProvider &) = delete;
152
153 /**
154 * Set the restriction entries that are to be used during commissioning when there is no accessing fabric.
155 *
156 * @param [in] entries The entries to set.
157 */
158 CHIP_ERROR SetCommissioningEntries(const std::vector<Entry> & entries);
159
160 /**
161 * Set the restriction entries for a fabric.
162 *
163 * @param [in] fabricIndex The index of the fabric for which to create entries.
164 * @param [in] entries The entries to set for the fabric.
165 */
166 CHIP_ERROR SetEntries(const FabricIndex, const std::vector<Entry> & entries);
167
168 /**
169 * Add a listener to be notified of changes in the access restriction list and active reviews.
170 *
171 * @param [in] listener The listener to add.
172 */
173 void AddListener(Listener & listener);
174
175 /**
176 * Remove a listener from being notified of changes in the access restriction list and active reviews.
177 *
178 * @param [in] listener The listener to remove.
179 */
180 void RemoveListener(Listener & listener);
181
182 /**
183 * Check whether access by a subject descriptor to a request path should be restricted (denied) for the given action
184 * during commissioning by using the CommissioningEntries.
185 *
186 * These restrictions are are only a part of overall access evaluation.
187 *
188 * If access is not restricted, CHIP_NO_ERROR will be returned.
189 *
190 * @retval CHIP_ERROR_ACCESS_DENIED if access is denied.
191 * @retval other errors should also be treated as restricted/denied.
192 * @retval CHIP_NO_ERROR if access is not restricted/denied.
193 */
194 CHIP_ERROR CheckForCommissioning(const SubjectDescriptor & subjectDescriptor, const RequestPath & requestPath);
195
196 /**
197 * Check whether access by a subject descriptor to a request path should be restricted (denied) for the given action.
198 * These restrictions are are only a part of overall access evaluation.
199 *
200 * If access is not restricted, CHIP_NO_ERROR will be returned.
201 *
202 * @retval CHIP_ERROR_ACCESS_DENIED if access is denied.
203 * @retval other errors should also be treated as restricted/denied.
204 * @retval CHIP_NO_ERROR if access is not restricted/denied.
205 */
206 CHIP_ERROR Check(const SubjectDescriptor & subjectDescriptor, const RequestPath & requestPath);
207
208 /**
209 * Request a review of the access restrictions for a fabric.
210 *
211 * @param [in] fabricIndex The index of the fabric requesting a review.
212 * @param [in] arl An optinal list of access restriction entries to review. If null, all entries will be reviewed.
213 * @param [out] token The unique token for the review, which can be matched to a review update event.
214 */
215 CHIP_ERROR RequestFabricRestrictionReview(FabricIndex fabricIndex, const std::vector<Entry> & arl, uint64_t & token)
216 {
217 token = mNextToken++;
218 return DoRequestFabricRestrictionReview(fabricIndex, token, arl);
219 }
220
221 /**
222 * Get the commissioning restriction entries.
223 *
224 * @retval the commissioning restriction entries.
225 */
226 const std::vector<Entry> & GetCommissioningEntries() const { return mCommissioningEntries; }
227
228 /**
229 * Get the restriction entries for a fabric.
230 *
231 * @param [in] fabricIndex the index of the fabric for which to get entries.
232 * @param [out] entries vector to hold the entries.
233 */
234 CHIP_ERROR GetEntries(const FabricIndex fabricIndex, std::vector<Entry> & entries) const
235 {
236 auto it = mFabricEntries.find(fabricIndex);
237 if (it == mFabricEntries.end())
238 {
239 return CHIP_ERROR_NOT_FOUND;
240 }
241
242 entries = (it->second);
243
244 return CHIP_NO_ERROR;
245 }
246
247protected:
248 /**
249 * Initiate a review of the access restrictions for a fabric. This method should be implemented by the platform and be
250 * non-blocking.
251 *
252 * @param [in] fabricIndex The index of the fabric requesting a review.
253 * @param [in] token The unique token for the review, which can be matched to a review update event.
254 * @param [in] arl An optinal list of access restriction entries to review. If null, all entries will be reviewed.
255 * @return CHIP_NO_ERROR if the review was successfully requested, or an error code if the request failed.
256 */
257 virtual CHIP_ERROR DoRequestFabricRestrictionReview(const FabricIndex fabricIndex, uint64_t token,
258 const std::vector<Entry> & arl) = 0;
259
260private:
261 /**
262 * Perform the access restriction check using the given entries.
263 */
264 CHIP_ERROR DoCheck(const std::vector<Entry> & entries, const SubjectDescriptor & subjectDescriptor,
265 const RequestPath & requestPath);
266
267 uint64_t mNextToken = 1;
268 Listener * mListeners = nullptr;
269 StandardAccessRestrictionExceptionChecker mExceptionChecker;
270 std::vector<Entry> mCommissioningEntries;
271 std::map<FabricIndex, std::vector<Entry>> mFabricEntries;
272};
273
274} // namespace Access
275} // namespace chip