I am creating a web application that will support several domains. For example, if my app were named www.webapp.com, I'd also have numerous customers mapping their domains to my site via DNS CNAME mappings, i.e. webapp.yourdomain.com CNAME www.webapp.com and foo.anotherdomain.com CNAME www.webapp.com, etc...
I want users to authenticate against my app via Google or Facebook (OAuth 2.0) - without me (or the domain owners) having to create a separate Google/Facebook app per mapped domain. Ideally, I would have the base domain act as a broker and redirect to the appropriate mapped domain when responding to the callback url. For example, a user visiting webapp.yourdomain.com/accounts/facebook/login would authenticate against Facebook with a callback url going to www.webapp.com/accounts/facebook/login/callback. When processing the request, I could find the appropriate context, and redirect to webapp.yourdomain.com/accounts/facebook/login/callback where the real authentication would take place (and domain-specific auth cookies would be set).
So, is this doable in django-allauth? How much hacking would it require? Or, is there another social authentication solution for Django that would be easier to implement this in?
You should use Django sites framework together with django-allauth.
Consumer keys, tokens make use of the Django sites framework. This is
especially helpful for larger multi-domain projects, but also allows
for for easy switching between a development (localhost) and
production setup without messing with your settings and database.
Just configure each social app in the admin backend.
Related
I am trying to be sure that I understand it correctly:
Is OAuth a bridge for only third party authenticator those so common like Facebook, Google? And using it improves user experience in secure way but not adding extra secure layer to Django login framework? Or only Authorization Code grant type is like that? Can I take it like this?
What is OAuth?
According to RFC 6749:
The OAuth 2.0 authorization framework enables a third-party
application to obtain limited access to an HTTP service, either on
behalf of a resource owner by orchestrating an approval interaction
between the resource owner and the HTTP service, or by allowing the
third-party application to obtain access on its own behalf.
Essentially, it is an authorization protocol used to share permissions between multiple applications.
If you decide to implement OAuth, your application will be the one to allow other services to programmatically view your users' data and act on their behalf, if needed.
Whenever an application requires access to another service that you use, it probably uses OAuth to perform those actions. (e.g. When games used to ask us to allow posting on Facebook on our behalf.)
What OAuth is not?
By looking at your question, I feel like there's a misunderstanding of OAuth.
OAuth is not a bridge for third-party authentication methods. If you are looking for this type of authentication mechanism, you should take a look into Single Sign-On (SSO). For Django, you can use django-simple-sso.
Does it enhance security?
Depending on the use case, yes, it can enhance security.
If your application needs to exchange information with other services, it is a good practice to limit what these third-party services are able to do in your app, feature and time-wise.
Let's say, for example, that your user needs to give permission to another application to gather information from yours:
If you were to use the old-fashioned e-mail and password combination method, these credentials would be exposed in case of this third-party service had a data breach.
Using OAuth on the other hand is much more secure, as the credentials stored in the server would not contain the user's password and have very specific roles, apart from being easily revoked.
If you have a Django app I would say that you don't have to implement OAuth - you should be fine with any login functionality Django offers.
OAuth is commonly used when different services talk to each other. These don't have to be third-party services, they can belong to the same party. For example, when you have a Single Page Application or a Mobile App that want to call your backend API to get some data. Then it's better to use OAuth as it is a standard and it helps you to implement authorization in a secure way.
When you think about "login with Google/Facebook", what you actually want is an SSO solution (Single Sign-On). That solution is very often implemented with OpenID Connect (OIDC), which is a protocol built on top of OAuth. Still, you can use just OIDC to log a user in with Google, get an ID Token, and then be able to authenticate the user to your Django app based on the ID Token from Google. You don't need OAuth for that (in the sense, that you don't need to get access tokens from Google, you don't need your own Authorization Server, and you can rely on cookie-based sessions).
We have
An existing Django backend with Python social auth for signing in with Google, providing web-based application and an API for the mobile app.
An iOS mobile app with GoogleSignIn pod.
Now we would like to allow mobile app users to sign in with Google inside the app, and then authenticate them on the backend, so that they can access their personal data via the app.
So my idea of the algorithm is:
App uses the GoogleSignIn and finally receives access_token.
App sends this access_token to the Backend.
Backend verifies this access_token, fetches/creates the user, returns some sessionid to the App.
App uses this sessionid for further requests.
The problem is with the third step: token verification. I found two ways of verifying:
1. Python social auth flow
As described in the docs:
token = request.GET.get('access_token')
user = request.backend.do_auth(token)
if user:
login(request, user)
return 'OK'
else:
return 'ERROR'
This would be a preferred flow, since it already has all the required steps and is working perfectly with the web app (like, accounts creation, defaults for newly created users, analytics collection, etc.).
But the problem is that the backend and the app use different CLIENT_IDs for the auth. This is due to the limitations in the Google Developers Console: when creating credentials, you need to select whether it will be a web app or an iOS app, and it cannot be both.
I tried to use different client ids (then backend cannot verify), tried to use web id inside the app (then the pod does not work), and tried to use app id inside the web (then the backend cannot verify again).
2. Google API Client Library
Another option is to utilize the way from the Google Sign-In for iOS documentation:
from google.oauth2 import id_token
from google.auth.transport import requests
try:
idinfo = id_token.verify_oauth2_token(token, requests.Request(), CLIENT_ID)
userid = idinfo['sub']
except ValueError:
# Invalid token
pass
It worked, but here we're missing all the pipeline provided by social auth (e.g. we need to create a user somehow), and I could not find a proper way of starting the pipeline from the middle, and I'm afraid it would be quite fragile and bug-prone code.
Another problem with this solution is that in reality we also have Signed in with Apple and Sign in with Facebook, and this solution will demand ad-hoc coding for each of these backends, which also bring more mess and unreliability.
3. Webview
Third option would be not to use SDKs in the Swift and just use a web view with the web application, as in the browser.
This solves the problem with the pipeline and client ids.
But it doesn't look native, and some users may suspect phishing attempts (how does it differ from a malicious app trying to steal Google identity by crafting the same-looking form?). Also, I'm not sure it will play nicely with the accounts configured on the device. And it also will require us to open a browser even for signing in with Apple, which looks somewhat awkward. And we're not sure such an app will pass the review.
But, maybe, these all are minor concerns?
⁂
So, what do you think? Is there a fourth option? Or maybe improvements to the options above? How is it solved in your app?
I have a pair of django apps. One runs an api on one port (8001) and the other app runs a website (port 8000) where angularJS on the page consumes that api generated by the other app. There are reasons I've set it up this way.
The apps don't share a user model.
When I log in to the website and go to the page with the AngularJS, I am logged out when I refresh the page.
I can disable 'AuthenticationMiddleware' and 'SessionAuthenticationMiddleware' on the api app, but then I can't log in to the admin panel. It's functional, but it's a non-starter.
My workaround of last resort is to stand up an admin only site that has authentication and uses the same db but doesn't have a publicly available API.
Surely there is a way to disable the Auth and SessionAuth middleware on a per view basis...
The app is built using the Django Rest Framework.
Thoughts?
Make api server to use DRF token based authentication.
And to disable the Auth and SessionAuth middleware on a per view basis you will have to write custom middleware or decorator.
I am developing a back-end for a webpage using Django Rest Framework. The webpage will be public, and it will only fetch information from this service. Thus, I have to deploy both service and webpage.
Since the webpage is public access (without any type of login) I can avoid having to set up the SSL stuff. However, by default, the DRF comes with the browsable API and the login field. I know I can remove the browsable API, but is it enough?
For instance, the configurations I would have would be:
(removing the BrowsableAPIRenderer)
'DEFAULT_RENDERER_CLASSES': ( 'rest_framework.renderers.JSONRenderer',
'rest_framework.renderers.JSONPRenderer',
'rest_framework_csv.renderers.CSVRenderer', )
and:
CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_METHODS = (
'GET',
'HEAD',
'OPTIONS',
)
I am using https://github.com/ottoyiu/django-cors-headers for the CORS stuff.
Would this be enough to avoid unwanted login atempts? Is there any specific way to disable this option?
What 'DEFAULT_PERMISSION_CLASSES' shoul I use?
Best regards and thanks for any help!
If you have a login, but you don't have SSL, then your users are vulnerable to packet sniffing of credentials on many wifi and ethernet networks. Such a vulnerability can be trivially exploited with the Firesheep firefox plugin. Due to users' habit of reusing passwords, you could end up compromising their security to a more critical website. This is very unfortunate. It isn't entirely your problem if users reuse their password, but SSL should be a base layer of protection to your users.
While it is possible to use Django templates with Django Rest Framework (DRF) as the backend, you are not limited to using Django for your front-end. Consider AngularJS with DRF. Anyways, there is a significant learning curve for AngularJS, but you needn't limit yourself to having Django supply your front-end.
As far as removing the DRF BrowsableAPIRenderer, you will get some protection from "security through obscurity", but you really need to lock down your APIs through a proper permission model as an attacker can easily look at traffic generated by your front-end to your back-end and then manipulate the requests to your back-end. So, discoverability of your interface by an adversary will not be significantly reduced through getting rid of BrowsableAPIRenderer. It will only obscure back-end resources that your front-end isn't currently using and it will also make your life as a front-end dev a little more painful.
For DEFAULT_PERMISSION_CLASSES, take a gander at DRF permissions documentation. If you only have two user groups - logged in/authenticate and not logged in, then IsAuthenticatedOrReadOnly is a good place to start. If you start to have per-model permission bifurcation for different user groups, then
DjangoModelPermissions is a good place to dig into.
I need split my current Django application into two sites.
Site A will contain the public facing site which would contain all the static pages and the registration system.
The other site — Site B — is the site for registered users. They can also log-in to application site through Site B.
If I'm not mistaken, I can use django.contrib.sites framework to accomplish the task of having multiple sites but can have a common authetication/registration backend?
How can I accomplish this?
Thanks.
Django's django.contrib.sites framework is nice if both sites are running under the same server and access the same database. If you have a distributed application (different sites on different hosts or different sites on different databases), you can resort to single sign-on solutions.
I use OpenID with a custom provider to centralize logins between apps running on different databases. Other solutions include CAS (provider and consumer).
For this case, you would have 2 settings.py files called settings_A.py and settings_B.py which specify from settings import *
A would have SITE=1 and B would have SITE=B. you can then set these files in your apache configs by setting the environment variable for each virtual host DJANGO_SETTINGS_MODULE=settings_A and DJANGO_SETTINGS_MODULE=settings_B
Then you set up the contrib.sites app with your 2 domain names bound to the appropriate site ID, and your flatpages will be able to be bound to either or both sites.
Lastly, in settings_A.py settings_B.py you either specify seperate root urlconfs or you use the use settings.SITE in your urlconfs to enable and disable groups of urls for each site.
Hope this helps
EDIT: To clarify: as long as you use the same database and SECRET_KEY between both sites, you can use the same user accounts between them too. If the sites are of the form example.com and private.example.com then setting SESSION_COOKIE_DOMAIN to .example.com will allow the session to carry over between both sites.
You could use (external) LDAP authentication for both sites. You would need a LDAP server somewhere reachable for both sites. I never used this and I don't know how well it integrates with Django auth though. See http://packages.python.org/django-auth-ldap/