Authentication

If we take a look at how some Enamel class is defined with authentication we notice the indexPage and loginPage instance variables defined.

class AuthDemo(enamel.Enamel):
    indexPage = Index
    loginPage = pages.Login
    storage = SQLStorage('sqlite:///test.db')
    anonymousAccess = False
    authenticator = authentication.DatabaseAuthenticator

With anonymousAccess turned off (set to False) the loginPage is returned by the realm when no Avatar is found. This logic is found in the Realm object (realm.py Realm)

class Realm(object):
    # <snip>
    def requestAvatar(self, avatarId, mind, *interfaces):
        for iface in interfaces:
            if iface is inevow.IResource:
                if avatarId is checkers.ANONYMOUS:
                    if self.enamel.anonymousAccess:
                        avatarId = self.enamel.avatar()
                        res = self.enamel.indexPage(avatarId, self.enamel)
                    else:
                        res = self.enamel.loginPage(None, self.enamel)
                    res.realm = self
                    return (inevow.IResource, res, noLogout)
                else:
                    # on login pass to the default first page
                    res = self.enamel.indexPage(avatarId, self.enamel)
                    res.realm = self
                    return (inevow.IResource, res, res.logout)

        raise NotImplementedError, "Can't support that interface."

The Realm is the "heart" of Nevow Guarded authentication, which decides what resources are handed back to the client based on what the Credentials interface returns as the avatarId. If no avatarId is returned, this means authentication has not happened. In the case of anonymous access we hand back a dummy avatarId with default instantiation instead of creds.ANONYMOUS. This anonymous avatarId will then be overridden when valid authentication takes place.

In an anonymous access situation it's important to create a child somewhere to access the login page. In the testSQL example (Enamel class shown above) the indexPage is defined as follows

class Index(pages.Standard):
    # ...
    childPages = {
        'login': pages.Login,
        'addUser': CreateUser
    }
    # ...

Here a default instance of enamel.pages.Login is attached as a child and can be accessed as http://someserver/login/ to perform authentication. There is no default login child.

In a normal operational case the CreateUser? page class should throw an error if an attempt is made to access it without a valid avatarId.