Ir al contenido principal

Ralsina.Me — El sitio web de Roberto Alsina

Publicaciones sobre programming (publicaciones antiguas, página 8)

Authenticated Pages in CherryPy

Cher­ryPy is a cool, python­ic, sim­ple, quick, fun way to write web ap­pli­ca­tion­s.

I of­ten use Cher­ryPy to write cus­tom web ad­min tools for cus­tomer­s. Sup­pose you want to pro­vide them with a sim­ple way for pass­word man­age­men­t. Usu­al­ly I have the fol­low­ing re­quire­ments:

  • It must be sim­­ple ( not we­b­min )

  • It must not be a ter­mi­­nal ses­­sion (bye ssh :-( )

  • It must not be a graph­i­­cal ses­­sion (sad­­ly, that leaves out PyQt :-( )

  • It needs to do cus­­tom stuff: set the sam­­ba pass­­word at the same time, send a mail warn­ing about the next forced change, what­ev­er.

Some­day I may be able to use a sin­gle-app freeNX ses­sion, but right now that's a bit too much prob­lem for dif­fer­ent rea­son­s.

So, I wrote a Cher­ryPy page. Over time, I have be­come quite fond of it, and wrote a bunch of small tools around it. One of them was a way to lo­gin the us­er in­to the site us­ing the sys­tem's users and pass­word­s. Now I got to throw it away :-)

The new Cher­ryPy 2.1 has a mech­a­nism for im­ple­ment­ing pass­word-pro­tect­ed pages, called the Ses­sion au­then­ti­cate fil­ter which is sad­ly not doc­u­ment­ed yet any­where I can find.

So, here is my at­temp­t, so peo­ple googling it up can use it. Ex­cuse me:

cher­rypy ses­sio­n­au­then­ti­cate­filter cher­rypy ses­sio­n­au­then­ti­cate­filter cher­rypy ses­sio­n­au­then­ti­cate­filter cher­rypy ses­sio­n­au­then­ti­cate­filter cher­rypy ses­sio­n­au­then­ti­cate­filter cher­rypy ses­sio­n­au­then­ti­cate­filter cher­rypy ses­sio­n­au­then­ti­cate­filter cher­rypy ses­sio­n­au­then­ti­cate­filter cher­rypy ses­sio­n­au­then­ti­cate­filter cher­rypy ses­sio­n­au­then­ti­cate­filter

That should do it :-)

What you need first is a func­tion that takes a user­name and pass­word, and re­turns None on suc­cess, or an er­ror mes­sage for the fail­ure.

For example, I can adapt something I wrote earlier using check­pass­word-­pam

def validPass(name,password):
                cmd='/usr/bin/checkpassword-pam -s xdm -- /bin/true 3<&0'
                p=os.popen(cmd,'w')
                s='%s\000%s\000xxx\000'%(name,password)
                print cmd,s
                p.write(s)
                r=p.close()
                if r==None: #Success
                        return None
                else:
        return "Login Incorrect"

Al­so, you may want a func­tion that re­turns the lo­gin screen. If you do, re­mem­ber the fol­low­ing:

  1. It must set the form ac­tion to doLo­gin

  2. The us­er field should be called lo­gin

  3. The pass­word field should be called pass­word

  4. You will take a fromPage ar­gu­ment that you should pass through, so the us­er will end on the page he wants.

  5. You will take a er­rorMsg ar­gu­ment which is prob­a­bly the re­sult of a failed pre­vi­ous lo­gin. Dis­play it red or some­thing like it. Un­less it's emp­ty, in which case it should not be vis­i­ble.

Here's mine.

def loginScreen(fromPage, login = '', errorMsg = ''):
content="""
<form method="post" action="doLogin">
<div align=center>
        <span class=errormsg>%s</span><p>
        <table >
        <tr>
        <td>
                Login:
        <td>
                <input type="text" name="login" value="%s" size="40"/>
        <tr>
        <td>
                Password:
        <td>
        <input type="password" name="password" size="40"/>
        <input type="hidden" name="fromPage" value="%s"/>
        <tr>
        <td colspan=2 align=right>
        <input type="submit" value="Login" />
        </table>
        </div>
</form>
""" % (errorMsg, login, fromPage)
title='Login'
return renderTemplate(file='logintemplate.html')

Al­though I am us­ing a tem­plate to dis­play it nice­ly and with the right style, it should be pret­ty ob­vi­ous how it work­s.

You could use the de­fault lo­gin screen pro­vid­ed by the fil­ter. While it work­s, it's just ug­ly.

Then you need to ap­ply the fil­ter to the set of your pass-pro­tect­ed pages. Sup­pose you want the whole site to be pro­tect­ed, ex­cept for your /stat­ic di­rec­to­ry, which con­tains the stylesheet, im­ages and such. Then you put this in your con­fig­u­ra­tion file:

[/]
sessionAuthenticateFilter.on=True

[/static]
sessionAuthenticateFilter.on=False

Next thing is to hook the ses­sion au­then­ti­cate fil­ter to your cus­tom auth code. In your ap­p, do the fol­low­ing. It seems that you can't do this in the con­fig file, though, so do it in code.

    settings={
            '/': {
                                    'sessionAuthenticateFilter.checkLoginAndPassword': validPass,
                'sessionAuthenticateFilter.loginScreen':loginScreen
        }
}
cherrypy.config.update(settings)

And that's it. Now your site is pass­word pro­tect­ed. You can even have dif­fer­ent au­then­ti­ca­tion schemes for dif­fer­ent pieces of the site, by re­set­ting the hooks for the fold­er you pre­fer to a dif­fer­ent func­tion.

Al­so, I think this is a good ex­am­ple of why I like Cher­ryPy. This mech­a­nism is both flex­i­ble, pow­er­ful and sim­ple.

Small Linux Revisited

A Lit­tle His­to­ry

Many moons (al­most two years!) ago, I wrote an ar­ti­cle called Small Lin­ux de­tail­ing what I had done to make a rea­son­able Lin­ux fit in a Toshi­ba Li­bret­to 50.

That's a very lim­it­ed note­book, with un­der 800MB of disk, a 75Mhz Pen­tium CPU and 16MB of RAM, and it has served me well for a long time.

Now, how­ev­er, I am us­ing the al­most ex­act op­po­site, a sec­ond-­hand Toshi­ba Satel­lite 1955-S805.

Where Salma (the Li­bret­to) had a 640x480 screen, Mon­ty (Toshiba), has a 16" 1280x1024. The RAM has in­creased 32 times. But they have one thing in com­mon....

The 800MB HD

You see, Mon­ty is sec­ond hand. My fu­ture moth­er-in-law and broth­er-in-law brought it from New York when they vis­it­ed, for Rosario (My fu­ture wife, un­til Feb­ru­ary 18 2006 ;-).

And it had a bro­ken HD. And I want­ed to use it while I got a nice new 60GB one.

So, over­com­ing my fear of de­stroy­ing ex­pen­sive equip­men­t, I got the HD out of Salma and in­to Mon­ty, and start­ed think­ing....

The Tallest Guy In The World

He had a prob­lem: re­al­ly bad feet. He died of it, too. In the same way, Mon­ty now boot­ed, but the app se­lec­tion was out­dat­ed, and re­al­ly, lots of things Salma could­n't do, Mon­ty could.

What on earth can one in­stall on that disk when you don't have any oth­er re­al hard­ware lim­i­ta­tion­s?

The choice of dis­tri­bu­tion was trick­y.

I am a Cen­tOS guy late­ly, but the pack­age se­lec­tion is en­tan­gled enough that you can hard­ly get X in­stalled with­out cross­ing the 800M­B. The min­i­mal in­stall is about 450M­B.

De­bian again? Well... no.

Knop­pix?

Now, that has some se­ri­ous po­ten­tial, since I could run the OS from DVD/CD, and then use the whole 800MB for da­ta. But I want­ed some­thing where I could choose what to in­stal­l.

I could have gone the path of one of the mod­u­lar Knop­pix deriva­tives, but it was yet an­oth­er task on the pile.

So, I went with­.... ARCH.

ARCH Is Arch

Yes, ARCH is saucy. It in­stalls in rough­ly 200M­B, in­clud­ing ker­nel sources and GC­C. That's quite smal­l.

I man­aged to cre­ate a rea­son­able desk­top in about 550M­B, in­clud­ing:

Scite:

A nice text ed­i­tor

Python:

Need­ed it to work in a few prog­gies.

Firefox:

I have the RAM. The CPU is a 2.56 P4.

Xorg 8.2 with Nvidia drivers:

And just for kick­s, 3d­desk­top to see if they work ;-)

