federicoceratto / bottle-cork Goto Github PK
View Code? Open in Web Editor NEWAuthentication module for the Bottle and Flask web frameworks
Home Page: https://cork.readthedocs.io/en/latest/
License: GNU Lesser General Public License v3.0
Authentication module for the Bottle and Flask web frameworks
Home Page: https://cork.readthedocs.io/en/latest/
License: GNU Lesser General Public License v3.0
I'm using the default json backend and expect that I don't need to use pymongo or sqlalchemy (although in fact I will later be using sqlalchemy). When importing from backends all the different backends are made available. If you don't have pymongo installed it ought to do nothing and the module should not be available. I see you have some code for that already but it isn't hooked up. Can you please fix this? Thanks.
Related to #15
"The dependencies in setup.py were not being processed if beaker package was not already installed.
This was because setup.py depended on cork. Hence, when running pip, a compile of cork was initiated which failed because beaker package was not present."
Getting The PBKDF2 hash is not 32bytes long
when running the example recreate_example_conf.py script.
The mailer included is not configurable.
When attempting to use GMail smtp, I get SMTPSenderRefused, and Must issue a STARTTLS command first.
I patched this for my own use as follows:
session.ehlo()
session.starttls() # needed
session.ehlo()
session.login("[email protected]", "XXXXX")
It would be nice if the mailer could be more configurable.
It would be great to have a backend for Riak. As far as I could tell, It would be really similar to the mongodb backend
The following will fail because the initialisation doesn't add the "user" role.
aaa = Cork(config['auth_dir'], initialize=True)
aaa.register(...)
Code also cannot add the "user" role using aaa.create_role() because that call requires an authenticated user with a role level 100. Such a role obviously doesn't exist at this point, and no user exists because I can't register (or create_user.)
I used the included example, simple_webapp.py to register a user, but i never received the emails
When adding or deleting a user or a role from the sample application "admin" page, the change gets written to the relevant json file when the submit button is clicked, but reloading the admin page alternates between the state prior to the change and the state after the change.
Exposing _refresh() from json_backend.py and calling it upon entry in list_roles and list_users fixes things for me.
is there any ldap backend for Cork? if not any plans to add the same?
in cork.py https://github.com/FedericoCeratto/bottle-cork/blob/master/cork/cork.py#L798
the port is missing.
It should read this,
session = SMTP(self._conf['fqdn'], self._conf['port'])
also in the line above it.
Nice code!
Please provide a simple API mechanism for detecting that there is no user logged in. The current method, as far as I can tell, is to try to access the .current_user attribute and handle the exception raised if there is no current user.
In OpenShift, the standard way to login to MongoDB is with environment variables:
dbname = 'mydbname'
connection = pymongo.MongoClient(os.environ['OPENSHIFT_MONGODB_DB_URL'])
db = connection[dbname]
The environment variable OPENSHIFT_MONGODB_DB_URL
consists of:
OPENSHIFT_MONGODB_DB_URL=mongodb://admin:[email protected]:27017/
You can also access these environment variables which are self explanatory:
OPENSHIFT_MONGODB_DB_USERNAME
OPENSHIFT_MONGODB_DB_PASSWORD
OPENSHIFT_MONGODB_DB_HOST
OPENSHIFT_MONGODB_DB_PORT
But in any case, in OpenShift, you have to provide a password to access MongoDB.
I am editing mongodb_backend.py
so that it can connect to the database at line 138:
class MongoDBBackend(Backend):
def __init__(self, db_name='cork', hostname='localhost', port=27017, initialize=False):
"""Initialize MongoDB Backend"""
connection = MongoClient(host=hostname, port=port)
db = connection[db_name]
How can I add a password
parameter to this class?
(I am a bit of a newb with this, and trying to document my process as I go on the wiki so simple information appreciated if possible - thanks!)
Atm it's possible to create a new user with an empty string as username.
hey, would you be open to code submission for a two-legged OAuth authentication addition to cork? I think the only 'outside' library (other than bottle) is oauth2. I'm working on two-legged oauth now, but was considering incorporating it into cork...
cheers
simple_webapp_using_mongodb.py starts with a function:
populate_mongodb_backend()
I understand that it populates the database with:
admin
user to users
collectionadmin
, editor
and user
roles to roles
collectionbut I ran my app containing this function once and it went through fine, I ran it again and I got:
pymongo.errors.DuplicateKeyError: E11000 duplicate key error index: cork-example
.users.$login_1 dup key: { : "admin" }
I understand the error, that there is a duplicate, but I don't understand why the function is included like that - is it intended to run every time the program is run?
Or is it intended to just be run once and then commented out?
I don't think I could do the latter as it is intertwined with the next part of the code:
mb = populate_mongodb_backend()
aaa = Cork(backend=mb, email_sender='[email protected]', smtp_url='smtp://smtp.magnet.ie')
and aaa
is then used frequently thoughout the rest of the code.
I'm able to run the example application OK including sending email. One problem though when a port other than 25 is used it doesn't work. For example this works (default port 25 no authentication):
aaa = Cork('example_conf', email_sender='[email protected]', smtp_url='smtp://192.168.0.5')
But this doesn't (port 465 w/ authentication):
aaa = Cork('example_conf', email_sender='[email protected]', smtp_url="smtp://email.net:465/novalidate-cert/user=[email protected]")
I traced the problem to smtplib.py by adding the "debug = 1" command and it shows that smtplib.py is trying to connect to email.net on port 25 even though port 465 is designated in Cork, so it times out since port 25 is not operative. Also smtplib.py is not showing authentication information. I know the above smtp URL works as I tested in a different application and made sure firewalls are turned off etc.. here's the output with port set to 465 as above:
shuttle:[/home/stbalbach/python] python b2.py
Bottle v0.12.7 server starting up (using WSGIRefServer())...
Listening on http://127.0.0.1:8080/
Hit Ctrl-C to quit.
127.0.0.1 - - [18/May/2014 20:14:30] "GET /login HTTP/1.1" 200 1913
localhost - - [2014-05-18 20:14:46,197] Sending email using email.net
connect: ('email.net', 25)
connect: (25, 'email.net')
127.0.0.1 - - [18/May/2014 20:14:46] "POST /register HTTP/1.1" 200 26
localhost - - [2014-05-18 20:15:07,713] Error sending email: [Errno 116] Connection timed out
Traceback (most recent call last):
File "build/bdist.cygwin-1.7.29-i686/egg/cork/cork.py", line 847, in _send
session = SMTP(self._conf['fqdn'])
File "/usr/lib/python2.7/smtplib.py", line 249, in init
(code, msg) = self.connect(host, port)
File "/usr/lib/python2.7/smtplib.py", line 310, in connect
self.sock = self._get_socket(host, port, self.timeout)
File "/usr/lib/python2.7/smtplib.py", line 285, in _get_socket
return socket.create_connection((port, host), timeout)
File "/usr/lib/python2.7/socket.py", line 571, in create_connection
raise err
error: [Errno 116] Connection timed out
I've tried many variations on the smtp_url string, and a different SMTP provider that uses port 26 so it's nothing specific to SSL (port 465).
Cfg is Python 2.7.3 w/ latest Bottle and Cork on Cygwin/Windows 7.
Thanks,
Stephen
Using example file simple_webapp.py, works on system using python. Testing
maybe a beaker issue ??
ERROR
(venv)notroot@ubuntu:~/hellobottle$ foreman start
| started with pid 3196
| Bottle v0.11.4 server starting up (using WSGIRefServer())...
| Listening on http://0.0.0.0:5000/
| Hit Ctrl-C to quit.
| Traceback (most recent call last):
| File "/usr/local/lib/python2.7/dist-packages/bottle-0.11.4-py2.7.egg/bottle.py", line 763, in _handle
| return route.call(*_args)
| File "/usr/local/lib/python2.7/dist-packages/bottle-0.11.4-py2.7.egg/bottle.py", line 1572, in wrapper
| rv = callback(_a, **ka)
| File "corktest.py", line 81, in index
| aaa.require(fail_redirect='/login')
| File "/usr/local/lib/python2.7/dist-packages/cork/cork.py", line 259, in require
| cu = self.current_user
| File "/usr/local/lib/python2.7/dist-packages/cork/cork.py", line 409, in current_user
| username = session.get('username', None)
| AttributeError: 'NoneType' object has no attribute 'get'
hey.
I'm new to all of this; I usually just use the tools provided by awesome ppl like you, so I'm not sure how relevant this is.
As part of a project I am working on your library was included, and there was no problem on 32bit python2.7 version at work. But at home I'm using a 64bit one and I kept getting
"RuntimeError("The PBKDF2 hash is not 32 bytes long. The pycrypto library might be missing.")".
I looked around a bit and figured the problem was the hash was too long, not to short, so I shortened it. It works (apparently) flawlessly now. Since couple of ppl on the same project had this problem, and didn't find any solution on the internet, I thought I might mention this here.
There is a typo in the User.update() function (line 717 in my copy):
if email_addr is not None:
self._cork._store.users[username]['email'] = email_addr
Should be 'email_addr' not 'email'.
after (successfully) installing bottle-cork (using python 64-bit, version 2.7.3rc2), importing the module doesn't work.
steps to reproduce:
The error 'ImportError: No module named cork' is displayed.
In the sqlalchemy backend (line 155), the table definition sais
Column('username', String(128), primary_key=True),
I was wondering if it would make sense to use a numerical value, for example an auto-incrementing integer as the primary key, especially in scenarios where there are resources "belonging" to a user, in a sense that a user reference is part of another database record?
I would imagine that using the user name as a foreign key there could possibly increase the size of the data, add unnecessary redundancy, and be costly in joins.
For example, I have an application where there are "projects" that are created by a user, and have access lists allowing other users access to the project data as well. The project database is file based sqlite, using sqlalchemy, and thus lives in a different database context than the user database. I doubt that sqlite is smart enough to optimize that in a way that would be equivalent to numerical foreign key relations.
Thanks!
Andy
For db_full_url like 'postgresql://user:password@localhost/database', initialization will fail.
if initialize:
# Create new database if needed.
db_url, db_name = db_full_url.rsplit('/', 1)
self._engine = create_engine(db_url)
try:
self._engine.execute("CREATE DATABASE %s" % db_name)
except Exception, e:
log.info("Failed DB creation: %s" % e)
# SQLite in-memory database URL: "sqlite://:memory:"
if db_name != ':memory:':
self._engine.execute("USE %s" % db_name)
your mailer can be reused and thus is it possible to have the possibility to send emails to more then one recipient?
def send_email(self, email_addr, subject, email_text):
if type(email_addr) is list:
email_to = ", ".join(list)
else:
email_to = email_addr
I don't know if this is the right or wrong way to use sqlite with cork. But it looks like it will cause a thread releated error. I am unsure how to fix it though.
#!/usr/bin/python2.7
import bottle
from bottle_sqlite import SQLitePlugin
import sqlite3
# -------------------------------------------------
# Cork imports
# systemundertest = True
import cork
from beaker.middleware import SessionMiddleware
from cork.backends import SQLiteBackend
class mysqlitebackend( SQLiteBackend ):
@property
def connection(self):
try:
return self._connection
except AttributeError:
import sqlite3
# Set isolation_level to None so that we would have auto commit
#
self._connection = sqlite3.connect(self._filename, isolation_level = None)
return self._connection
aaa = cork.Cork( backend=mysqlitebackend('web.db'),
email_sender="Auth@localhost",
smtp_url="smtp://localhost:8800")
@bottle.route('/')
def root():
return "hello world <a href='/userarea'>go to fail</a>"
@bottle.get("/userarea")
def admin_userarea():
# should fail on this command ...
#
aaa.require(role="admin",fail_redirect="/")
return "my bad, everything is fine."
def main():
# Session Options for Beaker Session Cookie
session_opts = {
'session.cookie_expires': True,
'session.encrypt_key': 'please use a random key and keep it secret!',
'session.httponly': True,
'session.timeout': 3600 * 24, # 1 day
'session.type': 'cookie',
'session.validate_key': True,
}
app = SessionMiddleware(bottle.default_app(), session_opts)
bottle.run(debug=True, app=app, host='127.0.0.1', port=9999, server="paste" )
main()
Inside Cork.py script, when a User() is created, it validates for the "_id" in this line:
if session is not None:
try:
self.session_creation_time = session['_creation_time']
self.session_accessed_time = session['_accessed_time']
self.session_id = session['_id']
except:
pass
session['_id'] is not there, I see the username in the session instead of the _id, and I want that _id for making some DBRef on my collections.
Looking at the code for Cork.py and mongodb_backend.py I don't see anything storing the _id in the session.
Is this a bug or missing implementation?
I can make my own query and ask for the _id using the username, buy it's not very effective.
Thanks
At the moment Cork exclusively uses JsonBackend
to store its information and relies on several methods of this backend. Additionally, customizing the JSON backend is difficult because although the filenames can be passed to Cork's constructor, the JSON backend is created with fixed filenames in the end.
I created a patch that allows filenames in the JsonBackend to be defined by the user, and that also tries to remove some of the json specific calls by Cork:
https://gist.github.com/4645162
In order to template the registration confirmation and password reset emails I need to pass in the URL to template into the email (as this changes depending by deployment.)
Please consider adding an additional argument to the register/send_password_reset_email APIs to allow supplying further templating parameters.
I can not install...
Cause did not know me.
$ easy_install bottle-cork
Searching for bottle-cork
Best match: bottle-cork 0.10
Adding bottle-cork 0.10 to easy-install.pth file
Using {PROJECT_DIR}/env/lib/python2.6/site-packages
Processing dependencies for bottle-cork
Searching for pycrypto
Reading https://pypi.python.org/simple/pycrypto/
Best match: pycrypto 2.6.1
Downloading https://pypi.python.org/packages/source/p/pycrypto/pycrypto-2.6.1.tar.gz#md5=55a61a054aa66812daf5161a0d5d7eda
Processing pycrypto-2.6.1.tar.gz
Writing /var/folders/10/1gcb6yqd4m14g9qr7s0lztg40000gn/T/easy_install-nfzUGL/pycrypto-2.6.1/setup.cfg
Running pycrypto-2.6.1/setup.py -q bdist_egg --dist-dir /var/folders/10/1gcb6yqd4m14g9qr7s0lztg40000gn/T/easy_install-nfzUGL/pycrypto-2.6.1/egg-dist-tmp-zB3OXU
warning: GMP or MPIR library not found; Not building Crypto.PublicKey._fastmath.
clang: error: unknown argument: '-mno-fused-madd' [-Wunused-command-line-argument-hard-error-in-future]
clang: note: this will be a hard error (cannot be downgraded to a warning) in the future
error: Setup script exited with error: command 'cc' failed with exit status 1
Hello,
I am trying to set up an app with:
There is code and instructions for how to set up 1 - 3 in the above list here:
https://github.com/oshihirii/Python2.7MongoBottle
I am trying to figure out how to add the following to my application:
from cork import Cork
from cork.backends import MongoDBBackend
I thought perhaps I could just add 5 files from the cork
folder from this repo ie:
__init__.py
,
backends.py
,
cork.py
,
json_backend.py
and
mongodb_backend.py
to the wsgi
folder on OpenShift, but that is just throwing a 500 error.
How do I add these modules to the app?
Thank You.
After installing with pip in a virtualenv and python 3.2.3, cork throws an error when importing:
In [1]: from cork import Cork
---------------------------------------------------------------------------
ImportError Traceback (most recent call last)
<ipython-input-1-f37d0de2d530> in <module>()
----> 1 from cork import Cork
/home/natano/src/bottle-cork/cork/__init__.py in <module>()
----> 1 from cork import Cork, AAAException, AuthException, Mailer
ImportError: cannot import name Cork
Replacing "from cork import ..." with "from cork.cork import ..." in cork/init.py seems to solve the problem.
Hi,
Have you thought about adding python method decorators for authentication (ala django)?
cheers
In application I tried:
aaa = Cork(backend=mb, email_sender='[email protected]', smtp_url='smtp.gmail.com')
and when registering I get the message returned in the browserPlease check your mailbox.
but I do not receive an email (the user is created in the pending_registrations
collection though).
A few posts I have seen show passwords and port numbers are required when using smtplib with gmail but these don't seem to be parameters in the Cork class:
http://www.mkyong.com/python/how-do-send-email-in-python-via-smtplib/
http://stackoverflow.com/questions/10147455/trying-to-send-email-gmail-as-mail-provider-using-python
http://stackoverflow.com/questions/2918282/emailing-smtp-with-python-error
http://www.nixtutor.com/linux/send-mail-through-gmail-with-python/
http://stackoverflow.com/questions/7846480/sending-email-using-smtplib
Perhaps the parameters are available as defined in _parse_smtp_url()
:
https://github.com/FedericoCeratto/bottle-cork/blob/master/cork/cork.py#L752
I can't figure out how to format the url with password and port though.
I tried:
smtp_url = "[email protected]:[email protected]:587"
and:
smtp_url = "just-the-username:[email protected]:587"
with:
aaa = Cork(backend=mb, email_sender='[email protected]', smtp_url=smtp_url)
and users were created but didn't receive registration mail.
Update:
I just saw this post:
https://groups.google.com/d/msg/cork-discuss/M12qV-Uyv0o/ECqD0UNzyAoJ
and tried the following variations:
smtp_url = "smtp://just-username:[email protected]:587"
smtp_url = "smtp://[email protected]:[email protected]:587"
smtp_url = "smtp://[email protected]:[email protected]:587"
smtp_url = "smtp://just-username:[email protected]:587"
result:
user added, no email sent.
I think there is a design issue here. the randomly generated user/password hash cannot be verified against the hash already in the store, it will never match.
the verification process is very wrong, if only the username is valid (eg. admin) then ANY password will grant you access.
MongoDBBackend is currently not usable by me because I use mongolab.com and they require that the 'pymongo.Connection' be authenticated.
Would love to use this functionality.
It would be nice to have a storage backend for Cork that uses an SQL database. In addition to the actual backend code some changes would be necessary to define the backend that should be used for Cork.
I implemented a very raw version of an SQL backend based on SQLAlchemy: https://gist.github.com/4651239. It's not optimized or well tested at the moment, but it works.
At the moment the implementation uses an additional layer (SqlRowProxy, SqlDict, and SqlColumnDict) to emulate Python dictionaries for Cork's users
, roles
, or pending_registrations
. The classes of this layer are used to translate dictionary access to SQLAlchemy calls.
Comments are very welcome.
for me importing cork fails when pymongo is not installed.
The port is properly parsed from the email_url, but then it's not used. AFAICT, there's really no way starttls would work without it. On my local site-packages version, I changed it to be:
if proto == 'ssl':
log.debug("Setting up SSL")
session = SMTP_SSL(self._conf['fqdn'], self._conf['port'])
else:
session = SMTP(self._conf['fqdn'], self._conf['port'])
Sorry I'm too busy to submit a proper patch.
Add support for MongoDB as a backend.
Scrypt is meant to be more secure than PBKDF2
Implement Scrypt based on https://pypi.python.org/pypi/scrypt/
In SQLite, the "CREATE DATABASE %s" and "USE %s" queries fail with syntax errors.
example:
SqlAlchemyBackend('sqlite:///' + absolute_path_to_dbfile, initialize=True)
fails with
sqlalchemy.exc.OperationalError: (OperationalError) unable to open database file None None
This is caused by sqlalchemy_backend.py:138, where db_url should be db_full_url.
Now the error is
localhost - - [2014-08-19 09:36:18,563] Failed DB creation: (OperationalError) near DATABASE": syntax error 'CREATE DATABASE auth.sqlite' ()
sqlalchemy.exc.OperationalError: (OperationalError) near "USE": syntax error 'USE auth.sqlite' ()
The CREATE DATABASE error is caught via exception handling, but the USE query error is not.
Is it possible to make the SqlAlchemy backend work with file based sqlite?
I am using the latest bottle-cork package available from pip.
Add the bottle-sqlite plugin (https://github.com/defnull/bottle/tree/master/plugins/sqlite) as another storage option. For a small number of authenticated users, in the thousands to tens of thousands, sqlite is an ideal solution.
When installing in a virtualenv using pip and requirements.txt bottle-cork complains that either bottle or beaker is not installed
requirements.txt:
Beaker
Markdown
argparse
bottle
bottle-cork
distribute
dulwich
macaron
mercurial
wsgiref
steps to repeat
virtualenv env
. env/bin/activate
pip install -r requirements.txt
error
ImportError: No module named beaker
Has anyone implemented an ajax login with bottle-cork?
Specifically I want to:
I've had a look at the related elements but not come up with a solution yet:
Login Form
As defined in class:
https://github.com/FedericoCeratto/bottle-cork/blob/master/cork/cork.py#L84
As defined in function:
As defined as static page:
As defined in form:
https://github.com/FedericoCeratto/bottle-cork/blob/master/examples/views/login_form.tpl#L8
<form action="login" method="post" name="login">
<input type="text" name="username" />
<input type="password" name="password" />
<br/><br/>
<button type="submit" > OK </button>
<button type="button" class="close"> Cancel </button>
</form>
I hope I'm missing something here, but having looked at the code a little, I can't see anything that makes Cork threadsafe, other than relying on the nature of python dictionaries in CPython.
Some hosting providers do not offer threading support, this leads to issues in the mailer. An option to disable async mailer would be nice.
Just what the subject says, really. I installed beaker, tried to run the sample app, disabled encrypted cookies by removing the relevant entry in session_opts, and if I submit a wrong password, I get back a 200 reply without any content and am not redirected to the fail_redirect page.
If I submit the correct password, everything is OK and the session management works. But the fail_redirect is failing.
The following seemed to resolve an error I was getting when running the following in OpenShift:
python mongodb_backend.py
Background
Installed custom library from GitHub:
source ~/python/virtenv/bin/activate
pip install --log $OPENSHIFT_DATA_DIR/inst.log https://github.com/FedericoCeratto/bottle-cork/archive/master.zip
Running:
[<app>-<namespace>.rhcloud.com cork]\> python mongodb_backend.py
Traceback (most recent call last):
File "mongodb_backend.py", line 11, in <module>
from .base_backend import Backend, Table
ValueError: Attempted relative import in non-package
This blog post I think outlines a similar problem and solution well:
http://melitamihaljevic.blogspot.com.au/2013/04/python-relative-imports-hard-way.html
So in mongodb_backend.py
I changed:
from .base_backend import Backend, Table
to:
from base_backend import Backend, Table
and now I can run:
python mongodb_backend.py
I don't know if that has any other implications though.
validate_registration() is changing the user account database without checking if an account has been already registered.
If multiple users request registration of the same account all the validate_registration() calls will be successful an the account ownership would be reassigned to the last caller.
The 0.7 release (thanks for it!) has a dependency on setuptools but anyway requires it already for executing the setup.py. What is the rationale for having it? Typically pacakging doesn't require depending on setuptools but is rather presumed to be there (because otherwise install_requires wouldn't have meaning).
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.