-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256
> diff --git a/applications/welcome/controllers/default.py
b/applications/welcome/controllers/default.py
> index c775603..e99ef0f 100644
> --- a/applications/welcome/controllers/default.py
> +++ b/applications/welcome/controllers/default.py
> @@ -57,4 +57,10 @@ def call():
> """
> return service()
>
> [email protected]_membership('masters')
> +def master_zone():
> + return dict(a='Hello, Master', b=request.vars.message)
>
> +def get_master_code():
> + url = auth.get_authorization_url(a='welcome', c='default',
f='master_zone', vars=dict(message='Greetings'))
> + return dict(a = A('copy this link', _href=url))
> diff --git a/applications/welcome/languages/es.py
b/applications/welcome/languages/es.py
> index 7579cc3..54a57c6 100644
> --- a/applications/welcome/languages/es.py
> +++ b/applications/welcome/languages/es.py
> @@ -55,6 +55,7 @@
> 'Available Databases and Tables': 'Bases de datos y tablas disponibles',
> 'Back': 'Atrás',
> 'Buy this book': 'Compra este libro',
> +"Buy web2py's book": "Buy web2py's book",
> 'Cache': 'Caché',
> 'cache': 'caché',
> 'Cache Keys': 'Llaves de la Caché',
> @@ -83,6 +84,7 @@
> 'compile': 'compilar',
> 'compiled application removed': 'aplicación compilada eliminada',
> 'Components and Plugins': 'Componentes y Plugins',
> +'Config.ini': 'Config.ini',
> 'contains': 'contiene',
> 'Controller': 'Controlador',
> 'Controllers': 'Controladores',
> @@ -119,6 +121,7 @@
> 'Description': 'Descripción',
> 'design': 'diseño',
> 'DESIGN': 'DISEÑO',
> +'Design': 'Design',
> 'Design for': 'Diseño por',
> 'detecting': 'detectando',
> 'DISK': 'DISCO',
> @@ -145,6 +148,7 @@
> 'End of impersonation': 'Fin de suplantación',
> 'enter a number between %(min)g and %(max)g': 'introduzca un número
entre %(min)g y %(max)g',
> 'enter a value': 'introduzca un valor',
> +'Enter an integer between %(min)g and %(max)g': 'Enter an integer
between %(min)g and %(max)g',
> 'enter an integer between %(min)g and %(max)g': 'introduzca un entero
entre %(min)g y %(max)g',
> 'enter date and time as %(format)s': 'introduzca fecha y hora como
%(format)s',
> 'Error logs for "%(app)s"': 'Bitácora de errores en "%(app)s"',
> @@ -177,6 +181,7 @@
> 'Groups': 'Grupos',
> 'Hello World': 'Hola Mundo',
> 'help': 'ayuda',
> +'Helping web2py': 'Helping web2py',
> 'Home': 'Inicio',
> 'How did you get here?': '¿Cómo llegaste aquí?',
> 'htmledit': 'htmledit',
> @@ -217,6 +222,7 @@
> 'License for': 'Licencia para',
> 'Live Chat': 'Chat en vivo',
> 'loading...': 'cargando...',
> +'Log In': 'Log In',
> 'Logged in': 'Sesión iniciada',
> 'Logged out': 'Sesión finalizada',
> 'Login': 'Inicio de sesión',
> @@ -256,6 +262,7 @@
> 'not in': 'no en',
> 'Object or table name': 'Nombre del objeto o tabla',
> 'Old password': 'Contraseña vieja',
> +'Online book': 'Online book',
> 'Online examples': 'Ejemplos en línea',
> 'Or': 'O',
> 'or import from csv file': 'o importar desde archivo CSV',
> @@ -319,6 +326,7 @@
> 'Services': 'Servicios',
> 'session expired': 'sesión expirada',
> 'shell': 'terminal',
> +'Sign Up': 'Sign Up',
> 'site': 'sitio',
> 'Size of cache:': 'Tamaño de la Caché:',
> 'some files could not be removed': 'algunos archivos no pudieron ser
removidos',
> diff --git a/applications/welcome/models/db.py
b/applications/welcome/models/db.py
> index 606dc6f..3438621 100644
> --- a/applications/welcome/models/db.py
> +++ b/applications/welcome/models/db.py
> @@ -8,6 +8,7 @@
> ## if SSL/HTTPS is properly configured and you want all HTTP requests to
> ## be redirected to HTTPS, uncomment the line below:
> # request.requires_https()
> +import random
>
> ## app configuration made easy. Look inside private/appconfig.ini
> from gluon.contrib.appconfig import AppConfig
> @@ -71,6 +72,8 @@ auth.settings.registration_requires_verification = False
> auth.settings.registration_requires_approval = False
> auth.settings.reset_password_requires_verification = True
>
> +auth.settings.jwt_secret = myconf.take('auth.jwt_secret')
> +
> #########################################################################
> ## Define your tables below (or better in another model file) for example
> ##
> diff --git a/applications/welcome/private/appconfig.ini
b/applications/welcome/private/appconfig.ini
> index f45efbf..6db7544 100644
> --- a/applications/welcome/private/appconfig.ini
> +++ b/applications/welcome/private/appconfig.ini
> @@ -8,7 +8,7 @@ pool_size = 1
>
> ; smtp address and credentials
> [smtp]
> -server = smtp.gmail.com:587
> +server = logging
> sender = [email protected]
> login = username:password
>
> @@ -16,4 +16,7 @@ login = username:password
> ; form styling
> [forms]
> formstyle = bootstrap3_inline
> -separator =
> \ No newline at end of file
> +separator =
> +
> +[auth]
> +jwt_secret = very_secret_even_random
> diff --git a/gluon/tools.py b/gluon/tools.py
> index 9d90b9a..da18795 100644
> --- a/gluon/tools.py
> +++ b/gluon/tools.py
> @@ -1171,6 +1171,8 @@ class Auth(object):
> remember_me_form=True,
> allow_basic_login=False,
> allow_basic_login_only=False,
> + jwt_algorithm='HS512',
> + jwt_secret='',
> on_failed_authentication=lambda x: redirect(x),
> formstyle=None,
> label_separator=None,
> @@ -3724,6 +3726,16 @@ class Auth(object):
> raise HTTP(403, 'ACCESS DENIED')
> return self.messages.access_denied
>
> + def get_authorization_url(self, a, c, f, vars):
> + keycode = self.get_authorization_code(a, c, f, vars)
> + return URL(a=a, c=c, f=f, vars=dict(_keycode=keycode))
> +
> + def get_authorization_code(self, a, c, f, vars):
> + import jwt
> + payload = {'_application':a, '_controller':c, '_function':f}
> + payload.update(vars)
> + return jwt.encode(payload, self.settings.jwt_secret,
algorithm=self.settings.jwt_algorithm)
> +
> def requires(self, condition, requires_login=True, otherwise=None):
> """
> Decorator that prevents access to action if not logged in
> @@ -3732,27 +3744,47 @@ class Auth(object):
> def decorator(action):
>
> def f(*a, **b):
> + r = current.request
>
> basic_allowed, basic_accepted, user = self.basic()
> user = user or self.user
> - if requires_login:
> +
> + authorization_failed = False
> + if self.settings.jwt_secret and r.vars._keycode:
> + import jwt
> + try:
> + encoded = r.vars._keycode
> + payload = jwt.decode(encoded,
self.settings.jwt_secret, algorithms=[self.settings.jwt_algorithm])
> + except (jwt.DecodeError, jwt.InvalidTokenError):
> + authorization_failed = True
> + if not authorization_failed:
> + acf = tuple(payload.pop(s) for s in
('_application', '_controller', '_function'))
> + if acf != (r.application, r.controller,
r.function):
> + authorization_failed = True
> + r.vars.clear()
> + r.vars.update(payload)
> + condition = True
> + elif requires_login:
> if not user:
> - if current.request.ajax:
> - raise HTTP(401,
self.messages.ajax_failed_authentication)
> - elif not otherwise is None:
> - if callable(otherwise):
> - return otherwise()
> - redirect(otherwise)
> - elif self.settings.allow_basic_login_only or \
> - basic_accepted or
current.request.is_restful:
> - raise HTTP(403, "Not authorized")
> - else:
> - next = self.here()
> - current.session.flash =
current.response.flash
> - return call_or_redirect(
> - self.settings.on_failed_authentication,
> - self.settings.login_url +
> - '?_next=' + urllib.quote(next))
> + authorization_failed = True
> +
> + if authorization_failed:
> + if r.ajax:
> + raise HTTP(401,
self.messages.ajax_failed_authentication)
> + elif not otherwise is None:
> + if callable(otherwise):
> + return otherwise()
> + redirect(otherwise)
> + elif self.settings.allow_basic_login_only or \
> + basic_accepted or r.is_restful:
> + raise HTTP(403, "Not authorized")
> + else:
> + next = self.here()
> + current.session.flash = current.response.flash
> + return call_or_redirect(
> + self.settings.on_failed_authentication,
> + self.settings.login_url +
> + '?_next=' + urllib.quote(next))
>
> if callable(condition):
> flag = condition()
> def get_master_code():
> url = auth.get_authorization_url(a='welcome', c='default',
f='master_zone', vars=dict(message='Greetings'))
> return dict(a = A('copy this link', _href=url))
users of that link will be automatically granted access to that a/c/f
and with that vars.
@auth.requires_membership('masters')
def master_zone():
return dict(a='Hello, Master', b=request.vars.message)
With small changes, this can also be used to authenticate (if
payload['_user']: ...)
> Can you elaborate. I like the current system (I wrote it ;-) but I was
> considering adding jwt. The
question is, is there duplication of functionality? Should jwt replace
the current token system? pros/cons?
jwt can be used for much more stuff. A standard example: in a
dropbox/seafile/etc clone, you set permissions for each file and folder,
but then it's pretty simple to share links for downloading individual files.
I have written a few lines with my proposal, just to give you an idea.
In appconfig.ini:
auth.jwt_secret='secret_password'
Then you can share a link for a page with
El 10/07/15 a las 07:45, Massimo Di Pierro escribió:
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2
iQIcBAEBCAAGBQJVn4WiAAoJEATsOw+FDrzIHC0P/38vidSs1hMsu3PaJWaGLuDZ
XMDp+UoVgWZmRw7enhvHHhdRxzyT8LGt8d4QmjYpOzbNyhij4wZOuWEBV5f/rUW7
zNfkjow8AYPz/C13yNUaCCmpxHb7g3gqCsOBM4fZkQ+5mu8ZY4Kua73jFPABXfu/
HNVb65N89HBZiwolBr8kYTWNscnx3J2RaHnhz3+smwkBu08cf58JpaAnUHeqpQDd
55gHjfyQR7uXV/9z3RHTt2cEoqr3Wp3097GUC7p8P0zNPWqfXI7eltr0igTXuIaG
3Lzya8UIs1972LowtoUF/ek0Kx2DaFoYIZEH5RdnMU6e6XSw4qL3xW/zqkiBepe+
DES3WEbPvNztqnJV3rmb9Jw0O+wLge0vI2Ax/VIrkhVBjxkBBOJ6roXQxQaABarg
z8HJHeLpdErnTLhK/oQG8xRxPFbQVRenCDksVSxlqejnz9C9mJq4KNz3Kn7Mk0sU
OuB+Q0KfYw4SSX1HiyhZmrdEiYeCVhQxj25qgegNByd4JTGry01jaBJFV7Vpj6qb
K3JroPb9T+dBJLTo9xhW40fYCg6rOV2bMnlqLqQGJK3HZKFbyAvPjUTWhxJsAMLN
0d7XmAe2PAw8Pj2Vsejp4iPtIcH8vTWE6AiGjf/lgYI6cWEVUf02TUwM26vaE9j1
6a7TnMCb8Bg4Ga5PcOkp
=Ed6b
-----END PGP SIGNATURE-----
--
Resources:
- http://web2py.com
- http://web2py.com/book (Documentation)
- http://github.com/web2py/web2py (Source code)
- https://code.google.com/p/web2py/issues/list (Report Issues)
---
You received this message because you are subscribed to the Google Groups
"web2py-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.