Modify

Opened 9 years ago

Closed 8 years ago

Last modified 8 years ago

#63 closed enhancement (fixed)

support htpasswd with Windows and Python 2.3

Reported by: sid|at|seegrid.com Owned by: mgood
Priority: high Component: AccountManagerPlugin
Severity: normal Keywords:
Cc: mgood Trac Release: 0.10

Description (last modified by athomas)

Change password fails on Windows if running Python 2.3:

Traceback (most recent call last):
  File "C:\Python23\Lib\site-packages\trac\web\modpython_frontend.py", line 205, in handler
    dispatch_request(mpr.path_info, mpr, env)
  File "C:\Python23\Lib\site-packages\trac\web\main.py", line 139, in dispatch_request
    dispatcher.dispatch(req)
  File "C:\Python23\Lib\site-packages\trac\web\main.py", line 107, in dispatch
    resp = chosen_handler.process_request(req)
  File "build\bdist.win32\egg\acct_mgr\web_ui.py", line 48, in process_request
  File "build\bdist.win32\egg\acct_mgr\web_ui.py", line 64, in _do_change_password
  File "build\bdist.win32\egg\acct_mgr\htfile.py", line 49, in set_password
  File "build\bdist.win32\egg\acct_mgr\htfile.py", line 102, in userline
  File "build\bdist.win32\egg\acct_mgr\htfile.py", line 75, in salt
  File "build\bdist.win32\egg\acct_mgr\htfile.py", line 30, in urandom
IOError: [Errno 2] No such file or directory: '/dev/urandom'

I saw another site hinted at using windrandom.pyd file for Windows for Python 2.3 (although it is deprecated in 2.4 in favor of os.urandom).

Attachments (0)

Change History (13)

comment:1 Changed 9 years ago by mgood

  • Status changed from new to assigned
  • Summary changed from Change password fails on Windows with Python 2.3 to support htpasswd with Windows and Python 2.3
  • Type changed from defect to enhancement

Ok, I didn't find a reasonable way to generate cryptographically sound random data on Windows with Python 2.3, but that winrandom module may work. Can you try it with the following patch:

  • acct_mgr/htfile.py

     
    2626try: 
    2727    from os import urandom 
    2828except ImportError: 
    29     def urandom(n): 
    30         return open('/dev/urandom').read(n) 
     29    try: 
     30        from winrandom import winrandom as urandom 
     31    except ImportError: 
     32        def urandom(n): 
     33            return open('/dev/urandom').read(n) 
    3134 
    3235 
    3336class AbstractPasswordFileStore(Component): 

Also, note that htdigest does not require random data so it could be used instead of htpasswd.

comment:2 Changed 9 years ago by athomas

  • Description modified (diff)

comment:3 Changed 9 years ago by Peter Bruin

I had the same problem on Windows. In the end I got rid of the random functions and just added the htpasswd.exe to the path and use that to create a new password.
Also had the problem that when changing a password the entry appeared twice in the file. I think this is because there was no check on written=True

Index: htfile.py
===================================================================
--- htfile.py	(revision 359)
+++ htfile.py	(working copy)
@@ -21,15 +21,7 @@
 
 from api import IPasswordStore
 
-# os.urandom was added in Python 2.4
-# try to fall back on reading from /dev/urandom on older Python versions
-try:
-    from os import urandom
-except ImportError:
-    def urandom(n):
-        return open('/dev/urandom').read(n)
-
-
+    
 class AbstractPasswordFileStore(Component):
     """Base class for managing password files such as Apache's htpasswd and
     htdigest formats.
@@ -81,7 +73,7 @@
                     written = True
                 else:
                     print line,
-        if userline:
+        if userline and not written:
             f = open(filename, 'a')
             try:
                 print >>f, userline
@@ -101,6 +93,7 @@
 
 class HtPasswdStore(AbstractPasswordFileStore):
     """Manages user accounts stored in Apache's htpasswd format.
