Permalink
Browse files

Resolve merge from feature/auth

  • Loading branch information...
2 parents 8f97125 + a18a29a commit e270d7c71c537719af2957fb1c655a3d6e69cae6 @mitechie committed Jun 18, 2011
Showing with 2,113 additions and 739 deletions.
  1. +0 −2 COPYING
  2. +24 −3 bookie/__init__.py
  3. +55 −11 bookie/lib/access.py
  4. +3 −2 bookie/lib/importer.py
  5. +45 −12 bookie/models/__init__.py
  6. +157 −0 bookie/models/auth.py
  7. +40 −13 bookie/models/fulltext.py
  8. +53 −18 bookie/routes.py
  9. +2 −1 bookie/static/css/bookie.css
  10. +0 −2 bookie/static/js/bookie.js
  11. +10 −4 bookie/static/js/mobile.js
  12. +17 −0 bookie/templates/auth/login.mako
  13. +35 −19 bookie/templates/bmark/func.mako
  14. +13 −2 bookie/templates/bmark/readable.mako
  15. +8 −3 bookie/templates/bmark/recent.mako
  16. +21 −7 bookie/templates/main_wrap.mako
  17. +3 −1 bookie/templates/mobile/index.mako
  18. +8 −2 bookie/templates/mobile_wrap.mako
  19. +11 −2 bookie/templates/tag/list.mako
  20. +3 −9 bookie/templates/utils/import.mako
  21. +8 −1 bookie/templates/utils/search.mako
  22. +1 −0 bookie/tests/__init__.py
  23. +81 −42 bookie/tests/test_api/__init__.py
  24. +85 −0 bookie/tests/test_auth/__init__.py
  25. +69 −0 bookie/tests/test_auth/test_model.py
  26. +394 −394 bookie/tests/test_delicious/__init__.py
  27. +9 −5 bookie/tests/test_utils/test_export.py
  28. +18 −11 bookie/tests/test_utils/test_fulltext.py
  29. +32 −8 bookie/tests/test_utils/test_imports.py
  30. +10 −5 bookie/tests/test_utils/test_readable.py
  31. +3 −34 bookie/tests/test_webviews/__init__.py
  32. +17 −1 bookie/views/__init__.py
  33. +159 −23 bookie/views/api.py
  34. +88 −0 bookie/views/auth.py
  35. +25 −9 bookie/views/bmarks.py
  36. +3 −3 bookie/views/delapi.py
  37. +6 −7 bookie/views/mobile.py
  38. +17 −31 bookie/views/tags.py
  39. +38 −26 bookie/views/utils.py
  40. +3 −3 docs/install.rst
  41. +2 −1 docs/started.rst
  42. +4 −1 extensions/chrome_ext/lib/bookie.api.js
  43. +1 −1 extensions/chrome_ext/manifest.json
  44. +7 −7 extensions/chrome_ext/options.html
  45. +1 −0 fabfile/__init__.py
  46. +45 −0 fabfile/admin.py
  47. +1 −0 fabfile/database.py
  48. +30 −0 migrations/versions/009_Add_user_db_table.py
  49. +25 −0 migrations/versions/010_Add_user_to_the_bmark_object.py
  50. +26 −0 migrations/versions/011_api_key_is_user_specific.py
  51. +2 −1 requirements.txt
  52. +44 −0 scripts/readability/README.rst
  53. +6 −0 scripts/readability/nlogger.json
  54. +43 −0 scripts/readability/readable_consumer.py
  55. +299 −0 scripts/readability/readable_producer.js
  56. +1 −4 test.ini
  57. +1 −4 test_mysql.ini
  58. +1 −4 test_psql.ini
