I'm trying to integrate Mozilla Persona (browserid) into a Pyramid application. The login process is:
user can login on any page by clicking on the login button
a popup then shows a login form
when the users enters correct login/password, an ajax call is made by the popup to a Pyramid view that checks users credentials, and calls Pyramid remember function if the check succeeded
the browserid javascript code then reloads the current page
Now I want to handle the case of a new user subscribing to the web app and present a new view asking for a few more details (desired username, etc).
Since the "remember" function is called by an ajax call from the popup, I cannot redirect the user the the "/newuser" page.
So every view needs to redirect new users to the "/newuser" url whenever the remembered browserid has no corresponding user in the database.
Is there a way to intercept user requests before calling a view to call the "new_user" view instead? Or maybe my authentication approach is fundamentally incorrect and I should rely on another approach?
One way to do this would be to create an exception that should be raised when the user is created, and use this exception as the context of a view that would redirect to the new page.
class NewUser(Exception):
pass
#view_config(context=NewUser)
def new_user_exception(request):
return HTTPFound(request.route_path('new_user'))
Make sure the exception is raised during the first request after the first login (after having created the user object, for example), and the user will be redirected to the right page.
You could also put the code for the welcome page directly in new_user_exception, but without redirection, this page would have the url asked by the user, whatever it was.
Another solution would be to tweak how the persona part is done. For that, I'm going to guess you are using pyramid_persona (I'm the writer :) ). If not, what I'm saying will still apply, and will be even simpler to do.
What you could do is :
Change the login view so that it includes in the response a boolean saying whether this is the first login or not.
Change the javascript to check this boolean, reload the page if it's not the first time, and redirect to the welcome page if it.
The code for the login view can use pyramid_persona's login view like this :
from pyramid_persona.views import login
#view_config(route_name='login')
def new_login(request):
response = login(request)
if response.status == 200: #the login worked
# tweak the response
return response
EDIT : There's now a part about this in pyramid_persona's documentation : Do extra work or verification at login.
Related
I am using the Django staff_member_required decorator to protect an admin area of the site.
I am using it like this
#staff_member_required(login_url=reverse_lazy('account_login'))
def kommando_home(request):
# business logic
return render(request, 'kommando/home.html', context)
I am using the custom login so users do not see the Django login page if they hit the URL.
However, if a user who does not have staff permision logs in, it just results in this:
I can add a redirect parameter to the decorator but that always redirects the user to the url provided even if the user has permission.
I tried looking into customizing the decorator but I do not see any way to check if permission denied is raised.
The reason for the infinite loop is this. The #staff_member_required requirement is not met since the user is not staff, which takes the user to the login_url, but the user is already logged in, so the account_login takes the user to it's next parameter, which is the original page with staff_member_required, etc...
What you might try instead is to check for the permission in the view itself, then redirect from there:
Check out Serafeim's answer at How to check the user's permissions in views.py?
Use has_perm:
So, from inside your get_context_data you can do something like this:
if self.request.user.has_perm('applications.admin_access'):
# redirect to one page
else:
# redirect to the other page
Say I have two pages one is example.com/login and another page is example.com/admin
And when I put the credentials on the login page I get redirected to the admin page.
Admin page has a logout button. If I press that button then it redirects me to the login page again.
What I exactly want to do is, I want to display a message "Login again" dynamically (I know how to display a message dynamically) but only when user gets redirected from the login page via admin panel.
How can I do that?
You can do that either by:
Using Session:
upon logout you set a variable in the session, that this user has been loged out.
logout(request)
request.session['logged_out'] = True
Get parameter:
add a parameter to the redirected login url, if you find that parameter show you message, if there is no parameter you don't have to show.
redirect('login/?logged-out=True')
in both cases you have to check in your view, and add a a property to check with in your context.
Login required decorator is not working properly in the django, it will not redirect properly to the login page if user is not registered or logged in.
So in my django framework i made the login page other pages in the project.Now i want say if some other third party user try to run my any webpage on that specific time my website ask him/her for login before accessing my any website page,to resist that i used the login required decorator but when i logged in and copy my other webpage url and paste in the new window it will not show the login page just straight open that webpage in the new window.HOW DO I FIX IT????HELP ME OUT PLEASE.......
URLS OF MY WEBPAGES:-
path("loggedin/",views.loggedin,name="loggedin"),
VIEW PAGE:-
from django.contrib.auth.decorators import login_required
This is my index page where user can register his/her self and after that they will login and go to the next page......
def index(request):
return render(request,'userside/index.html')
And this is the page which comes after the index(main dashboard) page
#login_required(login_url='userside/loggedin')
##staff_member_required
def mainpage(request):
return render(request,"userside/mainpage.html")
The other webpage of my project
#login_required(login_url='/userside/loggedin')
def criminalsinfo(request):
crimins=Criminals.objects.all()
return render(request,'userside/criminalsinfo.html',{'crimins':crimins})
yes means in the same browser we open a new window
That means you are already logged in.
To confirm it, in your browser, visit your page and in cookies check if have sessionid or not. If yes, then it means you are already logged in.
Possible solutions:
Remove sessionid.
Use incognito mode.
Use another browser.
Flask-login doc says we should validate next using next_is_valid(), but I can't find any such method:
Warning: You MUST validate the value of the next parameter. If you do not, your application will be vulnerable to open redirects.
#app.route('/login', methods=['GET', 'POST'])
def login():
# Here we use a class of some kind to represent and validate our
# client-side form data. For example, WTForms is a library that will
# handle this for us.
form = LoginForm()
if form.validate_on_submit():
# Login and validate the user.
login_user(user)
flask.flash('Logged in successfully.')
next = flask.request.args.get('next')
if not next_is_valid(next):
return flask.abort(400)
return flask.redirect(next or flask.url_for('index'))
return flask.render_template('login.html', form=form)
Running this I get the error:
NameError: global name 'next_is_valid' is not defined
And if I do:
from flask.ext.login import next_is_valid
>> ImportError: cannot import name next_is_valid
Where is the next_is_valid() function, and if it doesn't exist, how do I validate the next parameter?
It doesn't say you must validate next with next_is_valid, only that
You MUST validate the value of the next parameter.
next_is_valid is just an example function.
You must determine if next is valid based on your own criteria. next is the url to redirect to on a successful login. If you have any permissions to apply or restrictions on your site this is where you would want to make sure they are enforced.
For example, a user could attempt to login with the request url http://example.com/login?next=admin/delete/all/users. If the login attempt was successful and the admin permission was not checked within your login function or on the endpoint itself, well, bad things could happen. It all depends on how you structure your application and control access to individual endpoints.
In addition to the examples mentioned by other answers, next could also be next=malicioussite.url. If a malicious actor sent someone to your login link with next set to their malicious site, then after logging in the user could think they are still on your site, but instead have been directed somewhere dangerous. Make sure to validate next against redirecting to other websites.
Question Clarification:
I'm trying to test if the user is authenticated or not for each page request.
I'm trying to use Authentication for the first time in Django and I am not grasping how the login view is supposed to handle authentications.
When I use #login_required, I'm redirecting to "/login" to check if the user is logged in and if not, display the login page. However, trying to redirect back to the original page is causing an infinite loop because it's sending me back to the login page over and over again.
I'm clearly not grasping how #login_required is supposed to work but I'm not sure what I'm missing. I've been searching around for awhile for an example, but everyone uses the default #login_required without the 'login_url' parameter.
So for example.. the page I'm trying to access would be...
#login_required(login_url='/login')
def index(request):
And then my login would be.. (obviously incomplete)..
Edit: just to note.. the session variables are set in another view
def login(request):
if '_auth_user_id' in request.session:
# just for testing purposes.. to make sure the id is being set
print "id:",request.session['_auth_user_id']
try:
user = Users.objects.get(id=request.session['_auth_user_id'])
except:
raise Exception("Invalid UserID")
# TODO: Check the backend session key
# this is what I'm having trouble with.. I'm not sure how
# to redirect back to the proper view
return redirect('/')
else:
form = LoginForm()
return render_to_response('login.html',
{'form':form},
context_instance=RequestContext(request)
)
Well, as you say, obviously that's not going to work, because it's incomplete. So, until you complete it, you're going to get an infinite loop - because you haven't written the code that puts _auth_user_id into request.session.
But I don't really know why you're making that test in the first place. The auth documentation has a perfectly good example of how to write a login view: get the username and password from the form, send them to authenticate to get the user object, then pass that to login... done.
Edit I think I might see where your confusion is. The login_required decorator itself does the check for whether the user is logged in - that's exactly what it's for. There's no need for you to write any code to do that. Your job is to write the code that actually logs the user in, by calling authenticate and login.
Try to call login(), see the next please:
https://docs.djangoproject.com/en/dev/topics/auth/#django.contrib.auth.login