Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/google/cloud/storage/hmac_key.py: 43%

92 statements  

« prev     ^ index     » next       coverage.py v7.3.1, created at 2023-09-25 06:17 +0000

1# Copyright 2019 Google LLC 

2# 

3# Licensed under the Apache License, Version 2.0 (the "License"); 

4# you may not use this file except in compliance with the License. 

5# You may obtain a copy of the License at 

6# 

7# http://www.apache.org/licenses/LICENSE-2.0 

8# 

9# Unless required by applicable law or agreed to in writing, software 

10# distributed under the License is distributed on an "AS IS" BASIS, 

11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 

12# See the License for the specific language governing permissions and 

13# limitations under the License. 

14 

15"""Configure HMAC keys that can be used to authenticate requests to Google Cloud Storage. 

16 

17See [HMAC keys documentation](https://cloud.google.com/storage/docs/authentication/hmackeys) 

18""" 

19 

20from google.cloud.exceptions import NotFound 

21from google.cloud._helpers import _rfc3339_nanos_to_datetime 

22 

23from google.cloud.storage.constants import _DEFAULT_TIMEOUT 

24from google.cloud.storage.retry import DEFAULT_RETRY 

25from google.cloud.storage.retry import DEFAULT_RETRY_IF_ETAG_IN_JSON 

26 

27 

28class HMACKeyMetadata(object): 

29 """Metadata about an HMAC service account key withn Cloud Storage. 

30 

31 :type client: :class:`~google.cloud.stoage.client.Client` 

32 :param client: client associated with the key metadata. 

33 

34 :type access_id: str 

35 :param access_id: (Optional) Unique ID of an existing key. 

36 

37 :type project_id: str 

38 :param project_id: (Optional) Project ID of an existing key. 

39 Defaults to client's project. 

40 

41 :type user_project: str 

42 :param user_project: (Optional) This parameter is currently ignored. 

43 """ 

44 

45 ACTIVE_STATE = "ACTIVE" 

46 """Key is active, and may be used to sign requests.""" 

47 INACTIVE_STATE = "INACTIVE" 

48 """Key is inactive, and may not be used to sign requests. 

49 

50 It can be re-activated via :meth:`update`. 

51 """ 

52 DELETED_STATE = "DELETED" 

53 """Key is deleted. It cannot be re-activated.""" 

54 

55 _SETTABLE_STATES = (ACTIVE_STATE, INACTIVE_STATE) 

56 

57 def __init__(self, client, access_id=None, project_id=None, user_project=None): 

58 self._client = client 

59 self._properties = {} 

60 

61 if access_id is not None: 

62 self._properties["accessId"] = access_id 

63 

64 if project_id is not None: 

65 self._properties["projectId"] = project_id 

66 

67 self._user_project = user_project 

68 

69 def __eq__(self, other): 

70 if not isinstance(other, self.__class__): 

71 return NotImplemented 

72 

73 return self._client == other._client and self.access_id == other.access_id 

74 

75 def __hash__(self): 

76 return hash(self._client) + hash(self.access_id) 

77 

78 @property 

79 def access_id(self): 

80 """Access ID of the key. 

81 

82 :rtype: str or None 

83 :returns: unique identifier of the key within a project. 

84 """ 

85 return self._properties.get("accessId") 

86 

87 @property 

88 def etag(self): 

89 """ETag identifying the version of the key metadata. 

90 

91 :rtype: str or None 

92 :returns: ETag for the version of the key's metadata. 

93 """ 

94 return self._properties.get("etag") 

95 

96 @property 

97 def id(self): 

98 """ID of the key, including the Project ID and the Access ID. 

99 

100 :rtype: str or None 

101 :returns: ID of the key. 

102 """ 

103 return self._properties.get("id") 

104 

105 @property 

106 def project(self): 

107 """Project ID associated with the key. 

108 

109 :rtype: str or None 

110 :returns: project identfier for the key. 

111 """ 

112 return self._properties.get("projectId") 

113 

114 @property 

115 def service_account_email(self): 

116 """Service account e-mail address associated with the key. 

117 

118 :rtype: str or None 

119 :returns: e-mail address for the service account which created the key. 

120 """ 

121 return self._properties.get("serviceAccountEmail") 

122 

123 @property 

124 def state(self): 

125 """Get / set key's state. 

126 

127 One of: 

128 - ``ACTIVE`` 

129 - ``INACTIVE`` 

130 - ``DELETED`` 

131 

132 :rtype: str or None 

133 :returns: key's current state. 

134 """ 

135 return self._properties.get("state") 

136 

137 @state.setter 

138 def state(self, value): 

139 self._properties["state"] = value 

140 

141 @property 

142 def time_created(self): 

143 """Retrieve the timestamp at which the HMAC key was created. 

144 

145 :rtype: :class:`datetime.datetime` or ``NoneType`` 

146 :returns: Datetime object parsed from RFC3339 valid timestamp, or 

147 ``None`` if the bucket's resource has not been loaded 

148 from the server. 

149 """ 