fluxbox:

I know it, and it's nice enough.

putty:

Nicer than xter­m, and has a handy SSH builtin.

ROX Filer:

Not re­al­ly all that use­ful, but what the hel­l, for 3MB you get side­bars, a file man­ag­er and a few ex­tra trick­s.

Slim:

A very nice xdm re­place­men­t. Spe­cial­ly with the mind­lock theme :-)

upx:

Com­press the ex­es. Save 30M­B. Good.

CherryPy:

It's what I am work­ing with. And it's on­ly 74K­B.

habak:

Sim­ple, small tool to set the X root dec­o­ra­tion.

rsync:

Stay synced with my old­er desk­top.

All in­clud­ed, I am at 120 pack­ages, us­ing 557MB of disk (with ex­ten­sive trim­ming, see the orig­i­nal ar­ti­cle for some ex­am­ples).

So, what's the dif­fer­ence be­tween this set of apps and my pre­vi­ous choice....

Well, look at the re­sult of free:

             total       used       free     shared    buffers     cached
Mem:        512544     408924     103620          0      33468     162916
-/+ buffers/cache:     212540     300004
Swap:            0          0          0

Just for laugh­s: here's the old one, when do­ing rough­ly the same things: edit­ing an ar­ti­cle, brows­ing the we­b, a few ter­mi­nal­s:

                total    used    free    shared   buffers        cached
