Skip to content
Open
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ virt_env/
*.pyc
.DS_Store
houdini/houdini/config*.py
static/
9 changes: 5 additions & 4 deletions houdini/houdini/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
ROOT = os.path.dirname(BASE_DIR)
STATIC_ROOT = os.path.join(ROOT, 'static')


# Quick-start development settings - unsuitable for production
Expand All @@ -38,8 +40,6 @@
SECURE_HSTS_SECONDS = 600 # TODO: should eventually be set to something like 31536000 (1 year)
SECURE_HSTS_INCLUDE_SUBDOMAINS = True

SSL_DEV_CERT_KEY = (os.getenv('SSL_DEV_CERT'), os.getenv('SSL_DEV_KEY'))

HOUDINI_KEY = os.getenv('app_key')
HOUDINI_SECRET = os.getenv('app_secret')
HOUDINI_SERVER = os.getenv('houdini_server')
Expand All @@ -57,12 +57,13 @@
EMAIL_HOST_PASSWORD = os.getenv('EMAIL_HOST_PASSWORD')

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
DEBUG = False

ALLOWED_HOSTS = []
ALLOWED_HOSTS = ['auth.thecorp.org']

ADMINS = (
('Justice Suh', 'justice.suh@gmail.com'),
('Peter Johnston', 'peter@thecorp.org'),
)


Expand Down
2 changes: 1 addition & 1 deletion houdini/houdini/wsgi.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "houdini.settings")

# set houdini specific env vars
import houdini.config_dev
import houdini.config_production

application = get_wsgi_application()
14 changes: 14 additions & 0 deletions houdini/houdini_admin/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.http import HttpResponse
from django.shortcuts import redirect, render
from django.utils.decorators import method_decorator
from django.views.generic.edit import UpdateView
from django.utils.decorators import method_decorator

Expand Down Expand Up @@ -234,3 +235,16 @@ def delete_permission(request, pk):
if permission_to_delete.delete():
messages.success(request, message)
return redirect('permissions')


@login_required
def login_test(request):
return render(request, "houdini_admin/login_test.html")

@role_required('super cool role')
def role_test(request):
return render(request, "houdini_admin/role_test.html")

