Пример #1
0
class Extension(lux.Extension):

    _config = [
        Parameter('WS_URL', '/ws', 'Websocket base url'),
        Parameter('PUBSUB_STORE', None,
                  'Connection string for a Publish/Subscribe data-store'),
        Parameter('WEBSOCKET_HARTBEAT', 25, 'Hartbeat in seconds'),
        Parameter('WEBSOCKET_AVAILABLE', True, 'Server handle websocket'),
    ]

    def on_config(self, app):
        app.add_events(['on_websocket_open'])

    def middleware(self, app):
        '''Add middleware to edit content
        '''
        socketio = SocketIO(app.config['WS_URL'])
        self.websocket = socketio.handle
        return [socketio]

    def on_loaded(self, app):
        pubsub_store = app.config['PUBSUB_STORE']
        if pubsub_store:
            self.pubsub_store = create_store(pubsub_store)
            self.websocket.pubsub = self.pubsub_store.pubsub()
Пример #2
0
class Extension(lux.Extension):

    _config = [
        # Override default email backend
        Parameter('EMAIL_BACKEND', 'lux.extensions.smtp.EmailBackend',
                  'Default locale'),
        Parameter('EMAIL_HOST', '', 'SMTP email host'),
        Parameter('EMAIL_PORT', 465, 'SMTP email port'),
        Parameter('EMAIL_HOST_USER', '', 'SMTP email host user'),
        Parameter('EMAIL_HOST_PASSWORD', '', 'SMTP email host user password'),
        Parameter('EMAIL_TIMEOUT', None, 'timeout for email timeout'),
        Parameter('EMAIL_USE_TLS', False, 'use TLS when using SMTP email'),
        Parameter('EMAIL_TLS_KEYFILE', None, 'TLS Keyfile'),
        Parameter('EMAIL_TLS_CERTFILE', None, 'TLS cert file'),
        Parameter('SMTP_LOG_LEVEL', None, 'Logging level for email messages')
    ]

    def on_start(self, app, server):
        level = app.config['SMTP_LOG_LEVEL']
        if level:
            smtp = SMTPLogger(app, level)
            root = logging.getLogger('')
            root.addHandler(smtp)
            for logger in root.manager.loggerDict.values():
                if (isinstance(logger, logging.Logger) and not logger.propagate
                        and logger.handlers):
                    logger.addHandler(smtp)
Пример #3
0
class Extension(lux.Extension):
    '''Admin site for database data
    '''
    _config = [
        Parameter('ADMIN_URL', 'admin',
                  'Admin site url', True),
        Parameter('ADMIN_SECTIONS', {},
                  'Admin sections information')]

    def middleware(self, app):
        admin = app.config['ADMIN_URL']
        if admin:
            app.require('lux.extensions.rest')
            self.admin = admin = Admin(admin)
            middleware = []
            all = app.module_iterator('admin', is_admin, '__admins__')
            for AdminRouterCls in all:
                if not AdminRouterCls._model:
                    continue
                route = AdminRouterCls()
                admin.add_child(route)
                path = route.path()
                if not path.endswith('/'):
                    middleware.append(RedirectRouter('%s/' % path, path))
            middleware.append(admin)
            return middleware
Пример #4
0
class Extension(lux.Extension):

    _config = [
        Parameter('OAUTH_PROVIDERS', None,
                  'Dictionary of dictionary of OAuth providers'),
        Parameter(
            'DEFAULT_OG_TYPE', 'website',
            'Default object graph protocol type. '
            'Set to None to disable OGP')
    ]

    def on_html_document(self, app, request, doc):
        doc.meta = NamespaceHeadMeta(doc.head)
        type = app.config['DEFAULT_OG_TYPE']
        if type:
            # add default OGP entries
            doc.meta['og:type'] = type
            doc.meta['og:url'] = app.site_url(request.path)
            doc.meta['og:locale'] = app.config['LOCALE']
            oauths = get_oauths(request)
            if oauths:
                for provider in oauths.values():
                    provider.on_html_document(request, doc)
                doc.before_render(self.meta_add_tags)
        doc.jscontext['oauths'] = oauth_context(request)

    def meta_add_tags(self, request, doc):
        with OGP(doc) as ogp:
            if request:
                oauth = request.cache.oauths
                for provider in oauth.values():
                    provider.ogp_add_tags(request, ogp)
