src/pyams_security/views/oauth.py
changeset 0 f04e1d0a0723
child 2 94e76f8e9828
equal deleted inserted replaced
-1:000000000000 0:f04e1d0a0723
       
     1 #
       
     2 # Copyright (c) 2008-2015 Thierry Florac <tflorac AT ulthar.net>
       
     3 # All Rights Reserved.
       
     4 #
       
     5 # This software is subject to the provisions of the Zope Public License,
       
     6 # Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
       
     7 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
       
     8 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
       
     9 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
       
    10 # FOR A PARTICULAR PURPOSE.
       
    11 #
       
    12 
       
    13 __docformat__ = 'restructuredtext'
       
    14 
       
    15 
       
    16 # import standard library
       
    17 from logging import WARNING
       
    18 
       
    19 # import interfaces
       
    20 from pyams_form.interfaces.form import IWidgetsSuffixViewletsManager
       
    21 from pyams_skin.layer import IPyAMSLayer
       
    22 from pyams_security.interfaces import AuthenticatedPrincipalEvent, LOGIN_REFERER_KEY, ISecurityManager, ILoginView
       
    23 
       
    24 # import packages
       
    25 from authomatic.adapters import WebObAdapter
       
    26 from authomatic.core import Authomatic
       
    27 from authomatic.providers import oauth1, oauth2
       
    28 from pyams_template.template import template_config
       
    29 from pyams_utils.registry import query_utility
       
    30 from pyams_viewlet.viewlet import Viewlet, viewlet_config
       
    31 from pyramid.httpexceptions import HTTPNotFound
       
    32 from pyramid.response import Response
       
    33 from pyramid.security import remember
       
    34 from pyramid.view import view_config
       
    35 
       
    36 
       
    37 #
       
    38 # Authomatic social login
       
    39 #
       
    40 
       
    41 @viewlet_config(name='social-login-suffix', layer=IPyAMSLayer,
       
    42                 manager=IWidgetsSuffixViewletsManager, view=ILoginView, weight=50)
       
    43 @template_config(template='templates/social-login.pt')
       
    44 class SocialLoginViewletsSuffix(Viewlet):
       
    45     """Social login viewlets suffix"""
       
    46 
       
    47     def __new__(cls, *args, **kwargs):
       
    48         manager = query_utility(ISecurityManager)
       
    49         if not manager.enable_social_login:
       
    50             return None
       
    51         return Viewlet.__new__(cls)
       
    52 
       
    53     @property
       
    54     def use_popup(self):
       
    55         manager = query_utility(ISecurityManager)
       
    56         return manager.social_login_use_popup
       
    57 
       
    58 
       
    59 CONFIG = {
       
    60 
       
    61     'twitter': {
       
    62         'id': 10,
       
    63         # Provider class
       
    64         'class_': oauth1.Twitter,
       
    65 
       
    66         # Twitter is an AuthorizationProvider so we need to set several other properties too:
       
    67         'consumer_key': 'F41qIog95eVs07RupYccokWbk',
       
    68         'consumer_secret': 'yrEYMT3VnkT4yvCsXvaKDWok5gehU6fjz38e2FTphE8BXaapUA',
       
    69     },
       
    70 
       
    71     'facebook': {
       
    72         'id': 20,
       
    73         # Provider class
       
    74         'class_': oauth2.Facebook,
       
    75 
       
    76         # Facebook is an AuthorizationProvider too.
       
    77         'consumer_key': '417712258385794',
       
    78         'consumer_secret': '0a2bfc72bdc05caff800b8e46fe8ca64',
       
    79 
       
    80         # But it is also an OAuth 2.0 provider and it needs scope.
       
    81         'scope': ['email'],
       
    82     },
       
    83 
       
    84     'google': {
       
    85         'id': 30,
       
    86         # Provider class
       
    87         'class_': oauth2.Google,
       
    88         'consumer_key': '203791088227-a2nuqdo2t74ebv1n0s8houb4jfmjtp1t.apps.googleusercontent.com',
       
    89         'consumer_secret': 'gsATqmPQASMtC60OACMcOH0i',
       
    90         'scope': ['email']
       
    91     }
       
    92 }
       
    93 
       
    94 
       
    95 @view_config(route_name='login')
       
    96 def login(request):
       
    97     """Login view for Authautomatic authentication"""
       
    98     # check security manager utility
       
    99     manager = query_utility(ISecurityManager)
       
   100     if (manager is None) or not manager.enable_social_login:
       
   101         raise HTTPNotFound()
       
   102     # store referer
       
   103     session = request.session
       
   104     if LOGIN_REFERER_KEY not in session:
       
   105         referer = request.referer
       
   106         session[LOGIN_REFERER_KEY] = referer
       
   107     # init authomatic
       
   108     provider_name = request.matchdict.get('provider_name')
       
   109     authomatic = Authomatic(config=CONFIG, secret=manager.authomatic_secret, logging_level=WARNING)
       
   110     # perform login
       
   111     response = Response()
       
   112     result = authomatic.login(WebObAdapter(request, response), provider_name)
       
   113     if result:
       
   114         if result.error:
       
   115             pass
       
   116         elif result.user:
       
   117             if not (result.user.id and result.user.name):
       
   118                 result.user.update()
       
   119             principal_id = 'oauth:{0}.{1}'.format(provider_name, result.user.id)
       
   120             request.registry.notify(AuthenticatedPrincipalEvent('oauth',
       
   121                                                                 principal_id=principal_id,
       
   122                                                                 user=result.user))
       
   123             headers = remember(request, principal_id)
       
   124             response.headerlist.extend(headers)
       
   125         if manager.social_login_use_popup:
       
   126             response.text = result.popup_html()
       
   127         response.status_code = 302
       
   128         if LOGIN_REFERER_KEY in session:
       
   129             response.location = session[LOGIN_REFERER_KEY]
       
   130             del session[LOGIN_REFERER_KEY]
       
   131         else:
       
   132             response.location = '/'
       
   133     return response