Browse Source

Merge branch 'master' into module-support

pull/1638/head
Armin Ronacher 15 years ago
parent
commit
de909b3bdf
  1. 165
      examples/openidexample/openidexample.py
  2. 108
      examples/openidexample/simpleopenid.py
  3. BIN
      examples/openidexample/static/openid.png
  4. 39
      examples/openidexample/static/style.css
  5. 22
      examples/openidexample/templates/create_profile.html
  6. 16
      examples/openidexample/templates/edit_profile.html
  7. 10
      examples/openidexample/templates/index.html
  8. 18
      examples/openidexample/templates/layout.html
  9. 12
      examples/openidexample/templates/login.html

165
examples/openidexample/openidexample.py

@ -1,165 +0,0 @@
# -*- coding: utf-8 -*-
"""
OpenID Example
~~~~~~~~~~~~~~
This simple application shows how OpenID can be used in an application.
Dependencies:
- python-openid
- SQLAlchemy
:copyright: (c) 2010 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""
from flask import Flask, render_template, request, g, session, flash, \
redirect, url_for, abort
from simpleopenid import SimpleOpenID
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.ext.declarative import declarative_base
# configuration
DATABASE_URI = 'sqlite:////tmp/openidexample.db'
OPENID_FS_PATH = '/tmp/openidexample-store'
SECRET_KEY = 'development key'
DEBUG = True
# setup flask
app = Flask(__name__)
app.debug = DEBUG
app.secret_key = SECRET_KEY
# setup simpleopenid
oid = SimpleOpenID(OPENID_FS_PATH)
# setup sqlalchemy
engine = create_engine(DATABASE_URI)
db_session = scoped_session(sessionmaker(autocommit=False,
autoflush=False,
bind=engine))
Base = declarative_base()
Base.query = db_session.query_property()
def init_db():
Base.metadata.create_all(bind=engine)
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String(60))
email = Column(String(200))
openid = Column(String(200))
def __init__(self, name, email, openid):
self.name = name
self.email = email
self.openid = openid
@app.before_request
def before_request():
g.user = None
if 'openid' in session:
g.user = User.query.filter_by(openid=session['openid']).first()
@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)
return render_template('login.html', next_url=oid.get_next_url())
@oid.after_login
def create_or_login(identity_url):
"""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'] = identity_url
user = User.query.filter_by(openid=identity_url).first()
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()))
@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')
db_session.add(User(name, email, session['openid']))
db_session.commit()
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:
db_session.delete(g.user)
db_session.commit()
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']
db_session.commit()
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 were signed out')
return redirect(oid.get_next_url())
if __name__ == '__main__':
app.run()

108
examples/openidexample/simpleopenid.py