Пример #5
0
class Extension(lux.Extension):
    '''Object data mapper extension
    '''
    _config = [
        Parameter('ADMIN_URL', 'admin', 'Admin site url', True),
        Parameter('ADMIN_PERMISSIONS', 'admin', 'Admin permission name')
    ]

    def middleware(self, app):
        admin = app.config['ADMIN_URL']
        if admin:
            self.admin = admin = Admin(admin)
            for model in model_iterator(app.config['EXTENSIONS']):
                meta = model._meta
                admin_cls = adminMap.get(meta, AdminModel)
                if admin_cls:
                    admin.add_child(admin_cls(meta))
            permission = app.config['ADMIN_PERMISSIONS']
            return [RequirePermission(permission)(admin)]

    def on_html_document(self, app, request, doc):
        backend = request.cache.auth_backend
        permission = app.config['ADMIN_PERMISSIONS']
        if backend and not backend.has_permission(request, permission):
            doc.jscontext.pop('ADMIN_URL', None)
Пример #6
0
class BrowserBackend(AuthBackend):
    '''Authentication backend for rendering Forms

    It can be used by web servers delegating authentication to a backend API
    or handling authentication on the same site.
    '''
    _config = [
        Parameter('LOGIN_URL', '/login', 'Url to login page', True),
        Parameter('LOGOUT_URL', '/logout', 'Url to logout', True),
        Parameter('REGISTER_URL', '/signup', 'Url to register with site',
                  True),
        Parameter('RESET_PASSWORD_URL', '/reset-password',
                  'If given, add the router to handle password resets', True)
    ]

    def on_config(self, app):
        app.require('lux.extensions.api')

    def middleware(self, app):
        middleware = []
        cfg = app.config
        api_url = cfg['API_URL']
        if not is_absolute_uri(api_url):
            api_url = None

        if cfg['LOGIN_URL']:
            middleware.append(Login(cfg['LOGIN_URL'], api_url=api_url))
            middleware.append(Logout(cfg['LOGOUT_URL'], api_url=api_url))
        if cfg['REGISTER_URL']:
            middleware.append(SignUp(cfg['REGISTER_URL'], api_url=api_url))
        if cfg['RESET_PASSWORD_URL']:
            middleware.append(
                ForgotPassword(cfg['RESET_PASSWORD_URL'], api_url=api_url))
        return middleware
Пример #7
0
class Extension(lux.Extension):
    _config = [
        Parameter('SERVER_CONFIGURATION', 'nginx_reverse_proxy', ''),
        Parameter('DOMAIN_NAME', None,
                  'Full domain name of your web site, e.g. '
                  'http://www.example.com')
    ]
Пример #8
0
class Extension(lux.Extension):
    _config = [
        Parameter('GZIP_MIN_LENGTH', 200,
                  'If a positive integer, a response middleware is added so '
                  'that it encodes the response via the gzip algorithm.'),
        Parameter('USE_ETAGS', False, ''),
        Parameter('CLEAN_URL', True,
                  'When ``True``, requests on url with consecutive slashes '
                  'are converted to valid url and redirected.'),
        Parameter('SERVE_STATIC_FILES', False,
                  'if ``True`` add middleware to serve static files.'),
        Parameter('FAVICON', None,
                  'Adds wsgi middleware to handle favicon url ``/favicon.ico``'
                  'served from ``MEDIA_URL/FAVICON``')]

    def middleware(self, app):
        '''Add two middleware handlers if configured to do so.'''
        middleware = []
        if app.config['CLEAN_URL']:
            middleware.append(wsgi.clean_path_middleware)
        if app.config['SERVE_STATIC_FILES']:
            icon = app.config['FAVICON']
            if icon:
                middleware.append(FileRouter('/favicon.ico', icon))
            path = app.config['MEDIA_URL']
            # Check if node modules are available
            node_modules = os.path.join(os.path.dirname(app.meta.path),
                                        'node_modules')
            if os.path.isdir(node_modules):
                node = '%snode_modules/' % path
                middleware.append(wsgi.MediaRouter(node, node_modules,
                                                   show_indexes=app.debug))
            middleware.append(MediaRouter(path, app.meta.media_dir,
                                          show_indexes=app.debug))
        return middleware

    def response_middleware(self, app):
        gzip = app.config['GZIP_MIN_LENGTH']
        middleware = []
        if gzip:
            middleware.append(wsgi.GZipMiddleware(gzip))
        if app.config['USE_ETAGS']:
            middleware.append(self.etag)
        return middleware

    def etag(self, environ, response):
        if response.has_header('ETag'):
            etag = response['ETag']
        elif response.streaming:
            etag = None
        else:
            etag = '"%s"' % hashlib.md5(response.content).hexdigest()
        if etag is not None:
            if (200 <= response.status_code < 300
                    and environ.get('HTTP_IF_NONE_MATCH') == etag):
                response.not_modified()
            else:
                response['ETag'] = etag
        return response
