Skip to content

Commit

Permalink
Add email_whitelist post-auth plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
barche committed Oct 3, 2016
1 parent 01cb513 commit d19e124
Show file tree
Hide file tree
Showing 7 changed files with 314 additions and 0 deletions.
4 changes: 4 additions & 0 deletions engine/src/juliabox/plugins/email_whitelist/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from impl_email_whitelist import EmailWhitelistHandler
from email_verify_tbl import EmailVerifyDB
from email_verify import EmailVerifyHandler
__author__ = 'barche'
72 changes: 72 additions & 0 deletions engine/src/juliabox/plugins/email_whitelist/email_verify.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import os
from juliabox.jbox_util import unquote, JBoxCfg
from juliabox.handlers import JBPluginHandler
from juliabox.db import JBoxUserV2, JBoxDBItemNotFound
from email_verify_tbl import EmailVerifyDB
from impl_email_whitelist import EmailWhitelistHandler
import urllib
from juliabox.cloud import JBPluginCloud

__author__ = 'barche'


class EmailVerifyHandler(JBPluginHandler):
provides = [JBPluginHandler.JBP_HANDLER]

CONFIGURED = False
EMAIL_PLUGIN = None
EMAIL_SENDER = ""

@staticmethod
def register(app):
app.add_handlers(".*$", [(r"/jboxauth/email_verify/", EmailVerifyHandler)])

@staticmethod
def configure():
if not EmailVerifyHandler.CONFIGURED:
plugin = JBPluginCloud.jbox_get_plugin(JBPluginCloud.JBP_SENDMAIL)
if plugin is None:
EmailVerifyHandler.log_error("No plugin found for sending mails. Cannot send verification mail.")
EmailVerifyHandler.EMAIL_PLUGIN = plugin
EmailVerifyHandler.EMAIL_SENDER = JBoxCfg.get('user_activation')['sender']

EmailVerifyHandler.CONFIGURED = True



def get(self):
EmailVerifyHandler.configure()

email = unquote(self.get_argument("email", None))
user_id = unquote(self.get_argument("user_id", None))
verification_code = unquote(self.get_argument("verification_code", None))
if user_id == None or email == None:
EmailVerifyHandler.log_error("Bad request to email handler")
return

EmailVerifyHandler.log_info("Request to verify email %s with user_id %s", email, user_id)

if not EmailWhitelistHandler.is_whitelisted(email):
self.render(os.path.join(EmailWhitelistHandler.TEMPLATE_PATH, "email_whitelist.tpl"), cfg=JBoxCfg.nv, user_id=user_id, message="ERROR: entered email is not whitelisted, please try again:")
return

if verification_code == None:
record = EmailVerifyDB(user_id, "pending_email_form_response", create=False)
record.set_email(email)

base_uri = self.request.protocol + "://" + self.request.host + self.request.uri.split('?')[0]
mail_body = base_uri + '?' + urllib.urlencode({
"user_id": user_id,
"email": email,
"verification_code": record.get_code()
})
EmailVerifyHandler.EMAIL_PLUGIN.send_email(email, EmailVerifyHandler.EMAIL_SENDER, 'JuliaBox account activation', mail_body)

self.render(os.path.join(EmailWhitelistHandler.TEMPLATE_PATH, "message.tpl"), cfg=JBoxCfg.nv, message="Email sent. Please click the link in the mail.")
else:
record = EmailVerifyDB(user_id, email, create=False)
if record.verify(verification_code):
s = dict(error="", success="Verification OK, please log in again", info="", pending_activation=False, user_id="")
self.rendertpl("index.tpl", cfg=JBoxCfg.nv, state=s)
else:
self.render(os.path.join(EmailWhitelistHandler.TEMPLATE_PATH, "message.tpl"), cfg=JBoxCfg.nv, message="Verification failed.")
65 changes: 65 additions & 0 deletions engine/src/juliabox/plugins/email_whitelist/email_verify_tbl.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
from juliabox.jbox_util import gen_random_secret
from juliabox.db import JBPluginDB, JBoxDBItemNotFound

