diff --git a/.travis.yml b/.travis.yml
index 34d9022..68188b0 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,6 +1,6 @@
language: python
python:
- - "2.7"
+ - "3.6"
# command to install dependencies
install:
- "pip install -r requirements.txt"
diff --git a/cdu/settings.py b/cdu/settings.py
index 0803bd6..a7839b7 100644
--- a/cdu/settings.py
+++ b/cdu/settings.py
@@ -29,8 +29,7 @@
ALLOWED_HOSTS = []
AUTHENTICATION_BACKENDS = [
- 'django_warrant.backend.CognitoBackend',
- 'django.contrib.auth.backends.ModelBackend'
+ 'django_warrant.backend.CognitoNoModelBackend'
]
COGNITO_TEST_USERNAME = env('COGNITO_TEST_USERNAME')
@@ -39,14 +38,25 @@
COGNITO_USER_POOL_ID = env('COGNITO_USER_POOL_ID')
+COGNITO_ADMIN_GROUP = env('COGNITO_ADMIN_GROUP','Admins')
+
COGNITO_APP_ID = env('COGNITO_APP_ID')
+COGNITO_CLIENT_SECRET = env('COGNITO_CLIENT_SECRET')
+
COGNITO_ATTR_MAPPING = env(
'COGNITO_ATTR_MAPPING',
{
'email': 'email',
'given_name': 'first_name',
'family_name': 'last_name',
+ 'name':'name',
+ 'username':'username',
+ 'address':'address',
+ 'gender':'gender',
+ 'preferred_username':'preferred_username',
+ 'phone_number':'phone_number',
+ 'phone_number_verified':'phone_number_verified',
'custom:api_key': 'api_key',
'custom:api_key_id': 'api_key_id'
},
@@ -75,7 +85,7 @@
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
- 'django.contrib.auth.middleware.AuthenticationMiddleware',
+ 'django_warrant.middleware.CognitoAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
@@ -132,8 +142,8 @@
},
]
-LOGIN_REDIRECT_URL = '/accounts/profile'
-
+LOGIN_REDIRECT_URL = '/'
+LOGIN_URL = '/login/'
# Internationalization
# https://docs.djangoproject.com/en/1.10/topics/i18n/
@@ -154,3 +164,5 @@
STATIC_URL = '/static/'
CRISPY_TEMPLATE_PACK = 'bootstrap3'
+
+# AUTH_USER_MODEL = 'django_warrant.UserObj'
\ No newline at end of file
diff --git a/cdu/urls.py b/cdu/urls.py
index 9414425..9dc1bdb 100644
--- a/cdu/urls.py
+++ b/cdu/urls.py
@@ -18,5 +18,5 @@
urlpatterns = [
url(r'^admin/', admin.site.urls),
- url(r'^accounts/', include('django_warrant.urls',namespace='dw'))
+ url(r'^', include('django_warrant.urls',namespace='dw'))
]
diff --git a/django_warrant/__init__.py b/django_warrant/__init__.py
index 1945ad5..39a4597 100644
--- a/django_warrant/__init__.py
+++ b/django_warrant/__init__.py
@@ -6,7 +6,8 @@ def add_user_tokens(sender, user, **kwargs):
"""
Add Cognito tokens to the session upon login
"""
- if user.backend == 'django_warrant.backend.CognitoBackend':
+ if user.backend in ['django_warrant.backend.CognitoBackend',
+ 'django_warrant.backend.CognitoNoModelBackend']:
request = kwargs['request']
request.session['ACCESS_TOKEN'] = user.access_token
request.session['ID_TOKEN'] = user.id_token
diff --git a/django_warrant/backend.py b/django_warrant/backend.py
index 114aef5..16ec4d7 100644
--- a/django_warrant/backend.py
+++ b/django_warrant/backend.py
@@ -6,48 +6,13 @@
from django.conf import settings
from django.contrib.auth.backends import ModelBackend
from django.contrib.auth import get_user_model
-from django.utils.six import iteritems
+from django.utils.crypto import salted_hmac
+from warrant_lite import WarrantLite
-from warrant import Cognito
+from django_warrant.models import UserObj
from .utils import cognito_to_dict
-class CognitoUser(Cognito):
- user_class = get_user_model()
- # Mapping of Cognito User attribute name to Django User attribute name
- COGNITO_ATTR_MAPPING = getattr(settings, 'COGNITO_ATTR_MAPPING',
- {
- 'email': 'email',
- 'given_name': 'first_name',
- 'family_name': 'last_name',
- }
- )
-
- def get_user_obj(self,username=None,attribute_list=[],metadata={},attr_map={}):
- user_attrs = cognito_to_dict(attribute_list,CognitoUser.COGNITO_ATTR_MAPPING)
- django_fields = [f.name for f in CognitoUser.user_class._meta.get_fields()]
- extra_attrs = {}
- for k, v in user_attrs.items():
- if k not in django_fields:
- extra_attrs.update({k: user_attrs.pop(k, None)})
- if getattr(settings, 'COGNITO_CREATE_UNKNOWN_USERS', True):
- user, created = CognitoUser.user_class.objects.update_or_create(
- username=username,
- defaults=user_attrs)
- else:
- try:
- user = CognitoUser.user_class.objects.get(username=username)
- for k, v in iteritems(user_attrs):
- setattr(user, k, v)
- user.save()
- except CognitoUser.user_class.DoesNotExist:
- user = None
- if user:
- for k, v in extra_attrs.items():
- setattr(user, k, v)
- return user
-
-
class AbstractCognitoBackend(ModelBackend):
__metaclass__ = abc.ABCMeta
@@ -55,7 +20,6 @@ class AbstractCognitoBackend(ModelBackend):
USER_NOT_FOUND_ERROR_CODE = 'UserNotFoundException'
- COGNITO_USER_CLASS = CognitoUser
@abc.abstractmethod
def authenticate(self, username=None, password=None):
@@ -65,24 +29,58 @@ def authenticate(self, username=None, password=None):
:param password: Cognito password
:return: returns User instance of AUTH_USER_MODEL or None
"""
- cognito_user = CognitoUser(
- settings.COGNITO_USER_POOL_ID,
- settings.COGNITO_APP_ID,
- access_key=getattr(settings, 'AWS_ACCESS_KEY_ID', None),
- secret_key=getattr(settings, 'AWS_SECRET_ACCESS_KEY', None),
- username=username)
+ wl = WarrantLite(username=username, password=password,
+ pool_id=settings.COGNITO_USER_POOL_ID,
+ client_id=settings.COGNITO_APP_ID,
+ client_secret=settings.COGNITO_CLIENT_SECRET)
+
try:
- cognito_user.authenticate(password)
+ tokens = wl.authenticate_user()
except (Boto3Error, ClientError) as e:
return self.handle_error_response(e)
- user = cognito_user.get_user()
+
+ access_token = tokens['AuthenticationResult']['AccessToken']
+ refresh_token = tokens['AuthenticationResult']['RefreshToken']
+ id_token = tokens['AuthenticationResult']['IdToken']
+ wl.verify_token(access_token, 'access_token', 'access')
+ wl.verify_token(id_token, 'id_token', 'id')
+
+ cognito_user = wl.client.get_user(
+ AccessToken=access_token
+ )
+ user = self.get_user_obj(username,cognito_user)
if user:
- user.access_token = cognito_user.access_token
- user.id_token = cognito_user.id_token
- user.refresh_token = cognito_user.refresh_token
+ user.access_token = access_token
+ user.id_token = id_token
+ user.refresh_token = refresh_token
return user
+ def get_user_obj(self,username,cognito_user):
+ user_attrs = cognito_to_dict(cognito_user.get('UserAttributes'),
+ settings.COGNITO_ATTR_MAPPING or {
+ 'email':'email',
+ 'given_name':'first_name',
+ 'family_name':'last_name'
+ })
+ User = get_user_model()
+ django_fields = [f.name for f in User._meta.get_fields()]
+ extra_attrs = {}
+ new_user_attrs = user_attrs.copy()
+
+ for k, v in user_attrs.items():
+ if k not in django_fields:
+ extra_attrs.update({k: new_user_attrs.pop(k, None)})
+ user_attrs = new_user_attrs
+ try:
+ u = User.objects.get(username=username)
+ except User.DoesNotExist:
+ u = None
+ if u:
+ for k, v in extra_attrs.items():
+ setattr(u, k, v)
+ return u
+
def handle_error_response(self, error):
error_code = error.response['Error']['Code']
if error_code in [
@@ -107,3 +105,56 @@ def authenticate(self, request, username=None, password=None):
request.session['REFRESH_TOKEN'] = user.refresh_token
request.session.save()
return user
+
+
+class CognitoNoModelBackend(ModelBackend):
+
+ def authenticate(self, request, username=None, password=None):
+ wl = WarrantLite(username=username, password=password,
+ pool_id=settings.COGNITO_USER_POOL_ID,
+ client_id=settings.COGNITO_APP_ID,
+ client_secret=settings.COGNITO_CLIENT_SECRET)
+
+ try:
+ tokens = wl.authenticate_user()
+ except (Boto3Error, ClientError) as e:
+ return self.handle_error_response(e)
+
+ access_token = tokens['AuthenticationResult']['AccessToken']
+ refresh_token = tokens['AuthenticationResult']['RefreshToken']
+ id_token = tokens['AuthenticationResult']['IdToken']
+ wl.verify_token(access_token, 'access_token', 'access')
+ wl.verify_token(id_token, 'id_token', 'id')
+
+ user = UserObj(wl.client.get_user(
+ AccessToken=access_token
+ ),access_token=access_token,is_authenticated=True)
+ user.refresh_token = refresh_token
+ user.access_token = access_token
+ user.id_token = id_token
+ user.session_auth_hash = get_session_auth_hash(password)
+ if user:
+ request.session['ACCESS_TOKEN'] = user.access_token
+ request.session['ID_TOKEN'] = user.id_token
+ request.session['REFRESH_TOKEN'] = user.refresh_token
+ request.session.save()
+ return user
+
+ def user_can_authenticate(self, user):
+ """
+ Reject users with is_active=False. Custom user models that don't have
+ that attribute are allowed.
+ """
+ is_active = getattr(user, 'is_active', None)
+ return is_active or is_active is None
+
+ def get_user(self,user_id):
+ pass
+
+
+def get_session_auth_hash(password):
+ """
+ Return an HMAC of the password field.
+ """
+ key_salt = "django.contrib.auth.models.AbstractBaseUser.get_session_auth_hash"
+ return salted_hmac(key_salt, password).hexdigest()
\ No newline at end of file
diff --git a/django_warrant/forms.py b/django_warrant/forms.py
index cfd66c1..3586fde 100644
--- a/django_warrant/forms.py
+++ b/django_warrant/forms.py
@@ -1,14 +1,19 @@
from django import forms
+from django.core.exceptions import ValidationError
+from django.utils.translation import gettext as _
class ProfileForm(forms.Form):
first_name = forms.CharField(max_length=200,required=True)
last_name = forms.CharField(max_length=200,required=True)
email = forms.EmailField(required=True)
- phone_number = forms.CharField(max_length=30,required=True)
+ phone_number = forms.CharField(max_length=30,required=True,help_text='ex. +14325551212')
gender = forms.ChoiceField(choices=(('female','Female'),('male','Male')),required=True)
address = forms.CharField(max_length=200,required=True)
preferred_username = forms.CharField(max_length=200,required=True)
+
+
+class AdminProfileForm(ProfileForm):
api_key = forms.CharField(max_length=200, required=False)
api_key_id = forms.CharField(max_length=200, required=False)
@@ -19,3 +24,38 @@ class APIKeySubscriptionForm(forms.Form):
def __init__(self, plans=[], users_plans=[], *args, **kwargs):
self.base_fields['plan'].choices = [(p.get('id'),p.get('name')) for p in plans if not p.get('id') in users_plans]
super(APIKeySubscriptionForm, self).__init__(*args, **kwargs)
+
+
+class ForgotPasswordForm(forms.Form):
+ username = forms.CharField(max_length=200,required=True)
+
+
+class PasswordForm(forms.Form):
+ password = forms.CharField(widget=forms.PasswordInput, required=True, max_length=200)
+ confirm_password = forms.CharField(widget=forms.PasswordInput, required=True, max_length=200)
+
+ def clean_confirm_password(self):
+ password = self.cleaned_data['password']
+ confirm_password = self.cleaned_data['confirm_password']
+ if password != confirm_password:
+ raise ValidationError(_('The passwords entered do not match.'))
+ return confirm_password
+
+
+class VerificationCodeForm(forms.Form):
+ username = forms.CharField(max_length=200,required=True)
+ verification_code = forms.CharField(max_length=6)
+
+
+class ConfirmForgotPasswordForm(VerificationCodeForm,PasswordForm):
+ pass
+
+
+class RegistrationForm(ProfileForm,PasswordForm,ForgotPasswordForm):
+ pass
+
+
+class UpdatePasswordForm(PasswordForm):
+ previous_password = forms.CharField(max_length=200,
+ widget=forms.PasswordInput,
+ required=True)
\ No newline at end of file
diff --git a/django_warrant/middleware.py b/django_warrant/middleware.py
index 8fb1475..99e09f6 100644
--- a/django_warrant/middleware.py
+++ b/django_warrant/middleware.py
@@ -1,3 +1,7 @@
+from django.conf import settings
+from django.utils.deprecation import MiddlewareMixin
+from django_warrant.models import get_user as gu
+
class APIKeyMiddleware(object):
"""
@@ -22,3 +26,20 @@ def process_request(request):
request.api_key = request.META['HTTP_AUTHORIZATION_ID']
return None
+
+
+def get_user(request):
+ if not hasattr(request, '_cached_user'):
+ request._cached_user = gu(request)
+ return request._cached_user
+
+
+class CognitoAuthenticationMiddleware(MiddlewareMixin):
+ def process_request(self, request):
+ assert hasattr(request, 'session'), (
+ "The Django authentication middleware requires session middleware "
+ "to be installed. Edit your MIDDLEWARE%s setting to insert "
+ "'django.contrib.sessions.middleware.SessionMiddleware' before "
+ "'django.contrib.auth.middleware.AuthenticationMiddleware'."
+ ) % ("_CLASSES" if settings.MIDDLEWARE is None else "")
+ request.user = get_user(request)
diff --git a/django_warrant/models.py b/django_warrant/models.py
index e69de29..5566e38 100644
--- a/django_warrant/models.py
+++ b/django_warrant/models.py
@@ -0,0 +1,206 @@
+import datetime
+
+from django.conf import settings
+from jose import jwt
+
+from django_warrant.utils import cognito_to_dict, dict_to_cognito, cog_client, \
+ refresh_access_token, attr_map_inverse
+
+
+class Group(object):
+
+ def __init__(self,attr_dict):
+ self._data = attr_dict
+
+ def __repr__(self):
+ return '<{class_name}: {uni}>'.format(
+ class_name=self.__class__.__name__, uni=self.__unicode__())
+
+ def __unicode__(self):
+ return self.username
+
+ def __getattr__(self, name):
+ if name in list(self.__dict__.get('_data',{}).keys()):
+ return self._data.get(name)
+
+
+class Meta(object):
+
+ def __init__(self,pk):
+ self.pk = pk
+
+
+class PK(object):
+
+ def __init__(self,sub):
+ self.value = sub
+
+ def value_to_string(self,obj):
+ return self.value
+
+ def to_python(self,obj):
+ return obj
+
+
+class AnonUserObj(object):
+ is_authenticated = False
+
+
+class UserObj(object):
+
+ def __init__(self, attribute_list, metadata=None, request=None,
+ password_hash=None,access_token=None,is_authenticated=False):
+ """
+ :param attribute_list:
+ :param metadata: Dictionary of User metadata
+ """
+
+ self._attr_map = settings.COGNITO_ATTR_MAPPING
+ self.username = attribute_list['Username']
+ self._data = cognito_to_dict(
+ attribute_list.get('UserAttributes')
+ or attribute_list.get('Attributes'),self._attr_map)
+ self.is_authenticated = is_authenticated
+ self.sub = self._data.pop('sub',None)
+ self.pk = self.sub
+ self.id = self.sub
+ self.email_verified = self._data.pop('email_verified',None)
+ self.phone_number_verified = self._data.pop('phone_number_verified',None)
+ self._metadata = {} if metadata is None else metadata
+ self._cached_groups = None
+ self._meta = Meta(PK(self._data.get('sub')))
+ if request:
+ self.access_token = request.session['ACCESS_TOKEN']
+ self.refresh_token = request.session['REFRESH_TOKEN']
+ self.id_token = request.session['ID_TOKEN']
+ elif access_token:
+ self.access_token = access_token
+
+ def __repr__(self):
+ return '<{class_name}: {uni}>'.format(
+ class_name=self.__class__.__name__, uni=self.__unicode__())
+
+ def __unicode__(self):
+ return self.username
+
+ def __getattr__(self, name):
+ if name in list(self.__dict__.get('_data',{}).keys()):
+ return self._data.get(name)
+ if name in list(self.__dict__.get('_metadata',{}).keys()):
+ return self._metadata.get(name)
+
+ def __setattr__(self, name, value):
+ if name in list(attr_map_inverse().keys()):
+ try:
+ self._data[name] = value
+ except TypeError:
+ self._data = {}
+ self._data[name] = value
+ else:
+ super(UserObj, self).__setattr__(name, value)
+
+ @property
+ def groups(self):
+ if not self._cached_groups:
+ self._cached_groups = [Group(i) for i in
+ cog_client.admin_list_groups_for_user(
+ Username=self.username,
+ UserPoolId=settings.COGNITO_USER_POOL_ID,
+ ).get('Groups')]
+ return self._cached_groups
+ else:
+ return self._cached_groups
+
+ @property
+ def group_names(self):
+ return [i.GroupName for i in self.groups]
+
+ @property
+ def is_staff(self):
+ return settings.COGNITO_ADMIN_GROUP in self.group_names
+
+ @property
+ def is_active(self):
+ return self._data.get('email')
+
+ def get_session_auth_hash(self):
+ return self.session_auth_hash
+
+ def check_token(self, renew=True):
+ """
+ Checks the exp attribute of the access_token and either refreshes
+ the tokens by calling the renew_access_tokens method or does nothing
+ :param renew: bool indicating whether to refresh on expiration
+ :return: bool indicating whether access_token has expired
+ """
+ if not self.access_token:
+ raise AttributeError('Access Token Required to Check Token')
+ now = datetime.datetime.now()
+ dec_access_token = jwt.get_unverified_claims(self.access_token)
+
+ if now > datetime.datetime.fromtimestamp(dec_access_token['exp']):
+ expired = True
+ if renew:
+ self.renew_access_token()
+ else:
+ expired = False
+ return expired
+
+ def renew_access_token(self):
+ """
+ Sets a new access token on the User using the refresh token.
+ """
+ auth_params = {'REFRESH_TOKEN': self.refresh_token}
+ self._add_secret_hash(auth_params, 'SECRET_HASH')
+ refresh_response = cog_client.initiate_auth(
+ ClientId=settings.COGNITO_APP_ID,
+ AuthFlow='REFRESH_TOKEN',
+ AuthParameters=auth_params,
+ )
+
+ self.access_token = refresh_response['AuthenticationResult']['AccessToken']
+ self.id_token = refresh_response['AuthenticationResult']['IdToken']
+ self.token_type = refresh_response['AuthenticationResult']['TokenType']
+
+ def save(self,admin=False,create=False,password=None,update_fields=None):
+ if not create:
+ if admin:
+ cog_client.admin_update_user_attributes(
+ UserPoolId=settings.COGNITO_USER_POOL_ID,
+ Username=self.username,
+ UserAttributes=dict_to_cognito(self._data,self._attr_map))
+ return
+ cog_client.update_user_attributes(
+ UserAttributes=dict_to_cognito(self._data, self._attr_map),
+ AccessToken=self.access_token
+ )
+ return
+ else:
+ cog_client.sign_up(
+ ClientId=settings.COGNITO_APP_ID,
+ Username=self.username,
+ Password=password,
+ UserAttributes=dict_to_cognito(self._data, self._attr_map)
+ )
+ return
+
+ def delete(self,admin=False):
+ cog_client.admin_disable_user(
+ UserPoolId=settings.COGNITO_USER_POOL_ID,
+ Username=self.username
+ )
+ return
+
+
+def get_user(request):
+ if not request.session.get('ACCESS_TOKEN'):
+ return AnonUserObj()
+ try:
+ return UserObj(cog_client.get_user(
+ AccessToken=request.session['ACCESS_TOKEN']),
+ request=request,is_authenticated=True)
+ except Exception:
+ refresh_access_token(request)
+ return UserObj(cog_client.get_user(
+ AccessToken=request.session['ACCESS_TOKEN']),
+ request=request,is_authenticated=True)
diff --git a/django_warrant/templates/warrant/admin-list-users.html b/django_warrant/templates/warrant/admin-list-users.html
index f778597..f931eb7 100644
--- a/django_warrant/templates/warrant/admin-list-users.html
+++ b/django_warrant/templates/warrant/admin-list-users.html
@@ -7,6 +7,7 @@
First Name |
Last Name |
|
+ |
{% for obj in object_list %}
@@ -14,6 +15,7 @@
| {{ obj.first_name }} |
{{ obj.last_name }} |
View |
+ Update |
{% endfor %}
diff --git a/django_warrant/templates/warrant/admin-profile.html b/django_warrant/templates/warrant/admin-profile.html
new file mode 100644
index 0000000..a9fdf4d
--- /dev/null
+++ b/django_warrant/templates/warrant/admin-profile.html
@@ -0,0 +1,3 @@
+{% extends 'warrant/profile.html' %}
+
+{% block h1_title %}{{ user.username }}'s Profile{% endblock h1_title %}
\ No newline at end of file
diff --git a/django_warrant/templates/warrant/admin-update-profile.html b/django_warrant/templates/warrant/admin-update-profile.html
new file mode 100644
index 0000000..2f82738
--- /dev/null
+++ b/django_warrant/templates/warrant/admin-update-profile.html
@@ -0,0 +1,3 @@
+{% extends 'warrant/update-profile.html' %}
+
+{% block h1_title %}Update {{ user.username }}'s Profile{% endblock h1_title %}
\ No newline at end of file
diff --git a/django_warrant/templates/warrant/base.html b/django_warrant/templates/warrant/base.html
index 10c00ff..9722a78 100644
--- a/django_warrant/templates/warrant/base.html
+++ b/django_warrant/templates/warrant/base.html
@@ -43,23 +43,37 @@
{% block nav_title %}Warrant{% endblock %}
+ {% if messages %}
+{% endif %}
{% block body %}
{% block content %}
+ {% for message in messages %}
+
+{% endfor %}
+
+
+
{% block h1_title %}{% endblock h1_title %}
+
+
diff --git a/django_warrant/templates/warrant/confirm-forgot-password.html b/django_warrant/templates/warrant/confirm-forgot-password.html
new file mode 100644
index 0000000..3eebcc6
--- /dev/null
+++ b/django_warrant/templates/warrant/confirm-forgot-password.html
@@ -0,0 +1,3 @@
+{% extends 'warrant/form.html' %}
+
+{% block h1_title %}Confirm Verification Code{% endblock h1_title %}
\ No newline at end of file
diff --git a/django_warrant/templates/warrant/forgot-password.html b/django_warrant/templates/warrant/forgot-password.html
new file mode 100644
index 0000000..3397fc5
--- /dev/null
+++ b/django_warrant/templates/warrant/forgot-password.html
@@ -0,0 +1,3 @@
+{% extends 'warrant/form.html' %}
+
+{% block h1_title %}Forgot Password{% endblock h1_title %}
\ No newline at end of file
diff --git a/django_warrant/templates/warrant/form.html b/django_warrant/templates/warrant/form.html
new file mode 100644
index 0000000..f3e9180
--- /dev/null
+++ b/django_warrant/templates/warrant/form.html
@@ -0,0 +1,11 @@
+{% extends 'warrant/base.html' %}
+{% load crispy_forms_tags %}
+{% block h1_title %}Update Your Profile{% endblock h1_title %}
+{% block main_content %}
+
+ {% block extra_form_info %}{% endblock extra_form_info %}
+{% endblock %}
\ No newline at end of file
diff --git a/django_warrant/templates/warrant/login.html b/django_warrant/templates/warrant/login.html
index b54997e..1577187 100644
--- a/django_warrant/templates/warrant/login.html
+++ b/django_warrant/templates/warrant/login.html
@@ -1,13 +1,6 @@
-{% extends 'warrant/base.html' %}
+{% extends 'warrant/form.html' %}
{% block title %}Login{% endblock title %}
-{% block main_content %}
-
+{% block h1_title %}Login{% endblock %}
+{% block extra_form_info %}
+
Forgot Password |
Sign Up
{% endblock %}
diff --git a/django_warrant/templates/warrant/profile.html b/django_warrant/templates/warrant/profile.html
index a33a3a5..c9a3445 100644
--- a/django_warrant/templates/warrant/profile.html
+++ b/django_warrant/templates/warrant/profile.html
@@ -1,8 +1,8 @@
{% extends 'warrant/base.html' %}
-{% load cognito_tags %}
+{% block h1_title %}{{ user.username }}{% endblock h1_title %}
{% block main_content %}
-
{{ user|username }}
+
Update your Profile
- First Name:
diff --git a/django_warrant/templates/warrant/registration.html b/django_warrant/templates/warrant/registration.html
new file mode 100644
index 0000000..b984030
--- /dev/null
+++ b/django_warrant/templates/warrant/registration.html
@@ -0,0 +1,3 @@
+{% extends 'warrant/form.html' %}
+
+{% block h1_title %}Registration{% endblock h1_title %}
diff --git a/django_warrant/templates/warrant/subscriptions.html b/django_warrant/templates/warrant/subscriptions.html
index 428d6ac..8a91c29 100644
--- a/django_warrant/templates/warrant/subscriptions.html
+++ b/django_warrant/templates/warrant/subscriptions.html
@@ -1,5 +1,7 @@
{% extends 'warrant/base.html' %}
+{% block h1_title %}My Subscriptions{% endblock h1_title %}
+
{% block main_content %}
diff --git a/django_warrant/templates/warrant/update-profile.html b/django_warrant/templates/warrant/update-profile.html
index 3ec407f..431cc3e 100644
--- a/django_warrant/templates/warrant/update-profile.html
+++ b/django_warrant/templates/warrant/update-profile.html
@@ -1,10 +1,3 @@
-{% extends 'warrant/base.html' %}
-{% load crispy_forms_tags %}
+{% extends 'warrant/form.html' %}
-{% block main_content %}
-
-{% endblock %}
\ No newline at end of file
+{% block h1_title %}Update Your Profile{% endblock h1_title %}
diff --git a/django_warrant/templatetags/__init__.py b/django_warrant/templatetags/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/django_warrant/templatetags/cognito_tags.py b/django_warrant/templatetags/cognito_tags.py
deleted file mode 100644
index 9f30226..0000000
--- a/django_warrant/templatetags/cognito_tags.py
+++ /dev/null
@@ -1,7 +0,0 @@
-from django import template
-
-register = template.Library()
-
-@register.filter('username')
-def username(user):
- return user._metadata.get('username')
diff --git a/django_warrant/tests.py b/django_warrant/tests.py
index 5a58b51..87e7f52 100644
--- a/django_warrant/tests.py
+++ b/django_warrant/tests.py
@@ -15,15 +15,51 @@
from django.test.client import RequestFactory
from django.utils.six import iteritems
-from django_warrant.backend import CognitoBackend, CognitoUser
+from django_warrant.backend import CognitoBackend
from django_warrant.middleware import APIKeyMiddleware
-from warrant import Cognito
+
def set_tokens(cls, *args, **kwargs):
cls.access_token = 'accesstoken'
cls.id_token = 'idtoken'
cls.refresh_token = 'refreshtoken'
+def authenticate_user(cls,*args, **kwargs):
+ return {
+ 'ChallengeParameters': {},
+ 'AuthenticationResult': {
+ 'AccessToken': 'fake.access.token',
+ 'ExpiresIn': 3600,
+ 'TokenType': 'Bearer',
+ 'RefreshToken': 'fake.refresh.token',
+ 'IdToken': 'fake.id.token'},
+ 'ResponseMetadata': {
+ 'RequestId': 'abc123-1234-4567-789-9101112',
+ 'HTTPStatusCode': 200,
+ 'HTTPHeaders': {
+ 'date': 'Thu, 10 May 2018 15:23:12 GMT',
+ 'content-type': 'application/x-amz-json-1.1',
+ 'content-length': '4056',
+ 'connection': 'keep-alive',
+ 'x-amzn-requestid': 'abc123-f233-sfsdf-k342334'},
+ 'RetryAttempts': 0}
+ }
+
+def verify_tokens(cls,*args, **kwargs):
+ return {
+ 'sub': 'asfadfadf-3323sd-sdt4-adf22-5dfgdfsaddf',
+ 'event_id': 'sdf44sdsd-3234-9540-8a21-234sdfdsff',
+ 'token_use': 'access',
+ 'scope': 'aws.cognito.signin.user.admin',
+ 'auth_time': 1525966559,
+ 'iss': 'https://cognito-idp.us-east-1.amazonaws.com/us-east-1_Bgbf9cyLt',
+ 'exp': 1525970159,
+ 'iat': 1525966559,
+ 'jti': '23ssdfsdf-tt44-5678-9fgv-345dfgdfgfdfgg',
+ 'client_id': '7dsfsdfdsfdfgkdfkkd',
+ 'username': 'fakeusername'
+ }
+
def get_user(cls, *args, **kwargs):
user = {
'user_status': kwargs.pop('user_status', 'CONFIRMED'),
diff --git a/django_warrant/urls.py b/django_warrant/urls.py
index 25d7fd8..88d1da7 100644
--- a/django_warrant/urls.py
+++ b/django_warrant/urls.py
@@ -2,17 +2,25 @@
from django.contrib.auth import views as auth_views
from django.urls import re_path
-from .views import ProfileView,UpdateProfileView,MySubsriptions,\
- AdminListUsers,AdminSubscriptions,LogoutView
+from django_warrant.views import SubscriptionsView, AdminProfileView, ForgotPasswordView, ConfirmForgotPasswordView, \
+ RegistrationView, ConfirmRegistrationView, UpdatePasswordView
+from .views import ProfileView,UpdateProfileView,\
+ AdminListUsers,LogoutView,AdminUpdateProfileView
app_name = 'dw'
urlpatterns = (
re_path(r'^login/$', auth_views.login, {'template_name': 'warrant/login.html'}, name='login'),
re_path(r'^logout/$', LogoutView.as_view(), {'template_name': 'warrant/logout.html'}, name='logout'),
- re_path(r'^profile/$', ProfileView.as_view(),name='profile'),
+ re_path(r'^forgot-password/$', ForgotPasswordView.as_view(), name='forgot-password'),
+ re_path(r'^register/$', RegistrationView.as_view(), name='register'),
+ re_path(r'^confirm-register/$', ConfirmRegistrationView.as_view(), name='confirm-register'),
+ re_path(r'^update-password/$', UpdatePasswordView.as_view(), name='update-password'),
+ re_path(r'^confirm-forgot-password/$', ConfirmForgotPasswordView.as_view(), name='confirm-forgot-password'),
+ re_path(r'^$', ProfileView.as_view(),name='profile'),
+ re_path(r'^subscriptions/$', SubscriptionsView.as_view(),name='subscriptions'),
re_path(r'^profile/update/$', UpdateProfileView.as_view(),name='update-profile'),
- re_path(r'^profile/subscriptions/$', MySubsriptions.as_view(),name='subscriptions'),
re_path(r'^admin/cognito-users/$', AdminListUsers.as_view(),name='admin-cognito-users'),
- re_path(r'^admin/cognito-users/(?P[-\w]+)$', AdminSubscriptions.as_view(),name='admin-cognito-user')
+ re_path(r'^admin/cognito-users/(?P[-\w]+)/$', AdminProfileView.as_view(),name='admin-cognito-user'),
+ re_path(r'^admin/cognito-users/(?P[-\w]+)/update/$', AdminUpdateProfileView.as_view(),name='admin-cognito-update-user')
)
\ No newline at end of file
diff --git a/django_warrant/utils.py b/django_warrant/utils.py
index d4f5e29..0c1d072 100644
--- a/django_warrant/utils.py
+++ b/django_warrant/utils.py
@@ -1,5 +1,10 @@
+import boto3
from django.conf import settings
-from warrant import Cognito
+from warrant_lite import WarrantLite
+
+
+apigw_client = boto3.client('apigateway')
+cog_client = boto3.client('cognito-idp')
def cognito_to_dict(attr_list,mapping):
@@ -11,6 +16,23 @@ def cognito_to_dict(attr_list,mapping):
user_attrs[name] = value
return user_attrs
+
+def dict_to_cognito(attr_dict,mapping):
+ cognito_list = list()
+ inv_map = {v: k for k, v in mapping.items()}
+ for k,v in attr_dict.items():
+ name = inv_map.get(k)
+ cognito_list.append({'Name':name,'Value':v})
+ return cognito_list
+
+
+def attr_map_inverse():
+ attr_dict = settings.COGNITO_ATTR_MAPPING.copy()
+ attr_dict.pop('username')
+ attr_dict.pop('phone_number_verified')
+ return {v: k for k, v in attr_dict.items()}
+
+
def user_obj_to_django(user_obj):
c_attrs = settings.COGNITO_ATTR_MAPPING
user_attrs = dict()
@@ -20,17 +42,29 @@ def user_obj_to_django(user_obj):
user_attrs[dk] = v
return user_attrs
-def get_cognito(request):
- c = Cognito(settings.COGNITO_USER_POOL_ID,settings.COGNITO_APP_ID,
- access_token=request.session.get('ACCESS_TOKEN'),
- id_token=request.session.get('ID_TOKEN'),
- refresh_token=request.session.get('REFRESH_TOKEN'))
- changed = c.check_token()
- if changed:
- request.session['ACCESS_TOKEN'] = c.access_token
- request.session['REFRESH_TOKEN'] = c.refresh_token
- request.session['ID_TOKEN'] = c.id_token
- request.session.save()
- return c
+def refresh_access_token(request):
+ """
+ Sets a new access token on the User using the refresh token.
+ """
+ refresh_token = request.session['REFRESH_TOKEN']
+ auth_params = {'REFRESH_TOKEN': refresh_token}
+ if settings.COGNITO_CLIENT_SECRET:
+ username = request.user.username
+ auth_params['SECRET_HASH'] = WarrantLite.get_secret_hash(username,
+ settings.COGNITO_APP_ID,
+ settings.COGNITO_CLIENT_SECRET)
+ refresh_response = cog_client.initiate_auth(
+ ClientId=settings.COGNITO_APP_ID,
+ AuthFlow='REFRESH_TOKEN',
+ AuthParameters=auth_params,
+ )
+ request.session['ACCESS_TOKEN'] = refresh_response['AuthenticationResult']['AccessToken']
+ request.session['ID_TOKEN'] = refresh_response['AuthenticationResult']['IdToken']
+ request.session.save()
+ return {
+ 'access_token': refresh_response['AuthenticationResult']['AccessToken'],
+ 'id_token': refresh_response['AuthenticationResult']['IdToken'],
+ 'token_type': refresh_response['AuthenticationResult']['TokenType']
+ }
\ No newline at end of file
diff --git a/django_warrant/views/__init__.py b/django_warrant/views/__init__.py
index f939f4c..60020ae 100644
--- a/django_warrant/views/__init__.py
+++ b/django_warrant/views/__init__.py
@@ -1,2 +1,3 @@
+from .admin import *
from .profile import *
from .subscriptions import *
\ No newline at end of file
diff --git a/django_warrant/views/admin.py b/django_warrant/views/admin.py
new file mode 100644
index 0000000..92e08f1
--- /dev/null
+++ b/django_warrant/views/admin.py
@@ -0,0 +1,63 @@
+from django.contrib import messages
+from django.views.generic import FormView, TemplateView
+
+from django_warrant.forms import AdminProfileForm
+from django_warrant.utils import cog_client
+
+try:
+ from django.urls import reverse_lazy
+except ImportError:
+ from django.core.urlresolvers import reverse_lazy
+from django.views.generic.list import ListView
+
+from django.conf import settings
+from ..models import UserObj
+from .mixins import AdminMixin, GetUserMixin
+
+
+class AdminListUsers(AdminMixin,ListView):
+ template_name = 'warrant/admin-list-users.html'
+
+ def test_func(self):
+ return self.request.user.is_staff
+
+ def get_queryset(self):
+ ul = cog_client.list_users(UserPoolId=settings.COGNITO_USER_POOL_ID).get('Users')
+ response = [UserObj(i) for i in ul]
+ return response
+
+
+class AdminProfileView(AdminMixin,GetUserMixin,TemplateView):
+ template_name = 'warrant/admin-profile.html'
+
+ def get_context_data(self, **kwargs):
+ context = super(AdminProfileView, self).get_context_data(**kwargs)
+ context['user'] = self.admin_get_user(self.kwargs.get('username'))
+ return context
+
+
+class AdminUpdateProfileView(AdminMixin,GetUserMixin,FormView):
+ template_name = 'warrant/admin-update-profile.html'
+ form_class = AdminProfileForm
+
+ def test_func(self):
+ return self.request.user.is_staff
+
+ def get_success_url(self):
+ return reverse_lazy('dw:admin-cognito-users')
+
+ def get_initial(self):
+ self.user = self.admin_get_user(
+ self.kwargs.get('username'))
+ return self.user._data
+
+ def form_valid(self, form):
+ if not self.user:
+ self.user = self.admin_get_user(
+ self.kwargs.get('username'))
+ self.user._data = form.cleaned_data
+ self.user.save(admin=True)
+ messages.success(self.request,
+ "You have successfully updated {}'s profile.".format(
+ self.kwargs.get('username')))
+ return super(AdminUpdateProfileView, self).form_valid(form)
\ No newline at end of file
diff --git a/django_warrant/views/mixins.py b/django_warrant/views/mixins.py
new file mode 100644
index 0000000..f420219
--- /dev/null
+++ b/django_warrant/views/mixins.py
@@ -0,0 +1,46 @@
+from django.conf import settings
+from django.contrib.auth.mixins import LoginRequiredMixin, \
+ UserPassesTestMixin, AccessMixin
+
+from django_warrant.models import UserObj, get_user
+from django_warrant.utils import cog_client, apigw_client
+
+
+class AdminMixin(LoginRequiredMixin,UserPassesTestMixin):
+
+ def test_func(self):
+ return self.request.user.is_staff
+
+
+class GetUserMixin(object):
+
+ def get_user(self):
+ return get_user(self.request)
+
+ def admin_get_user(self,username):
+ return UserObj(cog_client.admin_get_user(
+ UserPoolId=settings.COGNITO_USER_POOL_ID,
+ Username=username),is_authenticated=False)
+
+
+class TokenMixin(AccessMixin):
+
+ def dispatch(self, request, *args, **kwargs):
+ if not request.session.get('REFRESH_TOKEN'):
+ return self.handle_no_permission()
+ return super(TokenMixin, self).dispatch(
+ request, *args, **kwargs)
+
+
+class GetSubscriptionsMixin(GetUserMixin):
+
+ def get_subscriptions(self,api_key_id):
+ return apigw_client.get_usage_plans(
+ keyId=api_key_id).get('items', [])
+
+ def get_user_subscriptions(self):
+ return self.get_subscriptions(self.get_user().api_key_id)
+
+ def get_admin_subscriptions(self):
+ return self.get_subscriptions(self.admin_get_user(
+ self.kwargs.get('username')).api_key_id)
\ No newline at end of file
diff --git a/django_warrant/views/profile.py b/django_warrant/views/profile.py
index 53ab205..f445249 100644
--- a/django_warrant/views/profile.py
+++ b/django_warrant/views/profile.py
@@ -1,7 +1,14 @@
-from django.contrib.auth.mixins import LoginRequiredMixin, AccessMixin
+from botocore.exceptions import ClientError
+
+from django.conf import settings
+from django.contrib.auth.mixins import LoginRequiredMixin
from django.utils.decorators import method_decorator
+from django.utils.translation import gettext as _
from django.views.decorators.cache import never_cache
+from django_warrant.utils import cog_client, dict_to_cognito, apigw_client
+from django_warrant.views.mixins import GetUserMixin, TokenMixin
+
try:
from django.urls import reverse_lazy
except ImportError:
@@ -9,25 +16,10 @@
from django.views.generic import FormView, TemplateView
from django.contrib import messages
from django.contrib.auth.views import LogoutView as DJLogoutView
-from django.conf import settings
-
-from django_warrant.utils import get_cognito
-from django_warrant.forms import ProfileForm
-
-
-class TokenMixin(AccessMixin):
-
- def dispatch(self, request, *args, **kwargs):
- if not request.session.get('REFRESH_TOKEN'):
- return self.handle_no_permission()
- return super(TokenMixin, self).dispatch(
- request, *args, **kwargs)
-class GetUserMixin(object):
- def get_user(self):
- c = get_cognito(self.request)
- return c.get_user(attr_map=settings.COGNITO_ATTR_MAPPING)
+from django_warrant.forms import ProfileForm, ForgotPasswordForm, ConfirmForgotPasswordForm, RegistrationForm, \
+ VerificationCodeForm, UpdatePasswordForm
class ProfileView(LoginRequiredMixin,TokenMixin,GetUserMixin,TemplateView):
@@ -47,13 +39,15 @@ def get_success_url(self):
return reverse_lazy('dw:profile')
def get_initial(self):
- u = self.get_user()
- return u.__dict__.get('_data')
+ self.user = self.get_user()
+ return self.user._data
def form_valid(self, form):
- c = get_cognito(self.request)
- c.update_profile(form.cleaned_data,settings.COGNITO_ATTR_MAPPING)
- messages.success(self.request,'You have successfully updated your profile.')
+ if not self.user:
+ self.user = self.get_user()
+ self.user._data = form.cleaned_data
+ self.user.save()
+ messages.success(self.request,_('You have successfully updated your profile.'))
return super(UpdateProfileView, self).form_valid(form)
@@ -64,3 +58,124 @@ def dispatch(self, request, *args, **kwargs):
request.session.delete()
return super(LogoutView, self).dispatch(request, *args, **kwargs)
+
+class CognitoFormView(FormView):
+ success_message = None
+ client_error_field = None
+
+ def get_success_message(self,resp):
+ return self.success_message
+
+ def cognito_command(self,form):
+ return {}
+
+ def extra_command(self,form):
+ pass
+
+ def form_valid(self, form):
+ try:
+ resp = self.cognito_command(form)
+ self.extra_command(form)
+ messages.success(self.request,_(self.get_success_message(resp)))
+ return super(CognitoFormView, self).form_valid(form)
+ except ClientError as e:
+ form.add_error(self.client_error_field, e.response['Error']['Message'])
+ return self.form_invalid(form)
+
+
+class ForgotPasswordView(CognitoFormView):
+ template_name = 'warrant/forgot-password.html'
+ form_class = ForgotPasswordForm
+ success_url = reverse_lazy('dw:confirm-forgot-password')
+ success_message = 'Confirmation code delivered to {} by {}'
+ client_error_field = 'username'
+
+ def cognito_command(self,form):
+ return cog_client.forgot_password(
+ ClientId=settings.COGNITO_APP_ID,
+ Username=form.cleaned_data['username']
+ )
+
+ def get_success_message(self,resp):
+ return _(self.success_message.format(
+ resp['CodeDeliveryDetails']['Destination'],
+ resp['CodeDeliveryDetails']['DeliveryMedium']
+ ))
+
+
+class ConfirmForgotPasswordView(CognitoFormView):
+ template_name = 'warrant/confirm-forgot-password.html'
+ form_class = ConfirmForgotPasswordForm
+ success_url = reverse_lazy('dw:profile')
+ success_message = 'You have successfully changed your password.'
+
+ def cognito_command(self,form):
+ return cog_client.confirm_forgot_password(
+ ClientId=settings.COGNITO_APP_ID,
+ Username=form.cleaned_data['username'],
+ ConfirmationCode=form.cleaned_data['verification_code'],
+ Password=form.cleaned_data['password']
+ )
+
+
+class RegistrationView(CognitoFormView):
+ template_name = 'warrant/registration.html'
+ form_class = RegistrationForm
+ success_message = 'Confirmation code delivered to {} by {}'
+ success_url = reverse_lazy('dw:confirm-register')
+ def get_success_message(self,resp):
+ return _(self.success_message.format(
+ resp['CodeDeliveryDetails']['Destination'],
+ resp['CodeDeliveryDetails']['DeliveryMedium']
+ ))
+
+ def cognito_command(self,form):
+ cv = form.cleaned_data.copy()
+ cv.pop('confirm_password')
+ cv['name'] = '{} {}'.format(cv['first_name'],cv['last_name'])
+ return cog_client.sign_up(
+ ClientId=settings.COGNITO_APP_ID,
+ Username=cv.pop('username'),
+ Password=cv.pop('password'),
+ UserAttributes=dict_to_cognito(cv,
+ settings.COGNITO_ATTR_MAPPING)
+ )
+
+
+class ConfirmRegistrationView(GetUserMixin,CognitoFormView):
+ template_name = 'warrant/registration.html'
+ form_class = VerificationCodeForm
+ success_message = 'You have successfully registered.'
+ success_url = reverse_lazy('dw:profile')
+
+ def cognito_command(self,form):
+ return cog_client.confirm_sign_up(
+ ClientId=settings.COGNITO_APP_ID,
+ Username=form.cleaned_data['username'],
+ ConfirmationCode=form.cleaned_data['verification_code']
+ )
+
+ def extra_command(self,form):
+ username = form.cleaned_data['username']
+ resp = apigw_client.create_api_key(
+ name=username,
+ description='Created by during registration by django-warrant'
+ )
+ u = self.admin_get_user(username)
+ u.api_key = resp['value']
+ u.api_key_id = resp['id']
+ u.save(admin=True)
+
+
+class UpdatePasswordView(LoginRequiredMixin,TokenMixin,CognitoFormView):
+ template_name = 'warrant/update-profile.html'
+ form_class = UpdatePasswordForm
+ success_message = 'You have successfully changed your password.'
+ success_url = reverse_lazy('dw:profile')
+
+ def cognito_command(self,form):
+ return cog_client.change_password(
+ PreviousPassword=form.cleaned_data['previous_password'],
+ ProposedPassword=form.cleaned_data['proposed_password'],
+ AccessToken=self.request.session['ACCESS_TOKEN']
+ )
\ No newline at end of file
diff --git a/django_warrant/views/subscriptions.py b/django_warrant/views/subscriptions.py
index 7c98a83..b0b165e 100644
--- a/django_warrant/views/subscriptions.py
+++ b/django_warrant/views/subscriptions.py
@@ -1,95 +1,11 @@
-import boto3
-from django.contrib import messages
+from django.contrib.auth.mixins import LoginRequiredMixin
+from django.views.generic import ListView
-from django.contrib.auth.mixins import LoginRequiredMixin, \
- UserPassesTestMixin
-from django.http import Http404
-try:
- from django.urls import reverse_lazy
-except ImportError:
- from django.core.urlresolvers import reverse_lazy
-from django.views.generic import FormView
-from django.views.generic.list import MultipleObjectMixin, ListView
+from django_warrant.views.mixins import GetSubscriptionsMixin, TokenMixin
-from django.conf import settings
-from warrant import UserObj, Cognito
-from django_warrant.forms import APIKeySubscriptionForm
-
-class GetCognitoUserMixin(object):
- client = boto3.client('apigateway')
-
- def get_user_object(self):
- cog_client = boto3.client('cognito-idp')
- user = cog_client.get_user(
- AccessToken=self.request.session['ACCESS_TOKEN'])
- u = UserObj(username=user.get('UserAttributes')[0].get('username'),
- attribute_list=user.get('UserAttributes'),
- attr_map=settings.COGNITO_ATTR_MAPPING)
- return u
-
- def get_queryset(self):
- try:
- u = self.get_user_object()
- except KeyError:
- raise Http404
- my_plans = self.client.get_usage_plans(keyId=u.api_key_id)
- return my_plans.get('items',[])
-
-
-class MySubsriptions(LoginRequiredMixin,GetCognitoUserMixin,ListView):
+class SubscriptionsView(LoginRequiredMixin,TokenMixin,GetSubscriptionsMixin,ListView):
template_name = 'warrant/subscriptions.html'
-
-class AdminListUsers(UserPassesTestMixin,ListView):
- template_name = 'warrant/admin-list-users.html'
-
- def test_func(self):
- return self.request.user.is_staff
-
def get_queryset(self):
- response = Cognito(settings.COGNITO_USER_POOL_ID,settings.COGNITO_APP_ID)\
- .get_users(attr_map=settings.COGNITO_ATTR_MAPPING)
- return response
-
-
-class AdminSubscriptions(UserPassesTestMixin,GetCognitoUserMixin,
- FormView):
- template_name = 'warrant/admin-subscriptions.html'
- form_class = APIKeySubscriptionForm
-
- def get_success_url(self):
- return reverse_lazy('dw:admin-cognito-user',
- args=[self.kwargs.get('username')])
-
- def test_func(self):
- return self.request.user.has_perm('can_edit')
-
- def get_user_object(self):
- return Cognito(settings.COGNITO_USER_POOL_ID,settings.COGNITO_APP_ID,
- username=self.kwargs.get('username')).admin_get_user(
- attr_map=settings.COGNITO_ATTR_MAPPING)
-
- def get_context_data(self, **kwargs):
- kwargs['object_list'] = self.object_list = self.get_queryset()
- context = super(AdminSubscriptions, self).get_context_data(**kwargs)
- return context
-
- def get_form_kwargs(self):
- kwargs = super(AdminSubscriptions, self).get_form_kwargs()
- kwargs.update({'plans':self.client.get_usage_plans().get('items',[]),
- 'users_plans':[p.get('id') for p in self.get_queryset()]})
- return kwargs
-
- def form_invalid(self, form):
-
- return super(AdminSubscriptions, self).form_invalid(form)
-
- def form_valid(self, form):
- self.client.create_usage_plan_key(
- usagePlanId=form.cleaned_data['plan'],
- keyId=self.get_user_object().api_key_id,
- keyType='API_KEY'
- )
- messages.success(self.request,'Addedd subscription successfully.')
- return super(AdminSubscriptions, self).form_valid(form)
\ No newline at end of file
+ return self.get_user_subscriptions()
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
index d65c599..3f60b36 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -2,4 +2,5 @@ Django>=2.0
django-braces>=1.11.0
django-crispy-forms>=1.6.1
django-extensions>=1.7.7
-warrant>=0.2.0
+python-jose>=3.0.0
+warrant-lite>=1.0.2
diff --git a/setup.py b/setup.py
index e2dc3c2..47ef0e3 100644
--- a/setup.py
+++ b/setup.py
@@ -21,7 +21,7 @@ def parse_requirements(filename):
long_description=README,
classifiers=[
'Framework :: Django',
- 'Framework :: Django :: 1.10',
+ 'Framework :: Django :: 2.0',
"Programming Language :: Python",
"Topic :: Software Development :: Libraries :: Python Modules",
"Environment :: Web Environment",