Turbogears authentication over mongodb users database

amol | March 3rd, 2010 | Software Development | Comments

As we saw that there isn’t a lot of documentation around about how to perform authentication in turbogears over mongodb we decided to create a simple code snippet and public it here to help people trying to obtain the same thing.

This is mainly a proof of concept and is quick and dirty way to obtain it. You will probably have something like ming as your model, instead of directly accessing mongo.

This code also validates password over the clear text one, you will probably have hashed passwords in your database, so remember to change validate_password method as required

To make it work you will have to place this code inside your config.app_cfg, it also expects you to have you database exposed as db inside your model

from my_app.model import db
from zope.interface import implements
from repoze.who.interfaces import IAuthenticator, IMetadataProvider
from repoze.who.plugins.friendlyform import FriendlyFormPlugin
from repoze.who.plugins.auth_tkt import AuthTktCookiePlugin
from repoze.who.middleware import PluggableAuthenticationMiddleware
 
def validate_password(user, password):
   return user['password'] == password
 
class MongoAuthenticatorPlugin(object):
    implements(IAuthenticator)
 
    # IAuthenticator
    def authenticate(self, environ, identity):
        if not ('login' in identity and 'password' in identity):
            return None
 
        login = identity.get('login')
        user = db.users.find_one({'user_name':login})
        if user and validate_password(user, identity.get('password')):
            return identity['login']
 
class MongoUserMDPlugin(object):
    implements(IMetadataProvider)
 
    def add_metadata(self, environ, identity):
        user_data = {'user_name':identity['repoze.who.userid']}
        identity['user'] = db.users.find_one(user_data)
 
class MyAppConfig(AppConfig):
    auth_backend = 'sqlalchemy' #this is a fake, but it's needed to enable
                                #auth middleware at least on TG2.0
 
    login_url = '/login'
    login_handler = '/login_handler'
    post_login_url = None
    logout_handler = '/logout_handler'
    post_logout_url = None
    login_counter_name = None
 
    def add_auth_middleware(self, app, skip_authentication):
        cookie_secret = pylons_config.get('auth_cookie_secret', 
                                          'myapp_adsfsdfh3423')
        cookie_name = pylons_config.get('auth_cookie_name', 
                                        'myapp_auth')
 
        who_args = {}
 
        form_plugin = FriendlyFormPlugin(self.login_url,
                              self.login_handler,
                              self.post_login_url,
                              self.logout_handler,
                              self.post_logout_url,
                              login_counter_name=self.login_counter_name,
                              rememberer_name='cookie')
        challengers = [('form', form_plugin)]
 
        auth = MongoAuthenticatorPlugin()
        authenticators = [('mongoauth', auth)]
 
        cookie = AuthTktCookiePlugin(cookie_secret, cookie_name)
 
        identifiers = [('cookie', cookie), ('form', form_plugin)]
 
        provider = MongoUserMDPlugin()
        mdproviders = [('mongoprovider', provider)]
 
        from repoze.who.classifiers import default_request_classifier
        from repoze.who.classifiers import default_challenge_decider
        log_stream = None
 
        app = PluggableAuthenticationMiddleware(app,
                                          identifiers,
                                          authenticators,
                                          challengers,
                                          mdproviders,
                                          default_request_classifier,
                                          default_challenge_decider)
 
        return app
 
base_config = MyAppConfig()
base_config.renderers = []
 
base_config.package = my_app
 
#Set the default renderer
base_config.default_renderer = 'genshi'
base_config.renderers.append('genshi')
base_config.renderers.append('json')
 
#Configure the base SQLALchemy Setup
base_config.use_sqlalchemy = False
base_config.model = my_app.model

Tags: , ,

ACR gets Slice Templates

amol | March 1st, 2010 | Web | Comments

ACR is a flexible and quite powerfull CMS library, but users have to learn Slices and Slicegroups to be able to insert more advanced content like photo galleries, videos and a news section. To simplify this process we created “Slice Templates”.

