Django Rest Framework and AWS Cognito - python

Currently, I am using django-warrant to utilize cognito (JWT) based authentication to access APIs. After creating pool and app, I have set up following in my settings file:
AUTHENTICATION_BACKENDS = [
'django.contrib.auth.backends.ModelBackend',
'django_warrant.backend.CognitoBackend',
]
COGNITO_USER_POOL_ID = 'poolid'
COGNITO_APP_ID = 'app id'
COGNITO_ATTR_MAPPING = {
'email': 'email',
'given_name': 'name',
'family_name': 'last name',
}
COGNITO_CREATE_UNKNOWN_USERS = False
AWS_ACCESS_KEY_ID = 'access_key'
AWS_SECRET_ACCESS_KEY = 'access_key_secret'
In Midddleware, I have added:
MIDDLEWARE = [
.............,
'warrant.django.middleware.APIKeyMiddleware',
..............,
]
In Installed apps, I have added,
INSTALLED_APPS = [
............,
'django_warrant',
............,
]
In urls.py, I have added:
path('accounts/', include('django_warrant.urls'))
When I try to hit accounts/login url, it is throwing the error of missing templates.
As I am using it for the first time, I am clueless how to proceed further with it to map django users with cognito users. I have searched tutorials related to this but found None. Please provide me guidance so that I can manage to proceed further.

Related

Not Found error after logging in with google using django-allauth

I am using django-allauth package and google provider for authentication in my django project. Everything worked fine in development however when I launched my project on the server, I got an error. When I press the "Log in with Google" button in my sign in page, I get redirected to the page where google asks me to choose my Google account to continue with.
Then after this step, where I get redirected to my site, I'm encountered with a Not Found error.
I tried a bunch of stuff found online but they didn't work.
here is my Google credentials authorized redirect URIs.
In my settings.py file I configured allauth as below:
# Django-allauth configs
AUTH_USER_MODEL = 'accounts.User'
AUTHENTICATION_BACKENDS = [
# Needed to login by username in Django admin, regardless of `allauth`
'django.contrib.auth.backends.ModelBackend',
# `allauth` specific authentication methods, such as login by e-mail
'allauth.account.auth_backends.AuthenticationBackend',
]
SITE_ID = 1
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_UNIQUE_EMAIL = True
ACCOUNT_AUTHENTICATION_METHOD = "email"
ACCOUNT_USERNAME_REQUIRED = False
ACCOUNT_USER_MODEL_USERNAME_FIELD = None
ACCOUNT_SIGNUP_REDIRECT_URL = 'accounts:create_profile_url'
ACCOUNT_EMAIL_VERIFICATION = 'none'
LOGIN_REDIRECT_URL = 'dashboard_url'
ACCOUNT_FORMS = {
'login': 'accounts.forms.CustomLoginForm',
'signup': 'accounts.forms.CustomSignupForm',
'change_password': 'accounts.forms.CustomChangePasswordForm',
}
ACCOUNT_DEFAULT_HTTP_PROTOCOL='https'
and I've added 'allauth.urls' in my urlpatterns too
urlpatterns = [
...
path('accounts/', include('allauth.urls')),
...
]
I could really use some help. Thanks.

How to change a URL that is configured inside a library?

