Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ID Site support #19

Open
wants to merge 5 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions docs/quickstart.rst
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,26 @@ walk you through the basics:
- Navigate to ``/login``. You will see a login page. You can now re-enter
your user credentials and log into the site again.

ID Site
-------

If you'd like to not worry about using your own registration and login
screens at all, you can use Stormpath's new `ID site feature
<http://docs.stormpath.com/guides/using-id-site/>`_. This is a hosted login
subdomain which handles authentication for you automatically.

To make this work, you need to specify a few additional settings:

app.config['STORMPATH_ENABLE_ID_SITE'] = True
app.config['STORMPATH_ID_SITE_CALLBACK_URL'] = '/id-site-callback'

.. note::
Please note that the ID Site callback URL must be a relative path and it must
match the one set in the Stormpath ID Site Dashboard.
For production pruposes your will probably also want to set app.config['SERVER_NAME']
for the relative callback url to be properly generated to match the absolute URL
specified in the Stormpath ID Site Dashboard.

Wasn't that easy?!

.. note::
Expand Down
117 changes: 83 additions & 34 deletions flask_stormpath/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@
login,
logout,
register,
id_site_login,
id_site_logout,
id_site_register,
id_site_forgot_password,
id_site_callback,
)


Expand Down Expand Up @@ -163,56 +168,96 @@ def init_routes(self, app):

:param obj app: The Flask app.
"""
if app.config['STORMPATH_ENABLE_REGISTRATION']:
app.add_url_rule(
app.config['STORMPATH_REGISTRATION_URL'],
'stormpath.register',
register,
methods = ['GET', 'POST'],
)

if app.config['STORMPATH_ENABLE_LOGIN']:
if app.config['STORMPATH_ENABLE_ID_SITE']:

app.add_url_rule(
app.config['STORMPATH_LOGIN_URL'],
'stormpath.login',
login,
methods = ['GET', 'POST'],
id_site_login,
methods = ['GET'],
)

if app.config['STORMPATH_ENABLE_FORGOT_PASSWORD']:
app.add_url_rule(
app.config['STORMPATH_FORGOT_PASSWORD_URL'],
'stormpath.forgot',
forgot,
methods = ['GET', 'POST'],
app.config['STORMPATH_REGISTRATION_URL'],
'stormpath.register',
id_site_register,
methods = ['GET'],
)

app.add_url_rule(
app.config['STORMPATH_FORGOT_PASSWORD_CHANGE_URL'],
'stormpath.forgot_change',
forgot_change,
methods = ['GET', 'POST'],
app.config['STORMPATH_FORGOT_PASSWORD_URL'],
'stormpath.forgot',
id_site_forgot_password,
methods = ['GET'],
)

if app.config['STORMPATH_ENABLE_LOGOUT']:
app.add_url_rule(
app.config['STORMPATH_LOGOUT_URL'],
'stormpath.logout',
logout,
id_site_logout,
methods = ['GET'],
)

if app.config['STORMPATH_ENABLE_GOOGLE']:
app.add_url_rule(
app.config['STORMPATH_GOOGLE_LOGIN_URL'],
'stormpath.google_login',
google_login,
app.config['STORMPATH_ID_SITE_CALLBACK_URL'],
'stormpath.id_site_callback',
id_site_callback,
methods = ['GET'],
)

if app.config['STORMPATH_ENABLE_FACEBOOK']:
app.add_url_rule(
app.config['STORMPATH_FACEBOOK_LOGIN_URL'],
'stormpath.facebook_login',
facebook_login,
)
else:

if app.config['STORMPATH_ENABLE_REGISTRATION']:
app.add_url_rule(
app.config['STORMPATH_REGISTRATION_URL'],
'stormpath.register',
register,
methods = ['GET', 'POST'],
)

if app.config['STORMPATH_ENABLE_LOGIN']:
app.add_url_rule(
app.config['STORMPATH_LOGIN_URL'],
'stormpath.login',
login,
methods = ['GET', 'POST'],
)

if app.config['STORMPATH_ENABLE_FORGOT_PASSWORD']:
app.add_url_rule(
app.config['STORMPATH_FORGOT_PASSWORD_URL'],
'stormpath.forgot',
forgot,
methods = ['GET', 'POST'],
)
app.add_url_rule(
app.config['STORMPATH_FORGOT_PASSWORD_CHANGE_URL'],
'stormpath.forgot_change',
forgot_change,
methods = ['GET', 'POST'],
)

if app.config['STORMPATH_ENABLE_LOGOUT']:
app.add_url_rule(
app.config['STORMPATH_LOGOUT_URL'],
'stormpath.logout',
logout,
)

if app.config['STORMPATH_ENABLE_GOOGLE']:
app.add_url_rule(
app.config['STORMPATH_GOOGLE_LOGIN_URL'],
'stormpath.google_login',
google_login,
)

if app.config['STORMPATH_ENABLE_FACEBOOK']:
app.add_url_rule(
app.config['STORMPATH_FACEBOOK_LOGIN_URL'],
'stormpath.facebook_login',
facebook_login,
)

@property
def client(self):
Expand Down Expand Up @@ -274,9 +319,13 @@ def application(self):
ctx = stack.top
if ctx is not None:
if not hasattr(ctx, 'stormpath_application'):
ctx.stormpath_application = self.client.applications.search(
self.app.config['STORMPATH_APPLICATION']
)[0]
if self.app.config['STORMPATH_APPLICATION'].startswith('http'):
ctx.stormpath_application = self.client.applications.get(
self.app.config['STORMPATH_APPLICATION'])
else:
ctx.stormpath_application = self.client.applications.search(
self.app.config['STORMPATH_APPLICATION']
)[0]

return ctx.stormpath_application

Expand Down
39 changes: 39 additions & 0 deletions flask_stormpath/id_site.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
from flask.ext.login import login_user, logout_user
from flask import redirect, current_app, request

from .models import User


ID_SITE_STATUS_AUTHENTICATED = 'AUTHENTICATED'
ID_SITE_STATUS_LOGOUT = 'LOGOUT'
ID_SITE_STATUS_REGISTERED = 'REGISTERED'


def _handle_authenticated(id_site_response):
login_user(User.from_id_site(id_site_response.account),
remember=True)
return redirect(request.args.get('next') or current_app.config['STORMPATH_REDIRECT_URL'])


def _handle_logout(id_site_response):
logout_user()
return redirect('/')


_handle_registered = _handle_authenticated


def handle_id_site_callback(id_site_response):
if id_site_response:
action = CALLBACK_ACTIONS[id_site_response.status]
return action(id_site_response)
else:
return None


CALLBACK_ACTIONS = {
ID_SITE_STATUS_AUTHENTICATED: _handle_authenticated,
ID_SITE_STATUS_LOGOUT: _handle_logout,
ID_SITE_STATUS_REGISTERED: _handle_registered
}

7 changes: 7 additions & 0 deletions flask_stormpath/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,13 @@ def from_login(self, login, password):

return _user

@classmethod
def from_id_site(self, account):
_user = account
_user.__class__ = User

return _user

@classmethod
def from_google(self, code):
"""
Expand Down
2 changes: 2 additions & 0 deletions flask_stormpath/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ def init_settings(config):
config.setdefault('STORMPATH_API_KEY_SECRET', None)
config.setdefault('STORMPATH_API_KEY_FILE', None)
config.setdefault('STORMPATH_APPLICATION', None)
config.setdefault('STORMPATH_ENABLE_ID_SITE', False)
config.setdefault('STORMPATH_ID_SITE_CALLBACK_URL', None)