Пример #9
0
class Extension(lux.Extension):

    _config = [
        Parameter('HTML5_NAVIGATION', False, 'Enable Html5 navigation', True),
        Parameter('ANGULAR_VIEW_ANIMATE', False,
                  'Enable Animation of ui-router views.'),
        Parameter('NGMODULES', [], 'Angular module to load')
    ]

    def on_html_document(self, app, request, doc):
        router = html_router(request.app_handler)

        if not router:
            return
        #
        add_ng_modules(doc, app.config['NGMODULES'])

        # Use HTML5 navigation and angular router
        if app.config['HTML5_NAVIGATION']:
            add_ng_modules(doc, LUX_UI_ROUTER)

            doc.body.data({
                'ng-model': 'page',
                'ng-controller': 'Page',
                'page': ''
            })

            doc.head.meta.append(Html('base', href="/"))
            sitemap = angular_sitemap(request, router)
            add_ng_modules(doc, sitemap.pop('modules'))
            doc.jscontext.update(sitemap)
            doc.jscontext['page'] = router.state
        else:
            add_ng_modules(doc, LUX_ROUTER)
            add_ng_modules(doc, router.uimodules)

    def context(self, request, context):
        router = html_router(request.app_handler)
        if request.config['HTML5_NAVIGATION'] and router:
            pages = request.html_document.jscontext['pages']
            page = pages.get(router.state)
            context['html_main'] = self.uiview(request, context, page)

    def uiview(self, request, context, page):
        '''Wrap the ``main`` html with a ``ui-view`` container.
        Add animation class if specified in :setting:`ANGULAR_VIEW_ANIMATE`.
        '''
        app = request.app
        main = context.get('html_main', '')
        if 'templateUrl' in page or 'template' in page:
            main = Html('div', main, cn='hidden', id="seo-view")
        div = Html('div', main, cn='angular-view')
        animate = app.config['ANGULAR_VIEW_ANIMATE']
        if animate:
            add_ng_modules(request.html_document, ('ngAnimate', ))
            div.addClass(animate)
        div.data('ui-view', '')
        return div.render()
Пример #10
0
class Extension(lux.Extension):

    _config = [
        Parameter('THEME', None, ''),
        Parameter('ICON_PROVIDER', 'fontawesome', 'Icons provider to use')
    ]

    def on_html_document(self, app, request, doc):
        if doc.has_default_content_type:
            icon = app.config['ICON_PROVIDER']
            if icon == 'fontawesome':
                doc.head.links.append('fontawesome')
            doc.data('icon', icon)
Пример #11
0
class Extension(lux.Extension):

    _config = [
        Parameter('EXCLUDE_EXTENSIONS_CSS', None,
                  'Optional list of extensions to exclude form the css'),
        Parameter('NAVBAR_COLLAPSE_WIDTH', 768,
                  'Width when to collapse the navbar')
    ]

    def on_html_document(self, app, request, doc):
        navbar = doc.jscontext.get('navbar') or {}
        navbar['collapseWidth'] = app.config['NAVBAR_COLLAPSE_WIDTH']
        doc.jscontext['navbar'] = navbar
Пример #12
0
class Extension(lux.Extension):
    '''The sessions extensions provides wsgi middleware for managing sessions
    and users.

    In addition it provides utilities for managing Cross Site Request Forgery
    protection and user permissions levels.
    '''
    _config = [
        Parameter('CODE_HIGHLIGHT_THEME', 'tomorrow', 'highlight.js theme'),
        Parameter('CODEMIRROR_THEME', 'monokai', 'codemirror.js theme')
    ]

    def on_html_document(self, app, request, doc):
        add_ng_modules(doc, ('highlight', 'lux.codemirror'))
