Return-Path: Delivered-To: new-httpd-archive@hyperreal.org Received: (qmail 17914 invoked by uid 6000); 3 Jan 2000 01:44:35 -0000 Received: (qmail 17907 invoked from network); 3 Jan 2000 01:44:33 -0000 Received: from liberty.uc.wlu.edu (root@137.113.192.101) by taz.hyperreal.org with SMTP; 3 Jan 2000 01:44:33 -0000 Received: from WISDOM.UC.WLU.EDU (wisdom.uc.wlu.edu [137.113.192.113]) by liberty.uc.wlu.edu (8.8.6 (PHNE_17135)/8.8.6) with SMTP id UAA20777 for ; Sun, 2 Jan 2000 20:44:31 -0500 (EST) Received: from WluD-Message_Server by WISDOM.UC.WLU.EDU with Novell_GroupWise; Sun, 02 Jan 2000 20:44:32 -0500 Message-Id: X-Mailer: Novell GroupWise 5.5.2 Date: Sun, 02 Jan 2000 20:44:30 -0500 From: "Cliff Woolley" To: Cc: Subject: Re: Multimodal authentication Mime-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Disposition: inline Sender: new-httpd-owner@apache.org Precedence: bulk Reply-To: new-httpd@apache.org Status: O >>> Doug Luce 01/02/00 02:19PM >>> >If all modules return DECLINE instead of an error, don't you end up with >an error being transmitted to the browser, and a line like "configuration >error: couldn't check user. No user file?" in your error log? Wouldn't >it be better to have a message like "Nobody wants to authenticate you" >be sent? That's correct. You get a 500 Server Error. That's why you have to make sure that the last one (and only the last one) in line *IS* authoritative. =-) That way, the client either gets 200 OK, 401 Auth Required, or 403 Forbidden, but never 500 Server Error (all else being equal). >This also doesn't map onto the semantics of "If I didn't authenticate this >user, I shouldn't check their access." mod_auth, even in >non-authoritative mode, will try to validate access anyway. Of course, if >it fails, it DECLINES and lets the next module have a try. But if another >module authenticates a user, and applies different access logic to their >group membership, mod_auth might be stomping on some toes (or vice versa, >causing problems controlling precedence through module order in >Configuration.tmpl). While I don't think this would be a problem in my >specific case, I don't think this is good in general. This is done intentionally, though, because authenticating the user and allowing access are different processes, and you might WANT to have a different module allow access than the one that validated that user was who he said he was. It just happens to be frequently convenient to do these two things in the same module, but it doesn't have to be that way. You could even split out the logic for the standard "require" statements from mod_auth into a separate module if you wanted, and it'd all still work (see below). If you think about it, most of the logic for (simple) require statements is duplicated across modules anyway. It makes sense that the first module that can grok the require statement and knows to let the user in should, regardless of whether or not that's the same module that validated the user's identity... it's more efficient to let simple cases be handled by the first module in line that can handle them. You just have to be careful in your configuration, that's all. Granted, it's less efficient than ONLY running the check_access hook for the module that validated the user, but then that causes the problem of FORCING the duplication of code for the simple cases across modules when it's not needed (even though it'd probably be done anyway, it doesn't *have to* be that way). >There's two problems here: a module trying to check access on a user it >didn't authenticate, and the standard require statements being interpreted >by different modules. These are either problems or benefits, depending on how you look at it. =-) I tend to think of them as benefits. Here's why. Assuming you have it set up right so that only the last auth module is authoritative, then most of the modules will never *fail* a person on an access check... they will only return DECLINED or OK. Only the last (authoritative) module will fail the person. It doesn't matter which module returns OK along the line, as long as that module is correct in doing so. Therefore no module will ever "step on toes" if they're all configured right. The standard require statements vs. non-standard ones are a good example of this: it works either way. (I tend to like the standard one because it's standard. ) Take the case of standard requires first. Let's say you "require user bob". It doesn't matter which module validated that this request came from "bob". The first module that understands this statement (mod_auth in the example I gave earlier) has the authority to say that "bob" is allowed access to this resource. For a more complicated require like "require context /.mktg.acme" from mod_auth_nds (again using my earlier example), mod_auth would decline because it doesn't understand "require context". mod_auth_nds would then either allow or disallow access because it does understand that syntax. No problems there. Even for a "require valid-user", you're still okay. This case even comes pretty close to being what you seem to want. Using the earlier example, assume that the person who authenticated was an NDS user. mod_auth doesn't recognize that the person is a valid-user because the person isn't in the .htpasswd file. mod_auth_nds *does* recognize that it's a valid-user because the person *is* in the .ndsusers file. It happens that mod_auth_nds was also the module that authenticated the user in the first place. That doesn't really matter, but it worked out that way anyway. Now take non-standard require variants (like "LDAPrequire" or whatever). This basically works out to be the same argument as what I said for "require valid-user" a second ago. It works. Take my earlier example and use mod_auth_ldap instead of mod_auth_nds. Now it works exactly the same whether or not mod_auth_ldap happens to use "LDAPrequire group" or "require group", except that in the earlier case, mod_auth_ldap has to duplicate a little more logic in processing the require line. Let's say you have an LDAP user who's authenticating and who is in your allowed LDAPrequire'd group. If it uses "LDAPrequire group", then mod_auth would just decline because there were no "require" lines it understood. mod_auth_ldap would pick it up, verify that the person was in the LDAPrequire'd group, and allow access. If mod_auth_ldap used the standard "require group" instead, it'd be exactly the same: mod_auth would understand the require line, but it woudn't be able to verify that the person was in the require'd group because that person wasn't in the AuthGroupFile (if there was even one specified... that doesn't matter). mod_auth_ldap would then pick up the "require group" line, verify that the person *was* in a group that it knew about, and allow access. You could even mix-and-match if you wanted, and that would work just as well: require user some-htpasswd-user some-ldap-user some-other-ldap-user Bottom line: all of this works either way, so isn't it easier on the end user to have standard config directives? Now one interesting point that this all brings up is that I don't think that mod_auth handles the AuthAuthoritative directive precisely correctly for subdirectories of protected directories that don't have .htaccess files of their own. But the solution there is a rather easy fix to mod_auth, not a change in the core logic at all. I'll start another thread to gather opinions on that one. --Cliff Cliff Woolley Central Systems Software Administrator Washington and Lee University http://www.wlu.edu/~jwoolley/ Work: (540) 463-8089 Pager: (540) 462-2303