1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275
|
WebLogin Page Flow
Introduction
WebLogin is the name for the component of WebAuth that handles user
authentication interaction. It is a CGI service that runs on the WebKDC
and presents HTML login forms, status pages, and handles translating
browser cookies into XML requests to the WebKDC and vice versa. See
doc/weblogin-config for full configuration and customization
documentation.
We want to support SPNEGO (and other authentication methods implemented
by other Apache modules) as a possible authentication mechanism for
users. However, attempting SPNEGO unconditionally has deleterious
effects in some browsers: some versions of Opera hang or stop loading
the page with an error, and IE throws up a basic-auth dialog box unless
the WebLogin URL has been added to its intranet sites. We therefore
want to permit a configuration where the username/password dialog box is
always shown first, but the user may choose to attempt SPNEGO, and then
may also choose to set a cookie that always directs them to SPNEGO.
This is generalized into a system that handles any Apache authentication
type, but makes it optional. weblogin can be configured in any of three
modes: always ask for username and password unless the user has a single
sign-on cookie, always attempt Apache authentication first and only ask
for username and password as a fallback, or ask for username and
password by default but provide the option of Apache authentication and
a cookie that can be set to always attempt it first. Apache
authentication is referred to as REMOTE_USER through the code and the
rest of this document, and the abbreviation "remuser" is used in
variables and cookies.
This flow documentation is also available in visual form in the file
docs/diagrams/weblogin-flow.svg or weblogin-flow.png. This may be a
clearer way to understand the page flow, and is worth consulting in
conjunction with this document.
Cookie Check
For all methods of visiting WebLogin, the WebLogin script first checks
whether a test cookie is already set. If it isn't, it redirects the
user back to the same page with an additional query parameter appended,
setting the test cookie in the process.
If the cookie still isn't set when the browser requests the page again,
the user is shown an error page explaining that cookies must be enabled.
The following page flows assume that this has happened already and the
user's test cookie is already set.
Basic Page Flow
Here is the WebLogin page flow in the basic case where no REMOTE_USER
complications are introduced:
1. User is sent to WebLogin with a request token and a webkdc-service
token from the WAS. WebLogin passes that request and any single
sign-on cookies from the browser to the WebKDC. If the WebKDC says
that authentication is successful (based on the cookies, generally,
but it is also allowed to make out-of-band decisions even though it
generally won't), it returns an id token or proxy token and says it
was successful. In that case, go to step 3. Otherwise, proceed to
step 2.
2. WebLogin presents a username/password form, keeping the request
token in a hidden field. This form will also have an "I don't want
to log in" link if the application provided a cancel URL. If the
user submits a username and password, it is validated with the
WebKDC. If that validation fails, they are returned to the same
page with an error. If it succeeds, they proceed to step 3.
3. User is presented with a confirmation page that states their
authenticated identity, provides a link back to the original service
with the id or proxy token in the URL, and also provides an "I don't
want to log in" link going to the cancel URL of the application if
provided by the initial request.
Page Flow with REMOTE_USER
If we always try Apache authentication first, using the configuration in
install-spengo (for example) that sets up an alias to the login script
as an authentication failure handler, we get the following page flow:
1. User is sent to WebLogin with a request token and a webkdc-service
token from the WAS. WebLogin (via Apache) attempts to authenticate.
If they succeed, WebLogin is called with REMOTE_USER set. It uses
that information to generate an artificial single sign-on token and
calls the WebKDC with it to get an appropriate id or proxy token.
If that authentication is sufficient, go to step 5. Otherwise, go
to step 2.
If Apache authentication does *not* succeed, Apache throws an
authentication error (401) and then dispatches the request to the
401 error handler. Go to step 3.
2. Apache authentication succeeded, but that wasn't sufficient to
authenticate the user. Present the regular username/password dialog
with hidden fields as above, repeat until the username/password
works, and then go to step 5.
3. The login page is invoked again as a 401 error handler and reads the
request token and webkdc-service token out of the separate
environment variables Apache uses for error handlers. This login
page must obviously not be protected by Apache authentication. It
passes the request to the WebKDC with any single sign-on cookies as
described above. Go to step 5 if the user is authenticated, step 4
otherwise.
4. WebLogin presents the username/password form with hidden fields as
above. User submits username/password, which is then validated.
When successful, proceed to step 5. The submit target of the form
must be a URL not protected by Apache authentication (generally the
same failure handler URL is reused).
5. User is presented with a confirmation page as described above and
can continue, authenticated, to the application.
Page Flow with Optional REMOTE_USER
We want to instead allow the user to select whether to attempt Apache
authentication or not, and to set a cookie that says to always use
Apache authentication if desired. To do that, we will use the following
page flow:
1. User is sent to WebLogin with tokens. WebLogin passes the request
and any single sign-on cookies to the WebKDC. If the user is
authenticated, go to step 6. Otherwise, continue to step 2.
2. WebLogin checks for the "always use REMOTE_USER" cookie. If present
*and* the application doesn't require username/password
authentication, user is redirected to the configured REMOTE_USER
URL, keeping the tokens at the end of the URL. Go to step 3.
Otherwise, go to step 5.
3. Apache attempts authentication. If successful, the user is passed
to the login script with REMOTE_USER set. Go to step 4. Otherwise,
the user is sent to the login script with a different URL (not
protected by Apache authentication) as a failure handler. Go to
step 5.
4. The WebLogin script takes the REMOTE_USER value, cobbles up a single
sign-on token, and passes that to the WebKDC. If that's sufficient
for authentication, proceed to step 6. Otherwise, the
username/password dialog is presented again. Note that this case
should not happen, since we catch applications that require
username/password at step 2 and don't send them through the Apache
authentication route. But if it does, loop there until successful
authentication, and then go to step 6.
5. No REMOTE_USER cookie was set, REMOTE_USER was tried and failed, or
the WAS requested forced login. If it was tried and failed, read
the token information out of the failure handler environment
variables. Present a username/password dialog box that also has an
alternative that says to try REMOTE_USER, but suppress the latter if
called as a failure handler or if forced login was requested. Loop
until the user successfully authenticates with username/password and
then go to step 6.
6. The user has successfully authenticated. Show the standard page
with the link to the application. If we used REMOTE_USER *or* if a
REMOTE_USER cookie is present, Also show a check box indicating
whether the "always use REMOTE_USER" cookie is present and a button
that lets the user change that setting while returning them to the
same confirmation page with the same link to the calling
application.
Implementation
In order to implement this page flow, the login.fcgi script uses the
following logic:
1. If we already have return_url set in the query, we're at the
confirmation page and the user has changed their REMOTE_USER
configuration. Set or clear the REMOTE_USER cookie as appropriate
and then go to step 6 (displaying the confirmation page).
Otherwise, continue to step 2.
2. Check to see if the environment variable REDIRECT_QUERY_STRING is
set. If so, set a flag saying we're running as an error handler.
3. Make sure we have a request token RT and a webkdc-service token ST
in the request. If not, throw up the error page.
4. Construct the message we're going to send to the WebKDC. We always
talk to the WebKDC unless we're already at the confirmation page,
since the WebKDC may decide to authenticate the user at any step.
The WebKDC request contains:
* The request token from RT.
* The webkdc-service token from ST.
* The username and password if provided in the request (via a form
submission, for instance).
* Any tokens stored in cookies beginning with "webauth_wpt_".
These are the single sign-on cookies.
* Remote and local IP address and port information for logging.
* If Apache REMOTE_USER support is enabled *and* REMOTE_USER is
set, an additional single sign-on token manufactured from the
identity in REMOTE_USER.
5. Submit the request to the WebKDC and read the response. Pull out
the login cancel URL, if any, from the response no matter what and
store it for later use.
6. If the WebKDC said that the user is now authenticated, display the
confirmation page. Display the configuration checkbox for
REMOTE_USER unless the REMOTE_USER cookie is not set *and*
REMOTE_USER is not set in the environment (which means that either
we attempted Apache authentication and failed or we never tried).
The configuration checkbox, if present, must contain all of the data
required to rebuild the confirmation page, namely:
* The return URL including response token and state token.
* The authenticated username.
* The login cancel token, if any.
We do *not* have to preserve the proxy cookies, since we will have
set them the first time through the confirm page.
Note that the confirmation page can be suppressed with a WebLogin
configuration option. If it is suppressed, it is replaced by a 302
redirect (following REMOTE_USER authentication or authentication
based on an existing single sign-on cookie) or a 303 redirect
(following username/password form submission).
7. If we get this far, the user isn't authenticated yet. There are
six possibilities.
* If the WebKDC returns a fatal error, display the error page and
we're done. They lose.
* If the WebKDC returns WK_ERR_USER_AND_PASS_REQUIRED, they *do*
have a "use REMOTE_USER" cookie, and we are not running as a
failure handler, redirect to the configured REMOTE_USER URL,
including the original request token and webkdc-service token in
the URL.
* If the WebKDC returns WK_ERR_USER_AND_PASS_REQUIRED, they do
*not* have a "use REMOTE_USER" cookie, and we are not running as
a failure handler, display the login page including the button
that lets them try Apache authentication.
* If the WebKDC returns WK_ERR_USER_AND_PASS_REQUIRED and neither
of the above cases are true, we tried Apache authentication and
it failed. Display the login page but omit the button that lets
them try Apache authentication.
* If the WebKDC returns WK_ERR_LOGIN_FORCED, well, username and
password are required. We don't get to even try Apache
authentication in this case. Present the username/password
dialog without the REMOTE_USER button.
* If the WebKDC returns WK_ERR_LOGIN_FAILED, they already tried
using a username and password but got the wrong one. In this
case, don't show the REMOTE_USER button. They've already made a
choice, and more importantly the original login may have been
forced. We don't want someone to have forced login, enter the
wrong username and password, and then get a REMOTE_USER option.
They may choose to take it, and then end up being authenticated
but still having to enter their username and password (very
confusing).
License
Copyright 2006, 2008, 2009, 2011
The Board of Trustees of the Leland Stanford Junior University
Copying and distribution of this file, with or without modification, are
permitted in any medium without royalty provided the copyright notice
and this notice are preserved. This file is offered as-is, without any
warranty.
|