Slice Templates are actually a set of common ways to use slices to insert more advanced content. The first two slice templates implemented are:

  • Youtube Videos which make easy to insert a youtube video inside an ACR Page.
  • Photo Gallery which makes easy to insert a photo gallery with cool effects inside an ACR Page.

Next template to come will be a news section, for now you can upgrade your libACR and start using the templates feature or take a look at the screenshots of the currently implemented templates

Tags: , ,

Remote desktop, meet multimedia; school, meet remote desktop

lu_zero | February 17th, 2010 | Opensource | Comments

Recently we got contacted about crafting some kind of solution for remote participation to school lesson. Hospitalized students may have hard time catching up and the current technologies, even the overpriced and underused “interactive blackboards” may help a bit in the picture.

What’s an “interactive blackboard” ? It is more or less a projector and any kind of tracking pointer, usually the IR flavour you can see in wide use through the Nintendo Wii. Not exactly a breakthrough it’s something you could craft with about 50e of components and any price for a projector (like the relatively inexpensive and highly portable ones from 3m). You might have some “value added software” that give you an UI that is more “blackboardish” than your standard desktop but that’s all.

How is it used during lessons? Pretty much like a normal blackboard, worst case you have a dumb teacher feeding his poor students dull slides made not so well.

That said it gets pretty easy think about a way to keep the hospitalized student and the rest of the class linked: put a remote desktop solution (nx, vnc, whatever) on the system wired to the blackboard and arrange some controls so that the teacher could give and take the “chalk” to the remote student.

Simple enough isn’t it?

Problems:

- What if the teacher would like to see and heard the remote student?

Well there is plenty of streaming solutions (I’m eyeing sip-communicator currently since they really put a great show at Fosdem, but ekiga or skype could do as well).

- What if the teacher starts to use the “interactive board” to show a DVD and wants the remote student enjoy it?

Ok, there we have a problem, having a large surface updated quite often and asking to have a _good_ quality and expecting the remote student having just a wireless link like umts, edge, gprs is getting really painful.

There are some solutions that have some heuristics in place to discover when a surface is holding a video and they try to compress using some not-so-lossy and quite-enough-low-delay. A bit suboptimal but should work somehow. I wonder if somebody has already thought about harnessing XV, XvMC and libVA capabilities and try to wire the not so fully decoded bitstream this way. Given you have a vaapi implementation on both endpoint and the right codec you may get a perfect movie and probably also spare some bandwidth. If I’ll have time probably I’ll try to have a proof of concept using the efikamx as endpoint, given it will get a vaapi bridget to it’s hardware accelerators.

For the audio you can compress it quite well w/out many complaints and wiring it from a desktop to another is relatively easy (hi, pulse!).

So I already described some months of work, now the last problem:

- What if I want many remote students interact with the same class and blackboard?

Ops. Given the class may have a link that’s no better than umts as well if we are talking about bare remote desktop might be feasible

If we could cut the video feeds and keep just the voices of the remote students we could still survive with 3-4 at most

If we want them to enjoy the video the teacher is about to show to the classe then… we need something else, completely. The whole blackboard&such software could stay better on a server with enough bandwidth and cpu to serve all the remote nodes with ease. Also the class could use a thin client wired to the interactive blackboard and more or less everybody could be happy. Sadly such technologies aren’t that ready. There is spice that’s quite promising, but not ready yet.

That’s all for now, I spent enough time rambling. We’ll see if this “cloud”y ideas will end in an implementation or not. And I haven’t started yet thinking about which software would run on this contraption… Anybody has a any experience with educational software for middle/high schools?

Tags: , , , , ,

Turbogears Glossom finally live

amol | January 31st, 2010 | Web | Comments