Пример #13
0
class BrowserBackend(RegistrationMixin, AuthBackend):
    '''Authentication backend for rendering Forms in the Browser

    It can be used by web servers delegating authentication to a backend API
    or handling authentication on the same site.
    '''
    _config = [
        Parameter('LOGIN_URL', '/login', 'Url to login page', True),
        Parameter('LOGOUT_URL', '/logout', 'Url to logout', True),
        Parameter('REGISTER_URL', '/signup', 'Url to register with site',
                  True),
        Parameter('TOS_URL', '/tos', 'Terms of Service url', True),
        Parameter('PRIVACY_POLICY_URL', '/privacy-policy',
                  'The url for the privacy policy, required for signups', True)
    ]
    LoginRouter = Login
    LogoutRouter = Logout
    SignUpRouter = SignUp
    ForgotPasswordRouter = ForgotPassword

    def middleware(self, app):
        middleware = []
        cfg = app.config
        api = cfg['API_URL']

        if cfg['LOGIN_URL']:
            middleware.append(
                auth_router(api, cfg['LOGIN_URL'], self.LoginRouter, False))

        if cfg['LOGOUT_URL'] and self.LogoutRouter:
            middleware.append(
                auth_router(api, cfg['LOGOUT_URL'], self.LogoutRouter))

        if cfg['REGISTER_URL']:
            middleware.append(
                auth_router(api, cfg['REGISTER_URL'], self.SignUpRouter))

        if cfg['RESET_PASSWORD_URL']:
            middleware.append(
                auth_router(api, cfg['RESET_PASSWORD_URL'],
                            self.ForgotPasswordRouter))

        return middleware

    def on_html_document(self, app, request, doc):
        if is_absolute_uri(app.config['API_URL']):
            add_ng_modules(doc, ('lux.restapi', 'lux.users'))
        else:
            add_ng_modules(doc, ('lux.webapi', 'lux.users'))
Пример #14
0
class Extension(lux.Extension):

    _config = [
        Parameter('SITEMAP_CACHE_TIMEOUT', None,
                  ('Sitemap cache timeout, if not set it defaults to '
                   'the DEFAULT_CACHE_TIMEOUT parameter'))
    ]
Пример #15
0
class Extension(lux.Extension):
    _config = [
        Parameter('ANONYMOUS_GROUP', 'anonymous',
                  'Name of the group for all anonymous users'),
        Parameter('DEFAULT_PERMISSION_LEVEL', rest.READ,
                  'Default permission level')
    ]

    def on_config(self, app):
        app.require('lux.extensions.odm')

    def on_token(self, app, request, token, user):
        if user.is_authenticated():
            token['username'] = user.username
            token['user_id'] = user.id
            token['name'] = user.full_name
Пример #16
0
class Extension(lux.Extension):

    _config = [
        Parameter('OAUTH_PROVIDERS', None,
                  'Dictionary of dictionary of OAuth providers'),
        Parameter(
            'DEFAULT_OG_TYPE', 'website',
            'Default object graph protocol type. '
            'Set to None to disable OGP'),
        Parameter(
            'CANONICAL_URL', True, 'Add canonical meta tag to website. '
            'Can be a function or False')
    ]

    def on_html_document(self, app, request, doc):
        canonical = app.config['CANONICAL_URL']
        if hasattr(canonical, '__call__'):
            canonical = canonical(request, doc)
        if canonical:
            if not isinstance(canonical, str):
                canonical = request.absolute_uri()
            doc.head.links.append(canonical, 'canonical')

        type = app.config['DEFAULT_OG_TYPE']
        # add canonical if not available
        if type:
            # add default OGP entries
            doc.meta['og:type'] = type
            if canonical:
                doc.meta['og:url'] = canonical
            doc.meta['og:locale'] = app.config['LOCALE']
            doc.meta['og:site_name'] = app.config['APP_NAME']
            oauths = get_oauths(request)
            if oauths:
                for provider in oauths.values():
                    provider.on_html_document(request, doc)
                doc.before_render(self.meta_add_tags)
        doc.jscontext['oauths'] = oauth_context(request)

    def meta_add_tags(self, request, doc):
        '''Add meta tags to the html document just before rendering
        '''
        with OGP(doc) as ogp:
            if request:
                oauth = request.cache.oauths
                for provider in oauth.values():
                    provider.ogp_add_tags(request, ogp)
