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