More updates to authentication

This commit is contained in:
Tim Bentley 2013-03-11 21:00:00 +00:00
parent c62dab074e
commit 5c79832bcc
5 changed files with 46 additions and 86 deletions

View File

@ -36,6 +36,7 @@ from PyQt4 import QtGui
from openlp.core.lib import Registry from openlp.core.lib import Registry
class SettingsTab(QtGui.QWidget): class SettingsTab(QtGui.QWidget):
""" """
SettingsTab is a helper widget for plugins to define Tabs for the settings SettingsTab is a helper widget for plugins to define Tabs for the settings

View File

@ -860,8 +860,6 @@ class SlideController(DisplayController):
""" """
Go to the requested slide Go to the requested slide
""" """
if not self.service_item or not message[0]:
return
index = int(message[0]) index = int(message[0])
if not self.service_item: if not self.service_item:
return return

View File

@ -34,24 +34,24 @@ http://tools.cherrypy.org/wiki/AuthenticationAndAccessRestrictions
""" """
import cherrypy import cherrypy
import urlparse import logging
from openlp.core.lib import Settings
SESSION_KEY = '_cp_openlp' SESSION_KEY = '_cp_openlp'
log = logging.getLogger(__name__)
def check_credentials(user_name, password): def check_credentials(user_name, password):
""" """
Verifies credentials for username and password. Verifies credentials for username and password.
Returns None on success or a string describing the error on failure Returns None on success or a string describing the error on failure
""" """
# @todo make from config if user_name == Settings().value(u'remotes/user id') and password == Settings().value(u'remotes/password'):
print "check_credentials"
if user_name == 'openlp' and password == 'openlp':
return None return None
else: else:
return u"Incorrect username or password." return u"Incorrect username or password."
# if u.password != md5.new(password).hexdigest():
# return u"Incorrect password"
def check_auth(*args, **kwargs): def check_auth(*args, **kwargs):
@ -60,17 +60,14 @@ def check_auth(*args, **kwargs):
is not None, a login is required and the entry is evaluated as a list of is not None, a login is required and the entry is evaluated as a list of
conditions that the user must fulfill conditions that the user must fulfill
""" """
print "check_auth"
conditions = cherrypy.request.config.get('auth.require', None) conditions = cherrypy.request.config.get('auth.require', None)
print urlparse.urlparse(cherrypy.url()), conditions if not Settings().value(u'remotes/authentication enabled'):
print conditions return None
if conditions is not None: if conditions is not None:
username = cherrypy.session.get(SESSION_KEY) username = cherrypy.session.get(SESSION_KEY)
print username
if username: if username:
cherrypy.request.login = username cherrypy.request.login = username
for condition in conditions: for condition in conditions:
print "c ", condition
# A condition is just a callable that returns true or false # A condition is just a callable that returns true or false
if not condition(): if not condition():
raise cherrypy.HTTPRedirect("/auth/login") raise cherrypy.HTTPRedirect("/auth/login")
@ -97,49 +94,6 @@ def require_auth(*conditions):
return decorate return decorate
# Conditions are callables that return True
# if the user fulfills the conditions they define, False otherwise
#
# They can access the current username as cherrypy.request.login
#
# Define those at will however suits the application.
#def member_of(groupname):
# def check():
# # replace with actual check if <username> is in <groupname>
# return cherrypy.request.login == 'joe' and groupname == 'admin'
# return check
#def name_is(reqd_username):
# return lambda: reqd_username == cherrypy.request.login
#def any_of(*conditions):
# """
# Returns True if any of the conditions match
# """
# def check():
# for c in conditions:
# if c():
# return True
# return False
# return check
# By default all conditions are required, but this might still be
# needed if you want to use it inside of an any_of(...) condition
#def all_of(*conditions):
# """
# Returns True if all of the conditions match
# """
# def check():
# for c in conditions:
# if not c():
# return False
# return True
# return check
# Controller to provide login and logout actions
class AuthController(object): class AuthController(object):
def on_login(self, username): def on_login(self, username):
@ -156,14 +110,26 @@ class AuthController(object):
""" """
Provides a login form Provides a login form
""" """
return """<html><body> return """<html>
<form method="post" action="/auth/login"> <head>
<input type="hidden" name="from_page" value="%(from_page)s" /> <meta charset="utf-8" />
%(msg)s<br /> <meta name="viewport" content="width=device-width, minimum-scale=1, maximum-scale=1" />
Username: <input type="text" name="username" value="%(username)s" /><br /> <title>User Login</title>
Password: <input type="password" name="password" /><br /> <link rel="stylesheet" href="/files/jquery.mobile.css" />
<input type="submit" value="Log in" /> <link rel="stylesheet" href="/files/openlp.css" />
</body></html>""" % locals() <link rel="shortcut icon" type="image/x-icon" href="/files/images/favicon.ico">
<script type="text/javascript" src="/files/jquery.js"></script>
<script type="text/javascript" src="/files/openlp.js"></script>
<script type="text/javascript" src="/files/jquery.mobile.js"></script>
</head>
<body>
<form method="post" action="/auth/login">
<input type="hidden" name="from_page" value="%(from_page)s" />
%(msg)s<br/>
Username: <input type="text" name="username" value="%(username)s" /><br />
Password: <input type="password" name="password" /><br />
<input type="submit" value="Log in" />
</body></html>""" % locals()
@cherrypy.expose @cherrypy.expose
def login(self, username=None, password=None, from_page="/"): def login(self, username=None, password=None, from_page="/"):