Пример #17
0
class TokenBackend(AuthBackend):
    '''Backend based on JWT_

    Requires pyjwt_ package.

    .. _pyjwt: https://pypi.python.org/pypi/PyJWT
    .. _JWT: http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html
    '''
    form = LoginForm

    _config = [
        Parameter('AUTHORIZATION_URL', '/authorizations',
                  'Url for authorizations', True),
    ]

    def on_config(self, app):
        if not jwt:
            raise ImproperlyConfigured('JWT library not available')

    def api_sections(self, app):
        yield Authorization(app.config['AUTHORIZATION_URL'])

    def request(self, request):
        '''Check for ``HTTP_AUTHORIZATION`` header and if it is available
        and the authentication type if ``bearer`` try to perform
        authentication using JWT_.
        '''
        auth = request.get('HTTP_AUTHORIZATION')
        user = request.cache.user
        if auth and user.is_anonymous():
            auth_type, key = auth.split(None, 1)
            auth_type = auth_type.lower()
            if auth_type == 'bearer':
                try:
                    data = jwt.decode(key, self.secret_key)
                except jwt.ExpiredSignature:
                    request.app.logger.info('JWT token has expired')
                    # In this case we want the client to perform
                    # a new authentication. Raise 401
                    raise Http401('Token')
                except Exception:
                    request.app.logger.exception('Could not load user')
                else:
                    user = self.get_user(request, **data)
                    if user:
                        request.cache.user = user

    def create_token(self, request, user):
        '''Create the token
        '''
        payload = self.jwt_payload(request, user)
        return jwt.encode(payload, cfg['SECRET_KEY'])

    def jwt_payload(self, request, user):
        expiry = self.session_expiry(request)
        payload = {'user_id': user.id}
        if expiry:
            payload['exp'] = int(time.mktime(expiry.timetuple()))
        return payload
Пример #18
0
class Extension(lux.Extension):
    _config = [
        Parameter('NAVIGATION_LEVELS', 1, ''),
        Parameter('NAVIGATION_BRAND', '',
                  'Html string for the brand in the toolbar'),
        Parameter(
            'NAVIGATION_BRAND_LINK', '/',
            'The href value of the anchor which display the brand in the'
            ' navigation toolbar'),
        Parameter('NAVIGATION_TEMPLATE',
                  ('brand', 'main', 'secondary', 'user'),
                  'Layout of the Navigation Toolbar'),
        Parameter('NAVIGATION_CLASSES', 'nav nav-list standard', '')
    ]

    def on_html_document(self, app, request, doc):
        '''Add the ``html_navigation`` entry in the ``request.cache``.

        Loop over all Routers which have the ``navigation_visit`` method
        implemented. The ``html_navigation`` is an instance of
        :class:`NavigationInfo` and can be used to add navigation
        items as well as logos and search boxes.
        '''
        if doc.has_default_content_type:
            brand = app.config['NAVIGATION_BRAND']
            request.cache.html_navigation = NavigationInfo(brand)

    def navigation(self, request, routers, levels=None):
        '''Create an ul with links.'''
        levels = levels or self.config['NAVIGATION_LEVELS']
        ul = Html('ul', cn=self.config['NAVIGATION_CLASSES'])
        for _, router in sorted(self._ordered_nav(routers),
                                key=lambda x: x[0]):
            if router.parameters.navigation:
                try:
                    link = router.link()
                except KeyError:
                    continue
                ul.append(link)
        return ul.render(request)

    def _ordered_nav(self, routers):
        for router in routers:
            if router.parameters.navigation:
                yield router.parameters.navigation, router
Пример #19
0
class Extension(lux.Extension):

    _config = [
        Parameter('WS_URL', '/ws', 'Websocket base url'),
        Parameter('WS_HANDLER', LuxWs, 'Websocket handler'),
        Parameter('WEBSOCKET_HARTBEAT', 25, 'Hartbeat in seconds'),
        Parameter('WEBSOCKET_AVAILABLE', True, 'Server handle websocket'),
    ]

    def on_config(self, app):
        app.add_events(('on_websocket_open', 'on_websocket_close'))

    def middleware(self, app):
        '''Add middleware to edit content
        '''
        handler = app.config['WS_HANDLER']
        if handler:
            socketio = SocketIO(app.config['WS_URL'], handler(app))
            return [socketio]
Пример #20
0
class Extension(lux.Extension):
    '''Object data mapper extension

    Uses pulsar-odm for sychronous & asynchronous data mappers
    '''
    _config = [
        Parameter('DATASTORE', None,
                  'Dictionary for mapping models to their back-ends database'),
        Parameter('DATABASE_SESSION_SIGNALS', True,
                  'Register event handlers for database session'),
        Parameter('MIGRATIONS', None,
                  'Dictionary for mapping alembic settings')
    ]

    def on_config(self, app):
        '''Initialise Object Data Mapper'''
        app.require('lux.extensions.rest')
        app.odm = Odm(app, app.config['DATASTORE'])
        app.add_events(('on_before_commit', 'on_after_commit'))
