def main():
    try:
        Utils.GetAuthToken(login_email, password, AUTH_TOKEN_SERVICE, LIB_SIG,
                           None)
    except AuthTokenError, e:
        if str(e).find('InvalidSecondFactor') != -1:
            print """The user has enabled two factor authentication in this
  account. Have the user generate an application-specific password to make
  calls against the AdWords API. See
  http://adwordsapi.blogspot.com/2011/02/authentication-changes-with-2-step.html
  for more details."""
        else:
            raise e
    def _SetHeaders(self):
        """Sets the SOAP headers for this service's requests."""
        now = time.time()
        if ((('authToken' not in self._headers
              and 'auth_token_epoch' not in self._config) or
             int(now - self._config['auth_token_epoch']) >= AUTH_TOKEN_EXPIRE)
                and not self._headers.get('oauth2credentials')):
            if ('email' not in self._headers or not self._headers['email']
                    or 'password' not in self._headers
                    or not self._headers['password']):
                raise ValidationError(
                    'Required authentication headers, \'email\' and '
                    '\'password\', are missing. Unable to regenerate '
                    'authentication token.')
            self._headers['authToken'] = Utils.GetAuthToken(
                self._headers['email'], self._headers['password'],
                AUTH_TOKEN_SERVICE, LIB_SIG, self._config['proxy'])
            self._config['auth_token_epoch'] = time.time()

        # Apply headers to the SOAPpy service.
        soap_headers = SOAPpy.Types.headerType(
            attrs={'xmlns': self._namespace})
        request_header_data = {}
        if 'authToken' in self._headers:
            authentication_block = SOAPpy.Types.structType(
                data={'token': self._headers['authToken']},
                name='authentication',
                typed=0,
                attrs={(SOAPpy.NS.XSI3, 'type'): 'ClientLogin'})
            request_header_data['authentication'] = authentication_block
        for key in self._headers:
            if (key in GenericDfpService._IGNORED_HEADER_VALUES
                    or not self._headers[key]):
                continue
            value = self._headers[key]
            if key == 'applicationName':
                value = ''.join([value, LIB_SIG])
            request_header_data[key] = SOAPpy.Types.stringType(value)
        request_header = SOAPpy.Types.structType(data=request_header_data,
                                                 name='RequestHeader',
                                                 typed=0)
        soap_headers.RequestHeader = request_header
        if 'authToken' in self._headers:
            soap_headers.RequestHeader._keyord = [
                'applicationName', 'authentication'
            ]
        self._soappyservice.soapproxy.header = soap_headers
    def _SetHeaders(self):
        """Sets the SOAP headers for this service's requests."""
        now = time.time()
        if ((('authToken' not in self._headers
              and 'auth_token_epoch' not in self._config) or
             int(now - self._config['auth_token_epoch']) >= AUTH_TOKEN_EXPIRE)
                and not self._headers.get('oauth2credentials')):
            if ('email' not in self._headers or not self._headers['email']
                    or 'password' not in self._headers
                    or not self._headers['password']):
                raise ValidationError(
                    'Required authentication headers, \'email\' and '
                    '\'password\', are missing. Unable to regenerate '
                    'authentication token.')
            self._headers['authToken'] = Utils.GetAuthToken(
                self._headers['email'], self._headers['password'],
                AUTH_TOKEN_SERVICE, LIB_SIG, self._config['proxy'])
            self._config['auth_token_epoch'] = time.time()

        # Apply headers to the SOAPpy service.
        header_attrs = {
            'xmlns':
            self._namespace,
            'xmlns:cm': ('https://adwords.google.com/api/adwords/cm/' +
                         self._op_config['version'])
        }
        soap_headers = SOAPpy.Types.headerType(attrs=header_attrs)
        request_header_data = {}
        for key in GenericAdWordsService._POSSIBLE_ADWORDS_REQUEST_HEADERS:
            if (key in GenericAdWordsService._OAUTH_IGNORE_HEADERS
                    and self._headers.get('oauth2credentials')):
                continue
            if key in self._headers and self._headers[key]:
                value = self._headers[key]
                if key in GenericAdWordsService._STR_CONVERT:
                    value = str(value)
                elif key == 'userAgent':
                    value = ''.join([value, LIB_SIG])
                request_header_data['cm:' +
                                    key] = SOAPpy.Types.stringType(value)
        request_header = SOAPpy.Types.structType(data=request_header_data,
                                                 name='RequestHeader',
                                                 typed=0)
        soap_headers.RequestHeader = request_header
        self._soappyservice.soapproxy.header = soap_headers
 def __ReloadAuthToken(self):
   """Ensures we have a valid auth_token in our headers."""
   # Load/set authentication token. If authentication token has expired,
   # regenerate it.
   now = time.time()
   if (('authToken' not in self.__service._headers and
        'auth_token_epoch' not in self._config) or
       int(now - self._config['auth_token_epoch']) >= AUTH_TOKEN_EXPIRE):
     if ('email' not in self.__service._headers or
         not self._headers['email'] or
         'password' not in self.__service._headers or
         not self.__service._headers['password']):
       msg = ('Required authentication headers, \'email\' and \'password\', '
              'are missing. Unable to regenerate authentication token.')
       raise ValidationError(msg)
     self._headers['authToken'] = Utils.GetAuthToken(
         self.__service._headers['email'], self.__service._headers['password'],
         AUTH_TOKEN_SERVICE, LIB_SIG, self._config['proxy'])
     self._config['auth_token_epoch'] = time.time()
  def __init__(self, headers=None, config=None, path=None):
    """Inits Client.

    Args:
      [optional]
      headers: dict Object with populated authentication credentials.
      config: dict Object with client configuration values.
      path: str Relative or absolute path to home directory (i.e. location of
            pickles and logs/).

    Example:
      headers = {
        'email': '*****@*****.**',
        'password': '******',
        'authToken': '...',
        'applicationName': 'GoogleTest',
        'networkCode': 'ca-01234567',
        'oauth2credentials': 'See use_oauth2.py'
      }
      config = {
        'home': '/path/to/home',
        'log_home': '/path/to/logs/home',
        'proxy': 'http://example.com:8080',
        'xml_parser': '1', # PYXML = 1, ELEMENTREE = 2
        'debug': 'n',
        'raw_debug': 'n',
        'xml_log': 'y',
        'request_log': 'y',
        'raw_response': 'n',
        'strict': 'y',
        'pretty_xml': 'y',
        'compress': 'y',
        'access': ''
      }
      path = '/path/to/home'
    """
    super(DfpClient, self).__init__(headers, config, path)

    self.__lock = thread.allocate_lock()
    self.__loc = None

    if path is not None:
      # Update absolute path for a given instance of DfpClient, based on
      # provided relative path.
      if os.path.isabs(path):
        DfpClient.home = path
      else:
        # NOTE(api.sgrinberg): Keep first parameter of join() as os.getcwd(),
        # do not change it to DfpClient.home. Otherwise, may break when
        # multiple instances of DfpClient exist during program run.
        DfpClient.home = os.path.join(os.getcwd(), path)

      # If pickles don't exist at given location, default to "~".
      if (not headers and not config and
          (not os.path.exists(os.path.join(DfpClient.home,
                                           DfpClient.auth_pkl_name)) or
           not os.path.exists(os.path.join(DfpClient.home,
                                           DfpClient.config_pkl_name)))):
        DfpClient.home = os.path.expanduser('~')
    elif not headers:
      DfpClient.home = os.path.expanduser('~')

    # Update location for both pickles.
    DfpClient.auth_pkl = os.path.join(DfpClient.home,
                                      DfpClient.auth_pkl_name)
    DfpClient.config_pkl = os.path.join(DfpClient.home,
                                        DfpClient.config_pkl_name)

    # Only load from the pickle if config wasn't specified.
    self._config = config or self.__LoadConfigValues()
    self._config = self.__SetMissingDefaultConfigValues(self._config)
    self._config['home'] = DfpClient.home

    # Validate XML parser to use.
    SanityCheck.ValidateConfigXmlParser(self._config['xml_parser'])

    # Only load from the pickle if 'headers' wasn't specified.
    if headers is None:
      self._headers = self.__LoadAuthCredentials()
    else:
      if Utils.BoolTypeConvert(self._config['strict']):
        SanityCheck.ValidateRequiredHeaders(headers, REQUIRED_SOAP_HEADERS)
      self._headers = headers

    # Load/set authentication token.
    try:
      if headers and 'authToken' in headers and headers['authToken']:
        self._headers['authToken'] = headers['authToken']
      elif 'email' in self._headers and 'password' in self._headers:
        self._headers['authToken'] = Utils.GetAuthToken(
            self._headers['email'], self._headers['password'],
            AUTH_TOKEN_SERVICE, LIB_SIG, self._config['proxy'])
      elif (self._headers.get('oauth2credentials')):
        # If they have oauth2credentials, that's also fine.
        pass
      else:
        msg = ('Authentication data, email or/and password, OAuth2 credentials '
               'is missing.')
        raise ValidationError(msg)
      self._config['auth_token_epoch'] = time.time()
    except AuthTokenError:
      # We would end up here if non-valid Google Account's credentials were
      # specified.
      self._headers['authToken'] = None
      self._config['auth_token_epoch'] = 0

    # Initialize logger.
    self.__logger = Logger(LIB_SIG, self._config['log_home'])
    def CallMethod(self,
                   method_name,
                   params,
                   service_name=None,
                   loc=None,
                   request=None):
        """Make an API call to specified method.

    Args:
      method_name: str API method name.
      params: list List of parameters to send to the API method.
      [optional]
      service_name: str API service name.
      loc: service Locator.
      request: instance Holder of the SOAP request.

    Returns:
      tuple/str Response from the API method. If 'raw_response' flag enabled a
                string is returned, tuple otherwise.
    """
        # Acquire thread lock.
        self._lock.acquire()

        try:
            if not service_name and self.__service:
                service_name = self.__service
            headers = self._headers
            config = self._config
            config['data_injects'] = ()
            error = {}

            # Load/unload version specific authentication and configuration data.
            if AdWordsSanityCheck.IsJaxbApi(self._op_config['version']):
                # Set boolean to the format expected by the server, True => true.
                for key in ['validateOnly', 'partialFailure']:
                    if key in self._headers:
                        self._headers[key] = self._headers[key].lower()

                # Load/set authentication token. If authentication token has expired,
                # regenerate it.
                now = time.time()
                if ((('authToken' not in headers and 'auth_token_epoch'
                      not in config) or int(now - config['auth_token_epoch'])
                     >= AUTH_TOKEN_EXPIRE) and not 'oauth_enabled' in config):
                    if ('email' not in headers or not headers['email']
                            or 'password' not in headers
                            or not headers['password']):
                        msg = (
                            'Required authentication headers, \'email\' and '
                            '\'password\', are missing. Unable to regenerate '
                            'authentication token.')
                        raise ValidationError(msg)
                    headers['authToken'] = Utils.GetAuthToken(
                        headers['email'], headers['password'],
                        AUTH_TOKEN_SERVICE, LIB_SIG, config['proxy'])
                    config['auth_token_epoch'] = time.time()
                    self._headers = headers
                    self._config = config
                headers = Utils.UnLoadDictKeys(
                    headers, ['email', 'password', 'useragent'])
                ns = '/'.join([
                    'https://adwords.google.com/api/adwords',
                    self._op_config['group'], self._op_config['version']
                ])
                default_ns = '/'.join([
                    'https://adwords.google.com/api/adwords',
                    self._op_config['default_group'],
                    self._op_config['version']
                ])
                config['ns_target'] = (ns, 'RequestHeader')

                if (config['soap_lib'] == SOAPPY
                        and (self._op_config['default_group'] !=
                             self._op_config['group']
                             or self.__service == 'BulkMutateJobService')):
                    from adspygoogle.adwords.soappy import SERVICE_TYPES
                    data_injects = []
                    for header in headers:
                        if headers[header]:
                            data_injects.append((header, 'ns1:%s' % header))
                    data_injects.append(
                        ('<RequestHeader>',
                         '<RequestHeader xmlns="%s" xmlns:ns1="%s">' %
                         (ns, default_ns)))
                    data_injects.append(
                        ('<SOAP-ENV:Body xmlns="%s">' % ns,
                         '<SOAP-ENV:Body xmlns="%s" xmlns:ns1="%s">' %
                         (ns, default_ns)))
                    for item in SERVICE_TYPES:
                        if (item['group'] == self._op_config['default_group']
                                and re.compile(
                                    '<%s>|<%s ' %
                                    (item['attr'],
                                     item['attr'])).findall(params)):
                            # TODO(api.sgrinberg): Find a more elegant solution that doesn't
                            # involve manual triggering for attributes that show up in both
                            # groups.
                            if ((self._op_config['group'] == 'o'
                                 and item['attr'] == 'urls') or
                                (self.__service == 'TrafficEstimatorService'
                                 and item['attr'] == 'maxCpc')
                                    or item['attr'] == 'selector'
                                    or item['attr'] == 'operator'):
                                continue
                            if self.__service != 'BulkMutateJobService':
                                data_injects.append(
                                    (' xsi3:type="%s">' % item['type'], '>'))
                            data_injects.append(('<%s>' % item['attr'],
                                                 '<ns1:%s>' % item['attr']))
                            data_injects.append(('<%s ' % item['attr'],
                                                 '<ns1:%s ' % item['attr']))
                            data_injects.append(('</%s>' % item['attr'],
                                                 '</ns1:%s>' % item['attr']))
                    config['data_injects'] = tuple(data_injects)
            else:
                headers['useragent'] = headers['userAgent']
                headers = Utils.UnLoadDictKeys(headers,
                                               ['authToken', 'userAgent'])
                config = Utils.UnLoadDictKeys(
                    config, ['ns_target', 'auth_token_epoch'])

            buf = AdWordsSoapBuffer(xml_parser=self._config['xml_parser'],
                                    pretty_xml=Utils.BoolTypeConvert(
                                        self._config['pretty_xml']))

            start_time = time.strftime('%Y-%m-%d %H:%M:%S')
            response = super(AdWordsWebService, self).CallMethod(
                headers, config, method_name, params, buf,
                AdWordsSanityCheck.IsJaxbApi(self._op_config['version']),
                LIB_SIG, LIB_URL, service_name, loc, request)
            stop_time = time.strftime('%Y-%m-%d %H:%M:%S')

            # Restore list type which was overwritten by SOAPpy.
            if config['soap_lib'] == SOAPPY and isinstance(response, tuple):
                from adspygoogle.common.soappy import MessageHandler
                holder = []
                for element in response:
                    holder.append(
                        MessageHandler.RestoreListType(
                            element, ('value', 'partialFailureErrors',
                                      'conversionTypes')))
                response = tuple(holder)

            if isinstance(response, dict) or isinstance(response, Error):
                error = response

            if not Utils.BoolTypeConvert(self.__config['raw_debug']):
                self.__ManageSoap(buf, start_time, stop_time, error)
        finally:
            # Release thread lock.
            if self._lock.locked():
                self._lock.release()

        if Utils.BoolTypeConvert(self._config['raw_response']):
            return response
        return response
    def CallMethod(self,
                   method_name,
                   params,
                   service_name=None,
                   loc=None,
                   request=None):
        """Make an API call to specified method.

    Args:
      method_name: str API method name.
      params: list List of parameters to send to the API method.
      [optional]
      service_name: str API service name.
      loc: service Locator.
      request: instance Holder of the SOAP request.

    Returns:
      tuple/str Response from the API method. If 'raw_response' flag enabled a
                string is returned, tuple otherwise.
    """
        # Acquire thread lock.
        self._lock.acquire()

        try:
            headers = self._headers
            config = self._config
            config['data_injects'] = ()
            error = {}

            # Load/set authentication token. If authentication token has expired,
            # regenerate it.
            now = time.time()
            if ((('authToken' not in headers
                  and 'auth_token_epoch' not in config) or
                 int(now - config['auth_token_epoch']) >= AUTH_TOKEN_EXPIRE)):
                headers['authToken'] = Utils.GetAuthToken(
                    headers['email'], headers['password'], AUTH_TOKEN_SERVICE,
                    LIB_SIG, config['proxy'])
                config['auth_token_epoch'] = time.time()
                self._headers = headers
                self._config = config

            headers = Utils.UnLoadDictKeys(Utils.CleanUpDict(headers),
                                           ['email', 'password'])
            name_space = '/'.join([
                'https://www.google.com/apis/ads/publisher',
                self._op_config['version']
            ])
            config['ns_target'] = (name_space, 'RequestHeader')

            # Load new authentication headers, starting with version v201103.
            data_injects = []
            if self.__op_config['version'] > 'v201101':
                new_headers = {}
                for key in headers:
                    if key == 'authToken' and headers[key]:
                        if config['soap_lib'] == SOAPPY:
                            data_injects.append(
                                ('<authentication>',
                                 '<authentication xsi3:type="ClientLogin">'))
                            config['data_injects'] = tuple(data_injects)
                        else:
                            config['auth_type'] = 'ClientLogin'
                        new_headers['authentication'] = {
                            'token': headers['authToken']
                        }
                    elif key == 'oAuthToken' and headers[key]:
                        # TODO(api.sgrinberg): Add support for OAuth.
                        pass
                    else:
                        new_headers[key] = headers[key]
                headers = new_headers

            buf = DfpSoapBuffer(xml_parser=self._config['xml_parser'],
                                pretty_xml=Utils.BoolTypeConvert(
                                    self._config['pretty_xml']))

            start_time = time.strftime('%Y-%m-%d %H:%M:%S')
            response = super(DfpWebService, self).CallMethod(
                headers, config, method_name, params, buf,
                DfpSanityCheck.IsJaxbApi(self._op_config['version']), LIB_SIG,
                LIB_URL, service_name, loc, request)
            stop_time = time.strftime('%Y-%m-%d %H:%M:%S')

            # Restore list type which was overwritten by SOAPpy.
            if config['soap_lib'] == SOAPPY and isinstance(response, tuple):
                from adspygoogle.common.soappy import MessageHandler
                holder = []
                for element in response:
                    holder.append(
                        MessageHandler.RestoreListType(
                            element, ('results', 'afcFormats', 'sizes',
                                      'targetedAdUnitIds', 'excludedAdUnitIds',
                                      'targetedPlacementIds', 'frequencyCaps',
                                      'creativeSizes')))
                response = tuple(holder)

            if isinstance(response, dict) or isinstance(response, Error):
                error = response

            if not Utils.BoolTypeConvert(self.__config['raw_debug']):
                self.__ManageSoap(buf, start_time, stop_time, error)
        finally:
            # Release thread lock.
            if self._lock.locked():
                self._lock.release()

        if Utils.BoolTypeConvert(self._config['raw_response']):
            return response
        return response