|  | /* | 
|  | * | 
|  | *    Copyright (c) 2024 Project CHIP Authors | 
|  | *    All rights reserved. | 
|  | * | 
|  | *    Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | *    you may not use this file except in compliance with the License. | 
|  | *    You may obtain a copy of the License at | 
|  | * | 
|  | *        http://www.apache.org/licenses/LICENSE-2.0 | 
|  | * | 
|  | *    Unless required by applicable law or agreed to in writing, software | 
|  | *    distributed under the License is distributed on an "AS IS" BASIS, | 
|  | *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | *    See the License for the specific language governing permissions and | 
|  | *    limitations under the License. | 
|  | */ | 
|  |  | 
|  | #pragma once | 
|  |  | 
|  | #include "Privilege.h" | 
|  | #include "RequestPath.h" | 
|  | #include "SubjectDescriptor.h" | 
|  | #include <algorithm> | 
|  | #include <app-common/zap-generated/cluster-objects.h> | 
|  | #include <cstdint> | 
|  | #include <lib/core/CHIPError.h> | 
|  | #include <lib/core/DataModelTypes.h> | 
|  | #include <lib/core/Optional.h> | 
|  | #include <lib/support/CHIPMem.h> | 
|  | #include <map> | 
|  | #include <memory> | 
|  | #include <protocols/interaction_model/Constants.h> | 
|  | #include <vector> | 
|  |  | 
|  | namespace chip { | 
|  | namespace Access { | 
|  |  | 
|  | class AccessRestrictionProvider | 
|  | { | 
|  | public: | 
|  | static constexpr size_t kNumberOfFabrics      = CHIP_CONFIG_MAX_FABRICS; | 
|  | static constexpr size_t kEntriesPerFabric     = CHIP_CONFIG_ACCESS_RESTRICTION_MAX_ENTRIES_PER_FABRIC; | 
|  | static constexpr size_t kRestrictionsPerEntry = CHIP_CONFIG_ACCESS_RESTRICTION_MAX_RESTRICTIONS_PER_ENTRY; | 
|  |  | 
|  | /** | 
|  | * Defines the type of access restriction, which is used to determine the meaning of the restriction's id. | 
|  | */ | 
|  | enum class Type : uint8_t | 
|  | { | 
|  | kAttributeAccessForbidden = 0, | 
|  | kAttributeWriteForbidden  = 1, | 
|  | kCommandForbidden         = 2, | 
|  | kEventForbidden           = 3 | 
|  | }; | 
|  |  | 
|  | /** | 
|  | * Defines a single restriction on an attribute, command, or event. | 
|  | * | 
|  | * If id is not set, the restriction applies to all attributes, commands, or events of the given type (wildcard). | 
|  | */ | 
|  | struct Restriction | 
|  | { | 
|  | Type restrictionType; | 
|  | Optional<uint32_t> id; | 
|  | }; | 
|  |  | 
|  | /** | 
|  | * Defines a single entry in the access restriction list, which contains a list of restrictions | 
|  | * for a cluster on an endpoint. | 
|  | */ | 
|  | struct Entry | 
|  | { | 
|  | FabricIndex fabricIndex; | 
|  | EndpointId endpointNumber; | 
|  | ClusterId clusterId; | 
|  | std::vector<Restriction> restrictions; | 
|  | }; | 
|  |  | 
|  | /** | 
|  | * Defines the interface for a checker for access restriction exceptions. | 
|  | */ | 
|  | class AccessRestrictionExceptionChecker | 
|  | { | 
|  | public: | 
|  | virtual ~AccessRestrictionExceptionChecker() = default; | 
|  |  | 
|  | /** | 
|  | * Check if any restrictions are allowed to be applied on the given endpoint and cluster | 
|  | * because of constraints against their use in ARLs. | 
|  | * | 
|  | * @retval true if ARL checks are allowed to be applied to the cluster on the endpoint, false otherwise | 
|  | */ | 
|  | virtual bool AreRestrictionsAllowed(EndpointId endpoint, ClusterId cluster) = 0; | 
|  | }; | 
|  |  | 
|  | /** | 
|  | * Define a standard implementation of the AccessRestrictionExceptionChecker interface | 
|  | * which is the default implementation used by AccessResrictionProvider. | 
|  | */ | 
|  | class StandardAccessRestrictionExceptionChecker : public AccessRestrictionExceptionChecker | 
|  | { | 
|  | public: | 
|  | StandardAccessRestrictionExceptionChecker()  = default; | 
|  | ~StandardAccessRestrictionExceptionChecker() = default; | 
|  |  | 
|  | bool AreRestrictionsAllowed(EndpointId endpoint, ClusterId cluster) override; | 
|  | }; | 
|  |  | 
|  | /** | 
|  | * Used to notify of changes in the access restriction list and active reviews. | 
|  | */ | 
|  | class Listener | 
|  | { | 
|  | public: | 
|  | virtual ~Listener() = default; | 
|  |  | 
|  | /** | 
|  | * Notifies of a change in the commissioning access restriction list. | 
|  | */ | 
|  | virtual void MarkCommissioningRestrictionListChanged() = 0; | 
|  |  | 
|  | /** | 
|  | * Notifies of a change in the access restriction list. | 
|  | * | 
|  | * @param [in] fabricIndex  The index of the fabric in which the list has changed. | 
|  | */ | 
|  | virtual void MarkRestrictionListChanged(FabricIndex fabricIndex) = 0; | 
|  |  | 
|  | /** | 
|  | * Notifies of an update to an active review with instructions and an optional redirect URL. | 
|  | * | 
|  | * @param [in] fabricIndex  The index of the fabric in which the entry has changed. | 
|  | * @param [in] token        The token of the review being updated (obtained from ReviewFabricRestrictionsResponse) | 
|  | * @param [in] instruction  Optional instructions to be displayed to the user. | 
|  | * @param [in] redirectUrl  An optional URL to redirect the user to for more information. | 
|  | */ | 
|  | virtual void OnFabricRestrictionReviewUpdate(FabricIndex fabricIndex, uint64_t token, Optional<CharSpan> instruction, | 
|  | Optional<CharSpan> redirectUrl) = 0; | 
|  |  | 
|  | private: | 
|  | Listener * mNext = nullptr; | 
|  |  | 
|  | friend class AccessRestrictionProvider; | 
|  | }; | 
|  |  | 
|  | AccessRestrictionProvider()          = default; | 
|  | virtual ~AccessRestrictionProvider() = default; | 
|  |  | 
|  | AccessRestrictionProvider(const AccessRestrictionProvider &)             = delete; | 
|  | AccessRestrictionProvider & operator=(const AccessRestrictionProvider &) = delete; | 
|  |  | 
|  | /** | 
|  | * Set the restriction entries that are to be used during commissioning when there is no accessing fabric. | 
|  | * | 
|  | * @param [in] entries  The entries to set. | 
|  | */ | 
|  | CHIP_ERROR SetCommissioningEntries(const std::vector<Entry> & entries); | 
|  |  | 
|  | /** | 
|  | * Set the restriction entries for a fabric. | 
|  | * | 
|  | * @param [in] fabricIndex  The index of the fabric for which to create entries. | 
|  | * @param [in] entries  The entries to set for the fabric. | 
|  | */ | 
|  | CHIP_ERROR SetEntries(const FabricIndex, const std::vector<Entry> & entries); | 
|  |  | 
|  | /** | 
|  | * Add a listener to be notified of changes in the access restriction list and active reviews. | 
|  | * | 
|  | * @param [in] listener  The listener to add. | 
|  | */ | 
|  | void AddListener(Listener & listener); | 
|  |  | 
|  | /** | 
|  | * Remove a listener from being notified of changes in the access restriction list and active reviews. | 
|  | * | 
|  | * @param [in] listener  The listener to remove. | 
|  | */ | 
|  | void RemoveListener(Listener & listener); | 
|  |  | 
|  | /** | 
|  | * Check whether access by a subject descriptor to a request path should be restricted (denied) for the given action | 
|  | * during commissioning by using the CommissioningEntries. | 
|  | * | 
|  | * These restrictions are are only a part of overall access evaluation. | 
|  | * | 
|  | * If access is not restricted, CHIP_NO_ERROR will be returned. | 
|  | * | 
|  | * @retval CHIP_ERROR_ACCESS_DENIED if access is denied. | 
|  | * @retval other errors should also be treated as restricted/denied. | 
|  | * @retval CHIP_NO_ERROR if access is not restricted/denied. | 
|  | */ | 
|  | CHIP_ERROR CheckForCommissioning(const SubjectDescriptor & subjectDescriptor, const RequestPath & requestPath); | 
|  |  | 
|  | /** | 
|  | * Check whether access by a subject descriptor to a request path should be restricted (denied) for the given action. | 
|  | * These restrictions are are only a part of overall access evaluation. | 
|  | * | 
|  | * If access is not restricted, CHIP_NO_ERROR will be returned. | 
|  | * | 
|  | * @retval CHIP_ERROR_ACCESS_DENIED if access is denied. | 
|  | * @retval other errors should also be treated as restricted/denied. | 
|  | * @retval CHIP_NO_ERROR if access is not restricted/denied. | 
|  | */ | 
|  | CHIP_ERROR Check(const SubjectDescriptor & subjectDescriptor, const RequestPath & requestPath); | 
|  |  | 
|  | /** | 
|  | * Request a review of the access restrictions for a fabric. | 
|  | * | 
|  | * @param [in]  fabricIndex  The index of the fabric requesting a review. | 
|  | * @param [in]  arl          An optinal list of access restriction entries to review.  If null, all entries will be reviewed. | 
|  | * @param [out] token        The unique token for the review, which can be matched to a review update event. | 
|  | */ | 
|  | CHIP_ERROR RequestFabricRestrictionReview(FabricIndex fabricIndex, const std::vector<Entry> & arl, uint64_t & token) | 
|  | { | 
|  | token = mNextToken++; | 
|  | return DoRequestFabricRestrictionReview(fabricIndex, token, arl); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Get the commissioning restriction entries. | 
|  | * | 
|  | * @retval the commissioning restriction entries. | 
|  | */ | 
|  | const std::vector<Entry> & GetCommissioningEntries() const { return mCommissioningEntries; } | 
|  |  | 
|  | /** | 
|  | * Get the restriction entries for a fabric. | 
|  | * | 
|  | * @param [in]  fabricIndex the index of the fabric for which to get entries. | 
|  | * @param [out] entries vector to hold the entries. | 
|  | */ | 
|  | CHIP_ERROR GetEntries(const FabricIndex fabricIndex, std::vector<Entry> & entries) const | 
|  | { | 
|  | auto it = mFabricEntries.find(fabricIndex); | 
|  | if (it == mFabricEntries.end()) | 
|  | { | 
|  | return CHIP_ERROR_NOT_FOUND; | 
|  | } | 
|  |  | 
|  | entries = (it->second); | 
|  |  | 
|  | return CHIP_NO_ERROR; | 
|  | } | 
|  |  | 
|  | protected: | 
|  | /** | 
|  | * Initiate a review of the access restrictions for a fabric. This method should be implemented by the platform and be | 
|  | * non-blocking. | 
|  | * | 
|  | * @param [in] fabricIndex  The index of the fabric requesting a review. | 
|  | * @param [in] token        The unique token for the review, which can be matched to a review update event. | 
|  | * @param [in] arl          An optinal list of access restriction entries to review.  If null, all entries will be reviewed. | 
|  | * @return                  CHIP_NO_ERROR if the review was successfully requested, or an error code if the request failed. | 
|  | */ | 
|  | virtual CHIP_ERROR DoRequestFabricRestrictionReview(const FabricIndex fabricIndex, uint64_t token, | 
|  | const std::vector<Entry> & arl) = 0; | 
|  |  | 
|  | private: | 
|  | /** | 
|  | * Perform the access restriction check using the given entries. | 
|  | */ | 
|  | CHIP_ERROR DoCheck(const std::vector<Entry> & entries, const SubjectDescriptor & subjectDescriptor, | 
|  | const RequestPath & requestPath); | 
|  |  | 
|  | uint64_t mNextToken   = 1; | 
|  | Listener * mListeners = nullptr; | 
|  | StandardAccessRestrictionExceptionChecker mExceptionChecker; | 
|  | std::vector<Entry> mCommissioningEntries; | 
|  | std::map<FabricIndex, std::vector<Entry>> mFabricEntries; | 
|  | }; | 
|  |  | 
|  | } // namespace Access | 
|  | } // namespace chip |