Installation

python-spresso is available on PyPI.

pip install python-spresso

Usage

The following examples only shows how to instantiate the providers. It is not a working example as site adapter implementations for the Identity Provider are missing. Take a look at the examples directory.

Example Settings

from wsgiref.simple_server import make_server

import spresso

# Create the controller.
provider = spresso.Settings()

provider.add_grant(spresso.ForwardAuthenticateGrant())
# Wrap the controller with the WSGI adapter
app = spresso.wsgi.ProviderApplication(provider)

if __name__ == "__main__":
    httpd = make_server('', 8080, app)
    httpd.serve_forever()

Example Identity Provider

from wsgiref.simple_server import make_server

import spresso

class LoginSiteAdapter(spresso.LoginSiteAdapter):
    TEMPLATE = '''
        <form id='loginform' onsubmit="getIdentityAssertion(); return false;">
            Email Address: <span id="email_placeholder"></span><br>
            Password:<input type="password" id="password">
            <button type="submit">Log In</button>
        </form>
    '''

    def authenticate_user(self, request, response, environ):
        # Return user email from session
        pass

    def render_auth_page(self, request, response, environ):
        response.body = self.TEMPLATE
        return response


class SignSiteAdapter(spresso.IdentityProviderSignSiteAdapter):
    def authenticate_user(self, request, response, environ):
        # raise spresso.error.UserNotAuthenticated("message") Exception
        # if the user could not be authenticated locally.
        # POST parameter are accessible through the request object:
        # request.post_param('email'), request.post_param('password'))


login = LoginSiteAdapter()
sign = SignSiteAdapter()

# Create the controller.
provider = spresso.Settings()

provider.add_grant(
    spresso.IdentityProviderAuthenticationGrant(
        login_site_adapter=login,
        signature_site_adapter=sign
    )
)

# Wrap the controller with the WSGI adapter
app = spresso.wsgi.ProviderApplication(provider)

if __name__ == "__main__":
    httpd = make_server('', 8081, app)
    httpd.serve_forever()

Example Relying Party

from wsgiref.simple_server import make_server

import spresso

sessions = dict()
authenticated_sessions = dict()


class IndexSiteAdapter(spresso.IndexSiteAdapter):
    TEMPLATE = '''
        authenticated_sessions: {}<br>
        <form onsubmit="startLogin(); return false;">
            <input id="email_input" value="" required autofocus>
            <button type="submit">Login</button>
        </form>
    '''

    def render_auth_page(self, request, response, environ):
        # retrieve cookie and get session from user
        response.body = self.TEMPLATE.format(authenticated_sessions)
        return response


class StartLoginSiteAdapter(spresso.StartLoginSiteAdapter):
    def save_session(self, session):
        sessions.update(session)


class RedirectSiteAdapter(spresso.RedirectSiteAdapter):
    def load_session(self, key):
        return sessions.get(key)


class LoginSiteAdapter(spresso.LoginSiteAdapter):
    def load_session(self, key):
        return sessions.get(key)

    def save_session(self, session):
        authenticated_sessions.update(session)

    def authentication_callback(self):
        print('User is logged in')


index = IndexSiteAdapter()
start_login = StartLoginSiteAdapter()
redirect = RedirectSiteAdapter()
login = LoginSiteAdapter()
# Create the controller.
provider = spresso.RelyingPartyAuthenticationSettings()

provider.add_grant(
    spresso.RelyingPartyAuthenticationGrant(
        index_site_adapter=index,
        start_login_site_adapter=start_login,
        redirect_site_adapter=redirect,
        login_site_adapter=login
    )
)

# Wrap the controller with the Wsgi adapter
app = spresso.wsgi.ProviderApplication(provider)

if __name__ == "__main__":
    httpd = make_server('', 8082, app)
    httpd.serve_forever()

Site adapter

python-spresso does not define how you identify a user or show a confirmation dialogue. Instead your application should use the API defined by spresso.controller.grant.authentication.SiteAdapter.

Extendability

Provider WSGI applications can be wrapped with other applications. This can be achieved by using classes from the werkzeug python package.

Additionally a PathDispatcher is available, that first checks the Provider application and then a default application.

# Path prefix based dispatching
app = DispatcherMiddleware(provider_app, {
    '/app': app
})

run_simple('localhost', 5000, app)


# Path based dispatching
app = PathDispatcher(flask_app, provider_app)