Merge branch 'devel-2.7'
[ganeti-local] / lib / http / auth.py
index f71ede0..5dec95b 100644 (file)
@@ -27,17 +27,12 @@ import re
 import base64
 import binascii
 
-from ganeti import utils
+from ganeti import compat
 from ganeti import http
+from ganeti import utils
 
 from cStringIO import StringIO
 
-try:
-  from hashlib import md5
-except ImportError:
-  from md5 import new as md5
-
-
 # Digest types from RFC2617
 HTTP_BASIC_AUTH = "Basic"
 HTTP_DIGEST_AUTH = "Digest"
@@ -98,7 +93,7 @@ class HttpServerRequestAuthentication(object):
     """
     # today we don't have per-request filtering, but we might want to
     # add it in the future
-    # pylint: disable-msg=W0613
+    # pylint: disable=W0613
     return self.AUTH_REALM
 
   def AuthenticationRequired(self, req):
@@ -112,7 +107,7 @@ class HttpServerRequestAuthentication(object):
 
     """
     # Unused argument, method could be a function
-    # pylint: disable-msg=W0613,R0201
+    # pylint: disable=W0613,R0201
     return False
 
   def PreHandleRequest(self, req):
@@ -204,7 +199,7 @@ class HttpServerRequestAuthentication(object):
 
     """
     try:
-      creds = base64.b64decode(in_data.encode('ascii')).decode('ascii')
+      creds = base64.b64decode(in_data.encode("ascii")).decode("ascii")
     except (TypeError, binascii.Error, UnicodeError):
       logging.exception("Error when decoding Basic authentication credentials")
       return False
@@ -271,7 +266,7 @@ class HttpServerRequestAuthentication(object):
         # There can not be a valid password for this case
         raise AssertionError("No authentication realm")
 
-      expha1 = md5()
+      expha1 = compat.md5_hash()
       expha1.update("%s:%s:%s" % (username, realm, password))
 
       return (expected_password.lower() == expha1.hexdigest().lower())
@@ -292,8 +287,8 @@ class PasswordFileUser(object):
     self.options = options
 
 
-def ReadPasswordFile(file_name):
-  """Reads a password file.
+def ParsePasswordFile(contents):
+  """Parses the contents of a password file.
 
   Lines in the password file are of the following format::
 
@@ -303,24 +298,20 @@ def ReadPasswordFile(file_name):
   options are optional and separated by comma (','). Empty lines and comments
   ('#') are ignored.
 
-  @type file_name: str
-  @param file_name: Path to password file
+  @type contents: str
+  @param contents: Contents of password file
   @rtype: dict
   @return: Dictionary containing L{PasswordFileUser} instances
 
   """
   users = {}
 
-  for line in utils.ReadFile(file_name).splitlines():
-    line = line.strip()
-
-    # Ignore empty lines and comments
-    if not line or line.startswith("#"):
-      continue
-
+  for line in utils.FilterEmptyLinesAndComments(contents):
     parts = line.split(None, 2)
     if len(parts) < 2:
       # Invalid line
+      # TODO: Return line number from FilterEmptyLinesAndComments
+      logging.warning("Ignoring non-comment line with less than two fields")
       continue
 
     name = parts[0]
@@ -331,6 +322,8 @@ def ReadPasswordFile(file_name):
     if len(parts) >= 3:
       for part in parts[2].split(","):
         options.append(part.strip())
+    else:
+      logging.warning("Ignoring values for user '%s': %s", name, parts[3:])
 
     users[name] = PasswordFileUser(name, password, options)