Package ganeti :: Package rapi :: Package auth :: Module basic_auth
[hide private]
[frames] | no frames]

Source Code for Module ganeti.rapi.auth.basic_auth

  1  # 
  2  # 
  3   
  4  # Copyright (C) 2006, 2007, 2008, 2009, 2010, 2012, 2013, 2015 Google Inc. 
  5  # All rights reserved. 
  6  # 
  7  # Redistribution and use in source and binary forms, with or without 
  8  # modification, are permitted provided that the following conditions are 
  9  # met: 
 10  # 
 11  # 1. Redistributions of source code must retain the above copyright notice, 
 12  # this list of conditions and the following disclaimer. 
 13  # 
 14  # 2. Redistributions in binary form must reproduce the above copyright 
 15  # notice, this list of conditions and the following disclaimer in the 
 16  # documentation and/or other materials provided with the distribution. 
 17  # 
 18  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 
 19  # IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 
 20  # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
 21  # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 
 22  # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
 23  # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
 24  # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
 25  # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
 26  # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
 27  # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
 28  # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 29   
 30   
 31  """Module interacting with RAPI users config file 
 32   
 33  """ 
 34   
 35  import logging 
 36  import os 
 37  try: 
 38    from pyinotify import pyinotify # pylint: disable=E0611 
 39  except ImportError: 
 40    import pyinotify 
 41   
 42  from ganeti import asyncnotifier 
 43  from ganeti import compat 
 44  from ganeti import http 
 45  from ganeti.http.auth import HttpServerRequestAuthentication 
 46  from ganeti import pathutils 
 47  from ganeti.rapi import auth 
 48  from ganeti.rapi.auth import users_file 
 49   
 50   
51 -class FileEventHandler(asyncnotifier.FileEventHandlerBase):
52 - def __init__(self, wm, path, cb):
53 """Initializes this class. 54 55 @param wm: Inotify watch manager 56 @type path: string 57 @param path: File path 58 @type cb: callable 59 @param cb: Function called on file change 60 61 """ 62 asyncnotifier.FileEventHandlerBase.__init__(self, wm) 63 64 self._cb = cb 65 self._filename = os.path.basename(path) 66 67 # Different Pyinotify versions have the flag constants at different places, 68 # hence not accessing them directly 69 mask = (pyinotify.EventsCodes.ALL_FLAGS["IN_CLOSE_WRITE"] | 70 pyinotify.EventsCodes.ALL_FLAGS["IN_DELETE"] | 71 pyinotify.EventsCodes.ALL_FLAGS["IN_MOVED_FROM"] | 72 pyinotify.EventsCodes.ALL_FLAGS["IN_MOVED_TO"]) 73 74 self._handle = self.AddWatch(os.path.dirname(path), mask)
75
76 - def process_default(self, event):
77 """Called upon inotify event. 78 79 """ 80 if event.name == self._filename: 81 logging.debug("Received inotify event %s", event) 82 self._cb()
83 84
85 -def SetupFileWatcher(filename, cb):
86 """Configures an inotify watcher for a file. 87 88 @type filename: string 89 @param filename: File to watch 90 @type cb: callable 91 @param cb: Function called on file change 92 93 """ 94 wm = pyinotify.WatchManager() 95 handler = FileEventHandler(wm, filename, cb) 96 asyncnotifier.AsyncNotifier(wm, default_proc_fun=handler)
97 98
99 -class BasicAuthenticator(auth.RapiAuthenticator):
100 """Class providing an Authenticate method based on basic http authentication. 101 102 """ 103
104 - def __init__(self, user_fn=None):
105 """Loads users file and initializes a watcher for it. 106 107 @param user_fn: A function that should be called to obtain a user info 108 instead of the default users_file interface. 109 110 """ 111 if user_fn: 112 self.user_fn = user_fn 113 return 114 115 self.users = users_file.RapiUsers() 116 self.user_fn = self.users.Get 117 # Setup file watcher (it'll be driven by asyncore) 118 SetupFileWatcher(pathutils.RAPI_USERS_FILE, 119 compat.partial(self.users.Load, 120 pathutils.RAPI_USERS_FILE)) 121 122 self.users.Load(pathutils.RAPI_USERS_FILE)
123
124 - def ValidateRequest(self, req, handler_access, realm):
125 """Checks whether a user can access a resource. 126 127 """ 128 request_username, request_password = HttpServerRequestAuthentication \ 129 .ExtractUserPassword(req) 130 if request_username is None: 131 raise http.HttpUnauthorized() 132 if request_password is None: 133 raise http.HttpBadRequest(message=("Basic authentication requires" 134 " password")) 135 136 user = self.user_fn(request_username) 137 if not (user and HttpServerRequestAuthentication 138 .VerifyBasicAuthPassword(request_username, 139 request_password, 140 user.password, realm)): 141 # Unknown user or password wrong 142 return None 143 144 if (not handler_access or 145 set(user.options).intersection(handler_access)): 146 # Allow access 147 return request_username 148 149 # Access forbidden 150 raise http.HttpForbidden()
151