@permission_required('even new one')
def permission_test(request):
return render(request, "houdini_admin/permission_test.html")
6 changes: 0 additions & 6 deletions houdini/houdini_client/auth_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,6 @@ def authenticate(self, email=None, password=None, response=None):
# POST it to the login endpoint
r = requests.post(
settings.HOUDINI_SERVER + "/endpoints/login",
# TODO: cert and verify will change in production
# cert isn't necessary since we have verify=False, but we will leave it
# as a placeholder for when we are in production with Let's Encrypt
cert=settings.SSL_DEV_CERT_KEY,
verify=False,
# TODO: ^only in development!!!
data={
"app_key": settings.HOUDINI_KEY,
"jwt_string": jwt_string
Expand Down
36 changes: 0 additions & 36 deletions houdini/houdini_client/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,12 +100,6 @@ def register(request):
# POST it to the create_user endpoint
r = requests.post(
settings.HOUDINI_SERVER + "/endpoints/create_user",
# TODO: cert and verify will change in production
# cert isn't necessary since we have verify=False, but we will leave it
# as a placeholder for when we are in production with Let's Encrypt
cert=settings.SSL_DEV_CERT_KEY,
verify=False,
# TODO: ^only in development!!!
data={
"app_key": settings.HOUDINI_KEY,
"jwt_string": jwt_string
Expand Down Expand Up @@ -146,12 +140,6 @@ def activate(request, key):
# POST it to the regenerate_activation_key endpoint
r = requests.post(
settings.HOUDINI_SERVER + "/endpoints/regenerate_activation_key",
# TODO: cert and verify will change in production
# cert isn't necessary since we have verify=False, but we will leave it
# as a placeholder for when we are in production with Let's Encrypt
cert=settings.SSL_DEV_CERT_KEY,
verify=False,
# TODO: ^only in development!!!
data={
"app_key": settings.HOUDINI_KEY,
"jwt_string": jwt_string
Expand All @@ -170,12 +158,6 @@ def activate(request, key):
# POST it to the activate_user endpoint
r = requests.post(
settings.HOUDINI_SERVER + "/endpoints/activate_user",
# TODO: cert and verify will change in production
# cert isn't necessary since we have verify=False, but we will leave it
# as a placeholder for when we are in production with Let's Encrypt
cert=settings.SSL_DEV_CERT_KEY,
verify=False,
# TODO: ^only in development!!!
data={
"app_key": settings.HOUDINI_KEY,
"jwt_string": jwt_string
Expand Down Expand Up @@ -222,12 +204,6 @@ def password_change(request):
# POST it to the password_change endpoint
r = requests.post(
settings.HOUDINI_SERVER + "/endpoints/password_change",
# TODO: cert and verify will change in production
# cert isn't necessary since we have verify=False, but we will leave it
# as a placeholder for when we are in production with Let's Encrypt
cert=settings.SSL_DEV_CERT_KEY,
verify=False,
# TODO: ^only in development!!!
data={
"app_key": settings.HOUDINI_KEY,
"jwt_string": jwt_string
Expand Down Expand Up @@ -263,12 +239,6 @@ def password_reset(request):
# POST it to the password_reset endpoint
r = requests.post(
settings.HOUDINI_SERVER + "/endpoints/password_reset",
# TODO: cert and verify will change in production
# cert isn't necessary since we have verify=False, but we will leave it
# as a placeholder for when we are in production with Let's Encrypt
cert=settings.SSL_DEV_CERT_KEY,
verify=False,
# TODO: ^only in development!!!
data={
"app_key": settings.HOUDINI_KEY,
"jwt_string": jwt_string
Expand Down Expand Up @@ -304,12 +274,6 @@ def password_set(request, key):
# POST it to the password_set endpoint
r = requests.post(
settings.HOUDINI_SERVER + "/endpoints/password_set",
# TODO: cert and verify will change in production
# cert isn't necessary since we have verify=False, but we will leave it
# as a placeholder for when we are in production with Let's Encrypt
cert=settings.SSL_DEV_CERT_KEY,
verify=False,
# TODO: ^only in development!!!
data={
"app_key": settings.HOUDINI_KEY,
"jwt_string": jwt_string
Expand Down
6 changes: 5 additions & 1 deletion houdini/houdini_server/endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,11 @@ def post(self, request):
app_roles = set(self.app.roles.all())
# Get all of the roles the user has
user_roles = set(user.roles.all())
relevant_roles = app_roles.intersection(user_roles)
user_app_roles = app_roles.intersection(user_roles)
# Now get all of the roles that they have and inherit
relevant_roles = set()
for role in user_app_roles:
relevant_roles.add(role.get_all_inherited_roles())
# Now get all of the permissions for every role
permissions = set()
for role in relevant_roles:
Expand Down
42 changes: 40 additions & 2 deletions houdini/houdini_server/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ def get_parent_slugs_for_role(self):
return [parent.slug for parent in self.parents]

def get_parent_permissions(self):
# TODO: This could be sped up by using something to prevent iterating across the same parent multiple times
parent_permissions = set()
search_queue = Queue()
for parent in self.parents.all():
Expand All @@ -156,6 +157,19 @@ def get_all_permissions(self):
permissions |= self.get_parent_permissions()
return permissions

def get_all_inherited_roles(self):
parents = set()
search_queue = Queue()
for parent in self.parents.all():
search_queue.put(parent)
while not search_queue.empty():
parent = search_queue.get()
parents.add(parent)
for role_parent in parent.parents.all():
if role_parent not in parents:
search_queue.put(parent)


def __str__(self):
return self.name

Expand All @@ -182,6 +196,28 @@ def refresh_table():
mapping.save()


class RolesToParents(models.Model):
role = models.ForeignKey('Role')
parents = models.TextField()

@staticmethod
def refresh_table():
"""
Clears the entire table and for every role finds all of its parents
:return: void
"""
# First clear the entire table
RolesToParents.objects.all().delete()
# Now regenerate all of the mappings
for role in Role.objects.all():
parents = role.get_all_inherited_roles()
parents_list = [parent.name for parent in parents]
parents_list += [parent.slug for parent in parents]
parents_string = json.dumps(parents_list)
mapping = RolesToParents(role=role, parents=parents_string)
mapping.save()


class HoudiniUserManager(UserManager):
def get_by_natural_key(self, email):
return self.get(email=email)
Expand Down Expand Up @@ -233,9 +269,11 @@ def generate_activation_key(self):
def send_activation_email(self, activate_url, resend=False):
activation_link = activate_url + self.activation_key
if resend:
message = "Hello " + str(self) + "! Your old activation key expired so we have generated a new one for you. Go to this link to activate your account: " + activation_link
message = "Hello " + str(
self) + "! Your old activation key expired so we have generated a new one for you. Go to this link to activate your account: " + activation_link
else:
message = "Hello " + str(self) + "! You have successfully registered for an account. Go to this link to activate your account: " + activation_link
message = "Hello " + str(
self) + "! You have successfully registered for an account. Go to this link to activate your account: " + activation_link
send_mail(
"Activate your account",
message,
Expand Down
13 changes: 11 additions & 2 deletions houdini/houdini_server/signals.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,28 @@
from django.db.models.signals import post_save, m2m_changed, post_delete
from django.dispatch import receiver
from .models import Role, RolesToPermissions
from .models import Role, RolesToPermissions, RolesToParents


@receiver(m2m_changed, sender=Role.permissions.through)
def role_m2m_changed(sender, **kwargs):
def role_m2m_permissions_changed(sender, **kwargs):
RolesToPermissions.refresh_table()


@receiver(m2m_changed, sender=Role.parents.through)
def role_m2m_parents_changed(sender, **kwargs):
RolesToParents.refresh_table()


@receiver(post_delete, sender="houdini_server.Role")
def role_post_delete(sender, **kwargs):
RolesToPermissions.refresh_table()


@receiver(post_save, sender="houdini_server.Permission")
def permission_post_save(sender, **kwargs):
RolesToPermissions.refresh_table()


@receiver(post_delete, sender="houdini_server.Permission")
def permission_post_delete(sender, **kwargs):
RolesToPermissions.refresh_table()
8 changes: 1 addition & 7 deletions houdini/manage.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,7 @@
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "houdini.settings")

# set houdini specific env vars
import houdini.config_dev

# TODO: only in development!!!
# disable SSL warnings so we can use a self-signed cert
import requests
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
import houdini.config_production

try:
from django.core.management import execute_from_command_line
Expand Down
3 changes: 3 additions & 0 deletions restart.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/bash
/home/thecorp/django/houdini/stop.sh
/home/thecorp/django/houdini/start.sh
5 changes: 5 additions & 0 deletions start.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/bash

cd /home/thecorp/django/houdini/houdini

../virt_env/bin/gunicorn -w 8 -b 127.0.0.1:8080 --log-file /tmp/houdini.log -D houdini.wsgi:application
2 changes: 2 additions & 0 deletions stop.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/bin/bash
kill -9 `ps -aux | grep gunicorn | grep houdini.wsgi:application | awk '{ print $2 }'`