Exemple #1
0
 def __get_at_by_psm_app(self):
     """
     Acquiring account access token using PSMApp provisioned by Oracle for
     each tenant. Keeping this path to remain the backward compatibility if
     users are using the client id and secret from Application ANDC. This
     path shouldn't work after IDCS hides client secret of Oracle-created
     Applications. This will be deprecated eventually.
     """
     # 1. acquire IDCS AT
     result = self.__get_at_by_password(
         DefaultAccessTokenProvider._IDCS_SCOPE)
     if result is None:
         raise IllegalStateException(
             'Error acquiring Identity Cloud Service access token, unable '
             + 'to get metadata to proceed acquiring account access token.')
     # 2. look up audience, client id and secret of PSMApp
     auth_header = 'Bearer ' + result
     psm_info = self.__get_psm_app(auth_header)
     if psm_info is None:
         raise IllegalStateException(
             'Error finding required metadata from Identity Cloud Service,'
             + ' unable to proceed acquiring account access token.')
     # 3. acquire PSM AT
     auth_header = self.__get_auth_header(psm_info.client_id,
                                          psm_info.client_secret)
     psm_fqs = psm_info.audience + Utils.PSM_SCOPE
     user_creds = self.__get_user_creds()
     replaced = str.format(DefaultAccessTokenProvider._RO_GRANT_FORMAT,
                           user_creds.get_credential_alias(), psm_fqs)
     payload = replaced + user_creds.get_secret()
     return self.__get_access_token(auth_header, payload, psm_fqs)
Exemple #2
0
 def __add_app(self, auth, payload):
     # Add the custom OAuth client
     response = self.__request_utils.do_post_request(
         self.__idcs_url + Utils.APP_ENDPOINT,
         Utils.scim_headers(self.__host, auth), payload, self.__timeout_ms)
     self.__check_not_none(response, 'response of adding OAuth client')
     response_code = response.get_status_code()
     content = response.get_content()
     if response_code == codes.conflict:
         raise IllegalStateException(
             'OAuth Client ' + self.__name + ' already exists. To ' +
             'recreate, run with ' + OAuthClient._DELETE_FLAG + '. To ' +
             'verify if existing client is configured correctly, run with ' +
             OAuthClient._VERIFY_FLAG)
     elif response_code >= codes.multiple_choices:
         OAuthClient.__idcs_errors(response, 'Adding custom client')
     app_id = 'id'
     oauth_id = 'name'
     secret = 'clientSecret'
     app_id_value = Utils.get_field(content, app_id)
     oauth_id_value = Utils.get_field(content, oauth_id)
     secret_value = Utils.get_field(content, secret)
     if (app_id_value is None or oauth_id_value is None or
             secret_value is None):
         raise IllegalStateException(
             str.format('Unable to find {0} or {1} or {2} in ,' + content,
                        app_id, oauth_id, secret))
     return OAuthClient.Client(app_id_value, oauth_id_value, secret_value)
Exemple #3
0
 def __do_verify(self, errors):
     self.__output('Verifying OAuth Client ' + self.__name)
     try:
         auth = 'Bearer ' + self.__get_bootstrap_token()
         response = self.__request_utils.do_get_request(
             self.__idcs_url + OAuthClient._CLIENT_EP + self.__name + '%22',
             Utils.scim_headers(self.__host, auth), self.__timeout_ms)
         self.__check_not_none(response, 'client metadata')
         response_code = response.get_status_code()
         content = response.get_content()
         if response_code >= codes.multiple_choices:
             OAuthClient.__idcs_errors(
                 response, 'Getting client ' + self.__name)
         grants = Utils.get_field(content, 'allowedGrants')
         if grants is None:
             # No results in response
             raise IllegalStateException(
                 'OAuth Client ' + self.__name + ' doesn\'t exist, or the ' +
                 'token file is invalid, user who downloads the token ' +
                 'must have Identity Domain Administrator role')
         # Verify if client has required grants
         self.__verify_grants(grants, errors)
         # Verify if client has PSM and ANDC FQS
         self.__verify_scopes(
             Utils.get_field(content, 'allowedScopes', 'fqs'), errors)
         # Verify if client has ANDC role
         self.__verify_role(
             Utils.get_field(content, 'grantedAppRoles', 'display'), errors)
         if len(errors) > 0:
             return
         self.__output('Verification succeed')
     except Exception as e:
         self.__output('Verification failed of OAuth client ' + self.__name)
         raise e