150 value = self._properties.get("timeCreated") 

151 if value is not None: 

152 return _rfc3339_nanos_to_datetime(value) 

153 

154 @property 

155 def updated(self): 

156 """Retrieve the timestamp at which the HMAC key was created. 

157 

158 :rtype: :class:`datetime.datetime` or ``NoneType`` 

159 :returns: Datetime object parsed from RFC3339 valid timestamp, or 

160 ``None`` if the bucket's resource has not been loaded 

161 from the server. 

162 """ 

163 value = self._properties.get("updated") 

164 if value is not None: 

165 return _rfc3339_nanos_to_datetime(value) 

166 

167 @property 

168 def path(self): 

169 """Resource path for the metadata's key.""" 

170 

171 if self.access_id is None: 

172 raise ValueError("No 'access_id' set.") 

173 

174 project = self.project 

175 if project is None: 

176 project = self._client.project 

177 

178 return f"/projects/{project}/hmacKeys/{self.access_id}" 

179 

180 @property 

181 def user_project(self): 

182 """Project ID to be billed for API requests made via this bucket. 

183 

184 This property is currently ignored by the server. 

185 

186 :rtype: str 

187 """ 

188 return self._user_project 

189 

190 def exists(self, timeout=_DEFAULT_TIMEOUT, retry=DEFAULT_RETRY): 

191 """Determine whether or not the key for this metadata exists. 

192 

193 :type timeout: float or tuple 

194 :param timeout: 

195 (Optional) The amount of time, in seconds, to wait 

196 for the server response. See: :ref:`configuring_timeouts` 

197 

198 :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy 

199 :param retry: 

200 (Optional) How to retry the RPC. See: :ref:`configuring_retries` 

201 

202 :rtype: bool 

203 :returns: True if the key exists in Cloud Storage. 

204 """ 

205 try: 

206 qs_params = {} 

207 

208 if self.user_project is not None: 

209 qs_params["userProject"] = self.user_project 

210 

211 self._client._get_resource( 

212 self.path, 

213 query_params=qs_params, 

214 timeout=timeout, 

215 retry=retry, 

216 ) 

217 except NotFound: 

218 return False 

219 else: 

220 return True 

221 

222 def reload(self, timeout=_DEFAULT_TIMEOUT, retry=DEFAULT_RETRY): 

223 """Reload properties from Cloud Storage. 

224 

225 :type timeout: float or tuple 

226 :param timeout: 

227 (Optional) The amount of time, in seconds, to wait 

228 for the server response. See: :ref:`configuring_timeouts` 

229 

230 :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy 

231 :param retry: 

232 (Optional) How to retry the RPC. See: :ref:`configuring_retries` 

233 

234 :raises :class:`~google.api_core.exceptions.NotFound`: 

235 if the key does not exist on the back-end. 

236 """ 

237 qs_params = {} 

238 

239 if self.user_project is not None: 

240 qs_params["userProject"] = self.user_project 

241 

242 self._properties = self._client._get_resource( 

243 self.path, 

244 query_params=qs_params, 

245 timeout=timeout, 

246 retry=retry, 

247 ) 

248 

249 def update(self, timeout=_DEFAULT_TIMEOUT, retry=DEFAULT_RETRY_IF_ETAG_IN_JSON): 

250 """Save writable properties to Cloud Storage. 

251 

252 :type timeout: float or tuple 

253 :param timeout: 

254 (Optional) The amount of time, in seconds, to wait 

255 for the server response. See: :ref:`configuring_timeouts` 

256 

257 :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy 

258 :param retry: 

259 (Optional) How to retry the RPC. See: :ref:`configuring_retries` 

260 

261 :raises :class:`~google.api_core.exceptions.NotFound`: 

262 if the key does not exist on the back-end. 

263 """ 

264 qs_params = {} 

265 if self.user_project is not None: 

266 qs_params["userProject"] = self.user_project 

267 

268 payload = {"state": self.state} 

269 self._properties = self._client._put_resource( 

270 self.path, 

271 payload, 

272 query_params=qs_params, 

273 timeout=timeout, 

274 retry=retry, 

275 ) 

276 

277 def delete(self, timeout=_DEFAULT_TIMEOUT, retry=DEFAULT_RETRY): 

278 """Delete the key from Cloud Storage. 

279 

280 :type timeout: float or tuple 

281 :param timeout: 

282 (Optional) The amount of time, in seconds, to wait 

283 for the server response. See: :ref:`configuring_timeouts` 

284 

285 :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy 

286 :param retry: 

287 (Optional) How to retry the RPC. See: :ref:`configuring_retries` 

288 

289 :raises :class:`~google.api_core.exceptions.NotFound`: 

290 if the key does not exist on the back-end. 

291 """ 

292 qs_params = {} 

293 if self.user_project is not None: 

294 qs_params["userProject"] = self.user_project 

295 

296 self._client._delete_resource( 

297 self.path, 

298 query_params=qs_params, 

299 timeout=timeout, 

300 retry=retry, 

301 )