Authentication in pyramid - python-2.7

I am trying to set up a basic navigation in pyramid (1.4a1). According to the tutorial given at tutorial groupfinder is called once we remember after login is successful. This works on my local but when I try the same on a server it doesn't call groupfinder at all and keeps looping between the two routes. Here's my code snippet:
from pyramid.security import remember, forget, authenticated_userid
from pyramid.httpexceptions import HTTPFound, HTTPForbidden
from pyramid.threadlocal import get_current_registry
from pyramid.url import route_url
from pyramid.view import view_config, forbidden_view_config
#view_config(route_name='index',
renderer='templates:templates/index.pt',
permission='Authenticated')
def index_view(request):
try:
full_name = (request.user.first_name + ' ' + request.user.last_name)
except:
full_name = "Anonymous"
return {"label": label, "user_name": full_name}
#forbidden_view_config()
def forbidden(request):
if authenticated_userid(request):
return HTTPForbidden()
loc = request.route_url('login.view', _query=(('next', request.path),))
return HTTPFound(location=loc)
#view_config(route_name='login.view')
def login_view(request):
came_from = request.route_url('index')
#perform some authentication
username = 'xyz'
if authenticate(username):
headers = remember(request, username)
#user was authenticated. Must call groupfinder internally and set principal as authenticated.
return HTTPFound(location=came_from, headers=headers)
else:
return HTTPForbidden('Could not authenticate.')
return HTTPForbidden('Could not authenticate.')
Also, my ACL looks like:
__acl__ = [(Allow, Authenticated, 'Authenticated'), DENY_ALL].
Can someone tell my why groupfinder is not being called? Is the request routing happening properly? Also, the same code works on my local setup fine. So there is no problem in groupfinder or ACL authorization settings.
Thanks much!

After lot of debugging and digging up I found out that the issue was very simple. Don't know the reason for the behavior but I had added secure = True attribute when calling AuthTktAuthenticationPolicy(). When I removed this attribute, it started working.

Related

Authentication with GitLab to a terminal

I have a terminal that served in webbrowser with wetty. I want to authenticate the user from gitlab to let user with interaction with the terminal(It is inside docker container. When user authenticated i ll allow him to see the containers terminal).
I am trying to do OAuth 2.0 but couldn't manage to achieve.
That is what i tried.
I created an application on gitlab.
Get the code and secret and make a http call with python script.
Script directed me to login and authentication page.
I tried to get code but failed(Their is no mistake on code i think)
Now the problem starts in here. I need to get the auth code from redirected url to gain access token but couldn't figure out. I used flask library for get the code.
from flask import Flask, abort, request
from uuid import uuid4
import requests
import requests.auth
import urllib2
import urllib
CLIENT_ID = "clientid"
CLIENT_SECRET = "clientsecret"
REDIRECT_URI = "https://UnrelevantFromGitlabLink.com/console"
def user_agent():
raise NotImplementedError()
def base_headers():
return {"User-Agent": user_agent()}
app = Flask(__name__)
#app.route('/')
def homepage():
text = 'Authenticate with gitlab'
return text % make_authorization_url()
def make_authorization_url():
# Generate a random string for the state parameter
# Save it for use later to prevent xsrf attacks
state = str(uuid4())
save_created_state(state)
params = {"client_id": CLIENT_ID,
"response_type": "code",
"state": state,
"redirect_uri": REDIRECT_URI,
"scope": "api"}
url = "https://GitlapDomain/oauth/authorize?" + urllib.urlencode(params)
print get_redirected_url(url)
print(url)
return url
# Left as an exercise to the reader.
# You may want to store valid states in a database or memcache.
def save_created_state(state):
pass
def is_valid_state(state):
return True
#app.route('/console')
def reddit_callback():
print("-----------------")
error = request.args.get('error', '')
if error:
return "Error: " + error
state = request.args.get('state', '')
if not is_valid_state(state):
# Uh-oh, this request wasn't started by us!
abort(403)
code = request.args.get('code')
print(code.json())
access_token = get_token(code)
# Note: In most cases, you'll want to store the access token, in, say,
# a session for use in other parts of your web app.
return "Your gitlab username is: %s" % get_username(access_token)
def get_token(code):
client_auth = requests.auth.HTTPBasicAuth(CLIENT_ID, CLIENT_SECRET)
post_data = {"grant_type": "authorization_code",
"code": code,
"redirect_uri": REDIRECT_URI}
headers = base_headers()
response = requests.post("https://MyGitlabDomain/oauth/token",
auth=client_auth,
headers=headers,
data=post_data)
token_json = response.json()
return token_json["access_token"]
if __name__ == '__main__':
app.run(host="0.0.0.0",debug=True, port=65010)
I think my problem is on my redirect url. Because it is just an irrelevant link from GitLab and there is no API the I can make call.
If I can fire
#app.route('/console')
that line on Python my problem will probably will be solved.
I need to make correction on my Python script or different angle to solve my problem. Please help.
I was totally miss understand the concept of auth2. Main aim is to have access_token. When i corrected callback url as localhost it worked like charm.