# Which fields should be displayed when registering new users?
config.setdefault('STORMPATH_ENABLE_FACEBOOK', False)
Expand Down
40 changes: 40 additions & 0 deletions flask_stormpath/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
current_app,
flash,
redirect,
url_for,
render_template,
request,
)
Expand All @@ -21,6 +22,7 @@
RegistrationForm,
)
from .models import User
from .id_site import handle_id_site_callback


def register():
Expand Down Expand Up @@ -399,3 +401,41 @@ def logout():
"""
logout_user()
return redirect('/')


def id_site_login():
rdr = current_app.stormpath_manager.application.build_id_site_redirect_url(
callback_uri=url_for('stormpath.id_site_callback', _external=True),
state=request.args.get('state'))
return redirect(rdr)


def id_site_register():
rdr = current_app.stormpath_manager.application.build_id_site_redirect_url(
callback_uri=url_for('stormpath.id_site_callback', _external=True),
state=request.args.get('state'),
path="/#/register")
return redirect(rdr)


def id_site_forgot_password():
rdr = current_app.stormpath_manager.application.build_id_site_redirect_url(
callback_uri=url_for('stormpath.id_site_callback', _external=True),
state=request.args.get('state'),
path="/#/forgot")
return redirect(rdr)


def id_site_logout():
rdr = current_app.stormpath_manager.application.build_id_site_redirect_url(
callback_uri=url_for('stormpath.id_site_callback', _external=True),
state=request.args.get('state'),
logout=True)
return redirect(rdr)


def id_site_callback():
ret = current_app.stormpath_manager.application.handle_id_site_callback(
request.url)
return handle_id_site_callback(ret)