__author__ = 'barche'


class EmailVerifyDB(JBPluginDB):
provides = [JBPluginDB.JBP_TABLE_RDBMS]

NAME = 'jbox_email_verify'

TABLE = None

KEYS = ['user_id']
ATTRIBUTES = ['email', 'verification_code', 'is_verified']
SQL_INDEXES = None
KEYS_TYPES = [JBPluginDB.VCHAR]
TYPES = [JBPluginDB.VCHAR, JBPluginDB.VCHAR, JBPluginDB.INT]

def __init__(self, user_id, email, create=False):
count = self.query_count(user_id__eq=user_id, email__eq=email)
if count > 0 and create:
raise RuntimeError("Email verify record exists, but create was requested")
if count == 0 and (not create):
raise RuntimeError("Email verify record does not exist")

if create:
data = {
'user_id': user_id,
'email': email,
'verification_code': gen_random_secret(),
'is_verified': 0
}
self.create(data)

self.item = self.fetch(user_id=user_id, email=email)
self.is_new = create

@classmethod
def get_verified_emails(cls, user_id):
records = cls.query(user_id__eq=user_id, is_verified__eq=1)
verified_email_list = []
for rec in records:
verified_email_list.append(rec['email'])
return verified_email_list


def set_email(self, email):
self.set_attrib('email', email)
self.save()

def verify(self, verification_code):
if self.get_attrib('verification_code') == verification_code:
self.set_attrib('is_verified', 1)
self.save()
return True
return False

def get_code(self):
return self.get_attrib('verification_code')

def is_verified(self):
if self.get_attrib('is_verified') == 1:
return True
return False
61 changes: 61 additions & 0 deletions engine/src/juliabox/plugins/email_whitelist/email_whitelist.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<html lang="en">
<head>
<meta charset="utf-8" />
<title>JuliaBox</title>

<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
<link rel="stylesheet" href="/assets/css/icons.css" />
{% if cfg["env_type"] == "dev" %}
<link rel="stylesheet/less" type="text/css" href="/assets/css/base.less" />
<script src="//cdnjs.cloudflare.com/ajax/libs/less.js/1.7.3/less.min.js"></script>
{% else %}
<link rel="stylesheet" type="text/css" href="/assets/css/base.css" />
{% end %}

<script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.7.0/underscore-min.js"></script>

<script src="//code.jquery.com/jquery-1.11.0.min.js"></script>
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/bootbox.js/4.3.0/bootbox.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>
<script src="//apis.google.com/js/client.js"></script>
<script src="/assets/js/jquery-gdrive.js"></script>
<script src="/assets/js/juliabox.js"></script>
<script type="text/javascript" src="//use.typekit.net/cpz5ogz.js"></script>
<script type="text/javascript">try{Typekit.load();}catch(e){}</script>
{% block head %}
{% end %}
</head>
<body>
<div class="header-wrap">
<div class="container">
<div class="row header-row">
<div class="logo-and-name">
<img class="brand-logo" src="/assets/img/juliacloudlogo.png"/>
<div class="brand-title hidden-xs hidden-sm">JuliaBox<sup> beta</sup></div>
</div>
{% block tabs %}
{% end %}
</div><!-- row -->
<div style="clear:both;"></div>
</div>
</div>

<div class="container">
<table width="100%" height="100%" align="center" valign="middle">
<tr width="100%" height="100%" align="center" valign="middle">
<td width="100%" height="100%" align="center" valign="middle">
<div>
<div>{{message}}</div>
<form action="/jboxauth/email_verify/" method="get">
<input type="text" placeholder="Email whitelist check. Enter a whitelisted email and hit &#x23ce;" class="form-control email-box" name="email" id="email" required autofocus>
<input type="hidden" name="user_id" value={{user_id}}>
<input style="display:none" type="submit" value="Launch">
</form>
</div>
</td>
</tr>
</table>
</div>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import os
from juliabox.jbox_util import unquote, JBoxCfg
from juliabox.handlers import JBPluginHandler
from juliabox.db import JBoxUserV2, JBoxDBItemNotFound
from email_verify_tbl import EmailVerifyDB