We started to collaborate with the Glossom project more than an year ago, the first version was a Ruby on Rails prototype and has served well thousand of users for about an year. When the Glossom team decided to rewrite the software to move from a prototype to a more complete software we studied which frameworks were available and finally decided for Turbogears2.

Turbogears is a quite complete and really flexible framework, we used it since version 1.0 for about 3 years and the more we used it the more we loved it. It might have its problems but differently from other solutions when the framework has a limit it is really easy to bypass the framework and implement your own solution without any hack and with a clean way. Turbogears developers really focused on letting your tune each component in any way, and even totally replace it with something else if you don’t like it.

After six months of development the application has finally gone live and is now serving ~10000 registered users with its servers based on an apache load balancer, mod_wsgi turbogears application servers and mysql database servers.

So welcome to Glossom and thank you to Turbogears team for all the help!

We also have to say thank you to FFmpeg for now converting our videos and FlyPDF for generating our PDFs! :D (you can download FlyPDF from sourceforge if you want to give it a try)

Tags:

Successor to cloud computing, aka tweelter new architecture

amol | January 20th, 2010 | Web | Comments

When you have to perform a real big amount of operations you have two options

  • Increase your computational power (like using a cloud solution or scale on more servers)
  • Move your computations to the most available cloud platform of the world: your users
To improve tweelter performances and avoid overloading twitter API we are studying a new computational architecture for tweelter which can return results to the user faster and give less overhead to our servers.
The key to achieve the result is to move most of the search overhead to the computers of the other users currently viewing tweelter, like SETI@home does, by using tweelter you would speed up other users searches and also your own searches.

Tags: ,

Tweelter, the twitter filter

amol | December 5th, 2009 | Web | Comments

While speaking with the top-ix people during a meeting we started to talk about the need of a way to filter out “noise” from twitter searches.

Probably everyone found that searching something on twitter returns a big list of retweets and duplicated tweets. As those reduce the ability to follow a discussion or an event on twitter they are usually more a problem than a useful result.

At the end of that meeting Tweelter was born.

Tweelter is a twitter search engine which filters out duplicated entries, retweets and permits to search results older than one month on most followed topics. More interesting thing is that tweelter performs those search in a parallel manner and on a distributed mongodb. While retrieving all the results of the same search using the twitter api would require more then 10-20 seconds by using tweelter you will get the same results in 2-3 seconds and the more a search is performed the faster it gets.

So give tweelter a try if you need to follow a discussion on twitter, it might help you to follow the discussion in an easier manner.

Tags: ,

Rehearsing new ACR look and feel

amol | November 24th, 2009 | Opensource, Web | Comments

As some turbogears projects are starting to use ACR as their CMS library we received the first few requests by real users and the most prominent one is to have a better administrative section. Currently administration section is implemented by using the great tgext.admin and sprox, even if those are really good to quickly implement a CRUD section they might not couple very well when a more interactive and advanced user experience is required.

So a transition phase that will end with a totally new administration section for ACR has been started, currently the system implements a new user interface still using the same backend as before to handle the operations, but on the long time the backend itself will be rewritten to handle easier contents creation and management. In the mean time also support for multi-language, versioning and authors has been added.

Tags: , ,

Injecting static content in TurboGears

amol | November 21st, 2009 | Web | Comments

Something that you usually need to do when providing a library or a reusable wsgi application is installing static data with the library itself.

This can be quickly performed by adding something like

package_data = {”:['*.html', '*.js', '*.css', '*.png']}

to your setup.py