Django test Client can only login once?

Our team is currently writing tests for our application. I am currently writing code to acces the views. These views are behind a login-screen, so our test first have to login and than peform the rest of the test. I've run into a very strange error. Basically My tests can only login once.
As you can see in the example below, both classes are doing the exact same thing, yet only one of them succeeds with the login, the other gives a '302 doest not equal 200' assertion error.
If I comment out the bottom one, the one at the top works, and vice versa.
Code that is testing different views also doesnt work, unless I comment out all other tests.
It doesnt matter if I login like shown below, or use a different variant (like self.client.login(username='test', password='password')).
Me and my team have no idea why Django is behaving this way and what we are doing wrong. Its almost as if the connection remains open and we would have to add code to close it. But the django-documentation doesnt mention any of this. DOes anyone know what we are doing wrong?
class FunctieListView_tests(TestCase):
"""Function listview only shows the data for the current_user / tenant"""
def setUp(self):
self.tenant = get_tenant()
self.function = get_function(self.tenant)
self.client = Client(HTTP_HOST='tc.tc:8000')
self.user = get_user(self.tenant)
def test_correct_function_context(self):
# Test if the view is only displaying the correct context data
self.client.post(settings.LOGIN_URL, {
'username': self.user.username,
'password': 'password'
}, HTTP_HOST='tc.tc:8000')
response = self.client.get(reverse('functie_list'))
self.assertEqual(response.status_code, 200)
self.assertTrue(response.context['functie_templates'] != None)
self.assertEqual(response.context['functie_templates'][0],
FunctieTemplate.objects.filter(linked_tenant=self.tenant)[0])
class FunctieListView_2_tests(TestCase):
"""Role Listview only shows the data for the current_user / tenant"""
def setUp(self):
self.tenant = get_tenant()
self.function = get_function(self.tenant)
self.client = Client(HTTP_HOST='tc.tc:8000')
self.user = get_user(self.tenant)
def test_correct_function_context_second(self):
#login
# Test if the view is only displaying the correct context data
self.client.post(settings.LOGIN_URL, {
'username': self.user.username,
'password': 'password'
}, HTTP_HOST='tc.tc:8000')
response = self.client.get(reverse('functie_list'))
self.assertEqual(response.status_code, 200)
self.assertTrue(response.context['functie_templates'] != None)
self.assertEqual(response.context['functie_templates'][0],
FunctieTemplate.objects.filter(linked_tenant=self.tenant)[0])
The users, tenants and functions are defined in a seperate utils file like so:
def get_user(tenant, name='test'):
u = User.objects.create_user(name, '{}#test.test'.format(name), 'password')
u.save()
u.profile.tenant = tenant
u.profile.tenant_role = generis.models.TENANT_OWNER
u.profile.save()
return u
def get_function(tenant):
userfunction = UserFunction.objects.create(name='test_functie', linked_tenant=tenant)
userfunction.save()
return userfunction
def get_tenant(slug_var='tc'):
f = elearning.models.FontStyle(font='foobar')
f.save()
c = elearning.models.ColorScheme(name='foobar', title='foo', text='fleeb', background='juice', block_background='schleem', box='plumbus')
c.save()
t = elearning.models.Tenant(name='tc', slug=slug_var, default_font_style=f, default_color_scheme=c)
t.save()
return t
My guess is that it happens because you are instantiating the Client yourself in setUp. Although it looks fine the outcome is obviously different from the regular behavior. I never had problems with login using the preinitialized self.client of django.test.TestCase.
Looking at django.test.client.Client, it says in the inline documentation:
Client objects are stateful - they will retain cookie (and thus session) details for the lifetime of the Client instance.
and a still existing cookie would explain the behavior you describe.
I cannot find HTTP_HOST in django.test.client.py, so I'm not sure whether you are really using that Client class at all. If you need access to a live server instance during tests, you could use Django's LiveServerTestCase.