__author__ = 'barche'


class EmailWhitelistHandler(JBPluginHandler):
provides = [JBPluginHandler.JBP_HANDLER,
JBPluginHandler.JBP_HANDLER_POST_AUTH]

WHITELIST = []
CONFIGURED = False
TEMPLATE_PATH = os.path.dirname(__file__)

@staticmethod
def register(app):
app.add_handlers(".*$", [(r"/jboxauth/email_whitelist/", EmailWhitelistHandler)])

def get(self):
#EmailWhitelistHandler.log_info("State arg: %s", self.get_argument("state"))
email = unquote(self.get_argument("email"))
EmailWhitelistHandler.log_info("Obtained email %s", email)

@staticmethod
def configure():
if not EmailWhitelistHandler.CONFIGURED:
data = JBoxCfg.get('email_whitelist')
if data == None:
EmailWhitelistHandler.log_error("No email_whitelist config entry")
return
EmailWhitelistHandler.WHITELIST = data.get('allowed_addresses')

if len(EmailWhitelistHandler.WHITELIST) == 0:
EmailWhitelistHandler.log_error("No allowed_addresses config entry for email_whitelist")

EmailWhitelistHandler.CONFIGURED = True

@staticmethod
def is_whitelisted(email):
for allowed_mail in EmailWhitelistHandler.WHITELIST:
if email.lower().endswith(allowed_mail.lower()):
return True
return False


@staticmethod
def process_user_id(handler, user_id):
EmailWhitelistHandler.configure()

# Check if the user_id matches
if EmailWhitelistHandler.is_whitelisted(user_id):
return True

# Check if any of the users verified email addresses match
verified_emails = EmailVerifyDB.get_verified_emails(user_id)
for allowed_mail in EmailWhitelistHandler.WHITELIST:
for verified_email in verified_emails:
if EmailWhitelistHandler.is_whitelisted(verified_email):
return True

# No match, create a pending email verify request
EmailVerifyDB(user_id, "pending_email_form_response", create=True)

handler.render(os.path.join(EmailWhitelistHandler.TEMPLATE_PATH, "email_whitelist.tpl"), cfg=JBoxCfg.nv, user_id=user_id, message="Please enter white-listed email as per tutor instructions:")

return False
42 changes: 42 additions & 0 deletions engine/src/juliabox/plugins/email_whitelist/message.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<html lang="en">
<head>
<meta charset="utf-8" />
<title>JuliaBox</title>

<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
<link rel="stylesheet" href="/assets/css/icons.css" />
{% if cfg["env_type"] == "dev" %}
<link rel="stylesheet/less" type="text/css" href="/assets/css/base.less" />
<script src="//cdnjs.cloudflare.com/ajax/libs/less.js/1.7.3/less.min.js"></script>
{% else %}
<link rel="stylesheet" type="text/css" href="/assets/css/base.css" />
{% end %}
</head>
<body>
<div class="header-wrap">
<div class="container">
<div class="row header-row">
<div class="logo-and-name">
<img class="brand-logo" src="/assets/img/juliacloudlogo.png"/>
<div class="brand-title hidden-xs hidden-sm">JuliaBox<sup> beta</sup></div>
</div>
{% block tabs %}
{% end %}
</div><!-- row -->
<div style="clear:both;"></div>
</div>
</div>

<div class="container">
<table width="100%" height="100%" align="center" valign="middle">
<tr width="100%" height="100%" align="center" valign="middle">
<td width="100%" height="100%" align="center" valign="middle">
<div>
<div>{{message}}</div>
</div>
</td>
</tr>
</table>
</div>
</body>
</html>
1 change: 1 addition & 0 deletions scripts/install/create_tables_sqlite.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

# import any plugins that contribute tables
import juliabox.plugins.course_homework
import juliabox.plugins.email_whitelist


def table_exists(table_name):
Expand Down

0 comments on commit d19e124

Please sign in to comment.