big change to the webui auth system

added converting of old 1.1 config files
added converting of old md5 passwords to sha1
This commit is contained in:
Damien Churchill 2009-05-07 16:27:22 +00:00
parent 2766c103e2
commit af4c73a594
5 changed files with 171 additions and 62 deletions

View File

@ -28,3 +28,122 @@ AUTH_LEVEL_NORMAL = 5
AUTH_LEVEL_ADMIN = 10 AUTH_LEVEL_ADMIN = 10
AUTH_LEVEL_DEFAULT = AUTH_LEVEL_NORMAL AUTH_LEVEL_DEFAULT = AUTH_LEVEL_NORMAL
import time
import random
import hashlib
import logging
from twisted.internet.defer import Deferred
from deluge import component
from deluge.ui.web.json_api import JSONComponent, export
log = logging.getLogger(__name__)
class Auth(JSONComponent):
def __init__(self):
super(Auth, self).__init__("Auth")
def _create_session(self, login='admin'):
m = hashlib.md5()
m.update(login)
m.update(str(time.time()))
m.update(str(random.getrandbits(40)))
m.update(m.hexdigest())
session_id = m.hexdigest()
log.debug("Creating session for %s", login)
config = component.get("DelugeWeb").config
if type(config["sessions"]) is list:
config.config["sessions"] = {}
config["sessions"][session_id] = {
"login": login
}
return session_id
@export
def change_password(self, new_password):
salt = hashlib.sha1(str(random.getrandbits(40))).hexdigest()
s = hashlib.sha1(salt)
s.update(new_password)
config = component.get("DelugeWeb").config
config["pwd_salt"] = salt
config["pwd_sha1"] = s.hexdigest()
log.debug("Changing password")
@export
def check_session(self, session_id):
d = Deferred()
config = component.get("DelugeWeb").config
d.callback(session_id in config["sessions"])
return d
@export
def delete_session(self, session_id):
d = Deferred()
config = component.get("DelugeWeb").config
del config["sessions"][session_id]
d.callback(True)
return d
@export
def login(self, password):
"""Method to allow the webui to authenticate
"""
config = component.get("DelugeWeb").config
d = Deferred()
if "old_pwd_md5" in config.config:
# We are using the 1.1 webui auth method
log.debug("Received a login via the 1.1 auth method")
from base64 import decodestring
m = hashlib.md5()
m.update(decodestring(config["old_pwd_salt"]))
m.update(password)
if m.digest() == decodestring(config["old_pwd_md5"]):
# We have a match, so we can create and return a session id.
d.callback(self._create_session())
# We also want to move the password over to sha1 and remove
# the old passwords from the config file.
self.change_password(password)
del config.config["old_pwd_salt"]
del config.config["old_pwd_md5"]
elif "pwd_md5" in config.config:
# We are using the 1.2-dev auth method
log.debug("Received a login via the 1.2-dev auth method")
m = hashlib.md5()
m.update(config["pwd_salt"])
m.update(password)
if m.hexdigest() == config['pwd_md5']:
# We have a match, so we can create and return a session id.
d.callback(self._create_session())
# We also want to move the password over to sha1 and remove
# the old passwords from the config file.
self.change_password(password)
del config.config["pwd_md5"]
del config.config["pwd_salt"]
elif "pwd_sha1" in config.config:
# We are using the 1.2 auth method
log.debug("Received a login via the 1.2 auth method")
s = hashlib.sha1()
s.update(config["pwd_salt"])
s.update(password)
if s.hexdigest() == config["pwd_sha1"]:
# We have a match, so we can create and return a session id.
d.callback(self._create_session())
else:
# Can't detect which method we should be using so just deny
# access.
log.debug("Failed to detect the login method")
d.callback(False)
return d

View File