Пример #21
0
class Amazon(OAuth2API):
    WEB_AUTH_URL = 'https://www.amazon.com/ap/oa'
    BASE_URL = 'https://api.amazon.com'
    scopes = ('user', 'user:email', 'user:follow', 'public_repo', 'repo',
              'repo:status', 'delete_repo', 'notifications', 'gist')
    auth_class = OAuth2
    json = True
    params = [
        Parameter('AMAZON_CLIENT_ID', None, 'Amazon OAUth client ID'),
        Parameter('AMAZON_CLIENT_SECRET', None, 'Amazon OAUth secret'),
        Parameter('AMAZON_SCOPE', 'profile', 'Amazon application scope')
    ]

    @classmethod
    def build(cls, cfg=None):
        if cfg:
            id = cfg.get('AMAZON_CLIENT_ID')
            secret = cfg.get('AMAZON_CLIENT_SECRET')
            if id and secret:
                return cls(client_id=id,
                           client_secret=secret,
                           client_scope=cfg.get('AMAZON_SCOPE') or 'profile')

    def html_login_link(self, request):
        img = Html('img',
                   src=('https://images-na.ssl-images-amazon.com/images'
                        '/G/01/lwa/btnLWA_gold_156x32.png'),
                   width=156,
                   height=32,
                   alt='Login with Amazon')
        href = self.web_oauth(request)
        return Html('a', img, href=href)

    authorization = api_function(
        '/auth/o2',
        method='GET',
        allowed_params={
            'state': None,
            'response_type': 'code',  # token or code
            'redirect_uri': None
        },
        required_params=('response_type', ),
        allow_redirects=False)
Пример #22
0
class Extension(lux.Extension):
    '''Object data mapper extension
    '''
    _config = [
        Parameter('DATASTORE', None,
                  'Dictionary for mapping models to their back-ends database')
    ]

    def on_config(self, app):
        '''Initialise Object Data Mapper'''
        app.odm = Odm(app, app.config['DATASTORE'])
Пример #23
0
class Extension(lux.Extension):

    _config = [
        Parameter(
            'FONTAWESOME',
            '//netdna.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome',
            'FONTAWESOME url. Set to none to not use it.'),
        Parameter('BOOTSTRAP',
                  '//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap',
                  'Twitter bootstrap url. Set to none to not use it.'),
        Parameter('EXCLUDE_EXTENSIONS_CSS', None,
                  'Optional list of extensions to exclude form the css'),
        Parameter('NAVBAR_COLLAPSE_WIDTH', 768,
                  'Width when to collapse the navbar')
    ]

    def on_html_document(self, app, request, doc):
        navbar = doc.jscontext.get('navbar') or {}
        navbar['collapseWidth'] = app.config['NAVBAR_COLLAPSE_WIDTH']
        doc.jscontext['navbar'] = navbar
        for name in ('BOOTSTRAP', 'FONTAWESOME'):
            doc.head.links.append(app.config[name])
Пример #24
0
class Extension(lux.Extension):
    _config = [Parameter('TEST_DOCS', False, '')]

    def middleware(self, app):
        content = Content('blog',
                          child_url='<int:year>/<month2>/<slug>',
                          html_body_template='blog.html',
                          dir=os.path.join(base, 'content', 'blog'),
                          meta_child={'og:type', 'article'})
        # if app.config['TEST_DOCS']:
        #     doc = SphinxDocs('docs',
        #                      dir=os.path.join(base, 'content', 'docs'))
        #     content.add_child(doc)
        return [content]
Пример #25
0
class Extension(lux.Extension):
    '''The sessions extensions provides wsgi middleware for managing sessions
    and users.

    In addition it provides utilities for managing Cross Site Request Forgery
    protection and user permissions levels.
    '''
    _config = [
        Parameter('CODE_HIGHLIGHT_THEME', 'tomorrow', 'highlight.js theme')
    ]

    def on_html_document(self, app, request, doc):
        ngmodules = set(doc.jscontext.get('ngModules', ()))
        ngmodules.add('highlight')
        doc.jscontext['ngModules'] = list(ngmodules)
Пример #26
0
class Extension(lux.Extension):
    _config = [Parameter('TEST_DOCS', False, '')]

    def middleware(self, app):
        content = HtmlContent('/',
                              Sitemap('/sitemap.xml'),
                              Blog('blog',
                                   child_url='<int:year>/<month2>/<slug>',
                                   html_body_template='blog.html',
                                   dir=base + 'content/blog',
                                   meta_child={'og:type', 'article'}),
                              dir=base + 'content/site',
                              meta={'template': 'main.html'})
        if app.config['TEST_DOCS']:
            doc = SphinxDocs('docs', dir=base + 'content/docs')
            content.add_child(doc)
        return [content]
