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

Source Code for Module Products.ZenUtils.Security

  1  ########################################################################### 
  2  # 
  3  # This program is part of Zenoss Core, an open source monitoring platform. 
  4  # Copyright (C) 2007, Zenoss Inc. 
  5  # 
  6  # This program is free software; you can redistribute it and/or modify it 
  7  # under the terms of the GNU General Public License version 2 or (at your 
  8  # option) any later version as published by the Free Software Foundation. 
  9  # 
 10  # For complete information please visit: http://www.zenoss.com/oss/ 
 11  # 
 12  ########################################################################### 
 13   
 14  import os 
 15  from random import random 
 16  from datetime import datetime 
 17  from sets import Set as set 
 18   
 19  from OFS.Folder import Folder 
 20  from Products.PluggableAuthService import plugins 
 21  from Products.PluggableAuthService import interfaces 
 22  from Products.PluggableAuthService import PluggableAuthService 
 23   
 24   
 25  ZENOSS_ROLES = ['ZenUser', 'ZenManager'] 
 26   
 27   
28 -def backupACLUserFolder(context):
29 timestamp = datetime.now().strftime('%Y.%d.%m-%H%M%S') 30 randomBit = int(random() * 10000) 31 backupFolderName = 'backup_acl_users_%s-%d' % (timestamp, randomBit) 32 backupFolder = Folder(backupFolderName) 33 backupFolder._setObject('acl_users', context.acl_users) 34 context._setObject(backupFolder.getId(), backupFolder) 35 context._delObject('acl_users') 36 return backupFolderName
37 38
39 -def _createInitialUser(self):
40 """ 41 Note: copied and adapted from AccessControl.User.BasicUser 42 43 If there are no users or only one user in this user folder, 44 populates from the 'inituser' file in the instance home. 45 We have to do this even when there is already a user 46 just in case the initial user ignored the setup messages. 47 We don't do it for more than one user to avoid 48 abuse of this mechanism. 49 Called only by OFS.Application.initialize(). 50 """ 51 from AccessControl.User import readUserAccessFile 52 53 plugins = self.plugins.listPlugins( 54 interfaces.plugins.IUserEnumerationPlugin) 55 # get the user count, but only for functional plugins 56 userCounts = [ len(plugin.listUserInfo()) for id, plugin in plugins if hasattr(plugin, "listUserInfo")] 57 58 if len(userCounts) <= 1: 59 info = readUserAccessFile('inituser') 60 if info: 61 import App.config 62 name, password, domains, remote_user_mode = info 63 userManagers = self.plugins.listPlugins(interfaces.plugins.IUserAdderPlugin) 64 roleManagers = self.plugins.listPlugins(interfaces.plugins.IRolesPlugin) 65 for pluginId, userPlugin in userManagers: 66 # delete user 67 try: 68 userPlugin.removeUser(name) 69 except KeyError: 70 # user doesn't exist 71 pass 72 # recreate user 73 userPlugin.doAddUser(name, password) 74 # add role 75 for pluginId, rolePlugin in roleManagers: 76 rolePlugin.assignRoleToPrincipal('Manager', name) 77 cfg = App.config.getConfiguration() 78 # now that we've loaded from inituser, let's delete the file 79 try: 80 os.remove(os.path.join(cfg.instancehome, 'inituser')) 81 except: 82 pass
83 84
85 -def createPASFolder(context):
86 # check to see if we need to monkey patch PAS to accomodate inituser files 87 pas = PluggableAuthService.PluggableAuthService 88 if not hasattr(pas, '_createInitialUser'): 89 pas._createInitialUser = _createInitialUser 90 91 # create new PAS 92 PluggableAuthService.addPluggableAuthService(context) 93 context.acl_users.title = 'PAS'
94 95
96 -def setupBasciAuthHelper(context):
97 acl = context.acl_users 98 id = 'basicAuthHelper' 99 if not hasattr(acl, id): 100 plugins.HTTPBasicAuthHelper.addHTTPBasicAuthHelper(acl, id) 101 interfaces = [] 102 physPath = '/'.join(context.getPhysicalPath()) 103 if physPath == '': 104 interfaces = ['IExtractionPlugin', 'IChallengePlugin', 105 'ICredentialsResetPlugin'] 106 elif physPath == '/zport': 107 interfaces = ['IExtractionPlugin', 'IChallengePlugin'] 108 acl.basicAuthHelper.manage_activateInterfaces(interfaces)
109 110
111 -def setupCookieHelper(context, primaryAuth=False):
112 acl = context.acl_users 113 id = 'cookieAuthHelper' 114 if not hasattr(acl, id): 115 plugins.CookieAuthHelper.addCookieAuthHelper(acl, id) 116 interfaces = [] 117 # note that we are only enabling CookieAuth for the Zenoss portal 118 # acl_users, not for the root acl_users. 119 physPath = '/'.join(context.getPhysicalPath()) 120 if physPath == '': 121 interfaces = ['IExtractionPlugin'] 122 elif physPath == '/zport': 123 interfaces = ['IExtractionPlugin', 124 'ICredentialsResetPlugin', 125 'IChallengePlugin'] 126 if primaryAuth: 127 interfaces.append('ICredentialsUpdatePlugin') 128 acl.cookieAuthHelper.manage_activateInterfaces(interfaces)
129
130 -def setupSessionHelper(context, primaryAuth=True):
131 acl = context.acl_users 132 id = 'sessionAuthHelper' 133 if not hasattr(acl, id): 134 plugins.SessionAuthHelper.manage_addSessionAuthHelper(acl, id) 135 136 interfaces = ['IExtractionPlugin', 137 'ICredentialsResetPlugin'] 138 if primaryAuth: 139 interfaces.append('ICredentialsUpdatePlugin') 140 acl.sessionAuthHelper.manage_activateInterfaces(interfaces)
141
142 -def activateCookieBasedAuthentication(context):
143 """ 144 This sets cookie authentication as the primary auth 145 mechanism. This means that the users credentials will be stored 146 encoded in a cookie. 147 """ 148 setupCookieHelper(context, primaryAuth=True) 149 setupSessionHelper(context, primaryAuth=False)
150
151 -def activateSessionBasedAuthentication(context):
152 """ 153 Stores the user credentials in the session and the token is sent 154 to the server. The user will be forced to re-login when zope 155 restarts or the session times out. 156 """ 157 setupCookieHelper(context, primaryAuth=False) 158 setupSessionHelper(context, primaryAuth=True)
159
160 -def setupRoleManager(context):
161 acl = context.acl_users 162 id = 'roleManager' 163 if not hasattr(acl, id): 164 plugins.ZODBRoleManager.addZODBRoleManager(acl, id) 165 acl.roleManager.manage_activateInterfaces(['IRolesPlugin', 166 'IRoleEnumerationPlugin', 'IRoleAssignerPlugin']) 167 # setup roles 168 for role in ZENOSS_ROLES: 169 try: 170 acl.roleManager.addRole(role) 171 except KeyError: 172 # that role already exists 173 pass
174 175
176 -def setupUserManager(context):
177 acl = context.acl_users 178 id = 'userManager' 179 if not hasattr(acl, id): 180 plugins.ZODBUserManager.addZODBUserManager(acl, id) 181 acl.userManager.manage_activateInterfaces(['IAuthenticationPlugin', 182 'IUserEnumerationPlugin', 'IUserAdderPlugin'])
183 184
185 -def setupTypeSniffer(context):
186 acl = context.acl_users 187 id = 'requestTypeSniffer' 188 if not hasattr(acl, id): 189 plugins.RequestTypeSniffer.addRequestTypeSnifferPlugin(acl, id) 190 acl.requestTypeSniffer.manage_activateInterfaces(['IRequestTypeSniffer'])
191 192
193 -def setupProtocolChooser(context):
194 acl = context.acl_users 195 id = 'protocolChooser' 196 if not hasattr(acl, id): 197 plugins.ChallengeProtocolChooser.addChallengeProtocolChooserPlugin(acl, 198 id) 199 acl.protocolChooser.manage_activateInterfaces([ 200 'IChallengeProtocolChooser']) 201 protocolMapping = {} 202 # set up non-Browser protocols to use HTTP BasicAuth 203 physPath = '/'.join(context.getPhysicalPath()) 204 if physPath == '': 205 protocolMapping = { 206 'Browser': ['http'], 207 'FTP': ['http'], 208 'WebDAV': ['http'], 209 'XML-RPC': ['http'], 210 } 211 elif physPath == '/zport': 212 protocolMapping = { 213 'FTP': ['http'], 214 'WebDAV': ['http'], 215 'XML-RPC': ['http'], 216 } 217 # we don't want to hard-code plugin names here, so let's do a lookup 218 icookie = plugins.CookieAuthHelper.ICookieAuthHelper 219 ichallenge = interfaces.plugins.IChallengePlugin 220 challenge = [ p for id, p in acl.plugins.listPlugins(ichallenge) ] 221 # valid cooike auth plugins 222 cookiePlugins = [ p for p in challenge if icookie.providedBy(p) ] 223 # we want to move the cookie auth instance above the basic auth listing so 224 # that it is accessed first and we can keep 'Browser' set to any; for 225 # now, let's just get the first match and use that one (there should 226 # really only be one...) 227 cookie = cookiePlugins[0] 228 index = challenge.index(cookie) 229 for i in xrange(index): 230 acl.plugins.movePluginsUp(ichallenge, [cookie.id]) 231 acl.protocolChooser.manage_updateProtocolMapping(protocolMapping)
232 233
234 -def setupPASFolder(context):
235 setupBasciAuthHelper(context) 236 setupCookieHelper(context) 237 setupSessionHelper(context) 238 setupRoleManager(context) 239 setupUserManager(context) 240 setupTypeSniffer(context) 241 # this one has to go last in case any of the protocol mappings need to make 242 # reference to an already-installed plugin 243 setupProtocolChooser(context)
244 245
246 -def replaceACLWithPAS(context, deleteBackup=False):
247 # archive the old "User Folder" 248 backupId = backupACLUserFolder(context) 249 250 # create a new PAS acl_users 251 createPASFolder(context) 252 setupPASFolder(context) 253 254 # set up some convenience vars 255 orig = getattr(context, backupId).acl_users 256 acl = context.acl_users 257 258 # migrate the old user information over to the PAS 259 for u in orig.getUsers(): 260 user, password, domains, roles = (u.name, u.__, u.domains, u.roles) 261 acl.userManager.doAddUser(user, password) 262 for role in roles: 263 acl.roleManager.assignRoleToPrincipal(role, user) 264 # initialize UserSettings for each user 265 try: 266 dmd = context.getPhysicalRoot().zport.dmd 267 dmd.ZenUsers.getUserSettings(user) 268 except AttributeError: 269 # no dmd, or no ZenUsers 270 pass 271 272 # delete backup? 273 if deleteBackup: 274 context._delObject(backupId)
275 276
277 -def migratePAS(context):
278 # check to see if the current acl_users is a PAS instance or not 279 newModule = 'Products.PluggableAuthService.PluggableAuthService' 280 try: 281 acl = context.acl_users 282 # if there's an acl_users object, let's see if theres a login_form 283 # attribute; if there is, we need to delete it 284 if (hasattr(acl, 'cookieAuthHelper') 285 and hasattr(acl.cookieAuthHelper, 'login_form')): 286 acl.cookieAuthHelper._delObject('login_form') 287 except AttributeError: 288 createPASFolder(context) 289 acl = context.acl_users 290 291 if acl.__module__ != newModule: 292 replaceACLWithPAS(context) 293 else: 294 # check to see if there are any missing attributes; we have to make the 295 # dir() call twice, because (when testing in the dmd) the 'plugins' 296 # attribute doesn't show up on the first call. 297 dummy = dir(acl) 298 full = set(dir(acl)) 299 needed = set(['_createInitialUser', 'plugins']) 300 # if any of 'needed' are missing, the PAS has to be recreated 301 if not full.issuperset(needed): 302 backupId = backupACLUserFolder(context) 303 backup = context._getOb(backupId) 304 createPASFolder(context) 305 # now that we have a monkey-patched acl_users, restore the plugins 306 for itemId in backup.objectIds(): 307 acl._setObject(itemId, backup._getOb(itemId)) 308 # delete the (empty) backup 309 context._delObject(backupId) 310 # the next function calls all the setup functions, each of which do an 311 # attriibute check and installs anything that's missing 312 setupPASFolder(context)
313