@ -1,108 +0,0 @@
# -*- coding: utf-8 -*-
"""
simpleopenid
~~~~~~~~~~~~
Tiny wrapper around python-openid to make working with the basic
API in a flask application easier. Adapt this code for your own
project if necessary.
:copyright: (c) 2010 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""
from functools import wraps
from flask import request, session, flash, redirect
from werkzeug import url_quote
from openid.association import Association
from openid.store.interface import OpenIDStore
from openid.store.filestore import FileOpenIDStore
from openid.consumer.consumer import Consumer, SUCCESS, CANCEL
from openid.consumer import discover
from openid.store import nonce
# python-openid is a really stupid library in that regard, we have
# to disable logging by monkey patching
from openid import oidutil
oidutil.log = lambda *a, **kw: None
class SimpleOpenID(object):
"""Simple helper class for OpenID auth."""
def __init__(self, store_path):
self.store_path = store_path
self.after_login_func = None
def create_store(self):
"""Creates the filesystem store"""
return FileOpenIDStore(self.store_path)
def signal_error(self, msg):
"""Signals an error. It does this by flashing a message"""
flash(u'Error: ' + msg)
def get_next_url(self):
"""Return the URL where we want to redirect to."""
return request.values.get('next') or \
request.referrer or \
request.url_root
def get_current_url(self):
"""the current URL + next"""
return request.base_url + '?next=' + url_quote(self.get_next_url())
def get_success_url(self):
"""Return the success URL"""
return self.get_current_url() + '&openid_complete=yes'
def errorhandler(f):
"""Called if an error occours with the message. By default
``'Error: message'`` is flashed.
"""
self.signal_error = f
return f
def after_login(self, f):
"""This function will be called after login. It must redirect to
a different place and remember the user somewhere. The session
is not modified by SimpleOpenID.
"""
self.after_login_func = f
return f
def loginhandler(self, f):
"""Marks a function as login handler. This decorator injects some
more OpenID required logic.
"""
self.login_endpoint = f.__name__
@wraps(f)
def decorated(*args, **kwargs):
if request.args.get('openid_complete') != u'yes':
return f(*args, **kwargs)
consumer = Consumer(session, self.create_store())
openid_response = consumer.complete(request.args.to_dict(),
self.get_current_url())
if openid_response.status == SUCCESS:
return self.after_login_func(openid_response.identity_url)
elif openid_response.status == CANCEL:
self.signal_error(u'The request was cancelled')
return redirect(self.get_current_url())
self.signal_error(u'OpenID authentication error')
return redirect(self.get_current_url())
return decorated
def try_login(self, identity_url):
"""This tries to login with the given identity URL. This function
must be called from the login_handler.
"""
try:
consumer = Consumer(session, self.create_store())
auth_request = consumer.begin(identity_url)
except discover.DiscoveryFailure:
self.signal_error(u'The OpenID was invalid')
return redirect(self.get_current_url())
trust_root = request.host_url
return redirect(auth_request.redirectURL(request.host_url,
self.get_success_url()))

BIN
examples/openidexample/static/openid.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 433 B

39
examples/openidexample/static/style.css

@ -1,39 +0,0 @@
body {
font-family: 'Georgia', serif;
font-size: 16px;
margin: 30px;
padding: 0;
}
a {
color: #335E79;
}
p.message {
color: #335E79;
padding: 10px;
background: #CADEEB;
}
input {
font-family: 'Georgia', serif;
font-size: 16px;
border: 1px solid black;
color: #335E79;
padding: 2px;
}
input[type="submit"] {
background: #CADEEB;
color: #335E79;
border-color: #335E79;
}
input[name="openid"] {
background: url(openid.png) 4px no-repeat;
padding-left: 24px;
}
h1, h2 {
font-weight: normal;
}

22
examples/openidexample/templates/create_profile.html

@ -1,22 +0,0 @@
{% extends "layout.html" %}
{% block title %}Create Profile{% endblock %}
{% block body %}
<h2>Create Profile</h2>
<p>
Hey! This is the first time you signed in on this website. In
order to proceed we need a couple of more information from you:
<form action="" method=post>
<dl>
<dt>Name:
<dd><input type=text name=name size=30 value="{{ request.form.name }}">
<dt>E-Mail
<dd><input type=text name=email size=30 value="{{ request.form.email }}">
</dl>
<p>
<input type=submit value="Create profile">
<input type=hidden name=next value="{{ next_url }}">
</form>
<p>
If you don't want to proceed, you can <a href="{{ url_for('logout')
}}">sign out</a> again.
{% endblock %}

16
examples/openidexample/templates/edit_profile.html

@ -1,16 +0,0 @@
{% extends "layout.html" %}
{% block title %}Edit Profile{% endblock %}
{% block body %}
<h2>Edit Profile</h2>
<form action="" method=post>
<dl>
<dt>Name:
<dd><input type=text name=name size=30 value="{{ form.name }}">
<dt>E-Mail
<dd><input type=text name=email size=30 value="{{ form.email }}">
</dl>
<p>
<input type=submit value="Update profile">
<input type=submit name=delete value="Delete">
</form>
{% endblock %}

10
examples/openidexample/templates/index.html

@ -1,10 +0,0 @@
{% extends "layout.html" %}
{% block body %}
<h2>Overview</h2>
{% if g.user %}
<p>
Hello {{ g.user.name }}!
{% endif %}
<p>
This is just an example page so that something is here.
{% endblock %}

18
examples/openidexample/templates/layout.html

@ -1,18 +0,0 @@
<!doctype html>
<title>{% block title %}Welcome{% endblock %} | Flask OpenID Example</title>
<link rel=stylesheet type=text/css href="{{ url_for('static',
filename='style.css') }}">
<h1>Flask OpenID Example</h1>
<ul class=navigation>
<li><a href="{{ url_for('index') }}">overview</a>
{% if g.user %}
<li><a href="{{ url_for('edit_profile') }}">profile</a>
<li><a href="{{ url_for('logout') }}">sign out [{{ g.user.name }}]</a>
{% else %}
<li><a href="{{ url_for('login') }}">sign in</a>
{% endif %}
</ul>
{% for message in get_flashed_messages() %}
<p class=message>{{ message }}
{% endfor %}
{% block body %}{% endblock %}

12
examples/openidexample/templates/login.html

@ -1,12 +0,0 @@
{% extends "layout.html" %}
{% block title %}Sign in{% endblock %}
{% block body %}
<h2>Sign in</h2>
<form action="" method=post>
<p>
OpenID:
<input type=text name=openid size=30>
<input type=submit value="Sign in">
<input type=hidden name=next value="{{ next_url }}">
</form>
{% endblock %}
Loading…
Cancel
Save