+    We actaully use the httpasswd.exe and placed it into the c:\windows dir
 
     To use this implementation add the following configuration section to trac.ini
     {{{
@@ -119,7 +112,13 @@
         return user + ':'
 
     def userline(self, user, password):
-        return self.prefix(user) + md5crypt(password, salt(), '$apr1$')
+        line = 'htpasswd -nb ' + user + ' ' + password
+        cmd = os.popen(line)
+        list = cmd.readlines()
+        result = cmd.close() # This is the return code of the program!
+        for line2 in list:
+            return line2.rstrip( "\r\n" )
 
     def _check_userline(self, password, prefix, suffix):
         if not suffix.startswith('$apr1$'):
}}}

Some more functions could be removed but this worked for me and I wanted to change as little as possible because of future merges

comment:4 Changed 9 years ago by Peter Bruin

I added this patch in my previous comment but it didn't come through:

Index: htfile.py
===================================================================
--- htfile.py	(revision 359)
+++ htfile.py	(working copy)
@@ -21,15 +21,7 @@
 
 from api import IPasswordStore
 
-# os.urandom was added in Python 2.4
-# try to fall back on reading from /dev/urandom on older Python versions
-try:
-    from os import urandom
-except ImportError:
-    def urandom(n):
-        return open('/dev/urandom').read(n)
-
-
+    
 class AbstractPasswordFileStore(Component):
     """Base class for managing password files such as Apache's htpasswd and
     htdigest formats.
@@ -81,7 +73,7 @@
                     written = True
                 else:
                     print line,
-        if userline:
+        if userline and not written:
             f = open(filename, 'a')
             try:
                 print >>f, userline
@@ -119,7 +112,13 @@
         return user + ':'
 
     def userline(self, user, password):
-        return self.prefix(user) + md5crypt(password, salt(), '$apr1$')
+        line = 'htpasswd -nb ' + user + ' ' + password
+        cmd = os.popen(line)
+        list = cmd.readlines()
+        result = cmd.close() # This is the return code of the program!
+        for line2 in list:
+            return line2.rstrip( "\r\n" )
 
     def _check_userline(self, password, prefix, suffix):
         if not suffix.startswith('$apr1$'):

comment:5 Changed 9 years ago by Gerry <ggl@…>

I tried your fix for htfile.py, since I run as well Python2.3 on Windows.
Didn't get it running. It looks like that it was trying to write to the password file, but there is no entry even though the date of the file changed.
Where did you set the path for htpasswd.exe?

comment:6 Changed 8 years ago by chogeha

  • Cc Peter Briun added
  • Priority changed from normal to high
  • Trac Release set to 0.10
  • Type changed from enhancement to defect

I tried Peter Briun patch to my trac, and it can work for python23 on window.
But there was a problem below.
When I create a new account and password in first,it can work and login success.
But when I create another new account or change the first account of password,
it will display an error.
Is this problem have any way to solve or it was improving now?
like below

Python Traceback

Traceback (most recent call last):
  File "C:\Python23\trac\web\main.py", line 299, in dispatch_request
    dispatcher.dispatch(req)
  File "C:\Python23\trac\web\main.py", line 189, in dispatch
    resp = chosen_handler.process_request(req)
  File "build\bdist.win32\egg\acct_mgr\web_ui.py", line 53, in process_request
  File "build\bdist.win32\egg\acct_mgr\web_ui.py", line 72, in _do_delete
  File "build\bdist.win32\egg\acct_mgr\api.py", line 97, in delete_user
  File "build\bdist.win32\egg\acct_mgr\htfile.py", line 47, in delete_user
  File "build\bdist.win32\egg\acct_mgr\htfile.py", line 71, in _update_file
  File "C:\Python23\Lib\fileinput.py", line 231, in next
    line = self.readline()
  File "C:\Python23\Lib\fileinput.py", line 300, in readline
    os.rename(self._filename, self._backupfilename)
OSError: [Errno 2] No such file or directory

Best Regards

comment:7 Changed 8 years ago by mike@…

  • Cc mgood added; Peter Briun removed

I'm having trouble implementing the first solution using the winrandom.py. Where do I find that file in the Python23 dist, or a download somewhere?

comment:8 Changed 8 years ago by sambloomquist

Here is an "old school" way of fixing this issue if you can't get winrandom to work, as I couldn't.

try:
    from os import urandom
except ImportError:
    import random
    def urandom(n):
        L = [chr(random.randrange(0, 256)) for i in range(n)]
        return "".join(L)

comment:9 Changed 8 years ago by Peter Bruin

I tried the old school fix but got an error that random was not found. So in the end I went back to try and fix my previous working patch. It turned out that when the main line of trac went unicode the python library caused an error as it can not handle it. So I used the fix from [705] as fixed by mgood.

Index: htfile.py
===================================================================
--- htfile.py	(revision 867)
+++ htfile.py	(working copy)
@@ -21,15 +21,7 @@
 
 from api import IPasswordStore
 
-# os.urandom was added in Python 2.4
-# try to fall back on reading from /dev/urandom on older Python versions
-try:
-    from os import urandom
-except ImportError:
-    def urandom(n):
-        return open('/dev/urandom').read(n)
-
-
+    
 class AbstractPasswordFileStore(Component):
     """Base class for managing password files such as Apache's htpasswd and
     htdigest formats.
