From bad4f25e6eba143f7892d148fa9b4f4db75ef63e Mon Sep 17 00:00:00 2001 From: Oleksiy Solyanyk Date: Mon, 18 Jul 2011 22:47:20 +0300 Subject: [PATCH 01/13] Added support for groups --- README.rst | 5 +++ django_odesk/auth/backends.py | 26 +++++++++++-- django_odesk/auth/utils.py | 53 +++++++++++++++++++++++++++ django_odesk/conf/default_settings.py | 18 +++++++-- 4 files changed, 95 insertions(+), 7 deletions(-) create mode 100644 django_odesk/auth/utils.py diff --git a/README.rst b/README.rst index 36b7d59..3f5dfae 100644 --- a/README.rst +++ b/README.rst @@ -111,6 +111,11 @@ For simple cases you may just set login page to the LOGIN_URL = '/odesk_auth/authenticate/' +Groups +------ + + +.. TODO Documenation Authentication without a database --------------------------------- diff --git a/django_odesk/auth/backends.py b/django_odesk/auth/backends.py index c156c21..9746a6f 100644 --- a/django_odesk/auth/backends.py +++ b/django_odesk/auth/backends.py @@ -6,6 +6,7 @@ from django.contrib.auth.backends import ModelBackend from django_odesk.auth.models import get_user_model +from django_odesk.auth.utils import sync_odesk_permissions from django_odesk.conf import settings from django_odesk.core.clients import DefaultClient @@ -98,6 +99,8 @@ def has_module_perms(self, user_obj, app_label): class BaseModelBackend(ModelBackend): create_unknown_user = True + create_unknown_group = True + sync_permissions_on_login = True def authenticate(self, token=None): client = DefaultClient(token) @@ -113,18 +116,22 @@ def authenticate(self, token=None): if self.create_unknown_user: user, created = model.objects.get_or_create(username=username) if created: - user = self.configure_user(user, auth_user) + user = self.configure_user(user, auth_user, token) else: try: user = model.objects.get(username=username) except model.DoesNotExist: pass + + if self.sync_permissions_on_login: + sync_odesk_permissions(user, token, self.create_unknown_group) + return user def clean_username(self, auth_user): - return auth_user['mail'] + return auth_user['uid']+'@odesk.com' - def configure_user(self, user, auth_user): + def configure_user(self, user, auth_user, token): return user def get_user(self, user_id): @@ -136,12 +143,22 @@ def get_user(self, user_id): class ModelBackend(BaseModelBackend): + + supports_object_permissions = False @property def create_unknown_user(self): return settings.ODESK_CREATE_UNKNOWN_USER + + @property + def create_unknown_group(self): + return settings.ODESK_CREATE_UNKNOWN_GROUP + + @property + def sync_permissions_on_login(self): + return settings.ODESK_SYNC_PERMISSIONS_ON_LOGIN - def configure_user(self, user, auth_user): + def configure_user(self, user, auth_user, token): user.first_name = auth_user['first_name'] user.last_name = auth_user['last_name'] user.email = auth_user['mail'] @@ -153,4 +170,5 @@ def configure_user(self, user, auth_user): user.is_superuser = True user.set_unusable_password() user.save() + sync_odesk_permissions(user, token, self.create_unknown_group) return user diff --git a/django_odesk/auth/utils.py b/django_odesk/auth/utils.py new file mode 100644 index 0000000..58cc5e7 --- /dev/null +++ b/django_odesk/auth/utils.py @@ -0,0 +1,53 @@ +from django.db import IntegrityError +from django.contrib.auth.models import Group + +from django_odesk.core.clients import DefaultClient + +def get_odesk_permissions(auth_token): + """ + Gets oDesk team roles/permissions for the authenticated user + """ + client = DefaultClient(auth_token) + response = client.hr.get_user_role() + permissions = [] + for record in response['userrole']: + data = dict(team_id = record['team__id'], role=record['role']) + if record['permissions']: + data['permissions'] = record['permissions']['permission'] + permissions.append(data) + return permissions + + + +def sync_odesk_permissions(user, auth_token, create_groups=True): + """ + Syncs oDesk team roles/permissions with Django groups + """ + permissions = get_odesk_permissions(auth_token) + user.groups.through.objects.filter(group__name__contains = '@odesk.com').delete() + + def get_or_create_group(name): + created = False + group = None + try: + group = Group.objects.get(name=name) + except Group.DoesNotExist: + if create_groups: + group = Group(name=name) + group.save() + return group, created + + for perm in permissions: + name = '%s@odesk.com' % perm['team_id'] + group, c = get_or_create_group(name=name) + if group: + user.groups.add(group) + #Adding special groups for admins + #May later add other pseudo-roles + if perm['role'] == 'admin': + name = '%s:%s@odesk.com' % (perm['team_id'], 'admins') + group, c = get_or_create_group(name=name) + if group: + user.groups.add(group) + return True + diff --git a/django_odesk/conf/default_settings.py b/django_odesk/conf/default_settings.py index 107ec18..14fd93f 100644 --- a/django_odesk/conf/default_settings.py +++ b/django_odesk/conf/default_settings.py @@ -1,10 +1,22 @@ - -#TODO: Annotate settings - +#oDesk API keys ODESK_PUBLIC_KEY = '' ODESK_PRIVATE_KEY = '' +#Whether a new user should be created if doesn't exist in the DB yet ODESK_CREATE_UNKNOWN_USER = True + +#Define oDesk users who will get staff status when added to the DB ODESK_ADMINS = () + +#Define oDesk users who will get superuser status when added to the DB ODESK_SUPERUSERS = () + +#Use to define your own `User` model ODESK_CUSTOM_USER_MODEL = None + +#Whether a new group should be created if doesn't exist in the DB yet +ODESK_CREATE_UNKNOWN_GROUP = True + +#Do we want permissions (groups) to be synced with oDesk +#each time user logs in +ODESK_SYNC_PERMISSIONS_ON_LOGIN = False From c05f9c9439519317708695cfd06e6f2f842f1b62 Mon Sep 17 00:00:00 2001 From: Oleksiy Solyanyk Date: Thu, 21 Jul 2011 08:31:11 -0700 Subject: [PATCH 02/13] Added documentation for the groups --- README.rst | 46 +++++++++++++++++++++++++++++++-- django_odesk/__init__.py | 2 +- django_odesk/auth/decorators.py | 12 +++++++++ 3 files changed, 57 insertions(+), 3 deletions(-) create mode 100644 django_odesk/auth/decorators.py diff --git a/README.rst b/README.rst index 3f5dfae..0785070 100644 --- a/README.rst +++ b/README.rst @@ -114,12 +114,54 @@ For simple cases you may just set login page to the Groups ------ +`django-odesk` has support for Django groups. Groups are direct mapping +of oDesk teams. For each team the user is a member of, the corresponding +`django.contrib.auth.models.Group` is created with the name in the form:: + + company:team@odesk.com + +The synchronyzation between oDesk teams and user groups is happening on +user object's creation by default. You can make it happen each time the +user logs in by setting:: + + ODESK_SYNC_PERMISSIONS_ON_LOGIN = True + +Similar to creation of the unknown user, you can disable automatic creation +of new groups by setting:: + + ODESK_CREATE_UNKNOWN_GROUP = True + +Since Django's authentication system has no support for roles, `django-odeask` +has limited support for "pseudo-roles". If the user has "admin" role in oDesk +team, they become the member of additional group, with the name of the from:: + + company:team:admins@odesk.com + +Currently only admin role is supported. + +It is sometimes desirable to limit the view only to the members of the +specific oDesk team. `django-odesk` provides the convenient decorator to +check for group membership:: + + from django_odesk.auth.decorators import group_required + + @group_required('company:team@odesk.com') + def my_view(request) + ... + +You can also give the list of group names. The user passes test if they +belong to at least one of them:: + + from django_odesk.auth.decorators import group_required + + @group_required(['company:team@odesk.com','company:team2@odesk.com']) + def my_view(request) + ... -.. TODO Documenation Authentication without a database --------------------------------- - +. If for some reason you don't want to use Django's `User` model or the database layer at all, you can still use oDesk authentication. All you need to change is an authentication backend. Use `SimpleBackend` diff --git a/django_odesk/__init__.py b/django_odesk/__init__.py index 6dc8a41..41f3b83 100644 --- a/django_odesk/__init__.py +++ b/django_odesk/__init__.py @@ -1,4 +1,4 @@ -VERSION = (0, 0, 1, 'alpha', 1) +VERSION = (0, 0, 2, 'alpha', 1) def get_version(): version = '%s.%s' % (VERSION[0], VERSION[1]) diff --git a/django_odesk/auth/decorators.py b/django_odesk/auth/decorators.py new file mode 100644 index 0000000..172d050 --- /dev/null +++ b/django_odesk/auth/decorators.py @@ -0,0 +1,12 @@ +from django.contrib.auth.decorators import user_passes_test +from django.contrib.auth.models import Group + +def group_required(names, login_url=None): + """ + Checks if the user is a member of a particular group (or at least one + group from the list) + """ + if not hasattr(names,'__iter__'): + names = [names] + return user_passes_test(lambda u: u.groups.filter(name__in=names), + login_url=login_url) From 467949337f261f28524544996e4e888480783590 Mon Sep 17 00:00:00 2001 From: Oleksiy Solyanyk Date: Thu, 21 Jul 2011 13:53:53 -0700 Subject: [PATCH 03/13] A typo in the documentation --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 0785070..a88ce95 100644 --- a/README.rst +++ b/README.rst @@ -129,7 +129,7 @@ user logs in by setting:: Similar to creation of the unknown user, you can disable automatic creation of new groups by setting:: - ODESK_CREATE_UNKNOWN_GROUP = True + ODESK_CREATE_UNKNOWN_GROUP = False Since Django's authentication system has no support for roles, `django-odeask` has limited support for "pseudo-roles". If the user has "admin" role in oDesk From 533324226e63b5f7d20d676d0801789ca5acb5c0 Mon Sep 17 00:00:00 2001 From: Oleksiy Solyanyk Date: Thu, 4 Aug 2011 15:17:54 -0700 Subject: [PATCH 04/13] Added settings for pseudo-groups and auth-only mode --- README.rst | 28 +++++++++++++++++++++++++-- django_odesk/__init__.py | 2 +- django_odesk/auth/utils.py | 18 ++++++++--------- django_odesk/auth/views.py | 4 +++- django_odesk/conf/default_settings.py | 8 ++++++++ setup.py | 6 +++--- 6 files changed, 50 insertions(+), 16 deletions(-) diff --git a/README.rst b/README.rst index a88ce95..3df850a 100644 --- a/README.rst +++ b/README.rst @@ -137,7 +137,11 @@ team, they become the member of additional group, with the name of the from:: company:team:admins@odesk.com -Currently only admin role is supported. +Currently only admin role is supported. + +In order turn on the "pseudo-groups" feature, set the corresponding variable:: + + ODESK_CREATE_PSEUDO_GROUPS = True It is sometimes desirable to limit the view only to the members of the specific oDesk team. `django-odesk` provides the convenient decorator to @@ -158,10 +162,30 @@ belong to at least one of them:: def my_view(request) ... +Auth-only mode +-------------- + +Using oDesk APIs imposes an inherent secuirty risk. The person who has access +to the application server is capable of performing arbitrary actions on oDesk +on behalf of everyone who've been using the application, uless the users have +de-authorized the application expicitly. But sometimes all you need is just +to authenticate oDesk users and not make any other API calls. You can reduce +the mentioned risk, by not storing the API token anywhere after user has +logged in. + +Since version 0.0.2 `django-odesk` supports "auth-only" mode that works +exactly like that. To turn it on, set:: + + ODESK_AUTH_ONLY = True + +Please note that if you use `django_odesk.core.clients.RequestClient`, either +directly or with `RequestClientMiddleware` in auth-only mode, the client will +only be capable of calling public API methods. + Authentication without a database --------------------------------- -. + If for some reason you don't want to use Django's `User` model or the database layer at all, you can still use oDesk authentication. All you need to change is an authentication backend. Use `SimpleBackend` diff --git a/django_odesk/__init__.py b/django_odesk/__init__.py index 41f3b83..8d9e382 100644 --- a/django_odesk/__init__.py +++ b/django_odesk/__init__.py @@ -1,4 +1,4 @@ -VERSION = (0, 0, 2, 'alpha', 1) +VERSION = (0, 0, 2, 'beta', 0) def get_version(): version = '%s.%s' % (VERSION[0], VERSION[1]) diff --git a/django_odesk/auth/utils.py b/django_odesk/auth/utils.py index 58cc5e7..59f482d 100644 --- a/django_odesk/auth/utils.py +++ b/django_odesk/auth/utils.py @@ -2,6 +2,7 @@ from django.contrib.auth.models import Group from django_odesk.core.clients import DefaultClient +from django_odesk.conf import settings def get_odesk_permissions(auth_token): """ @@ -35,19 +36,18 @@ def get_or_create_group(name): if create_groups: group = Group(name=name) group.save() + if group: + user.groups.add(group) return group, created for perm in permissions: name = '%s@odesk.com' % perm['team_id'] group, c = get_or_create_group(name=name) - if group: - user.groups.add(group) - #Adding special groups for admins - #May later add other pseudo-roles - if perm['role'] == 'admin': - name = '%s:%s@odesk.com' % (perm['team_id'], 'admins') - group, c = get_or_create_group(name=name) - if group: - user.groups.add(group) + if settings.ODESK_CREATE_PSEUDO_GROUPS: + #Adding special groups for admins + #May later add other pseudo-roles + if perm['role'] == 'admin': + name = '%s:%s@odesk.com' % (perm['team_id'], 'admins') + group, c = get_or_create_group(name=name) return True diff --git a/django_odesk/auth/views.py b/django_odesk/auth/views.py index 504d29b..5d894b8 100644 --- a/django_odesk/auth/views.py +++ b/django_odesk/auth/views.py @@ -4,6 +4,7 @@ from django_odesk.core.clients import DefaultClient from django_odesk.auth import ODESK_REDIRECT_SESSION_KEY, \ ODESK_TOKEN_SESSION_KEY +from django_odesk.conf import settings def authenticate(request): redirect_to = request.REQUEST.get(REDIRECT_FIELD_NAME, '') @@ -17,7 +18,8 @@ def callback(request, redirect_url=None): frob = request.GET.get('frob', None) if frob: token, auth_user = odesk_client.auth.get_token(frob) - request.session[ODESK_TOKEN_SESSION_KEY] = token + if not settings.ODESK_AUTH_ONLY: + request.session[ODESK_TOKEN_SESSION_KEY] = token #TODO: Get rid of (conceptually correct) additional request to odesk.com user = django_authenticate(token = token) if user: diff --git a/django_odesk/conf/default_settings.py b/django_odesk/conf/default_settings.py index 14fd93f..76ca5fb 100644 --- a/django_odesk/conf/default_settings.py +++ b/django_odesk/conf/default_settings.py @@ -5,6 +5,11 @@ #Whether a new user should be created if doesn't exist in the DB yet ODESK_CREATE_UNKNOWN_USER = True +#Setting this to True would prevent the backend from storing the +#authentication token in the session, so no API calls would be possible. +#Use if all you want is authentication +ODESK_AUTH_ONLY = False + #Define oDesk users who will get staff status when added to the DB ODESK_ADMINS = () @@ -17,6 +22,9 @@ #Whether a new group should be created if doesn't exist in the DB yet ODESK_CREATE_UNKNOWN_GROUP = True +#Define whether "pseudo-groups" (like company:team:admins) are created +ODESK_CREATE_PSEUDO_GROUPS = False + #Do we want permissions (groups) to be synced with oDesk #each time user logs in ODESK_SYNC_PERMISSIONS_ON_LOGIN = False diff --git a/setup.py b/setup.py index 8a55461..9c8897b 100644 --- a/setup.py +++ b/setup.py @@ -1,4 +1,4 @@ -from distutils.core import setup +from setuptools import setup, find_packages version = __import__('django_odesk').get_version() @@ -8,8 +8,8 @@ long_description='', author='Oleksiy Solyanyk', author_email='solex@odesk.com', - packages = ['django_odesk','django_odesk.auth', 'django_odesk.core', 'django_odesk.conf'], - install_requires = ['python-odesk>=0.1.2', ], + packages = find_packages(), + install_requires = ['setuptools','python-odesk>=0.1.2', ], classifiers=['Development Status :: 1 - Alpha', 'Environment :: Web Environment', 'Intended Audience :: Developers', From de98e9ee2c919fb6fa135209f1673f23e76127af Mon Sep 17 00:00:00 2001 From: Oleksiy Solyanyk Date: Wed, 17 Aug 2011 11:20:25 +0300 Subject: [PATCH 05/13] Version changed to final --- django_odesk/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/django_odesk/__init__.py b/django_odesk/__init__.py index 8d9e382..da6558b 100644 --- a/django_odesk/__init__.py +++ b/django_odesk/__init__.py @@ -1,4 +1,4 @@ -VERSION = (0, 0, 2, 'beta', 0) +VERSION = (0, 0, 2, 'final', 0) def get_version(): version = '%s.%s' % (VERSION[0], VERSION[1]) From 80c6874e13b62ee3e688cd556c1b2b0c818312a2 Mon Sep 17 00:00:00 2001 From: Yury Yurevich Date: Fri, 9 Sep 2011 02:28:30 +0700 Subject: [PATCH 06/13] Handle roles for users with single team. --- django_odesk/auth/utils.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/django_odesk/auth/utils.py b/django_odesk/auth/utils.py index 59f482d..1cb0c78 100644 --- a/django_odesk/auth/utils.py +++ b/django_odesk/auth/utils.py @@ -11,7 +11,11 @@ def get_odesk_permissions(auth_token): client = DefaultClient(auth_token) response = client.hr.get_user_role() permissions = [] - for record in response['userrole']: + roles = response['userrole'] + # oDesk API returns dict if there is single role + if isinstance(roles, dict): + roles = [roles] + for record in roles: data = dict(team_id = record['team__id'], role=record['role']) if record['permissions']: data['permissions'] = record['permissions']['permission'] From 2ade33422da12e81a46b75b62b48b07ba7e1772b Mon Sep 17 00:00:00 2001 From: Yury Yurevich Date: Fri, 9 Sep 2011 02:46:59 +0700 Subject: [PATCH 07/13] Handle users without membership. --- django_odesk/auth/utils.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/django_odesk/auth/utils.py b/django_odesk/auth/utils.py index 1cb0c78..d02d557 100644 --- a/django_odesk/auth/utils.py +++ b/django_odesk/auth/utils.py @@ -11,6 +11,9 @@ def get_odesk_permissions(auth_token): client = DefaultClient(auth_token) response = client.hr.get_user_role() permissions = [] + # oDesk API returns empty string if user has no membership in any group + if not response: + return [] roles = response['userrole'] # oDesk API returns dict if there is single role if isinstance(roles, dict): From 0df73bd0e1976c6f35e92d53b388a426c1312a62 Mon Sep 17 00:00:00 2001 From: Kostia Balitsky Date: Thu, 22 Sep 2011 21:13:56 +0300 Subject: [PATCH 08/13] Fixed a bug with clients --- django_odesk/core/clients.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/django_odesk/core/clients.py b/django_odesk/core/clients.py index b425339..ad855eb 100644 --- a/django_odesk/core/clients.py +++ b/django_odesk/core/clients.py @@ -6,6 +6,11 @@ from django_odesk.auth import ODESK_TOKEN_SESSION_KEY, ENCRYPTION_KEY_NAME from django_odesk.auth.encrypt import decrypt_token +try: + ENCRYPT_API_TOKEN = settings.ENCRYPT_API_TOKEN +except AttributeError, e: + ENCRYPT_API_TOKEN = False + class DefaultClient(Client): def __init__(self, api_token=None): @@ -21,10 +26,14 @@ def __init__(self, api_token=None): class RequestClient(DefaultClient): def __init__(self, request): - encryption_key = request.COOKIES.get(ENCRYPTION_KEY_NAME, None) - encrypted_token = request.session.get(ODESK_TOKEN_SESSION_KEY, None) - api_token = None - if encryption_key and encrypted_token: - api_token = decrypt_token(encryption_key, encrypted_token) + from_session = request.session.get(ODESK_TOKEN_SESSION_KEY, None) + if ENCRYPT_API_TOKEN: + encryption_key = request.COOKIES.get(ENCRYPTION_KEY_NAME, None) + encrypted_token = from_session + api_token = None + if encryption_key and encrypted_token: + api_token = decrypt_token(encryption_key, encrypted_token) + else: + api_token = from_session super(RequestClient, self).__init__(api_token) From 4964846bef4574b0fd3cc20bb1b117266bea70d3 Mon Sep 17 00:00:00 2001 From: Kostia Balitsky Date: Fri, 23 Sep 2011 10:59:20 +0300 Subject: [PATCH 09/13] Changed option name to uniform one, changed default settings usage, changed README.rst --- README.rst | 9 +++++++++ django_odesk/auth/views.py | 9 ++------- django_odesk/conf/default_settings.py | 3 +++ django_odesk/core/clients.py | 6 +----- 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/README.rst b/README.rst index 3df850a..2f6d0be 100644 --- a/README.rst +++ b/README.rst @@ -6,6 +6,7 @@ Requirements ============ * `python-odesk` + * `PyCrypto` Authentication @@ -261,6 +262,14 @@ used in conjunction with `django_odesk.auth`:: client.team.get_teamrooms() # ... +Note that the token is stored in django session encrypted (by default). The +encryption method used is AES. This key is stored in client +browser cookies and has expiration time set to two hours. +You can disable the encryption via specifying the following option +in your settings.py file: + + ODESK_ENCRYPT_API_TOKEN = False + If you plan to use odesk API calls extensively in your views, there is another shortcut, the `django_odesk.core.middleware.RequestClientMiddleware`. It populates `request` with `odesk_client` attribute, which is an instance diff --git a/django_odesk/auth/views.py b/django_odesk/auth/views.py index 8734c27..98da3ca 100644 --- a/django_odesk/auth/views.py +++ b/django_odesk/auth/views.py @@ -11,11 +11,6 @@ from django_odesk.conf import settings from encrypt import encrypt_token -try: - ENCRYPT_API_TOKEN = settings.ENCRYPT_API_TOKEN -except AttributeError, e: - ENCRYPT_API_TOKEN = False - def authenticate(request): redirect_to = request.REQUEST.get(REDIRECT_FIELD_NAME, '') request.session[ODESK_REDIRECT_SESSION_KEY] = redirect_to @@ -38,7 +33,7 @@ def callback(request, redirect_url=None): logging.error(msg) return HttpResponseRedirect(redirect_url or '/') if not settings.ODESK_AUTH_ONLY: - if ENCRYPT_API_TOKEN: + if settings.ODESK_ENCRYPT_API_TOKEN: encryption_key, encrypted_token = encrypt_token(token) put_in_session = encrypted_token else: @@ -55,7 +50,7 @@ def callback(request, redirect_url=None): redirect_url = request.session.pop(ODESK_REDIRECT_SESSION_KEY, redirect_url) response = HttpResponseRedirect(redirect_url or '/') - if not settings.ODESK_AUTH_ONLY and ENCRYPT_API_TOKEN: + if not settings.ODESK_AUTH_ONLY and settings.ODESK_ENCRYPT_API_TOKEN: expires = datetime.timedelta(hours = 2) + datetime.datetime.utcnow() # this is for Django 1.3 # string conversion for django 1.2 somehow doesn't work either, so I use max_age response.set_cookie(ENCRYPTION_KEY_NAME, encryption_key, expires = expires, max_age = 60*60*2) diff --git a/django_odesk/conf/default_settings.py b/django_odesk/conf/default_settings.py index 76ca5fb..b7d8abd 100644 --- a/django_odesk/conf/default_settings.py +++ b/django_odesk/conf/default_settings.py @@ -28,3 +28,6 @@ #Do we want permissions (groups) to be synced with oDesk #each time user logs in ODESK_SYNC_PERMISSIONS_ON_LOGIN = False + +#Whether oDesk api_token should be encrypted or not +ODESK_ENCRYPT_API_TOKEN = True diff --git a/django_odesk/core/clients.py b/django_odesk/core/clients.py index ad855eb..4e7278c 100644 --- a/django_odesk/core/clients.py +++ b/django_odesk/core/clients.py @@ -6,10 +6,6 @@ from django_odesk.auth import ODESK_TOKEN_SESSION_KEY, ENCRYPTION_KEY_NAME from django_odesk.auth.encrypt import decrypt_token -try: - ENCRYPT_API_TOKEN = settings.ENCRYPT_API_TOKEN -except AttributeError, e: - ENCRYPT_API_TOKEN = False class DefaultClient(Client): @@ -27,7 +23,7 @@ class RequestClient(DefaultClient): def __init__(self, request): from_session = request.session.get(ODESK_TOKEN_SESSION_KEY, None) - if ENCRYPT_API_TOKEN: + if settings.ODESK_ENCRYPT_API_TOKEN: encryption_key = request.COOKIES.get(ENCRYPTION_KEY_NAME, None) encrypted_token = from_session api_token = None From 91688aed72e965f3e9bd02dfdcb078355cedcca4 Mon Sep 17 00:00:00 2001 From: Oleksiy Solyanyk Date: Fri, 23 Sep 2011 11:13:00 +0300 Subject: [PATCH 10/13] Added pycrypto dependency --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 9c8897b..0bd82e1 100644 --- a/setup.py +++ b/setup.py @@ -9,7 +9,7 @@ author='Oleksiy Solyanyk', author_email='solex@odesk.com', packages = find_packages(), - install_requires = ['setuptools','python-odesk>=0.1.2', ], + install_requires = ['setuptools','python-odesk>=0.1.2', 'pycrypto'], classifiers=['Development Status :: 1 - Alpha', 'Environment :: Web Environment', 'Intended Audience :: Developers', From 9d967dac37255b428cd740c486a76da167e753dd Mon Sep 17 00:00:00 2001 From: Kostia Balitsky Date: Mon, 17 Oct 2011 14:34:36 +0300 Subject: [PATCH 11/13] Added note about situation with django tests to README.rst --- README.rst | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/README.rst b/README.rst index 2f6d0be..1b76d9e 100644 --- a/README.rst +++ b/README.rst @@ -45,6 +45,10 @@ To do so, add the `django_odesk.auth.backends.ModelBackend` to your 'django_odesk.auth.backends.ModelBackend', ) +.. note:: + Please, note that `django_odesk` authentication backend may cause failing + Django tests. Please, read a paragraph below to find out why this happens. + You will also need to enable both `SessionMiddleware` and `AuthenticationMiddleware`:: @@ -289,3 +293,25 @@ Then you may use the client in your views:: request.odesk_client.team.get_teamrooms() # ... +Django Tests Failure +==================== + +If your project is using `django_odesk` with it's model authentication backend +`django_odesk.auth.backends.ModelBackend`, you will face problems with running +standard Django's tests (in particular - `django.contrib.auth` tests): + + `$ python manage.py test` + +will give you lot's of errors. +This happens due to the nature of `django.contrib.auth` tests. While officially +Django's auth system supports third-party backends, its tests are intended to +check only standard (or very close to standard) backend. Really, `here `_ +you can see intension to authenticate user via username/password pair which +is of course incorrect in our case. + +There is no way to prevent this by changing `django_odesk` package. Thus one who uses +`django_odesk` has two possible choices: + +- ignore tests failure +- add Django's standard `django.contrib.auth.backends.ModelBackend` to the end of + `AUTHENTICATION_BACKENDS` tuple in your `settings.py` file. From 2c05ff488b12bd3b477a47c36adbe801d105dea9 Mon Sep 17 00:00:00 2001 From: Oleksiy Solyanyk Date: Fri, 28 Oct 2011 16:36:01 -0700 Subject: [PATCH 12/13] Crytical bug in group sync fixed --- django_odesk/auth/utils.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/django_odesk/auth/utils.py b/django_odesk/auth/utils.py index 59f482d..8673942 100644 --- a/django_odesk/auth/utils.py +++ b/django_odesk/auth/utils.py @@ -25,7 +25,8 @@ def sync_odesk_permissions(user, auth_token, create_groups=True): Syncs oDesk team roles/permissions with Django groups """ permissions = get_odesk_permissions(auth_token) - user.groups.through.objects.filter(group__name__contains = '@odesk.com').delete() + user.groups.through.objects.filter(user=user, + group__name__contains = '@odesk.com').delete() def get_or_create_group(name): created = False From 9e1aac8d56f83ffbe3cefc12a6a9be1b9e82bb97 Mon Sep 17 00:00:00 2001 From: Boo Date: Tue, 8 Nov 2011 17:18:52 +0200 Subject: [PATCH 13/13] PyCrypto version must be at least 2.1 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 0bd82e1..9b20219 100644 --- a/setup.py +++ b/setup.py @@ -9,7 +9,7 @@ author='Oleksiy Solyanyk', author_email='solex@odesk.com', packages = find_packages(), - install_requires = ['setuptools','python-odesk>=0.1.2', 'pycrypto'], + install_requires = ['setuptools','python-odesk>=0.1.2', 'pycrypto>=2.1'], classifiers=['Development Status :: 1 - Alpha', 'Environment :: Web Environment', 'Intended Audience :: Developers',