Skip to content

Commit 716af46

Browse files
committed
Merge pull request #11 from nhr/templatized
Templatized Django package
2 parents 797a15d + f5d8869 commit 716af46

File tree

7 files changed

+325
-20
lines changed

7 files changed

+325
-20
lines changed

.openshift/README.md

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Django Template for OpenShift
2+
3+
## Template App Information
4+
Product: Django
5+
Version: 1.4
6+
Source: https://github.com/django/django.git
7+
Commit: 2591fb8d4c0246f68b79554976c012039df75359
8+
9+
## Maintenance
10+
This folder contains a diff file that includes the changes made to the
11+
stock Django app in order to make it OpenShift-Template-ready. If
12+
you are a maintainer tasked with updating the Django template, you
13+
may be able to use this patch file on the updated Django code to
14+
automatically reapply these changes.
15+
16+
Here are the steps involved:
17+
18+
1. Under the 'wsgi' directory, apply any patches required to update the 'openshift' Django app.
19+
2. From the template root directory, run 'git apply --check .openshift/template.patch' to test for patching problems.
20+
3. Next run 'git am --signoff < .openshift/template.patch' to apply the patch to the template.
21+
22+
If this process succeeds, then the changes have been automatically
23+
applied. Otherwise it may be necessary to manually apply the
24+
changes. If the base package has changed enough, you may need to
25+
re-audit the base code and generate a new patch file.

.openshift/action_hooks/deploy

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@ if [ ! -f $OPENSHIFT_DATA_DIR/sqlite3.db ]
1010
then
1111
echo "Copying $OPENSHIFT_REPO_DIR/wsgi/openshift/sqlite3.db to $OPENSHIFT_DATA_DIR"
1212
cp "$OPENSHIFT_REPO_DIR"wsgi/openshift/sqlite3.db $OPENSHIFT_DATA_DIR
13+
python "$OPENSHIFT_REPO_DIR".openshift/action_hooks/secure_db.py
1314
else
1415
echo "Executing 'python $OPENSHIFT_REPO_DIR/wsgi/openshift/manage.py syncdb --noinput'"
1516
python "$OPENSHIFT_REPO_DIR"wsgi/openshift/manage.py syncdb --noinput
1617
fi
1718

1819
echo "Executing 'python $OPENSHIFT_REPO_DIR/wsgi/openshift/manage.py collectstatic --noinput'"
19-
python "$OPENSHIFT_REPO_DIR"wsgi/openshift/manage.py collectstatic --noinput
20+
python "$OPENSHIFT_REPO_DIR"wsgi/openshift/manage.py collectstatic --noinput

.openshift/action_hooks/secure_db.py

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#!/usr/bin/env python
2+
import hashlib, imp, os, sqlite3
3+
4+
# Load the openshift helper library
5+
lib_path = os.environ['OPENSHIFT_REPO_DIR'] + 'wsgi/openshift/'
6+
modinfo = imp.find_module('openshiftlibs', [lib_path])
7+
openshiftlibs = imp.load_module('openshiftlibs', modinfo[0], modinfo[1], modinfo[2])
8+
9+
# Open the database
10+
conn = sqlite3.connect(os.environ['OPENSHIFT_DATA_DIR'] + '/sqlite3.db')
11+
c = conn.cursor()
12+
13+
# Grab the default security info
14+
c.execute('SELECT password FROM AUTH_USER WHERE id = 1')
15+
pw_info = c.fetchone()[0]
16+
17+
# The password is stored as [hashtype]$[salt]$[hashed]
18+
pw_fields = pw_info.split("$")
19+
hashtype = pw_fields[0]
20+
old_salt = pw_fields[1]
21+
old_pass = pw_fields[2]
22+
23+
# Randomly generate a new password and a new salt
24+
# The PASSWORD value below just sets the length (12)
25+
# for the real new password.
26+
old_keys = { 'SALT': old_salt, 'PASS': '123456789ABC' }
27+
use_keys = openshiftlibs.openshift_secure(old_keys)
28+
29+
# Encrypt the new password
30+
new_salt = use_keys['SALT']
31+
new_pass = use_keys['PASS']
32+
new_hashed = hashlib.sha1(new_salt + new_pass).hexdigest()
33+
new_pw_info = "$".join([hashtype,new_salt,new_hashed])
34+
35+
# Update the database
36+
c.execute('UPDATE AUTH_USER SET password = ? WHERE id = 1', [new_pw_info])
37+
conn.commit()
38+
c.close()
39+
conn.close()
40+
41+
# Print the new password info
42+
print "CLIENT_MESSAGE: The password for user 'admin' in your Django app is " + new_pass + " ...be sure to write this down as you will not see this message again.\n"

.openshift/template.patch

