How to access session data in a signal handler? - django

Whenever a visitor who is not a user adds content to my site I just create a dummy user account and store it's id in the session of that visitor.
Now when a visitor finally logs in using Facebook, Google or any other OAuth I want to merge the dummy user with the real user account. I figure a good way would be to catch the login signal. But in order to find the previous dummy user account I need to enter the session data. How can I get to it from within the handler?
If it's not possible than how to approach this problem?
Please note that I want to be able to use various login apps like django-social-auth so I need a solution that hooks in very clean.
Thank you for your time.

The login signal includes the current request as one of it's parameters:
https://docs.djangoproject.com/en/1.7/ref/contrib/auth/#module-django.contrib.auth.signals
Something like:
#receiver(signal=user_logged_in)
def merge_accounts(sender, request, user, **kwargs):
user.update_details_from(request.session['your-dummy-data'])

Related

Flask Dance oauth on different domains

I am implementing a Oauth for different services and I am using "OAuth2ConsumerBlueprint" (using flask-dance).
I was thinking about Flask-OAuth but I think I would end up with the same issues I am facing with Flask-Dance.
What I am planning to do is:
User go on ".mydomain.com"
User click on Login via FB for example
User goes on social.mydomain.com (so that the authorized URL is always the same)
User after login should be brought to ".mydomain.com"
it looks like I cannot find a way to do it.. It should be feasible. I tried to parse out different information eg.:
print(request)
print(request.referrer)
I even used: #oauth_authorized.connect
Printed all the information to see if I could collect some additional information to reuse
print(vars(request))
print(vars(blueprint))
print(vars(token))
print(session)
Also I tried to add in the GET parameters a "foo" variable to see if I could read it back again from the social.mydomain.com but I couldn't. No idea on how to redirect the user back to the original .mydomain.com
Any suggestions here on how can I have the authentication done on a specific subdomain (so I only need to whitelist one subdomain) and then redirect the user to his own domain?
That is how I setup everything:
facebook = OAuth2ConsumerBlueprint(
"fb_social", __name__, url_prefix='/fb',
client_id=FB_CLIENT_ID,
client_secret=FB_SECRET,
scope='email',
base_url="https://graph.facebook.com/",
token_url="https://graph.facebook.com/oauth/access_token",
authorization_url="https://www.facebook.com/dialog/oauth",
redirect_to='fb_social.social_facebook',
)
Thanks a lot
Hook into the oauth_authorized signal, and return a redirect to the location where you want the user to go.

AWS Cognito custom auth - sending metadata to a challenge lambda functions

I'm developing a custom passwordless auth to sign into a Cognito user pool. I will describe what I'm trying to implement in case anything is silly. I want a user to enter their email address, then receive a magic login link via email, and when they click on that be taken back to the site and be logged in.
This uses custom auth lambda functions to define/create a challenge with a time based password and send it to the user in an email. I am having a couple of problems:
Problem 1)
When the user returns with the code they might not be in the same browser/device and certainly won't be in the same tab so they don't have the session, meaning I need to call cognitoUser.initiateAuth again. This goes through the define/create challenge lambdas again so a second email gets sent even though at this point the user is coming from the email link so already has the code. Note: the session id is not available in the event object when the challenge is created, also I've read these sessions only last 3 minutes and my time based passwords will last ~15minutes, so I don't think I can include the session id in the email.
Problem 2)
You can login from a few places (browser, android app, etc) and I would like to be able to include the url or at least protocol as a parameter to control what gets sent in the email, e.g. if you entered your email address in the android app then the email you get would be myapp://login?code=xxx and if you did it on the web it would be https://example.com/login?code=xxx
It seems like I would be able to implement both of these to work properly if only I could find some way to send custom metadata through to the DefineChallenge and CreateChallenge lambda such that it would appear in the event object. I thought adding ValidationData to the AuthenticationDetails object would do this, but that information doesn't appear in the event object in the Lambda fns.
The workaround I've found is to create a new client id for every situation - one for initiating auth, one for redeeming token, and repeat for each different protocol. But that is a lot of client ids quickly - a pain to mantain and clumsy.
So tl;dr is: I want to send custom metadata from my cognitoUser.initiateAuth(...) call in JS and have it available in my Define/Create Challenge lambda fns.
You can split the authentication process into multiple custom auth challenges. This allows custom auth state to be supplied via the challenge response as client metadata.
Auth session state must be persisted in a database in order to be shared between devices.
Your custom login flow will probably have two challenge steps: the first prompts for auth type and the second prompts for the secret code. The action taken by the "Create Auth Challenge" Lambda will depend on the auth type. If the auth type is "Email" then the secret code and magic link are generated, stored in DynamoDB and emailed. If the auth type is "MagicLink" then the secret is loaded from DynamoDB. Clicking on a Magic link will initiate a new auth session and automatically supply all the challenge answers.
There are a few other things to consider:
Your magic link needs to encapsulate the Cognito username as well as the one-time secret and probably some other session id that is used as a key in dynamodb.
You probably should not put app-specific links into your emails. Instead associate your domain with your app and/or leverage the redirect URI parameter of your web-based login page.
You can also access custom Cognito user attributes from the Lambda function which can be used to indicate user login preferences (eg Email vs SMS for login codes).