Context: I need to configure OIDC using Django to allow my application to be accessed by users.
Problem: I'm using a library called mozilla-django-oidc that is pretty straight-forward, but when I test the configuration, it keeps returning the following error:
400 - Invalid redirect_uri
Cause: As I tested in Postman, this error occurs because the callback URL is wrong. When I searched more deeply mozilla-django-oidc, I've found it sets a standard URL path for callback (/oidc/callback/) which is not the URL allowed by the OIDC we need to access.
Key Question #1: How can I modify the mozilla-django-oidc code so that the standard callback URL path is what I need it to be?
Key Question #2: Is there anyway I can make these changes in my code, instead of mozilla-django-oidc?
Below are some settings of my Django code:
My Django - views.py
# Mozila OIDC configuration settings
OIDC_OP_AUTHORIZATION_ENDPOINT = "https://XXXXXXXXXXXXXXXXXXXXX"
OIDC_OP_TOKEN_ENDPOINT = "https://XXXXXXXXXXXXXXXXXXXXX"
OIDC_OP_USER_ENDPOINT = "https://XXXXXXXXXXXXXXXXXXXXX"
OIDC_RP_CLIENT_ID = "XXXXXXXXXXXXXXXXXXXXXXX"
OIDC_RP_CLIENT_SECRET = "XXXXXXXXXXXXXXXXXXXXXXX"
LOGIN_REDIRECT_URL = "https://myurl.com"
My Django - settings.py
# Add 'mozilla_django_oidc' to INSTALLED_APPS
INSTALLED_APPS = (
# ...
'django.contrib.auth',
'mozilla_django_oidc', # Load after auth
# ...
)
# Add 'mozilla_django_oidc' authentication backend
AUTHENTICATION_BACKENDS = (
'mozilla_django_oidc.auth.OIDCAuthenticationBackend',
# ...
)
My Django - urls.py
urlpatterns = patterns(
# ...
url(r'^oidc/', include('mozilla_django_oidc.urls')),
# ...
)
mozilla-django-oidc - urls.py
urlpatterns = [
url(r'^callback/$', OIDCCallbackClass.as_view(),
name='oidc_authentication_callback'),
url(r'^authenticate/$', OIDCAuthenticateClass.as_view(),
name='oidc_authentication_init'),
url(r'^logout/$', views.OIDCLogoutView.as_view(), name='oidc_logout'),
]
Other parts of mozilla-django-oidc library can be found at https://github.com/mozilla/mozilla-django-oidc/tree/master/mozilla_django_oidc

Django OAuth- Separate Resource and Authorization Server

I'm using Django Oauth Library.
I want to have different Auth and Resource Server.
On Auth Server, following is my setting.
INSTALLED_APPS = [
...
'oauth2_provider',
'rest_framework',
]
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'oauth2_provider.contrib.rest_framework.OAuth2Authentication',
),
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
),
}
# ############## OAUTH SETTINGS ###################
OAUTH2_PROVIDER = {
'SCOPES': {'users': 'user details', 'read': 'Read scope', 'write': 'Write scope', 'groups': 'Access to your groups', 'introspection': 'introspection'},
'ACCESS_TOKEN_EXPIRE_SECONDS': 86400, # 1 Day.
}
On my Resource Server
INSTALLED_APPS = [
...
'oauth2_provider',
'rest_framework',
]
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'oauth2_provider.contrib.rest_framework.OAuth2Authentication',
),
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
),
}
# ############## OAUTH SETTINGS ###################
OAUTH2_PROVIDER = {
'RESOURCE_SERVER_INTROSPECTION_URL': 'http://localhost:8000/o/introspect/',
'RESOURCE_SERVER_AUTH_TOKEN': '3yUqsWtwKYKHnfivFcJu',
}
Question 1)
How do I obtain RESOURCE_SERVER_AUTH_TOKEN?
Question 2)
Upon introspecting the token, Auth Server returns 403 Forbidden Error in the console logs.
Following is the flow to obtain the access token.
I get the client_id, client_secret, grant_type and scopes from the client POST request onto the Resource Server. I call the AuthServer from the Resource Server and return the response back to the client.
What exactly am I missing over here?
According django-oauth-toolkit implementation, Resource server first tries to check whether access token is available in its db or not.
If access token is not present, it will check introspection URL and introspection token are available in settings. If introspection settings is available then resource server tries to validate the user token with an introspection endpoint.
So the issue seems to be that AUTH SERVER and DRF might be returing 403 Forbidden since the permission is set as IsAuthenticated. This could be either due to invalid token or invalid user.
So create a user for the resource server and then create an application for the resource server user.
creating the application,
client_type=Application.CLIENT_CONFIDENTIAL
authorization_grant_type=Application.GRANT_AUTHORIZATION_COD‌​E
And generate a token through the admin site and update the resource server INTROSPECTION setting with the newly created token. Make sure you put the appropriate scopes while creating the token.