+133
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
From 2b49faba38b8ceb8abe639b5f7ec022a59f47ce0 Mon Sep 17 00:00:00 2001
2+
From: "N. Harrison Ripps" <[email protected]>
3+
Date: Mon, 23 Jul 2012 11:05:13 -0400
4+
Subject: [PATCH] Added changes to templatize the quick start.
5+
6+
---
7+
wsgi/openshift/openshiftlibs.py | 81 +++++++++++++++++++++++++++++++++++++++
8+
wsgi/openshift/settings.py | 14 ++++++-
9+
2 files changed, 93 insertions(+), 2 deletions(-)
10+
create mode 100644 wsgi/openshift/openshiftlibs.py
11+
12+
diff --git a/wsgi/openshift/openshiftlibs.py b/wsgi/openshift/openshiftlibs.py
13+
new file mode 100644
14+
index 0000000..a11e0e5
15+
--- /dev/null
16+
+++ b/wsgi/openshift/openshiftlibs.py
17+
@@ -0,0 +1,81 @@
18+
+#!/usr/bin/env python
19+
+import hashlib, inspect, os, random, sys
20+
+
21+
+# Gets the secret token provided by OpenShift
22+
+# or generates one (this is slightly less secure, but good enough for now)
23+
+def get_openshift_secret_token():
24+
+ token = os.getenv('OPENSHIFT_SECRET_TOKEN')
25+
+ name = os.getenv('OPENSHIFT_APP_NAME')
26+
+ uuid = os.getenv('OPENSHIFT_APP_UUID')
27+
+ if token is not None:
28+
+ return token
29+
+ elif (name is not None and uuid is not None):
30+
+ return hashlib.sha256(name + '-' + uuid).hexdigest()
31+
+ return None
32+
+
33+
+# Loop through all provided variables and generate secure versions
34+
+# If not running on OpenShift, returns defaults and logs an error message
35+
+#
36+
+# This function calls secure_function and passes an array of:
37+
+# {
38+
+# 'hash': generated sha hash,
39+
+# 'variable': name of variable,
40+
+# 'original': original value
41+
+# }
42+
+def openshift_secure(default_keys, secure_function = 'make_secure_key'):
43+
+ # Attempts to get secret token
44+
+ my_token = get_openshift_secret_token()
45+
+
46+
+ # Only generate random values if on OpenShift
47+
+ my_list = default_keys
48+
+
49+
+ if my_token is not None:
50+
+ # Loop over each default_key and set the new value
51+
+ for key, value in default_keys.iteritems():
52+
+ # Create hash out of token and this key's name
53+
+ sha = hashlib.sha256(my_token + '-' + key).hexdigest()
54+
+ # Pass a dictionary so we can add stuff without breaking existing calls
55+
+ vals = { 'hash': sha, 'variable': key, 'original': value }
56+
+ # Call user specified function or just return hash
57+
+ my_list[key] = sha
58+
+ if secure_function is not None:
59+
+ # Pick through the global and local scopes to find the function.
60+
+ possibles = globals().copy()
61+
+ possibles.update(locals())
62+
+ supplied_function = possibles.get(secure_function)
63+
+ if not supplied_function:
64+
+ raise Exception("Cannot find supplied security function")
65+
+ else:
66+
+ my_list[key] = supplied_function(vals)
67+
+ else:
68+
+ calling_file = inspect.stack()[1][1]
69+
+ if os.getenv('OPENSHIFT_REPO_DIR'):
70+
+ base = os.getenv('OPENSHIFT_REPO_DIR')
71+
+ calling_file.replace(base,'')
72+
+ sys.stderr.write("OPENSHIFT WARNING: Using default values for secure variables, please manually modify in " + calling_file + "\n")
73+
+
74+
+ return my_list
75+
+
76+
+
77+
+# This function transforms default keys into per-deployment random keys;
78+
+def make_secure_key(key_info):
79+
+ hashcode = key_info['hash']
80+
+ key = key_info['variable']
81+
+ original = key_info['original']
82+
+
83+
+ chars = '0123456789abcdef'
84+
+
85+
+ # Use the hash to seed the RNG
86+
+ random.seed(int("0x" + hashcode[:8], 0))
87+
+
88+
+ # Create a random string the same length as the default
89+
+ rand_key = ''
90+
+ for _ in range(len(original)):
91+
+ rand_pos = random.randint(0,len(chars))
92+
+ rand_key += chars[rand_pos:(rand_pos+1)]
93+
+
94+
+ # Reset the RNG
95+
+ random.seed()
96+
+
97+
+ # Set the value
98+
+ return rand_key
99+
diff --git a/wsgi/openshift/settings.py b/wsgi/openshift/settings.py
100+
index 842669e..2f44079 100644
101+
--- a/wsgi/openshift/settings.py
102+
+++ b/wsgi/openshift/settings.py
103+
@@ -1,6 +1,6 @@
104+
# -*- coding: utf-8 -*-
105+
# Django settings for openshift project.
106+
-import os
107+
+import imp, os
108+
109+
# a setting to determine whether we are running on OpenShift
110+
ON_OPENSHIFT = False
111+
@@ -104,8 +104,18 @@ STATICFILES_FINDERS = (
112+
#'django.contrib.staticfiles.finders.DefaultStorageFinder',
113+
)
114+
115+
+# Make a dictionary of default keys
116+
+default_keys = { 'SECRET_KEY': 'vm4rl5*ymb@2&d_(gc$gb-^twq9w(u69hi--%$5xrh!xk(t%hw' }
117+
+
118+
+# Replace default keys with dynamic values if we are in OpenShift
119+
+use_keys = default_keys
120+
+if ON_OPENSHIFT:
121+
+ imp.find_module('openshiftlibs')
122+
+ import openshiftlibs
123+
+ use_keys = openshiftlibs.openshift_secure(default_keys)
124+
+
125+
# Make this unique, and don't share it with anybody.
126+
-SECRET_KEY = 'vm4rl5*ymb@2&d_(gc$gb-^twq9w(u69hi--%$5xrh!xk(t%hw'
127+
+SECRET_KEY = use_keys['SECRET_KEY']
128+
129+
# List of callables that know how to import templates from various sources.
130+
TEMPLATE_LOADERS = (
131+
--
132+
1.7.5.4
133+

README.md

+27-17
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,31 @@
1+
12
Django on OpenShift
23
===================
34

4-
This git repository helps you get up and running quickly w/ a Django installation
5-
on OpenShift. The Django project name used in this repo is 'openshift'
6-
but you can feel free to change it. Right now the backend is sqlite3 and the
7-
database runtime is @ $OPENSHIFT_DATA_DIR/sqlite3.db.
5+
This git repository helps you get up and running quickly w/ a Django
6+
installation on OpenShift. The Django project name used in this repo
7+
is 'openshift' but you can feel free to change it. Right now the
8+
backend is sqlite3 and the database runtime is @
9+
$OPENSHIFT_DATA_DIR/sqlite3.db.
810

9-
When you push this application up for the first time, the sqlite database is
10-
copied from wsgi/openshift/sqlite3.db. This is the stock database that is created
11-
when 'python manage.py syncdb' is run with only the admin app installed.
11+
Before you push this app for the first time, you will need to change
12+
the Django admin password (see below). Then, when you first push this
13+
application to the cloud instance, the sqlite database is copied from
14+
wsgi/openshift/sqlite3.db with your newly changed login
15+
credentials. Other than the password change, this is the stock
16+
database that is created when 'python manage.py syncdb' is run with
17+
only the admin app installed.
1218

13-
You can delete the database from your git repo after the first push (you probably
14-
should for security). On subsequent pushes, a 'python manage.py syncdb' is
15-
executed to make sure that any models you added are created in the DB. If you
16-
do anything that requires an alter table, you could add the alter statements
17-
in GIT_ROOT/.openshift/action_hooks/alter.sql and then use
18-
GIT_ROOT/.openshift/action_hooks/deploy to execute that script (make sure to
19-
back up your database w/ 'rhc app snapshot save' first :) )
19+
On subsequent pushes, a 'python manage.py syncdb' is executed to make
20+
sure that any models you added are created in the DB. If you do
21+
anything that requires an alter table, you could add the alter
22+
statements in GIT_ROOT/.openshift/action_hooks/alter.sql and then use
23+
GIT_ROOT/.openshift/action_hooks/deploy to execute that script (make
24+
sure to back up your database w/ 'rhc app snapshot save' first :) )
2025

