Skip to content

Commit a2454b1

Browse files
author
Nicholas Chen
committed
Adding Service Account support to the GoogleAds Library
1 parent 649d060 commit a2454b1

File tree

56 files changed

+2849
-306
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+2849
-306
lines changed

ChangeLog

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,22 @@
1+
3.0.0 - 1/5/2015
2+
* Three new dependencies have been added: httplib2, oauth2client, and pysocks.
3+
* One dependency has been removed: oauthlib
4+
* BREAKING CHANGE: Python3 versions < 3.3 are no longer supported.
5+
* BREAKING CHANGE: The https_proxy argument for the GoogleRefreshTokenClient has
6+
been deprecated. It has been replaced by proxy_info, which is an optional
7+
argument taking an httplib2.ProxyInfo instance.
8+
* PYTHON2 ONLY: You may now authorize with Service Accounts using the new
9+
GoogleServiceAccountClient. As of this release, it will only work with
10+
Python2.
11+
* Added new Service Account authorization examples for AdWords, DFA, and DFP.
12+
* The googleads.yaml file has been refactored to reflect the changes to proxy
13+
support.
14+
* WARNING: As of this release, you must set disable_ssl_certificate_validation
15+
to False when using Python3.
16+
* Added new examples for DFP Sales Manager: PremiumRateService, BaseRateService,
17+
ExchangeRateService, RateCardService, WorkflowRequestService, ProductService,
18+
ProductTemplateService.
19+
120
2.3.0 - 12/05/2014
221
* Removed v201402 support.
322
* The return_money_in_micros argument has been removed from the AdWords
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,6 @@
1+
1.0.1 - 1/5/2015
2+
- Updated dependencies listed in README, for the changes introduced in googleads
3+
3.0.0.
4+
15
1.0.0:
26
- Initial release of the demo.

examples/adwords/adwords_appengine_demo/README

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -60,30 +60,33 @@ prepared your OAuth2 Credentials via the Google Developers Console.
6060
6. Copy the httplib2 package from your Python installation's dist-packages
6161
directory into this project.
6262

63-
7. Copy the oauthlib package from your Python installation's dist-packages
63+
7. Copy the oauth2client package from your Python installation's dist-packages
6464
directory into this project.
6565

6666
8. Copy the pytz package from your Python installation's dist-packages
6767
directory into this project.
6868

69-
9. Copy the suds package from your Python installation's dist-packages
69+
9. Copy socks.py from the PySocks tarball found in your Python installation's
70+
dist-packages directory into this project.
71+
72+
10. Copy the suds package from your Python installation's dist-packages
7073
directory into this project.
7174

