Narcisse Doudieu Siewe
Narcisse Doudieu Siewe

Reputation: 1094

datas' session not well managed with pyramid_beaker

I have the following codes, I'm using pyramid_beaker + gunicorn + pyramid_jinja2.

I noticed that when user is logged in, if I quickly and repeatedly do a "GET" to "http://my_server_ip_adress/addClientPersonne", I got many times a permission deny as if the logged user doesn't have "add_client" permission which is not normal. When making a "print session" I can see that sometimes the session has all the authentications informations to allow user to access the link above but another time it doesn't and the access is deny...maybe my configurations about pyramid_beaker are not good? any suggestions?

thanks.

my production.ini file

[app:main]
use = egg:annuaireldap#main
pyramid.includes = pyramid_beaker
                   pyramid_jinja2
session.key = annuaireldap
session.secret = iuyryoiuiytghvfs-tifrsztft
session.cookie_on_exception = true
session.type = memory


my views.py


@view_config(route_name="Menu", renderer='templates/menu.jinja2', request_method='GET')
def menu(request):
    bootstrap_css_url = request.static_url('annuaireldap:static/bootstrap.min.css')
    bootstrap_js_url = request.static_url('annuaireldap:static/bootstrap.min.js')
    jquery_js_url = request.static_url('annuaireldap:static/jquery.min.js')
    custom_css_url = request.static_url('annuaireldap:static/custom_css.css')
    to_rend = {'bootstrap_css':bootstrap_css_url,'bootstrap_js':bootstrap_js_url,'jquery_js':jquery_js_url,'custom_css':custom_css_url}
    to_rend.update({'Menu_1':request.route_url('addClientPersonne'),
                    'Menu_2':request.route_url('addClientEntreprise'),
                    'Menu_3':request.route_url('SeeAll')})
    return to_rend            


@view_config(route_name='SeeAll', renderer='templates/menu.jinja2', request_method=('GET', 'POST'))
def seeall(request):
    return {}


@view_config(route_name='login', renderer='templates/login.jinja2', 
             request_method=('GET', 'POST'))
def login(request):
    bootstrap_css_url = request.static_url('annuaireldap:static/bootstrap.min.css')
    bootstrap_js_url = request.static_url('annuaireldap:static/bootstrap.min.js')
    jquery_js_url = request.static_url('annuaireldap:static/jquery.min.js')
    custom_css_url = request.static_url('annuaireldap:static/custom_css.css')
    settings = request.registry.settings
    server_uri = settings['server_uri']
    rendered_form = None
    base_dn_user = settings['base_dn_user']
    cl = Credentials().bind(request=request)
    se_connecter = deform.form.Button(name='se_connecter',
                                      title='se connecter')
    form = deform.form.Form(cl, buttons=(se_connecter,))
    url_redirect = request.route_url('login')
    session = request.session
    session.save()
    if authenticated_userid(request):
       url_redirect = request.route_url("Menu")
       resp = HTTPFound(location=url_redirect)
       return request.response.merge_cookies(resp)
    if request.method == 'POST':
       if 'se_connecter' in request.POST:
          try:
              deserialized = form.validate(request.POST.items())
              username = deserialized['username']
              password = deserialized['password']
              server = Server(server_uri)
              user_dn = 'uid=%s,%s'%(username, base_dn_user)
              user_dn = 'cn=admin,dc=splynx,dc=lan'
              password = '1235789'
              conn = Connection(server, user=user_dn, password=password)
              if conn.bind():
                 session[username] = ['agent']
                 remember(request, username)
                 url_redirect = request.route_url('Menu')
              resp = HTTPFound(location=url_redirect)
              return request.response.merge_cookies(resp)
          except ValidationFailure as e:
              rendered_form = e.render()
    else:
        rendered_form = form.render()
    return {'bootstrap_css':bootstrap_css_url, 
            'bootstrap_js':bootstrap_js_url, 
            'jquery_js':jquery_js_url, 
            'rendered_form':rendered_form,
            'custom_css':custom_css_url}



@view_config(route_name='addClientPersonne', permission='add_client',
             request_method=('GET', 'POST'), renderer='templates/addPersonne.jinja2')
def addClientPersonne(request):
    bootstrap_css_url = request.static_url('annuaireldap:static/bootstrap.min.css')
    bootstrap_js_url = request.static_url('annuaireldap:static/bootstrap.min.js')
    jquery_js_url = request.static_url('annuaireldap:static/jquery.min.js')
    custom_css_url = request.static_url('annuaireldap:static/custom_css.css')
    rendered_form = None
    settings = request.registry.settings
    cl = ClientPersonne().bind(request=request)
    ajouter = deform.form.Button(name='Ajouter',
                                 title='Ajouter')
    form = deform.form.Form(cl, buttons=(ajouter,))
    request.session.save()
    if request.method == 'POST':
       if 'Ajouter' in request.POST: 
         try:
            server_uri = settings['server_uri']
            server = Server(server_uri)
            deserialized = form.validate(request.POST.items())
            nom = deserialized['nom']
            prenom = deserialized['prenom']
            telephone = deserialized['telephone']
            description = deserialized['description']
            description = "" if description == colander.null else description
            creator_dn = settings['creator_dn']
            creator_pwd = settings['creator_pwd']
            conn = Connection(server, user=creator_dn, password=creator_pwd)
            base_clients_personnes = settings['base_clients_personnes']
            new_user_dn = 'uid=%s,%s'%(get_token(14), base_clients_personnes)
            if conn.bind():
               attributes = {'telephoneNumber':telephone,
                             'sn':nom,
                             'cn':prenom}
               if description:
                  attributes['description'] = description
               conn.add(new_user_dn, ['person', 'uidObject'], attributes)
               conn.unbind()  
            url_redirect = request.route_url('Menu')
            resp = HTTPFound(location=url_redirect)
            return request.response.merge_cookies(resp)
         except ValidationFailure as e:
            rendered_form = e.render()
         except Exception as e:
            rendered_form = form.render()  
    else:
       rendered_form = form.render()
    return {'bootstrap_css':bootstrap_css_url, 
            'bootstrap_js':bootstrap_js_url, 
            'jquery_js':jquery_js_url, 
            'rendered_form':rendered_form,
            'custom_css':custom_css_url}


my root factory

class CustomResourceFactory():
      __acl__ = [
                  (Allow, 'agent', {'add_client', 'modify_client', 'view_client', 'delete_client'}),
                  DENY_ALL
                ]
      def __init__(self, request):
          print "concombre"
          pass

Upvotes: 1

Views: 58

Answers (2)

Jyoti Amage
Jyoti Amage

Reputation: 23

The issue is with the gunicorn multiple workers. If you run this code with single worker it will run fine. The user session in is in memory for that worker and will not accessible from other workers.

So when you login the user details will be with only that worker and when hit the next GET call the request will go to the different worker where it will not get the user details and it will deny your request.

Upvotes: 0

Michael Merickel
Michael Merickel

Reputation: 23341

If you have gunicorn configured to fork then you can't use an in-memory session store as it will not be shared across processes. You can confirm that this is the issue by turning off forking in gunicorn or switching to a wsgi server like waitress that does not fork.

Upvotes: 0

Related Questions