Exemple #4
0
 def get_service_access_token(self):
     self._ensure_creds_provider()
     if self._andc_fqs is None:
         self._find_oauth_scopes()
     if self._andc_fqs is None:
         raise IllegalStateException(
             'Unable to find service scope from OAuth Client, retry with ' +
             'service entitlement id.')
     return self._get_at_by_password(self._andc_fqs)
Exemple #5
0
 def __get_psm_app(self, auth_header):
     """
     Get PSMApp metadata from IDCS. The secret of PSMApp will be hidden by
     IDCS, if no secret, return an error to ask users create custom client.
     This will be deprecated eventually.
     """
     # Get PSMApp metadata from IDCS.
     response = self.__request_utils.do_get_request(
         self.__idcs_url + Utils.APP_ENDPOINT +
         DefaultAccessTokenProvider._PSM_APP_FILTER,
         Utils.token_headers(self.__host, auth_header), self.__timeout_ms)
     if response is None:
         raise IllegalStateException(
             'Error getting required metadata from Identity Cloud Service,'
             + ' unable to acquire account access token, no response')
     response_code = response.get_status_code()
     content = response.get_content()
     if response_code >= codes.multiple_choices:
         Utils.handle_idcs_errors(
             response, 'Getting account metadata',
             'Please grant user Identity Domain Administrator or ' +
             'Application Administrator role')
     oauth_id = 'name'
     audience = 'audience'
     secret = 'clientSecret'
     try:
         oauth_id_value = Utils.get_field(content, oauth_id)
         audience_value = Utils.get_field(content, audience)
         secret_value = Utils.get_field(content, secret)
     except IllegalStateException as ise:
         raise UnauthorizedException(
             'Please grant user Identity Domain Administrator or ' +
             'Application Administrator role. ' + str(ise))
     if oauth_id_value is None or audience_value is None:
         raise IllegalStateException(
             'Account metadata response contains invalid value: ' + content)
     if secret_value is None:
         raise IllegalStateException(
             'Account metadata doesn\'t have a secret, unable to acquire ' +
             'account access token. Must create the custom OAuth Client ' +
             'first. Account metadata: ' + content)
     return DefaultAccessTokenProvider.PSMAppInfo(oauth_id_value,
                                                  secret_value,
                                                  audience_value)
Exemple #6
0
 def get_service_access_token(self):
     self.__ensure_creds_provider()
     if self.__andc_fqs is None:
         self.__find_oauth_scopes()
     if self.__andc_fqs is None:
         raise IllegalStateException(
             'Unable to find service scope, OAuth client isn\'t ' +
             'configured properly, run OAuthClient utility to verify and ' +
             'recreate.')
     return self.__get_at_by_password(self.__andc_fqs)
Exemple #7
0
 def __get_bootstrap_token(self):
     # Read access token from given file
     with open(self.__at_file, 'r') as at_file:
         content = at_file.read()
     bootstrap_token = loads(content)
     field = 'app_access_token'
     app_access_token = bootstrap_token.get(field)
     if app_access_token is None:
         raise IllegalStateException(
             'Access token file contains invalid value: ' + content)
     return app_access_token
Exemple #8
0
 def __verify_role(self, roles, errors):
     if roles is None:
         raise IllegalStateException(
             'OAuth client ' + self.__name + ' doesn\'t have roles')
     self.__log_verbose('OAuth client allowed roles: ' + str(roles))
     match = 0
     for role in roles:
         if role == 'ANDC_FullAccessRole':
             match += 1
     if match != 1:
         errors.append('Missing required role ANDC_FullAccessRole')
     self.__log_verbose('Role verification succeed')
Exemple #9
0
 def _get_access_token(self, auth_header, payload, fqs):
     response = self._request_utils.do_post_request(
         self._idcs_url + Utils.TOKEN_ENDPOINT, Utils.token_headers(
             self._host, auth_header), payload, self._timeout_ms)
     if response is None:
         raise IllegalStateException('Error acquiring access token with '
                                     'scope ' + fqs + ', no response')
     response_code = response.get_status_code()
     content = response.get_content()
     if response_code >= codes.multiple_choices:
         self._handle_token_error_response(response_code, content)
     return self._parse_access_token_response(content)
Exemple #10
0
 def __parse_access_token_response(self, response):
     """
     A valid response from IDCS is in JSON format and must contains the field
     "access_token" and "expires_in".
     """
     response = loads(response)
     access_token = response.get(DefaultAccessTokenProvider._AT_FIELD)
     if access_token is None:
         raise IllegalStateException(
             'Access token response contains invalid value, response: ' +
             str(response))
     self.__logutils.log_debug('Acquired access token ' + access_token)
     return access_token