Django signup/login not directing users to ?next=/my/url

Setup
I use [django-allauth][1] for user accounts.
# urls.py
url(r'^login$', allauth.account.views.login, name="account_login"),
url(r'^join$', allauth.account.views.signup, name="account_signup"),
.
# settings.py
LOGIN_REDIRECT_URL = '/me'
LOGIN_URL = '/join' # users sent here if they run into #login_required decorator
# To collect additional info if user signs up by email:
ACCOUNT_SIGNUP_FORM_CLASS = 'allauth.account.forms.WinnerSignupForm'
.
That custom signup form:
# account/forms.py
from .models import Winner, FriendCode
class WinnerSignupForm(forms.ModelForm):
"""
This is the additional custom form to accompany the default fields email/password (and maybe username)
"""
class Meta:
model = Winner
fields = ('author_display_name','signupcode',)
widgets = {'author_display_name':forms.TextInput(attrs={
'placeholder': _('Display Name'), # 'Display Name',
'autofocus': 'autofocus',
})
,
'signupcode': forms.TextInput(attrs={
'placeholder': _('Invite code (optional)'),
'autofocus': 'autofocus'
})
}
def signup(self, request, user):
# custom code that performs some account setup for the user
# just runs a procedure; there's no "return" at end of this block
I don't think my custom WinnerSignupForm is causing the issue, because the problem persists even if I disable it (i.e., I comment out this line from settings.py: ACCOUNT_SIGNUP_FORM_CLASS = 'allauth.account.forms.WinnerSignupForm')
Behaviour
0. Without ?next=/some/url parameter:
Thanks to LOGIN_REDIRECT_URL in settings.py, if I visit example.com/join or example.com/login, I'll wind up on example.com/me
That is fine.
1. If I am already logged in, everything works as expected:
A) If I visit https://example.com/login?next=/some/url,
I'm immediately forwarded to https://example.com/some/url (without being asked to log in, since I am already logged in).
I conclude the /login view is correctly reading the next=/some/url argument.
B) Similarly, if I visit https://example.com/join?next=/some/url, I'm immediately forwarded to https://example.com/some/url.
I conclude the /join view is also correctly reading the next=/some/url argument.
2. If I log in or sign up by social account, everything works as expected
This uses allauth/socialaccount
After I sign up or log in, I'm forwarded to https://example.com/some/url
However, here's the problem:
3. But! If I log in by email, ?next=/some/url is being ignored:
A) If I visit https://example.com/login?next=/some/url, I'm brought first to the /login page.
If I log in by email, I'm then forwarded to https://example.com/me
For some reason now, the ?next= is not over-riding the default LOGIN_REDIRECT_URL in settings.
(If I log in via Twitter, the ?next= paramter is correctly read, and I'm brought to https://example.com/some/url.)
B) Similarly, if I visit https://example.com/join?next=/some/url, I'm brought first to the /join (signup) page, and after successful login by email, I'm brought to /me, i.e., the fallback LOGIN_REDIRECT_URL defined in settings.py.
Inspecting the POST data in the signup/login form, the "next" parameter is there alright: {"next": "/some/url", "username": "myusername", "password": "..."}
More context
Extracts from django-allauth:
# allauth/account/views.py
from .utils import (get_next_redirect_url, complete_signup,
get_login_redirect_url, perform_login,
passthrough_next_redirect_url)
...
class SignupView(RedirectAuthenticatedUserMixin, CloseableSignupMixin,
AjaxCapableProcessFormViewMixin, FormView):
template_name = "account/signup.html"
form_class = SignupForm
redirect_field_name = "next"
success_url = None
def get_form_class(self):
return get_form_class(app_settings.FORMS, 'signup', self.form_class)
def get_success_url(self):
# Explicitly passed ?next= URL takes precedence
ret = (get_next_redirect_url(self.request,
self.redirect_field_name)
or self.success_url)
return ret
...
.
# allauth/account/utils.py
def get_next_redirect_url(request, redirect_field_name="next"):
"""
Returns the next URL to redirect to, if it was explicitly passed
via the request.
"""
redirect_to = request.GET.get(redirect_field_name)
if not is_safe_url(redirect_to):
redirect_to = None
return redirect_to
def get_login_redirect_url(request, url=None, redirect_field_name="next"):
redirect_url \
= (url
or get_next_redirect_url(request,
redirect_field_name=redirect_field_name)
or get_adapter().get_login_redirect_url(request))
return redirect_url
_user_display_callable = None
...
I'm pretty sure it was originally working when I installed [django-allauth][1] out of the box. I must have somehow interfered to break this ?next=/some/url functionality, though I can't remember the last time it was working or find out what I've done to mess things up.
Any tips on troubleshooting would be greatly appreciated.
(In case relevant -- perhaps settings are not being read correctly;
ACCOUNT_LOGIN_ON_PASSWORD_RESET = True in settings.py seems to be ignored, users have to log in after resetting their password.)
#Akshay, the following work-around worked for me.
I added the following lines to allauth/account/adapter.py, within the get_login_redirect_url sub-function.
goto = request.POST.get('next', '')
if goto:
return goto
To clarify, the result looks like this:
class DefaultAccountAdapter(object):
# no change to stash_verified_email, unstash_verified_email, etc.
# edit only get_login_redirect_url as follows
def get_login_redirect_url(self, request):
"""
Returns the default URL to redirect to after logging in. Note
that URLs passed explicitly (e.g. by passing along a `next`
GET parameter) take precedence over the value returned here.
"""
assert request.user.is_authenticated()
url = getattr(settings, "LOGIN_REDIRECT_URLNAME", None)
if url:
warnings.warn("LOGIN_REDIRECT_URLNAME is deprecated, simply"
" use LOGIN_REDIRECT_URL with a URL name",
DeprecationWarning)
else:
url = settings.LOGIN_REDIRECT_URL
# Added 20170301 - look again for ?next parameter, as work-around fallback
goto = request.POST.get('next', '')
if goto:
return goto
print "found next url in adapter.py"
else:
print "no sign of next in adapter.py"
# end of work-around manually added bit
return resolve_url(url)
# leave remainder of fn untouched
# get_logout_redirect_url, get_email_confirmation_redirect_url, etc.
I still don't know how I broke this functionality in the first place, so I won't mark my answer as accepted/best answer. It does, however, resolve the issue I had, so I am happy. Hope this is useful to others.