View File

@ -130,6 +130,7 @@ from openlp.plugins.remotes.lib.httpauth import AuthController, require_auth
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class HttpServer(object): class HttpServer(object):
""" """
Ability to control OpenLP via a web browser. Ability to control OpenLP via a web browser.
@ -156,10 +157,19 @@ class HttpServer(object):
clients. Listen out for socket connections. clients. Listen out for socket connections.
""" """
log.debug(u'Start CherryPy server') log.debug(u'Start CherryPy server')
port = Settings().value(self.plugin.settingsSection + u'/port') if Settings().value(self.plugin.settingsSection + u'/https enabled'):
address = Settings().value(self.plugin.settingsSection + u'/ip address') port = Settings().value(self.plugin.settingsSection + u'/https port')
server_config = {u'server.socket_host': str(address), address = Settings().value(self.plugin.settingsSection + u'/ip address')
u'server.socket_port': port} shared_data = AppLocation.get_directory(AppLocation.SharedData)
server_config = {u'server.socket_host': str(address),
u'server.socket_port': port,
u'server.ssl_certificate': os.path.join(shared_data, u'openlp.crt'),
u'server.ssl_private_key': os.path.join(shared_data, u'openlp.key')}
else:
port = Settings().value(self.plugin.settingsSection + u'/port')
address = Settings().value(self.plugin.settingsSection + u'/ip address')
server_config = {u'server.socket_host': str(address),
u'server.socket_port': port}
cherrypy.config.update(server_config) cherrypy.config.update(server_config)
cherrypy.config.update({'environment': 'embedded'}) cherrypy.config.update({'environment': 'embedded'})
cherrypy.config.update({'engine.autoreload_on': False}) cherrypy.config.update({'engine.autoreload_on': False})
@ -231,10 +241,8 @@ class HttpConnection(object):
""" """
Handles the requests for the main url. This is secure depending on settings in config. Handles the requests for the main url. This is secure depending on settings in config.
""" """
print "default"
url = urlparse.urlparse(cherrypy.url()) url = urlparse.urlparse(cherrypy.url())
self.url_params = urlparse.parse_qs(url.query) self.url_params = urlparse.parse_qs(url.query)
print url
# Loop through the routes we set up earlier and execute them # Loop through the routes we set up earlier and execute them
return self._process_http_request(args, kwargs) return self._process_http_request(args, kwargs)
@ -243,10 +251,8 @@ class HttpConnection(object):
""" """
Handles the requests for the stage url. This is not secure. Handles the requests for the stage url. This is not secure.
""" """
print "Stage"
url = urlparse.urlparse(cherrypy.url()) url = urlparse.urlparse(cherrypy.url())
self.url_params = urlparse.parse_qs(url.query) self.url_params = urlparse.parse_qs(url.query)
print url
return self._process_http_request(args, kwargs) return self._process_http_request(args, kwargs)
@cherrypy.expose @cherrypy.expose
@ -254,24 +260,20 @@ class HttpConnection(object):
""" """
Handles the requests for the files url. This is not secure. Handles the requests for the files url. This is not secure.
""" """
print "files"
url = urlparse.urlparse(cherrypy.url()) url = urlparse.urlparse(cherrypy.url())
self.url_params = urlparse.parse_qs(url.query) self.url_params = urlparse.parse_qs(url.query)
print url
return self._process_http_request(args, kwargs) return self._process_http_request(args, kwargs)
def _process_http_request(self, args, kwargs): def _process_http_request(self, args, kwargs):
""" """
Common function to process HTTP requests where secure or insecure Common function to process HTTP requests where secure or insecure
""" """
print "common handler"
url = urlparse.urlparse(cherrypy.url()) url = urlparse.urlparse(cherrypy.url())
self.url_params = urlparse.parse_qs(url.query) self.url_params = urlparse.parse_qs(url.query)
response = None response = None
for route, func in self.routes: for route, func in self.routes:
match = re.match(route, url.path) match = re.match(route, url.path)
if match: if match:
print 'Route "%s" matched "%s"', route, url.path, func
log.debug('Route "%s" matched "%s"', route, url.path) log.debug('Route "%s" matched "%s"', route, url.path)
args = [] args = []
for param in match.groups(): for param in match.groups():
@ -474,11 +476,8 @@ class HttpConnection(object):
# This slot expects an int within a list. # This slot expects an int within a list.
id = data[u'request'][u'id'] id = data[u'request'][u'id']
Registry().execute(event, [id]) Registry().execute(event, [id])
else:
Registry().execute(event, [0])
json_data = {u'results': {u'success': True}} json_data = {u'results': {u'success': True}}
cherrypy.response.headers['Content-Type'] = u'application/json' cherrypy.response.headers['Content-Type'] = u'application/json'
print json.dumps(json_data)
return json.dumps(json_data) return json.dumps(json_data)
def service(self, action): def service(self, action):
@ -545,7 +544,6 @@ class HttpConnection(object):
""" """
Go live on an item of type ``plugin``. Go live on an item of type ``plugin``.
""" """
print "go_live"
try: try:
id = json.loads(self.url_params[u'data'][0])[u'request'][u'id'] id = json.loads(self.url_params[u'data'][0])[u'request'][u'id']
except KeyError, ValueError: except KeyError, ValueError:
@ -577,7 +575,7 @@ class HttpConnection(object):
def _http_not_found(self): def _http_not_found(self):
cherrypy.response.status = 404 cherrypy.response.status = 404
cherrypy.response.body = ["<html><body>Sorry, an error occured</body></html>"] cherrypy.response.body = ["<html><body>Sorry, an error occurred </body></html>"]
def _get_service_manager(self): def _get_service_manager(self):
""" """