@@ -74,14 +66,14 @@
         filename = self._get_filename()
         written = False
         if os.path.exists(filename):
-            for line in fileinput.input(filename, inplace=True):
+            for line in fileinput.input(str(filename), inplace=True):
                 if line.startswith(prefix):
                     if not written and userline:
                         print userline
                     written = True
                 else:
                     print line,
-        if userline:
+        if userline and not written:
             f = open(filename, 'a')
             try:
                 print >>f, userline
@@ -101,6 +93,7 @@
 
 class HtPasswdStore(AbstractPasswordFileStore):
     """Manages user accounts stored in Apache's htpasswd format.
+    We actaully use the httpasswd.exe and placed it into the c:\windows dir
 
     To use this implementation add the following configuration section to trac.ini
     {{{
@@ -119,7 +112,13 @@
         return user + ':'
 
     def userline(self, user, password):
-        return self.prefix(user) + md5crypt(password, salt(), '$apr1$')
+        line = 'htpasswd -nb ' + user + ' ' + password
+        cmd = os.popen(line)
+        list = cmd.readlines()
+        result = cmd.close() # This is the return code of the program!
+        for line2 in list:
+            return line2.rstrip( "\r\n" )
+        else: return 'dummy:'+line
 
     def _check_userline(self, password, prefix, suffix):
         if not suffix.startswith('$apr1$'):
}}}

Gerry asked about the path for htpasswd.exe. I blundly placed htpasswd.exe in c:\windows :)

comment:10 Changed 8 years ago by mgood

  • Type changed from defect to enhancement

Well, I don't want to make the htpasswd program a requirement for this plugin. I had also been avoiding the random module since those methods don't incorporate sufficient entropy for most cryptographic purposes. However, giving it some more thought, they should be suitable for generating the salt values since the security of the hash isn't really dependent on the salt, it just needed to prevent dictionary attacks. So, I'll incorporate something similar to the "old school" method.

comment:11 Changed 8 years ago by Gerry <ggl@…>

The "old school" method worked for me. Thanks!

comment:12 Changed 8 years ago by mgood

  • Resolution set to fixed
  • Status changed from assigned to closed

(In [1518]) provide a more cross-platform compatible fallback if os.urandom is not available (fixes #63)

comment:13 Changed 8 years ago by mgood

#793 has been marked as a duplicate.

Add Comment

Modify Ticket

Action
as closed .
The resolution will be deleted. Next status will be 'reopened'.
Author


E-mail address and user name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.