summaryrefslogtreecommitdiff
path: root/src/pixelated/resources/login_resource.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/pixelated/resources/login_resource.py')
-rw-r--r--src/pixelated/resources/login_resource.py182
1 files changed, 182 insertions, 0 deletions
diff --git a/src/pixelated/resources/login_resource.py b/src/pixelated/resources/login_resource.py
new file mode 100644
index 00000000..fd09976b
--- /dev/null
+++ b/src/pixelated/resources/login_resource.py
@@ -0,0 +1,182 @@
+#
+# Copyright (c) 2016 ThoughtWorks, Inc.
+#
+# Pixelated is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Pixelated is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
+
+import logging
+import os
+from xml.sax import SAXParseException
+
+from twisted.cred import credentials
+from twisted.internet import defer
+from twisted.python.filepath import FilePath
+from twisted.web import util
+from twisted.web.http import UNAUTHORIZED, OK
+from twisted.web.resource import IResource, NoResource
+from twisted.web.server import NOT_DONE_YET
+from twisted.web.static import File
+from twisted.web.template import Element, XMLFile, renderElement, renderer
+
+from pixelated.adapter.welcome_mail import add_welcome_mail
+from pixelated.resources import BaseResource, UnAuthorizedResource, IPixelatedSession
+
+log = logging.getLogger(__name__)
+
+
+def _get_startup_folder():
+ path = os.path.dirname(os.path.abspath(__file__))
+ return os.path.join(path, '..', 'assets')
+
+
+def _get_static_folder():
+ static_folder = os.path.abspath(os.path.join(
+ os.path.abspath(__file__), "..", "..", "..", "web-ui", "app"))
+ # this is a workaround for packaging
+ if not os.path.exists(static_folder):
+ static_folder = os.path.abspath(
+ os.path.join(os.path.abspath(__file__), "..", "..", "..", "..", "web-ui", "app"))
+ if not os.path.exists(static_folder):
+ static_folder = os.path.join(
+ '/', 'usr', 'share', 'pixelated-user-agent')
+ 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)
+ self._banner_filename = banner or "_login_disclaimer_banner.html"
+
+ 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))
+
+ def render(self, request):
+ try:
+ return super(DisclaimerElement, self).render(request)
+ except SAXParseException:
+ return ["Invalid XML template format for %s." % self._banner_filename]
+ except IOError:
+ return ["Disclaimer banner file %s could not be read or does not exit." % self._banner_filename]
+
+
+class LoginWebSite(Element):
+ loader = XMLFile(FilePath(os.path.join(
+ _get_startup_folder(), 'login.html')))
+
+ 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)
+ 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, disclaimer_banner=None):
+ BaseResource.__init__(self, services_factory)
+ self._static_folder = _get_static_folder()
+ self._startup_folder = _get_startup_folder()
+ self._portal = portal
+ self._disclaimer_banner = disclaimer_banner
+ self.putChild('startup-assets', File(self._startup_folder))
+
+ def set_portal(self, portal):
+ self._portal = portal
+
+ def getChild(self, path, request):
+ if path == '':
+ return self
+ if path == 'login':
+ return self
+ if not self.is_logged_in(request):
+ return UnAuthorizedResource()
+ return NoResource()
+
+ def render_GET(self, request):
+ request.setResponseCode(OK)
+ return self._render_template(request)
+
+ def _render_template(self, request, error_msg=None):
+ site = LoginWebSite(error_msg=error_msg,
+ disclaimer_banner_file=self._disclaimer_banner)
+ return renderElement(request, site)
+
+ def render_POST(self, request):
+ if self.is_logged_in(request):
+ return util.redirectTo("/", request)
+
+ def render_response(leap_session):
+ request.setResponseCode(OK)
+ request.write(
+ open(os.path.join(self._startup_folder, 'Interstitial.html')).read())
+ request.finish()
+ self._setup_user_services(leap_session, request)
+
+ def render_error(error):
+ log.info('Login Error for %s' % request.args['username'][0])
+ log.info('%s' % error)
+ request.setResponseCode(UNAUTHORIZED)
+ return self._render_template(request, 'Invalid credentials')
+
+ d = self._handle_login(request)
+ d.addCallbacks(render_response, render_error)
+ d.addErrback(self.generic_error_handling, request)
+
+ return NOT_DONE_YET
+
+ @defer.inlineCallbacks
+ def _handle_login(self, request):
+ self.creds = self._get_creds_from(request)
+ iface, leap_session, logout = yield self._portal.login(self.creds, None, IResource)
+ defer.returnValue(leap_session)
+
+ def _get_creds_from(self, request):
+ username = request.args['username'][0]
+ password = request.args['password'][0]
+ return credentials.UsernamePassword(username, password)
+
+ @defer.inlineCallbacks
+ def _setup_user_services(self, leap_session, request):
+ user_id = leap_session.user_auth.uuid
+ if not self._services_factory.is_logged_in(user_id):
+ yield self._services_factory.create_services_from(leap_session)
+ self._init_http_session(request, user_id)
+
+ @defer.inlineCallbacks
+ def _initialize_services(self, leap_session):
+ yield self._services_factory.create_services_from(leap_session)
+
+ if leap_session.fresh_account:
+ yield add_welcome_mail(leap_session.mail_store)
+
+ def _init_http_session(self, request, user_id):
+ session = IPixelatedSession(request.getSession())
+ session.user_uuid = user_id