72-
10. Create an App Engine application in the
75+
11. Create an App Engine application in the
7376
[Google App Engine Console](https://appengine.google.com/).
7477

75-
11. Go to this project's app.yaml, and enter in your application name for the
78+
12. Go to this project's app.yaml, and enter in your application name for the
7679
"application" field.
7780

78-
12. You can now deploy this project by running the following command:
81+
13. You can now deploy this project by running the following command:
7982

8083
`python $APPENGINE_SDK_DIR/appcfg --oauth2 update .`
8184

82-
12. When you go to your App for the first time, you will need to log in and
85+
14. When you go to your App for the first time, you will need to log in and
8386
provide OAuth2 and AdWords API credentials. You can use credentials
8487
generated via the generate_refresh_token.py example.
8588

86-
13. With all information entered, you can now use the UI to view and modify
89+
15. With all information entered, you can now use the UI to view and modify
8790
your account details.
8891

8992

@@ -97,7 +100,8 @@ Submit bug reports or feature requests to our
97100

98101
* [Python v2.7](https://www.python.org/downloads/)
99102
* [httplib2 v0.9+](https://pypi.python.org/pypi/httplib2)
100-
* [oauthlib v0.6.3+](https://pypi.python.org/pypi/oauthlib)
103+
* [oauth2client v1.4.5+](https://pypi.python.org/pypi/oauth2client/)
104+
* [pysocks v1.5.0+](https://pypi.python.org/pypi/PySocks/)
101105
* [pytz 2014.7+](https://pypi.python.org/pypi/pytz)
102106
* [suds-jurko 0.6+](https://pypi.python.org/pypi/suds-jurko)
103107
* [App Engine SDK v1.9.11+](https://developers.google.com/appengine/downloads)
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#!/usr/bin/python
2+
#
3+
# Copyright 2014 Google Inc. All Rights Reserved.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
"""Initializes an AdWordsClient via impersonation using a Service Account."""
18+
19+
__author__ = 'Mark Saniscalchi'
20+
21+
from googleads import adwords
22+
from googleads import oauth2
23+
24+
# OAuth 2.0 credential information. In a real application, you'd probably be
25+
# pulling these values from a credential storage.
26+
SERVICE_ACCOUNT_EMAIL = 'INSERT_SERVICE_ACCOUNT_EMAIL_HERE'
27+
KEY_FILE = 'INSERT_PATH_TO_KEY_FILE'
28+
SERVICE_ACCOUNT_USER = 'INSERT_IMPERSONATED_EMAIL_HERE'
29+
30+
# AdWords API information.
31+
DEVELOPER_TOKEN = 'INSERT_DEVELOPER_TOKEN_HERE'
32+
USER_AGENT = 'INSERT_USER_AGENT_HERE'
33+
CLIENT_CUSTOMER_ID = 'INSERT_CLIENT_CUSTOMER_ID_HERE'
34+
35+
36+
def main(service_account_email, key_file, service_account_user,
37+
developer_token, user_agent, client_customer_id):
38+
oauth2_client = oauth2.GoogleServiceAccountClient(
39+
oauth2.GetAPIScope('adwords'), service_account_email, key_file,
40+
sub=service_account_user)
41+
42+
adwords_client = adwords.AdWordsClient(
43+
developer_token, oauth2_client, user_agent, client_customer_id)
44+
45+
customer = adwords_client.GetService('CustomerService').get()
46+
print 'You are logged in as customer: %s' % customer['customerId']
47+
48+
49+
if __name__ == '__main__':
50+
main(SERVICE_ACCOUNT_EMAIL, KEY_FILE, SERVICE_ACCOUNT_USER,
51+
DEVELOPER_TOKEN, USER_AGENT, CLIENT_CUSTOMER_ID)

examples/adwords/authentication/generate_refresh_token.py

Lines changed: 23 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -16,61 +16,46 @@
1616

1717
"""Generates refresh token for AdWords using the Installed Application flow."""
1818

19-
__author__ = 'Joseph DiLallo'
19+
__author__ = 'Mark Saniscalchi'
2020

2121
import sys
22-
import urllib2
2322

24-
from oauthlib import oauth2
23+
from oauth2client import client
2524

2625
# Your OAuth 2.0 Client ID and Secret. If you do not have an ID and Secret yet,
2726
# please go to https://console.developers.google.com and create a set.
2827
CLIENT_ID = 'INSERT_CLIENT_ID_HERE'
2928
CLIENT_SECRET = 'INSERT_CLIENT_SECRET_HERE'
3029

31-
# You may optionally provide an HTTPS proxy.
32-
HTTPS_PROXY = None
33-
3430
# The AdWords API OAuth 2.0 scope.
3531
SCOPE = u'https://www.googleapis.com/auth/adwords'
36-
# This callback URL will allow you to copy the token from the success screen.
37-
CALLBACK_URL = 'urn:ietf:wg:oauth:2.0:oob'
38-
# The HTTP headers needed on OAuth 2.0 refresh requests.
39-
OAUTH2_REFRESH_HEADERS = {'content-type':
40-
'application/x-www-form-urlencoded'}
41-
# The web address for generating new OAuth 2.0 credentials at Google.
42-
GOOGLE_OAUTH2_AUTH_ENDPOINT = 'https://accounts.google.com/o/oauth2/auth'
43-
GOOGLE_OAUTH2_GEN_ENDPOINT = 'https://accounts.google.com/o/oauth2/token'
4432

4533

4634
def main():
47-
oauthlib_client = oauth2.WebApplicationClient(CLIENT_ID)
48-
49-
authorize_url = oauthlib_client.prepare_request_uri(
50-
GOOGLE_OAUTH2_AUTH_ENDPOINT, redirect_uri=CALLBACK_URL, scope=SCOPE)
51-
print ('Log in to your AdWords account and open the following URL: \n%s\n' %
52-
authorize_url)
35+
"""Retrieve and display the access and refresh token."""
36+
flow = client.OAuth2WebServerFlow(
37+
client_id=CLIENT_ID,
38+
client_secret=CLIENT_SECRET,
39+
scope=[SCOPE],
40+
user_agent='Ads Python Client Library',
41+
redirect_uri='urn:ietf:wg:oauth:2.0:oob')
42+
43+
authorize_url = flow.step1_get_authorize_url()
44+
45+
print ('Log into the Google Account you use to access your AdWords account'
46+
'and go to the following URL: \n%s\n' % (authorize_url))
5347
print 'After approving the token enter the verification code (if specified).'
5448
code = raw_input('Code: ').strip()
5549

56-
post_body = oauthlib_client.prepare_request_body(
57-
client_secret=CLIENT_SECRET, code=code, redirect_uri=CALLBACK_URL)
58-
if sys.version_info[0] == 3:
59-
post_body = bytes(post_body, 'utf8')
60-
request = urllib2.Request(GOOGLE_OAUTH2_GEN_ENDPOINT, post_body,
61-
OAUTH2_REFRESH_HEADERS)
62-
if HTTPS_PROXY:
63-
request.set_proxy(HTTPS_PROXY, 'https')
64-
raw_response = urllib2.urlopen(request).read().decode()
65-
oauth2_credentials = oauthlib_client.parse_request_body_response(raw_response)
66-
67-
print ('Your access token is %s and your refresh token is %s'
68-
% (oauth2_credentials['access_token'],
69-
oauth2_credentials['refresh_token']))
70-
print ('You can cache these credentials into a yaml file with the '
71-
'following keys:\nadwords:\n client_id: %s\n client_secret: %s\n'
72-
' refresh_token: %s\n'
73-
% (CLIENT_ID, CLIENT_SECRET, oauth2_credentials['refresh_token']))
50+
try:
51+
credential = flow.step2_exchange(code)
52+
except client.FlowExchangeError, e:
53+
print 'Authentication has failed: %s' % e
54+
sys.exit(1)
55+
else:
56+
print ('OAuth 2.0 authorization successful!\n\n'
57+
'Your access token is:\n %s\n\nYour refresh token is:\n %s'
58+
% (credential.access_token, credential.refresh_token))
7459

7560

7661
if __name__ == '__main__':
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#!/usr/bin/python
2+
#
3+
# Copyright 2014 Google Inc. All Rights Reserved.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
"""Initializes a DfaClient via impersonation using a Service Account."""
18+
19+
__author__ = 'Mark Saniscalchi'
20+
21+
from googleads import dfa
22+
from googleads import oauth2
23+
24+
# OAuth 2.0 credential information. In a real application, you'd probably be
25+
# pulling these values from a credential storage.
26+
SERVICE_ACCOUNT_EMAIL = 'INSERT_SERVICE_ACCOUNT_EMAIL_HERE'
27+
KEY_FILE = 'INSERT_PATH_TO_KEY_FILE'
28+
SERVICE_ACCOUNT_USER = 'INSERT_IMPERSONATED_EMAIL_HERE'
29+
30+
# DFA API information.
31+
USER_PROFILE_NAME = 'INSERT_USER_PROFILE_NAME_HERE'
32+
APPLICATION_NAME = 'INSERT_APPLICATION_NAME_HERE'
33+
34+
35+
def main(service_account_email, key_file, service_account_user,
36+
user_profile_name, application_name):
37+
oauth2_client = oauth2.GoogleServiceAccountClient(
38+
oauth2.GetAPIScope('dfa'), service_account_email, key_file,
39+
sub=service_account_user)
40+
41+
dfa_client = dfa.DfaClient(user_profile_name, oauth2_client, application_name)
42+
43+
campaign_service = dfa_client.GetService(
44+
'campaign', server='https://advertisersapitest.doubleclick.net')
45+
results = campaign_service.getCampaignsByCriteria({})
46+
if results['records']:
47+
for campaign in results['records']:
48+
print ('Campaign with name \'%s\' and ID \'%s\' was found.'
49+
% (campaign['name'], campaign['id']))
50+
51+
52+
if __name__ == '__main__':
53+
main(SERVICE_ACCOUNT_EMAIL, KEY_FILE, SERVICE_ACCOUNT_USER, USER_PROFILE_NAME,
54+
APPLICATION_NAME)

examples/dfa/authentication/generate_refresh_token.py

Lines changed: 23 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -16,61 +16,46 @@
1616

1717
"""Generates a refresh token for use with DFA."""
1818

19-
__author__ = 'Joseph DiLallo'
19+
__author__ = 'Mark Saniscalchi'
2020

2121
import sys
22-
import urllib2
2322

24-
from oauthlib import oauth2
23+
from oauth2client import client
2524

2625
# Your OAuth 2.0 Client ID and Secret. If you do not have an ID and Secret yet,
2726
# please go to https://console.developers.google.com and create a set.
2827
CLIENT_ID = 'INSERT_CLIENT_ID_HERE'
2928
CLIENT_SECRET = 'INSERT_CLIENT_SECRET_HERE'
3029

31-
# You may optionally provide an HTTPS proxy.
32-
HTTPS_PROXY = None
33-
3430
# The DFA API OAuth 2.0 scope.
3531
SCOPE = u'https://www.googleapis.com/auth/dfatrafficking'
36-
# This callback URL will allow you to copy the token from the success screen.
37-
CALLBACK_URL = 'urn:ietf:wg:oauth:2.0:oob'
38-
# The HTTP headers needed on OAuth 2.0 refresh requests.
39-
OAUTH2_REFRESH_HEADERS = {'content-type':
40-
'application/x-www-form-urlencoded'}
41-
# The web address for generating new OAuth 2.0 credentials at Google.
42-
GOOGLE_OAUTH2_AUTH_ENDPOINT = 'https://accounts.google.com/o/oauth2/auth'
43-
GOOGLE_OAUTH2_GEN_ENDPOINT = 'https://accounts.google.com/o/oauth2/token'
4432

4533

4634
def main():
47-
oauthlib_client = oauth2.WebApplicationClient(CLIENT_ID)
48-
49-
authorize_url = oauthlib_client.prepare_request_uri(
50-
GOOGLE_OAUTH2_AUTH_ENDPOINT, redirect_uri=CALLBACK_URL, scope=SCOPE)
51-
print ('Log in to your DFA account and open the following URL: \n%s\n' %
52-
authorize_url)
35+
"""Retrieve and display the access and refresh token."""
36+
flow = client.OAuth2WebServerFlow(
37+
client_id=CLIENT_ID,
38+
client_secret=CLIENT_SECRET,
39+
scope=[SCOPE],
40+
user_agent='Ads Python Client Library',
41+
redirect_uri='urn:ietf:wg:oauth:2.0:oob')
42+
43+
authorize_url = flow.step1_get_authorize_url()
44+
45+
print ('Log into the Google Account you use to access your DFA account'
46+
'and go to the following URL: \n%s\n' % (authorize_url))
5347
print 'After approving the token enter the verification code (if specified).'
5448
code = raw_input('Code: ').strip()
5549

56-
post_body = oauthlib_client.prepare_request_body(
57-
client_secret=CLIENT_SECRET, code=code, redirect_uri=CALLBACK_URL)
58-
if sys.version_info[0] == 3:
59-
post_body = bytes(post_body, 'utf8')
60-
request = urllib2.Request(GOOGLE_OAUTH2_GEN_ENDPOINT, post_body,
61-
OAUTH2_REFRESH_HEADERS)
62-
if HTTPS_PROXY:
63-
request.set_proxy(HTTPS_PROXY, 'https')
64-
raw_response = urllib2.urlopen(request).read().decode()
65-
oauth2_credentials = oauthlib_client.parse_request_body_response(raw_response)
66-
67-
print ('Your access token is %s and your refresh token is %s'
68-
% (oauth2_credentials['access_token'],
69-
oauth2_credentials['refresh_token']))
70-
print ('You can cache these credentials into a yaml file with the '
71-
'following keys:\ndfa:\n client_id: %s\n client_secret: %s\n'
72-
' refresh_token: %s\n'
73-
% (CLIENT_ID, CLIENT_SECRET, oauth2_credentials['refresh_token']))
50+
try:
51+
credential = flow.step2_exchange(code)
52+
except client.FlowExchangeError, e:
53+
print 'Authentication has failed: %s' % e
54+
sys.exit(1)
55+
else:
56+
print ('OAuth 2.0 authorization successful!\n\n'
57+
'Your access token is:\n %s\n\nYour refresh token is:\n %s'
58+
% (credential.access_token, credential.refresh_token))
7459

7560

7661
if __name__ == '__main__':

0 commit comments

Comments
 (0)