PermissionDelegateHandler.h (7796B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 /* 8 * Permission delegate handler provides a policy of how top-level can 9 * delegate permission to embedded iframes. 10 * 11 * This class includes a mechanism to delegate permission using feature 12 * policy. Feature policy will assure that only cross-origin iframes which 13 * have been explicitly granted access will have the opportunity to request 14 * permission. 15 * 16 * For example if an iframe has not been granted access to geolocation by 17 * Feature Policy, geolocation request from the iframe will be automatically 18 * denied. if the top-level origin already has access to geolocation and the 19 * iframe has been granted access to geolocation by Feature Policy, the iframe 20 * will also have access to geolocation. If the top-level frame did not have 21 * access to geolocation, and the iframe has been granted access to geolocation 22 * by Feature Policy, a request from the cross-origin iframe would trigger a 23 * prompt using of the top-level origin. 24 */ 25 26 #ifndef mozilla_PermissionDelegateHandler_h 27 #define mozilla_PermissionDelegateHandler_h 28 29 #include "mozilla/Array.h" 30 #include "nsCycleCollectionParticipant.h" 31 #include "nsISupports.h" 32 #include "nsIPermissionDelegateHandler.h" 33 #include "nsIPermissionManager.h" 34 #include "nsCOMPtr.h" 35 36 class nsIPrincipal; 37 class nsIContentPermissionRequest; 38 39 namespace mozilla { 40 namespace dom { 41 class Document; 42 class WindowContext; 43 } // namespace dom 44 45 class PermissionDelegateHandler final : public nsIPermissionDelegateHandler { 46 public: 47 NS_DECL_CYCLE_COLLECTING_ISUPPORTS_FINAL 48 NS_DECL_CYCLE_COLLECTION_CLASS(PermissionDelegateHandler) 49 50 NS_DECL_NSIPERMISSIONDELEGATEHANDLER 51 52 explicit PermissionDelegateHandler() = default; 53 explicit PermissionDelegateHandler(mozilla::dom::Document* aDocument); 54 55 static constexpr size_t DELEGATED_PERMISSION_COUNT = 15; 56 57 typedef struct DelegatedPermissionList { 58 Array<uint32_t, DELEGATED_PERMISSION_COUNT> mPermissions; 59 60 bool operator==(const DelegatedPermissionList& aOther) const { 61 return mPermissions == aOther.mPermissions; 62 } 63 } DelegatedPermissionList; 64 65 bool Initialize(); 66 67 /* 68 * Indicates if we has the right to make permission request with aType 69 */ 70 bool HasPermissionDelegated(const nsACString& aType) const; 71 72 /* 73 * Get permission state, which applied permission delegate policy. 74 * 75 * @param aType the permission type to get 76 * @param aPermission out argument which will be a permission type that we 77 * will return from this function. 78 * @param aExactHostMatch whether to look for the exact host name or also for 79 * subdomains that can have the same permission. 80 */ 81 nsresult GetPermission(const nsACString& aType, uint32_t* aPermission, 82 bool aExactHostMatch); 83 84 /* 85 * Get permission state for permission api, which applied 86 * permission delegate policy. 87 * 88 * @param aType the permission type to get 89 * @param aExactHostMatch whether to look for the exact host name or also for 90 * subdomains that can have the same permission. 91 * @param aPermission out argument which will be a permission type that we 92 * will return from this function. 93 */ 94 nsresult GetPermissionForPermissionsAPI(const nsACString& aType, 95 uint32_t* aPermission); 96 97 enum PermissionDelegatePolicy { 98 /* Always delegate permission from top level to iframe and the iframe 99 * should use top level origin to get/set permission.*/ 100 eDelegateUseTopOrigin, 101 102 /* Permission is delegated using Feature Policy. Permission is denied by 103 * default in cross origin iframe and the iframe only could get/set 104 * permission if there's allow attribute set in iframe. e.g allow = 105 * "geolocation" */ 106 eDelegateUseFeaturePolicy, 107 108 /* Persistent denied permissions in cross origin iframe */ 109 ePersistDeniedCrossOrigin, 110 111 /* This is the old behavior of cross origin iframe permission. The 112 * permission delegation should not have an effect on iframe. The cross 113 * origin iframe get/set permissions by its origin */ 114 eDelegateUseIframeOrigin, 115 }; 116 117 /* 118 * Indicates matching between Feature Policy and Permissions name defined in 119 * Permissions Manager, not DOM Permissions API. Permissions API exposed in 120 * DOM only supports "geo" at the moment but Permissions Manager also supports 121 * "camera", "microphone". 122 */ 123 typedef struct { 124 const char* mPermissionName; 125 const char16_t* mFeatureName; 126 PermissionDelegatePolicy mPolicy; 127 } PermissionDelegateInfo; 128 129 /** 130 * The loader maintains a weak reference to the document with 131 * which it is initialized. This call forces the reference to 132 * be dropped. 133 */ 134 void DropDocumentReference() { mDocument = nullptr; } 135 136 /* 137 * Helper function to return the delegate info value for aPermissionName. 138 * @param aPermissionName the permission name to get 139 */ 140 static const PermissionDelegateInfo* GetPermissionDelegateInfo( 141 const nsAString& aPermissionName); 142 143 /* 144 * Helper function to return the delegate principal. This will return nullptr, 145 * or request's principal or top level principal based on the delegate policy 146 * will be applied for a given type. 147 * We use this function when prompting, no need to perform permission check 148 * (deny/allow). 149 * 150 * @param aType the permission type to get 151 * @param aRequest The request which the principal is get from. 152 * @param aResult out argument which will be a principal that we 153 * will return from this function. 154 */ 155 static nsresult GetDelegatePrincipal(const nsACString& aType, 156 nsIContentPermissionRequest* aRequest, 157 nsIPrincipal** aResult); 158 159 /** 160 * Populate all delegated permissions to the WindowContext of the associated 161 * document. We only populate the permissions for the top-level content. 162 */ 163 void PopulateAllDelegatedPermissions(); 164 165 /** 166 * Update the given delegated permission to the WindowContext. We only 167 * update it for the top-level content. 168 */ 169 void UpdateDelegatedPermission(const nsACString& aType); 170 171 private: 172 ~PermissionDelegateHandler() = default; 173 174 /* 175 * Check whether the permission is blocked by FeaturePolicy directive. 176 * Default allowlist for a featureName of permission used in permissions 177 * delegate should be set to eSelf, to ensure that permission is denied by 178 * default and only have the opportunity to request permission with allow 179 * attribute. 180 */ 181 bool HasFeaturePolicyAllowed(const PermissionDelegateInfo* info) const; 182 183 /** 184 * A helper function to test the permission and set the result to the given 185 * list. It will return true if the permission is changed, otherwise false. 186 */ 187 bool UpdateDelegatePermissionInternal( 188 PermissionDelegateHandler::DelegatedPermissionList& aList, 189 const nsACString& aType, size_t aIdx, 190 nsresult (NS_STDCALL nsIPermissionManager::*aTestFunc)(nsIPrincipal*, 191 const nsACString&, 192 uint32_t*)); 193 194 // A weak pointer to our document. Nulled out by DropDocumentReference. 195 mozilla::dom::Document* mDocument; 196 197 nsCOMPtr<nsIPrincipal> mPrincipal; 198 RefPtr<nsIPermissionManager> mPermissionManager; 199 }; 200 201 } // namespace mozilla 202 203 #endif // mozilla_PermissionDelegateHandler_h