But then how can we let our turbogears application serve that?

  • For html files (genshi templates) the solution is quite simple, you can just expose them by using @expose(’librarypackage.templatesdir.template’). For example supposing we are installing libcool with its templates in libcool/templates you can do @expose(’libcool.templates.index’)
  • For js and css files you can add them to your pages by creating a tw.api.JSLink or tw.api.CSSLink object. Just create inside your library something like: cool_js = tw.api.JSLink(modname = __name__, filename = ’static/cool.js’) and then place in the controller exposing the view where you want to use that js file cool_js.inject()
  • Exposing images can be more complex, you have to declare a widget which will render the img tag by using ToscaWidgets resources exposure.
    class IconLink(tw.api.Link):
        """
        A link to an icon.
        """
        template = """<img src="$link" alt="$alt" />"""
    
        params = dict(alt="Alternative text when not displaying the image")
    
        def __init__(self, *args, **kw):
            super(IconLink, self).__init__(*args, **kw)
            self.alt = kw.get('alt')

    then you can create one IconLink for each icon in your library with something like: parent = IconLink(modname=__name__, filename=’static/icons/parent.png’, alt=’Up’) and inside your views you can place the icon by doing ${parent.display()} . This will add the image by exposing it from inside the static directory of your library package. Remember that you need to add an __init__.py inside the static directory and its subdirectory if you want setuptools to correctly install the static files.

Tags: , ,

Syslog(3)

lu_zero | November 8th, 2009 | Uncategorized | Comments

Recently Diego complained with me about the mod_accesslog I quickly drafted for Feng.

I didn’t check much about supporting bare files log but I just used syslog since that’s what I use for all the services that support it. Luckily he fixed the glitches I left since his usage patterns are quite different than mine.

Bare file logging usually is used by default in certain applications mostly because:

  • You want to keep per-usage/per-user/per-deploy logs (think certain apache deploys)
  • Your application doesn’t support syslog at all
  • You didn’t knew about syslog and/or your logger daemon is a pain to configure
  • You are fond of logrotate and/or you like to get your disk full of historic data

Having syslog based logging usually has some disadvantages over bare file just because you have to configure both the logger and the application, but gets quite handy when you need to tune all the logs in particular ways like sending them over the network or having the server automatically notify critical issues over email.

I really dislike bare file logging, mostly because I’m quite fond of metalog (so I’m not afraid of configuring my logger) and while deploying gluster for Stack! Studios render farm I really hated having those stupid bare files around while the rest of the well behaving applications would had their log correctly routed from the storage nodes to the almost centralized logging facility.

Having proper centralized logging is surely useful when you have to admin a system with a large number of applications, but for a big and increasing number of nodes it gets a boon.

Moreover if you plan to have read-only netbooted root images and almost zero local storage (more on the crazy solution I’m baking with bartek at Stack! could appear sooner or later) you really start to love it (and have a love-hate relationship with syslog-ng for its less than crystal clear documentation)

Using SwfUpload with TurboGears 2

amol | October 10th, 2009 | Web | Comments

SwfUpload doesn’t permit to upload things through authenticated methods, this is because it doesn’t pass the cookies needed to identify your users.

Partly this problem can be solved by using swfupload.cookies.js plugin. This plugins fetches all your cookies and passes them as POST arguments. This way you can get your authtkt cookie and use it to identify your user.

from webob.exc import *
from paste.auth import auth_tkt

if kw.has_key('authtkt'):
    #by default it is usually configured to do not use the remote address
    #otherwise you can fetch it from request.environ['REMOTE_ADDR']
    remote_addr = '0.0.0.0'

    #cookie secret is usually defined in your config/app_cfg.py
    #as base_config.sa_auth.cookie_secret or in your development.ini
    cookie_secret = "some_random_string_like_BQQP+BeyrTzTHClBCEdW"

    try:
        data = auth_tkt.parse_ticket(cookie_secret,
                                      kw.get('authtkt'),
                                      remote_addr)
        username = data[1]
        user = DBSession.query(User).filter_by(username=username).one()
    except:
        raise HTTPBadRequest

filename = kw['Filename']
file = kw['Filedata'].file

By using this code you can fetch the user that is uploading the file. This requires the method to do not use @require decorator to check for user permissions, as you will know the user only after entering the method. But you can create your own predicate if you really want to use @require.

Tags: , ,

Search