Modify

Opened 18 years ago

Closed 17 years ago

Last modified 17 years ago

#63 closed enhancement (fixed)

support htpasswd with Windows and Python 2.3

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

Description (last modified by Alec Thomas)

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 18 years ago by Matt Good

Status: newassigned
Summary: Change password fails on Windows with Python 2.3support htpasswd with Windows and Python 2.3
Type: defectenhancement

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 18 years ago by Alec Thomas

Description: modified (diff)

comment:3 Changed 18 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 18 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 18 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 18 years ago by chogeha

Cc: Peter Briun added; anonymous removed
Priority: normalhigh
Trac Release: 0.10
Type: enhancementdefect

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 18 years ago by Mike

Cc: Matt Good 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 18 years ago by Sam Bloomquist

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 18 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 18 years ago by Matt Good

Type: defectenhancement

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 18 years ago by Gerry <ggl@…>

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

comment:12 Changed 17 years ago by Matt Good

Resolution: fixed
Status: assignedclosed

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

comment:13 Changed 17 years ago by Matt Good

#793 has been marked as a duplicate.

Modify Ticket

Change Properties
Set your email in Preferences
Action
as closed The owner will remain Matt Good.
The resolution will be deleted. Next status will be 'reopened'.

Add Comment


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

 
Note: See TracTickets for help on using tickets.