1# Copyright 2014 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"""Manage access to objects and buckets.""" 
    16 
    17from google.cloud.storage._helpers import _add_generation_match_parameters 
    18from google.cloud.storage._opentelemetry_tracing import create_trace_span 
    19from google.cloud.storage.constants import _DEFAULT_TIMEOUT 
    20from google.cloud.storage.retry import DEFAULT_RETRY 
    21from google.cloud.storage.retry import DEFAULT_RETRY_IF_METAGENERATION_SPECIFIED 
    22 
    23 
    24class _ACLEntity(object): 
    25    """Class representing a set of roles for an entity. 
    26 
    27    This is a helper class that you likely won't ever construct 
    28    outside of using the factor methods on the :class:`ACL` object. 
    29 
    30    :type entity_type: str 
    31    :param entity_type: The type of entity (ie, 'group' or 'user'). 
    32 
    33    :type identifier: str 
    34    :param identifier: (Optional) The ID or e-mail of the entity. For the special 
    35                       entity types (like 'allUsers'). 
    36    """ 
    37 
    38    READER_ROLE = "READER" 
    39    WRITER_ROLE = "WRITER" 
    40    OWNER_ROLE = "OWNER" 
    41 
    42    def __init__(self, entity_type, identifier=None): 
    43        self.identifier = identifier 
    44        self.roles = set([]) 
    45        self.type = entity_type 
    46 
    47    def __str__(self): 
    48        if not self.identifier: 
    49            return str(self.type) 
    50        else: 
    51            return "{acl.type}-{acl.identifier}".format(acl=self) 
    52 
    53    def __repr__(self): 
    54        return f"<ACL Entity: {self} ({', '.join(self.roles)})>" 
    55 
    56    def get_roles(self): 
    57        """Get the list of roles permitted by this entity. 
    58 
    59        :rtype: list of strings 
    60        :returns: The list of roles associated with this entity. 
    61        """ 
    62        return self.roles 
    63 
    64    def grant(self, role): 
    65        """Add a role to the entity. 
    66 
    67        :type role: str 
    68        :param role: The role to add to the entity. 
    69        """ 
    70        self.roles.add(role) 
    71 
    72    def revoke(self, role): 
    73        """Remove a role from the entity. 
    74 
    75        :type role: str 
    76        :param role: The role to remove from the entity. 
    77        """ 
    78        if role in self.roles: 
    79            self.roles.remove(role) 
    80 
    81    def grant_read(self): 
    82        """Grant read access to the current entity.""" 
    83        self.grant(_ACLEntity.READER_ROLE) 
    84 
    85    def grant_write(self): 
    86        """Grant write access to the current entity.""" 
    87        self.grant(_ACLEntity.WRITER_ROLE) 
    88 
    89    def grant_owner(self): 
    90        """Grant owner access to the current entity.""" 
    91        self.grant(_ACLEntity.OWNER_ROLE) 
    92 
    93    def revoke_read(self): 
    94        """Revoke read access from the current entity.""" 
    95        self.revoke(_ACLEntity.READER_ROLE) 
    96 
    97    def revoke_write(self): 
    98        """Revoke write access from the current entity.""" 
    99        self.revoke(_ACLEntity.WRITER_ROLE) 
    100 
    101    def revoke_owner(self): 
    102        """Revoke owner access from the current entity.""" 
    103        self.revoke(_ACLEntity.OWNER_ROLE) 
    104 
    105 
    106class ACL(object): 
    107    """Container class representing a list of access controls.""" 
    108 
    109    _URL_PATH_ELEM = "acl" 
    110    _PREDEFINED_QUERY_PARAM = "predefinedAcl" 
    111 
    112    PREDEFINED_XML_ACLS = { 
    113        # XML API name -> JSON API name 
    114        "project-private": "projectPrivate", 
    115        "public-read": "publicRead", 
    116        "public-read-write": "publicReadWrite", 
    117        "authenticated-read": "authenticatedRead", 
    118        "bucket-owner-read": "bucketOwnerRead", 
    119        "bucket-owner-full-control": "bucketOwnerFullControl", 
    120    } 
    121 
    122    PREDEFINED_JSON_ACLS = frozenset( 
    123        [ 
    124            "private", 
    125            "projectPrivate", 
    126            "publicRead", 
    127            "publicReadWrite", 
    128            "authenticatedRead", 
    129            "bucketOwnerRead", 
    130            "bucketOwnerFullControl", 
    131        ] 
    132    ) 
    133    """See 
    134    https://cloud.google.com/storage/docs/access-control/lists#predefined-acl 
    135    """ 
    136 
    137    loaded = False 
    138 
    139    # Subclasses must override to provide these attributes (typically, 
    140    # as properties). 
    141    reload_path = None 
    142    save_path = None 
    143    user_project = None 
    144 
    145    def __init__(self): 
    146        self.entities = {} 
    147 
    148    def _ensure_loaded(self, timeout=_DEFAULT_TIMEOUT): 
    149        """Load if not already loaded. 
    150 
    151        :type timeout: float or tuple 
    152        :param timeout: 
    153            (Optional) The amount of time, in seconds, to wait 
    154            for the server response.  See: :ref:`configuring_timeouts` 
    155        """ 
    156        if not self.loaded: 
    157            self.reload(timeout=timeout) 
    158 
    159    @classmethod 
    160    def validate_predefined(cls, predefined): 
    161        """Ensures predefined is in list of predefined json values 
    162 
    163        :type predefined: str 
    164        :param predefined: name of a predefined acl 
    165 
    166        :type predefined: str 
    167        :param predefined: validated JSON name of predefined acl 
    168 
    169        :raises: :exc: `ValueError`: If predefined is not a valid acl 
    170        """ 
    171        predefined = cls.PREDEFINED_XML_ACLS.get(predefined, predefined) 
    172        if predefined and predefined not in cls.PREDEFINED_JSON_ACLS: 
    173            raise ValueError(f"Invalid predefined ACL: {predefined}") 
    174        return predefined 
    175 
    176    def reset(self): 
    177        """Remove all entities from the ACL, and clear the ``loaded`` flag.""" 
    178        self.entities.clear() 
    179        self.loaded = False 
    180 
    181    def __iter__(self): 
    182        self._ensure_loaded() 
    183 
    184        for entity in self.entities.values(): 
    185            for role in entity.get_roles(): 
    186                if role: 
    187                    yield {"entity": str(entity), "role": role} 
    188 
    189    def entity_from_dict(self, entity_dict): 
    190        """Build an _ACLEntity object from a dictionary of data. 
    191 
    192        An entity is a mutable object that represents a list of roles 
    193        belonging to either a user or group or the special types for all 
    194        users and all authenticated users. 
    195 
    196        :type entity_dict: dict 
    197        :param entity_dict: Dictionary full of data from an ACL lookup. 
    198 
    199        :rtype: :class:`_ACLEntity` 
    200        :returns: An Entity constructed from the dictionary. 
    201        """ 
    202        entity = entity_dict["entity"] 
    203        role = entity_dict["role"] 
    204 
    205        if entity == "allUsers": 
    206            entity = self.all() 
    207 
    208        elif entity == "allAuthenticatedUsers": 
    209            entity = self.all_authenticated() 
    210 
    211        elif "-" in entity: 
    212            entity_type, identifier = entity.split("-", 1) 
    213            entity = self.entity(entity_type=entity_type, identifier=identifier) 
    214 
    215        if not isinstance(entity, _ACLEntity): 
    216            raise ValueError(f"Invalid dictionary: {entity_dict}") 
    217 
    218        entity.grant(role) 
    219        return entity 
    220 
    221    def has_entity(self, entity): 
    222        """Returns whether or not this ACL has any entries for an entity. 
    223 
    224        :type entity: :class:`_ACLEntity` 
    225        :param entity: The entity to check for existence in this ACL. 
    226 
    227        :rtype: bool 
    228        :returns: True of the entity exists in the ACL. 
    229        """ 
    230        self._ensure_loaded() 
    231        return str(entity) in self.entities 
    232 
    233    def get_entity(self, entity, default=None): 
    234        """Gets an entity object from the ACL. 
    235 
    236        :type entity: :class:`_ACLEntity` or string 
    237        :param entity: The entity to get lookup in the ACL. 
    238 
    239        :type default: anything 
    240        :param default: This value will be returned if the entity 
    241                        doesn't exist. 
    242 
    243        :rtype: :class:`_ACLEntity` 
    244        :returns: The corresponding entity or the value provided 
    245                  to ``default``. 
    246        """ 
    247        self._ensure_loaded() 
    248        return self.entities.get(str(entity), default) 
    249 
    250    def add_entity(self, entity): 
    251        """Add an entity to the ACL. 
    252 
    253        :type entity: :class:`_ACLEntity` 
    254        :param entity: The entity to add to this ACL. 
    255        """ 
    256        self._ensure_loaded() 
    257        self.entities[str(entity)] = entity 
    258 
    259    def entity(self, entity_type, identifier=None): 
    260        """Factory method for creating an Entity. 
    261 
    262        If an entity with the same type and identifier already exists, 
    263        this will return a reference to that entity.  If not, it will 
    264        create a new one and add it to the list of known entities for 
    265        this ACL. 
    266 
    267        :type entity_type: str 
    268        :param entity_type: The type of entity to create 
    269                            (ie, ``user``, ``group``, etc) 
    270 
    271        :type identifier: str 
    272        :param identifier: The ID of the entity (if applicable). 
    273                           This can be either an ID or an e-mail address. 
    274 
    275        :rtype: :class:`_ACLEntity` 
    276        :returns: A new Entity or a reference to an existing identical entity. 
    277        """ 
    278        entity = _ACLEntity(entity_type=entity_type, identifier=identifier) 
    279        if self.has_entity(entity): 
    280            entity = self.get_entity(entity) 
    281        else: 
    282            self.add_entity(entity) 
    283        return entity 
    284 
    285    def user(self, identifier): 
    286        """Factory method for a user Entity. 
    287 
    288        :type identifier: str 
    289        :param identifier: An id or e-mail for this particular user. 
    290 
    291        :rtype: :class:`_ACLEntity` 
    292        :returns: An Entity corresponding to this user. 
    293        """ 
    294        return self.entity("user", identifier=identifier) 
    295 
    296    def group(self, identifier): 
    297        """Factory method for a group Entity. 
    298 
    299        :type identifier: str 
    300        :param identifier: An id or e-mail for this particular group. 
    301 
    302        :rtype: :class:`_ACLEntity` 
    303        :returns: An Entity corresponding to this group. 
    304        """ 
    305        return self.entity("group", identifier=identifier) 
    306 
    307    def domain(self, domain): 
    308        """Factory method for a domain Entity. 
    309 
    310        :type domain: str 
    311        :param domain: The domain for this entity. 
    312 
    313        :rtype: :class:`_ACLEntity` 
    314        :returns: An entity corresponding to this domain. 
    315        """ 
    316        return self.entity("domain", identifier=domain) 
    317 
    318    def all(self): 
    319        """Factory method for an Entity representing all users. 
    320 
    321        :rtype: :class:`_ACLEntity` 
    322        :returns: An entity representing all users. 
    323        """ 
    324        return self.entity("allUsers") 
    325 
    326    def all_authenticated(self): 
    327        """Factory method for an Entity representing all authenticated users. 
    328 
    329        :rtype: :class:`_ACLEntity` 
    330        :returns: An entity representing all authenticated users. 
    331        """ 
    332        return self.entity("allAuthenticatedUsers") 
    333 
    334    def get_entities(self): 
    335        """Get a list of all Entity objects. 
    336 
    337        :rtype: list of :class:`_ACLEntity` objects 
    338        :returns: A list of all Entity objects. 
    339        """ 
    340        self._ensure_loaded() 
    341        return list(self.entities.values()) 
    342 
    343    @property 
    344    def client(self): 
    345        """Abstract getter for the object client.""" 
    346        raise NotImplementedError 
    347 
    348    def _require_client(self, client): 
    349        """Check client or verify over-ride. 
    350 
    351        :type client: :class:`~google.cloud.storage.client.Client` or 
    352                      ``NoneType`` 
    353        :param client: the client to use.  If not passed, falls back to the 
    354                       ``client`` stored on the current ACL. 
    355 
    356        :rtype: :class:`google.cloud.storage.client.Client` 
    357        :returns: The client passed in or the currently bound client. 
    358        """ 
    359        if client is None: 
    360            client = self.client 
    361        return client 
    362 
    363    def reload(self, client=None, timeout=_DEFAULT_TIMEOUT, retry=DEFAULT_RETRY): 
    364        """Reload the ACL data from Cloud Storage. 
    365 
    366        If :attr:`user_project` is set, bills the API request to that project. 
    367 
    368        :type client: :class:`~google.cloud.storage.client.Client` or 
    369                      ``NoneType`` 
    370        :param client: (Optional) The client to use.  If not passed, falls back 
    371                       to the ``client`` stored on the ACL's parent. 
    372        :type timeout: float or tuple 
    373        :param timeout: 
    374            (Optional) The amount of time, in seconds, to wait 
    375            for the server response.  See: :ref:`configuring_timeouts` 
    376 
    377        :type retry: :class:`~google.api_core.retry.Retry` 
    378        :param retry: 
    379            (Optional) How to retry the RPC. See: :ref:`configuring_retries` 
    380        """ 
    381        with create_trace_span(name="Storage.ACL.reload"): 
    382            path = self.reload_path 
    383            client = self._require_client(client) 
    384            query_params = {} 
    385 
    386            if self.user_project is not None: 
    387                query_params["userProject"] = self.user_project 
    388 
    389            self.entities.clear() 
    390 
    391            found = client._get_resource( 
    392                path, 
    393                query_params=query_params, 
    394                timeout=timeout, 
    395                retry=retry, 
    396            ) 
    397            self.loaded = True 
    398 
    399            for entry in found.get("items", ()): 
    400                self.add_entity(self.entity_from_dict(entry)) 
    401 
    402    def _save( 
    403        self, 
    404        acl, 
    405        predefined, 
    406        client, 
    407        if_generation_match=None, 
    408        if_generation_not_match=None, 
    409        if_metageneration_match=None, 
    410        if_metageneration_not_match=None, 
    411        timeout=_DEFAULT_TIMEOUT, 
    412        retry=DEFAULT_RETRY_IF_METAGENERATION_SPECIFIED, 
    413    ): 
    414        """Helper for :meth:`save` and :meth:`save_predefined`. 
    415 
    416        :type acl: :class:`google.cloud.storage.acl.ACL`, or a compatible list. 
    417        :param acl: The ACL object to save.  If left blank, this will save 
    418                    current entries. 
    419 
    420        :type predefined: str 
    421        :param predefined: An identifier for a predefined ACL.  Must be one of the 
    422            keys in :attr:`PREDEFINED_JSON_ACLS` If passed, `acl` must be None. 
    423 
    424        :type client: :class:`~google.cloud.storage.client.Client` or 
    425                      ``NoneType`` 
    426        :param client: (Optional) The client to use.  If not passed, falls back 
    427                       to the ``client`` stored on the ACL's parent. 
    428 
    429        :type if_generation_match: long 
    430        :param if_generation_match: 
    431            (Optional) See :ref:`using-if-generation-match` 
    432 
    433        :type if_generation_not_match: long 
    434        :param if_generation_not_match: 
    435            (Optional) See :ref:`using-if-generation-not-match` 
    436 
    437        :type if_metageneration_match: long 
    438        :param if_metageneration_match: 
    439            (Optional) See :ref:`using-if-metageneration-match` 
    440 
    441        :type if_metageneration_not_match: long 
    442        :param if_metageneration_not_match: 
    443            (Optional) See :ref:`using-if-metageneration-not-match` 
    444 
    445        :type timeout: float or tuple 
    446        :param timeout: 
    447            (Optional) The amount of time, in seconds, to wait 
    448            for the server response.  See: :ref:`configuring_timeouts` 
    449 
    450        :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy 
    451        :param retry: 
    452            (Optional) How to retry the RPC. See: :ref:`configuring_retries` 
    453        """ 
    454        client = self._require_client(client) 
    455        query_params = {"projection": "full"} 
    456 
    457        if predefined is not None: 
    458            acl = [] 
    459            query_params[self._PREDEFINED_QUERY_PARAM] = predefined 
    460 
    461        if self.user_project is not None: 
    462            query_params["userProject"] = self.user_project 
    463 
    464        _add_generation_match_parameters( 
    465            query_params, 
    466            if_generation_match=if_generation_match, 
    467            if_generation_not_match=if_generation_not_match, 
    468            if_metageneration_match=if_metageneration_match, 
    469            if_metageneration_not_match=if_metageneration_not_match, 
    470        ) 
    471 
    472        path = self.save_path 
    473 
    474        result = client._patch_resource( 
    475            path, 
    476            {self._URL_PATH_ELEM: list(acl)}, 
    477            query_params=query_params, 
    478            timeout=timeout, 
    479            retry=retry, 
    480        ) 
    481 
    482        self.entities.clear() 
    483 
    484        for entry in result.get(self._URL_PATH_ELEM, ()): 
    485            self.add_entity(self.entity_from_dict(entry)) 
    486 
    487        self.loaded = True 
    488 
    489    def save( 
    490        self, 
    491        acl=None, 
    492        client=None, 
    493        if_generation_match=None, 
    494        if_generation_not_match=None, 
    495        if_metageneration_match=None, 
    496        if_metageneration_not_match=None, 
    497        timeout=_DEFAULT_TIMEOUT, 
    498        retry=DEFAULT_RETRY_IF_METAGENERATION_SPECIFIED, 
    499    ): 
    500        """Save this ACL for the current bucket. 
    501 
    502        If :attr:`user_project` is set, bills the API request to that project. 
    503 
    504        :type acl: :class:`google.cloud.storage.acl.ACL`, or a compatible list. 
    505        :param acl: The ACL object to save.  If left blank, this will save 
    506                    current entries. 
    507 
    508        :type client: :class:`~google.cloud.storage.client.Client` or 
    509                      ``NoneType`` 
    510        :param client: (Optional) The client to use.  If not passed, falls back 
    511                       to the ``client`` stored on the ACL's parent. 
    512 
    513        :type if_generation_match: long 
    514        :param if_generation_match: 
    515            (Optional) See :ref:`using-if-generation-match` 
    516 
    517        :type if_generation_not_match: long 
    518        :param if_generation_not_match: 
    519            (Optional) See :ref:`using-if-generation-not-match` 
    520 
    521        :type if_metageneration_match: long 
    522        :param if_metageneration_match: 
    523            (Optional) See :ref:`using-if-metageneration-match` 
    524 
    525        :type if_metageneration_not_match: long 
    526        :param if_metageneration_not_match: 
    527            (Optional) See :ref:`using-if-metageneration-not-match` 
    528 
    529        :type timeout: float or tuple 
    530        :param timeout: 
    531            (Optional) The amount of time, in seconds, to wait 
    532            for the server response.  See: :ref:`configuring_timeouts` 
    533 
    534        :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy 
    535        :param retry: 
    536            (Optional) How to retry the RPC. See: :ref:`configuring_retries` 
    537        """ 
    538        with create_trace_span(name="Storage.ACL.save"): 
    539            if acl is None: 
    540                acl = self 
    541                save_to_backend = acl.loaded 
    542            else: 
    543                save_to_backend = True 
    544 
    545            if save_to_backend: 
    546                self._save( 
    547                    acl, 
    548                    None, 
    549                    client, 
    550                    if_generation_match=if_generation_match, 
    551                    if_generation_not_match=if_generation_not_match, 
    552                    if_metageneration_match=if_metageneration_match, 
    553                    if_metageneration_not_match=if_metageneration_not_match, 
    554                    timeout=timeout, 
    555                    retry=retry, 
    556                ) 
    557 
    558    def save_predefined( 
    559        self, 
    560        predefined, 
    561        client=None, 
    562        if_generation_match=None, 
    563        if_generation_not_match=None, 
    564        if_metageneration_match=None, 
    565        if_metageneration_not_match=None, 
    566        timeout=_DEFAULT_TIMEOUT, 
    567        retry=DEFAULT_RETRY_IF_METAGENERATION_SPECIFIED, 
    568    ): 
    569        """Save this ACL for the current bucket using a predefined ACL. 
    570 
    571        If :attr:`user_project` is set, bills the API request to that project. 
    572 
    573        :type predefined: str 
    574        :param predefined: An identifier for a predefined ACL.  Must be one 
    575                           of the keys in :attr:`PREDEFINED_JSON_ACLS` 
    576                           or :attr:`PREDEFINED_XML_ACLS` (which will be 
    577                           aliased to the corresponding JSON name). 
    578                           If passed, `acl` must be None. 
    579 
    580        :type client: :class:`~google.cloud.storage.client.Client` or 
    581                      ``NoneType`` 
    582        :param client: (Optional) The client to use.  If not passed, falls back 
    583                       to the ``client`` stored on the ACL's parent. 
    584 
    585        :type if_generation_match: long 
    586        :param if_generation_match: 
    587            (Optional) See :ref:`using-if-generation-match` 
    588 
    589        :type if_generation_not_match: long 
    590        :param if_generation_not_match: 
    591            (Optional) See :ref:`using-if-generation-not-match` 
    592 
    593        :type if_metageneration_match: long 
    594        :param if_metageneration_match: 
    595            (Optional) See :ref:`using-if-metageneration-match` 
    596 
    597        :type if_metageneration_not_match: long 
    598        :param if_metageneration_not_match: 
    599            (Optional) See :ref:`using-if-metageneration-not-match` 
    600 
    601        :type timeout: float or tuple 
    602        :param timeout: 
    603            (Optional) The amount of time, in seconds, to wait 
    604            for the server response.  See: :ref:`configuring_timeouts` 
    605 
    606        :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy 
    607        :param retry: 
    608            (Optional) How to retry the RPC. See: :ref:`configuring_retries` 
    609        """ 
    610        with create_trace_span(name="Storage.ACL.savePredefined"): 
    611            predefined = self.validate_predefined(predefined) 
    612            self._save( 
    613                None, 
    614                predefined, 
    615                client, 
    616                if_generation_match=if_generation_match, 
    617                if_generation_not_match=if_generation_not_match, 
    618                if_metageneration_match=if_metageneration_match, 
    619                if_metageneration_not_match=if_metageneration_not_match, 
    620                timeout=timeout, 
    621                retry=retry, 
    622            ) 
    623 
    624    def clear( 
    625        self, 
    626        client=None, 
    627        if_generation_match=None, 
    628        if_generation_not_match=None, 
    629        if_metageneration_match=None, 
    630        if_metageneration_not_match=None, 
    631        timeout=_DEFAULT_TIMEOUT, 
    632        retry=DEFAULT_RETRY_IF_METAGENERATION_SPECIFIED, 
    633    ): 
    634        """Remove all ACL entries. 
    635 
    636        If :attr:`user_project` is set, bills the API request to that project. 
    637 
    638        Note that this won't actually remove *ALL* the rules, but it 
    639        will remove all the non-default rules.  In short, you'll still 
    640        have access to a bucket that you created even after you clear 
    641        ACL rules with this method. 
    642 
    643        :type client: :class:`~google.cloud.storage.client.Client` or 
    644                      ``NoneType`` 
    645        :param client: (Optional) The client to use.  If not passed, falls back 
    646                       to the ``client`` stored on the ACL's parent. 
    647 
    648        :type if_generation_match: long 
    649        :param if_generation_match: 
    650            (Optional) See :ref:`using-if-generation-match` 
    651 
    652        :type if_generation_not_match: long 
    653        :param if_generation_not_match: 
    654            (Optional) See :ref:`using-if-generation-not-match` 
    655 
    656        :type if_metageneration_match: long 
    657        :param if_metageneration_match: 
    658            (Optional) See :ref:`using-if-metageneration-match` 
    659 
    660        :type if_metageneration_not_match: long 
    661        :param if_metageneration_not_match: 
    662            (Optional) See :ref:`using-if-metageneration-not-match` 
    663 
    664        :type timeout: float or tuple 
    665        :param timeout: 
    666            (Optional) The amount of time, in seconds, to wait 
    667            for the server response.  See: :ref:`configuring_timeouts` 
    668 
    669        :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy 
    670        :param retry: 
    671            (Optional) How to retry the RPC. See: :ref:`configuring_retries` 
    672        """ 
    673        with create_trace_span(name="Storage.ACL.clear"): 
    674            self.save( 
    675                [], 
    676                client=client, 
    677                if_generation_match=if_generation_match, 
    678                if_generation_not_match=if_generation_not_match, 
    679                if_metageneration_match=if_metageneration_match, 
    680                if_metageneration_not_match=if_metageneration_not_match, 
    681                timeout=timeout, 
    682                retry=retry, 
    683            ) 
    684 
    685 
    686class BucketACL(ACL): 
    687    """An ACL specifically for a bucket. 
    688 
    689    :type bucket: :class:`google.cloud.storage.bucket.Bucket` 
    690    :param bucket: The bucket to which this ACL relates. 
    691    """ 
    692 
    693    def __init__(self, bucket): 
    694        super(BucketACL, self).__init__() 
    695        self.bucket = bucket 
    696 
    697    @property 
    698    def client(self): 
    699        """The client bound to this ACL's bucket.""" 
    700        return self.bucket.client 
    701 
    702    @property 
    703    def reload_path(self): 
    704        """Compute the path for GET API requests for this ACL.""" 
    705        return f"{self.bucket.path}/{self._URL_PATH_ELEM}" 
    706 
    707    @property 
    708    def save_path(self): 
    709        """Compute the path for PATCH API requests for this ACL.""" 
    710        return self.bucket.path 
    711 
    712    @property 
    713    def user_project(self): 
    714        """Compute the user project charged for API requests for this ACL.""" 
    715        return self.bucket.user_project 
    716 
    717 
    718class DefaultObjectACL(BucketACL): 
    719    """A class representing the default object ACL for a bucket.""" 
    720 
    721    _URL_PATH_ELEM = "defaultObjectAcl" 
    722    _PREDEFINED_QUERY_PARAM = "predefinedDefaultObjectAcl" 
    723 
    724 
    725class ObjectACL(ACL): 
    726    """An ACL specifically for a Cloud Storage object / blob. 
    727 
    728    :type blob: :class:`google.cloud.storage.blob.Blob` 
    729    :param blob: The blob that this ACL corresponds to. 
    730    """ 
    731 
    732    def __init__(self, blob): 
    733        super(ObjectACL, self).__init__() 
    734        self.blob = blob 
    735 
    736    @property 
    737    def client(self): 
    738        """The client bound to this ACL's blob.""" 
    739        return self.blob.client 
    740 
    741    @property 
    742    def reload_path(self): 
    743        """Compute the path for GET API requests for this ACL.""" 
    744        return f"{self.blob.path}/acl" 
    745 
    746    @property 
    747    def save_path(self): 
    748        """Compute the path for PATCH API requests for this ACL.""" 
    749        return self.blob.path 
    750 
    751    @property 
    752    def user_project(self): 
    753        """Compute the user project charged for API requests for this ACL.""" 
    754        return self.blob.user_project 
    755 
    756    def save( 
    757        self, 
    758        acl=None, 
    759        client=None, 
    760        if_generation_match=None, 
    761        if_generation_not_match=None, 
    762        if_metageneration_match=None, 
    763        if_metageneration_not_match=None, 
    764        timeout=_DEFAULT_TIMEOUT, 
    765        retry=DEFAULT_RETRY, 
    766    ): 
    767        """Save this ACL for the current object. 
    768 
    769        If :attr:`user_project` is set, bills the API request to that project. 
    770 
    771        :type acl: :class:`google.cloud.storage.acl.ACL`, or a compatible list. 
    772        :param acl: The ACL object to save.  If left blank, this will save 
    773                    current entries. 
    774 
    775        :type client: :class:`~google.cloud.storage.client.Client` or 
    776                      ``NoneType`` 
    777        :param client: (Optional) The client to use.  If not passed, falls back 
    778                       to the ``client`` stored on the ACL's parent. 
    779 
    780        :type if_generation_match: long 
    781        :param if_generation_match: 
    782            (Optional) See :ref:`using-if-generation-match` 
    783 
    784        :type if_generation_not_match: long 
    785        :param if_generation_not_match: 
    786            (Optional) See :ref:`using-if-generation-not-match` 
    787 
    788        :type if_metageneration_match: long 
    789        :param if_metageneration_match: 
    790            (Optional) See :ref:`using-if-metageneration-match` 
    791 
    792        :type if_metageneration_not_match: long 
    793        :param if_metageneration_not_match: 
    794            (Optional) See :ref:`using-if-metageneration-not-match` 
    795 
    796        :type timeout: float or tuple 
    797        :param timeout: 
    798            (Optional) The amount of time, in seconds, to wait 
    799            for the server response.  See: :ref:`configuring_timeouts` 
    800 
    801        :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy 
    802        :param retry: 
    803            (Optional) How to retry the RPC. See: :ref:`configuring_retries` 
    804        """ 
    805        super().save( 
    806            acl=acl, 
    807            client=client, 
    808            if_generation_match=if_generation_match, 
    809            if_generation_not_match=if_generation_not_match, 
    810            if_metageneration_match=if_metageneration_match, 
    811            if_metageneration_not_match=if_metageneration_not_match, 
    812            timeout=timeout, 
    813            retry=retry, 
    814        ) 
    815 
    816    def save_predefined( 
    817        self, 
    818        predefined, 
    819        client=None, 
    820        if_generation_match=None, 
    821        if_generation_not_match=None, 
    822        if_metageneration_match=None, 
    823        if_metageneration_not_match=None, 
    824        timeout=_DEFAULT_TIMEOUT, 
    825        retry=DEFAULT_RETRY, 
    826    ): 
    827        """Save this ACL for the current object using a predefined ACL. 
    828 
    829        If :attr:`user_project` is set, bills the API request to that project. 
    830 
    831        :type predefined: str 
    832        :param predefined: An identifier for a predefined ACL.  Must be one 
    833                           of the keys in :attr:`PREDEFINED_JSON_ACLS` 
    834                           or :attr:`PREDEFINED_XML_ACLS` (which will be 
    835                           aliased to the corresponding JSON name). 
    836                           If passed, `acl` must be None. 
    837 
    838        :type client: :class:`~google.cloud.storage.client.Client` or 
    839                      ``NoneType`` 
    840        :param client: (Optional) The client to use.  If not passed, falls back 
    841                       to the ``client`` stored on the ACL's parent. 
    842 
    843        :type if_generation_match: long 
    844        :param if_generation_match: 
    845            (Optional) See :ref:`using-if-generation-match` 
    846 
    847        :type if_generation_not_match: long 
    848        :param if_generation_not_match: 
    849            (Optional) See :ref:`using-if-generation-not-match` 
    850 
    851        :type if_metageneration_match: long 
    852        :param if_metageneration_match: 
    853            (Optional) See :ref:`using-if-metageneration-match` 
    854 
    855        :type if_metageneration_not_match: long 
    856        :param if_metageneration_not_match: 
    857            (Optional) See :ref:`using-if-metageneration-not-match` 
    858 
    859        :type timeout: float or tuple 
    860        :param timeout: 
    861            (Optional) The amount of time, in seconds, to wait 
    862            for the server response.  See: :ref:`configuring_timeouts` 
    863 
    864        :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy 
    865        :param retry: 
    866            (Optional) How to retry the RPC. See: :ref:`configuring_retries` 
    867        """ 
    868        super().save_predefined( 
    869            predefined=predefined, 
    870            client=client, 
    871            if_generation_match=if_generation_match, 
    872            if_generation_not_match=if_generation_not_match, 
    873            if_metageneration_match=if_metageneration_match, 
    874            if_metageneration_not_match=if_metageneration_not_match, 
    875            timeout=timeout, 
    876            retry=retry, 
    877        ) 
    878 
    879    def clear( 
    880        self, 
    881        client=None, 
    882        if_generation_match=None, 
    883        if_generation_not_match=None, 
    884        if_metageneration_match=None, 
    885        if_metageneration_not_match=None, 
    886        timeout=_DEFAULT_TIMEOUT, 
    887        retry=DEFAULT_RETRY, 
    888    ): 
    889        """Remove all ACL entries. 
    890 
    891        If :attr:`user_project` is set, bills the API request to that project. 
    892 
    893        Note that this won't actually remove *ALL* the rules, but it 
    894        will remove all the non-default rules.  In short, you'll still 
    895        have access to a bucket that you created even after you clear 
    896        ACL rules with this method. 
    897 
    898        :type client: :class:`~google.cloud.storage.client.Client` or 
    899                      ``NoneType`` 
    900        :param client: (Optional) The client to use.  If not passed, falls back 
    901                       to the ``client`` stored on the ACL's parent. 
    902 
    903        :type if_generation_match: long 
    904        :param if_generation_match: 
    905            (Optional) See :ref:`using-if-generation-match` 
    906 
    907        :type if_generation_not_match: long 
    908        :param if_generation_not_match: 
    909            (Optional) See :ref:`using-if-generation-not-match` 
    910 
    911        :type if_metageneration_match: long 
    912        :param if_metageneration_match: 
    913            (Optional) See :ref:`using-if-metageneration-match` 
    914 
    915        :type if_metageneration_not_match: long 
    916        :param if_metageneration_not_match: 
    917            (Optional) See :ref:`using-if-metageneration-not-match` 
    918 
    919        :type timeout: float or tuple 
    920        :param timeout: 
    921            (Optional) The amount of time, in seconds, to wait 
    922            for the server response.  See: :ref:`configuring_timeouts` 
    923 
    924        :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy 
    925        :param retry: 
    926            (Optional) How to retry the RPC. See: :ref:`configuring_retries` 
    927        """ 
    928        super().clear( 
    929            client=client, 
    930            if_generation_match=if_generation_match, 
    931            if_generation_not_match=if_generation_not_match, 
    932            if_metageneration_match=if_metageneration_match, 
    933            if_metageneration_not_match=if_metageneration_not_match, 
    934            timeout=timeout, 
    935            retry=retry, 
    936        )