Exemple #11
0
 def get_field(content, field, sub_field=None, allow_none=True):
     content_str = content
     content = loads(content)
     value = content.get(field)
     values = None
     if value is None:
         value = Utils.__get_field_recursively(content, field)
         if not allow_none and value is None:
             raise IllegalStateException(field + ' doesn\'t exist in ' +
                                         content_str)
     if isinstance(value, list) and sub_field is not None:
         values = list()
         for item in value:
             if isinstance(item, dict):
                 values.append(item.get(sub_field))
     return value if sub_field is None else values
Exemple #12
0
 def __get_andc_info(self, auth):
     # Get App ANDC metadata from IDCS
     response = self.__request_utils.do_get_request(
         self.__idcs_url + OAuthClient._ANDC_APP_EP,
         Utils.scim_headers(self.__host, auth), self.__timeout_ms)
     self.__check_not_none(response, 'getting service metadata')
     content = response.get_content()
     if response.get_status_code() >= codes.multiple_choices:
         OAuthClient.__idcs_errors(response, 'Getting service metadata')
     audience = 'audience'
     app_id = 'id'
     audience_value = Utils.get_field(content, audience)
     app_id_value = Utils.get_field(content, app_id)
     if audience_value is None or app_id_value is None:
         raise IllegalStateException(
             str.format('Unable to find {0} or {1} in ,' + content,
                        audience, app_id))
     return OAuthClient.ANDC(app_id_value, audience_value)
Exemple #13
0
    def handle_idcs_errors(response, action, unauthorized_msg):
        """
        Possible error codes returned from IDCS for SCIM endpoints.

        Unexpected case:\n
        307, 308 - redirect-related errors\n
        400 - bad request, indicates code error\n
        403 - request operation is not allowed\n
        404 - this PSMApp doesn't exist\n
        405 - method not allowed\n
        409 - version mismatch\n
        412 - precondition failed for update op\n
        413 - request too long\n
        415 - not acceptable\n
        501 - this method not implemented

        Security failure case:\n
        401 - no permission

        Service unavailable:\n
        500 - internal server error\n
        503 - service unavailable\n
        """
        response_content = response.get_content()
        response_code = response.get_status_code()
        if response_code == codes.unauthorized:
            raise UnauthorizedException(action + ' is unauthorized. ' +
                                        unauthorized_msg +
                                        '. Error response: ' +
                                        response_content)
        elif (response_code == codes.server_error
              or response_code == codes.unavailable):
            raise RequestTimeoutException(
                action + ' error, expect to retry, error response: ' +
                response_content + ', status code: ' + str(response_code))
        else:
            raise IllegalStateException(action +
                                        ' error, IDCS error response: ' +
                                        response_content)
Exemple #14
0
 def _find_oauth_scopes(self):
     # Find PSM and ANDC FQS from allowed scopes of OAuth client.
     if self._andc_fqs is not None and self._psm_fqs is not None:
         return
     creds = self._get_client_creds()
     oauth_id = creds.get_credential_alias()
     auth = self._get_auth_header(oauth_id, creds.get_secret())
     try:
         auth = 'Bearer ' + self._get_access_token(
             auth, DefaultAccessTokenProvider._CLIENT_GRANT_PAYLOAD,
             DefaultAccessTokenProvider._IDCS_SCOPE)
     except InvalidAuthorizationException as iae:
         self._logutils.log_info(
             str.format('Unable to find FQS from OAuth client {0}: {1}.',
                        oauth_id, str(iae)))
         return
     response = self._request_utils.do_get_request(
         self._idcs_url + Utils.APP_ENDPOINT +
         DefaultAccessTokenProvider._CLIENT_FILTER + '%22' + oauth_id +
         '%22', Utils.scim_headers(self._host, auth), self._timeout_ms)
     if response is None:
         raise IllegalStateException(
             'Error getting client metadata from Identity Cloud Service, ' +
             'no response.')
     if response.get_status_code() >= codes.multiple_choices:
         Utils.handle_idcs_errors(
             response, 'Getting client metadata',
             'Please verify if the OAuth client is configured properly.')
     fqs_list = Utils.get_field(
         response.get_content(), 'allowedScopes', 'fqs')
     if fqs_list is None:
         return
     for fqs in fqs_list:
         if fqs.startswith(AccessTokenProvider.ANDC_AUD_PREFIX):
             self._andc_fqs = fqs
         elif fqs.endswith(Utils.PSM_SCOPE):
             self._psm_fqs = fqs
Exemple #15
0
 def __check_not_none(self, response, action):
     if response is None:
         raise IllegalStateException(
             'Error ' + action + ' from Oracle Identity Cloud Service, ' +
             'no response')