pvl/login/server.py
changeset 351 147f5e86b139
parent 350 1ca04394c314
child 354 d46c8d3e3140
--- a/pvl/login/server.py	Mon Jan 13 02:46:18 2014 +0200
+++ b/pvl/login/server.py	Mon Jan 13 03:20:04 2014 +0200
@@ -28,6 +28,10 @@
     def redirect (self, *url, **params) :
         return pvl.web.response.redirect(self.url(*url, **params))
 
+    pubtkt = None
+    cookie_error = None
+    verify_error = None
+
     def process_cookie (self) :
         """
             Reverse the urlencoding used for the cookie...
@@ -37,27 +41,34 @@
 
         cookie = self.request.cookies.get(self.app.cookie_name)
         
+        if not cookie :
+            return
+
         log.debug("cookie %s=%s", self.app.cookie_name, cookie)
 
-        if cookie :
-            cookie = werkzeug.urls.url_unquote(cookie)
+        cookie = werkzeug.urls.url_unquote(cookie)
         
         log.debug("cookie decoded: %s", cookie)
         
-        if cookie :
-            return self.app.load(cookie)
+        if not cookie :
+            return
+
+        try :
+            self.pubtkt = self.app.load(cookie)
+
+        except pubtkt.ParseError as ex :
+            self.cookie_error = ex
+
+        except pubtkt.VerifyError as ex :
+            self.pubtkt = ex.pubtkt
+            self.verify_error = ex
+ 
 
 class Index (Handler) :
     TITLE = u"Päivölä Network Login"
     
-    pubtkt = None
-    cookie_error = None
-
     def process (self) :
-        try :
-            self.pubtkt = self.process_cookie()
-        except pubtkt.Error as ex :
-            self.cookie_error = ex
+        self.process_cookie()
             
         if not self.pubtkt :
             return self.redirect(Login)
@@ -70,46 +81,79 @@
 
         return "%2d:%02d:%02d" % (hours, minutes, seconds)
 
+    def render_status (self, pubtkt) :
+        valid = pubtkt.valid()
+        grace = pubtkt.grace()
+
+        if valid and grace :
+            return 'success'
+        elif valid and grace is False :
+            return 'warning'
+        elif valid :
+            return 'success'
+        else :
+            return 'danger'
+
     def render_pubtkt_fields (self, pubtkt) :
         """
             Yield (glyphicon, text) to render as fields for ticket.
         """
 
-        yield 'user', "User account", pubtkt.uid
-        
-        valid = self.render_valid(pubtkt.valid())
+        yield 'user', None, "User account", pubtkt.uid
         
-        if pubtkt.graceperiod :
-            valid = "{valid} ({grace})".format(valid=valid, grace=self.render_valid(pubtkt.grace()))
+        valid = pubtkt.valid()
+        grace = pubtkt.grace()
 
-        yield 'time', "Remaining validity", valid
+        if valid and grace :
+            valid = "{valid} ({grace})".format(valid=self.render_valid(valid), grace=self.render_valid(grace))
+            valid_status = 'success'
+        elif valid and grace is False :
+            valid = "Renewable ({grace})".format(valid=self.render_valid(valid), grace=self.render_valid(grace))
+            valid_status = 'warning'
+        elif valid :
+            valid = "{valid}".format(valid=self.render_valid(valid))
+            valid_status = 'success'
+        else :
+            valid = "Expired"
+            valid_status = 'danger'
+
+        yield 'time', valid_status, "Remaining validity", valid
 
         if pubtkt.cip :
-            yield 'cloud', "Network address", pubtkt.cip
+            yield 'cloud', None, "Network address", pubtkt.cip
 
         if pubtkt.udata :
-            yield 'comment', "Associated data", pubtkt.udata
+            yield 'comment', None, "Associated data", pubtkt.udata
 
         for token in pubtkt.tokens :
-            yield 'flag', "Access token", token
+            yield 'flag', None, "Access token", token
 
         if pubtkt.bauth :
-            yield 'keys', "Authentication token", pubtkt.bauth
+            yield 'keys', None, "Authentication token", pubtkt.bauth
 
     def render_pubtkt (self, pubtkt) :
-        return html.div(class_='panel panel-info')(
+        status = self.render_status(pubtkt)
+
+        return html.div(class_='panel panel-{status}'.format(status=status))(
             html.div(class_='panel-heading')("Login: {pubtkt.uid}".format(pubtkt=self.pubtkt)),
-            html.div(class_='panel-body')(
-                "This is a valid login ticket.",
-            ),
             html.ul(class_='list-group')(
-                html.li(class_='list-group-item', title=title)(
+                html.li(class_='list-group-item {status}'.format(status=('alert-'+status if status else '')), title=title)(
                     html.span(class_='glyphicon glyphicon-{glyphicon}'.format(glyphicon=icon)) if icon else None,
                     info,
-                ) for icon, title, info in self.render_pubtkt_fields(pubtkt)
+                ) for icon, status, title, info in self.render_pubtkt_fields(pubtkt)
             ),
             html.div(class_='panel-footer')(
-                html.form(action='/logout', method='post')(
+                (
+                    html.form(action=self.url(Login), method='post')(
+                        html.button(type='submit', class_='btn btn-success')("Renew"),
+                    )
+                ) if pubtkt.valid() else (
+                    html.form(action=self.url(Login), method='get')(
+                        html.button(type='submit', class_='btn btn-info')("Login"),
+                    ),
+                ),
+
+                html.form(action=self.url(Logout), method='post')(
                     html.button(type='submit', class_='btn btn-warning')("Logout"),
                 ),
             ),
@@ -142,10 +186,9 @@
 
     """
 