2126

2227
Running on OpenShift
23-
----------------------------
28+
--------------------
2429

2530
Create an account at http://openshift.redhat.com/
2631

@@ -37,12 +42,17 @@ Add this upstream repo
3742
cd django
3843
git remote add upstream -m master git://github.com/openshift/django-example.git
3944
git pull -s recursive -X theirs upstream master
40-
45+
4146
Then push the repo upstream
4247

4348
git push
49+
50+
**Note**: As the git push output scrolls by, keep an eye out for a
51+
line of output that starts with 'CLIENT_MESSAGE: '. This line
52+
contains the generated admin password that you will need to begin
53+
administering your Django app. This is the only time the password
54+
will be displayed, so be sure to save it somewhere!
4455

4556
That's it, you can now checkout your application at (default admin account is admin/admin):
4657

4758
http://django-$yournamespace.rhcloud.com
48-

wsgi/openshift/openshiftlibs.py

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
#!/usr/bin/env python
2+
import hashlib, inspect, os, random, sys
3+
4+
# Gets the secret token provided by OpenShift
5+
# or generates one (this is slightly less secure, but good enough for now)
6+
def get_openshift_secret_token():
7+
token = os.getenv('OPENSHIFT_SECRET_TOKEN')
8+
name = os.getenv('OPENSHIFT_APP_NAME')
9+
uuid = os.getenv('OPENSHIFT_APP_UUID')
10+
if token is not None:
11+
return token
12+
elif (name is not None and uuid is not None):
13+
return hashlib.sha256(name + '-' + uuid).hexdigest()
14+
return None
15+
16+
# Loop through all provided variables and generate secure versions
17+
# If not running on OpenShift, returns defaults and logs an error message
18+
#
19+
# This function calls secure_function and passes an array of:
20+
# {
21+
# 'hash': generated sha hash,
22+
# 'variable': name of variable,
23+
# 'original': original value
24+
# }
25+
def openshift_secure(default_keys, secure_function = 'make_secure_key'):
26+
# Attempts to get secret token
27+
my_token = get_openshift_secret_token()
28+
29+
# Only generate random values if on OpenShift
30+
my_list = default_keys
31+
32+
if my_token is not None:
33+
# Loop over each default_key and set the new value
34+
for key, value in default_keys.iteritems():
35+
# Create hash out of token and this key's name
36+
sha = hashlib.sha256(my_token + '-' + key).hexdigest()
37+
# Pass a dictionary so we can add stuff without breaking existing calls
38+
vals = { 'hash': sha, 'variable': key, 'original': value }
39+
# Call user specified function or just return hash
40+
my_list[key] = sha
41+
if secure_function is not None:
42+
# Pick through the global and local scopes to find the function.
43+
possibles = globals().copy()
44+
possibles.update(locals())
45+
supplied_function = possibles.get(secure_function)
46+
if not supplied_function:
47+
raise Exception("Cannot find supplied security function")
48+
else:
49+
my_list[key] = supplied_function(vals)
50+
else:
51+
calling_file = inspect.stack()[1][1]
52+
if os.getenv('OPENSHIFT_REPO_DIR'):
53+
base = os.getenv('OPENSHIFT_REPO_DIR')
54+
calling_file.replace(base,'')
55+
sys.stderr.write("OPENSHIFT WARNING: Using default values for secure variables, please manually modify in " + calling_file + "\n")
56+
57+
return my_list
58+
59+
60+
# This function transforms default keys into per-deployment random keys;
61+
def make_secure_key(key_info):
62+
hashcode = key_info['hash']
63+
key = key_info['variable']
64+
original = key_info['original']
65+
66+
chars = '0123456789'
67+
chars += 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
68+
chars += '!@#%^&*()'
69+
chars += '-_ []{}<>~`+=,.;:/?|'
70+
71+
# Use the hash to seed the RNG
72+
random.seed(int("0x" + hashcode[:8], 0))
73+
74+
# Create a random string the same length as the default
75+
rand_key = ''
76+
for _ in range(len(original)):
77+
rand_pos = random.randint(0,len(chars))
78+
rand_key += chars[rand_pos:(rand_pos+1)]
79+
80+
# Reset the RNG
81+
random.seed()
82+
83+
# Set the value
84+
return rand_key

