From a1395e944e94964d4da69cd744330a099f0c6dd4 Mon Sep 17 00:00:00 2001 From: NavaL Date: Thu, 11 Feb 2016 09:43:40 +0100 Subject: adds argument to supply custom disclaimer/banner on login screen Issue #598 --- service/pixelated/application.py | 8 +++--- .../pixelated/assets/_login_disclaimer_banner.html | 9 +++++++ service/pixelated/assets/login.html | 2 +- service/pixelated/config/arguments.py | 1 + service/pixelated/resources/login_resource.py | 30 ++++++++++++++++----- service/pixelated/resources/root_resource.py | 4 +-- service/test/unit/resources/test_login_resource.py | 31 ++++++++++++++++++++++ 7 files changed, 72 insertions(+), 13 deletions(-) create mode 100644 service/pixelated/assets/_login_disclaimer_banner.html (limited to 'service') diff --git a/service/pixelated/application.py b/service/pixelated/application.py index b0f2d3fc..c7613fc6 100644 --- a/service/pixelated/application.py +++ b/service/pixelated/application.py @@ -166,24 +166,24 @@ def _start_in_multi_user_mode(args, root_resource, services_factory): events_server.ensure_server() config, provider = initialize_leap_provider(args.provider, args.leap_provider_cert, args.leap_provider_cert_fingerprint, args.leap_home) - protected_resource = set_up_protected_resources(root_resource, provider, services_factory) + protected_resource = set_up_protected_resources(root_resource, provider, services_factory, banner=args.banner) start_site(args, protected_resource) reactor.getThreadPool().adjustPoolsize(5, 15) return defer.succeed(None) -def set_up_protected_resources(root_resource, provider, services_factory, checker=None): +def set_up_protected_resources(root_resource, provider, services_factory, checker=None, banner=None): if not checker: checker = LeapPasswordChecker(provider) session_checker = SessionChecker(services_factory) - anonymous_resource = LoginResource(services_factory) + anonymous_resource = LoginResource(services_factory, disclaimer_banner=banner) realm = PixelatedRealm(root_resource, anonymous_resource) _portal = portal.Portal(realm, [checker, session_checker, AllowAnonymousAccess()]) protected_resource = PixelatedAuthSessionWrapper(_portal, root_resource, anonymous_resource, []) anonymous_resource.set_portal(_portal) - root_resource.initialize(_portal) + root_resource.initialize(_portal, disclaimer_banner=banner) return protected_resource diff --git a/service/pixelated/assets/_login_disclaimer_banner.html b/service/pixelated/assets/_login_disclaimer_banner.html new file mode 100644 index 00000000..dfc63030 --- /dev/null +++ b/service/pixelated/assets/_login_disclaimer_banner.html @@ -0,0 +1,9 @@ +
+ +
diff --git a/service/pixelated/assets/login.html b/service/pixelated/assets/login.html index d59ac4cd..a8585d05 100644 --- a/service/pixelated/assets/login.html +++ b/service/pixelated/assets/login.html @@ -28,7 +28,7 @@
- Some disclaimer +
diff --git a/service/pixelated/config/arguments.py b/service/pixelated/config/arguments.py index 6a609b73..abd5d881 100644 --- a/service/pixelated/config/arguments.py +++ b/service/pixelated/config/arguments.py @@ -30,6 +30,7 @@ def parse_user_agent_args(): parser.add_argument('-sc', '--sslcert', metavar='', default=None, help='use specified file as web server\'s SSL certificate (when using the user-agent together with the pixelated-dispatcher)') parser.add_argument('--multi-user', help='Run user agent in multi user mode', action='store_false', default=True, dest='single_user') parser.add_argument('-p', '--provider', help='specify a provider for mutli-user mode', metavar='', default=None, dest='provider') + parser.add_argument('--banner', help='banner file to show on login screen') args = parser.parse_args() diff --git a/service/pixelated/resources/login_resource.py b/service/pixelated/resources/login_resource.py index 1e1beb48..6f25fbcb 100644 --- a/service/pixelated/resources/login_resource.py +++ b/service/pixelated/resources/login_resource.py @@ -49,30 +49,48 @@ def _get_static_folder(): return static_folder +class DisclaimerElement(Element): + loader = XMLFile(FilePath(os.path.join(_get_startup_folder(), '_login_disclaimer_banner.html'))) + + def __init__(self, banner): + super(DisclaimerElement, self).__init__() + self._set_loader(banner) + + def _set_loader(self, banner): + if banner: + current_path = os.path.dirname(os.path.abspath(__file__)) + banner_file_path = os.path.join(current_path, "..", "..", "..", banner) + self.loader = XMLFile(FilePath(banner_file_path)) + + class LoginWebSite(Element): loader = XMLFile(FilePath(os.path.join(_get_startup_folder(), 'login.html'))) - def __init__(self, error_msg=None): + def __init__(self, error_msg=None, disclaimer_banner_file=None): super(LoginWebSite, self).__init__() self._error_msg = error_msg + self.disclaimer_banner_file = disclaimer_banner_file @renderer def error_msg(self, request, tag): if self._error_msg is not None: return tag(self._error_msg) - else: - return tag('') + return tag('') + + @renderer + def disclaimer(self, request, tag): + return DisclaimerElement(self.disclaimer_banner_file).render(request) class LoginResource(BaseResource): BASE_URL = 'login' - def __init__(self, services_factory, portal=None): + def __init__(self, services_factory, portal=None, disclaimer_banner=None): BaseResource.__init__(self, services_factory) self._static_folder = _get_static_folder() self._startup_folder = _get_startup_folder() - self._html_template = open(os.path.join(self._startup_folder, 'login.html')).read() self._portal = portal + self._disclaimer_banner = disclaimer_banner self.putChild('startup-assets', File(self._startup_folder)) def set_portal(self, portal): @@ -92,7 +110,7 @@ class LoginResource(BaseResource): return self._render_template(request) def _render_template(self, request, error_msg=None): - site = LoginWebSite(error_msg=error_msg) + site = LoginWebSite(error_msg=error_msg, disclaimer_banner_file=self._disclaimer_banner) return renderElement(request, site) def render_POST(self, request): diff --git a/service/pixelated/resources/root_resource.py b/service/pixelated/resources/root_resource.py index 61df0f39..6e619951 100644 --- a/service/pixelated/resources/root_resource.py +++ b/service/pixelated/resources/root_resource.py @@ -56,7 +56,7 @@ class RootResource(BaseResource): return self return Resource.getChild(self, path, request) - def initialize(self, portal=None): + def initialize(self, portal=None, disclaimer_banner=None): self.putChild('assets', File(self._static_folder)) self.putChild('keys', KeysResource(self._services_factory)) self.putChild(AttachmentsResource.BASE_URL, AttachmentsResource(self._services_factory)) @@ -67,7 +67,7 @@ class RootResource(BaseResource): self.putChild('mail', MailResource(self._services_factory)) self.putChild('feedback', FeedbackResource(self._services_factory)) self.putChild('user-settings', UserSettingsResource(self._services_factory)) - self.putChild(LoginResource.BASE_URL, LoginResource(self._services_factory, portal)) + self.putChild(LoginResource.BASE_URL, LoginResource(self._services_factory, portal, disclaimer_banner=disclaimer_banner)) self.putChild(LogoutResource.BASE_URL, LogoutResource(self._services_factory)) self._mode = MODE_RUNNING diff --git a/service/test/unit/resources/test_login_resource.py b/service/test/unit/resources/test_login_resource.py index bc238ae8..3cd9d3b2 100644 --- a/service/test/unit/resources/test_login_resource.py +++ b/service/test/unit/resources/test_login_resource.py @@ -1,3 +1,5 @@ +import os + import test.support.mockito from leap.exceptions import SRPAuthenticationError @@ -58,16 +60,45 @@ class TestLoginResource(unittest.TestCase): input_username = 'name="username"' input_password = 'name="password"' input_submit = 'name="login"' + default_disclaimer = 'Some disclaimer' written_response = ''.join(request.written) self.assertIn(form_action, written_response) self.assertIn(form_method, written_response) self.assertIn(input_password, written_response) self.assertIn(input_submit, written_response) self.assertIn(input_username, written_response) + self.assertIn(default_disclaimer, written_response) d.addCallback(assert_form_rendered) return d + def _write(self, filename, content): + with open(filename, 'w') as disclaimer_file: + disclaimer_file.write(content) + + def test_override_login_disclaimer_message(self): + request = DummyRequest(['']) + + banner_file_name = 'banner.txt' + banner_disclaimer_content = '

some custom disclaimer

' + self._write(banner_file_name, banner_disclaimer_content) + + self.resource._disclaimer_banner = 'service/_trial_temp/' + banner_file_name + + d = self.web.get(request) + + def assert_custom_disclaimer_rendered(_): + self.assertEqual(200, request.responseCode) + written_response = ''.join(request.written) + self.assertIn(banner_disclaimer_content, written_response) + + def tear_down(_): + os.remove(banner_file_name) + + d.addCallback(assert_custom_disclaimer_rendered) + d.addCallback(tear_down) + return d + class TestLoginPOST(unittest.TestCase): def setUp(self): -- cgit v1.2.3