Permalink
Browse files

added instance/settings-sample.py

  • Loading branch information...
1 parent ef901f5 commit cdb72a3cfc857ebcf5bcbb426a7dcf19b2fde31b @kracekumar committed Nov 20, 2012
Showing with 233 additions and 221 deletions.
  1. +3 −0 .gitignore
  2. +14 −11 README.md
  3. +10 −0 instance/settings-sample.py
  4. +3 −1 modules/__init__.py
  5. +167 −173 modules/oauth2.py
  6. +3 −0 requirements.txt
  7. +33 −36 server.py
View
3 .gitignore
@@ -0,0 +1,3 @@
+*.py[cox]
+settings.py
+instance/settings.py
View
25 README.md
@@ -1,16 +1,19 @@
-Flask-Login-Oauth2
+Flask-Login-Oauth2
==================
+Installation
+-------
+$ pip install -r requirements.txt
+
+
flask-login-oauth2 and google oauth2 library for authenticating users through New Google Oauth2 mechanism and maintaining session for users
-Just register your new Google app at https://code.google.com/apis/console#access
-and register these values:
+Just register your new Google app at https://code.google.com/apis/console#access
+and copy `settings-sample.py` to `settings.py` and modifiy `GOOGLE_CLIENT_ID` , `GOOGLE_CLIENT_SECRET`,
+`REDIRECT_URI` and `SECRET_KEY`
- CLIENT_ID in server.py
- CLIENT_SECRET in server.py
- REDIRECT_URI in modules/oauth2.py
-run the server
+run the server
$python server.py
Running on http://127.0.0.1:5000/
@@ -22,11 +25,11 @@ It uses the following scopes:
https://mail.google.com/
-To Get all Access to the Gmail Imap server of the user
+To Get all Access to the Gmail Imap server of the user
+
+ https://www.googleapis.com/auth/userinfo.profile
- https://www.googleapis.com/auth/userinfo.profile
-
-To Get Access to the User Profile
+To Get Access to the User Profile
Read More About Scopes here at https://developers.google.com/gdata/faq#AuthScopes
View
10 instance/settings-sample.py
@@ -0,0 +1,10 @@
+#: Secret key
+SECRET_KEY = 'make this something random'
+#: GOOGLE_CLIENT_ID
+GOOGLE_CLIENT_ID = u''
+#: GOOGLE_CLIENT_SECRET
+GOOGLE_CLIENT_SECRET = u''
+#: Hardcoded dummy redirect URI for non-web apps.
+REDIRECT_URI = 'REDIRECTURI FOR YOUR APP'
+#: The URL root for accessing Google Accounts.
+GOOGLE_ACCOUNTS_BASE_URL = 'https://accounts.google.com'
View
4 modules/__init__.py
@@ -6,5 +6,7 @@
:copyright: (c) 2012 by GrexIt.
:license: BSD, see LICENSE for more details.
"""
+from flask import Flask
-
+app = Flask(__name__, instance_relative_config=True)
+app.config.from_pyfile('settings.py')
View
340 modules/oauth2.py
@@ -68,266 +68,260 @@
import sys
import urllib
+from modules import app
+
def SetupOptionParser():
- # Usage message is the module's docstring.
- parser = OptionParser(usage=__doc__)
- parser.add_option('--generate_oauth2_token',
+ # Usage message is the module's docstring.
+ parser = OptionParser(usage=__doc__)
+ parser.add_option('--generate_oauth2_token',
action='store_true',
dest='generate_oauth2_token',
help='generates an OAuth2 token for testing')
- parser.add_option('--generate_oauth2_string',
+ parser.add_option('--generate_oauth2_string',
action='store_true',
dest='generate_oauth2_string',
help='generates an initial client response string for '
'OAuth2')
- parser.add_option('--client_id',
+ parser.add_option('--client_id',
default=None,
help='Client ID of the application that is authenticating. '
'See OAuth2 documentation for details.')
- parser.add_option('--client_secret',
+ parser.add_option('--client_secret',
default=None,
help='Client secret of the application that is '
'authenticating. See OAuth2 documentation for '
'details.')
- parser.add_option('--access_token',
+ parser.add_option('--access_token',
default=None,
help='OAuth2 access token')
- parser.add_option('--refresh_token',
+ parser.add_option('--refresh_token',
default=None,
help='OAuth2 refresh token')
- parser.add_option('--scope',
+ parser.add_option('--scope',
default='https://mail.google.com/',
help='scope for the access token. Multiple scopes can be '
'listed separated by spaces with the whole argument '
'quoted.')
- parser.add_option('--test_imap_authentication',
+ parser.add_option('--test_imap_authentication',
action='store_true',
dest='test_imap_authentication',
help='attempts to authenticate to IMAP')
- parser.add_option('--test_smtp_authentication',
+ parser.add_option('--test_smtp_authentication',
action='store_true',
dest='test_smtp_authentication',
help='attempts to authenticate to SMTP')
- parser.add_option('--user',
+ parser.add_option('--user',
default=None,
help='email address of user whose account is being '
'accessed')
- return parser
-
-
-# The URL root for accessing Google Accounts.
-GOOGLE_ACCOUNTS_BASE_URL = 'https://accounts.google.com'
-
-
-# Hardcoded dummy redirect URI for non-web apps.
-REDIRECT_URI = 'REDIRECTURI FOR YOUR APP'
+ return parser
def AccountsUrl(command):
- """Generates the Google Accounts URL.
+ """Generates the Google Accounts URL.
- Args:
- command: The command to execute.
+ Args:
+ command: The command to execute.
- Returns:
- A URL for the given command.
- """
- return '%s/%s' % (GOOGLE_ACCOUNTS_BASE_URL, command)
+ Returns:
+ A URL for the given command.
+ """
+ return '%s/%s' % (app.config['GOOGLE_ACCOUNTS_BASE_URL'], command)
def UrlEscape(text):
- # See OAUTH 5.1 for a definition of which characters need to be escaped.
- return urllib.quote(text, safe='~-._')
+ # See OAUTH 5.1 for a definition of which characters need to be escaped.
+ return urllib.quote(text, safe='~-._')
def UrlUnescape(text):
- # See OAUTH 5.1 for a definition of which characters need to be escaped.
- return urllib.unquote(text)
+ # See OAUTH 5.1 for a definition of which characters need to be escaped.
+ return urllib.unquote(text)
def FormatUrlParams(params):
- """Formats parameters into a URL query string.
-
- Args:
- params: A key-value map.
-
- Returns:
- A URL query string version of the given parameters.
- """
- param_fragments = []
- for param in sorted(params.iteritems(), key=lambda x: x[0]):
- param_fragments.append('%s=%s' % (param[0], UrlEscape(param[1])))
- return '&'.join(param_fragments)
-
-
-def GeneratePermissionUrl(client_id,useremail, scope='https://mail.google.com/ https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email'):
- """Generates the URL for authorizing access.
-
- This uses the "OAuth2 for Installed Applications" flow described at
- https://developers.google.com/accounts/docs/OAuth2InstalledApp
-
- Args:
- client_id: Client ID obtained by registering your app.
- scope: scope for access token, e.g. 'https://mail.google.com'
- Returns:
- A URL that the user should visit in their browser.
- """
- params = {}
- params['client_id'] = client_id
- params['redirect_uri'] = REDIRECT_URI
- params['scope'] = scope
- params['state'] = useremail
- params['response_type'] = 'code'
- return '%s?%s' % (AccountsUrl('o/oauth2/auth'),
+ """Formats parameters into a URL query string.
+
+ Args:
+ params: A key-value map.
+
+ Returns:
+ A URL query string version of the given parameters.
+ """
+ param_fragments = []
+ for param in sorted(params.iteritems(), key=lambda x: x[0]):
+ param_fragments.append('%s=%s' % (param[0], UrlEscape(param[1])))
+ return '&'.join(param_fragments)
+
+
+def GeneratePermissionUrl(client_id, useremail,
+ scope='https://mail.google.com/ https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email'):
+ """Generates the URL for authorizing access.
+
+ This uses the "OAuth2 for Installed Applications" flow described at
+ https://developers.google.com/accounts/docs/OAuth2InstalledApp
+
+ Args:
+ client_id: Client ID obtained by registering your app.
+ scope: scope for access token, e.g. 'https://mail.google.com'
+ Returns:
+ A URL that the user should visit in their browser.
+ """
+ params = {}
+ params['client_id'] = client_id
+ params['redirect_uri'] = app.config['REDIRECT_URI']
+ params['scope'] = scope
+ params['state'] = useremail
+ params['response_type'] = 'code'
+ return '%s?%s' % (AccountsUrl('o/oauth2/auth'),
FormatUrlParams(params))
def AuthorizeTokens(client_id, client_secret, authorization_code):
- """Obtains OAuth access token and refresh token.
+ """Obtains OAuth access token and refresh token.
- This uses the application portion of the "OAuth2 for Installed Applications"
- flow at https://developers.google.com/accounts/docs/OAuth2InstalledApp#handlingtheresponse
+ This uses the application portion of the "OAuth2 for Installed Applications"
+ flow at https://developers.google.com/accounts/docs/OAuth2InstalledApp#handlingtheresponse
- Args:
- client_id: Client ID obtained by registering your app.
- client_secret: Client secret obtained by registering your app.
- authorization_code: code generated by Google Accounts after user grants
+ Args:
+ client_id: Client ID obtained by registering your app.
+ client_secret: Client secret obtained by registering your app.
+ authorization_code: code generated by Google Accounts after user grants
permission.
- Returns:
- The decoded response from the Google Accounts server, as a dict. Expected
- fields include 'access_token', 'expires_in', and 'refresh_token'.
- """
- params = {}
- params['client_id'] = client_id
- params['client_secret'] = client_secret
- params['code'] = authorization_code
- params['redirect_uri'] = REDIRECT_URI
- params['grant_type'] = 'authorization_code'
- request_url = AccountsUrl('o/oauth2/token')
-
- response = urllib.urlopen(request_url, urllib.urlencode(params)).read()
- return json.loads(response)
+ Returns:
+ The decoded response from the Google Accounts server, as a dict. Expected
+ fields include 'access_token', 'expires_in', and 'refresh_token'.
+ """
+ params = {}
+ params['client_id'] = client_id
+ params['client_secret'] = client_secret
+ params['code'] = authorization_code
+ params['redirect_uri'] = app.config['REDIRECT_URI']
+ params['grant_type'] = 'authorization_code'
+ request_url = AccountsUrl('o/oauth2/token')
+
+ response = urllib.urlopen(request_url, urllib.urlencode(params)).read()
+ return json.loads(response)
def RefreshToken(client_id, client_secret, refresh_token):
- """Obtains a new token given a refresh token.
+ """Obtains a new token given a refresh token.
- See https://developers.google.com/accounts/docs/OAuth2InstalledApp#refresh
+ See https://developers.google.com/accounts/docs/OAuth2InstalledApp#refresh
- Args:
- client_id: Client ID obtained by registering your app.
- client_secret: Client secret obtained by registering your app.
- refresh_token: A previously-obtained refresh token.
- Returns:
- The decoded response from the Google Accounts server, as a dict. Expected
- fields include 'access_token', 'expires_in', and 'refresh_token'.
- """
- params = {}
- params['client_id'] = client_id
- params['client_secret'] = client_secret
- params['refresh_token'] = refresh_token
- params['grant_type'] = 'refresh_token'
- request_url = AccountsUrl('o/oauth2/token')
+ Args:
+ client_id: Client ID obtained by registering your app.
+ client_secret: Client secret obtained by registering your app.
+ refresh_token: A previously-obtained refresh token.
+ Returns:
+ The decoded response from the Google Accounts server, as a dict. Expected
+ fields include 'access_token', 'expires_in', and 'refresh_token'.
+ """
+ params = {}
+ params['client_id'] = client_id
+ params['client_secret'] = client_secret
+ params['refresh_token'] = refresh_token
+ params['grant_type'] = 'refresh_token'
+ request_url = AccountsUrl('o/oauth2/token')
- response = urllib.urlopen(request_url, urllib.urlencode(params)).read()
- return json.loads(response)
+ response = urllib.urlopen(request_url, urllib.urlencode(params)).read()
+ return json.loads(response)
def GenerateOAuth2String(username, access_token, base64_encode=True):
- """Generates an IMAP OAuth2 authentication string.
+ """Generates an IMAP OAuth2 authentication string.
- See https://developers.google.com/google-apps/gmail/oauth2_overview
+ See https://developers.google.com/google-apps/gmail/oauth2_overview
- Args:
- username: the username (email address) of the account to authenticate
- access_token: An OAuth2 access token.
- base64_encode: Whether to base64-encode the output.
+ Args:
+ username: the username (email address) of the account to authenticate
+ access_token: An OAuth2 access token.
+ base64_encode: Whether to base64-encode the output.
- Returns:
- The SASL argument for the OAuth2 mechanism.
- """
- auth_string = 'user=%s\1auth=Bearer %s\1\1' % (username, access_token)
- if base64_encode:
- auth_string = base64.b64encode(auth_string)
- return auth_string
+ Returns:
+ The SASL argument for the OAuth2 mechanism.
+ """
+ auth_string = 'user=%s\1auth=Bearer %s\1\1' % (username, access_token)
+ if base64_encode:
+ auth_string = base64.b64encode(auth_string)
+ return auth_string
def TestImapAuthentication(user, auth_string):
- """Authenticates to IMAP with the given auth_string.
+ """Authenticates to IMAP with the given auth_string.
- Prints a debug trace of the attempted IMAP connection.
+ Prints a debug trace of the attempted IMAP connection.
- Args:
- user: The Gmail username (full email address)
- auth_string: A valid OAuth2 string, as returned by GenerateOAuth2String.
+ Args:
+ user: The Gmail username (full email address)
+ auth_string: A valid OAuth2 string, as returned by GenerateOAuth2String.
Must not be base64-encoded, since imaplib does its own base64-encoding.
- """
- print
- imap_conn = imaplib.IMAP4_SSL('imap.gmail.com')
- imap_conn.debug = 4
- imap_conn.authenticate('XOAUTH2', lambda x: auth_string)
- imap_conn.select('INBOX')
+ """
+ print
+ imap_conn = imaplib.IMAP4_SSL('imap.gmail.com')
+ imap_conn.debug = 4
+ imap_conn.authenticate('XOAUTH2', lambda x: auth_string)
+ imap_conn.select('INBOX')
def TestSmtpAuthentication(user, auth_string):
- """Authenticates to SMTP with the given auth_string.
+ """Authenticates to SMTP with the given auth_string.
- Args:
- user: The Gmail username (full email address)
- auth_string: A valid OAuth2 string, not base64-encoded, as returned by
+ Args:
+ user: The Gmail username (full email address)
+ auth_string: A valid OAuth2 string, not base64-encoded, as returned by
GenerateOAuth2String.
- """
- print
- smtp_conn = smtplib.SMTP('smtp.gmail.com', 587)
- smtp_conn.set_debuglevel(True)
- smtp_conn.ehlo('test')
- smtp_conn.starttls()
- smtp_conn.docmd('AUTH', 'XOAUTH2 ' + base64.b64encode(auth_string))
+ """
+ print
+ smtp_conn = smtplib.SMTP('smtp.gmail.com', 587)
+ smtp_conn.set_debuglevel(True)
+ smtp_conn.ehlo('test')
+ smtp_conn.starttls()
+ smtp_conn.docmd('AUTH', 'XOAUTH2 ' + base64.b64encode(auth_string))
def RequireOptions(options, *args):
- missing = [arg for arg in args if getattr(options, arg) is None]
- if missing:
- print 'Missing options: %s' % ' '.join(missing)
- sys.exit(-1)
+ missing = [arg for arg in args if getattr(options, arg) is None]
+ if missing:
+ print 'Missing options: %s' % ' '.join(missing)
+ sys.exit(-1)
def main(argv):
- options_parser = SetupOptionParser()
- (options, args) = options_parser.parse_args()
- if options.refresh_token:
- RequireOptions(options, 'client_id', 'client_secret')
- response = RefreshToken(options.client_id, options.client_secret,
+ options_parser = SetupOptionParser()
+ (options, args) = options_parser.parse_args()
+ if options.refresh_token:
+ RequireOptions(options, 'client_id', 'client_secret')
+ response = RefreshToken(options.client_id, options.client_secret,
options.refresh_token)
- print 'Access Token: %s' % response['access_token']
- print 'Access Token Expiration Seconds: %s' % response['expires_in']
- elif options.generate_oauth2_string:
- RequireOptions(options, 'user', 'access_token')
- print ('OAuth2 argument:\n' +
- GenerateOAuth2String(options.user, options.access_token))
- elif options.generate_oauth2_token:
- RequireOptions(options, 'client_id', 'client_secret')
- print 'To authorize token, visit this url and follow the directions:'
- print ' %s' % GeneratePermissionUrl(options.client_id, options.scope)
- authorization_code = raw_input('Enter verification code: ')
- response = AuthorizeTokens(options.client_id, options.client_secret,
+ print 'Access Token: %s' % response['access_token']
+ print 'Access Token Expiration Seconds: %s' % response['expires_in']
+ elif options.generate_oauth2_string:
+ RequireOptions(options, 'user', 'access_token')
+ print ('OAuth2 argument:\n' +
+ GenerateOAuth2String(options.user, options.access_token))
+ elif options.generate_oauth2_token:
+ RequireOptions(options, 'client_id', 'client_secret')
+ print 'To authorize token, visit this url and follow the directions:'
+ print ' %s' % GeneratePermissionUrl(options.client_id, options.scope)
+ authorization_code = raw_input('Enter verification code: ')
+ response = AuthorizeTokens(options.client_id, options.client_secret,
authorization_code)
- print 'Refresh Token: %s' % response['refresh_token']
- print 'Access Token: %s' % response['access_token']
- print 'Access Token Expiration Seconds: %s' % response['expires_in']
- elif options.test_imap_authentication:
- RequireOptions(options, 'user', 'access_token')
- TestImapAuthentication(options.user,
+ print 'Refresh Token: %s' % response['refresh_token']
+ print 'Access Token: %s' % response['access_token']
+ print 'Access Token Expiration Seconds: %s' % response['expires_in']
+ elif options.test_imap_authentication:
+ RequireOptions(options, 'user', 'access_token')
+ TestImapAuthentication(options.user,
GenerateOAuth2String(options.user, options.access_token,
base64_encode=False))
- elif options.test_smtp_authentication:
- RequireOptions(options, 'user', 'access_token')
- TestSmtpAuthentication(options.user,
+ elif options.test_smtp_authentication:
+ RequireOptions(options, 'user', 'access_token')
+ TestSmtpAuthentication(options.user,
GenerateOAuth2String(options.user, options.access_token,
base64_encode=False))
- else:
- options_parser.print_help()
- print 'Nothing to do, exiting.'
+ else:
+ options_parser.print_help()
+ print 'Nothing to do, exiting.'
return
-
View
3 requirements.txt
@@ -0,0 +1,3 @@
+flask
+flask-login
+requests
View
69 server.py
@@ -1,31 +1,20 @@
-"""
- INSTALL
- Flask
- Flask-Login
- requests
-"""
-from flask import Flask, request, render_template, redirect, url_for, flash
-from flask.ext.login import (LoginManager, current_user, login_required,
- login_user, logout_user, UserMixin, AnonymousUser,
- confirm_login, fresh_login_required)
-from flask import request
+#! /usr/bin/env python
+#! -*- coding: utf-8 -*-
+
import json
-import traceback
-import time
import requests
-"""
- Imports End
-"""
-app = Flask(__name__)
-CLIENT_ID = ""
-CLIENT_SECRET = ""
+from flask import request, redirect
+from flask.ext.login import (LoginManager, current_user, login_required,
+ login_user, logout_user, UserMixin, AnonymousUser)
+
+from modules import app
+
-"""
-User Session management Class
-"""
class User(UserMixin):
- def __init__(self, email, id,fname="", lname="",accesstoken="", active=True):
- self.email = email
+ """User Session management Class
+ """
+ def __init__(self, email, id, fname="", lname="", accesstoken="", active=True):
+ self.email = email
self.id = id
self.active = active
self.fname = fname
@@ -34,46 +23,54 @@ def __init__(self, email, id,fname="", lname="",accesstoken="", active=True):
def is_active(self):
return self.active
+
def myemail(self):
return self.email
+
def get_userid(self):
return self.id
+
def get_fname(self):
return self.fname
+
def get_lname(self):
return self.lname
"""
-USER_STORE is the store of all the users. Ideally it should be in Database
+USER_STORE is the store of all the users. Ideally it should be in Database
"""
USERS = {
1: User("anurag@grexit.com", 1, "Anurag", "Maher", "", True)
}
"""
-USER_NAMES maintains a dictionary of all the users with their email address
+USER_NAMES maintains a dictionary of all the users with their email address
"""
USER_NAMES = dict((u.email, u) for u in USERS.itervalues())
+
class Anonymous(AnonymousUser):
name = u"Anonymous"
+
@app.route("/")
def hello():
if current_user.is_authenticated():
- return " User " + str(current_user.myemail()) + " is logged in "
+ return " User " + str(current_user.myemail()) + " is logged in "
return "Hello World!"
+
@app.route("/logout", methods=["GET"])
@login_required
def logout():
logout_user()
return redirect("/")
+
@app.route("/login", methods=["GET", "POST"])
def login():
- from modules.oauth2 import GeneratePermissionUrl
+ from modules.oauth2 import GeneratePermissionUrl
if current_user.is_authenticated():
return current_user.get_id()
@@ -85,19 +82,20 @@ def login():
return "user already exists and logged in"
if request.method == "GET" and request.args.get('email', ''):
- url = GeneratePermissionUrl(__CLIENT_ID__, request.args.get('email', ''))
+ url = GeneratePermissionUrl(app.config['GOOGLE_CLIENT_ID'], request.args.get('email', ''))
return redirect(url)
return "No Email Provided"
+
@app.route("/oauth2callback", methods=["GET", "POST"])
def oauth2callback():
- from grexit.modules.imap.oauth2 import AuthorizeTokens
+ from grexit.modules.imap.oauth2 import AuthorizeTokens
if request.method == "GET":
authorizationcode = request.args.get('code', '')
- useremail = request.args.get('state', '')
- response = AuthorizeTokens(CLIENT_ID,
- CLIENT_SECRET,
- authorizationcode)
+ useremail = request.args.get('state', '')
+ response = AuthorizeTokens(app.config['GOOGLE_CLIENT_ID'],
+ app.config['GOOGLE_CLIENT_SECRET'],
+ authorizationcode)
accesstoken = response["access_token"]
r = requests.get('https://www.googleapis.com/oauth2/v1/userinfo?access_token=' + accesstoken)
j = json.loads(r.text)
@@ -118,12 +116,11 @@ def oauth2callback():
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.anonymous_user = Anonymous
-app.secret_key = "enter some key" # required for session management in flask
+
@login_manager.user_loader
def load_user(id):
return USERS.get(int(id))
if __name__ == "__main__":
app.run(debug=True)
-

0 comments on commit cdb72a3

Please sign in to comment.