+    def process (self) :
+        self.process_cookie()
 
-    auth_error = None
-
-    def process (self) :
         if self.request.method == 'POST' :
             back = self.app.login_server
             username = self.request.form.get('username')
@@ -156,28 +199,39 @@
                 username = username.strip().lower()
                 
                 try :
-                    pt = self.app.auth(username, password)
+                    self.pubtkt = self.app.auth(username, password)
 
                 except pubtkt.Error as ex :
                     self.auth_errors = ex
-
-                else :
-                    # browsers seem to be very particular about quoting ;'s in cookie values...
-                    # this follows PHP's setcookie() encoding...
-                    cookie = werkzeug.urls.url_quote(self.app.sign(pt))
+            
+            elif self.pubtkt and self.pubtkt.valid() :
+                # renew
+                self.app.renew(self.pubtkt)
 
-                    # redirect with cookie
-                    response = pvl.web.response.redirect(back)
+            else :
+                return
 
-                    response.set_cookie(self.app.cookie_name, cookie,
-                        domain      = self.app.cookie_domain,
-                        secure      = self.app.cookie_secure,
-                        httponly    = self.app.cookie_httponly,
-                    )
+            # browsers seem to be very particular about quoting ;'s in cookie values...
+            # this follows PHP's setcookie() encoding...
+            cookie = werkzeug.urls.url_quote(self.app.sign(self.pubtkt))
 
-                    return response
+            # redirect with cookie
+            response = pvl.web.response.redirect(back)
+
+            response.set_cookie(self.app.cookie_name, cookie,
+                domain      = self.app.cookie_domain,
+                secure      = self.app.cookie_secure,
+                httponly    = self.app.cookie_httponly,
+            )
+
+            return response
 
     def render (self) :
+        if self.pubtkt :
+            username = self.pubtkt.uid
+        else :
+            username = None
+
         domain = self.app.login_domain
 
         return html.div(class_='container')(
@@ -188,7 +242,7 @@
                     html.div(class_='form-group')(
                         html.div(class_='input-group')(
                             html.label(for_='username', class_='sr-only')("Username"),
-                            html.input(name='username', type='text', class_='form-control', placeholder="username", required=True, autofocus=True),
+                            html.input(name='username', type='text', class_='form-control', placeholder="username", required=True, autofocus=True, value=username),
                             html.span(class_='input-group-addon')("@{domain}".format(domain=domain)),
                         ),
 
@@ -205,11 +259,7 @@
     TITLE = "Logout"
 
     def process (self) :
-        try :
-            self.pubtkt = self.process_cookie() 
-        except Error as ex :
-            self.pubtkt_error = ex
-            self.pubtkt = ex.pubtkt
+        self.process_cookie()
 
         if not self.pubtkt :
             return self.redirect(Index)
@@ -251,7 +301,7 @@
     
     login_domain = 'test.paivola.fi'
     login_server = 'https://login.test.paivola.fi/'
-    login_expire = datetime.timedelta(hours=1)
+    login_expire = datetime.timedelta(seconds=60)
 
     cookie_name = 'auth_pubtkt'
     cookie_domain = 'test.paivola.fi'
@@ -289,3 +339,9 @@
         
         return pubtkt.sign(self.server_keys.private)
  
+    def renew (self, pubtkt) :
+        """
+            Renew and re-sign the given pubtkt.
+        """
+
+        pubtkt.renew(self.login_expire)