Package Products :: Package ZenUtils :: Package patches :: Module pasmonkey
[hide private]
[frames] | no frames]

Source Code for Module Products.ZenUtils.patches.pasmonkey

  1  ############################################################################## 
  2  #  
  3  # Copyright (C) Zenoss, Inc. 2007, all rights reserved. 
  4  #  
  5  # This content is made available according to terms specified in 
  6  # License.zenoss under the directory where your Zenoss product is installed. 
  7  #  
  8  ############################################################################## 
  9   
 10   
 11  ''' 
 12  This module contains monkey patches we needed to make to PAS when we switched 
 13  from native ZODB-managed authentication to pluggable authentication. 
 14   
 15  This module needs to be imported by ZenUtils/__init__.py. 
 16   
 17  Related tickets: 
 18    http://dev.zenoss.org/trac/ticket/379 
 19    http://dev.zenoss.org/trac/ticket/402 
 20    http://dev.zenoss.org/trac/ticket/443 
 21    http://dev.zenoss.org/trac/ticket/1042 
 22    http://dev.zenoss.org/trac/ticket/4225 
 23    http://jira.zenoss.com/jira/browse/ZEN-110 
 24  ''' 
 25   
 26  import urllib 
 27  import urlparse 
 28  from uuid import uuid1 
 29  from cgi import parse_qs 
 30  from Acquisition import aq_base 
 31  from AccessControl.SpecialUsers import emergency_user 
 32  from zope.event import notify 
 33  from Products.PluggableAuthService import PluggableAuthService 
 34  from Products.PluggableAuthService.plugins import CookieAuthHelper 
 35  from Products.PluggableAuthService.interfaces.authservice import _noroles 
 36  from Products.ZenMessaging.audit import audit 
 37  from Products.ZenUtils.events import UserLoggedInEvent, UserLoggedOutEvent 
 38  from Products.ZenUtils.Security import _createInitialUser 
 39   
 40  # monkey patch PAS to allow inituser files, but check to see if we need to 
 41  # actually apply the patch, first -- support may have been added at some point 
 42  pas = PluggableAuthService.PluggableAuthService 
 43  if not hasattr(pas, '_createInitialUser'): 
 44      pas._createInitialUser =  _createInitialUser 
 45   
 46  # Monkey patch PAS to monitor logouts (credential resets). 
 47  # Have to check the request object to determine when we have an actual 
 48  # logout instead of 'fake' logout (like the logout of the anonymous user) 
 49  _originalResetCredentials = pas.resetCredentials 
50 -def _resetCredentials(self, request, response=None):
51 audit("UI.Authentication.Logout") 52 notify(UserLoggedOutEvent(self.zport.dmd.ZenUsers.getUserSettings())) 53 _originalResetCredentials(self, request, response)
54 pas.resetCredentials = _resetCredentials 55 56 # Monkey patch PAS to audit log successful and failed login attempts
57 -def validate(self, request, auth='', roles=_noroles):
58 """ 59 Here is a run down of how this method is called and where it ends up returning 60 in various login situations. 61 62 Failure (admin, local, LDAP, and Active Directory) 63 is_top=0, user_ids=[], name=login, if not is_top: return None (outside loop) 64 is_top=1, user_ids=[], name=login, return anonymous 65 66 Success (admin) 67 is_top=0, user_ids=[], name=login, if not is_top: return (outside loop) 68 is_top=1, user_ids=[('admin', 'admin')], name=login, if self._authorizeUser(...): return user 69 70 Success (local, LDAP, and Active Directory) 71 is_top=0, user_ids=[('username', 'username')], name=login, if self._authorizeUser(...): return user 72 """ 73 plugins = self._getOb( 'plugins' ) 74 is_top = self._isTop() 75 user_ids = self._extractUserIds(request, plugins) 76 accessed, container, name, value = self._getObjectContext(request['PUBLISHED'], request) 77 ipaddress = getattr(request, '_client_addr', 'Unknown') 78 for user_id, login in user_ids: 79 user = self._findUser(plugins, user_id, login, request=request) 80 if aq_base(user) is emergency_user: 81 if is_top: 82 return user 83 else: 84 return None 85 86 if self._authorizeUser(user, accessed, container, name, value, roles): 87 if name == 'login': 88 audit('UI.Authentication.Valid', ipaddress=ipaddress) 89 notify(UserLoggedInEvent(self.zport.dmd.ZenUsers.getUserSettings())) 90 return user 91 92 if not is_top: 93 return None 94 95 anonymous = self._createAnonymousUser(plugins) 96 if self._authorizeUser(anonymous, accessed, container, name, value, roles): 97 if name == 'login': 98 username_ = request.form.get('__ac_name', 'Unknown') 99 audit('UI.Authentication.Failed', username_=username_, ipaddress=ipaddress) 100 return anonymous 101 102 return None
103 104 pas.validate = validate 105 106 # monkey patches for the PAS login form 107
108 -def manage_afterAdd(self, item, container):
109 """We don't want CookieAuthHelper setting the login attribute, we we'll 110 override manage_afterAdd(). 111 112 For now, the only thing that manage_afterAdd does is set the login_form 113 attribute, but we will need to check this after every upgrade of the PAS. 114 """ 115 pass
116 117 CookieAuthHelper.CookieAuthHelper.manage_afterAdd = manage_afterAdd 118
119 -def login(self):
120 """ 121 Set a cookie and redirect to the url that we tried to 122 authenticate against originally. 123 124 FIXME - I don't think we need this any more now that the EULA is gone -EAD 125 """ 126 127 request = self.REQUEST 128 response = request['RESPONSE'] 129 130 login = request.get('__ac_name', '') 131 password = request.get('__ac_password', '') 132 submitted = request.get('submitted', '') 133 134 pas_instance = self._getPAS() 135 136 if pas_instance is not None: 137 pas_instance.updateCredentials(request, response, login, password) 138 139 came_from = request.form.get('came_from') or '' 140 if came_from: 141 parts = urlparse.urlsplit(came_from) 142 querydict = parse_qs(parts[3]) 143 querydict.pop('terms', None) 144 if 'submitted' not in querydict.keys(): 145 querydict['submitted'] = submitted 146 newqs = urllib.urlencode(querydict, doseq=True) 147 parts = parts[:3] + (newqs,) + parts[4:] 148 came_from = urlparse.urlunsplit(parts) 149 else: 150 submittedQs = 'submitted=%s' % submitted 151 came_from = '/zport/dmd?%s' % submittedQs 152 if not self.dmd.acceptedTerms: 153 url = "%s/zenoss_terms/?came_from=%s" % ( 154 self.absolute_url(), urllib.quote(came_from)) 155 else: 156 url = came_from 157 158 if self.dmd.uuid is None: 159 self.dmd.uuid = str(uuid1()) 160 return response.redirect(url)
161 162 CookieAuthHelper.CookieAuthHelper.login = login 163 164
165 -def termsCheck(self):
166 """ Check to see if the user has accepted the Zenoss terms. 167 """ 168 request = self.REQUEST 169 response = request['RESPONSE'] 170 171 acceptStatus = request.form.get('terms') or '' 172 url = request.form.get('came_from') or self.absolute_url() 173 174 if acceptStatus != 'Accept': 175 self.resetCredentials(request, response) 176 if '?' in url: 177 url += '&' 178 else: 179 url += '?' 180 url += 'terms=Decline' 181 else: 182 self.dmd.acceptedTerms = True 183 self.dmd.uuid = str(uuid1()) 184 return response.redirect(url)
185 186 CookieAuthHelper.CookieAuthHelper.termsCheck = termsCheck 187