Mem:            14708   14144     564      4644       816          5304
-/+ buffers/cache:       8024    6684
Swap:           47992   18880   29112

Scary is­n't it? I am us­ing rough­ly 25 times the amount of mem­o­ry I used on the li­bret­to. It's easy to see why, tho.

Con­sid­er the desk­top. It shows a pret­ty pic­ture. It is 1280x1024. It is in mil­lions of col­ors. That is in RAM. That is ei­ther 3932160 or 5242880 bytes. On the li­bret­to, I was in­ten­tion­al­ly not us­ing any­thing there :-)

So, it re­al­ly is not com­pa­ra­ble any­way, and Mon­ty's life as a mal­formed box will be short. But it was quite a bit of fun :-)

Not letting stuff fall off the ' net

For a bunch of apps I write, I of­ten want to be able to add a systray icon.

But... I write them us­ing PyQt, and the systray stuff is in PyKDE.

But... Torsten Marek did write a mod­ule to do that. The on­ly prob­lem for me is the python-c­types re­quire­men­t, but it's no big deal for my apps that are not mas­sive­ly de­ployed.

You can find his code, in a some­what man­gled for­m, here

And since build­ing ex­ten­sion mod­ules is not com­plete­ly triv­ial, here's a sim­ple set­up.py that will do it:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from distutils.core import setup
from distutils.extension import Extension

setup(
  name = "systray",
  ext_modules=[
    Extension('traywin', ['traywin.c'],  libraries=["X11"],library_dirs=['/usr/X11R6/lib'])],
)

Put it in the same folder with his code, then you can do python setup.py install or somesuch, then you can use it in your app like in Torsten's systray2.py example, and it will work.

Data aware widgets in KDE

Well, read­ing in plan­etkde about how nice da­ta aware wid­gets would be, I have to say this:

  • Da­­ta aware wid­gets are great

  • Da­­ta aware wid­gets in C++ are not the best pos­si­ble so­lu­­tion

Us­ing a high­er lev­el lan­guage, and specif­i­cal­ly a more dy­nam­ic lan­guage makes lots of things much sim­pler.

As a tiny, lame ex­am­ple, please check the lit­tle thing I wrote about da­ta aware wid­gets in python here.

I am sure that some of our bet­ter pro­gram­mers (or more cre­ative thinker­s) can come up with awe­some stuff if they di­vorce from C++ in this sub­ject :-)

Extreme code reuse

I am, as al­ways, play­ing with stuff. And I was faced with a prob­lem I must have solved a dozen times be­fore:

Giv­en a list of items with ob­vi­ous hi­er­ar­chi­cal names (say, a list of fold­er­s), turn it in­to a rea­son­able da­ta struc­ture.

Since there are not all that many names, there is no need to do it on-de­mand, or any­thing like that.

I must con­fess I suck at this kind of things be­cause I hve to ac­tu­al­ly think them through. I don't know how to do this kind of things.

Mind you, I have done it be­fore, but I said, hey, maybe google can help me...

And yeah! Python code from 1994 that does ex­act­ly what I need­ed. I had to touch a sin­gle line ( string.s­plit­field­s(a,'.') to a.s­plit('/') ) and it worked.

The In­ter­net nev­er for­get­s!


Contents © 2000-2024 Roberto Alsina