Skip to content

Commit

Permalink
Merge pull request getredash#98 from EverythingMe/feature_allow_exter…
Browse files Browse the repository at this point in the history
…nal_users

Feature: allow external users
  • Loading branch information
arikfr committed Feb 13, 2014
2 parents 41acfb7 + 8c05d5b commit 45ece74
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 24 deletions.
66 changes: 43 additions & 23 deletions authentication.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import functools
import hashlib
import hmac
from flask import request, make_response
from flask.ext.googleauth import GoogleFederated
from flask import current_app, request, make_response, g, redirect, url_for
from flask.ext.googleauth import GoogleAuth
import time
from werkzeug.contrib.fixers import ProxyFix
import werkzeug.wrappers
from redash import models, settings


Expand All @@ -23,36 +22,57 @@ class HMACAuthentication(object):
def __init__(self, auth):
self.auth = auth

def required(self, fn):
wrapped_fn = self.auth.required(fn)
@staticmethod
def api_key_authentication():
signature = request.args.get('signature')
expires = float(request.args.get('expires') or 0)
query_id = request.view_args.get('query_id', None)

@functools.wraps(fn)
def decorated(*args, **kwargs):
signature = request.args.get('signature')
expires = float(request.args.get('expires') or 0)
query_id = request.view_args.get('query_id', None)
# TODO: 3600 should be a setting
if signature and query_id and time.time() < expires <= time.time() + 3600:
query = models.Query.get(models.Query.id == query_id)
calculated_signature = sign(query.api_key, request.path, expires)

if query.api_key and signature == calculated_signature:
return True

return False

# TODO: 3600 should be a setting
if signature and query_id and time.time() < expires <= time.time() + 3600:
query = models.Query.get(models.Query.id == query_id)
calculated_signature = sign(query.api_key, request.path, expires)
@staticmethod
def is_user_logged_in():
return g.user is not None

if query.api_key and signature == calculated_signature:
return fn(*args, **kwargs)
@staticmethod
def valid_user():
email = g.user['email']
if not settings.GOOGLE_APPS_DOMAIN:
return True

return email in settings.ALLOWED_EXTERNAL_USERS or email.endswith("@%s" % settings.GOOGLE_APPS_DOMAIN)

def required(self, fn):
@functools.wraps(fn)
def decorated(*args, **kwargs):
if self.is_user_logged_in() and self.valid_user():
return fn(*args, **kwargs)

# Work around for flask-restful testing only for flask.wrappers.Resource instead of
# werkzeug.wrappers.Response
resp = wrapped_fn(*args, **kwargs)
if isinstance(resp, werkzeug.wrappers.Response):
resp = make_response(resp)
if self.api_key_authentication():
return fn(*args, **kwargs)

return resp
blueprint = current_app.extensions['googleauth'].blueprint
# The make_response call is a work around for flask-restful testing only for
# flask.wrappers.Resource instead of werkzeug.wrappers.Response
return make_response(redirect(url_for("%s.login" % blueprint.name, next=request.url)))

return decorated


def setup_authentication(app):
openid_auth = GoogleFederated(settings.GOOGLE_APPS_DOMAIN, app)
openid_auth = GoogleAuth(app)
# If we don't have a list of external users, we can use Google's federated login, which limits
# the domain with which you can sign in.
if not settings.ALLOWED_EXTERNAL_USERS and settings.GOOGLE_APPS_DOMAIN:
openid_auth._OPENID_ENDPOINT = "https://www.google.com/a/%s/o8/ud?be=o8" % settings.GOOGLE_APPS_DOMAIN
app.wsgi_app = ProxyFix(app.wsgi_app)
app.secret_key = settings.COOKIE_SECRET

Expand Down
11 changes: 10 additions & 1 deletion settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@ def fix_assets_path(path):
fullpath = os.path.join(os.path.dirname(__file__), path)
return fullpath


def array_from_string(str):
array = str.split(',')
if "" in array:
array.remove("")

return array

REDIS_URL = os.environ.get('REDASH_REDIS_URL', "redis://localhost:6379")

# "pg", "graphite" or "mysql"
Expand All @@ -41,7 +49,8 @@ def fix_assets_path(path):
# access
GOOGLE_APPS_DOMAIN = os.environ.get("REDASH_GOOGLE_APPS_DOMAIN", "")
# Email addresses of admin users (comma separated)
ADMINS = os.environ.get("REDASH_ADMINS", '').split(',')
ADMINS = array_from_string(os.environ.get("REDASH_ADMINS", ''))
ALLOWED_EXTERNAL_USERS = array_from_string(os.environ.get("REDASH_ALLOWED_EXTERNAL_USERS", ''))
STATIC_ASSETS_PATH = fix_assets_path(os.environ.get("REDASH_STATIC_ASSETS_PATH", "../rd_ui/dist/"))
WORKERS_COUNT = int(os.environ.get("REDASH_WORKERS_COUNT", "2"))
COOKIE_SECRET = os.environ.get("REDASH_COOKIE_SECRET", "c292a0a3aa32397cdb050e233733900f")
Expand Down

0 comments on commit 45ece74

Please sign in to comment.