Revision abe318b3
b/lib/server/rapi.py | ||
---|---|---|
71 | 71 |
""" |
72 | 72 |
AUTH_REALM = "Ganeti Remote API" |
73 | 73 |
|
74 |
def __init__(self, _client_cls=None): |
|
74 |
def __init__(self, user_fn, _client_cls=None): |
|
75 |
"""Initializes this class. |
|
76 |
|
|
77 |
@type user_fn: callable |
|
78 |
@param user_fn: Function receiving username as string and returning |
|
79 |
L{http.auth.PasswordFileUser} or C{None} if user is not found |
|
80 |
|
|
81 |
""" |
|
75 | 82 |
# pylint: disable=W0233 |
76 | 83 |
# it seems pylint doesn't see the second parent class there |
77 | 84 |
http.server.HttpServerHandler.__init__(self) |
78 | 85 |
http.auth.HttpServerRequestAuthentication.__init__(self) |
79 | 86 |
self._client_cls = _client_cls |
80 | 87 |
self._resmap = connector.Mapper() |
81 |
self._users = None |
|
82 |
|
|
83 |
def LoadUsers(self, filename): |
|
84 |
"""Loads a file containing users and passwords. |
|
85 |
|
|
86 |
@type filename: string |
|
87 |
@param filename: Path to file |
|
88 |
|
|
89 |
""" |
|
90 |
logging.info("Reading users file at %s", filename) |
|
91 |
try: |
|
92 |
try: |
|
93 |
contents = utils.ReadFile(filename) |
|
94 |
except EnvironmentError, err: |
|
95 |
self._users = None |
|
96 |
if err.errno == errno.ENOENT: |
|
97 |
logging.warning("No users file at %s", filename) |
|
98 |
else: |
|
99 |
logging.warning("Error while reading %s: %s", filename, err) |
|
100 |
return False |
|
101 |
|
|
102 |
users = http.auth.ParsePasswordFile(contents) |
|
103 |
|
|
104 |
except Exception, err: # pylint: disable=W0703 |
|
105 |
# We don't care about the type of exception |
|
106 |
logging.error("Error while parsing %s: %s", filename, err) |
|
107 |
return False |
|
108 |
|
|
109 |
self._users = users |
|
110 |
|
|
111 |
return True |
|
88 |
self._user_fn = user_fn |
|
112 | 89 |
|
113 | 90 |
@staticmethod |
114 | 91 |
def FormatErrorMessage(values): |
... | ... | |
172 | 149 |
""" |
173 | 150 |
ctx = self._GetRequestContext(req) |
174 | 151 |
|
175 |
# Check username and password |
|
176 |
valid_user = False |
|
177 |
if self._users: |
|
178 |
user = self._users.get(username, None) |
|
179 |
if user and self.VerifyBasicAuthPassword(req, username, password, |
|
180 |
user.password): |
|
181 |
valid_user = True |
|
182 |
|
|
183 |
if not valid_user: |
|
152 |
user = self._user_fn(username) |
|
153 |
if not (user and |
|
154 |
self.VerifyBasicAuthPassword(req, username, password, |
|
155 |
user.password)): |
|
184 | 156 |
# Unknown user or password wrong |
185 | 157 |
return False |
186 | 158 |
|
... | ... | |
232 | 204 |
return serializer.DumpJson(result) |
233 | 205 |
|
234 | 206 |
|
207 |
class RapiUsers: |
|
208 |
def __init__(self): |
|
209 |
"""Initializes this class. |
|
210 |
|
|
211 |
""" |
|
212 |
self._users = None |
|
213 |
|
|
214 |
def Get(self, username): |
|
215 |
"""Checks whether a user exists. |
|
216 |
|
|
217 |
""" |
|
218 |
if self._users: |
|
219 |
return self._users.get(username, None) |
|
220 |
else: |
|
221 |
return None |
|
222 |
|
|
223 |
def Load(self, filename): |
|
224 |
"""Loads a file containing users and passwords. |
|
225 |
|
|
226 |
@type filename: string |
|
227 |
@param filename: Path to file |
|
228 |
|
|
229 |
""" |
|
230 |
logging.info("Reading users file at %s", filename) |
|
231 |
try: |
|
232 |
try: |
|
233 |
contents = utils.ReadFile(filename) |
|
234 |
except EnvironmentError, err: |
|
235 |
self._users = None |
|
236 |
if err.errno == errno.ENOENT: |
|
237 |
logging.warning("No users file at %s", filename) |
|
238 |
else: |
|
239 |
logging.warning("Error while reading %s: %s", filename, err) |
|
240 |
return False |
|
241 |
|
|
242 |
users = http.auth.ParsePasswordFile(contents) |
|
243 |
|
|
244 |
except Exception, err: # pylint: disable=W0703 |
|
245 |
# We don't care about the type of exception |
|
246 |
logging.error("Error while parsing %s: %s", filename, err) |
|
247 |
return False |
|
248 |
|
|
249 |
self._users = users |
|
250 |
|
|
251 |
return True |
|
252 |
|
|
253 |
|
|
235 | 254 |
class FileEventHandler(asyncnotifier.FileEventHandlerBase): |
236 | 255 |
def __init__(self, wm, path, cb): |
237 | 256 |
"""Initializes this class. |
... | ... | |
304 | 323 |
|
305 | 324 |
""" |
306 | 325 |
mainloop = daemon.Mainloop() |
307 |
handler = RemoteApiHandler() |
|
326 |
|
|
327 |
users = RapiUsers() |
|
328 |
|
|
329 |
handler = RemoteApiHandler(users.Get) |
|
308 | 330 |
|
309 | 331 |
# Setup file watcher (it'll be driven by asyncore) |
310 | 332 |
SetupFileWatcher(constants.RAPI_USERS_FILE, |
311 |
compat.partial(handler.LoadUsers, constants.RAPI_USERS_FILE))
|
|
333 |
compat.partial(users.Load, constants.RAPI_USERS_FILE))
|
|
312 | 334 |
|
313 |
handler.LoadUsers(constants.RAPI_USERS_FILE)
|
|
335 |
users.Load(constants.RAPI_USERS_FILE)
|
|
314 | 336 |
|
315 | 337 |
server = \ |
316 | 338 |
http.server.HttpServer(mainloop, options.bind_address, options.port, |
Also available in: Unified diff