Skip to content

Commit

Permalink
Merge pull request #2 from ryepdx/master
Browse files Browse the repository at this point in the history
Added MongoDB example
  • Loading branch information
ib-lundgren committed Dec 18, 2012
2 parents 82d59f5 + bfbf722 commit 3cb6d5e
Show file tree
Hide file tree
Showing 17 changed files with 761 additions and 0 deletions.
21 changes: 21 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,27 @@ After installing you can run the demo application::

(venv)$ python flask-oauthprovider/examples/runserver.py

MongoDB Example
-------

This repo also includes a fully working, MongoDB / pymongo
backed OAuth provider in the `/examples`_ folder.

Before running the demo you need to install a few dependencies (virtualenv is
highly recommended).::

$ virtualenv venv
$ source venv/bin/activate
(venv)$ git clone https://github.com/idan/oauthlib.git
(venv)$ python oauthlib/setup.py install
(venv)$ git clone https://github.com/ib-lundgren/flask-oauthprovider.git
(venv)$ python flask-oauthprovider/setup.py install
(venv)$ pip install flask-openid pymongo

After installing you can run the demo application::

(venv)$ python flask-oauthprovider/examples/runserver_mongo.py

Usage
-----

Expand Down
35 changes: 35 additions & 0 deletions examples/mongo_demoprovider/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from flask import Flask, request
from provider import ExampleProvider
from models import AccessToken, ResourceOwner as User

app = Flask(__name__)
app.config.update(
DATABASE_URI="",
SECRET_KEY="debugging key"
)

provider = ExampleProvider(app)

# Imported to setup views
import login

@app.route('/callback')
def callback():
return str(request.__dict__)

@app.route("/protected")
@provider.require_oauth()
def protected_view():
token = request.oauth.resource_owner_key
access_token = AccessToken.get_collection().find_one({'token':token})
user = User.find_one({'_id':access_token['resource_owner_id']})
return user['name']


@app.route("/protected_realm")
@provider.require_oauth(realm="secret")
def protected_realm_view():
token = request.oauth.resource_owner_key
access_token = AccessToken.get_collection().find_one({'token':token})
user = User.find_one({'_id':access_token['resource_owner_id']})
return user['email']
116 changes: 116 additions & 0 deletions examples/mongo_demoprovider/login.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
# -*- coding: utf-8 -*-
from mongo_demoprovider import app
from models import ResourceOwner as User
from flask import g, session, render_template, request, redirect, flash
from flask import abort, url_for
from flask.ext.openid import OpenID

# setup flask-openid
oid = OpenID(app)


@app.before_request
def before_request():
g.user = None
if 'openid' in session:
user_dict = User.find_one({'openid':session['openid']})

if user_dict:
g.user = User()
g.user.update(user_dict)


@app.route('/')
def index():
return render_template('index.html')


@app.route('/login', methods=['GET', 'POST'])
@oid.loginhandler
def login():
"""Does the login via OpenID. Has to call into `oid.try_login`
to start the OpenID machinery.
"""
# if we are already logged in, go back to were we came from
if g.user is not None:
return redirect(oid.get_next_url())
if request.method == 'POST':
openid = request.form.get('openid')
if openid:
return oid.try_login(openid, ask_for=['email', 'fullname',
'nickname'])
return render_template('login.html', next=oid.get_next_url(),
error=oid.fetch_error())


@oid.after_login
def create_or_login(resp):
"""This is called when login with OpenID succeeded and it's not
necessary to figure out if this is the users's first login or not.
This function has to redirect otherwise the user will be presented
with a terrible URL which we certainly don't want.
"""
session['openid'] = resp.identity_url
user = User.get_collection().find_one({'openid':resp.identity_url})
if user is not None:
flash(u'Successfully signed in')
g.user = user
return redirect(oid.get_next_url())
return redirect(url_for('create_profile', next=oid.get_next_url(),
name=resp.fullname or resp.nickname,
email=resp.email))


