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

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