I can't get OpenID to work (openid.consumer.consumer.ProtocolError: Parameter next not in return_to URL)

I'm using Django-Allauth in my Django project. I added some Social Providers (Facebook, Google) and it works perfectly!
But I'm facing a problem when trying to use OpenID providers.
I've been testing it with Yahoo and AOL so far, and both end up with the same error: openid.consumer.consumer.ProtocolError: Parameter next not in return_to URL.
Configuration
settings.py
Some relevant info of my project's setting.py file:
INSTALLED_APPS = [
# Django apps
'django.contrib.auth',
'django.contrib.sites',
# Allauth apps
'allauth',
'allauth.account',
'allauth.socialaccount',
'allauth.socialaccount.providers.openid',
'allauth.socialaccount.providers.facebook',
'allauth.socialaccount.providers.google',
# Project apps
'frontoffice.apps.FrontofficeConfig',
'middleoffice.apps.MiddleofficeConfig',
]
SITE_ID = 1
AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend',
'allauth.account.auth_backends.AuthenticationBackend',
)
# Email sending
EMAIL_HOST = 'smtp.sendgrid.net'
EMAIL_HOST_USER = 'apikey'
EMAIL_HOST_PASSWORD = 'secret'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
# Auth and allauth settings
ACCOUNT_AUTHENTICATION_METHOD = 'email'
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_USERNAME_REQUIRED = False
ACCOUNT_USERNAME_MIN_LENGTH = 3
# Redirections
ACCOUNT_LOGOUT_REDIRECT_URL = '/front-office'
LOGIN_REDIRECT_URL = '/front-office'
# Email verification
ACCOUNT_EMAIL_VERIFICATION = 'mandatory'
SOCIALACCOUNT_EMAIL_VERIFICATION = 'mandatory'
ACCOUNT_EMAIL_CONFIRMATION_EXPIRE_DAYS = 3 # in days
ACCOUNT_EMAIL_CONFIRMATION_COOLDOWN = 30 # in seconds
# Account signup
ACCOUNT_SIGNUP_EMAIL_ENTER_TWICE = True
ACCOUNT_SIGNUP_FORM_CLASS = 'frontoffice.forms.UserAccountForm'
# Social Accounts
SOCIALACCOUNT_AUTO_SIGNUP = False
SOCIALACCOUNT_EMAIL_REQUIRED = True
SOCIALACCOUNT_QUERY_EMAIL = True
SOCIALACCOUNT_PROVIDERS = {
'openid': {
'SERVERS': [
dict(id='yahoo',
name='Yahoo OpenID',
openid_url='http://me.yahoo.com'),
]
},
'facebook': {
'SCOPE': ['email', ],
'METHOD': 'js_sdk',
'INIT_PARAMS': {'cookie': True},
'FIELDS': ['id', 'email', 'name', 'first_name', 'last_name', 'verified', 'locale', 'timezone', 'link', 'gender', 'updated_time',],
'VERIFIED_EMAIL': False,
},
'google': {
'SCOPE': [
'profile',
'email',
],
'AUTH_PARAMS': {
'access_type': 'online',
}
}
}
I'm aware some settings don't override defaults or are redundant, it just helps me remembering what behaviours I should expect.
Using OpenID Auth
Error stacktrace
As I said, I tried Yahoo OpenID (http://me.yahoo.com), both from pre-defined provider and OpenID URL, and AOL, from URL (http://openid.aol.com/myUserName).
Both return the aforementionned error, here's an example stacktrace :
INFO:django.server:"GET /accounts/openid/login/?openid=http%3A%2F%2Fme.yahoo.com&process=login HTTP/1.1" 302 0
ERROR:root:Verifying return_to arguments: Parameter next not in return_to URL
Traceback (most recent call last):
File "d:\Profiles\user\Envs\Django\lib\site-packages\openid\consumer\consumer.py", line 673, in _checkReturnTo
self._verifyReturnToArgs(message.toPostArgs())
File "d:\Profiles\user\Envs\Django\lib\site-packages\openid\consumer\consumer.py", line 886, in _verifyReturnToArgs
(pair[0], ))
openid.consumer.consumer.ProtocolError: Parameter next not in return_to URL
INFO:django.server:
"GET /accounts/openid/callback/?janrain_nonce=2017-11-21T15:56:32_nonce_zu
&next=
&openid.ns=http://specs.openid.net/auth/2.0
&openid.mode=id_res
&openid.return_to=http://localhost:8000/accounts/openid/callback/?janrain_nonce=2017-11-21T15:56:32_nonce_zu
&next=
&openid.claimed_id=https://me.yahoo.com/a/C7dd_secret_bVtec-#784b5
&openid.identity=https://me.yahoo.com/a/C7dd_secret_bVtec-
&openid.assoc_handle=1P.qFXi_secret_7MP8.Cv06_secret_wEeA--
&openid.realm=http://localhost:8000/
&openid.ns.ax=http://openid.net/srv/ax/1.0
&openid.ax.mode=fetch_response
&openid.ax.value.email=jane.doe#yahoo.fr
&openid.ax.value.fullname=Jane Doe
&openid.response_nonce=2017-11-21T15:56:33Zd_nonce_eA--
&openid.signed=assoc_handle,claimed_id,identity,mode,ns,op_endpoint,response_nonce,return_to,signed,ax.value.email,ax.type.email,ax.value.fullname,ax.type.fullname,ns.ax,ax.mode,pape.auth_level.nist
&openid.op_endpoint=https://open.login.yahooapis.com/openid/op/auth
&openid.ax.type.email=http://axschema.org/contact/email
&openid.ax.type.fullname=http://axschema.org/namePerson
&openid.pape.auth_level.nist=0
&openid.sig=n/JOWn_secret_3630=
HTTP/1.1"
200 647
I put line feeds between parameters for readability.
Question
As you can see, the error message is quite self-explanatory: parameter &next= is empty.
Would anyone happen to know where things might have gone wrong? Is it provider-related, libray-related, configuration/implementation-related?
Thanks in advance!
It turns out that there is a bug with allauth, where not providing next in the openid login URL will result in this error. I issued a PR to address this issue, so hopefully it gets merged in at some point.
In the meantime, you have two options:
Use my branch with the fix (or add to requirements.txt via -e git://github.com/pydolan/django-allauth.git#fix-yahoo-openid#egg=django-allauth);
Always provide a value for next. For example: /accounts/openid/login/?process=login&openid=https%3A%2F%2Fme.yahoo.com&next=%2F will let you login to Yahoo with OpenID.

Django - accessing Django Rest endpoint on AWS Elastic Beanstalk

Very new to AWS and deploying my own projects/services in general. I deployed my first Django Rest API on Beanstalk.
I can access the application URL in the browser (http://myappenv.someid.us-west-2.elasticbeanstalk.com/, no problem.
However when I use that base url in my application on localhost, I get a 403: Authentication credentials were not provided.
I am passing the DRF Token in the header, just like I normally would to access each endpoint. ie http://myappenv.someid.us-west-2.elasticbeanstalk.com/mentions.
When I switch back to a local version of the API in my application, I can access it normally.
My application is hitting the endpoint but, for some reason, even with the token passing, its returning the 403
my DRF is setup in settings.py as follows:
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': (
'rest_framework.renderers.JSONRenderer',
'rest_framework.renderers.BrowsableAPIRenderer',
),
'DEFAULT_AUTHENTICATION_CLASSES': (
#'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.TokenAuthentication'
),
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
) ,
'DEFAULT_FILTER_BACKENDS': ('rest_framework.filters.DjangoFilterBackend',)
}
Any ideas? Would appreciate any feedback.
After going through the DRF documentation, I have to adjust my DEFAULT_PERMISSION_CLASSES

Categories