+Note that Auth caches the logged in user in the session and that's what you get in ``auth.user``, so you need to clear the sessions for the extra fields changes to be reflected in it.
+
+
#### Renaming ``Auth`` tables
[renaming_auth_tables]
#### Renaming ``Auth`` tables
[renaming_auth_tables]

+[[two_step_verification]]
+#### Two-step verification
+
+Two-step verification (or Two-factor authentication) is a way of improving
+authentication security. The setting adds an extra step in the login process.
+In the first step, users are shown the standard username/password form. If they
+successfully pass this challenge by submitting the correct username and password,
+and two-factor authentication is enabled for the user, the server will present
+a second form before logging them in. This form will ask users for a six-digit code
+that has been emailed to their accounts (the server emails the code if the username
+and password was correct). The user gets four attempts to enter this code correctly.
+If the code is incorrect, the second verification step is treated as having failed
+and the user must complete the first challenge (username/password) again.
+
+This functionality can be enabled on a per-user basis by defining a group
+with role 'web2py Two-Step Authentication' and adding users to that group.
+
### Authorization
### Authorization

``
auth.enable_record_versioning(db,
archive_db=None,
archive_names='%(tablename)s_archive',
current_record='current_record'):
``:code
``
db.enable_record_versioning(db,
archive_db=None,
archive_names='%(tablename)s_archive',
current_record='current_record'):
``:code

``
auth = Auth(db, signature=False)
+``
``
auth = Auth(db, signature=False)

#### Renaming ``Auth`` tables
[renaming_auth_tables]
The actual names of the ``Auth`` tables are stored in
``
auth.settings.table_user_name = 'auth_user'
auth.settings.table_group_name = 'auth_group'
auth.settings.table_membership_name = 'auth_membership'
auth.settings.table_permission_name = 'auth_permission'
auth.settings.table_event_name = 'auth_event'
``:code
The names of the table can be changed by reassigning the above variables after the ``auth`` object is defined and before the Auth tables are defined. For example:
``
auth = Auth(db)
auth.settings.table_user_name = 'person'
#...
auth.define_tables()
``:code
The actual tables can also be referenced, independently of their actual names, by
``
auth.settings.table_user
auth.settings.table_group
auth.settings.table_membership
auth.settings.table_permission
auth.settings.table_event
``:code
Note: auth.signature gets defined when Auth is initialized, which is before you have set the custom table names. To avoid this do:
``
auth = Auth(db, signature=False)
In that case, auth.signature will instead be defined when you call auth.define_tables(), by which point the custom tables names will already be set.
#### Other login methods and login forms
+
``LDAP``:inxx ``PAM``:inxx
#### Renaming ``Auth`` tables
[[renaming_auth_tables]]
The actual names of the ``Auth`` tables are stored in
``
auth.settings.table_user_name = 'auth_user'
auth.settings.table_group_name = 'auth_group'
auth.settings.table_membership_name = 'auth_membership'
auth.settings.table_permission_name = 'auth_permission'
auth.settings.table_event_name = 'auth_event'
``:code
The names of the table can be changed by reassigning the above variables after the ``auth`` object is defined and before the Auth tables are defined. For example:
``
auth = Auth(db)
auth.settings.table_user_name = 'person'
#...
auth.define_tables()
``:code
The actual tables can also be referenced, independently of their actual names, by
``
auth.settings.table_user
auth.settings.table_group
auth.settings.table_membership
auth.settings.table_permission
auth.settings.table_event
``:code
Note: auth.signature gets defined when Auth is initialized, which is before you have set the custom table names. To avoid this do:
``
auth = Auth(db, signature=False)
-``:code
In that case, auth.signature will instead be defined when you call auth.define_tables(), by which point the custom tables names will already be set.
#### Other login methods and login forms
``LDAP``:inxx ``PAM``:inxx

+[[basic_authentication]]
#### Access Control and Basic Authentication
#### Access Control and Basic Authentication

#### Renaming ``Auth`` tables
[[renaming_auth_tables]]
The actual names of the ``Auth`` tables are stored in
``
auth.settings.table_user_name = 'auth_user'
auth.settings.table_group_name = 'auth_group'
auth.settings.table_membership_name = 'auth_membership'
auth.settings.table_permission_name = 'auth_permission'
auth.settings.table_event_name = 'auth_event'
``:code
The names of the table can be changed by reassigning the above variables after the ``auth`` object is defined and before the Auth tables are defined. For example:
``
auth = Auth(db)
auth.settings.table_user_name = 'person'
#...
auth.define_tables()
``:code
The actual tables can also be referenced, independently of their actual names, by
``
auth.settings.table_user
auth.settings.table_group
auth.settings.table_membership
auth.settings.table_permission
auth.settings.table_event
``:code
Note: auth.signature gets defined when Auth is initialized, which is before you have set the custom table names. To avoid this do:
``
auth = Auth(db, signature=False)
+``:code
#### Renaming ``Auth`` tables
[renaming_auth_tables]
The actual names of the ``Auth`` tables are stored in
``
auth.settings.table_user_name = 'auth_user'
auth.settings.table_group_name = 'auth_group'
auth.settings.table_membership_name = 'auth_membership'
auth.settings.table_permission_name = 'auth_permission'
auth.settings.table_event_name = 'auth_event'
``:code
The names of the table can be changed by reassigning the above variables after the ``auth`` object is defined and before the Auth tables are defined. For example:
``
auth = Auth(db)
auth.settings.table_user_name = 'person'
#...
auth.define_tables()
``:code
The actual tables can also be referenced, independently of their actual names, by
``
auth.settings.table_user
auth.settings.table_group
auth.settings.table_membership
auth.settings.table_permission
auth.settings.table_event
``:code
Note: auth.signature gets defined when Auth is initialized, which is before you have set the custom table names. To avoid this do:
``
auth = Auth(db, signature=False)

There is an experimental argument, ``ajax=True``, which uses the ajax API to recaptcha. It can be used with any recaptcha, but it was specifically added to allow recpatcha fields to work in LOAD forms (see Chapter 12 for more about LOAD, which allows web2py to 'plugin' components of a page with ajax ). It's experimental because it may be replaced with automatic detection of when ajax is required.
Notice that ``use_ssl=False`` by default.
-There is an experimental argument, ``ajax=False``. Set to ``True`` to activate the ajax API of recaptcha. It can be used with any recaptcha, but it was specifically added to allow recpatcha fields to work in LOAD forms (see Chapter 12 for more about LOAD, which allows web2py to 'plugin' components of a page with ajax).
It's experimental because it may be replaced with automatic detection of when ajax is required, or possibly the ajax interface will be used in all cases.
-
Notice that ``use_ssl=False`` by default. Modern browsers give errors if non-ssl components are mixed with pages sent with https.

+There is an experimental argument, ``ajax=False``. Set to ``True`` to activate the ajax API of recaptcha. It can be used with any recaptcha, but it was specifically added to allow recpatcha fields to work in LOAD forms (see Chapter 12 for more about LOAD, which allows web2py to 'plugin' components of a page with ajax).
+It's experimental because it may be replaced with automatic detection of when ajax is required, or possibly the ajax interface will be used in all cases.
+
+
+Notice that ``use_ssl=False`` by default. Modern browsers give errors if non-ssl components are mixed with pages sent with https.
-Notice that ``use_ssl=False`` by default.

The ``Recaptcha`` constructor takes some optional arguments:
``
Recaptcha(..., use_ssl=False, error_message='invalid', label='Verify:', options='')
``:code
+Notice that ``use_ssl=False`` by default. If your login is served via https, modern browsers won't show the recaptcha because serving mixed http/https content is a security risk. Change to ``use_ssl=True``
+
The ``Recaptcha`` constructor takes some optional arguments:
``
Recaptcha(..., use_ssl=True, error_message='invalid', label='Verify:', options='')
``:code
-Notice that ``use_ssl=False`` by default.

To start using ``Auth``, you need at least this code in a model file, which is also provided with the web2py "welcome" application and assumes a ``db`` connection object:
``
from gluon.tools import Auth
auth = Auth(db)
auth.define_tables(username=False,signature=False)
``:code
+By default, web2py uses email for login. If instead you want to log in using username set ``auth.define_tables(username=True)``
+
+Setting ``signature=True`` adds user and date stamping to auth tables, to track modifications.
+
Auth has an optional ``secure=True`` argument, which will force authenticated pages to go over HTTPS. ``https``:inxx
By default, Auth protects logins against cross-site request forgeries (CSRF). This is actually provided by web2py's standard CSRF protection whenever forms are generated in a session. However, under some circumstances, the overhead of creating a session for login,password request and reset attempts may be undesirable. DOS attacks are theoretically possible. CSRF protection can be disabled for Auth forms (as of v 2.6):
``Auth = Auth(..., csrf_prevention = False)``:code
Note that doing this purely to avoid session overload on a busy site is not recommended because of the introduced security risk. Instead, see the Deployment chapter for advice on reducing session overheads.
-------
The ``password`` field of the ``db.auth_user`` table defaults to a ``CRYPT`` validator, which needs an ``hmac_key``. On legacy web2py applications you may see an extra argument passed to the Auth constructor: ``hmac_key = Auth.get_or_create_key()``. The latter is a function that read the HMAC key from a file "private/auth.key" within the application folder. If the file does not exist it creates a random ``hmac_key``. If multiple apps share the same auth database, make sure they also use the same ``hmac_key``. This is no longer necessary for new applications since passwords are salted with an individual random salt.
-------
If multiple apps share the same auth database you may want to disable migrations: ``auth.define_tables(migrate=False)``.
To expose **Auth**, you also need the following function in a controller (for example in "default.py"):
``
def user(): return dict(form=auth())
``:code
-------
The ``auth`` object and the ``user`` action are already defined in the
scaffolding application.
-------
web2py also includes a sample view "welcome/views/default/user.html" to render this function properly that looks like this:
``
{{extend 'layout.html'}}
<h2>{{=T( request.args(0).replace('_',' ').capitalize() )}}</h2>
<div id="web2py_user_form">
{{=form}}
{{if request.args(0)=='login':}}
custom_auth_table.password.requires = [IS_STRONG(), CRYPT()]
custom_auth_table.email.requires = [
IS_EMAIL(error_message=auth.messages.invalid_email),
IS_NOT_IN_DB(db, custom_auth_table.email)]
auth.settings.table_user = custom_auth_table # tell auth to use custom_auth_table
## before auth.define_tables()
``:code
You can add any field you wish, and you can change validators but you cannot remove
the fields marked as "required" in this example.
It is important to make "password", "registration_key", "reset_password_key" and "registration_id" fields ``readable=False`` and ``writable=False``, since a visitor must not be allowed to tamper with them.
If you add a field called "username", it will be used in place of "email" for login. If you do, you will need to add a validator as well:
``
auth_table.username.requires = IS_NOT_IN_DB(db, auth_table.username)
``:code
#### Renaming ``Auth`` tables
+[renaming_auth_tables]
The actual names of the ``Auth`` tables are stored in
``
auth.settings.table_user_name = 'auth_user'
auth.settings.table_group_name = 'auth_group'
auth.settings.table_membership_name = 'auth_membership'
auth.settings.table_permission_name = 'auth_permission'
auth.settings.table_event_name = 'auth_event'
``:code
The names of the table can be changed by reassigning the above variables after the ``auth`` object is defined and before the Auth tables are defined. For example:
``
auth = Auth(db)
auth.settings.table_user_name = 'person'
#...
auth.define_tables()
``:code
The actual tables can also be referenced, independently of their actual names, by
``
auth.settings.table_user
auth.settings.table_group
auth.settings.table_membership
auth.settings.table_permission
auth.settings.table_event
``:code
+Note: auth.signature gets defined when Auth is initialized, which is before you have set the custom table names. To avoid this do:
+
+``
+auth = Auth(db, signature=False)
+
+In that case, auth.signature will instead be defined when you call auth.define_tables(), by which point the custom tables names will already be set.
+
+
#### Other login methods and login forms
``LDAP``:inxx ``PAM``:inxx
To start using ``Auth``, you need at least this code in a model file, which is also provided with the web2py "welcome" application and assumes a ``db`` connection object:
``
from gluon.tools import Auth
auth = Auth(db)
auth.define_tables()
``:code
Auth has an optional ``secure=True`` argument, which will force authenticated pages to go over HTTPS. ``https``:inxx
By default, Auth protects logins against cross-site request forgeries (CSRF). This is actually provided by web2py's standard CSRF protection whenever forms are generated in a session. However, under some circumstances, the overhead of creating a session for login,password request and reset attempts may be undesirable. DOS attacks are theoretically possible. CSRF protection can be disabled for Auth forms (as of v 2.6):
``Auth = Auth(..., csrf_prevention = False)``:code
Note that doing this purely to avoid session overload on a busy site is not recommended because of the introduced security risk. Instead, see the Deployment chapter for advice on reducing session overheads.
-------
The ``password`` field of the ``db.auth_user`` table defaults to a ``CRYPT`` validator, which needs an ``hmac_key``. On legacy web2py applications you may see an extra argument passed to the Auth constructor: ``hmac_key = Auth.get_or_create_key()``. The latter is a function that read the HMAC key from a file "private/auth.key" within the application folder. If the file does not exist it creates a random ``hmac_key``. If multiple apps share the same auth database, make sure they also use the same ``hmac_key``. This is no longer necessary for new applications since passwords are salted with an individual random salt.
-------
-By default, web2py uses email for login. If instead you want to log in using username set ``auth.define_tables(username=True)``
If multiple apps share the same auth database you may want to disable migrations: ``auth.define_tables(migrate=False)``.
To expose **Auth**, you also need the following function in a controller (for example in "default.py"):
``
def user(): return dict(form=auth())
``:code
-------
The ``auth`` object and the ``user`` action are already defined in the
scaffolding application.
-------
web2py also includes a sample view "welcome/views/default/user.html" to render this function properly that looks like this:
``
{{extend 'layout.html'}}
<h2>{{=T( request.args(0).replace('_',' ').capitalize() )}}</h2>
<div id="web2py_user_form">
{{=form}}
{{if request.args(0)=='login':}}
custom_auth_table.password.requires = [IS_STRONG(), CRYPT()]
custom_auth_table.email.requires = [
IS_EMAIL(error_message=auth.messages.invalid_email),
IS_NOT_IN_DB(db, custom_auth_table.email)]
auth.settings.table_user = custom_auth_table # tell auth to use custom_auth_table
## before auth.define_tables()
``:code
You can add any field you wish, and you can change validators but you cannot remove
the fields marked as "required" in this example.
It is important to make "password", "registration_key", "reset_password_key" and "registration_id" fields ``readable=False`` and ``writable=False``, since a visitor must not be allowed to tamper with them.
If you add a field called "username", it will be used in place of "email" for login. If you do, you will need to add a validator as well:
``
auth_table.username.requires = IS_NOT_IN_DB(db, auth_table.username)
``:code
#### Renaming ``Auth`` tables
The actual names of the ``Auth`` tables are stored in
``
auth.settings.table_user_name = 'auth_user'
auth.settings.table_group_name = 'auth_group'
auth.settings.table_membership_name = 'auth_membership'
auth.settings.table_permission_name = 'auth_permission'
auth.settings.table_event_name = 'auth_event'
``:code
The names of the table can be changed by reassigning the above variables after the ``auth`` object is defined and before the Auth tables are defined. For example:
``
auth = Auth(db)
auth.settings.table_user_name = 'person'
#...
auth.define_tables()
``:code
The actual tables can also be referenced, independently of their actual names, by
``
auth.settings.table_user
auth.settings.table_group
auth.settings.table_membership
auth.settings.table_permission
auth.settings.table_event
``:code
#### Other login methods and login forms
``LDAP``:inxx ``PAM``:inxx