Пример #27
0
class Geonames(API):
    BASE_URL = 'http://api.geonames.org'
    #auth_class = auth.KeyAuth
    json = True
    params = [Parameter('GEONAMES_USERNAME', None, 'Geonames username')]

    def setup(self, username=None, **params):
        self.username = username

    @classmethod
    def build(cls, cfg=None):
        if cfg:
            un = cfg.get('GEONAMES_USERNAME')
            if un:
                return cls(username=un)

    country_info = api_function('/countryInfoJSON',
                                allowed_params={
                                    'style': 'full',
                                    'formatted': 'true'
                                },
                                callback=country_info)
Пример #28
0
class Extension(lux.Extension):
    '''Content management System

    Used by both front-end and back-end.

    Requires the :mod:`lux.extensions.odm` extension
    '''
    _config = [
        Parameter('CMS_LOAD_PLUGINS', True, 'Load plugins from extensions')
    ]
    _partials = None

    def api_sections(self, app):
        app.require('lux.extensions.odm')
        return [PageCRUD(), TemplateCRUD()]

    def on_loaded(self, app):
        app.cms = CMS(app)

    def on_html_document(self, app, request, doc):
        '''Add the ``lux.cms`` module to angular bootstrap
        '''
        add_ng_modules(doc, 'lux.cms')
Пример #29
0
class AuthMixin(PasswordMixin):
    '''Mixin to implement authentication backend based on
    SQLAlchemy models
    '''
    _config = [
        Parameter('GENERAL_MAILING_LIST_TOPIC', 'general',
                  "topic for general mailing list")
    ]

    def api_sections(self, app):
        '''At the authorization router to the api
        '''
        yield Authorization()

    def get_user(self,
                 request,
                 user_id=None,
                 token_id=None,
                 username=None,
                 email=None,
                 auth_key=None,
                 **kw):
        '''Securely fetch a user by id, username or email

        Returns user or nothing
        '''
        odm = request.app.odm()

        if token_id and user_id:
            with odm.begin() as session:
                query = session.query(odm.token)
                query = query.filter_by(user_id=user_id, id=token_id)
                query.update({'last_access': datetime.utcnow()},
                             synchronize_session=False)
                if not query.count():
                    return

        if auth_key:
            with odm.begin() as session:
                query = session.query(odm.registration)
                reg = query.get(auth_key)
                if reg and not reg.confirmed and reg.expiry > datetime.now():
                    user_id = reg.user_id
                else:
                    return

        with odm.begin() as session:
            query = session.query(odm.user)
            try:
                if user_id:
                    user = query.get(user_id)
                elif username:
                    user = query.filter_by(username=username).one()
                elif email:
                    user = query.filter_by(email=normalise_email(email)).one()
                else:
                    return
            except NoResultFound:
                return

        return user

    def authenticate(self,
                     request,
                     user_id=None,
                     username=None,
                     email=None,
                     user=None,
                     password=None,
                     **kw):
        odm = request.app.odm()

        try:
            if not user:
                with odm.begin() as session:
                    query = session.query(odm.user)
                    if user_id:
                        user = query.get(user_id)
                    elif username:
                        user = query.filter_by(username=username).one()
                    elif email:
                        email = normalise_email(email)
                        user = query.filter_by(email=email).one()
                    else:
                        raise AuthenticationError('Invalid credentials')
            if user and self.crypt_verify(user.password, password):
                return user
            else:
                raise NoResultFound
        except NoResultFound:
            if username:
                raise AuthenticationError('Invalid username or password')
            elif email:
                raise AuthenticationError('Invalid email or password')
            else:
                raise AuthenticationError('Invalid credentials')

    def has_permission(self, request, name, level):
        user = request.cache.user
        # Superuser, always true
        if user.is_superuser():
            return True
        else:
            permissions = self.get_permissions(request)
            return has_permission(request, permissions, name, level)

    def create_user(self,
                    request,
                    username=None,
                    password=None,
                    email=None,
                    first_name=None,
                    last_name=None,
                    active=False,
                    superuser=False,
                    **kwargs):
        '''Create a new user.

        Either ``username`` or ``email`` must be provided.
        '''
        odm = request.app.odm()

        email = normalise_email(email)
        assert username or email

        with odm.begin() as session:
            if not username:
                username = email

            user = odm.user(username=username,
                            password=self.password(password),
                            email=email,
                            first_name=first_name,
                            last_name=last_name,
                            active=active,
                            superuser=superuser)
            session.add(user)

        return user

    def create_superuser(self, request, **params):
        params['superuser'] = True
        params['active'] = True
        return self.create_user(request, **params)

    def create_token(self, request, user, **kwargs):
        '''Create the token and return a two element tuple
        containing the token and the encoded version
        '''
        odm = request.app.odm()
        ip_address = request.get_client_address()
        user_id = user.id if user.is_authenticated() else None

        with odm.begin(close=False) as session:
            token = odm.token(id=uuid.uuid4(),
                              user_id=user_id,
                              ip_address=ip_address,
                              user_agent=self.user_agent(request, 80),
                              **kwargs)
            session.add(token)
        token.encoded = self.encode_token(request,
                                          token_id=token.id.hex,
                                          user=token.user or user,
                                          expiry=token.expiry)
        session.close()
        return token

    def create_auth_key(self, request, user, expiry=None, **kw):
        '''Create a registration entry and return the registration id
        '''
        if not expiry:
            expiry = request.cache.auth_backend.auth_key_expiry(request)
        odm = request.app.odm()
        with odm.begin() as session:
            reg = odm.registration(id=digest(user.username),
                                   user_id=user.id,
                                   expiry=expiry,
                                   confirmed=False)
            session.add(reg)

        return reg.id

    def set_password(self, request, user, password):
        '''Set a new password for user
        '''
        with request.app.odm().begin() as session:
            user.password = self.password(password)
            session.add(user)
        return user

    def confirm_auth_key(self, request, key):
        odm = request.app.odm()
        with odm.begin() as session:
            reg = session.query(odm.registration).get(key)
            if reg:
                session.delete(reg)
                return True

    @cached(user=True)
    def get_permissions(self, request):
        odm = request.app.odm()
        user = request.cache.user
        perms = {}
        with odm.begin() as session:
            if user.is_authenticated():
                session.add(user)
                groups = set(user.groups)
            else:
                cfg = request.config
                query = session.query(odm.group)
                groups = set(query.filter_by(name=cfg['ANONYMOUS_GROUP']))
            for group in groups:
                perms.update(((p.name, p.policy) for p in group.permissions))
        return perms
