-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit fabbec9
Showing
8 changed files
with
331 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import hmac | ||
import hashlib | ||
import md5 | ||
import urllib2 | ||
|
||
from django.conf import settings | ||
import phpserialize | ||
|
||
from models import WpOptions, WpUsers, WpUsermeta | ||
|
||
|
||
SITE_URL = WpOptions.objects.using('wordpress')\ | ||
.get(option_name='siteurl').option_value | ||
COOKIEHASH = md5.new(SITE_URL).hexdigest() | ||
LOGIN_URL = SITE_URL + "/wp-login.php" | ||
|
||
|
||
def _hmac(salt, data): | ||
return hmac.new(salt, msg=data, digestmod=hashlib.md5).hexdigest() | ||
|
||
|
||
def _generate_auth_cookie(username, password, expires): | ||
expires = str(expires) | ||
wp_salt = settings.LOGGED_IN_KEY + settings.LOGGED_IN_SALT | ||
pass_fragment = password[8:12] | ||
wp_hash = _hmac(wp_salt, username + pass_fragment + "|" + expires) | ||
auth_cookie = _hmac(wp_hash, username + "|" + expires) | ||
return auth_cookie | ||
|
||
|
||
def get_wordpress_user(request): | ||
cookie_key = 'wordpress_logged_in_' + COOKIEHASH | ||
cookie_value = request.COOKIES.get(cookie_key) | ||
if not cookie_value: | ||
return None | ||
username, expires, hmac = urllib2.unquote(cookie_value).split('|') | ||
wp_user = WpUsers.objects.using('wordpress').get(login=username) | ||
if hmac == _generate_auth_cookie(username, wp_user.password, expires): | ||
return wp_user | ||
else: | ||
return None |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
from django.core.exceptions import PermissionDenied | ||
from django.shortcuts import redirect | ||
|
||
from . import get_wordpress_user, LOGIN_URL | ||
|
||
|
||
def wordpress_login_required(fn, *args, **kwargs): | ||
def wrapped(request, *args, **kwargs): | ||
if not request.wordpress_user: | ||
redirect_to = request.build_absolute_uri(request.path) | ||
return redirect(LOGIN_URL + "?redirect_to=" + redirect_to) | ||
else: | ||
return fn(request, *args, **kwargs) | ||
return wrapped | ||
|
||
|
||
def wordpress_requires_role(role): | ||
def real_decorator(fn, *args, **kwargs): | ||
def wrapped(request, *args, **kwargs): | ||
if role in request.wordpress_user.roles: | ||
return fn(request, *args, **kwargs) | ||
else: | ||
raise PermissionDenied() | ||
return wrapped | ||
return real_decorator | ||
|
||
|
||
def wordpress_requires_capability(capability): | ||
def real_decorator(fn, *args, **kwargs): | ||
def wrapped(request, *args, **kwargs): | ||
if capability in request.wordpress_user.capabilities: | ||
return fn(request, *args, **kwargs) | ||
else: | ||
raise PermissionDenied() | ||
return wrapped | ||
return real_decorator |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
from django.utils.functional import SimpleLazyObject | ||
|
||
from . import get_wordpress_user | ||
|
||
|
||
class WordpressAuthMiddleware(object): | ||
def process_request(self, request): | ||
assert hasattr(request, 'session'), "django-wordpress-auth requires session middleware to be installed. Edit your MIDDLEWARE_CLASSES setting to insert 'django.contrib.sessions.middleware.SessionMiddleware'." | ||
|
||
request.wordpress_user = SimpleLazyObject(lambda: get_wordpress_user(request)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
from django.db import models | ||
|
||
import phpserialize | ||
|
||
|
||
class WpOptions(models.Model): | ||
option_id = models.BigIntegerField(primary_key=True) | ||
option_name = models.CharField(max_length=192, unique=True) | ||
option_value = models.TextField() | ||
autoload = models.CharField(max_length=60) | ||
|
||
class Meta: | ||
db_table = u'wp_options' | ||
|
||
class WpUsermeta(models.Model): | ||
umeta_id = models.BigIntegerField(primary_key=True) | ||
user_id = models.BigIntegerField() | ||
meta_key = models.CharField(max_length=765, blank=True) | ||
meta_value = models.TextField(blank=True) | ||
|
||
class Meta: | ||
db_table = u'wp_usermeta' | ||
|
||
class WpUsers(models.Model): | ||
# Field name made lowercase. | ||
id = models.BigIntegerField(primary_key=True, db_column='ID') | ||
|
||
login = models.CharField(max_length=180, db_column='user_login') | ||
password = models.CharField(max_length=192, db_column='user_pass') | ||
nicename = models.CharField(max_length=150, db_column='user_nicename') | ||
email = models.CharField(max_length=300, db_column='user_email') | ||
url = models.CharField(max_length=300, db_column='user_url') | ||
user_registered = models.DateTimeField(db_column='user_registered') | ||
user_activation_key = models.CharField(max_length=180, | ||
db_column='user_activation_key') | ||
user_status = models.IntegerField(db_column='user_status') | ||
display_name = models.CharField(max_length=750, db_column='display_name') | ||
|
||
class Meta: | ||
db_table = u'wp_users' | ||
|
||
def __str__(self): | ||
return str(self.login) | ||
|
||
@property | ||
def roles(self): | ||
""" Returns a list of all roles for the user. """ | ||
php_serialized_roles = WpUsermeta.objects.using('wordpress').get( | ||
user_id=self.id, meta_key='wp_capabilities').meta_value | ||
roles = phpserialize.loads(php_serialized_roles) | ||
return [role for role, enabled in roles.iteritems() if enabled] | ||
|
||
@property | ||
def capabilities(self): | ||
capabilities = [] | ||
roles_data = phpserialize.loads( | ||
WpOptions.objects.using('wordpress')\ | ||
.get(option_name='wp_user_roles').option_value) | ||
for role in self.roles: | ||
role_capabilities = roles_data.get(role).get('capabilities') | ||
for capability, enabled in role_capabilities.iteritems(): | ||
if enabled: | ||
capabilities.append(capability) | ||
return set(capabilities) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
# Deprecated, can be removed | ||
import os | ||
|
||
APP_NAME = os.path.basename(os.path.abspath(os.path.join(__file__, os.path.pardir))) | ||
|
||
|
||
class WordpressRouter(object): | ||
|
||
def db_for_read(self, model, **hints): | ||
"Point all operations on wordpress models to 'wordpress'" | ||
if model._meta.app_label == APP_NAME: | ||
return 'wordpress' | ||
return None | ||
|
||
def db_for_write(self, model, **hints): | ||
"Point all operations on wordpress models to 'wordpress'" | ||
if model._meta.app_label == APP_NAME: | ||
return 'wordpress' | ||
return None | ||
|
||
def allow_relation(self, obj1, obj2, **hints): | ||
"Allow any relation if a model in wordpress is involved" | ||
if obj1._meta.app_label == APP_NAME or obj2._meta.app_label == APP_NAME: | ||
return True | ||
return None | ||
|
||
def allow_syncdb(self, db, model): | ||
"We don't create the wordpress tables via Django." | ||
return model._meta.app_label != APP_NAME |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import os | ||
|
||
APP_NAME = os.path.basename(os.path.abspath(os.path.join(__file__, os.path.pardir))) | ||
|
||
|
||
class WordpressRouter(object): | ||
|
||
def db_for_read(self, model, **hints): | ||
"Point all operations on wordpress models to 'wordpress'" | ||
if model._meta.app_label == APP_NAME: | ||
return 'wordpress' | ||
return None | ||
|
||
def db_for_write(self, model, **hints): | ||
"Point all operations on wordpress models to 'wordpress'" | ||
if model._meta.app_label == APP_NAME: | ||
return 'wordpress' | ||
return None | ||
|
||
def allow_relation(self, obj1, obj2, **hints): | ||
"Allow any relation if a model in wordpress is involved" | ||
if obj1._meta.app_label == APP_NAME or obj2._meta.app_label == APP_NAME: | ||
return True | ||
return None | ||
|
||
def allow_syncdb(self, db, model): | ||
"We don't create the wordpress tables via Django." | ||
return model._meta.app_label != APP_NAME |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
from django.http import HttpResponse | ||
|
||
from . import get_wordpress_user | ||
from decorators import wordpress_login_required, wordpress_requires_role, \ | ||
wordpress_requires_capability | ||
|
||
|
||
@wordpress_login_required | ||
def show_session(request): | ||
return HttpResponse(request.wordpress_user.login) | ||
|
||
|
||
@wordpress_requires_role('lima_member') | ||
def test_roles(request): | ||
return HttpResponse('Success') | ||
|
||
|
||
@wordpress_requires_capability('view_cls_records') | ||
def test_capabilities(request): | ||
return HttpResponse('Success') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
===================== | ||
Django Wordpress Auth | ||
===================== | ||
|
||
Introduction | ||
============ | ||
|
||
Allows for access in Django to a Wordpress installation for checking for | ||
things like login status and roles / capabilities. | ||
|
||
Requirements | ||
============ | ||
|
||
Python Dependencies : | ||
|
||
* `phpserialize`_ | ||
|
||
Wordpress Dependencies : | ||
|
||
* `root Cookie`_ | ||
* `Members`_ | ||
|
||
.. _`phpserialize`: http://pypi.python.org/pypi/phpserialize | ||
.. _`root Cookie`: http://wordpress.org/extend/plugins/root-cookie/ | ||
.. _`Members`: http://wordpress.org/extend/plugins/members/ | ||
|
||
Installation | ||
============ | ||
|
||
Add your wordpress's auth keys and salts (found in wp-config.php). | ||
|
||
.. sourcecode:: python | ||
|
||
LOGGED_IN_KEY = "rs&^D%jPdu=vk|VVDsdfsdgsdgsdg9sd87f98s7h[Xm$3gT/@1xdasd" | ||
LOGGED_IN_SALT = "3]x^n{d8=su23902iu09jdc09asjd09asjd09jasdV-Lv-OydAQ%?~" | ||
|
||
Add your wordpress database. | ||
|
||
.. sourcecode:: python | ||
|
||
DATABASES = { | ||
'default': { | ||
... # default django DB | ||
}, | ||
'wordpress': { # must be named 'wordpress' | ||
'ENGINE': 'django.db.backends.mysql', | ||
'NAME': 'wordpress', | ||
'USER': 'XXX', | ||
'PASSWORD': 'XXX', | ||
'HOST': '', | ||
'PORT': '', | ||
} | ||
} | ||
|
||
Add the middleware. Make sure it's placed somewhere after the session | ||
middleware. | ||
|
||
.. sourcecode:: python | ||
|
||
MIDDLEWARE_CLASSES = ( | ||
'django.contrib.sessions.middleware.SessionMiddleware', | ||
# ... | ||
'django_wordpress_auth.middleware.WordpressAuthMiddleware', | ||
) | ||
|
||
Finally, add to installed apps. | ||
|
||
.. sourcecode:: python | ||
|
||
INSTALLED_APPS = ( | ||
# ... | ||
'django_wordpress_auth', | ||
) | ||
|
||
Usage | ||
===== | ||
|
||
To restrict a view to a certain role, simply wrap the view in the | ||
``wordpress_requires_role`` decorator. | ||
|
||
.. sourcecode:: python | ||
|
||
from django_wordpress_auth.decorators import wordpress_requires_role | ||
|
||
@wordpress_requires_role('my_role') | ||
def my_view(): | ||
pass | ||
|
||
You can restrict a view to a capability as well. | ||
|
||
.. sourcecode:: python | ||
|
||
from django_wordpress_auth.decorators import wordpress_requires_capability | ||
|
||
@wordpress_requires_capability('my_capability') | ||
def my_view(): | ||
pass | ||
|
||
Finally, the middleware provides access to the wordpress user via | ||
``request.wordpress_user``. | ||
|
||
See ``models.py`` for full reference. Some of the redundant naming conventions | ||
in the wordpress database have been made simpler as well. |