Beginners question on Authentication ...

129 views
Skip to first unread message

Jon Paris

unread,
Apr 22, 2020, 4:08:14 PM4/22/20
to web2py-users
In the section on basic Authentication in the documents (http://web2py.com/books/default/chapter/29/03/overview#An-image-blog) it says to include in the model the following:

from gluon.tools import Auth
auth = Auth(db)
auth.define_tables(username=True)

And to add this to the default controller.

def user():
    return dict(form=auth())

But _where_?  

The def user(); part was already in the base controller.

So I just added the "from ..." to the start of the file where it already had:
from gluon.contrib.appconfig import AppConfig

That cause the app to fail with a message that db did not exist.

So I moved the two action lines down to the end following the table definition. No error that way but no authentication occurs either.

So where is the stuff supposed to go so that it is actioned? 



Jim S

unread,
Apr 22, 2020, 4:30:31 PM4/22/20
to web2py-users
Jon

Can you post the traceback that you're receiving?

-Jim

Jon Paris

unread,
Apr 22, 2020, 5:09:04 PM4/22/20
to web2py-users
Well there's not error message right now - but if I move these two lines:

auth = Auth(db)
auth.define_tables(username=True)

 back to the beginning of the file (after the from ...) then I get this:

Traceback (most recent call last):
  File "/Applications/web2py.app/Contents/MacOS/gluon/restricted.py", line 219, in restricted
    exec(ccode, environment)
  File "/Applications/web2py.app/Contents/MacOS/applications/Images/models/db.py", line 9, in <module>
    auth = Auth(db)
NameError: name 'db' is not defined

In what would appear to my (very) untrained eye - if I leave them at the end of the file then there is no error ... but no authentication either.

Jim Steil

unread,
Apr 22, 2020, 5:34:11 PM4/22/20
to web...@googlegroups.com
I'm guessing if at the top, they are getting called before db is defined.

Are you able to share your db.py?

-Jim

--
Resources:
- http://web2py.com
- http://web2py.com/book (Documentation)
- http://github.com/web2py/web2py (Source code)
- https://code.google.com/p/web2py/issues/list (Report Issues)
---
You received this message because you are subscribed to a topic in the Google Groups "web2py-users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/web2py/51UaQT4SxbQ/unsubscribe.
To unsubscribe from this group and all its topics, send an email to web2py+un...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/web2py/535b6e39-a1a8-48bb-944a-f836b9d6e835%40googlegroups.com.

Jon Paris

unread,
Apr 22, 2020, 5:39:33 PM4/22/20
to web...@googlegroups.com
# -*- coding: utf-8 -*-

# -------------------------------------------------------------------------
# AppConfig configuration made easy. Look inside private/appconfig.ini
# Auth is for authenticaiton and access control
# -------------------------------------------------------------------------
from gluon.contrib.appconfig import AppConfig
from gluon.tools import Auth
# If these tqwo lines are ativated they cause the db not ddefined error.
#   If active at the end of the source then no error but no authenticalion either
# auth = Auth(db)
# auth.define_tables(username=True)



# -------------------------------------------------------------------------
# This scaffolding model makes your app work on Google App Engine too
# File is released under public domain and you can use without limitations
# -------------------------------------------------------------------------

if request.global_settings.web2py_version < "2.15.5":
    raise HTTP(500, "Requires web2py 2.15.5 or newer")

# -------------------------------------------------------------------------
# if SSL/HTTPS is properly configured and you want all HTTP requests to
# be redirected to HTTPS, uncomment the line below:
# -------------------------------------------------------------------------
# request.requires_https()

# -------------------------------------------------------------------------
# once in production, remove reload=True to gain full speed
# -------------------------------------------------------------------------
configuration = AppConfig(reload=True)

if not request.env.web2py_runtime_gae:
    # ---------------------------------------------------------------------
    # if NOT running on Google App Engine use SQLite or other DB
    # ---------------------------------------------------------------------
    db = DAL(configuration.get('db.uri'),
             pool_size=configuration.get('db.pool_size'),
             migrate_enabled=configuration.get('db.migrate'),
             check_reserved=['all'])
else:
    # ---------------------------------------------------------------------
    # connect to Google BigTable (optional 'google:datastore://namespace')
    # ---------------------------------------------------------------------
    db = DAL('google:datastore+ndb')
    # ---------------------------------------------------------------------
    # store sessions and tickets there
    # ---------------------------------------------------------------------
    session.connect(request, response, db=db)
    # ---------------------------------------------------------------------
    # or store session in Memcache, Redis, etc.
    # from gluon.contrib.memdb import MEMDB
    # from google.appengine.api.memcache import Client
    # session.connect(request, response, db = MEMDB(Client()))
    # ---------------------------------------------------------------------

# -------------------------------------------------------------------------
# by default give a view/generic.extension to all actions from localhost
# none otherwise. a pattern can be 'controller/function.extension'
# -------------------------------------------------------------------------
response.generic_patterns = [] 
if request.is_local and not configuration.get('app.production'):
    response.generic_patterns.append('*')

# -------------------------------------------------------------------------
# choose a style for forms
# -------------------------------------------------------------------------
response.formstyle = 'bootstrap4_inline'
response.form_label_separator = ''

# -------------------------------------------------------------------------
# (optional) optimize handling of static files
# -------------------------------------------------------------------------
# response.optimize_css = 'concat,minify,inline'
# response.optimize_js = 'concat,minify,inline'

# -------------------------------------------------------------------------
# (optional) static assets folder versioning
# -------------------------------------------------------------------------
# response.static_version = '0.0.0'

# -------------------------------------------------------------------------
# Here is sample code if you need for
# - email capabilities
# - authentication (registration, login, logout, ... )
# - authorization (role based authorization)
# - services (xml, csv, json, xmlrpc, jsonrpc, amf, rss)
# - old style crud actions
# (more options discussed in gluon/tools.py)
# -------------------------------------------------------------------------

# host names must be a list of allowed host names (glob syntax allowed)
auth = Auth(db, host_names=configuration.get('host.names'))

auth.define_tables(username=True)

# -------------------------------------------------------------------------
# create all tables needed by auth, maybe add a list of extra fields
# -------------------------------------------------------------------------
auth.settings.extra_fields['auth_user'] = []
auth.define_tables(username=False, signature=False)

# -------------------------------------------------------------------------
# configure email
# -------------------------------------------------------------------------
mail = auth.settings.mailer
mail.settings.server = 'logging' if request.is_local else configuration.get('smtp.server')
mail.settings.sender = configuration.get('smtp.sender')
mail.settings.login = configuration.get('smtp.login')
mail.settings.tls = configuration.get('smtp.tls') or False
mail.settings.ssl = configuration.get('smtp.ssl') or False

# -------------------------------------------------------------------------
# configure auth policy
# -------------------------------------------------------------------------
auth.settings.registration_requires_verification = False
auth.settings.registration_requires_approval = False
auth.settings.reset_password_requires_verification = True

# -------------------------------------------------------------------------  
# read more at http://dev.w3.org/html5/markup/meta.name.html               
# -------------------------------------------------------------------------
response.meta.author = configuration.get('app.author')
response.meta.description = configuration.get('app.description')
response.meta.keywords = configuration.get('app.keywords')
response.meta.generator = configuration.get('app.generator')
response.show_toolbar = configuration.get('app.toolbar')

# -------------------------------------------------------------------------
# your http://google.com/analytics id                                      
# -------------------------------------------------------------------------
response.google_analytics_id = configuration.get('google.analytics_id')

# -------------------------------------------------------------------------
# maybe use the scheduler
# -------------------------------------------------------------------------
if configuration.get('scheduler.enabled'):
    from gluon.scheduler import Scheduler
    scheduler = Scheduler(db, heartbeat=configuration.get('scheduler.heartbeat'))

# -------------------------------------------------------------------------
# Define your tables below (or better in another model file) for example
#
# >>> db.define_table('mytable', Field('myfield', 'string'))
#
# Fields can be 'string','text','password','integer','double','boolean'
#       'date','time','datetime','blob','upload', 'reference TABLENAME'
# There is an implicit 'id integer autoincrement' field
# Consult manual for more options, validators, etc.
#
# More API examples for controllers:
#
# >>> db.mytable.insert(myfield='value')
# >>> rows = db(db.mytable.myfield == 'value').select(db.mytable.ALL)
# >>> for row in rows: print row.id, row.myfield
# -------------------------------------------------------------------------

# -------------------------------------------------------------------------
# after defining tables, uncomment below to enable auditing
# -------------------------------------------------------------------------
# auth.enable_record_versioning(db)

db = DAL("sqlite://storage.sqlite")

db.define_table('image',
                Field('title', unique=True),
                Field('file', 'upload'),
                format = '%(title)s')

db.define_table('post',
                Field('image_id', 'reference image'),
                Field('author'),
                Field('email'),
                Field('body', 'text'))

db.image.title.requires = IS_NOT_IN_DB(db, db.image.title)
db.post.image_id.requires = IS_IN_DB(db, db.image.id, '%(title)s')
db.post.author.requires = IS_NOT_EMPTY()
db.post.email.requires = IS_EMAIL()
db.post.body.requires = IS_NOT_EMPTY()

db.post.image_id.writable = db.post.image_id.readable = False

auth = Auth(db)
auth.define_tables(username=True)

Jim Steil

unread,
Apr 22, 2020, 5:49:45 PM4/22/20
to web...@googlegroups.com
Jon

You're redefining db right above your define_table for 'image'.  db is already assigned/defined higher up in the db.py file.  We don't want to redefine it.

I've just been looking at the tutorial you're following and see that it seems a bit out-dated.

-Jim

--
Resources:
- http://web2py.com
- http://web2py.com/book (Documentation)
- http://github.com/web2py/web2py (Source code)
- https://code.google.com/p/web2py/issues/list (Report Issues)
---
You received this message because you are subscribed to a topic in the Google Groups "web2py-users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/web2py/51UaQT4SxbQ/unsubscribe.
To unsubscribe from this group and all its topics, send an email to web...@googlegroups.com.

--
Resources:
- http://web2py.com
- http://web2py.com/book (Documentation)
- http://github.com/web2py/web2py (Source code)
- https://code.google.com/p/web2py/issues/list (Report Issues)
---
You received this message because you are subscribed to a topic in the Google Groups "web2py-users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/web2py/51UaQT4SxbQ/unsubscribe.
To unsubscribe from this group and all its topics, send an email to web2py+un...@googlegroups.com.

Jon Paris

unread,
Apr 22, 2020, 6:12:54 PM4/22/20
to web2py-users
Yes - I can see that now - but that was in the original scaffolding.

I moved stuff around and now have this at the start:

from gluon.contrib.appconfig import AppConfig
from gluon.tools import Auth

db = DAL("sqlite://storage.sqlite")

auth = Auth(db)
auth.define_tables(username=True)

The removed the duplicate entry for db = later in the script.

Same problem.  App works but no authentication request.

There's still a lot of "extra stuff" in the scaffolded code that I don't think I need it or not - but no duplication that I can see.


On Wednesday, April 22, 2020 at 5:49:45 PM UTC-4, Jim S wrote:
Jon

Jon Paris

unread,
Apr 22, 2020, 6:15:43 PM4/22/20
to web2py-users
P.S.

Just using the one I was pointed to Jim - if you know of a better one I'd be happy to hear it.

The biggest problem appears to be that it was written long before a lot of the "stuff" was added to the scaffold files. In some cases the tutorial tells you to replace the whole file - but in others (as in this case) it just tells you to add it without saying _where_.


On Wednesday, April 22, 2020 at 5:49:45 PM UTC-4, Jim S wrote:
<snip>

Jim Steil

unread,
Apr 22, 2020, 6:23:54 PM4/22/20
to web...@googlegroups.com
Jon

What does your controller look like?
-Jim

--
Resources:
- http://web2py.com
- http://web2py.com/book (Documentation)
- http://github.com/web2py/web2py (Source code)
- https://code.google.com/p/web2py/issues/list (Report Issues)
---
You received this message because you are subscribed to a topic in the Google Groups "web2py-users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/web2py/51UaQT4SxbQ/unsubscribe.
To unsubscribe from this group and all its topics, send an email to web2py+un...@googlegroups.com.

Jon Paris

unread,
Apr 22, 2020, 6:28:13 PM4/22/20
to web2py-users
Again pretty  much the scaffold code plus the tutorial changes I think.


# -*- coding: utf-8 -*-
# -------------------------------------------------------------------------
# This is a sample controller
# this file is released under public domain and you can use without limitations
# -------------------------------------------------------------------------

# ---- example index page ----
def index():
    images = db().select(db.image.ALL, orderby=db.image.title)
    return dict(images=images)

def show():
    image = db.image(request.args(0, cast=int)) or redirect(URL('index'))
    db.post.image_id.default = image.id
    form = SQLFORM(db.post)
    if form.process().accepted:
        response.flash = 'your comment is posted'
    comments = db(db.post.image_id == image.id).select(orderby=db.post.id)
    return dict(image=image, comments=comments, form=form)

def download():
    return response.download(request, db)

def user():
    return dict(form=auth())


# ---- API (example) -----
@auth.requires_login()
def api_get_user_email():
    if not request.env.request_method == 'GET': raise HTTP(403)
    return response.json({'status':'success', 'email':auth.user.email})

# ---- Smart Grid (example) -----
@auth.requires_membership('admin') # can only be accessed by members of admin groupd
def grid():
    response.view = 'generic.html' # use a generic view
    tablename = request.args(0)
    if not tablename in db.tables: raise HTTP(403)
    grid = SQLFORM.smartgrid(db[tablename], args=[tablename], deletable=False, editable=False)
    return dict(grid=grid)

# ---- Embedded wiki (example) ----
def wiki():
    auth.wikimenu() # add the wiki to the menu
    return auth.wiki() 

# ---- Action for login/register/etc (required for auth) -----
def user():
    """
    exposes:
    http://..../[app]/default/user/login
    http://..../[app]/default/user/logout
    http://..../[app]/default/user/register
    http://..../[app]/default/user/profile
    http://..../[app]/default/user/retrieve_password
    http://..../[app]/default/user/change_password
    http://..../[app]/default/user/bulk_register
    use @auth.requires_login()
        @auth.requires_membership('group name')
        @auth.requires_permission('read','table name',record_id)
    to decorate functions that need access control
    also notice there is http://..../[app]/appadmin/manage/auth to allow administrator to manage users
    """
    return dict(form=auth())

# ---- action to server uploaded static content (required) ---
@cache.action()
def download():
    """
    allows downloading of uploaded files
    http://..../[app]/default/download/[filename]
    """
    return response.download(request, db)
To unsubscribe from this group and all its topics, send an email to web...@googlegroups.com.

Jim Steil

unread,
Apr 22, 2020, 6:55:35 PM4/22/20
to web...@googlegroups.com
That is your default.py, correct?

Which function are you trying to protect with authorization?  I'm guessing it's the index or show.

First off, I'd get rid of the user and download functions you added.  They are already in place as they should be (the ones at the bottom are what you want).

If I'm correct in my guess about protecting index or show, then you need to add a decorator to them.

I'd add

@auth.requires_login() 

on the line above:

def show():

...and then give it a try.

-Jim


To unsubscribe from this group and all its topics, send an email to web2py+un...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/web2py/f998f6a2-a70f-4ecc-a62a-476dedeef390%40googlegroups.com.

Jon Paris

unread,
Apr 23, 2020, 10:52:25 AM4/23/20
to web2py-users
Responses in-line Jim - but before I get to that I really want to thank you for your assistance and patience.  I now have to give some serious thought to whether following this document is a worthwhile exercise as it seems to be so far off the mark as far as the current version is concerned. 


On Wednesday, April 22, 2020 at 6:55:35 PM UTC-4, Jim S wrote:
That is your default.py, correct?

Correct
 
Which function are you trying to protect with authorization?  I'm guessing it's the index or show.

I'm just trying to follow the documentation - more in a moment

First off, I'd get rid of the user and download functions you added.  They are already in place as they should be (the ones at the bottom are what you want).

Wow - obviously another case where the documentation has been made obsolete by changes in the scaffold code.  I didn't notice that. The scaffold includes so much and nothing in the docs gives any hint as to whether it is needed and "just leave it alone" or what you should do. I get the feeling that this tutorial was very useful for an earlier version of the tool but has not been updated as changes were made. I now know to look at every singe function I'm told to add to see if a version is already in place. 

The problem now is it is not longer clear which code causes these things to be actioned. I now know that all that was needed was the @auth.requires_login()  
  
If I'm correct in my guess about protecting index or show, then you need to add a decorator to them.

I'd add

@auth.requires_login() 

on the line above:

def show():

I did that and removed the dups and it now works as it should.  Now that I know this I went back to the document and I now see why I missed it. The wording is "We can now decorate the functions that we want to restrict, for example:" - note the "for example".  Since I wasn't interested in "decorating" (because to me based on other tools I have used it means to pretty up and add text labels, colors,  etc.). I foolishly assumed that all the other lines I had been told to add were what would invoke the authentication.

Anyway - thanks again.  Maybe I'll try one more section before I give up on this thing.

  
 

Jim S

unread,
Apr 23, 2020, 11:05:19 AM4/23/20
to web2py-users
Jon

I'd really encourage you to not give up on this.  I think your assessment is correct; there have been a lot changes to the code since that doc was originally written and it might be hard to navigate.  I went through it back in 2011, I read it from front to back before even trying to code with it.

I'd had experience with other Python web frameworks, most notably, TurboGears.  Web2py was a breath of fresh air.  So well documented, so well thought out.

However, at that time, I'd been coding in Python for about 6 years already.  I think some of the bumps you're running into might be due to being newer to Python; decorators for example, are a python concept.

If you're looking for a python web framework to get started with, I think web2py is the most approachable.  I've also worked with Flask a bit and feel that web2py gives you a lot more 'out of the box' whereas Flask requires you to make decisions on which extensions to use.  Django is a great framework, but it just never clicked with me

I'm happy to help you in any way I can.  You've given so much to the IBM i community.  It's my way of saying thank you.

Let me know if you'd like to get on a call or video conference sometime.  I'm pretty flexible with my schedule.

-Jim

Jon Paris

unread,
Apr 23, 2020, 11:29:02 AM4/23/20
to web...@googlegroups.com
Thanks Jim - I appreciate it.

Yes - I keep forgetting that for some reason Python has redefined a lot of terms. Dictionaries confused me until I realized that they were pretty much the same as keyed arrays in PHP and other languages. Not sure why so much relabelling but it certainly makes the learning curve a little steeper.

I'm trying to get py4web running for comparison as that seems to be the natural follow on to to web2py. Have you any experience with that?

--
Resources:
- http://web2py.com
- http://web2py.com/book (Documentation)
- http://github.com/web2py/web2py (Source code)
- https://code.google.com/p/web2py/issues/list (Report Issues)
---
You received this message because you are subscribed to the Google Groups "web2py-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to web2py+un...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/web2py/3a7865a7-6e9a-48c0-9e26-aeb9674b792e%40googlegroups.com.

Jim S

unread,
Apr 23, 2020, 11:39:38 AM4/23/20
to web2py-users
I've played with it a bit.  After using web2py, I miss some of the web2py features that aren't there in py4web.  SQLFORM.grid is the biggest one.  I use that all over the place.  I think Massimo is working on something similar in py4web but I haven't seen it yet.

For those of us with large web2py code bases, it seems like py4web isn't there yet.  It still needs some more of the web2py built-in capabilities (SQLFORM.grid, Authorization) before I could move to it.  Yes, I could write them myself, but I'm not as bright as Massimo and the others that contribute to the project.  Also, there seems to be more of a push to move to javascript front-end using Vue.js.  While I agree that is a great feature to have, it would be helpful for us old web2py guys to move to py4web with our current knowledge.

For me, I'm sticking with web2py for now and waiting to see where py4web goes in the next few months.

-Jim
To unsubscribe from this group and stop receiving emails from it, send an email to web...@googlegroups.com.

Massimo Di Pierro

unread,
Apr 26, 2020, 11:31:56 PM4/26/20
to web2py-users
Hello Jon,

unfortunately the documentation has been lagging. Recently we are putting a lot more efforts into py4web which, as you understood, is the natural successor of web2py. py4web is much cleaner and much faster. The Auth side is not quite as battle tested but we plan to release a new and improved Auth for py4web in a couple of weeks, maybe sooner. It is not quite true that py4web lacks the equivalent of web2py's grid. It is just different. py4web is designed for APIs and provides a mtable that generates grids client-side based on the APIs. There is a lot of new and better stuff in py4web which is undocumented but I will prioritize the py4web documentation.

Massimo

Ben Lawrence

unread,
Apr 27, 2020, 6:37:41 PM4/27/20
to web2py-users
Hi Massimo, thanks for web2py, I have used it for my business to track paid time off https://ptocheck.com of our employees, so its a great framework for niche apps, sort-of like filemaker https://www.filemaker.com
Your comment "py4web is designed for APIs" confused me because that is what https://falconframework.org does. Isn't py4web more than that? Isn't it more for applications where users can stay logged, more of a younger brother to web2py?
regards
Ben
Reply all
Reply to author
Forward
0 new messages