db.dog.large_image.authorize = lambda record: \
auth.is_logged_in() and \
auth.has_permission('read', db.dog, record.id, auth.user.id)
``:code
The attribute ``authorize`` of upload field can be None (the default) or a function that decides whether the user is logged in and has permission to 'read' the current record. In this example, there is no restriction on downloading images linked by the "small_image" field, but we require access control on images linked by the "large_image" field.
db.dog.large_image.authorization = lambda record: \
auth.is_logged_in() and \
auth.has_permission('read', db.dog, record.id, auth.user.id)
``:code
The attribute ``authorization`` of upload field can be None (the default) or a function that decides whether the user is logged in and has permission to 'read' the current record. In this example, there is no restriction on downloading images linked by the "small_image" field, but we require access control on images linked by the "large_image" field.

By default, Auth protects logins against cross-site request forgeries (CSRF). This is actually provided by web2py's standard CSRF protection whenever forms are generated in a session. However, under some circumstances, the overhead of creating a session for login,password request and reset attempts may be undesirable. DOS attacks are theoretically possible. CSRF protection can be disabled for Auth forms (as of v 2.6):
``Auth = Auth(..., csrf_prevention = False)``:code
Note that doing this purely to avoid session overload on a busy site is not recommended because of the introduced security risk. Instead, see the Deployment chapter for advice on reducing session overheads.
-------
The ``password`` field of the ``db.auth_user`` table defaults to a ``CRYPT`` validator, which needs an ``hmac_key``. On legacy web2py applications you may see an extra argument passed to the Auth constructor: ``hmac_key = Auth.get_or_create_key()``. The latter is a function that read the HMAC key from a file "private/auth.key" within the application folder. If the file does not exist it creates a random ``hmac_key``. If multiple apps share the same auth database, make sure they also use the same ``hmac_key``. This is no longer necessary for new applications since passwords are salted with an individual random salt.
-------
By default, Auth protects logins against cross-site request forgeries (CSRF). This is actually provided by web2py's standard CSRF protection whenever forms are generated in a session. However, under some circumstances, the overhead of creating a session for login,password request and reset attempts may be undesirable. DOS attacks are theoretically possible. CSRF protection can be disabled for Auth forms (as of v 2.6):
``Auth = Auth(..., csrf_prevention = False)``:code
Note that doing this purely to avoid session overload on a busy site is not recommended because of the introduced security risk. Instead, see the Deployment chapter for advice on reducing session overheads.
-------
The ``password`` field of the ``db.auth_user`` table defaults to a ``CRYPT`` validator, which needs and ``hmac_key``. On legacy web2py applications you may see an extra argument passed to the Auth constructor: ``hmac_key = Auth.get_or_create_key()``. The latter is a function that read the HMAC key from a file "private/auth.key" within the application folder. If the file does not exist it creates a random ``hmac_key``. If multiple apps share the same auth database, make sure they also use the same ``hmac_key``. This is no longer necessary for new applications since passwords are salted with an individual random salt.
-------