Beaker session in bottle

while using beaker session, i came across to use same session object along the whole application.
I came through this url: Bottle.py session with Beaker
But, still i am getting 'KeyError' when i am trying to access the save session value in one function by another function.
my rest.py file looks like:
import bottle
from bottle import route,default_app
from beaker.middleware import SessionMiddleware
app = bottle.default_app()
#bottle.hook('before_request')
def setup_request():
request.session = request.environ['beaker.session']
#app.route('/login')
def login():
request.session['uname'] = 'user'
#app.route('/logout')
def logout():
print request.session['uname']
# expecting to print user
session_opts = {
'session.type': 'file',
'session.data_dir': '/tmp/',
'session.cookie_expires': True,
}
app = SessionMiddleware(bottle.default_app(),session_opts)
I have mentioned the SessionMiddleware at the end as im getting errors with the help of this link https://groups.google.com/forum/#!topic/bottlepy/m0akSbWRpZg
But when i am accessing request.session in the logout function i am getting
'KeyError': Uname not found
can any one give clear example of how to adjust the code inorder to maintain same session in whole application.

How to forced logout a user when sessions stored in cache?

In certain circumstances I'd like to let the staff to kick out some users.
My django 1.8 site stores sessions in redis.
I tried this solution in my view:
#will be removed in 1.9
from django.utils.importlib import import_module
#staff_member_required
def kickout_user(request, username):
u = User.objects.get(username = username)
SessionStore = import_module(settings.SESSION_ENGINE).SessionStore
active_users = Request.objects.active_users(seconds=60)
active_users_ids = [user.id for user in active_users]
for session in stored_sessions:
SessionStore = import_module(settings.SESSION_ENGINE).SessionStore
s = SessionStore(session_key=session.session_key)
session_uid = session.get_decoded().get('_auth_user_id')
print 'session', session_uid
if session_uid == u.id:
print 'session going to be deleted for uid:', session_uid
session.delete()
print ' session deleted'+ u.username
But it gives this error:
global name 'Request' is not defined
There also some suggestions here, but they are either flawd or based writing additional middlewares that I find overkill and try to aovid.
You can try django-force-logout
and also visit this_link for more assistance