Merge branch 'master' into cas-version-2-and-3

Conflicts:
	flask_cas/__init__.py
	flask_cas/routing.py
	setup.py
	tests/test_routing.py
This commit is contained in:
Cameron Brandon White 2015-04-19 18:29:23 -07:00
commit 4a33cd1774
7 changed files with 63 additions and 16 deletions

View file

@ -1,5 +1,6 @@
language: python
python:
- "2.6"
- "2.7"
- "3.3"
- "3.4"

View file

@ -86,6 +86,26 @@ configuration value.
The `/logout/` route will redirect the user to the CAS logout page and
the `username` will be removed from the session.
For convenience you can use the `cas.login` and `cas.logout`
functions to redirect users to the login and logout pages.
```python
from flask.ext.cas import login
from flask.ext.cas import logout
```
If you would like to require that a user is logged in before continuing
you may use the `cas.login_required` method.
```python
from flask.ext.cas import login_required
app.route('/foo')
@login_required
def foo():
pass
```
### Configuration ###
#### Required Configs ####
@ -112,6 +132,7 @@ the `username` will be removed from the session.
import flask
from flask import Flask
from flask.ext.cas import CAS
from flask.ext.cas import login_required
app = Flask(__name__)
cas = CAS(app, '/cas')
@ -119,6 +140,7 @@ app.config['CAS_SERVER'] = 'https://sso.pdx.edu'
app.config['CAS_AFTER_LOGIN'] = 'route_root'
@app.route('/')
@login_required
def route_root():
return flask.render_template(
'layout.html',

View file

@ -15,6 +15,7 @@ except ImportError:
from . import routing
from functools import wraps
class CAS(object):
"""
@ -81,3 +82,19 @@ class CAS(object):
def attributes(self):
return flask.session.get(
self.app.config['CAS_ATTRIBUTES_SESSION_KEY'], None)
def login():
return flask.redirect(flask.url_for('cas.login', _external=True))
def logout():
return flask.redirect(flask.url_for('cas.logout', _external=True))
def login_required(function):
@wraps(function)
def wrap(*args, **kwargs):
if 'CAS_USERNAME' not in flask.session:
flask.session['CAS_AFTER_LOGIN_SESSION_URL'] = flask.request.path
return login()
else:
return function(*args, **kwargs)
return wrap

View file

@ -59,7 +59,7 @@ def create_url(base, path=None, *query):
# Remove key/value pairs with None values.
query = filter(lambda pair: pair[1] is not None, query)
# Add the query string to the url
url = urljoin(url, '?{}'.format(urlencode(list(query))))
url = urljoin(url, '?{0}'.format(urlencode(list(query))))
return url

View file

@ -40,12 +40,15 @@ def login():
if cas_token_session_key in flask.session:
if validate(flask.session[cas_token_session_key]):
redirect_url = flask.url_for(
current_app.config['CAS_AFTER_LOGIN'])
if 'CAS_AFTER_LOGIN_SESSION_URL' in flask.session:
redirect_url = flask.session.pop('CAS_AFTER_LOGIN_SESSION_URL')
else:
redirect_url = flask.url_for(
current_app.config['CAS_AFTER_LOGIN'])
else:
del flask.session[cas_token_session_key]
current_app.logger.debug('Redirecting to: {}'.format(redirect_url))
current_app.logger.debug('Redirecting to: {0}'.format(redirect_url))
return flask.redirect(redirect_url)
@ -68,7 +71,7 @@ def logout():
current_app.config['CAS_VERSION'],
)
current_app.logger.debug('Redirecting to: {}'.format(redirect_url))
current_app.logger.debug('Redirecting to: {0}'.format(redirect_url))
return flask.redirect(redirect_url)
@ -80,7 +83,9 @@ def validate(ticket):
key `CAS_USERNAME_SESSION_KEY`.
"""
current_app.logger.debug("validating token {}".format(ticket))
cas_username_session_key = current_app.config['CAS_USERNAME_SESSION_KEY']
current_app.logger.debug("validating token {0}".format(ticket))
_PROTOCOLS = {'1': _validate_cas1, '2': _validate_cas2, '3': _validate_cas3}
if current_app.config['CAS_VERSION'] not in _PROTOCOLS:
@ -93,7 +98,7 @@ def validate(ticket):
ticket,
version=current_app.config['CAS_VERSION'])
current_app.logger.debug("Making GET request to {}".format(
current_app.logger.debug("Making GET request to {0}".format(
cas_validate_url))
response = urlopen(cas_validate_url)

View file

@ -8,7 +8,7 @@ import textwrap
if __name__ == "__main__":
setuptools.setup(
name="Flask-CAS",
version="1.0.0",
version="0.5.1",
description="Flask extension for CAS",
author="Cameron Brandon White",
author_email="cameronbwhite90@gmail.com",

View file

@ -71,18 +71,16 @@ class test_cas_1_routing(test_routing):
with client.session_transaction() as s:
s[self.app.config['CAS_TOKEN_SESSION_KEY']] = ticket
client.get('/login/')
self.assertNotIn(
self.app.config['CAS_USERNAME_SESSION_KEY'],
flask.session)
self.assertNotIn(
self.app.config['CAS_TOKEN_SESSION_KEY'],
flask.session)
self.assertTrue(
self.app.config['CAS_USERNAME_SESSION_KEY'] not in flask.session)
self.assertTrue(
self.app.config['CAS_TOKEN_SESSION_KEY'] not in flask.session)
@mock.patch.object(routing, 'validate', return_value=True)
def test_login_by_cas_valid(self, m):
with self.app.test_client() as client:
ticket = '12345-abcdefg-cas'
response = client.get('/login/?ticket={}'.format(ticket))
response = client.get('/login/?ticket={0}'.format(ticket))
self.assertEqual(response.status_code, 302)
self.assertEqual(
response.headers['Location'],
@ -95,7 +93,7 @@ class test_cas_1_routing(test_routing):
def test_login_by_cas_invalid(self, m):
with self.app.test_client() as client:
ticket = '12345-abcdefg-cas'
response = client.get('/login/?ticket={}'.format(ticket))
response = client.get('/login/?ticket={0}'.format(ticket))
self.assertEqual(response.status_code, 302)
self.assertEqual(
response.headers['Location'],
@ -244,3 +242,7 @@ class test_cas_3_routing(test_routing):
self.assertNotIn(
self.app.config['CAS_TOKEN_SESSION_KEY'],
flask.session)
self.assertTrue(
self.app.config['CAS_USERNAME_SESSION_KEY'] not in flask.session)
self.assertTrue(
self.app.config['CAS_TOKEN_SESSION_KEY'] not in flask.session)