View
@@ -615,5 +615,3 @@ reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
-
- END OF TERMS AND CONDITIONS
View
@@ -1,20 +1,41 @@
+from pyramid.authentication import AuthTktAuthenticationPolicy
+from pyramid.authorization import ACLAuthorizationPolicy
from pyramid.config import Configurator
-from pyramid.session import UnencryptedCookieSessionFactoryConfig
from sqlalchemy import engine_from_config
+from bookie.lib.access import RequestWithUserAttribute
from bookie.models import initialize_sql
+from bookie.models.auth import UserMgr
from bookie.routes import build_routes
+from pyramid.security import Allow
+from pyramid.security import Everyone
+from pyramid.security import ALL_PERMISSIONS
+
+
+class RootFactory(object):
+ __acl__ = [ (Allow, Everyone, ALL_PERMISSIONS)]
+
+ def __init__(self, request):
+ self.__dict__.update(request.matchdict)
+
def main(global_config, **settings):
""" This function returns a Pyramid WSGI application.
"""
engine = engine_from_config(settings, 'sqlalchemy.')
initialize_sql(engine)
- unencrypt = UnencryptedCookieSessionFactoryConfig('itsaseekreet')
+ authn_policy = AuthTktAuthenticationPolicy(settings.get('auth.secret'),
+ callback=UserMgr.auth_groupfinder)
+ authz_policy = ACLAuthorizationPolicy()
+
+ config = Configurator(settings=settings,
+ root_factory='bookie.RootFactory',
+ authentication_policy=authn_policy,
+ authorization_policy=authz_policy)
+ config.set_request_factory(RequestWithUserAttribute)
- config = Configurator(settings=settings, session_factory=unencrypt)
config = build_routes(config)
config.add_static_view('static', 'bookie:static')
config.scan('bookie.views')
View
@@ -1,17 +1,22 @@
"""Handle auth and authz activities in bookie"""
import logging
+from pyramid.decorator import reify
from pyramid.httpexceptions import HTTPForbidden
-from pyramid.settings import asbool
+from pyramid.request import Request
+from pyramid.security import unauthenticated_userid
+
+from bookie.models.auth import UserMgr
+
LOG = logging.getLogger(__name__)
-class Authorize(object):
+class ApiAuthorize(object):
"""Context manager to check if the user is authorized
use:
- with Authorize(some_key):
+ with ApiAuthorize(some_key):
# do work
Will return NotAuthorized if it fails
@@ -34,17 +39,56 @@ def __exit__(self, exc_type, exc_value, traceback):
"""No cleanup work to do after usage"""
pass
-def edit_enabled(settings):
- """Is the config .ini setting for allowing edit enabled?
+class ReqAuthorize(object):
+ """Context manager to check if the user is logged in
- If the .ini setting for ui edits is not true, then no authed
+ use:
+ with ReqAuthorize(request):
+ # do work
+
+ Will return NotAuthorized if it fails
"""
- allow_edit = asbool(settings.get('allow_edit', False))
- if allow_edit:
- return True
- else:
- return False
+ def __init__(self, request, username=None):
+ """Create the context manager"""
+ LOG.debug('USER')
+ LOG.debug(request.user)
+
+ self.request = request
+ self.username = username
+
+ def __enter__(self):
+ """Verify api key set in constructor"""
+ if self.request.user is None:
+ LOG.error('Invalid Request: Not Logged in!')
+ raise HTTPForbidden('Invalid Authorization')
+
+ # if we have a username we're told to check against, make sure the
+ # username matches
+ if self.username is not None and self.username != self.request.user.username:
+ LOG.error('Invalid Request: Wrong Username!')
+ raise HTTPForbidden('Invalid Authorization')
+
+ def __exit__(self, exc_type, exc_value, traceback):
+ """No cleanup work to do after usage"""
+ pass
+class RequestWithUserAttribute(Request):
+ @reify
+ def user(self):
+ # <your database connection, however you get it, the below line
+ # is just an example>
+ # dbconn = self.registry.settings['dbconn']
+ LOG.debug('in Request with Attribute')
+ user_id = unauthenticated_userid(self)
+ LOG.debug(user_id)
+ if user_id is not None:
+ LOG.debug('user_id is not none')
+
+ # this should return None if the user doesn't exist
+ # in the database
+ user = UserMgr.get(user_id=user_id)
+ LOG.debug(user)
+ return user
View
@@ -8,9 +8,10 @@
class Importer(object):
"""The actual factory object we use for handling imports"""
- def __init__(self, import_io):
+ def __init__(self, import_io, username=None):
"""work on getting an importer instance"""
self.file_handle = import_io
+ self.username = username
def __new__(cls, *args, **kwargs):
"""Overriding new we return a subclass based on the file content"""
@@ -42,7 +43,7 @@ def save_bookmark(self, url, desc, ext, tags, dt=None, fulltext=None):
:param fulltext: Fulltext handler instance used to store that info
"""
- BmarkMgr.store(url, desc, ext, tags, dt=dt, fulltext=fulltext)
+ BmarkMgr.store(url, self.username, desc, ext, tags, dt=dt, fulltext=fulltext)
class DelImporter(Importer):
View
@@ -151,14 +151,20 @@ def from_string(tag_str):
return tag_objects
@staticmethod
- def find(order_by=None, tags=None):
+ def find(order_by=None, tags=None, username=None):
"""Find all of the tags in the system"""
qry = Tag.query
if tags:
# limit to only the tag names in this list
qry = qry.filter(Tag.name.in_(tags))
+ if username:
+ # then we'll need to bind to bmarks to be able to limit on the
+ # username field
+ bmark = aliased(Bmark)
+ qry = qry.join((bmark, Tag.bmark)).filter(bmark.username==username)
+
if order_by is not None:
qry = qry.order_by(order_by)
else:
@@ -388,28 +394,43 @@ class BmarkMgr(object):
"""Class to handle non-instance Bmark functions"""
@staticmethod
- def get_by_url(url):
+ def get_by_url(url, username=None):
"""Get a bmark from the system via the url"""
# normalize the url
clean_url = BmarkTools.normalize_url(url)
- return Bmark.query.join(Bmark.hashed).\
+
+ qry = Bmark.query.join(Bmark.hashed).\
options(contains_eager(Bmark.hashed)).\
- filter(Hashed.url == clean_url).one()
+ filter(Hashed.url == clean_url)
+
+ if username:
+ qry = qry.filter(Bmark.username==username)
+
+ return qry.one()
@staticmethod
- def get_by_hash(hash_id):
+ def get_by_hash(hash_id, username=None):
"""Get a bmark from the system via the hash_id"""
# normalize the url
- return Bmark.query.join(Bmark.hashed).\
+ qry = Bmark.query.join(Bmark.hashed).\
options(contains_eager(Bmark.hashed)).\
- filter(Hashed.hash_id == hash_id).first()
+ filter(Hashed.hash_id == hash_id)
+
+ if username:
+ qry = qry.filter(Bmark.username == username)
+
+ return qry.first()
@staticmethod
- def find(limit=50, order_by=None, page=0, tags=None, with_tags=True):
+ def find(limit=50, order_by=None, page=0, tags=None, with_tags=True,
+ username=None):
"""Search for specific sets of bookmarks"""
qry = Bmark.query
offset = limit * page
+ if username:
+ qry = qry.filter(Bmark.username == username)
+
if order_by is None:
order_by = Bmark.stored.desc()
@@ -495,7 +516,7 @@ def popular(limit=50, page=0, with_tags=False):
return res
@staticmethod
- def store(url, desc, ext, tags, dt=None, fulltext=None):
+ def store(url, username, desc, ext, tags, dt=None, fulltext=None):
"""Store a bookmark
:param url: bookmarked url
@@ -506,6 +527,7 @@ def store(url, desc, ext, tags, dt=None, fulltext=None):
"""
mark = Bmark(url,
+ username,
desc=desc,
ext=ext,
tags=tags,
@@ -524,9 +546,14 @@ def store(url, desc, ext, tags, dt=None, fulltext=None):
return mark
@staticmethod
- def hash_list():
+ def hash_list(username=None):
"""Get a list of the hash_ids we have stored"""
- return DBSession.query(Bmark.hash_id).all()
+ qry = DBSession.query(Bmark.hash_id)
+
+ if username:
+ qry = qry.filter(Bmark.username==username)
+
+ return qry.all()
class BmarkTools(object):
@@ -560,6 +587,8 @@ class Bmark(Base):
stored = Column(DateTime, default=datetime.now)
updated = Column(DateTime, onupdate=datetime.now)
clicks = Column(Integer, default=0)
+ username = Column(Unicode(255), ForeignKey('users.username'),
+ nullable=False,)
# DON"T USE
tag_str = Column(UnicodeText())
@@ -579,7 +608,10 @@ class Bmark(Base):
single_parent=True,
)
- def __init__(self, url, desc=None, ext=None, tags=None):
+ user = relation("User",
+ backref="bmark")
+
+ def __init__(self, url, username, desc=None, ext=None, tags=None):
"""Create a new bmark instance
:param url: string of the url to be added as a bookmark
@@ -597,6 +629,7 @@ def __init__(self, url, desc=None, ext=None, tags=None):
else:
self.hashed = existing
+ self.username = username
self.description = desc
self.extended = ext
Oops, something went wrong.

0 comments on commit e270d7c

Please sign in to comment.