Python Social Auth - How to know if social media connect is successful? - python

I have installed Python Social Auth. I use it to associate user site account with his social media accounts.
Facebook connect link is:
Connect
Redirection works but how to know if social media association is successful?
If an exception is catch, I can display get_messages() function. It's perfect!
But any return if it's successful.
I have tried to custom a pipeline but I have not access to request variable to set message like it: messages.success(request, "Successful message!')

You do have access to request in your custom pipeline:
The pipeline functions will get quite a lot of arguments, ranging from the backend in use, different model instances, server requests and provider responses.
You can read more about it here.
and you can get access to request object like this:
def custom_pipeline(strategy, *args, *kwargs):
request = strategy.request
and do whatever you wanted with messages.

There is an option
SOCIAL_AUTH_LOGIN_ERROR_URL = '/error/'
in python social auth settings which redirects to the url you mention in above setting.
This way you will know whether the connect is success or not.
Hope this is helpful.

Related

Django send authenticated user to another django server with the same db

I know question sounds strange, I will explain it here.
I have two Django servers which share the same DB. One is a light front/back server and the order one takes the heavy computing part. They share the same database.
I am currently securing the web, and I have a couple of views in the light server requiring user login:
#login_required()
#permission_required('auth.can_upload', login_url='/accounts/login/')
This works nicely in the light server since the user is authenticated (request.user returns a valid user in the views).
The problem comes when I have to send the uploaded data to the other server since it is protected as I showed earlier, I do not know how to pass it the user that is already logged (user is valid since servers share the DB).
# send an upload request using requests
s = requests.Session()
r1 = s.get(upload_process_url)
csrf_token = r1.cookies['csrftoken']
a = s.post(upload_process_url, files=request.FILES,
data={'csrfmiddlewaretoken': csrf_token},
headers=dict(Referer=upload_process_url))
I cannot ask every time the user and password or save them. The thing is I want to pass the user that is already logged in a request.
The user was logged using the default django accounts/login page and authentication.
Any clues and what could I try? I think this problem cannot be as difficult as it looks to me. I just want to send an authenticated request. If I remove the decorators everything works nicely with this code
Thanks a lot
Have a look at REMOTE_USER authentication:
This document describes how to make use of external authentication sources (where the Web server sets the REMOTE_USER environment variable) in your Django applications. This type of authentication solution is typically seen on intranet sites, with single sign-on solutions such as IIS and Integrated Windows Authentication or Apache and mod_authnz_ldap, CAS, Cosign, WebAuth, mod_auth_sspi, etc.
Basically your "light" server does the authentication as it already does. When you are doing a request to your "heavy" server, you should set a Auth-User header containing the username of your user. Django will then automatically authenticates the corresponding user.
By default, Django will read an environment variable set by an authentication server. But we can make it work with a HTTP header instead:
# middlewares.py
from django.contrib.auth.middleware import RemoteUserMiddleware
class CustomHeaderMiddleware(RemoteUserMiddleware):
header = 'HTTP_AUTH_USER'
# settings.py
MIDDLEWARE = [
'...',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'my_project.middlewares.CustomHeaderMiddleware',
'...',
]
Then, you can do something like this then in your request (assuming you have your Django user at hand):
s = requests.Session()
r1 = s.get(upload_process_url)
a = s.post(
upload_process_url,
files=request.FILES,
headers={
'Auth-User': user.username,
},
)
Since you're not doing a request from a browser, you can avoid the CSRF protection by marking the called "heavy" view with #csrf_exempt decorator (as you found yourself).
Be careful though that your "heavy" server should not be accessible directly on the internet and always behind a proxy/VPN accessible only by your "light" server.

python-social-auth and github, I have this error "The redirect_uri MUST match the registered callback URL for this application"

I'm using python-social-auth on a project to authenticate the user with Github.
I need to redirect the user depending on the link they use. To do that I'm using the next attribute on the url, and I didn't declare any redirect url on my github app neither in my django settings.
This is the href attribute I'm using for my link : {% url 'social:begin' 'github' %}?next={% url 'apply' j.slug %}
And the first time I click on it, I'm getting redirected to my homepage with this error in the url field : http://127.0.0.1:8000/?error=redirect_uri_mismatch&error_description=The+redirect_uri+MUST+match+the+registered+callback+URL+for+this+application.&error_uri=https%3A%2F%2Fdeveloper.github.com%2Fv3%2Foauth%2F%23redirect-uri-mismatch&state=Ui1EOKTHDhOkNJESI5RTjOCDEIdfFunt
But after first time the link work.
I don't know where is the problem, I hope someone can help me. Thanks
This library uses OAuth for GitHub authentication.
You must provide a callback URL, because the OAuth process causes the user's browser to actually leave your site as part of the authentication process. The callback URL that you send to GitHub is used to redirect users back to your site.
It looks like Python Social Auth handles some of this for you, though (emphasis mine):
GitHub
Github works similar to Facebook (OAuth).
Register a new application at GitHub Developers, set the callback URL to http://example.com/complete/github/ replacing example.com with your domain.
Fill App Id and App Secret values in the settings:
SOCIAL_AUTH_GITHUB_KEY = ''
SOCIAL_AUTH_GITHUB_SECRET = ''
Also it’s possible to define extra permissions with:
SOCIAL_AUTH_GITHUB_SCOPE = [...]
The tricky bit is getting this to work on your development machine.
Setting your domain to 127.0.0.1 in your hosts file should work, something like this
127.0.0.1 example.com
but make sure to comment this like out once you move into production!
You may also want to browse GitHub's OAuth documentation. Using a library is great, but if you understand the underlying technology you'll have fewer problems.
I did solve the login redirect URI mismatch by just using http://127.0.0.1:8000/
The problem has to do with the way you've configured the urls.py locally. If you have
path('social/', include('social_django.urls', namespace='social')),
then your Authorization callback URL should be
http://localhost/social/complete/github/

Subclassing User to differentiate between an admin and an App with an API key?

This is my first API, so please forgive/correct me if I make any wrong claims.
I have an app that has an API. I would only like external apps (mobile clients etc.) with a valid API key to have access to it, and I think django-rest-framework's TokenAuthentication is the right fit for it. I would also like users to be able to log in with their username & password, and I'm looking to use OAuth2Authentication for that. But I don't want apps that use TokenAuthentication to have a "User" instance in the database (as they are not users in the traditional sense) so I'm thinking about doing something like this:
class Client(User):
pass
django-rest-framework says that request.user will be an instance of User. Will I bump into any problems if I use Client instead?
Is this the standard way of handling this situation? It just doesn't feel right to me (mainly because of question 1)
For mobile clients to have access to your API, using django-restframework's TokenAuthentication will work just fine. As you have already ascertained. You need to design a mechanism for handing out your tokens. If you are doing this dynamically then you will need to have your API request handle this.
Mobile Client: ( initial API request )
request /API/rabbit/1/
( no token)
Server: 401
test for the token ( fails )
'login please' via HTTP 401 response. ( or some other custom header or response information )
You can define your api on how to accomplish this, most folks use the http:
401 Unauthorized error code. I point this out because its clearly a design decision.
Mobile Client: ( request login)
prompts user for username and password, and makes a request too /login/ this could be a special mobileclient login like /mobile/login/ whose difference is that it hands back a token on a successful login.
Server: 200
verifies valid user and hands out token.
you could write this logic, or you could use 'rest_framework.authtoken.views.obtain_auth_token' which I recommend. See rest-frameworks
token authentication for details on this. Heed its warning about https.
Mobile Client: ( re-request API with token in http header)
receives token
now remakes initial request to /API/rabbit/1/ with its token in the header.
Server: 200
verifies valid token in the header and provides access to API. You will be writing this code.
Finally: You will need to design a strategy to 'age-out' your tokens, and or lock out users.
Also: make sure you add 'rest_framework.authtoken' to your INSTALLED_APPS, and make sure you call manage.py syncdb
Aside: you do not specifically have to use the TokenAuthentication ( request.user, request.auth) you can write your own code to peek in the header and see if the token is set. This is fairly easy to do with the python Cookie lib. You are still using-heavly the token management features of django-rest-framework. To be honest I think there documentation is a bit incomplete on configuring the 'TokenAuthentication' authentication back-ends.
Hope this helps!

Django request.user is empty

Using django, I am authenticating the user through Google. I get the initial request tokens & redirect the user to google for auth. After which google redirects the user back to my website (using the redirect_url I provide).
At this point the request.user.id is None so is request.user.username why is this happening? I need the user ID to enter the access_tokens (that google sends me) into the DB.
Under what conditions can request.user object in Django be empty?
UPDATE1: When I get redirected back from Google with the url pattern as http://mywebsite.com/lserv?s=goog control comes back to my django views function, but django gives me the request.user object user as Anonymous user with no username or id. why?
UPDATE2:
all this is running on python manage.py runserver for now...
UPDATE3: Anybody faced anythn similar to this? basically, out of no reason the user in request clears out automatically & I get assigned as Anonymous user. All this happens between url requests from the user (from browser). Why?
Django's auth mechanism has nothing to do with Google's or any other auth service. If you want to integrate third party auth service with your Django site, you should do it youself.
If you're using oauth2 library, it's README has a section named "Logging into Django w/ Twitter" may help you.
If you are using oauth api from google. To get the user you have to do something like this
from google.appengine.api import oauth
# ...
try:
# Get the db.User that represents the user on whose behalf the
# consumer is making this request.
user = oauth.get_current_user()
except oauth.OAuthRequestError, e:
# The request was not a valid OAuth request.
# ...

Multiple authentication options with Tornado

Just started playing with Tornado and want to offer multiple methods of authentication. Currently my app is working fine with Google's hybrid OpenID/oAuth using tornado.auth.GoogleMixin and the unauthenticated users are automatically sent to Google's auth page.
If an unauthenticated user wants to use another option (ie. local auth or tornado.auth.TwitterMixin), how can I implement the logic to choose an auth mechanism within the login handler?
I added the decorator 'tornado.web.authenticated' to all of my exposed methods, and here is the my login handler class (pretty much straight from the Tornado examples) which is currently working with Google OpenID/oAuth:
class AuthLoginHandler(BaseHandler, tornado.auth.GoogleMixin):
#tornado.web.asynchronous
def get(self):
if self.get_argument('openid.mode', None):
self.get_authenticated_user(self.async_callback(self._on_auth))
return
## redirect after auth
self.authenticate_redirect()
def _on_auth(self, user):
## auth fail
if not user:
raise tornado.web.HTTPError(500, 'Google auth failed')
## auth success
identity = self.get_argument('openid.identity', None)
## set identity in cookie
self.set_secure_cookie('identity', tornado.escape.json_encode(identity))
self.redirect('/')
Appreciate any suggestions for a solution. Thanks
I think the easiest way to do it would be to change the AuthLoginHandler to something more specific, like GoogleAuthHandler, and create an appropriate route for that:
(r"/login/google/", GoogleAuthHandler),
(r"/login/facebook/", FacebookAuthHandler),
etc.
Then simply create links to each authentication provider on the page ala:
<a href="/login/google/>Login with Google</a>
Login with Facebook
If you wanted to make it fancier, you could provide the providers as a select box, or if you wanted to get REALLY fancy, you could parse their 'openid' URL (e.g., if username.google.com, self.redirect("/login/google"), but that assumes that users know their OpenID provider URLs, which is usually not the case. I'd guess if you gave them a google / facebook / twitter icon or something to click on that would confuse the least number of people.
I came upon this problem myself but in a slightly different circumstance.
One solution is actually to do something like this.
class AuthLoginHandler(BaseHandler, tornado.auth.GoogleMixin, tornado.auth.TwitterMixin):
def get(self):
if want_google:
tornado.auth.GoogleMixin.get_authenticated_user(self)
#...
elif want_twitter:
tornado.auth.TwitterMixin.get_authenticated_user(self)
#...

Categories

Resources