Changeset - 9a02f9ef28d7
[Not reviewed]
stable
0 7 0
Mads Kiilerich (kiilerix) - 10 years ago 2015-07-07 00:09:35
mads@kiilerich.com
utils: make API key generator more random

The API key generator abused temporary filenames in what seems to be an attempt
of creating keys that unambiguously specified the user and thus were unique
across users. A final hashing did however remove that property.

More importantly, tempfile is not documented to use secure random numbers ...
and it only uses 6 characters, giving approximately 36 bits of entropy.

Instead, use the cryptographically secure os.urandom directly to generate keys
with the same length but with the full 160 bits of entropy.

Reported and fixed by Andrew Bartlett.
7 files changed with 13 insertions and 23 deletions:
0 comments (0 inline, 0 general) First comment
kallithea/controllers/admin/my_account.py
Show inline comments
 
@@ -260,7 +260,7 @@ class MyAccountController(BaseController
 
        if request.POST.get('del_api_key_builtin'):
 
            user = User.get(user_id)
 
            if user:
 
                user.api_key = generate_api_key(user.username)
 
                user.api_key = generate_api_key()
 
                Session().add(user)
 
                Session().commit()
 
                h.flash(_("Api key successfully reset"), category='success')
kallithea/controllers/admin/users.py
Show inline comments
 
@@ -324,7 +324,7 @@ class UsersController(BaseController):
 
        if request.POST.get('del_api_key_builtin'):
 
            user = User.get(c.user.user_id)
 
            if user:
 
                user.api_key = generate_api_key(user.username)
 
                user.api_key = generate_api_key()
 
                Session().add(user)
 
                Session().commit()
 
                h.flash(_("Api key successfully reset"), category='success')
kallithea/lib/dbmigrate/schema/db_1_2_0.py
Show inline comments
 
@@ -336,7 +336,7 @@ class User(Base, BaseModel):
 
                    v = get_crypt_password(v)
 
                setattr(new_user, k, v)
 

	
 
            new_user.api_key = generate_api_key(form_data['username'])
 
            new_user.api_key = generate_api_key()
 
            Session.add(new_user)
 
            Session.commit()
 
            return new_user
kallithea/lib/utils2.py
Show inline comments
 
@@ -32,8 +32,10 @@ import sys
 
import time
 
import uuid
 
import datetime
 
import urllib
 
import binascii
 

	
 
import webob
 
import urllib
 
import urlobject
 

	
 
from pylons.i18n.translation import _, ungettext
 
@@ -161,23 +163,11 @@ def detect_mode(line, default):
 
        return default
 

	
 

	
 
def generate_api_key(username, salt=None):
 
def generate_api_key():
 
    """
 
    Generates unique API key for given username, if salt is not given
 
    it'll be generated from some random string
 

	
 
    :param username: username as string
 
    :param salt: salt to hash generate KEY
 
    :rtype: str
 
    :returns: sha1 hash from username+salt
 
    Generates a random (presumably unique) API key.
 
    """
 
    from tempfile import _RandomNameSequence
 
    import hashlib
 

	
 
    if salt is None:
 
        salt = _RandomNameSequence().next()
 

	
 
    return hashlib.sha1(username + salt).hexdigest()
 
    return binascii.hexlify(os.urandom(20))
 

	
 

	
 
def safe_int(val, default=None):
kallithea/model/api_key.py
Show inline comments
 
@@ -50,7 +50,7 @@ class ApiKeyModel(BaseModel):
 
        user = self._get_user(user)
 

	
 
        new_api_key = UserApiKeys()
 
        new_api_key.api_key = generate_api_key(user.username)
 
        new_api_key.api_key = generate_api_key()
 
        new_api_key.user_id = user.user_id
 
        new_api_key.description = description
 
        new_api_key.expires = time.time() + (lifetime * 60) if lifetime != -1 else -1
kallithea/model/user.py
Show inline comments
 
@@ -100,7 +100,7 @@ class UserModel(BaseModel):
 
                k = 'name'
 
            setattr(new_user, k, v)
 

	
 
        new_user.api_key = generate_api_key(form_data['username'])
 
        new_user.api_key = generate_api_key()
 
        self.sa.add(new_user)
 

	
 
        log_create_user(new_user.get_dict(), cur_user)
 
@@ -159,7 +159,7 @@ class UserModel(BaseModel):
 
            new_user.lastname = lastname
 

	
 
            if not edit:
 
                new_user.api_key = generate_api_key(username)
 
                new_user.api_key = generate_api_key()
 

	
 
            # set password only if creating an user or password is changed
 
            password_change = new_user.password and not check_password(password,
kallithea/tests/functional/test_login.py
Show inline comments
 
@@ -260,7 +260,7 @@ class TestLoginController(TestController
 
        new.email = email
 
        new.name = name
 
        new.lastname = lastname
 
        new.api_key = generate_api_key(username)
 
        new.api_key = generate_api_key()
 
        Session().add(new)
 
        Session().commit()
 

	
0 comments (0 inline, 0 general) First comment
You need to be logged in to comment. Login now