Disallow iframes via X-Frame-Options and CSP by default
authorRob Crittenden <rcritten@redhat.com>
Thu, 23 Apr 2015 20:42:27 +0000 (16:42 -0400)
committerPatrick Uiterwijk <puiterwijk@redhat.com>
Fri, 24 Apr 2015 17:10:34 +0000 (19:10 +0200)
A decorator, allow_iframe, is also created so that specific
pages can remove the deny values and allow operating within
a frame.

The Persona plugin relies on iframes and uses this decorator
for all endpoints.

https://fedorahosted.org/ipsilon/ticket/15

Signed-off-by: Rob Crittenden <rcritten@redhat.com>
Reviewed-by: Patrick Uiterwijk <puiterwijk@redhat.com>
ipsilon/providers/persona/auth.py
ipsilon/util/endpoint.py

index d314993..aeeaa5b 100644 (file)
@@ -2,6 +2,7 @@
 
 from ipsilon.providers.common import ProviderPageBase
 from ipsilon.util.user import UserSession
+from ipsilon.util.endpoint import allow_iframe
 
 import base64
 import cherrypy
@@ -71,6 +72,7 @@ class Sign(AuthenticateRequest):
                 return True
         return False
 
+    @allow_iframe
     def POST(self, *args, **kwargs):
         if 'email' not in kwargs or 'publicKey' not in kwargs \
                 or 'certDuration' not in kwargs or '@' not in kwargs['email']:
@@ -93,6 +95,7 @@ class Sign(AuthenticateRequest):
 
 
 class SignInResult(AuthenticateRequest):
+    @allow_iframe
     def GET(self, *args, **kwargs):
         user = UserSession().get_user()
 
@@ -106,6 +109,7 @@ class SignIn(AuthenticateRequest):
         self.result = SignInResult(*args, **kwargs)
         self.trans = None
 
+    @allow_iframe
     def GET(self, *args, **kwargs):
         username = None
         domain = None
@@ -135,6 +139,7 @@ class Persona(AuthenticateRequest):
         self.SignIn = SignIn(*args, **kwargs)
         self.trans = None
 
+    @allow_iframe
     def GET(self, *args, **kwargs):
         user = UserSession().get_user()
         return self._template('persona/provisioning.html',
index f160329..0016bc2 100644 (file)
@@ -4,6 +4,7 @@ import cherrypy
 from ipsilon.util.log import Log
 from ipsilon.util.user import UserSession
 from urllib import unquote
+from functools import wraps
 try:
     from urlparse import urlparse
 except ImportError:
@@ -11,6 +12,23 @@ except ImportError:
     from urllib.parse import urlparse
 
 
+def allow_iframe(func):
+    """
+    Remove the X-Frame-Options and CSP frame-options deny headers.
+    """
+    @wraps(func)
+    def wrapper(*args, **kwargs):
+        result = func(*args, **kwargs)
+        for (header, value) in [
+                ('X-Frame-Options', 'deny'),
+                ('Content-Security-Policy', 'frame-options \'deny\'')]:
+            if cherrypy.response.headers.get(header, None) == value:
+                cherrypy.response.headers.pop(header, None)
+        return result
+
+    return wrapper
+
+
 class Endpoint(Log):
     def __init__(self, site):
         self._site = site
@@ -19,6 +37,8 @@ class Endpoint(Log):
         self.default_headers = {
             'Cache-Control': 'no-cache, no-store, must-revalidate, private',
             'Pragma': 'no-cache',
+            'Content-Security-Policy': 'frame-options \'deny\'',
+            'X-Frame-Options': 'deny',
         }
         self.auth_protect = False