Add XSRF protection to oauth2decorator callback.
Also update all samples to use XSRF callback protection.

Reviewed in https://codereview.appspot.com/6473053/.
diff --git a/samples/appengine/grant.html b/samples/appengine/grant.html
index 0087325..aeb678b 100644
--- a/samples/appengine/grant.html
+++ b/samples/appengine/grant.html
@@ -8,7 +8,7 @@
       application</a>.</p>
     {% else %}
     <p><a href="{{ url }}">Grant</a> this application permission to read your
-    Buzz information and it will let you know how many followers you have.</p>
+    Google+ information and it will let you know how many followers you have.</p>
     {% endif %}
     <p>You can always <a
       href="https://www.google.com/accounts/b/0/IssuedAuthSubTokens">revoke</a>
diff --git a/samples/dailymotion/README b/samples/dailymotion/README
deleted file mode 100644
index 7139bde..0000000
--- a/samples/dailymotion/README
+++ /dev/null
@@ -1,3 +0,0 @@
-Demonstrates using oauth2client against the DailyMotion API.
-
-keywords: oauth2 appengine
diff --git a/samples/dailymotion/app.yaml b/samples/dailymotion/app.yaml
deleted file mode 100644
index a712bd2..0000000
--- a/samples/dailymotion/app.yaml
+++ /dev/null
@@ -1,9 +0,0 @@
-application: dailymotoauth2test
-version: 1
-runtime: python
-api_version: 1
-
-handlers:
-- url: .*
-  script: main.py
-
diff --git a/samples/dailymotion/index.yaml b/samples/dailymotion/index.yaml
deleted file mode 100644
index a3b9e05..0000000
--- a/samples/dailymotion/index.yaml
+++ /dev/null
@@ -1,11 +0,0 @@
-indexes:
-
-# AUTOGENERATED
-
-# This index.yaml is automatically updated whenever the dev_appserver
-# detects that a new type of query is run.  If you want to manage the
-# index.yaml file manually, remove the above marker line (the line
-# saying "# AUTOGENERATED").  If you want to manage some indexes
-# manually, move them above the marker line.  The index.yaml file is
-# automatically uploaded to the admin console when you next deploy
-# your application using appcfg.py.
diff --git a/samples/dailymotion/main.py b/samples/dailymotion/main.py
deleted file mode 100644
index 7f7256f..0000000
--- a/samples/dailymotion/main.py
+++ /dev/null
@@ -1,100 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright 2007 Google Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-__author__ = 'jcgregorio@google.com (Joe Gregorio)'
-
-
-import httplib2
-import logging
-import os
-import pickle
-
-from oauth2client.appengine import CredentialsProperty
-from oauth2client.appengine import StorageByKeyName
-from oauth2client.client import OAuth2WebServerFlow
-from google.appengine.api import users
-from google.appengine.ext import db
-from google.appengine.ext import webapp
-from google.appengine.ext.webapp import template
-from google.appengine.ext.webapp import util
-from google.appengine.ext.webapp.util import login_required
-
-
-FLOW = OAuth2WebServerFlow(
-    client_id='2ad565600216d25d9cde',
-    client_secret='03b56df2949a520be6049ff98b89813f17b467dc',
-    scope='read',
-    redirect_uri='https://dailymotoauth2test.appspot.com/auth_return',
-    user_agent='oauth2client-sample/1.0',
-    auth_uri='https://api.dailymotion.com/oauth/authorize',
-    token_uri='https://api.dailymotion.com/oauth/token'
-    )
-
-
-class Credentials(db.Model):
-  credentials = CredentialsProperty()
-
-
-class MainHandler(webapp.RequestHandler):
-
-  @login_required
-  def get(self):
-    user = users.get_current_user()
-    credentials = StorageByKeyName(
-        Credentials, user.user_id(), 'credentials').get()
-
-    if credentials is None or credentials.invalid == True:
-      authorize_url = FLOW.step1_get_authorize_url()
-      self.redirect(authorize_url)
-    else:
-      http = httplib2.Http()
-      http = credentials.authorize(http)
-
-      resp, content = http.request('https://api.dailymotion.com/me')
-
-      path = os.path.join(os.path.dirname(__file__), 'welcome.html')
-      logout = users.create_logout_url('/')
-      variables = {
-          'content': content,
-          'logout': logout
-          }
-      self.response.out.write(template.render(path, variables))
-
-
-class OAuthHandler(webapp.RequestHandler):
-
-  @login_required
-  def get(self):
-    user = users.get_current_user()
-    credentials = FLOW.step2_exchange(self.request.params)
-    StorageByKeyName(
-        Credentials, user.user_id(), 'credentials').put(credentials)
-    self.redirect("/")
-
-
-def main():
-  application = webapp.WSGIApplication(
-      [
-      ('/', MainHandler),
-      ('/auth_return', OAuthHandler)
-      ],
-      debug=True)
-  util.run_wsgi_app(application)
-
-
-if __name__ == '__main__':
-  main()
diff --git a/samples/dailymotion/welcome.html b/samples/dailymotion/welcome.html
deleted file mode 100644
index f86902f..0000000
--- a/samples/dailymotion/welcome.html
+++ /dev/null
@@ -1,14 +0,0 @@
-<html>
-  <head>
-    <title>Daily Motion Sample</title>
-    <style type=text/css>
-      td  { vertical-align: top; padding: 0.5em }
-      img { border:0 }
-    </style>
-  </head>
-  <body>
-    <p><a href="{{ logout }}">Logout</a></p>
-    <h2>Response body:</h2>
-    <pre>{{ content }} </pre>
-  </body>
-</html>
diff --git a/samples/django_sample/client_secrets.json b/samples/django_sample/client_secrets.json
new file mode 100644
index 0000000..a232f37
--- /dev/null
+++ b/samples/django_sample/client_secrets.json
@@ -0,0 +1,9 @@
+{
+  "web": {
+    "client_id": "[[INSERT CLIENT ID HERE]]",
+    "client_secret": "[[INSERT CLIENT SECRET HERE]]",
+    "redirect_uris": [],
+    "auth_uri": "https://accounts.google.com/o/oauth2/auth",
+    "token_uri": "https://accounts.google.com/o/oauth2/token"
+  }
+}
diff --git a/samples/django_sample/plus/models.py b/samples/django_sample/plus/models.py
index fd4bf74..890b278 100644
--- a/samples/django_sample/plus/models.py
+++ b/samples/django_sample/plus/models.py
@@ -18,8 +18,4 @@
     pass
 
 
