src/pyams_security/views/oauth.py
changeset 0 f04e1d0a0723
child 2 94e76f8e9828
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_security/views/oauth.py	Thu Feb 19 10:53:29 2015 +0100
@@ -0,0 +1,133 @@
+#
+# Copyright (c) 2008-2015 Thierry Florac <tflorac AT ulthar.net>
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+
+__docformat__ = 'restructuredtext'
+
+
+# import standard library
+from logging import WARNING
+
+# import interfaces
+from pyams_form.interfaces.form import IWidgetsSuffixViewletsManager
+from pyams_skin.layer import IPyAMSLayer
+from pyams_security.interfaces import AuthenticatedPrincipalEvent, LOGIN_REFERER_KEY, ISecurityManager, ILoginView
+
+# import packages
+from authomatic.adapters import WebObAdapter
+from authomatic.core import Authomatic
+from authomatic.providers import oauth1, oauth2
+from pyams_template.template import template_config
+from pyams_utils.registry import query_utility
+from pyams_viewlet.viewlet import Viewlet, viewlet_config
+from pyramid.httpexceptions import HTTPNotFound
+from pyramid.response import Response
+from pyramid.security import remember
+from pyramid.view import view_config
+
+
+#
+# Authomatic social login
+#
+
+@viewlet_config(name='social-login-suffix', layer=IPyAMSLayer,
+                manager=IWidgetsSuffixViewletsManager, view=ILoginView, weight=50)
+@template_config(template='templates/social-login.pt')
+class SocialLoginViewletsSuffix(Viewlet):
+    """Social login viewlets suffix"""
+
+    def __new__(cls, *args, **kwargs):
+        manager = query_utility(ISecurityManager)
+        if not manager.enable_social_login:
+            return None
+        return Viewlet.__new__(cls)
+
+    @property
+    def use_popup(self):
+        manager = query_utility(ISecurityManager)
+        return manager.social_login_use_popup
+
+
+CONFIG = {
+
+    'twitter': {
+        'id': 10,
+        # Provider class
+        'class_': oauth1.Twitter,
+
+        # Twitter is an AuthorizationProvider so we need to set several other properties too:
+        'consumer_key': 'F41qIog95eVs07RupYccokWbk',
+        'consumer_secret': 'yrEYMT3VnkT4yvCsXvaKDWok5gehU6fjz38e2FTphE8BXaapUA',
+    },
+
+    'facebook': {
+        'id': 20,
+        # Provider class
+        'class_': oauth2.Facebook,
+
+        # Facebook is an AuthorizationProvider too.
+        'consumer_key': '417712258385794',
+        'consumer_secret': '0a2bfc72bdc05caff800b8e46fe8ca64',
+
+        # But it is also an OAuth 2.0 provider and it needs scope.
+        'scope': ['email'],
+    },
+
+    'google': {
+        'id': 30,
+        # Provider class
+        'class_': oauth2.Google,
+        'consumer_key': '203791088227-a2nuqdo2t74ebv1n0s8houb4jfmjtp1t.apps.googleusercontent.com',
+        'consumer_secret': 'gsATqmPQASMtC60OACMcOH0i',
+        'scope': ['email']
+    }
+}
+
+
+@view_config(route_name='login')
+def login(request):
+    """Login view for Authautomatic authentication"""
+    # check security manager utility
+    manager = query_utility(ISecurityManager)
+    if (manager is None) or not manager.enable_social_login:
+        raise HTTPNotFound()
+    # store referer
+    session = request.session
+    if LOGIN_REFERER_KEY not in session:
+        referer = request.referer
+        session[LOGIN_REFERER_KEY] = referer
+    # init authomatic
+    provider_name = request.matchdict.get('provider_name')
+    authomatic = Authomatic(config=CONFIG, secret=manager.authomatic_secret, logging_level=WARNING)
+    # perform login
+    response = Response()
+    result = authomatic.login(WebObAdapter(request, response), provider_name)
+    if result:
+        if result.error:
+            pass
+        elif result.user:
+            if not (result.user.id and result.user.name):
+                result.user.update()
+            principal_id = 'oauth:{0}.{1}'.format(provider_name, result.user.id)
+            request.registry.notify(AuthenticatedPrincipalEvent('oauth',
+                                                                principal_id=principal_id,
+                                                                user=result.user))
+            headers = remember(request, principal_id)
+            response.headerlist.extend(headers)
+        if manager.social_login_use_popup:
+            response.text = result.popup_html()
+        response.status_code = 302
+        if LOGIN_REFERER_KEY in session:
+            response.location = session[LOGIN_REFERER_KEY]
+            del session[LOGIN_REFERER_KEY]
+        else:
+            response.location = '/'
+    return response