cubicweb/pyramid/auth.py
changeset 11631 faf279e33298
parent 11593 73bf8377a3d5
child 11811 f09efeead7f9
equal deleted inserted replaced
11478:1817f8946c22 11631:faf279e33298
       
     1 import datetime
       
     2 import logging
       
     3 import warnings
       
     4 
       
     5 from zope.interface import implementer
       
     6 
       
     7 from pyramid.settings import asbool
       
     8 from pyramid.authorization import ACLAuthorizationPolicy
       
     9 from cubicweb.pyramid.core import get_principals
       
    10 from pyramid_multiauth import MultiAuthenticationPolicy
       
    11 
       
    12 from pyramid.authentication import AuthTktAuthenticationPolicy
       
    13 
       
    14 from pyramid.interfaces import IAuthenticationPolicy
       
    15 
       
    16 log = logging.getLogger(__name__)
       
    17 
       
    18 
       
    19 @implementer(IAuthenticationPolicy)
       
    20 class UpdateLoginTimeAuthenticationPolicy(object):
       
    21     """An authentication policy that update the user last_login_time.
       
    22 
       
    23     The update is done in the 'remember' method, which is called by the login
       
    24     views login,
       
    25 
       
    26     Usually used via :func:`includeme`.
       
    27     """
       
    28 
       
    29     def authenticated_userid(self, request):
       
    30         pass
       
    31 
       
    32     def effective_principals(self, request):
       
    33         return ()
       
    34 
       
    35     def remember(self, request, principal, **kw):
       
    36         try:
       
    37             repo = request.registry['cubicweb.repository']
       
    38             with repo.internal_cnx() as cnx:
       
    39                 cnx.execute(
       
    40                     "SET U last_login_time %(now)s WHERE U eid %(user)s", {
       
    41                         'now': datetime.datetime.now(),
       
    42                         'user': principal})
       
    43                 cnx.commit()
       
    44         except:
       
    45             log.exception("Failed to update last_login_time")
       
    46         return ()
       
    47 
       
    48     def forget(self, request):
       
    49         return ()
       
    50 
       
    51 
       
    52 class CWAuthTktAuthenticationPolicy(AuthTktAuthenticationPolicy):
       
    53     """
       
    54     An authentication policy that inhibate the call the 'remember' if a
       
    55     'persistent' argument is passed to it, and is equal to the value that
       
    56     was passed to the constructor.
       
    57 
       
    58     This allow to combine two policies with different settings and select them
       
    59     by just setting this argument.
       
    60     """
       
    61     def __init__(self, secret, persistent, defaults={}, prefix='', **settings):
       
    62         self.persistent = persistent
       
    63         unset = object()
       
    64         kw = {}
       
    65         # load string settings
       
    66         for name in ('cookie_name', 'path', 'domain', 'hashalg'):
       
    67             value = settings.get(prefix + name, defaults.get(name, unset))
       
    68             if value is not unset:
       
    69                 kw[name] = value
       
    70         # load boolean settings
       
    71         for name in ('secure', 'include_ip', 'http_only', 'wild_domain',
       
    72                      'parent_domain', 'debug'):
       
    73             value = settings.get(prefix + name, defaults.get(name, unset))
       
    74             if value is not unset:
       
    75                 kw[name] = asbool(value)
       
    76         # load int settings
       
    77         for name in ('timeout', 'reissue_time', 'max_age'):
       
    78             value = settings.get(prefix + name, defaults.get(name, unset))
       
    79             if value is not unset:
       
    80                 kw[name] = int(value)
       
    81         super(CWAuthTktAuthenticationPolicy, self).__init__(secret, **kw)
       
    82 
       
    83     def remember(self, request, principals, **kw):
       
    84         if 'persistent' not in kw or kw.pop('persistent') == self.persistent:
       
    85             return super(CWAuthTktAuthenticationPolicy, self).remember(
       
    86                 request, principals, **kw)
       
    87         else:
       
    88             return ()
       
    89 
       
    90 
       
    91 def includeme(config):
       
    92     """ Activate the CubicWeb AuthTkt authentication policy.
       
    93 
       
    94     Usually called via ``config.include('cubicweb.pyramid.auth')``.
       
    95 
       
    96     See also :ref:`defaults_module`
       
    97     """
       
    98     settings = config.registry.settings
       
    99 
       
   100     policies = []
       
   101 
       
   102     if asbool(settings.get('cubicweb.auth.update_login_time', True)):
       
   103         policies.append(UpdateLoginTimeAuthenticationPolicy())
       
   104 
       
   105     if asbool(settings.get('cubicweb.auth.authtkt', True)):
       
   106         session_prefix = 'cubicweb.auth.authtkt.session.'
       
   107         persistent_prefix = 'cubicweb.auth.authtkt.persistent.'
       
   108 
       
   109         try:
       
   110             secret = config.registry['cubicweb.config']['pyramid-auth-secret']
       
   111             warnings.warn(
       
   112                 "pyramid-auth-secret from all-in-one is now "
       
   113                 "cubicweb.auth.authtkt.[session|persistent].secret",
       
   114                 DeprecationWarning)
       
   115         except:
       
   116             secret = 'notsosecret'
       
   117 
       
   118         session_secret = settings.get(
       
   119             session_prefix + 'secret', secret)
       
   120         persistent_secret = settings.get(
       
   121             persistent_prefix + 'secret', secret)
       
   122 
       
   123         if 'notsosecret' in (session_secret, persistent_secret):
       
   124             warnings.warn('''
       
   125 
       
   126                 !! SECURITY WARNING !!
       
   127 
       
   128                 The authentication cookies are signed with a static secret key.
       
   129 
       
   130                 Configure the following options in your pyramid.ini file:
       
   131 
       
   132                 - cubicweb.auth.authtkt.session.secret
       
   133                 - cubicweb.auth.authtkt.persistent.secret
       
   134 
       
   135                 YOU SHOULD STOP THIS INSTANCE unless your really know what you
       
   136                 are doing !!
       
   137 
       
   138             ''')
       
   139 
       
   140         policies.append(
       
   141             CWAuthTktAuthenticationPolicy(
       
   142                 session_secret, False,
       
   143                 defaults={
       
   144                     'hashalg': 'sha512',
       
   145                     'cookie_name': 'auth_tkt',
       
   146                     'timeout': 1200,
       
   147                     'reissue_time': 120,
       
   148                     'http_only': True,
       
   149                     'secure': True
       
   150                 },
       
   151                 prefix=session_prefix,
       
   152                 **settings
       
   153             )
       
   154         )
       
   155 
       
   156         policies.append(
       
   157             CWAuthTktAuthenticationPolicy(
       
   158                 persistent_secret, True,
       
   159                 defaults={
       
   160                     'hashalg': 'sha512',
       
   161                     'cookie_name': 'pauth_tkt',
       
   162                     'max_age': 3600*24*30,
       
   163                     'reissue_time': 3600*24,
       
   164                     'http_only': True,
       
   165                     'secure': True
       
   166                 },
       
   167                 prefix=persistent_prefix,
       
   168                 **settings
       
   169             )
       
   170         )
       
   171 
       
   172     kw = {}
       
   173     if asbool(settings.get('cubicweb.auth.groups_principals', True)):
       
   174         kw['callback'] = get_principals
       
   175 
       
   176     authpolicy = MultiAuthenticationPolicy(policies, **kw)
       
   177     config.registry['cubicweb.authpolicy'] = authpolicy
       
   178 
       
   179     config.set_authentication_policy(authpolicy)
       
   180     config.set_authorization_policy(ACLAuthorizationPolicy())