storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/docs/sts/client_grants/__init__.py (about)

     1  # -*- coding: utf-8 -*-
     2  # Licensed under the Apache License, Version 2.0 (the "License");
     3  # you may not use this file except in compliance with the License.
     4  # You may obtain a copy of the License at
     5  #
     6  #     http://www.apache.org/licenses/LICENSE-2.0
     7  #
     8  # Unless required by applicable law or agreed to in writing, software
     9  # distributed under the License is distributed on an "AS IS" BASIS,
    10  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  # See the License for the specific language governing permissions and
    12  # limitations under the License.
    13  
    14  import json
    15  # standard.
    16  import os
    17  
    18  import certifi
    19  # Dependencies
    20  import urllib3
    21  from botocore.credentials import CredentialProvider, RefreshableCredentials
    22  from botocore.exceptions import CredentialRetrievalError
    23  from dateutil.parser import parse
    24  
    25  from .sts_element import STSElement
    26  
    27  
    28  class ClientGrantsCredentialProvider(CredentialProvider):
    29      """
    30      ClientGrantsCredentialProvider implements CredentialProvider compatible
    31      implementation to be used with boto_session
    32      """
    33      METHOD = 'assume-role-client-grants'
    34      CANONICAL_NAME = 'AssumeRoleClientGrants'
    35  
    36      def __init__(self, cid, csec,
    37                   idp_ep='http://localhost:8080/auth/realms/minio/protocol/openid-connect/token',
    38                   sts_ep='http://localhost:9000'):
    39          self.cid = cid
    40          self.csec = csec
    41          self.idp_ep = idp_ep
    42          self.sts_ep = sts_ep
    43  
    44          # Load CA certificates from SSL_CERT_FILE file if set
    45          ca_certs = os.environ.get('SSL_CERT_FILE')
    46          if not ca_certs:
    47              ca_certs = certifi.where()
    48  
    49          self._http = urllib3.PoolManager(
    50              timeout=urllib3.Timeout.DEFAULT_TIMEOUT,
    51              maxsize=10,
    52              cert_reqs='CERT_NONE',
    53              ca_certs=ca_certs,
    54              retries=urllib3.Retry(
    55                  total=5,
    56                  backoff_factor=0.2,
    57                  status_forcelist=[500, 502, 503, 504]
    58              )
    59          )
    60  
    61      def load(self):
    62          """
    63          Search for credentials with client_grants
    64          """
    65          if self.cid is not None:
    66              fetcher = self._create_credentials_fetcher()
    67              return RefreshableCredentials.create_from_metadata(
    68                  metadata=fetcher(),
    69                  refresh_using=fetcher,
    70                  method=self.METHOD,
    71              )
    72          else:
    73              return None
    74  
    75      def _create_credentials_fetcher(self):
    76          method = self.METHOD
    77  
    78          def fetch_credentials():
    79              # HTTP headers are case insensitive filter out
    80              # all duplicate headers and pick one.
    81              headers = {}
    82              headers['content-type'] = 'application/x-www-form-urlencoded'
    83              headers['authorization'] = urllib3.make_headers(
    84                  basic_auth='%s:%s' % (self.cid, self.csec))['authorization']
    85  
    86              response = self._http.urlopen('POST', self.idp_ep,
    87                                            body="grant_type=client_credentials",
    88                                            headers=headers,
    89                                            preload_content=True,
    90                                            )
    91              if response.status != 200:
    92                  message = "Credential refresh failed, response: %s"
    93                  raise CredentialRetrievalError(
    94                      provider=method,
    95                      error_msg=message % response.status,
    96                  )
    97  
    98              creds = json.loads(response.data)
    99  
   100              query = {}
   101              query['Action'] = 'AssumeRoleWithClientGrants'
   102              query['Token'] = creds['access_token']
   103              query['DurationSeconds'] = creds['expires_in']
   104              query['Version'] = '2011-06-15'
   105  
   106              query_components = []
   107              for key in query:
   108                  if query[key] is not None:
   109                      query_components.append("%s=%s" % (key, query[key]))
   110  
   111              query_string = '&'.join(query_components)
   112              sts_ep_url = self.sts_ep
   113              if query_string:
   114                  sts_ep_url = self.sts_ep + '?' + query_string
   115  
   116              response = self._http.urlopen(
   117                  'POST', sts_ep_url, preload_content=True)
   118              if response.status != 200:
   119                  message = "Credential refresh failed, response: %s"
   120                  raise CredentialRetrievalError(
   121                      provider=method,
   122                      error_msg=message % response.status,
   123                  )
   124  
   125              return parse_grants_response(response.data)
   126  
   127          def parse_grants_response(data):
   128              """
   129              Parser for AssumeRoleWithClientGrants response
   130  
   131              :param data: Response data for AssumeRoleWithClientGrants request
   132              :return: dict
   133              """
   134              root = STSElement.fromstring(
   135                  'AssumeRoleWithClientGrantsResponse', data)
   136              result = root.find('AssumeRoleWithClientGrantsResult')
   137              creds = result.find('Credentials')
   138              return dict(
   139                  access_key=creds.get_child_text('AccessKeyId'),
   140                  secret_key=creds.get_child_text('SecretAccessKey'),
   141                  token=creds.get_child_text('SessionToken'),
   142                  expiry_time=parse(creds.get_child_text('Expiration')).isoformat())
   143  
   144          return fetch_credentials