Пример #30
0
class CsrfBackend(AuthBackend):
    '''A backend for Cross-Site Request Forgery prevention.

    Can be used on a session backend.
    '''
    _config = [
        Parameter('CSRF_EXPIRY', 60 * 60,
                  'Cross Site Request Forgery token expiry in seconds.'),
        Parameter('CSRF_PARAM', 'authenticity_token',
                  'CSRF parameter name in forms')
    ]
    REASON_BAD_TOKEN = "CSRF token missing or incorrect"
    CSRF_SET = frozenset(('GET', 'HEAD', 'OPTIONS'))

    def on_form(self, app, form):
        '''Handle CSRF on form
        '''
        request = form.request
        param = app.config['CSRF_PARAM']
        if (param and form.is_bound and request.method not in self.CSRF_SET):
            token = form.rawdata.get(param)
            self.validate_csrf_token(request, token)

    def on_html_document(self, app, request, doc):
        if request.method in self.CSRF_SET:
            cfg = app.config
            param = cfg['CSRF_PARAM']
            if param:
                csrf_token = self.csrf_token(request)
                if csrf_token:
                    doc.head.add_meta(name="csrf-param", content=param)
                    doc.head.add_meta(name="csrf-token", content=csrf_token)

    # CSRF
    def csrf_token(self, request):
        if not jwt:  # pragma    nocover
            raise ImproperlyConfigured('JWT library not available')
        session = request.cache.session
        if session:
            expiry = request.config['CSRF_EXPIRY']
            secret_key = request.config['SECRET_KEY']
            return jwt.encode(
                {
                    'session': session.get_key(),
                    'exp': time.time() + expiry
                }, secret_key)

    def validate_csrf_token(self, request, token):
        if not jwt:  # pragma    nocover
            raise ImproperlyConfigured('JWT library not available')
        if not token:
            raise PermissionDenied(self.REASON_BAD_TOKEN)
        try:
            secret_key = request.config['SECRET_KEY']
            token = jwt.decode(token, secret_key)
        except jwt.ExpiredSignature:
            raise PermissionDenied('Expired token')
        except Exception:
            raise PermissionDenied(self.REASON_BAD_TOKEN)
        else:
            if token['session'] != request.cache.session.get_key():
                raise PermissionDenied(self.REASON_BAD_TOKEN)