wsgi/openshift/settings.py

+12-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# -*- coding: utf-8 -*-
22
# Django settings for openshift project.
3-
import os
3+
import imp, os
44

55
# a setting to determine whether we are running on OpenShift
66
ON_OPENSHIFT = False
@@ -104,8 +104,18 @@
104104
#'django.contrib.staticfiles.finders.DefaultStorageFinder',
105105
)
106106

107+
# Make a dictionary of default keys
108+
default_keys = { 'SECRET_KEY': 'vm4rl5*ymb@2&d_(gc$gb-^twq9w(u69hi--%$5xrh!xk(t%hw' }
109+
110+
# Replace default keys with dynamic values if we are in OpenShift
111+
use_keys = default_keys
112+
if ON_OPENSHIFT:
113+
imp.find_module('openshiftlibs')
114+
import openshiftlibs
115+
use_keys = openshiftlibs.openshift_secure(default_keys)
116+
107117
# Make this unique, and don't share it with anybody.
108-
SECRET_KEY = 'vm4rl5*ymb@2&d_(gc$gb-^twq9w(u69hi--%$5xrh!xk(t%hw'
118+
SECRET_KEY = use_keys['SECRET_KEY']
109119

110120
# List of callables that know how to import templates from various sources.
111121
TEMPLATE_LOADERS = (

0 commit comments

Comments
 (0)