-class FlowAdmin(admin.ModelAdmin):
-    pass
-
-
 admin.site.register(CredentialsModel, CredentialsAdmin)
diff --git a/samples/django_sample/plus/views.py b/samples/django_sample/plus/views.py
index f5d5d18..f273b8d 100644
--- a/samples/django_sample/plus/views.py
+++ b/samples/django_sample/plus/views.py
@@ -2,27 +2,29 @@
 import logging
 import httplib2
 
-from django.http import HttpResponse
-from django.core.urlresolvers import reverse
-from django.contrib.auth.decorators import login_required
-
-from oauth2client.django_orm import Storage
-from oauth2client.client import OAuth2WebServerFlow
-from django_sample.plus.models import CredentialsModel
 from apiclient.discovery import build
-
+from django.contrib.auth.decorators import login_required
+from django.core.urlresolvers import reverse
+from django.http import HttpResponse
+from django.http import HttpResponseBadRequest
 from django.http import HttpResponseRedirect
 from django.shortcuts import render_to_response
+from django_sample.plus.models import CredentialsModel
+from django_sample import settings
+from oauth2client import xsrfutil
+from oauth2client.client import flow_from_clientsecrets
+from oauth2client.django_orm import Storage
 
-STEP2_URI = 'http://localhost:8000/oauth2callback'
+# CLIENT_SECRETS, name of a file containing the OAuth 2.0 information for this
+# application, including client_id and client_secret, which are found
+# on the API Access tab on the Google APIs
+# Console <http://code.google.com/apis/console>
+CLIENT_SECRETS = os.path.join(os.path.dirname(__file__), '..', 'client_secrets.json')
 
-FLOW = OAuth2WebServerFlow(
-    client_id='[[Insert Client ID here.]]',
-    client_secret='[[Insert Client Secret here.]]',
+FLOW = flow_from_clientsecrets(
+    CLIENT_SECRETS,
     scope='https://www.googleapis.com/auth/plus.me',
-    redirect_uri=STEP2_URI,
-    user_agent='plus-django-sample/1.0',
-    )
+    redirect_uri='http://localhost:8000/oauth2callback')
 
 
 @login_required
@@ -30,6 +32,8 @@
   storage = Storage(CredentialsModel, 'id', request.user, 'credential')
   credential = storage.get()
   if credential is None or credential.invalid == True:
+    FLOW.params['state'] = xsrfutil.generate_token(settings.SECRET_KEY,
+                                                   request.user)
     authorize_url = FLOW.step1_get_authorize_url()
     return HttpResponseRedirect(authorize_url)
   else:
@@ -48,6 +52,9 @@
 
 @login_required
 def auth_return(request):
+  if not xsrfutil.validate_token(settings.SECRET_KEY, request.REQUEST['state'],
+                                 request.user):
+    return  HttpResponseBadRequest()
   credential = FLOW.step2_exchange(request.REQUEST)
   storage = Storage(CredentialsModel, 'id', request.user, 'credential')
   storage.put(credential)