+[[mail_and_auth]]
#### ``Mail`` and ``Auth``
+You can read more about web2py API for emails and email configuration in [[Chapter 8 ../08 ]]. Here we limit the discussion to the interaction between ``Mail`` and ``Auth``.
+
+Define a mailer with
``
from gluon.tools import Mail
mail = Mail()
mail.settings.server = 'smtp.example.com:25'
mail.settings.sender = 'you@example.com'
mail.settings.login = 'username:password'
``
or simply use the mailer provided by ``auth``:
``
mail = auth.settings.mailer
mail.settings.server = 'smtp.example.com:25'
mail.settings.sender = 'you@example.com'
mail.settings.login = 'username:password'
``
You need to replace the mail.settings with the proper parameters for your SMTP server. Set ``mail.settings.login = None`` if the SMTP server does not require authentication. If you don't want to use TLS, set ``mail.settings.tls = False``
In ``Auth``, by default, email verification is disabled.
To enable email, append the following lines in the model where ``auth`` is defined:
``
auth.settings.registration_requires_verification = True
auth.settings.registration_requires_approval = False
auth.settings.reset_password_requires_verification = True
auth.messages.verify_email = 'Click on the link http://' + \
request.env.http_host + \
URL(r=request,c='default',f='user',args=['verify_email']) + \
'/%(key)s to verify your email'
auth.messages.reset_password = 'Click on the link http://' + \
request.env.http_host + \
URL(r=request,c='default',f='user',args=['reset_password']) + \
'/%(key)s to reset your password'
``:code
In the two ``auth.messages`` above, you may need to replace the URL portion of the string with the proper complete URL of the action. This is necessary because web2py may be installed behind a proxy, and it cannot determine its own public URLs with absolute certainty. The above examples (which are the default values) should, however, work in most cases.
auth.settings.manager_actions = dict(
You could then make two new menu items with these URLs:
``
URL('appadmin','manage',args=['db_admin'])
URL('appadmin','manage',args=['content_admin'])
``:code
The management setting called "content_mgr_group_v2" shows some more advanced possibilities. The key smartgrid_args is passed to the smartgrid used to edit or view the tables. Apart from the special key DEFAULT, table names are passed as keys (such as the table called "comments"). The syntax in this example names the tables as a list of strings, using the key db=content_db to specify the database.
#### Manual Authentication
Some times you want to implement your own logic and do "manual" user login.
This can also be done by calling the function:
``
user = auth.login_bare(username,password)
``:code
``login_bare`` returns user if the user exists and the password is valid, else it returns False. ``username`` is the email if the "auth_user" table does not have a "username" field.
#### Auth Settings and messages
Here is a list of all parameters that can be customized for **Auth**
The following must point to a ``gluon.tools.Mail`` object to allow ``auth`` to send emails:
``
auth.settings.mailer = None
``:code
+Read more about setting up mail here: [[Mail and Auth #mail_and_auth]]
+
The following must be the name of the controller that defined the ``user`` action:
``
auth.settings.controller = 'default'
``:code
The following was a very important setting in older web2py versions:
``
auth.settings.hmac_key = None
``:code
Where it was set to something like "sha512:a-pass-phrase" and passed to the CRYPT validator for the "password" field of the ``auth_user`` table, providing the algorithm and a-pass-phrase used to hash the passwords. However, web2py no longers needs this setting because it handles this automatically.
#### ``Mail`` and ``Auth``
-One can define a mailer with
``
from gluon.tools import Mail
mail = Mail()
mail.settings.server = 'smtp.example.com:25'
mail.settings.sender = 'you@example.com'
mail.settings.login = 'username:password'
``
or simply use the mailer provided by ``auth``:
``
mail = auth.settings.mailer
mail.settings.server = 'smtp.example.com:25'
mail.settings.sender = 'you@example.com'
mail.settings.login = 'username:password'
``
You need to replace the mail.settings with the proper parameters for your SMTP server. Set ``mail.settings.login = None`` if the SMTP server does not require authentication. If you don't want to use TLS, set ``mail.settings.tls = False``
-You can read more about web2py API for emails and email configuration in Chapter 8. Here we limit the discussion to the interaction between ``Mail`` and ``Auth``.
In ``Auth``, by default, email verification is disabled.
To enable email, append the following lines in the model where ``auth`` is defined:
``
auth.settings.registration_requires_verification = True
auth.settings.registration_requires_approval = False
auth.settings.reset_password_requires_verification = True
auth.messages.verify_email = 'Click on the link http://' + \
request.env.http_host + \
URL(r=request,c='default',f='user',args=['verify_email']) + \
'/%(key)s to verify your email'
auth.messages.reset_password = 'Click on the link http://' + \
request.env.http_host + \
URL(r=request,c='default',f='user',args=['reset_password']) + \
'/%(key)s to reset your password'
``:code
In the two ``auth.messages`` above, you may need to replace the URL portion of the string with the proper complete URL of the action. This is necessary because web2py may be installed behind a proxy, and it cannot determine its own public URLs with absolute certainty. The above examples (which are the default values) should, however, work in most cases.
auth.settings.manager_actions = dict(
You could then make two new menu items with these URLs:
``
URL('appadmin','manage',args=['db_admin'])
URL('appadmin','manage',args=['content_admin'])
``:code
The management setting called "content_mgr_group_v2" shows some more advanced possibilities. The key smartgrid_args is passed to the smartgrid used to edit or view the tables. Apart from the special key DEFAULT, table names are passed as keys (such as the table called "comments"). The syntax in this example names the tables as a list of strings, using the key db=content_db to specify the database.
#### Manual Authentication
Some times you want to implement your own logic and do "manual" user login.
This can also be done by calling the function:
``
user = auth.login_bare(username,password)
``:code
``login_bare`` returns user if the user exists and the password is valid, else it returns False. ``username`` is the email if the "auth_user" table does not have a "username" field.
#### Settings and messages
Here is a list of all parameters that can be customized for **Auth**
The following must point to a ``gluon.tools.Mail`` object to allow ``auth`` to send emails:
``
auth.settings.mailer = None
``:code
The following must be the name of the controller that defined the ``user`` action:
``
auth.settings.controller = 'default'
``:code
The following is a very important setting:
``
auth.settings.hmac_key = None
``:code
It must be set to something like "sha512:a-pass-phrase" and it will be passed to the CRYPT validator for the "password" field of the ``auth_user`` table. It will be the algorithm and a-pass-phrase used to hash the passwords.

+Note: If your app is based on the standard scaffold app Welcome, you use the auth.navbar.
+To get the settings below to take effect, you need to edit layout.html and set argument referrer_actions = None.
+auth.navbar(mode='dropdown',referrer_actions=None)
+
+It is also possible to keep referrer_actions for some auth events.
+For example
+``
+auth.navbar(referrer_actions=['login', 'profile'])
+``:code
+
+If the default behavior is left unchanged, auth.navbar uses the _next URL parameter, and uses that to send the user back to the referring page.
+However, if navbar's default auto-referring behavior is changed, the settings below will take effect.
+
``
auth.settings.login_next = URL('index')
auth.settings.logout_next = URL('index')
auth.settings.profile_next = URL('index')
auth.settings.register_next = URL('user', args='login')
auth.settings.retrieve_username_next = URL('index')
auth.settings.retrieve_password_next = URL('index')
auth.settings.change_password_next = URL('index')
auth.settings.request_reset_password_next = URL('user', args='login')
auth.settings.reset_password_next = URL('user', args='login')
auth.settings.verify_email_next = URL('user', args='login')
``:code
``
auth.settings.login_next = URL('index')
auth.settings.logout_next = URL('index')
auth.settings.profile_next = URL('index')
auth.settings.register_next = URL('user', args='login')
auth.settings.retrieve_username_next = URL('index')
auth.settings.retrieve_password_next = URL('index')
auth.settings.change_password_next = URL('index')
auth.settings.request_reset_password_next = URL('user', args='login')
auth.settings.reset_password_next = URL('user', args='login')
auth.settings.verify_email_next = URL('user', args='login')
``:code

``
auth.settings.registration_requires_verification = True
auth.settings.login_after_registration = True
``:code
``
auth.settings.registration_requires_approval = True
auth.settings.login_after_registration = True
``:code

It must be underlined that OAuth2.0 is limited only to authentication and authorization
(for instance CAS has more functionalities), this means that each OAuth2.0 provider
has a different way to receive a unique id from their user database through one of their APIs.
Specific methods are well explained on respective provider documentation, they usually consist in a very
simple REST call. This is why for each OAuth2.0 provider there is the need to write a few lines of code.
Before writing any instructions in the application model a first step is needed for any provider: registering a new application; this is usually done
on provider's site and is explained in provider's documentation.
It must be underlined that OAuth2.0 is limited only to authentication and authorization
(for instance CAS has more functionalities), this means that each OAuth2.0 provider
has a different way to receive a unique id from their user database through one of their APIs.
Specific methods are well explained on respective provider documentation, their usually consist in a very
simple REST call. This is why for each OAuth2.0 provider there is the need to write a few lines of code.
Before starting a first step is needed for any provider: registering a new application; this is usually done
on provider's site and is explained in provider's documentation.

+##### OAuth2.0
+``OAuth``:inxx ``Facebook``:inxx ``Google``:inxx ``Twitter``:inxx
+
+We have previously discussed integration with Janrain, yet sometimes you do not want to rely on a third party service and you want to access a OAuth2.0 provider directly;
+for example, Facebook, Linkedin, Twitter, Google all of them provide an OAuth2.0 authentication service.
+web2py handles the OAuth2.0 flow transparently so that a user can be verified against any configured OAuth2.0
+provider during login.
+Other than authentication an OAuth2.0 provider can grant to any web2py application access to user resources
+with restricted access thought a proprietary API. Google, Twitter, Facebook and so on, all have APIs that can be
+easily accessed by a web2py application.
+
+It must be underlined that OAuth2.0 is limited only to authentication and authorization
+(for instance CAS has more functionalities), this means that each OAuth2.0 provider
+has a different way to receive a unique id from their user database through one of their APIs.
+Specific methods are well explained on respective provider documentation, their usually consist in a very
+simple REST call. This is why for each OAuth2.0 provider there is the need to write a few lines of code.
+
+Before starting a first step is needed for any provider: registering a new application; this is usually done
+on provider's site and is explained in provider's documentation.
+
+There are a few things that needs to be known once there is the need to add a new OAuth2.0 provider to your
+application:
+ 1. the Authorization URI;
+ 2. the Token request URI;
+ 3. the application identification token and secret received upon registration of the new application;
+ 4. the permissions that the provider must grant to the web2py application, i.e. the "scope" (see the provider's documentation);
+ 5. the API call to receive a UID of the authenticating user, as explained on providers documentation.
+
+Point 1 to 4 are used to initialize the authorization endpoint used by web2py to communicate with the OAuth2.0 provider.
+The unique id is retrieved by web2py with a call to the get_user() method when needed during the login flow; this is where
+the API call of point 5 is needed.
+
+These are the essential modification that need to be done in your model:
+ a. import OAuthAccount class;
+ b. define a derived OAuthClass implementation;
+ c. override __init__() method of that class;
+ d. override get_user() method of that class.
+ e. instantiate the class with the data of points 1-4 of the above list;
+
+Once the class is instantiated, and the user is authenticated, the web2py application
+can access the API of the provider any time by using the OAuth2.0 access token by calling the accessToken() method
+of that class.
+
+What follows is an example of what can be used with Facebook. This is a basic example using Facebook Graph API,
+remind that, by writing a proper get_user() method, many different things can be done. The example shows how the
+OAuth2.0 access token can be used when calling the remote API of the provider.
First of all you must install the [[Facebook Python SDK https://github.com/pythonforfacebook/facebook-sdk/]].
Second, you need the following code in your model:
``
+## Define oauth application id and secret.
+FB_CLIENT_ID='xxx'
+FB_CLIENT_SECRET="yyyy"
+
## import required modules
try:
import json
except ImportError:
from gluon.contrib import simplejson as json
from facebook import GraphAPI, GraphAPIError
from gluon.contrib.login_methods.oauth20_account import OAuthAccount
## extend the OAUthAccount class
class FaceBookAccount(OAuthAccount):
"""OAuth impl for FaceBook"""
AUTH_URL="https://graph.facebook.com/oauth/authorize"
TOKEN_URL="https://graph.facebook.com/oauth/access_token"
def __init__(self):
OAuthAccount.__init__(self, None, FB_CLIENT_ID, FB_CLIENT_SECRET,
self.AUTH_URL, self.TOKEN_URL,
scope='email,user_about_me,user_activities, user_birthday, user_education_history, user_groups, user_hometown, user_interests, user_likes, user_location, user_relationships, user_relationship_details, user_religion_politics, user_subscriptions, user_work_history, user_photos, user_status, user_videos, publish_actions, friends_hometown, friends_location,friends_photos',
state="auth_provider=facebook",
display='popup')
self.graph = None
def get_user(self):
'''Returns the user using the Graph API.
'''
if not self.accessToken():
return None
if not self.graph:
class FaceBookAccount(OAuthAccount):
user = self.graph.get_object("me")
except GraphAPIError, e:
session.token = None
self.graph = None
if user:
if not user.has_key('username'):
username = user['id']
else:
username = user['username']
if not user.has_key('email'):
email = '%s.fakemail' %(user['id'])
else:
email = user['email']
return dict(first_name = user['first_name'],
last_name = user['last_name'],
username = username,
email = '%s' %(email) )
+
## use the above class to build a new login form
auth.settings.login_form=FaceBookAccount()
``:code
-##### OAuth2.0 and Facebook
-``OAuth``:inxx ``Facebook``:inxx
-
-We have previously discussed integration with Janrain (which has Facebook support), yet sometimes you do not want to rely on a third party service and you want to access a OAuth2.0 provider directly; for example, Facebook. Here is how:
-
-``
-from gluon.contrib.login_methods.oauth20_account import OAuthAccount
-auth.settings.login_form=OAuthAccount(YOUR_CLIENT_ID,YOUR_CLIENT_SECRET)
-``:code
-
-Things get a little more complex if you want to use Facebook OAuth2.0 to login into a specific Facebook app to access its API, instead of your own app. Here is an example for accessing the Facebook Graph API.
First of all you must install the [[Facebook Python SDK https://github.com/pythonforfacebook/facebook-sdk/]].
Second, you need the following code in your model:
``
## import required modules
try:
import json
except ImportError:
from gluon.contrib import simplejson as json
from facebook import GraphAPI, GraphAPIError
from gluon.contrib.login_methods.oauth20_account import OAuthAccount
-## extend the OAUthAccount class
-FB_CLIENT_ID='xxx'
FB_CLIENT_SECRET="yyyy"
class FaceBookAccount(OAuthAccount):
"""OAuth impl for FaceBook"""
AUTH_URL="https://graph.facebook.com/oauth/authorize"
TOKEN_URL="https://graph.facebook.com/oauth/access_token"
def __init__(self):
OAuthAccount.__init__(self, None, FB_CLIENT_ID, FB_CLIENT_SECRET,
self.AUTH_URL, self.TOKEN_URL,
scope='email,user_about_me,user_activities, user_birthday, user_education_history, user_groups, user_hometown, user_interests, user_likes, user_location, user_relationships, user_relationship_details, user_religion_politics, user_subscriptions, user_work_history, user_photos, user_status, user_videos, publish_actions, friends_hometown, friends_location,friends_photos',
state="auth_provider=facebook",
display='popup')
self.graph = None
def get_user(self):
'''Returns the user using the Graph API.
'''
if not self.accessToken():
return None
if not self.graph:
class FaceBookAccount(OAuthAccount):
user = self.graph.get_object("me")
except GraphAPIError, e:
session.token = None
self.graph = None
if user:
if not user.has_key('username'):
username = user['id']
else:
username = user['username']
if not user.has_key('email'):
email = '%s.fakemail' %(user['id'])
else:
email = user['email']
return dict(first_name = user['first_name'],
last_name = user['last_name'],
username = username,
email = '%s' %(email) )
## use the above class to build a new login form
auth.settings.login_form=FaceBookAccount()
``:code

``
## import required modules
+try:
+ import json
+except ImportError:
+ from gluon.contrib import simplejson as json
+from facebook import GraphAPI, GraphAPIError
from gluon.contrib.login_methods.oauth20_account import OAuthAccount
## extend the OAUthAccount class
+
+
+FB_CLIENT_ID='xxx'
+FB_CLIENT_SECRET="yyyy"
class FaceBookAccount(OAuthAccount):
"""OAuth impl for FaceBook"""
AUTH_URL="https://graph.facebook.com/oauth/authorize"
TOKEN_URL="https://graph.facebook.com/oauth/access_token"
+
+ def __init__(self):
+ OAuthAccount.__init__(self, None, FB_CLIENT_ID, FB_CLIENT_SECRET,
+ self.AUTH_URL, self.TOKEN_URL,
+ scope='email,user_about_me,user_activities, user_birthday, user_education_history, user_groups, user_hometown, user_interests, user_likes, user_location, user_relationships, user_relationship_details, user_religion_politics, user_subscriptions, user_work_history, user_photos, user_status, user_videos, publish_actions, friends_hometown, friends_location,friends_photos',
+ state="auth_provider=facebook",
+ display='popup')
self.graph = None
def get_user(self):
+ '''Returns the user using the Graph API.
+ '''
if not self.accessToken():
return None
+
if not self.graph:
self.graph = GraphAPI((self.accessToken()))
+
+ user = None
try:
user = self.graph.get_object("me")
+ except GraphAPIError, e:
+ session.token = None
+ self.graph = None
+
+ if user:
+ if not user.has_key('username'):
+ username = user['id']
+ else:
+ username = user['username']
+
+ if not user.has_key('email'):
+ email = '%s.fakemail' %(user['id'])
+ else:
+ email = user['email']
+
return dict(first_name = user['first_name'],
last_name = user['last_name'],
+ username = username,
+ email = '%s' %(email) )
## use the above class to build a new login form
auth.settings.login_form=FaceBookAccount()
``:code
``
## import required modules
-from facebook import GraphAPI
from gluon.contrib.login_methods.oauth20_account import OAuthAccount
## extend the OAUthAccount class
class FaceBookAccount(OAuthAccount):
"""OAuth impl for Facebook"""
AUTH_URL="https://graph.facebook.com/oauth/authorize"
TOKEN_URL="https://graph.facebook.com/oauth/access_token"
- def __init__(self, g):
- OAuthAccount.__init__(self, g,
- YOUR_CLIENT_ID,
- YOUR_CLIENT_SECRET,
- self.AUTH_URL,
- self.TOKEN_URL)
self.graph = None
# override function that fetches user info
def get_user(self):
- "Returns the user using the Graph API"
if not self.accessToken():
return None
if not self.graph:
self.graph = GraphAPI((self.accessToken()))
try:
user = self.graph.get_object("me")
return dict(first_name = user['first_name'],
last_name = user['last_name'],
- username = user['id'])
- except GraphAPIError:
- self.session.token = None
- self.graph = None
- return None
## use the above class to build a new login form
auth.settings.login_form=FaceBookAccount()
``:code

+By default, Auth protects logins against cross-site request forgeries (CSRF). This is actually provided by web2py's standard CSRF protection whenever forms are generated in a session. However, under some circumstances, the overhead of creating a session for login,password request and reset attempts may be undesirable. DOS attacks are theoretically possible. CSRF protection can be disabled for Auth forms (as of v 2.6):
+``Auth = Auth(..., csrf_prevention = False)``:code
+Note that doing this purely to avoid session overload on a busy site is not recommended because of the introduced security risk. Instead, see the Deployment chapter for advice on reducing session overheads.
-------
The ``password`` field of the ``db.auth_user`` table defaults to a ``CRYPT`` validator, which needs and ``hmac_key``. On legacy web2py applications you may see an extra argument passed to the Auth constructor: ``hmac_key = Auth.get_or_create_key()``. The latter is a function that read the HMAC key from a file "private/auth.key" within the application folder. If the file does not exist it creates a random ``hmac_key``. If multiple apps share the same auth database, make sure they also use the same ``hmac_key``. This is no longer necessary for new applications since passwords are salted with an individual random salt.
-------
-------
The ``password`` field of the ``db.auth_user`` table defaults to a ``CRYPT`` validator, which needs and ``hmac_key``. On legacy web2py applications you may see an extra argument passed to the Auth constructor: ``hmac_key = Auth.get_or_create_key()``. The latter is a function that read the HMAC key from a file "private/auth.key" within the application folder. If the file does not exist it creates a random ``hmac_key``. If multiple apps share the same auth database, make sure they also use the same ``hmac_key``. This is no longer necessary for new applications since passwords are salted with an individual random salt.
-------

To disable an action append its name to this list:
``
auth.settings.actions_disabled = []
``:code
To disabled an action append its name to this list:
``
auth.settings.actions_disabled = []
``:code

The concept allows different management settings, each of which allows a user group to edit a certain set of tables in this application.
Example:
First, create a group (also known as a role) for your privileged users. In this example, it will be called admin.
Give a user membership of this role.
Second, think of a name to describe this management setting, such as db_admin.
Add the following setting in the model where you created and configured your auth object (probably in the model db):
``
auth.settings.manager_actions = dict(db_admin=dict(role='admin',heading='Manage Database',tables = db.tables))
``:code
A menu item has the URL like below, passing the management setting name as an arg:
``
URL('appadmin','manage',args=['db_admin'])
``:code
This URL appears as /appadmin/manage/auth.
##### Advanced use
This mechanism allows multiple management settings; each additional management setting is just another key defined in auth.settings.manager_actions.
For example, you may want a group of users (such as 'Super') to have access to every table in a management setting called "db_admin", and another group (such as 'Content Manager') to have admin access to tables relating to content in a management setting called "content_admin".
This can be set up like this:
``
auth.settings.manager_actions = dict(
db_admin=dict(role='Super', heading='Manage Database', tables=db.tables),
content_admin=dict(role='Content Manager', tables=[content_db.articles, content_db.recipes, content_db.comments])
+ content_mgr_group_v2 = dict(role='Content Manager v2', db=content_db,
+ tables=['articles','recipes','comments'],
+ smartgrid_args=dict(
+ DEFAULT=dict(maxtextlength=50,paginate=30),
+ comments=dict(maxtextlength=100,editable=False)
+ )
+ )
``:code
(The heading key is optional. If missing, a smart default will be used)
You could then make two new menu items with these URLs:
``
URL('appadmin','manage',args=['db_admin'])
URL('appadmin','manage',args=['content_admin'])
``:code
+The management setting called "content_mgr_group_v2" shows some more advanced possibilities. The key smartgrid_args is passed to the smartgrid used to edit or view the tables. Apart from the special key DEFAULT, table names are passed as keys (such as the table called "comments"). The syntax in this example names the tables as a list of strings, using the key db=content_db to specify the database.
The concept allows different management settings, each of which allows a user group to edit to a certain set of tables in this application.
Example:
First, create a group (also known as a role) for your privileged users. In this example, it will be called admin.
Give a user membership of this role.
Second, think of a name to describe this management setting, such as db_admin.
Add the following setting in the model where you created and configured your auth object (probably in the model db):
``
auth.settings.manager_actions = dict(db_admin=dict(role='admin',heading='Manage Database',tables = db.tables))
``:code
A menu item has the URL like below, passing the management setting name as an arg:
``
URL('appadmin','manage',args=['db_admin'])
``:code
This URL appears as /appadmin/manage/auth.
##### Advanced use
This mechanism is allows multiple management settings; each additional management setting is just another key defined in auth.settings.manager_actions.
For example, you may want a group of users (such as 'Super') to have access to every table in a management setting called "db_admin", and another group (such as 'Content Manager') to have admin access to tables relating to content in a management setting called "content_admin".
This can be set up like this:
``
auth.settings.manager_actions = dict(
db_admin=dict(role='Super', heading='Manage Database', tables=db.tables),
content_admin=dict(role='Content Manager', tables=[content_db.articles, content_db.recipes, content_db.comments])
``:code
(The heading key is optional. If missing, a smart default will be used)
You could then make two new menu items with these URLs:
``
URL('appadmin','manage',args=['db_admin'])
URL('appadmin','manage',args=['content_admin'])
``:code

#### Application Management via privileged users (Experimental)
Normally administrator functions such as defining users and groups are managed by the server administrator. However, you may want a group of privileged users to have administrator rights for a specific application.
+This is possible with versions after web2py v2.5.1
+(Upgrading an existing application requires the new appadmin controller and the new appadmin.html view, copied from the welcome app. Also, apps created prior to web2py v2.6 need the new javascript file in welcome/static/js/web2py.js)
+The concept allows different management settings, each of which allows a user group to edit to a certain set of tables in this application.
+
+Example:
First, create a group (also known as a role) for your privileged users. In this example, it will be called admin.
Give a user membership of this role.
+Second, think of a name to describe this management setting, such as db_admin.
Add the following setting in the model where you created and configured your auth object (probably in the model db):
``
+auth.settings.manager_actions = dict(db_admin=dict(role='admin',heading='Manage Database',tables = db.tables))
+
``:code
+
+A menu item has the URL like below, passing the management setting name as an arg:
``
URL('appadmin','manage',args=['db_admin'])
``:code
This URL appears as /appadmin/manage/auth.
##### Advanced use
+This mechanism is allows multiple management settings; each additional management setting is just another key defined in auth.settings.manager_actions.
+
+For example, you may want a group of users (such as 'Super') to have access to every table in a management setting called "db_admin", and another group (such as 'Content Manager') to have admin access to tables relating to content in a management setting called "content_admin".
This can be set up like this:
``
auth.settings.manager_actions = dict(
+ db_admin=dict(role='Super', heading='Manage Database', tables=db.tables),
+ content_admin=dict(role='Content Manager', tables=[content_db.articles, content_db.recipes, content_db.comments])
``:code
(The heading key is optional. If missing, a smart default will be used)
You could then make two new menu items with these URLs:
``
+URL('appadmin','manage',args=['db_admin'])
+URL('appadmin','manage',args=['content_admin'])
``:code
#### Application Management via privileged users (Experimental)
Normally administrator functions such as defining users and groups are managed by the server administrator. However, you may want a group of privileged users to have administrator rights for a specific application.
-This is possible with versions after web2py 2.5.1
-(Upgrading an existing application requires the new appadmin controller and the new appadmin.html view, copied from the welcome app.)
First, create a group (also known as a role) for your privileged users. In this example, it will be called admin.
Give a user membership of this role.
Add the following setting in the model where you created and configured your auth object (probably in the model db):
``
-auth.settings.auth_manager_role = 'admin'
``:code
-A menu item has the URL:
``
URL('appadmin','manage',args=['auth'])
``:code
This URL appears as /appadmin/manage/auth.
-Members of the auth_manager_role (in this case, 'auth') can now edit the tables associated with user management for this specific application.
-
##### Advanced use
-This mechanism is generalised to allow different groups of privileged users administrator access to certain tables.
-For example, you may want a group of users (such as 'Super') to have access to every table, and another group (such as 'Content Manager') to have admin access to tables relating to content.
This can be set up like this:
``
auth.settings.manager_actions = dict(
- db=dict(role='Super', heading='Manage Database', tables=db.tables),
- content=dict(role='Content Manager', tables=[content_db.articles, content_db.recipes, content_db.comments])
``:code
(The heading key is optional. If missing, a smart default will be used)
You could then make two new menu items with these URLs:
``
-URL('appadmin','manage',args=['db'])
-URL('appadmin','manage',args=['content'])
``:code

#### Application Management via privileged users (Experimental)
Normally administrator functions such as defining users and groups are managed by the server administrator. However, you may want a group of privileged users to have administrator rights for a specific application.
This is possible with versions after web2py 2.5.1
(Upgrading an existing application requires the new appadmin controller and the new appadmin.html view, copied from the welcome app.)
First, create a group (also known as a role) for your privileged users. In this example, it will be called admin.
Give a user membership of this role.
Add the following setting in the model where you created and configured your auth object (probably in the model db):
``
auth.settings.auth_manager_role = 'admin'
``:code
A menu item has the URL:
``
URL('appadmin','manage',args=['auth'])
``:code
This URL appears as /appadmin/manage/auth.
Members of the auth_manager_role (in this case, 'auth') can now edit the tables associated with user management for this specific application.
##### Advanced use
This mechanism is generalised to allow different groups of privileged users administrator access to certain tables.
For example, you may want a group of users (such as 'Super') to have access to every table, and another group (such as 'Content Manager') to have admin access to tables relating to content.
This can be set up like this:
``
auth.settings.manager_actions = dict(
db=dict(role='Super', heading='Manage Database', tables=db.tables),
content=dict(role='Content Manager', tables=[content_db.articles, content_db.recipes, content_db.comments])
``:code
+(The heading key is optional. If missing, a smart default will be used)
+
You could then make two new menu items with these URLs:
``
URL('appadmin','manage',args=['db'])
URL('appadmin','manage',args=['content'])
``:code
#### Application Management via privileged users (Experimental)
Normally administrator functions such as defining users and groups are managed by the server administrator. However, you may want a group of privileged users to have administrator rights for a specific application.
This is possible with versions after web2py 2.5.1
(Upgrading an existing application requires the new appadmin controller and the new appadmin.heml view, copied from the welcome app.)
First, create a group (also known as a role) for your privileged users. In this example, it will be called admin.
Give a user membership of this role.
Add the following setting in the model where you created and configured your auth object (probably in the model db):
``
auth.settings.auth_manager_role = 'admin'
``:code
A menu item has the URL:
``
URL('appadmin','manage',args=['auth'])
``:code
This URL appears as /appadmin/manage/auth.
Members of the auth_manager_role (in this case, 'auth') can now edit the tables associated with user management for this specific application.
##### Advanced use
This mechanism is generalised to allow different groups of privileged users administrator access to certain tables.
For example, you may want a group of users (such as 'Super') to have access to every table, and another group (such as 'Content Manager') to have admin access to tables relating to content.
This can be set up like this:
``
auth.settings.manager_actions = dict(
db=dict(role='Super', heading='Manage Database', tables=db.tables),
content=dict(role='Content Manager', tables=[content_db.articles, content_db.recipes, content_db.comments])
``:code
You could then make two new menu items with these URLs:
``
URL('appadmin','manage',args=['db'])
URL('appadmin','manage',args=['Content Manager'])
``:code
-(The heading key is optional. If missing, a smart default will be used)

+#### Application Management via privileged users (Experimental)
+Normally administrator functions such as defining users and groups are managed by the server administrator. However, you may want a group of privileged users to have administrator rights for a specific application.
+This is possible with versions after web2py 2.5.1
+(Upgrading an existing application requires the new appadmin controller and the new appadmin.heml view, copied from the welcome app.)
+
First, create a group (also known as a role) for your privileged users. In this example, it will be called admin.
Give a user membership of this role.
Add the following setting in the model where you created and configured your auth object (probably in the model db):
``
+auth.settings.auth_manager_role = 'admin'
+``:code
+
+A menu item has the URL:
+``
+URL('appadmin','manage',args=['auth'])
``:code
+This URL appears as /appadmin/manage/auth.
+Members of the auth_manager_role (in this case, 'auth') can now edit the tables associated with user management for this specific application.
+
+##### Advanced use
+This mechanism is generalised to allow different groups of privileged users administrator access to certain tables.
+For example, you may want a group of users (such as 'Super') to have access to every table, and another group (such as 'Content Manager') to have admin access to tables relating to content.
+
+This can be set up like this:
``
+auth.settings.manager_actions = dict(
+ db=dict(role='Super', heading='Manage Database', tables=db.tables),
+ content=dict(role='Content Manager', tables=[content_db.articles, content_db.recipes, content_db.comments])
``:code
+You could then make two new menu items with these URLs:
+``
+URL('appadmin','manage',args=['db'])
+URL('appadmin','manage',args=['Content Manager'])
+``:code
+(The heading key is optional. If missing, a smart default will be used)
-#### User Management via privileged users (Experimental)
-Normally users and groups are managed by the server administrator. However, you may want a group of privileged users that can manage users and groups just for one application.
-Starting from web2py 2.5, you can do this.
First, create a group (also known as a role) for your privileged users. In this example, it will be called admin.
Give a user membership of this role.
Add the following setting in the model where you created and configured your auth object (probably in the model db):
``
-auth.settings.manager_group_role = 'admin'
``:code
-The user and groups administration menu has this URL (for adding to a menu)
``
-URL('appadmin','auth_manage')
``:code
-Upgrading an existing application requires a new appadmin controller (copied from the welcome app) and the new appadmin.html view.

+#### User Management via privileged users (Experimental)
+Normally users and groups are managed by the server administrator. However, you may want a group of privileged users that can manage users and groups just for one application.
+Starting from web2py 2.5, you can do this.
+First, create a group (also known as a role) for your privileged users. In this example, it will be called admin.
+Give a user membership of this role.
+
+Add the following setting in the model where you created and configured your auth object (probably in the model db):
+``
+auth.settings.manager_group_role = 'admin'
+``:code
+
+The user and groups administration menu has this URL (for adding to a menu)
+``
+URL('appadmin','auth_manage')
+``:code
+
+Upgrading an existing application requires a new appadmin controller (copied from the welcome app) and the new appadmin.html view.
+
+
#### Manual Authentication
#### Manual Authentication

If you want to connect to a web2py CAS provider from a different domain, you must enable them by appending to the list of allowed domains:
If you want to connect to a web2py CAS provider from a different domain, you must enable them by attending to the list of allowed domain:

Occasionally, it is necessary to combine requirements. This can be done via a generic ``requires`` decorator which takes a single argument, a true or false condition. For example, to give access to agents, but only on Tuesday:
``
@auth.requires(auth.has_membership(group_id='agents' \
and request.now.weekday()==1)
def function_seven():
return 'Hello agent, it must be Tuesday!'
``:code
Occasionally, it is necessary to combine requirements. This can be done via a generic ``requires`` decorator which takes a single argument, a true or false condition. For example, to give access to agents, but only on Tuesday:
``
@auth.requires(auth.has_membership(group_id=agents) \
and request.now.weekday()==1)
def function_seven():
return 'Hello agent, it must be Tuesday!'
``:code

``
from gluon.contrib.login_methods.rpx_account import RPXAccount
auth.settings.actions_disabled=['register','change_password','request_reset_password']
auth.settings.login_form = RPXAccount(request,
api_key='...',
domain='...',
url = "http://your-external-address/%s/default/user/login" % request.application)
``:code
+The first line imports the new login method, the second line disables local registration, and the third line asks web2py to use the RPX login method. You must insert your own ``api_key`` provided by Janrain.com, the domain you choose upon registration and the external ``url`` of your login page. To obtain then login at janrain.com, then go to [Deployment][Application Settings]. On the right side there is the "Application Info", The api_key is called "API Key (Secret)".
+
+The domain is the "Application Domain" without leading "https://" and without the trailing ".rpxnow.com/"
+For example: if you have registered a website as "secure.mywebsite.org", Janrain turns it to the Application Domain "https://secure-mywebsite.rpxnow.com".
+
``
from gluon.contrib.login_methods.rpx_account import RPXAccount
auth.settings.actions_disabled=['register','change_password','request_reset_password']
auth.settings.login_form = RPXAccount(request,
api_key='...',
domain='...',
url = "http://localhost:8000/%s/default/user/login" % request.application)
``:code
-The first line imports the new login method, the second line disables local registration, and the third line asks web2py to use the RPX login method. You must insert your own ``api_key`` provided by Janrain.com, the domain you choose upon registration and the external ``url`` of your login page.

-------
The ``password`` field of the ``db.auth_user`` table defaults to a ``CRYPT`` validator, which needs and ``hmac_key``. On legacy web2py applications you may see an extra argument passed to the Auth constructor: ``hmac_key = Auth.get_or_create_key()``. The latter is a function that read the HMAC key from a file "private/auth.key" within the application folder. If the file does not exist it creates a random ``hmac_key``. If multiple apps share the same auth database, make sure they also use the same ``hmac_key``. This is no longer necessary for new applications since passwords are salted with an individual random salt.
-------
By default, web2py uses email for login. If instead you want to log in using username set ``auth.define_tables(username=True)``
If multiple apps share the same auth database you may want to disable migrations: ``auth.define_tables(migrate=False)``.
To expose **Auth**, you also need the following function in a controller (for example in "default.py"):
``
def user(): return dict(form=auth())
``:code
-------
The ``auth`` object and the ``user`` action are already defined in the
scaffolding application.
-------
web2py also includes a sample view "welcome/views/default/user.html" to render this function properly that looks like this:
``
{{extend 'layout.html'}}
<h2>{{=T( request.args(0).replace('_',' ').capitalize() )}}</h2>
auth.messages.reset_password = 'Click on the link http://' + \
In the two ``auth.messages`` above, you may need to replace the URL portion of the string with the proper complete URL of the action. This is necessary because web2py may be installed behind a proxy, and it cannot determine its own public URLs with absolute certainty. The above examples (which are the default values) should, however, work in most cases.
### Authorization
Once a new user is registered, a new group is created to contain the user. The role of the new user is conventionally "user_[id]" where [id] is the id of the newly created user. The creation of the group can be disabled with
``
auth.settings.create_user_groups = None
``:code
although we do not suggest doing so. Notice that ``create_user_groups`` is not a boolean (although it can be ``False``) but it defaults to:
``
auth.settings.create_user_groups="user_%(id)s"
``:code
It store a template for the name of the group created for user ``id``.
Users have membership in groups. Each group is identified by a name/role. Groups have permissions. Users have permissions because of the groups they belong to. By default each user is made member of their own group.
You can also do
``
auth.settings.everybody_group_id = 5
``:code
-------
The ``password`` field of the ``db.auth_user`` table defaults to a ``CRYPT`` validator, which needs and ``hmac_key``. On legacy web2py applications you may see an extra argument passed to the Auth constructor: ``hmac_key = Auth.get_or_create_key()``. The latter is a function that read the HMAC key from a file "private/auth.key" within the application folder. If the file does not exist it creates a random ``hmac_key``. If multiple apps share the same auth database, make sure they also use the same ``hmac_key``. This is no loger necessary for new applications since passwords are salted with an individual random salt.
-------
By default, web2py uses email for login. If instead you want to log in using username set ``auth.define_tables(username=True)``
If multiple apps share the same auth database you may want to disable migrations: ``auth.define_tables(migrate=False)``.
To expose **Auth**, you also need the following function in a controller (for example in "default.py"):
``
def user(): return dict(form=auth())
``:code
-------
The ``auth`` object and the ``user`` action are already defined in the
scaffolding application.
-------
web2py also includes a sample view "welcome/views/default/user.html" to render this function properly that looks like this:
``
{{extend 'layout.html'}}
<h2>{{=T( request.args(0).replace('_',' ').capitalize() )}}</h2>
auth.messages.reset_password = 'Click on the link http://' + \
In the two ``auth.messages`` above, you may need to replace the URL portion of the string with the proper complete URL of the action. This is necessary because web2py may be installed behind a proxy, and it cannot determine its own public URLs with absolute certainty. The above examples (which are the default values) should, however, work in most cases.
### Authorization
Once a new user is registered, a new group is created to contain the user. The role of the new user is conventionally "user_[id]" where [id] is the id of the newly created user. The creation of the group can be disabled with
``
auth.settings.create_user_groups = None
``:code
although we do not suggest doing so. Notice that ``create_user_groups`` is not a boolean (although it can be ``False``) but it defaults to:
``
auth.settings.create_user_groups="user_%(id)s"
``:code
It store a template for the name of the group created for user ``id``.
Users have membership in groups. Each group is identified by a name/role. Groups have permissions. Users have permissions because of the groups they belong to. By default each user is made member of their own group.
You can also also do
``
auth.settings.everybody_group_id = 5
``:code

First of all you must install the [[Facebook Python SDK https://github.com/pythonforfacebook/facebook-sdk/]].
First of all you must install the [[Facebook Python SDK https://github.com/facebook/python-sdk]].

You need to replace the mail.settings with the proper parameters for your SMTP server. Set ``mail.settings.login = None`` if the SMTP server does not require authentication. If you don't want to use TLS, set ``mail.settings.tls = False``
You need to replace the mail.settings with the proper parameters for your SMTP server. Set ``mail.settings.login = None`` if the SMTP server does not require authentication.

**Auth** needs (and defines) the following tables:
- ``auth_user`` stores users' name, email address, password, and status (registration pending, accepted, blocked)
- ``auth_group`` stores groups or roles for users in a many-to-many structure. By default, each user is in its own group, but a user can be in multiple groups, and each group can contain multiple users. A group is identified by a role and a description.
- ``auth_membership`` links users and groups in a many-to-many structure.
- ``auth_permission`` links groups and permissions. A permission is identified by a name and, optionally, a table and a record. For example, members of a certain group can have "update" permissions on a specific record of a specific table.
- ``auth_event`` logs changes in the other tables and successful access via CRUD to objects controlled by the RBAC.
- ``auth_cas`` is used for Central Authentication Service (CAS). Every web2py application is a CAS provider and can optionally be a CAS consumer.
The schema is reproduced graphically in the image below:
[[image @///image/schema_auth.png center 300px]]
In principle, there is no restriction on the names of the roles and the names of the permissions; the developer can create them to fix the roles and permissions in the organization. Once they have been created, web2py provides an API to check if a user is logged in, if a user is a member of a given group, and/or if the user is a member of any group that has a given required permission.
web2py also provides decorators to restrict access to any function based on login, membership and permissions.
web2py also understands some specific permissions, i.e., those that have a name that correspond to the CRUD methods (create, read, update, delete) and can enforce them automatically without the need to use decorators.
In this chapter, we are going to discuss different parts of RBAC one by one.
### Authentication
In order to use RBAC, users need to be identified. This means that they need to register (or be registered) and log in.
**Auth** provides multiple login methods. The default one consists of identifying users based on the local ``auth_user`` table.
Alternatively, it can log in users against third-party authentication systems and single sign on providers such as Google, PAM, LDAP, Facebook, LinkedIn, Dropbox, OpenID, OAuth, etc..
To start using ``Auth``, you need at least this code in a model file, which is also provided with the web2py "welcome" application and assumes a ``db`` connection object:
``
from gluon.tools import Auth
auth = Auth(db)
auth.define_tables()
``:code
Auth has an optional ``secure=True`` argument, which will force authenticated pages to go over HTTPS. ``https``:inxx
-------
The ``password`` field of the ``db.auth_user`` table defaults to a ``CRYPT`` validator, which needs and ``hmac_key``. On legacy web2py applications you may see an extra argument passed to the Auth constructor: ``hmac_key = Auth.get_or_create_key()``. The latter is a function that read the HMAC key from a file "private/auth.key" within the application folder. If the file does not exist it creates a random ``hmac_key``. If multiple apps share the same auth database, make sure they also use the same ``hmac_key``. This is no loger necessary for new applications since passwords are salted with an individual random salt.
-------
By default, web2py uses email for login. If instead you want to log in using username set ``auth.define_tables(username=True)``
If multiple apps share the same auth database you may want to disable migrations: ``auth.define_tables(migrate=False)``.
To expose **Auth**, you also need the following function in a controller (for example in "default.py"):
``
def user(): return dict(form=auth())
``:code
-------
The ``auth`` object and the ``user`` action are already defined in the
scaffolding application.
-------
web2py also includes a sample view "welcome/views/default/user.html" to render this function properly that looks like this:
``
{{extend 'layout.html'}}
<h2>{{=T( request.args(0).replace('_',' ').capitalize() )}}</h2>
Notice that this function simply displays a ``form`` and therefore it can be cus
{{if request.args(0)=='login':}}...custom login form...{{pass}}
``:code
``auth.impersonate``:inxx ``auth.is_impersonating``:inxx
The controller above exposes multiple actions:
``
http://.../[app]/default/user/register
http://.../[app]/default/user/login
http://.../[app]/default/user/logout
http://.../[app]/default/user/profile
http://.../[app]/default/user/change_password
http://.../[app]/default/user/verify_email
http://.../[app]/default/user/retrieve_username
http://.../[app]/default/user/request_reset_password
http://.../[app]/default/user/reset_password
http://.../[app]/default/user/impersonate
http://.../[app]/default/user/groups
http://.../[app]/default/user/not_authorized
``:code
- **register** allows users to register. It is integrated with CAPTCHA, although this is disabled by default. This is also integrated with a client-side entropy calculator defined in "web2py.js". The calculator indicates the strength of the new password. You can use the ``IS_STRONG`` validator to prevent web2py from accepting weak passwords.
- **login** allows users who are registered to log in (if the registration is verified or does not require verification, if it has been approved or does not require approval, and if it has not been blocked).
- **logout** does what you would expect but also, as the other methods, logs the event and can be used to trigger some event.
- **profile** allows users to edit their profile, i.e. the content of the ``auth_user`` table. Notice that this table does not have a fixed structure and can be customized.
- **change_password** allows users to change their password in a fail-safe way.
- **verify_email**. If email verification is turned on, then visitors, upon registration, receive an email with a link to verify their email information. The link points to this action.
- **retrieve_username**. By default, **Auth** uses email and password for login, but it can, optionally, use username instead of email. In this latter case, if a user forgets his/her username, the ``retrieve_username`` method allows the user to type the email address and retrieve the username by email.
- **request_reset_password**. Allows users who forgot their password to request a new password. They will get a confirmation email pointing to **reset_password**.
- **impersonate** allows a user to "impersonate" another user. This is important for debugging and for support purposes. ``request.args[0]`` is the id of the user to be impersonated. This is only allowed if the logged in user ``has_permission('impersonate', db.auth_user, user_id)``. You can use ``auth.is_impersonating()`` to check is the current user is impersonating somebody else.
- **groups** lists the groups of which the current logged in user is a member.
- **not_authorized** displays an error message when the visitor tried to do something that he/she is not authorized to do
- **navbar** is a helper that generates a bar with login/register/etc. links.
Logout, profile, change_password, impersonate, and groups require login.
By default they are all exposed, but it is possible to restrict access to only some of these actions.
All of the methods above can be extended or replaced by subclassing **Auth**.
All of the methods above can be used in separate actions. For example:
auth.settings.registration_requires_approval = False
auth.settings.reset_password_requires_verification = True
auth.messages.verify_email = 'Click on the link http://' + \
request.env.http_host + \
URL(r=request,c='default',f='user',args=['verify_email']) + \
'/%(key)s to verify your email'
auth.messages.reset_password = 'Click on the link http://' + \
request.env.http_host + \
URL(r=request,c='default',f='user',args=['reset_password']) + \
'/%(key)s to reset your password'
``:code
In the two ``auth.messages`` above, you may need to replace the URL portion of the string with the proper complete URL of the action. This is necessary because web2py may be installed behind a proxy, and it cannot determine its own public URLs with absolute certainty. The above examples (which are the default values) should, however, work in most cases.
### Authorization
Once a new user is registered, a new group is created to contain the user. The role of the new user is conventionally "user_[id]" where [id] is the id of the newly created user. The creation of the group can be disabled with
``
auth.settings.create_user_groups = None
``:code
although we do not suggest doing so. Notice that ``create_user_groups`` is not a boolean (although it can be ``False``) but it defaults to:
**Auth** needs (and defines) the following tables:
- ``auth_user`` stores users' name, email address, password, and status (registration pending, accepted, blocked)
- ``auth_group`` stores groups or roles for users in a many-to-many structure. By default, each user is in its own group, but a user can be in multiple groups, and each group can contain multiple users. A group is identified by a role and a description.
- ``auth_membership`` links users and groups in a many-to-many structure.
- ``auth_permission`` links groups and permissions. A permission is identified by a name and, optionally, a table and a record. For example, members of a certain group can have "update" permissions on a specific record of a specific table.
- ``auth_event`` logs changes in the other tables and successful access via CRUD to objects controlled by the RBAC.
- ``auth_cas`` is used for Central Autheticatication Service (CAS). Every web2py application is a CAS provider and can optionally be a CAS consumer.
The schema is reproduced graphically in the image below:
[[image @///image/schema_auth.png center 300px]]
In principle, there is no restriction on the names of the roles and the names of the permissions; the developer can create them to fix the roles and permissions in the organization. Once they have been created, web2py provides an API to check if a user is logged in, if a user is a member of a given group, and/or if the user is a member of any group that has a given required permission.
web2py also provides decorators to restrict access to any function based on login, membership and permissions.
web2py also understands some specific permissions, i.e., those that have a name that correspond to the CRUD methods (create, read, update, delete) and can enforce them automatically without the need to use decorators.
In this chapter, we are going to discuss different parts of RBAC one by one.
### Authentication
In order to use RBAC, users need to be identified. This means that they need to register (or be registered) and log in.
**Auth** provides multiple login methods. The default one consists of identifying users based on the local ``auth_user`` table.
Alternatively, it can log in users against third-party authentication systems and single sign on providers such as Google, PAM, LDAP, Facebook, LinkedIn, Dropbox, OpenID, OAuth, etc..
To start using ``Auth``, you need at least this code in a model file, which is also provided with the web2py "welcome" application and assumes a ``db`` connection object:
``
from gluon.tools import Auth
auth = Auth(db)
auth.define_tables()
``:code
Auth has an optional ``secure=True`` argument, which will force authenticated pages to go over HTTPS. ``https``:inxx
-------
The ``password`` field of the ``db.auth_user`` table defaults to a ``CRYPT`` validator, which needs and ``hmac_key``. On legacy web2py applications you may see an extra argument passed to the Auth constructor: ``hmac_key = Auth.get_or_create_key()``. The latter is a function that read the hmac kay from a file "private/auth.key" within the application folder. If the file does not exist it creates a random ``hmac_key``. If multiple apps share the same auth database, make sure they also use the same ``hmac_key``. This is no loger necessary for new applications since passwords are salted with an individual random salt.
-------
By default, web2py uses email for login. If instead you want to log in using username set ``auth.define_tables(username=True)``
If multiple apps share the same auth database you may want to disable migrations: ``auth.define_tables(migrate=False)``.
To expose **Auth**, you also need the following function in a controller (for example in "default.py"):
``
def user(): return dict(form=auth())
``:code
-------
The ``auth`` object and the ``user`` action are already defined in the
scaffolding application.
-------
web2py also includes a sample view "welcome/views/default/user.html" to render this function properly that looks like this:
``
{{extend 'layout.html'}}
<h2>{{=T( request.args(0).replace('_',' ').capitalize() )}}</h2>
Notice that this function simply displays a ``form`` and therefore it can be cus
{{if request.args(0)=='login':}}...custom login form...{{pass}}
``:code
``auth.impersonate``:inxx ``auth.is_impersonating``:inxx
The controller above exposes multiple actions:
``
http://.../[app]/default/user/register
http://.../[app]/default/user/login
http://.../[app]/default/user/logout
http://.../[app]/default/user/profile
http://.../[app]/default/user/change_password
http://.../[app]/default/user/verify_email
http://.../[app]/default/user/retrieve_username
http://.../[app]/default/user/request_reset_password
http://.../[app]/default/user/reset_password
http://.../[app]/default/user/impersonate
http://.../[app]/default/user/groups
http://.../[app]/default/user/not_authorized
``:code
- **register** allows users to register. It is integrated with CAPTCHA, although this is disabled by default. This is also integrated with a client-side entropy calculator defined in "web2py.js". The calculator indictates the strenght of the new password. You can use the ``IS_STRONG`` validator to prevent web2py from accepting weak passwords.
- **login** allows users who are registered to log in (if the registration is verified or does not require verification, if it has been approved or does not require approval, and if it has not been blocked).
- **logout** does what you would expect but also, as the other methods, logs the event and can be used to trigger some event.
- **profile** allows users to edit their profile, i.e. the content of the ``auth_user`` table. Notice that this table does not have a fixed structure and can be customized.
- **change_password** allows users to change their password in a fail-safe way.
- **verify_email**. If email verification is turned on, then visitors, upon registration, receive an email with a link to verify their email information. The link points to this action.
- **retrieve_username**. By default, **Auth** uses email and password for login, but it can, optionally, use username instead of email. In this latter case, if a user forgets his/her username, the ``retrieve_username`` method allows the user to type the email address and retrieve the username by email.
- **request_reset_password**. Allows users who forgot their password to request a new password. They will get a confirmation email pointing to **reset_password**.
- **impersonate** allows a user to "impersonate" another user. This is important for debugging and for support purposes. ``request.args[0]`` is the id of the user to be impersonated. This is only allowed if the logged in user ``has_permission('impersonate', db.auth_user, user_id)``. You can use ``auth.is_impersonating()`` to check is the current user is impersonating somebody else.
- **groups** lists the groups of which the current logged in user is a member.
- **not_authorized** displays an error message when the visitor tried to do something that he/she is not authorized to do
- **navbar** is a helper that generates a bar with login/register/etc. links.
Logout, profile, change_password, impersonate, and groups require login.
By default they are all exposed, but it is possible to restrict access to only some of these actions.
All of the methods above can be extended or replaced by subclassing **Auth**.
All of the methods above can be used in separate actions. For example:
auth.settings.registration_requires_approval = False
auth.settings.reset_password_requires_verification = True
auth.messages.verify_email = 'Click on the link http://' + \
request.env.http_host + \
URL(r=request,c='default',f='user',args=['verify_email']) + \
'/%(key)s to verify your email'
auth.messages.reset_password = 'Click on the link http://' + \
request.env.http_host + \
URL(r=request,c='default',f='user',args=['reset_password']) + \
'/%(key)s to reset your password'
``:code
In the two ``auth.messages`` above, you may need to replace the URL portion of the string with the proper complete URL of the action. This is necessary because web2py may be installed behind a proxy, and it cannot determine its own public URLs with absolute certainty. The above examples (which are the default values) should, however, work in most cases.
### Authorization
Once a new user is registered, a new group is created to contain the user. The role of the new user is conventionally "user_[id]" where [id] is the id of the newly created user. The creation of the group can be disabled with
``
auth.settings.create_user_groups = None
``:code
although we do not suggest doing so. Notice that ``create_user_groups`` is not a boolean (althought it can be ``False``) but it defaults to:

**Auth** needs (and defines) the following tables:
- ``auth_user`` stores users' name, email address, password, and status (registration pending, accepted, blocked)
- ``auth_group`` stores groups or roles for users in a many-to-many structure. By default, each user is in its own group, but a user can be in multiple groups, and each group can contain multiple users. A group is identified by a role and a description.
- ``auth_membership`` links users and groups in a many-to-many structure.
- ``auth_permission`` links groups and permissions. A permission is identified by a name and, optionally, a table and a record. For example, members of a certain group can have "update" permissions on a specific record of a specific table.
- ``auth_event`` logs changes in the other tables and successful access via CRUD to objects controlled by the RBAC.
+- ``auth_cas`` is used for Central Autheticatication Service (CAS). Every web2py application is a CAS provider and can optionally be a CAS consumer.
+
+The schema is reproduced graphically in the image below:
+
+[[image @///image/schema_auth.png center 300px]]
+
+
**Auth** needs (and defines) the following tables:
- ``auth_user`` stores users' name, email address, password, and status (registration pending, accepted, blocked)
- ``auth_group`` stores groups or roles for users in a many-to-many structure. By default, each user is in its own group, but a user can be in multiple groups, and each group can contain multiple users. A group is identified by a role and a description.
- ``auth_membership`` links users and groups in a many-to-many structure.
- ``auth_permission`` links groups and permissions. A permission is identified by a name and, optionally, a table and a record. For example, members of a certain group can have "update" permissions on a specific record of a specific table.
- ``auth_event`` logs changes in the other tables and successful access via CRUD to objects controlled by the RBAC.

``
auth.settings.label_separator = ':'
``:code
``
auth.settings.label_separator = ':'
``:code

Another way to do this, although not really recommended, consists of defining your auth tables yourself. If a table is declared before ``auth.define_tables()`` it is used instead of the default one. Here is how to do it:
Another way to do this (for experts!) consists of defining your auth tables yourself. If a table is declared before ``auth.define_tables()`` it is used instead of the default one. Here is how to do it:

More details: [[reCAPTCHA http://www.google.com/recaptcha]]``recaptchagoogle``:cite and [[customizing http://code.google.com/apis/recaptcha/docs/customization.html]] .
More details: [[reCAPTCHA http://www.google.com/recaptcha]]``recaptchagoogle``:cite and [[customizing http://code.google.com/apis/recaptcha/docs/customization.html]]``recaptchacustomizing``:cite .

#### ``Mail`` and ``Auth``
### ``Mail`` and ``Auth``

The controller above exposes multiple actions:
``
http://.../[app]/default/user/register
http://.../[app]/default/user/login
http://.../[app]/default/user/logout
http://.../[app]/default/user/profile
http://.../[app]/default/user/change_password
http://.../[app]/default/user/verify_email
http://.../[app]/default/user/retrieve_username
http://.../[app]/default/user/request_reset_password
http://.../[app]/default/user/reset_password
http://.../[app]/default/user/impersonate
http://.../[app]/default/user/groups
http://.../[app]/default/user/not_authorized
``:code
- **register** allows users to register. It is integrated with CAPTCHA, although this is disabled by default. This is also integrated with a client-side entropy calculator defined in "web2py.js". The calculator indictates the strenght of the new password. You can use the ``IS_STRONG`` validator to prevent web2py from accepting weak passwords.
- **login** allows users who are registered to log in (if the registration is verified or does not require verification, if it has been approved or does not require approval, and if it has not been blocked).
- **logout** does what you would expect but also, as the other methods, logs the event and can be used to trigger some event.
- **profile** allows users to edit their profile, i.e. the content of the ``auth_user`` table. Notice that this table does not have a fixed structure and can be customized.
- **change_password** allows users to change their password in a fail-safe way.
- **verify_email**. If email verification is turned on, then visitors, upon registration, receive an email with a link to verify their email information. The link points to this action.
- **retrieve_username**. By default, **Auth** uses email and password for login, but it can, optionally, use username instead of email. In this latter case, if a user forgets his/her username, the ``retrieve_username`` method allows the user to type the email address and retrieve the username by email.
- **request_reset_password**. Allows users who forgot their password to request a new password. They will get a confirmation email pointing to **reset_password**.
- **impersonate** allows a user to "impersonate" another user. This is important for debugging and for support purposes. ``request.args[0]`` is the id of the user to be impersonated. This is only allowed if the logged in user ``has_permission('impersonate', db.auth_user, user_id)``. You can use ``auth.is_impersonating()`` to check is the current user is impersonating somebody else.
- **groups** lists the groups of which the current logged in user is a member.
- **not_authorized** displays an error message when the visitor tried to do something that he/she is not authorized to do
- **navbar** is a helper that generates a bar with login/register/etc. links.
The controller above exposes multiple actions:
``
http://.../[app]/default/user/register
http://.../[app]/default/user/login
http://.../[app]/default/user/logout
http://.../[app]/default/user/profile
http://.../[app]/default/user/change_password
http://.../[app]/default/user/verify_email
http://.../[app]/default/user/retrieve_username
http://.../[app]/default/user/request_reset_password
http://.../[app]/default/user/reset_password
http://.../[app]/default/user/impersonate
http://.../[app]/default/user/groups
http://.../[app]/default/user/not_authorized
``:code
- **register** allows users to register. It is integrated with CAPTCHA, although this is disabled by default.
- **login** allows users who are registered to log in (if the registration is verified or does not require verification, if it has been approved or does not require approval, and if it has not been blocked).
- **logout** does what you would expect but also, as the other methods, logs the event and can be used to trigger some event.
- **profile** allows users to edit their profile, i.e. the content of the ``auth_user`` table. Notice that this table does not have a fixed structure and can be customized.
- **change_password** allows users to change their password in a fail-safe way.
- **verify_email**. If email verification is turned on, then visitors, upon registration, receive an email with a link to verify their email information. The link points to this action.
- **retrieve_username**. By default, **Auth** uses email and password for login, but it can, optionally, use username instead of email. In this latter case, if a user forgets his/her username, the ``retrieve_username`` method allows the user to type the email address and retrieve the username by email.
- **request_reset_password**. Allows users who forgot their password to request a new password. They will get a confirmation email pointing to **reset_password**.
- **impersonate** allows a user to "impersonate" another user. This is important for debugging and for support purposes. ``request.args[0]`` is the id of the user to be impersonated. This is only allowed if the logged in user ``has_permission('impersonate', db.auth_user, user_id)``. You can use ``auth.is_impersonating()`` to check is the current user is impersonating somebody else.
- **groups** lists the groups of which the current logged in user is a member.
- **not_authorized** displays an error message when the visitor tried to do something that he/she is not authorized to do
- **navbar** is a helper that generates a bar with login/register/etc. links.

gives permission "name" (user defined) on the object "object" (also user defined) to members of the group ``group_id``. If "object" is a tablename then the permission can refer to the entire table by setting ``record_id`` to a value of zero, or the permission can refer to a specific record by specifying a ``record_id`` value greater than zero. When giving permissions on tables, it is common to use a permission name in the set ('create', 'read', 'update', 'delete', 'select') since these permissions are understood and can be enforced by the CRUD APIs.
gives permission "name" (user defined) on the object "object" (also user defined) to members of the group ``group_id``. If "object" is a tablename then the permission can refer to the entire table by setting ``record_id`` to a value of zero, or the permission can refer to a specific record by specifying a ``record_id`` value greater than zero. When giving permissions on tables, it is common to use a permission name in the set ('create', 'read', 'update', 'delete', 'select') since these permissions are understood and can be enforced by CRUD.

+Auth has an optional ``secure=True`` argument, which will force authenticated pages to go over HTTPS. ``https``:inxx
+
-------
The ``password`` field of the ``db.auth_user`` table defaults to a ``CRYPT`` validator, which needs and ``hmac_key``. On legacy web2py applications you may see an extra argument passed to the Auth constructor: ``hmac_key = Auth.get_or_create_key()``. The latter is a function that read the hmac kay from a file "private/auth.key" within the application folder. If the file does not exist it creates a random ``hmac_key``. If multiple apps share the same auth database, make sure they also use the same ``hmac_key``. This is no loger necessary for new applications since passwords are salted with an individual random salt.
-------
By default, web2py uses email for login. If instead you want to log in using username set ``auth.define_tables(username=True)``
If multiple apps share the same auth database you may want to disable migrations: ``auth.define_tables(migrate=False)``.
To expose **Auth**, you also need the following function in a controller (for example in "default.py"):
``
def user(): return dict(form=auth())
``:code
-------
The ``auth`` object and the ``user`` action are already defined in the
scaffolding application.
-------
web2py also includes a sample view "welcome/views/default/user.html" to render this function properly that looks like this:
``
web2py also includes a sample view "welcome/views/default/user.html" to render t
<h2>{{=T( request.args(0).replace('_',' ').capitalize() )}}</h2>
<div id="web2py_user_form">
{{=form}}
{{if request.args(0)=='login':}}
{{if not 'register' in auth.settings.actions_disabled:}}
<br/><a href="{{=URL(args='register')}}">register</a>
{{pass}}
{{if not 'request_reset_password' in auth.settings.actions_disabled:}}
<br/>
<a href="{{=URL(args='request_reset_password')}}">lost password</a>
{{pass}}
{{pass}}
</div>
``:code
Notice that this function simply displays a ``form`` and therefore it can be customized using normal custom form syntax. The only caveat is that the form displayed by ``form=auth()`` depends on ``request.args(0)``; therefore, if you replace the default ``auth()`` login form with a custom login form, you may need an ``if`` statement like this in the view:
``
{{if request.args(0)=='login':}}...custom login form...{{pass}}
``:code
+``auth.impersonate``:inxx ``auth.is_impersonating``:inxx
+
The controller above exposes multiple actions:
``
http://.../[app]/default/user/register
http://.../[app]/default/user/login
http://.../[app]/default/user/logout
http://.../[app]/default/user/profile
http://.../[app]/default/user/change_password
http://.../[app]/default/user/verify_email
http://.../[app]/default/user/retrieve_username
http://.../[app]/default/user/request_reset_password
http://.../[app]/default/user/reset_password
http://.../[app]/default/user/impersonate
http://.../[app]/default/user/groups
http://.../[app]/default/user/not_authorized
``:code
- **register** allows users to register. It is integrated with CAPTCHA, although this is disabled by default.
- **login** allows users who are registered to log in (if the registration is verified or does not require verification, if it has been approved or does not require approval, and if it has not been blocked).
- **logout** does what you would expect but also, as the other methods, logs the event and can be used to trigger some event.
- **profile** allows users to edit their profile, i.e. the content of the ``auth_user`` table. Notice that this table does not have a fixed structure and can be customized.
- **change_password** allows users to change their password in a fail-safe way.
- **verify_email**. If email verification is turned on, then visitors, upon registration, receive an email with a link to verify their email information. The link points to this action.
- **retrieve_username**. By default, **Auth** uses email and password for login, but it can, optionally, use username instead of email. In this latter case, if a user forgets his/her username, the ``retrieve_username`` method allows the user to type the email address and retrieve the username by email.
- **request_reset_password**. Allows users who forgot their password to request a new password. They will get a confirmation email pointing to **reset_password**.
- **impersonate** allows a user to "impersonate" another user. This is important for debugging and for support purposes. ``request.args[0]`` is the id of the user to be impersonated. This is only allowed if the logged in user ``has_permission('impersonate', db.auth_user, user_id)``. You can use ``auth.is_impersonating()`` to check is the current user is impersonating somebody else.
- **groups** lists the groups of which the current logged in user is a member.
- **not_authorized** displays an error message when the visitor tried to do something that he/she is not authorized to do
- **navbar** is a helper that generates a bar with login/register/etc. links.
Logout, profile, change_password, impersonate, and groups require login.
By default they are all exposed, but it is possible to restrict access to only some of these actions.
All of the methods above can be extended or replaced by subclassing **Auth**.
All of the methods above can be used in separate actions. For example:
``
def mylogin(): return dict(form=auth.login())
def myregister(): return dict(form=auth.register())
def myprofile(): return dict(form=auth.profile())
...
``
To restrict access to functions to only logged in visitors, decorate the function as in the following example
``
@auth.requires_login()
def hello():
return dict(message='hello %(first_name)s' % auth.user)
``:code
Any function can be decorated, not just exposed actions. Of course this is still only a very simple example of access control. More complex examples will be discussed later.
``auth.user``:inxx ``auth.user_id``:inxx ``auth.user_groups``.
-----
``auth.user`` contains a copy of the ``db.auth_user`` records for the current logged in user or ``None`` otherwise. There is also a ``auth.user_id`` which is the same as ``auth.user.id`` (i.e. the id of the current logger in user) or ``None``. Similarly, ``auth.user_groups`` contains a dictionary where each key is the id of a group of with the current logged in user is member of, the value is the corresponding group role.
-----
``otherwise``:inxx
The ``auth.requires_login()`` decorator as well as the other ``auth.requires_*`` decorators take an optional ``otherwise`` argument. It can be set to a string where to redirect the user if registration files or to a callable object. It is called if registration fails.
#### Restrictions on registration
If you want to allow visitors to register but not to log in until registration has been approved by the administrator:
``
auth.settings.registration_requires_approval = True
``:code
You can approve a registration via the appadmin interface. Look into the table ``auth_user``. Pending registrations have a ``registration_key`` field set to "pending". A registration is approved when this field is set to blank.
Via the appadmin interface, you can also block a user from logging in. Locate the user in the table ``auth_user`` and set the ``registration_key`` to "blocked". "blocked" users are not allowed to log in. Notice that this will prevent a visitor from logging in but it will not force a visitor who is already logged in to log out. The word "disabled" may be used instead of "blocked" if preferred, with exactly the same behavior.
You can also block access to the "register" page completely with this statement:
``
auth.settings.actions_disabled.append('register')
curl -d "firstName=John&lastName=Smith" -G -v --key private.key \
This works out of the box with Rocket (the web2py built-in web server) but you may need some extra configuration work on the web server side if you are using a different web server. In particular you need to tell your web server where the certificates are located on local host and that it needs to verify certificates coming from the clients. How to do it is web server dependent and therefore omitted here.
##### Multiple login forms
Some login methods modify the login_form, some do not. When they do that, they may not be able to coexist. Yet some coexist by providing multiple login forms in the same page. web2py provides a way to do it. Here is an example mixing normal login (auth) and RPX login (janrain.com):
``
from gluon.contrib.login_methods.extended_login_form import ExtendedLoginForm
other_form = RPXAccount(request, api_key='...', domain='...', url='...')
auth.settings.login_form = ExtendedLoginForm(auth, other_form, signals=['token'])
``:code
If signals are set and a parameter in request matches any signals,
it will return the call of ``other_form.login_form`` instead.
``other_form`` can handle some particular situations, for example,
multiple steps of OpenID login inside ``other_form.login_form``.
Otherwise it will render the normal login form together with the ``other_form``.
+#### Record versioning
+
+You can use Auth to enable full record versioning:
+
+``
+db.enable_record_versioning(db,
+ archive_db=None,
+ archive_names='%(tablename)s_archive',
+ current_record='current_record'):
+``:code
+
+This tells web2py to create an archive table for each of the tables in ``db`` and store a copy of each record when modified. The old copy is stored. The new copy is not.
+
+The last three parameters are optional:
+
+- ``archive_db`` allows to specify another database where the archive tables are to be stored. Setting it to ``None`` is the same as setting it to ``db``.
+- ``archive_names`` provides a pattern for naming each archive table.
+- ``current_record`` specified the name of the reference field to be used in the archive table to refer to the original, unmodified, record. Notice that ``archive_db!=db`` then the reference field is just an integer field since cross database references are not possible.
+
+
+Only tables with ``modified_by`` and ``modified_on`` fields (as created
+for example by auth.signature) will be archived.
+
+When you ``enable_record_versioning``, if records have an
+``is_active`` field (also created by auth.signature),
+records will never be deleted but they will be marked with ``is_active=False``.
+In fact, ``enable_record_versioning`` adds a ``common_filter`` to
+every versioned table that filters out records with ``is_active=False`` so they essentially become invisible.
+
+If you ``enable_record_versioning``, you should not use
+``auth.archive`` or ``crud.archive`` else you will end up with duplicate records.
+Those functions do explicitly what ``enable_record_versioning`` does automatically and
+they will be deprecated.
+
+
### ``Mail`` and ``Auth``
One can define a mailer with
``
from gluon.tools import Mail
mail = Mail()
mail.settings.server = 'smtp.example.com:25'
mail.settings.sender = 'you@example.com'
mail.settings.login = 'username:password'
``
or simply use the mailer provided by ``auth``:
``
mail = auth.settings.mailer
mail.settings.server = 'smtp.example.com:25'
mail.settings.sender = 'you@example.com'
mail.settings.login = 'username:password'
To enable email, append the following lines in the model where ``auth`` is defin
``
auth.settings.registration_requires_verification = True
auth.settings.registration_requires_approval = False
auth.settings.reset_password_requires_verification = True
auth.messages.verify_email = 'Click on the link http://' + \
request.env.http_host + \
URL(r=request,c='default',f='user',args=['verify_email']) + \
'/%(key)s to verify your email'
auth.messages.reset_password = 'Click on the link http://' + \
request.env.http_host + \
URL(r=request,c='default',f='user',args=['reset_password']) + \
'/%(key)s to reset your password'
``:code
In the two ``auth.messages`` above, you may need to replace the URL portion of the string with the proper complete URL of the action. This is necessary because web2py may be installed behind a proxy, and it cannot determine its own public URLs with absolute certainty. The above examples (which are the default values) should, however, work in most cases.
### Authorization
Once a new user is registered, a new group is created to contain the user. The role of the new user is conventionally "user_[id]" where [id] is the id of the newly created user. The creation of the group can be disabled with
``
auth.settings.create_user_groups = None
``:code
+although we do not suggest doing so. Notice that ``create_user_groups`` is not a boolean (althought it can be ``False``) but it defaults to:
+
+``
+auth.settings.create_user_groups="user_%(id)s"
+``:code
+
+It store a template for the name of the group created for user ``id``.
+
+Users have membership in groups. Each group is identified by a name/role. Groups have permissions. Users have permissions because of the groups they belong to. By default each user is made member of their own group.
+
+You can also also do
+``
+auth.settings.everybody_group_id = 5
+``:code
to make any new user automatically member of group number 5. Here 5 is used as an example and we assume the group was created already.
-------
The ``password`` field of the ``db.auth_user`` table defaults to a ``CRYPT`` validator, which needs and ``hmac_key``. On legacy web2py applications you may see an extra argument passed to the Auth constructor: ``hmac_key = Auth.get_or_create_key()``. The latter is a function that read the hmac kay from a file "private/auth.key" within the application folder. If the file does not exist it creates a random ``hmac_key``. If multiple apps share the same auth database, make sure they also use the same ``hmac_key``. This is no loger necessary for new applications since passwords are salted with an individual random salt.
-------
By default, web2py uses email for login. If instead you want to log in using username set ``auth.define_tables(username=True)``
If multiple apps share the same auth database you may want to disable migrations: ``auth.define_tables(migrate=False)``.
To expose **Auth**, you also need the following function in a controller (for example in "default.py"):
``
def user(): return dict(form=auth())
``:code
-------
The ``auth`` object and the ``user`` action are already defined in the
scaffolding application.
-------
web2py also includes a sample view "welcome/views/default/user.html" to render this function properly that looks like this:
``
web2py also includes a sample view "welcome/views/default/user.html" to render t
<h2>{{=T( request.args(0).replace('_',' ').capitalize() )}}</h2>
<div id="web2py_user_form">
{{=form}}
{{if request.args(0)=='login':}}
{{if not 'register' in auth.settings.actions_disabled:}}
<br/><a href="{{=URL(args='register')}}">register</a>
{{pass}}
{{if not 'request_reset_password' in auth.settings.actions_disabled:}}
<br/>
<a href="{{=URL(args='request_reset_password')}}">lost password</a>
{{pass}}
{{pass}}
</div>
``:code
Notice that this function simply displays a ``form`` and therefore it can be customized using normal custom form syntax. The only caveat is that the form displayed by ``form=auth()`` depends on ``request.args(0)``; therefore, if you replace the default ``auth()`` login form with a custom login form, you may need an ``if`` statement like this in the view:
``
{{if request.args(0)=='login':}}...custom login form...{{pass}}
``:code
The controller above exposes multiple actions:
``
http://.../[app]/default/user/register
http://.../[app]/default/user/login
http://.../[app]/default/user/logout
http://.../[app]/default/user/profile
http://.../[app]/default/user/change_password
http://.../[app]/default/user/verify_email
http://.../[app]/default/user/retrieve_username
http://.../[app]/default/user/request_reset_password
http://.../[app]/default/user/reset_password
http://.../[app]/default/user/impersonate
http://.../[app]/default/user/groups
http://.../[app]/default/user/not_authorized
``:code
- **register** allows users to register. It is integrated with CAPTCHA, although this is disabled by default.
- **login** allows users who are registered to log in (if the registration is verified or does not require verification, if it has been approved or does not require approval, and if it has not been blocked).
- **logout** does what you would expect but also, as the other methods, logs the event and can be used to trigger some event.
- **profile** allows users to edit their profile, i.e. the content of the ``auth_user`` table. Notice that this table does not have a fixed structure and can be customized.
- **change_password** allows users to change their password in a fail-safe way.
- **verify_email**. If email verification is turned on, then visitors, upon registration, receive an email with a link to verify their email information. The link points to this action.
- **retrieve_username**. By default, **Auth** uses email and password for login, but it can, optionally, use username instead of email. In this latter case, if a user forgets his/her username, the ``retrieve_username`` method allows the user to type the email address and retrieve the username by email.
- **request_reset_password**. Allows users who forgot their password to request a new password. They will get a confirmation email pointing to **reset_password**.
- **impersonate** allows a user to "impersonate" another user. This is important for debugging and for support purposes. ``request.args[0]`` is the id of the user to be impersonated. This is only allowed if the logged in user ``has_permission('impersonate', db.auth_user, user_id)``.
- **groups** lists the groups of which the current logged in user is a member.
- **not_authorized** displays an error message when the visitor tried to do something that he/she is not authorized to do
- **navbar** is a helper that generates a bar with login/register/etc. links.
Logout, profile, change_password, impersonate, and groups require login.
By default they are all exposed, but it is possible to restrict access to only some of these actions.
All of the methods above can be extended or replaced by subclassing **Auth**.
All of the methods above can be used in separate actions. For example:
``
def mylogin(): return dict(form=auth.login())
def myregister(): return dict(form=auth.register())
def myprofile(): return dict(form=auth.profile())
...
``
To restrict access to functions to only logged in visitors, decorate the function as in the following example
``
@auth.requires_login()
def hello():
return dict(message='hello %(first_name)s' % auth.user)
``:code
Any function can be decorated, not just exposed actions. Of course this is still only a very simple example of access control. More complex examples will be discussed later.
``auth.user``:inxx ``auth.user_id``:inxx
-----
``auth.user`` contains a copy of the ``db.auth_user`` records for the current logged in user or ``None`` otherwise. There is also a ``auth.user_id`` which is the same as ``auth.user.id`` (i.e. the id of the current logger in user) or ``None``.
-----
``otherwise``:inxx
The ``auth.requires_login()`` decorator as well as the other ``auth.requires_*`` decorators take an optional ``otherwise`` argument. It can be set to a string where to redirect the user if registration files or to a callable object. It is called if registration fails.
#### Restrictions on registration
If you want to allow visitors to register but not to log in until registration has been approved by the administrator:
``
auth.settings.registration_requires_approval = True
``:code
You can approve a registration via the appadmin interface. Look into the table ``auth_user``. Pending registrations have a ``registration_key`` field set to "pending". A registration is approved when this field is set to blank.
Via the appadmin interface, you can also block a user from logging in. Locate the user in the table ``auth_user`` and set the ``registration_key`` to "blocked". "blocked" users are not allowed to log in. Notice that this will prevent a visitor from logging in but it will not force a visitor who is already logged in to log out. The word "disabled" may be used instead of "blocked" if preferred, with exactly the same behavior.
You can also block access to the "register" page completely with this statement:
``
auth.settings.actions_disabled.append('register')
curl -d "firstName=John&lastName=Smith" -G -v --key private.key \
This works out of the box with Rocket (the web2py built-in web server) but you may need some extra configuration work on the web server side if you are using a different web server. In particular you need to tell your web server where the certificates are located on local host and that it needs to verify certificates coming from the clients. How to do it is web server dependent and therefore omitted here.
##### Multiple login forms
Some login methods modify the login_form, some do not. When they do that, they may not be able to coexist. Yet some coexist by providing multiple login forms in the same page. web2py provides a way to do it. Here is an example mixing normal login (auth) and RPX login (janrain.com):
``
from gluon.contrib.login_methods.extended_login_form import ExtendedLoginForm
other_form = RPXAccount(request, api_key='...', domain='...', url='...')
auth.settings.login_form = ExtendedLoginForm(auth, other_form, signals=['token'])
``:code
If signals are set and a parameter in request matches any signals,
it will return the call of ``other_form.login_form`` instead.
``other_form`` can handle some particular situations, for example,
multiple steps of OpenID login inside ``other_form.login_form``.
Otherwise it will render the normal login form together with the ``other_form``.
### ``Mail`` and ``Auth``
One can define a mailer with
``
from gluon.tools import Mail
mail = Mail()
mail.settings.server = 'smtp.example.com:25'
mail.settings.sender = 'you@example.com'
mail.settings.login = 'username:password'
``
or simply use the mailer provided by ``auth``:
``
mail = auth.settings.mailer
mail.settings.server = 'smtp.example.com:25'
mail.settings.sender = 'you@example.com'
mail.settings.login = 'username:password'
To enable email, append the following lines in the model where ``auth`` is defin
``
auth.settings.registration_requires_verification = True
auth.settings.registration_requires_approval = False
auth.settings.reset_password_requires_verification = True
auth.messages.verify_email = 'Click on the link http://' + \
request.env.http_host + \
URL(r=request,c='default',f='user',args=['verify_email']) + \
'/%(key)s to verify your email'
auth.messages.reset_password = 'Click on the link http://' + \
request.env.http_host + \
URL(r=request,c='default',f='user',args=['reset_password']) + \
'/%(key)s to reset your password'
``:code
In the two ``auth.messages`` above, you may need to replace the URL portion of the string with the proper complete URL of the action. This is necessary because web2py may be installed behind a proxy, and it cannot determine its own public URLs with absolute certainty. The above examples (which are the default values) should, however, work in most cases.
### Authorization
Once a new user is registered, a new group is created to contain the user. The role of the new user is conventionally "user_[id]" where [id] is the id of the newly created user. The creation of the group can be disabled with
``
auth.settings.create_user_groups = False
``:code
-although we do not suggest doing so.
Users have membership in groups. Each group is identified by a name/role. Groups have permissions. Users have permissions because of the groups they belong to.

+The condition argument of ``@auth.requires(condition)`` can be a callable and unless the condition is simple, it better to pass a callable than a condition since this will be faster, as the condition will only be evaluated if needed. For example
+
+``
+@auth.requires(lambda: check_condition())
+def action():
+ ....
+``:code
+
+``@auth.requires`` also takes an optional argument ``requires_login`` which defaults to ``True``. If set to False, it does not require login before evaluating the condition as true/false. The condition can be a boolean value or a function evaluating to boolean.
-The condition argument of ``@auth.requires(condition)`` can be a callable. ``@auth.requires`` also takes an optional argument ``requires_login`` which defaults to ``True``. If set to False, it does not require login before evaluating the condition as true/false. The condition can be a boolean value or a function evaluating to boolean.

-------
The ``password`` field of the ``db.auth_user`` table defaults to a ``CRYPT`` validator, which needs and ``hmac_key``. On legacy web2py applications you may see an extra argument passed to the Auth constructor: ``hmac_key = Auth.get_or_create_key()``. The latter is a function that read the hmac kay from a file "private/auth.key" within the application folder. If the file does not exist it creates a random ``hmac_key``. If multiple apps share the same auth database, make sure they also use the same ``hmac_key``. This is no loger necessary for new applications since passwords are salted with an individual random salt.
-------
By default, web2py uses email for login. If instead you want to log in using username set ``auth.define_tables(username=True)``
If multiple apps share the same auth database you may want to disable migrations: ``auth.define_tables(migrate=False)``.
To expose **Auth**, you also need the following function in a controller (for example in "default.py"):
``
def user(): return dict(form=auth())
``:code
-------
The ``auth`` object and the ``user`` action are already defined in the
scaffolding application.
-------
web2py also includes a sample view "welcome/views/default/user.html" to render this function properly that looks like this:
``
{{extend 'layout.html'}}
<h2>{{=T( request.args(0).replace('_',' ').capitalize() )}}</h2>
The call to
auth.define_tables()
``:code
defines all **Auth** tables that have not been defined already. This means that if you wish to do so, you can define your own ``auth_user`` table.
There are a number of ways to customize auth. The simplest way is to add extra fields:
``
## after auth = Auth(db)
auth.settings.extra_fields['auth_user']= [
Field('address'),
Field('city'),
Field('zip'),
Field('phone')]
## before auth.define_tables(username=True)
``
You can declare extra fields not just for table "auth_user" but also for other "auth_" tables.
Using ``extra_fields`` is the recommended way as it will not break any internal mechanism.
Another way to do this (for experts!) consists of defining your auth tables yourself. If a table is declared before ``auth.define_tables()`` it is used instead of the default one. Here is how to do it:
``
## after auth = Auth(db)
db.define_table(
auth.settings.table_user_name,
Field('first_name', length=128, default=''),
Field('last_name', length=128, default=''),
Field('email', length=128, default='', unique=True), # required
Field('password', 'password', length=512, # required
readable=False, label='Password'),
Field('address'),
Field('city'),
Field('zip'),
Field('phone'),
Field('registration_key', length=512, # required
writable=False, readable=False, default=''),
Field('reset_password_key', length=512, # required
writable=False, readable=False, default=''),
Field('registration_id', length=512, # required
writable=False, readable=False, default=''))
auth.settings.login_form=LinkedInAccount(request,KEY,SECRET,RETURN_URL)
``:code
``LinkedInAccount`` requires the "python-linkedin" module installed separately.
##### X509
You can also login by passing to the page an x509 certificate and your credential will be extracted from the certificate. This requires ``M2Crypto`` installed from
``
http://chandlerproject.org/bin/view/Projects/MeTooCrypto
``
Once you have M2Cryption installed you can do:
``
from gluon.contrib.login_methods.x509_auth import X509Account
auth.settings.actions_disabled=['register','change_password','request_reset_password']
auth.settings.login_form = X509Account()
``:code
You can now authenticate into web2py passing your x509 certificate. How to do this is browser-dependent, but probably you are more likely to use certificates for web services. In this case you can use for example ``cURL`` to try out your authentication:
-------
The ``password`` field of the ``db.auth_user`` table defaults to a ``CRYPT`` validator, which needs and ``hmac_key``. On legacy web2py applications you may see an extra argument passed to the Auth contructor: ``hmac_key = Auth.get_or_create_key()``. The latter is a function that read the hmac kay from a file "private/auth.key" within the application folder. If the file does not exist it creates a random ``hmac_key``. If multiple apps share the same auth database, make sure they also use the same ``hmac_key``. This is no loger necessary for new applications since passwords are salted with an individual random salt.
-------
By default, web2py uses email for login. If instead you want to log in using username set ``auth.define_tables(username=True)``
If multiple apps share the same auth database you may want to disable migrations: ``auth.define_tables(migrate=False)``.
To expose **Auth**, you also need the following function in a controller (for example in "default.py"):
``
def user(): return dict(form=auth())
``:code
-------
The ``auth`` object and the ``user`` action are already defined in the
scaffolding application.
-------
web2py also includes a sample view "welcome/views/default/user.html" to render this function properly that looks like this:
``
{{extend 'layout.html'}}
<h2>{{=T( request.args(0).replace('_',' ').capitalize() )}}</h2>
The call to
auth.define_tables()
``:code
defines all **Auth** tables that have not been defined already. This means that if you wish to do so, you can define your own ``auth_user`` table.
There are a number of ways to customize auth. The simplest way is to add extra fields:
``
## after auth = Auth(db)
auth.settings.extra_fields['auth_user']= [
Field('address'),
Field('city'),
Field('zip'),
Field('phone')]
## before auth.define_tables(username=True)
``
You can declare extra fields not just for table "auth_user" but also for other "auth_" tables.
Using ``extra_fields`` is the recommended way as it will not break any internal mechanism.
Another way to do (for experts!) consists of defining your auth tables youself. If a table is declared before ``auth.define_tables()`` it is used instead of the default one. Here is how to do it:
``
## after auth = Auth(db)
db.define_table(
auth.settings.table_user_name,
Field('first_name', length=128, default=''),
Field('last_name', length=128, default=''),
Field('email', length=128, default='', unique=True), # required
Field('password', 'password', length=512, # required
readable=False, label='Password'),
Field('address'),
Field('city'),
Field('zip'),
Field('phone'),
Field('registration_key', length=512, # required
writable=False, readable=False, default=''),
Field('reset_password_key', length=512, # required
writable=False, readable=False, default=''),
Field('registration_id', length=512, # required
writable=False, readable=False, default=''))
auth.settings.login_form=LinkedInAccount(request,KEY,SECRET,RETURN_URL)
``:code
``LinkedInAccount`` requires the "python-linkedin" module installed separately.
##### X509
You can also login by passing to the page an x509 certificate and your credential will be extracted from the certificate. This requires ``M2Crypto`` installed from
``
http://chandlerproject.org/bin/view/Projects/MeTooCrypto
``
Once you have M2Cryption installed you can do:
``
from gluon.contrib.login_methods.x509_auth import X509Account
auth.settings.actions_disabled=['register','change_password','request_reset_password']
auth.settings.login_form = X509Account()
``:code
You can now authenticate into web2py passing your x509 certificate. How to do this is browser dependant but probably you are more likely to use certificates for web services. In this case you can use for example ``cURL`` to try out your authentication:

To start using ``Auth``, you need at least this code in a model file, which is also provided with the web2py "welcome" application and assumes a ``db`` connection object:
``
from gluon.tools import Auth
auth = Auth(db)
auth.define_tables()
``:code
-------
The ``password`` field of the ``db.auth_user`` table defaults to a ``CRYPT`` validator, which needs and ``hmac_key``. On legacy web2py applications you may see an extra argument passed to the Auth contructor: ``hmac_key = Auth.get_or_create_key()``. The latter is a function that read the hmac kay from a file "private/auth.key" within the application folder. If the file does not exist it creates a random ``hmac_key``. If multiple apps share the same auth database, make sure they also use the same ``hmac_key``. This is no loger necessary for new applications since passwords are salted with an individual random salt.
-------
By default, web2py uses email for login. If instead you want to log in using username set ``auth.define_tables(username=True)``
If multiple apps share the same auth database you may want to disable migrations: ``auth.define_tables(migrate=False)``.
To expose **Auth**, you also need the following function in a controller (for example in "default.py"):
``
def user(): return dict(form=auth())
``:code
-------
The ``auth`` object and the ``user`` action are already defined in the
scaffolding application.
-------
web2py also includes a sample view "welcome/views/default/user.html" to render this function properly that looks like this:
``
{{extend 'layout.html'}}
<h2>{{=T( request.args(0).replace('_',' ').capitalize() )}}</h2>
All of the methods above can be used in separate actions. For example:
def mylogin(): return dict(form=auth.login())
def myregister(): return dict(form=auth.register())
def myprofile(): return dict(form=auth.profile())
...
``
To restrict access to functions to only logged in visitors, decorate the function as in the following example
``
@auth.requires_login()
def hello():
return dict(message='hello %(first_name)s' % auth.user)
``:code
Any function can be decorated, not just exposed actions. Of course this is still only a very simple example of access control. More complex examples will be discussed later.
``auth.user``:inxx ``auth.user_id``:inxx
-----
``auth.user`` contains a copy of the ``db.auth_user`` records for the current logged in user or ``None`` otherwise. There is also a ``auth.user_id`` which is the same as ``auth.user.id`` (i.e. the id of the current logger in user) or ``None``.
-----
+``otherwise``:inxx
+
+The ``auth.requires_login()`` decorator as well as the other ``auth.requires_*`` decorators take an optional ``otherwise`` argument. It can be set to a string where to redirect the user if registration files or to a callable object. It is called if registration fails.
+
#### Restrictions on registration
To start using ``Auth``, you need at least this code in a model file, which is also provided with the web2py "welcome" application and assumes a ``db`` connection object:
``
from gluon.tools import Auth
auth = Auth(db, hmac_key=Auth.get_or_create_key())
auth.define_tables()
``:code
-------
The ``password`` field of the ``db.auth_user`` table defaults to a ``CRYPT`` validator, which needs and ``hmac_key``. The ``Auth.get_or_create_key()`` is a function that read the hmac kay from a file "private/auth.key" within the application folder. If the file does not exist it creates a random ``hmac_key``. If multiple apps share the same auth database, make sure they also use the same ``hmac_key``.
-------
By default, web2py uses email for login. If instead you want to log in using username set ``auth.define_tables(username=True)``
If multiple apps share the same auth database you may want to disable migrations: ``auth.define_tables(migrate=False)``.
To expose **Auth**, you also need the following function in a controller (for example in "default.py"):
``
def user(): return dict(form=auth())
``:code
-------
The ``auth`` object and the ``user`` action are already defined in the
scaffolding application.
-------
web2py also includes a sample view "welcome/views/default/user.html" to render this function properly that looks like this:
``
{{extend 'layout.html'}}
<h2>{{=T( request.args(0).replace('_',' ').capitalize() )}}</h2>
All of the methods above can be used in separate actions. For example:
def mylogin(): return dict(form=auth.login())
def myregister(): return dict(form=auth.register())
def myprofile(): return dict(form=auth.profile())
...
``
To restrict access to functions to only logged in visitors, decorate the function as in the following example
``
@auth.requires_login()
def hello():
return dict(message='hello %(first_name)s' % auth.user)
``:code
Any function can be decorated, not just exposed actions. Of course this is still only a very simple example of access control. More complex examples will be discussed later.
``auth.user``:inxx ``auth.user_id``:inxx
-----
``auth.user`` contains a copy of the ``db.auth_user`` records for the current logged in user or ``None`` otherwise. There is also a ``auth.user_id`` which is the same as ``auth.user.id`` (i.e. the id of the current logger in user) or ``None``.
-----
#### Restrictions on registration