@ -84,7 +84,7 @@ Copyright:
onLogin: function() { onLogin: function() {
var passwordField = this.loginForm.items.get('password'); var passwordField = this.loginForm.items.get('password');
Deluge.Client.web.login(passwordField.getValue(), { Deluge.Client.auth.login(passwordField.getValue(), {
success: function(result) { success: function(result) {
if (result) { if (result) {
Deluge.Events.fire('login'); Deluge.Events.fire('login');
@ -112,7 +112,7 @@ Copyright:
onLogout: function() { onLogout: function() {
var session = Deluge.UI.cookies.get("session", false); var session = Deluge.UI.cookies.get("session", false);
if (session) { if (session) {
Deluge.Client.web.delete_session(session, { Deluge.Client.auth.delete_session(session, {
success: function(result) { success: function(result) {
Deluge.UI.cookies.clear("session"); Deluge.UI.cookies.clear("session");
this.show(); this.show();
@ -125,7 +125,7 @@ Copyright:
onBeforeShow: function() { onBeforeShow: function() {
var session = Deluge.UI.cookies.get("session", false); var session = Deluge.UI.cookies.get("session", false);
if (session) { if (session) {
Deluge.Client.web.check_session(session, { Deluge.Client.auth.check_session(session, {
success: function(result) { success: function(result) {
if (result) { if (result) {
Deluge.Events.fire('login'); Deluge.Events.fire('login');

File diff suppressed because one or more lines are too long

View File

@ -25,10 +25,9 @@
import os import os
import time import time
import base64 import base64
import random
import urllib import urllib
import hashlib
import logging import logging
import hashlib
import tempfile import tempfile
from types import FunctionType from types import FunctionType
@ -39,12 +38,20 @@ from deluge import common, component
from deluge.configmanager import ConfigManager from deluge.configmanager import ConfigManager
from deluge.ui import common as uicommon from deluge.ui import common as uicommon
from deluge.ui.client import client, Client from deluge.ui.client import client, Client
from deluge.ui.web.auth import *
from deluge.ui.web.common import _ from deluge.ui.web.common import _
json = common.json json = common.json
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
AUTH_LEVEL_DEFAULT = None
class JSONComponent(component.Component):
def __init__(self, name, interval=1, depend=None):
super(JSONComponent, self).__init__(name, interval, depend)
self._json = component.get("JSON")
self._json.register_object(self, name)
def export(auth_level=AUTH_LEVEL_DEFAULT): def export(auth_level=AUTH_LEVEL_DEFAULT):
""" """
Decorator function to register an object's method as an RPC. The object Decorator function to register an object's method as an RPC. The object
@ -54,6 +61,10 @@ def export(auth_level=AUTH_LEVEL_DEFAULT):
:param auth_level: int, the auth level required to call this method :param auth_level: int, the auth level required to call this method
""" """
global AUTH_LEVEL_DEFAULT
if AUTH_LEVEL_DEFAULT is None:
from deluge.ui.web.auth import AUTH_LEVEL_DEFAULT
def wrap(func, *args, **kwargs): def wrap(func, *args, **kwargs):
func._json_export = True func._json_export = True
func._json_auth_level = auth_level func._json_auth_level = auth_level
@ -245,13 +256,6 @@ class JSON(resource.Resource, component.Component):
log.debug("Registering method: %s", name + "." + d) log.debug("Registering method: %s", name + "." + d)
self._local_methods[name + "." + d] = getattr(obj, d) self._local_methods[name + "." + d] = getattr(obj, d)
class JSONComponent(component.Component):
def __init__(self, name, interval=1, depend=None):
super(JSONComponent, self).__init__(name, interval, depend)
self._json = component.get("JSON")
self._json.register_object(self, name)
DEFAULT_HOST = "127.0.0.1" DEFAULT_HOST = "127.0.0.1"
DEFAULT_PORT = 58846 DEFAULT_PORT = 58846
@ -435,51 +439,6 @@ class WebApi(JSONComponent):
d.callback(True) d.callback(True)
return d return d
def _create_session(self, login='admin'):
m = hashlib.md5()
m.update(login)
m.update(str(time.time()))
m.update(str(random.getrandbits(999)))
m.update(m.hexdigest())
session_id = m.hexdigest()
config = component.get("DelugeWeb").config
config["sessions"][session_id] = {
"login": login
}
return session_id
@export
def check_session(self, session_id):
d = Deferred()
config = component.get("DelugeWeb").config
d.callback(session_id in config["sessions"])
return d
@export
def delete_session(self, session_id):
d = Deferred()
config = component.get("DelugeWeb").config
del config["sessions"][session_id]
d.callback(True)
return d
@export
def login(self, password):
"""Method to allow the webui to authenticate
"""
config = component.get("DelugeWeb").config
m = hashlib.md5()
m.update(config['pwd_salt'])
m.update(password)
d = Deferred()
if m.hexdigest() == config['pwd_md5']:
# Change this to return a session id
d.callback(self._create_session())
else:
d.callback(False)
return d
@export @export
def get_hosts(self): def get_hosts(self):
"""Return the hosts in the hostlist""" """Return the hosts in the hostlist"""

View File

@ -43,6 +43,7 @@ from deluge.configmanager import ConfigManager
from deluge.log import setupLogger, LOG as _log from deluge.log import setupLogger, LOG as _log
from deluge.ui import common as uicommon from deluge.ui import common as uicommon
from deluge.ui.tracker_icons import TrackerIcons from deluge.ui.tracker_icons import TrackerIcons
from deluge.ui.web.auth import Auth
from deluge.ui.web.common import Template from deluge.ui.web.common import Template
from deluge.ui.web.json_api import JSON, WebApi from deluge.ui.web.json_api import JSON, WebApi
from deluge.ui.web.pluginmanager import PluginManager from deluge.ui.web.pluginmanager import PluginManager
@ -69,17 +70,24 @@ CONFIG_DEFAULTS = {
"port": 8112, "port": 8112,
"enabled_plugins": [], "enabled_plugins": [],
"theme": "slate", "theme": "slate",
"pwd_salt": "16f65d5c79b7e93278a28b60fed2431e", "pwd_salt": "c26ab3bbd8b137f99cd83c2c1c0963bcc1a35cad",
"pwd_md5": "2c9baa929ca38fb5c9eb5b054474d1ce", "pwd_sha1": "2ce1a410bcdcc53064129b6d950f2e9fee4edc1e",
"base": "", "base": "",
"sessions": {}, "sessions": {},
"sidebar_show_zero": False, "sidebar_show_zero": False,
"sidebar_show_trackers": False, "sidebar_show_trackers": False,
"show_keyword_search": False, "show_keyword_search": False,
"show_sidebar": True, "show_sidebar": True,
"cache_templates": False,
"https": False "https": False
} }
OLD_CONFIG_KEYS = (
"port", "enabled_plugins", "base", "sidebar_show_zero",
"sidebar_show_trackers", "show_keyword_search", "show_sidebar",
"cache_templates", "https"
)
def rpath(path): def rpath(path):
"""Convert a relative path into an absolute path relative to the location """Convert a relative path into an absolute path relative to the location
of this script. of this script.
@ -341,10 +349,33 @@ class DelugeWeb(component.Component):
super(DelugeWeb, self).__init__("DelugeWeb") super(DelugeWeb, self).__init__("DelugeWeb")
self.config = ConfigManager("web.conf", CONFIG_DEFAULTS) self.config = ConfigManager("web.conf", CONFIG_DEFAULTS)
old_config = ConfigManager("webui06.conf")
if old_config.config:
# we have an old config file here to handle so we should move
# all the values across to the new config file, and then remove
# it.
for key in OLD_CONFIG_KEYS:
self.config[key] = old_config[key]
# We need to base64 encode the passwords since utf-8 can't handle
# them otherwise.
from base64 import encodestring
self.config["old_pwd_md5"] = encodestring(old_config["pwd_md5"])
self.config["old_pwd_salt"] = encodestring(old_config["pwd_salt"])
# Save our config and if it saved successfully then rename the
# old configuration file.
if self.config.save():
config_dir = os.path.dirname(old_config.config_file)
backup_path = os.path.join(config_dir, 'web.conf.old')
os.rename(old_config.config_file, backup_path)
del old_config
self.top_level = TopLevel() self.top_level = TopLevel()
self.site = server.Site(self.top_level) self.site = server.Site(self.top_level)
self.port = self.config["port"] self.port = self.config["port"]
self.web_api = WebApi() self.web_api = WebApi()
self.auth = Auth()
# Since twisted assigns itself all the signals may as well make # Since twisted assigns itself all the signals may as well make
# use of it. # use of it.