which could be a good way to design an authentication mechanism to restrict the access to the backend to only registered users?

I'm making a mobile app that allows a registered user to
make a list of favourite email addresses.
I pretend to make the authentication process through openId,
so the user can login to the system using its gmail account.
The registered users of the system can insert many email
addresses to a database.
Then I have many controller methods.
One of them is getUsersByName(admin_email), which receives the email
of a registered user and returns a list of email adress inserted
by that user.
Now, the problem is that I don't want everyone can access
to getUsersByName(admin_email) and retrieve the response
related to every registered user.
What options do I have so only the user that inserted the email
addresses can access to the list related to it.
For instance, if a registered user calls getUsersByName(admin_email),
the server responses with the right list, but if someone not
registered makes an http request to getUsersByName(admin_email), the
server responses with a JSON error object.
My backend is in django and I want to make the client in Android.
I hope I have been clear enough.
Thanks in advance!
The easiest way to achieve what you're looking for is this and I'm going to assume Django 1.6 and that you're using a functional view and not a Class based View.
#login_required
def getUsersByName(request):
user_email = request.user.email
all_users_emails = UserEmail.objects.filter(added_by=user_email)
return render_to_response(...)
What this does is that this view is now protected by the decorator #login_required from being accessed if you're not logged in, i.e. you have to be registered and logged in, in order to view your added emails.
It will also redirect to your login view if an unregistered users tries to gain access to the view.
Furthermore by doing it like this, your users will never be able to send in others email addresses in order to gain access to them.
For Class based views you can take two approaches, both explained here

How Can I retain session information once a user registers (Django)?

When a new user is created, I want to retain some of the information in their session
e.g. things a user has stored in their session I want to use once they have registered (or logged in).
I would use either a post_save signal on the user model (or an auth login signal), but it appears that the signals don't put the request, or session into the signal sent. It also seems I can't easily get the session from just the user.
I'm using Django 1.4
Edit: let me give an example.
The problem boils down to this - I may want to retain information for a user's activities before they login, but where do I store this information before they login? A good place would be a session (or I could link the data held in a db to the session, using the session a little like a makeshift user).
In any case, until they login, I can simply use their session like a user credential, and store information that persists so long as their cookie does (how else can could I reliably track an anonymous user?).
But once they register (or log-in), I want to move that information from the session, into the account properly. One good reason is that it would make sense to delete data from anonymous users periodically, whereas registered user's data would be persisted.
To do this I simply want access to the session (could be via the request) from a handler to the new-user signal, so I can make a one-off transfer from data in the session. But the new-user signal doesn't hold the session (or request).
If you're using django.contrib.sessions and django.contrib.auth for the job, the session data should be retained automatically after login.
Moreover, the user_logged_in signal is sent along with request actually.
Edit:
So use user_logged_in signal. It carries request. Pick some specific key to store unauthenticated user's data (e.g. "_anonymous_data"). If that key is set on request.session while handeling signal, simply rewrite data on request.user.get_profile() object, call save and del request.session["_anonymous_data"].
The code to retreive it could look something like:
if request.user.is_authenticated():
user_data = request.user.get_profile()
else:
user_data = requerst.session["_anonymous_data"]
It's only a scratch of course. You don't want to hardcode session keys or write such logic in views. If you need it application wide, embed it in some abstraction class which takes request in __init__.
you could try using sessions:
https://docs.djangoproject.com/en/dev/topics/http/sessions/?from=olddocs

Is there django auth backend to authorize by temporary links?

I am searching a backend to authorize users by email without password. This backend should send them temprary authentication links to an inbox.
Is there any solution or I should write it myself?
Nothing like such available, so i fear you have to write it yourself.
As i understand, you can take lets say an "authentication_code" from a url you sent to user's mailbox.
http://example.net/allow/xauthcodex/
You can get 'xauthcodex' in view, which will later call authenticate() and then login().
You would have to write your own authentication backend though, that will take this auth_code, will check against it, and would return respective user, for login() function to work. I am assuming auth_code is unique for user.
Check out the http://bitbucket.org/lorien/django-urlauth/
I already wrote such application: http://github.com/svetlyak40wt/django-link-auth