@app.route('/create-profile', methods=['GET', 'POST'])
def create_profile():
"""If this is the user's first login, the create_or_login function
will redirect here so that the user can set up his profile.
"""
if g.user is not None or 'openid' not in session:
return redirect(url_for('index'))
if request.method == 'POST':
name = request.form['name']
email = request.form['email']
if not name:
flash(u'Error: you have to provide a name')
elif '@' not in email:
flash(u'Error: you have to enter a valid email address')
else:
flash(u'Profile successfully created')
User.get_collection().insert(User(name, email, session['openid']))
return redirect(oid.get_next_url())
return render_template('create_profile.html', next_url=oid.get_next_url())


@app.route('/profile', methods=['GET', 'POST'])
def edit_profile():
"""Updates a profile"""
if g.user is None:
abort(401)
form = dict(name=g.user.name, email=g.user.email)
if request.method == 'POST':
if 'delete' in request.form:
User.get_collection().remove(g.user)
session['openid'] = None
flash(u'Profile deleted')
return redirect(url_for('index'))
form['name'] = request.form['name']
form['email'] = request.form['email']
if not form['name']:
flash(u'Error: you have to provide a name')
elif '@' not in form['email']:
flash(u'Error: you have to enter a valid email address')
else:
flash(u'Profile successfully created')
g.user.name = form['name']
g.user.email = form['email']
uid = User.get_collection().save(g.user)
return redirect(url_for('edit_profile'))
return render_template('edit_profile.html', form=form)


@app.route('/logout')
def logout():
session.pop('openid', None)
flash(u'You have been signed out')
return redirect(oid.get_next_url())
110 changes: 110 additions & 0 deletions examples/mongo_demoprovider/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import pymongo


def get_connection():
return pymongo.MongoClient().demo_oauth_provider


class Model(dict):
@classmethod
def get_collection(cls):
conn = get_connection()
return conn[cls.table]

@classmethod
def find_one(cls, attrs):
return cls.get_collection().find_one(attrs)

@classmethod
def insert(cls, obj):
return cls.get_collection().insert(obj)

@classmethod
def save(cls, obj):
return cls.get_collection().save(obj)

def __getattr__(self, attr):
return self[attr]

def __setattr__(self, attr, value):
self[attr] = value



class ResourceOwner(Model):
table = "users"

def __init__(self, name="", email="", openid=""):
self.name = name
self.email = email
self.openid = openid
self.request_tokens = []
self.access_tokens = []
self.client_ids = []

def __repr__(self):
return "<ResourceOwner (%s, %s)>" % (self.name, self.email)


class Client(Model):
table = "clients"

def __init__(self, client_key, name, description, secret=None, pubkey=None):
self.client_key = client_key
self.name = name
self.description = description
self.secret = secret
self.pubkey = pubkey
self.request_tokens = []
self.access_tokens = []
self.callbacks = []
self.resource_owner_id = ""

def __repr__(self):
return "<Client (%s, %s)>" % (self.name, self.id)


class Nonce(Model):
table = "nonces"

def __init__(self, nonce, timestamp):
self.nonce = nonce
self.timestamp = timestamp
self.client_id = ""
self.request_token_id = ""
self.access_token_id = ""

def __repr__(self):
return "<Nonce (%s, %s, %s, %s)>" % (self.nonce, self.timestamp, self.client, self.resource_owner)


class RequestToken(Model):
table = "requestTokens"

def __init__(self, token, callback, secret=None, verifier=None, realm=None):
self.token = token
self.secret = secret
self.verifier = verifier
self.realm = realm
self.callback = callback
self.client_id = ""
self.resource_owner_id = ""


def __repr__(self):
return "<RequestToken (%s, %s, %s)>" % (self.token, self.client, self.resource_owner)


class AccessToken(Model):
table = "accessTokens"

def __init__(self, token, secret=None, verifier=None, realm=None):
self.token = token
self.secret = secret
self.verifier = verifier
self.realm = realm
self.client_id = ""
self.resource_owner_id = ""

def __repr__(self):
return "<AccessToken (%s, %s, %s)>" % (self.token, self.client, self.resource_owner)
Loading

0 comments on commit 3cb6d5e

Please sign in to comment.