We should pity the poor application writers, for they face an impossible battle: after they've strived long and hard to work with Kerberos v4, we suddenly change to Kerberos v5. Oh, wait, I mean the work long and hard to support HTTPS, and now we come along and say that ain't good enough: you need to support this "Pubcookie" thing.
Building a web application for use outside of your own environment is challenging. Heck, building an application inside of most of our environments is fairly challenging if you want it to be secure and easy to use. Application writers have their hands full understanding their (presumably hard) problem; they shouldn't need to understand the vagarities of all of the different WebISO solutions as well.
Some of the WebISO systems that application writers might wish to integrate with include:
Meanwhile, let's think about the evil people from the previous story who are constantly changing site requirements: they're trying to make a complete system that meets all of their users. Having the ability to customize the authentication components of the applications in the same way would be a tremendous boon.
A programming API for WebISO is a big challenge, since we want it to be similiar across many different programming languages and environments but not use "unnatural" constructs for each environment.
The general idea behind this proposed API is it's asynchronous nature:
Also important is the fact that requests are idempotent: the same request can be made multiple times by a web application, and the WebISO should perform the minimal work necessary to answer any given query.
If an application can support cookies, it should register two functions with the authentication layer:
typedef void set_cookie(string name, string value, string scope, string expires); typedef string get_cookie(string name); typedef string get_post_argument(string name); typedef string get_get_argument(string name); void callback_cookie_funcs(set_cookie *S, get_cookie *G); void callback_getargs_funcs(get_post_argument *GP, get_get_argument *GG);
To invoke the authentication subsystem an application must construct a query object. This object represents what it wishes to know about the principal acting on it. It also contains some mechanical information, such as whether to require authentication (perhaps with a certain type of authentication?) or where the user should be returned to after authentication.
The application can also save some amount of state with the query that will be returned with every answer object.
void query_return_uri(query Q, uri URI); void query_require_authentication(query Q, string AuthType, boolean b); void query_require_reauth(query Q, boolean b); void query_save_opaque_state(query Q, string state); void query_get_attr(query Q, string attribute, boolean required); void query_acceptable(query Q, ...); /* xxx what is acceptable security or types of principals? */
Finally, the turnaround:
answer query_submit(query Q);
All answer objects can be asked for several things:
boolean answer_isComplete(answer A); /* this returns 'anonymous' if no principal has been authenticated or the application isn't allowed to know the principal name. */ principal answer_getPrincipal(answer A); /* merely returns the state that was given to the authentication API with the query */ string answer_getOpaqueState(answer A);
If isComplete returns true, the following will always work. Otherwise, an application may try them; some might work or give partial information.
string answer_getAuthType(answer A); /* many of these things won't be filled out unless "isComplete" is set */ string answer_getAttribute(answer A); session answer_getSessionHandle(answer A);
If isComplete returns false, the application needs to kick off something to find out answers. For WebISO solutions that use a central login server and redirects, answer_getRedirect() is used.
It would be possible to extend this to also support other schemes that don't, at their heart, rely on redirects, such as the SunONE Identity Server. This requires a request/response cycle, which would be possible but I haven't worked out all the details.
uri answer_getRedirect(answer A); /* this one will give a full HTTP and HTML response, so that all applications need not have the know-how of the magic redirect forms */ void answer_getRedirectPage(answer A, OUT string httpheaders, OUT string html);
In order to have any sort of sane application support, the format of principals must be discussed.
Sadly, principals are one of those things that have a lot of contention in them. Are they dns? Are they "like" e-mail addresses? Is a person uniquely mapped to a principal or is a principal uniquely mapped to a person or both or neither?
Clearly it is desirable (and probably required) that the principal object used by the generic WebISO API implement the JAAS java.lang.Principal interface.
boolean principal_isAnonymous(principal P);
group membership? yuck!
xxx what should a session be? a string? xxx how much session management should there be? how seperable is it from the rest of the architecture?
C++ or Java would map these objects to objects in the language; Perl might map them to a class; C to a struct.
This is a straight translation of the generic API into PHP. Since retrieving and setting cookies and form parameters is standardized in PHP, the callback registration functions aren't present.
WebISO systems would subclass these two classes for an implementation.
class WebisoAnswer { function isComplete(); function getPrincipal(); function getOpaqueState(); function getAuthType(); function getRedirect(); function getRedirectPage($outheaders, $outhtml); } /* WebisoQuery::submit() has the same restriction on calling as setcookie(). It must be called before any output is sent to the browser. See chapter 17 of the PHP manual for more information. */ class WebisoQuery { function return_uri($uri); function require_authentication($authtype, $required); function require_reauth($required); function save_opaque_state($state); function get_attr($attr, $required); function submit(); }
This is an example application written in PHP.
/* first make sure we have a PHP session */ /* check authentication information in a PHP session; if we haven't already associated an id with this session, we ask the WebISO system for authentication */ /* ok, examine the answer. do we need to do a redirect? */