View File

@ -56,15 +56,13 @@ class RemoteTab(SettingsTab):
self.address_label.setObjectName(u'address_label') self.address_label.setObjectName(u'address_label')
self.address_edit = QtGui.QLineEdit(self.server_settings_group_box) self.address_edit = QtGui.QLineEdit(self.server_settings_group_box)
self.address_edit.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Fixed) self.address_edit.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Fixed)
self.address_edit.setValidator(QtGui.QRegExpValidator(QtCore.QRegExp(u'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}'),
self.address_edit.setValidator(QtGui.QRegExpValidator(QtCore.QRegExp(u'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}'),
self)) self))
self.address_edit.setObjectName(u'address_edit') self.address_edit.setObjectName(u'address_edit')
self.server_settings_layout.addRow(self.address_label, self.address_edit) self.server_settings_layout.addRow(self.address_label, self.address_edit)
self.twelve_hour_check_box = QtGui.QCheckBox(self.server_settings_group_box) self.twelve_hour_check_box = QtGui.QCheckBox(self.server_settings_group_box)
self.twelve_hour_check_box.setObjectName(u'twelve_hour_check_box') self.twelve_hour_check_box.setObjectName(u'twelve_hour_check_box')
self.server_settings_layout.addRow(self.twelve_hour_check_box) self.server_settings_layout.addRow(self.twelve_hour_check_box)
self.leftLayout.addWidget(self.server_settings_group_box) self.leftLayout.addWidget(self.server_settings_group_box)
self.http_settings_group_box = QtGui.QGroupBox(self.leftColumn) self.http_settings_group_box = QtGui.QGroupBox(self.leftColumn)
self.http_settings_group_box.setObjectName(u'http_settings_group_box') self.http_settings_group_box.setObjectName(u'http_settings_group_box')
@ -75,7 +73,6 @@ class RemoteTab(SettingsTab):
self.port_spin_box = QtGui.QSpinBox(self.http_settings_group_box) self.port_spin_box = QtGui.QSpinBox(self.http_settings_group_box)
self.port_spin_box.setMaximum(32767) self.port_spin_box.setMaximum(32767)
self.port_spin_box.setObjectName(u'port_spin_box') self.port_spin_box.setObjectName(u'port_spin_box')
self.http_setting_layout.addRow(self.port_label, self.port_spin_box) self.http_setting_layout.addRow(self.port_label, self.port_spin_box)
self.remote_url_label = QtGui.QLabel(self.http_settings_group_box) self.remote_url_label = QtGui.QLabel(self.http_settings_group_box)
self.remote_url_label.setObjectName(u'remote_url_label') self.remote_url_label.setObjectName(u'remote_url_label')
@ -244,7 +241,7 @@ class RemoteTab(SettingsTab):
Settings().setValue(self.settingsSection + u'/user id', self.user_id.text()) Settings().setValue(self.settingsSection + u'/user id', self.user_id.text())
Settings().setValue(self.settingsSection + u'/password', self.password.text()) Settings().setValue(self.settingsSection + u'/password', self.password.text())
if changed: if changed:
Registry().register_function(u'remotes_config_updated') Registry().execute(u'remotes_config_updated')
def on_twelve_hour_check_box_changed(self, check_state): def on_twelve_hour_check_box_changed(self, check_state):