Thread: "Optional ident" authentication
Is there a reason other than existing code why HBA should not allow "ident" to be combined with other authentication methods? Right now there's no fall-back mechanism for when an ident map doesn't cover a particular login attempt. The code isn't really structured to allow one, and I've assumed that that is the only real reason it isn't there. My personal itch is that I'd like to have an "ident sameuser" authentication that falls back on, say, PAM authentication when system user A wants to log into postgres under a different username B. To scratch that itch I've made a patch that adds a new authentication method called optident. It behaves like ident except that it continues walking down the HBA configuration on failure. AFAICS the patch should allow you, for example, to grant a web application or daemon passwordless login to its database while other users still need a password. That seems a bit safer than storing plaintext passwords in config files (and more often than not, forget to make them non-readable to untrusted users) like PHP/MySQL applications tend to do. It's a fairly radical patch in that it changes struct Port (from hba.h). The auth_method is replaced with a function pointer, and the UserAuth enum is replaced with a function-pointer typedef. I think I may also add a new enum for the corresponding password encryption algorithms, which crypt.c currently special-cases based on authentication method. That wasn't very pretty in the first place, I think. Some dead bits of code and text disappear ("trust authentication failed", "unknown authentication method failed") and no new translatable strings are added. Another side effect is that the message for "no matching hba line" is given only when it applies, rather than for every connection that hits the "reject" method. Most of the work went into making fallbacks possible in the first place. One alternative was to allow multiple arguments to authentication methods in pg_hba.conf, but that would have been just as radical a change. As it is, the changes are nicely contained--apart from changing the type of that one field in struct Port. Before I go any further with this, am I barking up the wrong tree? Am I missing something? Or is it worth doing? Jeroen
"Jeroen T. Vermeulen" <jtv@xs4all.nl> writes: > Is there a reason other than existing code why HBA should not allow > "ident" to be combined with other authentication methods? How about that it's a bad idea? A combo method seems ideally suited to security holes, in the form of letting through unintended logins. > To scratch that itch I've made a patch that adds a new authentication > method called optident. It behaves like ident except that it continues > walking down the HBA configuration on failure. ... and this particular approach would break more installations' security than I really want to think about. It's not really a new ident method, it's a very fundamental change in the semantics of pg_hba.conf. As an example of how much it would change things, the "reject" auth option would become a useless no-op. regards, tom lane
On Sun, November 26, 2006 23:51, Tom Lane wrote: >> Is there a reason other than existing code why HBA should not allow >> "ident" to be combined with other authentication methods? > > How about that it's a bad idea? A combo method seems ideally suited > to security holes, in the form of letting through unintended logins. Well, that's why I'm asking. But I was hoping for something more concrete than "it could possibly be misconfigured." Especially when we still generate default configs that say "trust" for all local logins! The Debian package does come with a safer default config using "ident sameuser." For a packager-maintained setup like that, where you know beforehand that both the backend and the system do PAM, it might make sense to have that passwordless "ident sameuser" login on local connections but use e.g. "pam login" for the rest--including cross-user local logins. As far as I can make out, the only way to make "optident" unsafe is to have a matching rule following that it either (1) is a "trust" rule or (2) demands a plaintext password login on a non-local, unencrypted connection (and actually gets used while someone is intercepting the packets). If you configure either of those, I'd say you're on thin ice anyway. It certainly goes right against the "increasingly strict, decreasingly specific" guideline. > ... and this particular approach would break more installations' > security than I really want to think about. It's not really a new ident > method, it's a very fundamental change in the semantics of pg_hba.conf. Sure. But only when people use it, and then it can be used for good or for evil like anything else. A new authentication method that's not in the default config doesn't affect anyone's installation all by itself. > As an example of how much it would change things, the "reject" auth > option would become a useless no-op. How? Why? Naturally I tested it in combination with "reject" and it still rejected just as it should: "optident X" plus "reject" matching the same login add up to a regular "ident X." Same for "optident X" when it's not followed by another matching rule: if you're mapped you're in, if you're not mapped you're out. It just gives you the ability to follow up with a fallback rule that actually authenticates. The simplest way to keep optident secure is by pairing it with a second rule that has the same fields to the left of the authentication method, but gives a stricter authentication method. Second-simplest way: don't use plaintext passwords on unencrypted, non-local connections across unsafe networks and don't do "trust" anywhere. Third-simplest way: follow the existing guideline of starting with specific, permissive rules and working your way towards broad, strict rules. If there are any problems with that, of course I'd like to hear about them. Jeroen
Jeroen T. Vermeulen wrote: > On Sun, November 26, 2006 23:51, Tom Lane wrote: > >>> Is there a reason other than existing code why HBA should not allow >>> "ident" to be combined with other authentication methods? >>> >> How about that it's a bad idea? A combo method seems ideally suited >> to security holes, in the form of letting through unintended logins. >> > > Well, that's why I'm asking. But I was hoping for something more concrete > than "it could possibly be misconfigured." Especially when we still > generate default configs that say "trust" for all local logins! > > The Debian package does come with a safer default config using "ident > sameuser." For a packager-maintained setup like that, where you know > beforehand that both the backend and the system do PAM, it might make > sense to have that passwordless "ident sameuser" login on local > connections but use e.g. "pam login" for the rest--including cross-user > local logins. > > As far as I can make out, the only way to make "optident" unsafe is to > have a matching rule following that it either (1) is a "trust" rule or > (2) demands a plaintext password login on a non-local, unencrypted > connection (and actually gets used while someone is intercepting the > packets). If you configure either of those, I'd say you're on thin ice > anyway. It certainly goes right against the "increasingly strict, > decreasingly specific" guideline. > > > >> ... and this particular approach would break more installations' >> security than I really want to think about. It's not really a new ident >> method, it's a very fundamental change in the semantics of pg_hba.conf. >> > > Sure. But only when people use it, and then it can be used for good or > for evil like anything else. A new authentication method that's not in > the default config doesn't affect anyone's installation all by itself. > > > >> As an example of how much it would change things, the "reject" auth >> option would become a useless no-op. >> > > How? Why? Naturally I tested it in combination with "reject" and it > still rejected just as it should: "optident X" plus "reject" matching the > same login add up to a regular "ident X." Same for "optident X" when it's > not followed by another matching rule: if you're mapped you're in, if > you're not mapped you're out. It just gives you the ability to follow up > with a fallback rule that actually authenticates. > > The simplest way to keep optident secure is by pairing it with a second > rule that has the same fields to the left of the authentication method, > but gives a stricter authentication method. Second-simplest way: don't > use plaintext passwords on unencrypted, non-local connections across > unsafe networks and don't do "trust" anywhere. Third-simplest way: follow > the existing guideline of starting with specific, permissive rules and > working your way towards broad, strict rules. > > If there are any problems with that, of course I'd like to hear about them. > > > > Quite apart from security concerns, I find this design awkward. If we have a fallback mechanism, shouldn't it be available for all auth methods (except, as Tom rightly points out, for reject)? ISTM that the fallback behaviour of a rule should be specified separately from the auth method. cheers andrew
Andrew Dunstan <andrew@dunslane.net> writes: > Quite apart from security concerns, I find this design awkward. That's really the basis of my objection to it: having an auth method that changes the basic semantics of the surrounding logical structure is, at best, awkward and confusing. When it's in a security-critical context, those attributes get triple demerits because of the risk of unforeseen consequences at the implementation level (eg, clients not being prepared for two successive login challenges of different kinds), not to mention the likelihood of an admin writing a pg_hba.conf file that doesn't do what he expected because he didn't understand what would happen. The examples given at the top of the thread don't seem to me to justify any new contortions anyway: >> My personal itch is that I'd like to have an "ident sameuser" >> authentication that falls back on, say, PAM authentication when system >> user A wants to log into postgres under a different username B. You can accomplish that with local sameuser all ident sameuserlocal all all pam >> ... to grant a web application or daemon passwordless >> login to its database while other users still need a password. local webapp,daemon all ident sameuserlocal all all pam regards, tom lane
On Mon, November 27, 2006 09:05, Tom Lane wrote: > Andrew Dunstan <andrew@dunslane.net> writes: >> Quite apart from security concerns, I find this design awkward. It is. I've considered adding a field, but that was a radical change to the configuration file format and to the parsing code, which may also be re-used for other purposes. > That's really the basis of my objection to it: having an auth method > that changes the basic semantics of the surrounding logical structure > is, at best, awkward and confusing. When it's in a security-critical > context, those attributes get triple demerits because of the risk of > unforeseen consequences at the implementation level (eg, clients not > being prepared for two successive login challenges of different kinds), Oh, I agree. That's why I chose the solution that guaranteed at most one interactive authentication method per login attempt. Prompting the user for, say, an LDAP password and then for a postgres password as an alternative is confusing and unpleasant. So I reasoned like this: when you stack authentication rules, only the last one should ever be interactive. Only one authentication method is provably noninteractive: ident. (Actually, ident already prompts for a password if it fails--the password just doesn't go anywhere and that is the part you can change with optident). There is one other authentication method that *can* be noninteractive: PAM. Whether it is interactive depends on its own configuration. PAM is nicely flexible, but there is one thing it can't do. It can't skip the interaction when the client is already running under the right user identity. It can't do that because PAM is running in the client's process context, which may be compromised. There's just no reliable way for PAM or any other client-side authentication library to know that it's really running under the user id it thinks it is. But ident, on the server side, does have reliable information in the form of the client socket. That makes "ident" a perfect complement to PAM or other (interactive) authentication methods. What I documented in my patch is "only noninteractive authentication methods may fall through." How that translates into a configuration file format is a separate issue, but I figured it was better to introduce a new authentication method than to change the configuration file format and introduce an option to all authentication methods that really only makes sense with one of them. >>> My personal itch is that I'd like to have an "ident sameuser" >>> authentication that falls back on, say, PAM authentication when system >>> user A wants to log into postgres under a different username B. > > You can accomplish that with > > local sameuser all ident sameuser > local all all pam Yes, but I wouldn't call it more elegant or harder to misconfigure. The behaviour I'm looking for (and I think it's a fairly basic and useful thing) is a combination of (1) coupling system user names to database user names and (2) forgoing interaction when it's not needed. What you suggest here draws the database name into the equation, which to me is counterintuitive and makes the solution less generic. I'll agree that your example is harder to configure _unsafely_. But when people cannot get exactly the authentication scheme they want, they'll usually end up with a more permissive one. In that sense I don't see your trick as inherently safer than optident. >>> ... to grant a web application or daemon passwordless >>> login to its database while other users still need a password. > > local webapp,daemon all ident sameuser > local all all pam Wait... Tom, are you switching the database and user fields around? AFAICS this allows _all_ users passwordless access to databases called "webapp" or "daemon." Probably not what you want, but you might not notice because your application kept running and people rarely complain that they're not being prompted for a password. If you're just doing this to prove your point about the risks of misconfiguration, here's how you could do a similar thing with optident, for all databases and users: local all all optident sameuser local all all pam I think that's less error-prone, not more so. Also, what if you want to grant specific system users passwordless login under specific role names? AFAICS you'd end up writing the username in both the usermap *and* the user field of pg_hba.conf. Let's say you have a usermap that looked like this: custommap jack webapp custommap jill daemon Now you can grant that access like this: local all webapp,daemon ident custommap local all all pam With optident, you don't need the double listing of usernames: local all webapp,daemon ident custommap local all all pam If you want to combine custommap with sameuser and still allow PAM login for all other local connections: local all all optident custommap local all all optident sameuser local all all pam You've shown that you can simulate this with the existing HBA, but at what cost? You're restricted to the case where database names match user names. You must remember to duplicate the usernames in your usermaps exactly to the corresponding places in pg_hba.conf. You still can't grant system user jack passwordless login as "postgres" on two or more databases while requiring passwords from everyone else who wants to do that. And you've shown us a dangerous mistake in just 4 lines using the existing system. All of this is easy with optident, AFAICS. So what if my patch changes the way HBA works? The existing HBA may be good and simple, but it's not perfect. The patch gives you more flexibility in improving it: you can add a "required but not sufficient" ident in the future, if you want, or do other checks based on dynamic criteria. You can have fallbacks from mechanisms that aren't always available. You get all of this without any changes or incompatibilities to existing configuration files. Any risk happens when people choose to use it, and if they do, that probably means that it's useful. Jeroen
Tom Lane wrote: >>> My personal itch is that I'd like to have an "ident sameuser" >>> authentication that falls back on, say, PAM authentication when system >>> user A wants to log into postgres under a different username B. > > You can accomplish that with > > local sameuser all ident sameuser > local all all pam You put "sameuser" in the database column instead of the "user" column - was the intentional? I've just tried this with "sameuser" in the user column, and it didn't work for me. I've also searched the docs, and I only found three references to "sameuser". One described "ident sameuser", while the other two were in the changelog, and told me that "sameuser" support in the _database_ column was introduced in 6.4, and that quoting removes the special meaning of sameuser since 8.0. Should sameuser work instead of all in the user column? greetings, Florian Pflug
"Florian G. Pflug" <fgp@phlo.org> writes: > Tom Lane wrote: >> You can accomplish that with >> >> local sameuser all ident sameuser >> local all all pam > You put "sameuser" in the database column instead of the "user" column - > was the intentional? I've just tried this with "sameuser" in the user > column, and it didn't work for me. You're right, I was confusing the database-column feature with what's involved here. There isn't really any way for "sameuser" to work in the user column, since that would require a way to identify the user's non-database username, which is exactly the province of the auth method. So never mind :-(. But I still question whether Jeroen's got any real use case that can't be handled the other way, viz local webapp,etc all ident sameuser regards, tom lane
Tom Lane wrote: > "Florian G. Pflug" <fgp@phlo.org> writes: >> Tom Lane wrote: >>> You can accomplish that with >>> >>> local sameuser all ident sameuser >>> local all all pam > >> You put "sameuser" in the database column instead of the "user" column - >> was the intentional? I've just tried this with "sameuser" in the user >> column, and it didn't work for me. > > You're right, I was confusing the database-column feature with what's > involved here. There isn't really any way for "sameuser" to work in the > user column, since that would require a way to identify the user's > non-database username, which is exactly the province of the auth method. > So never mind :-(. > > But I still question whether Jeroen's got any real use case that can't > be handled the other way, viz While I agree that the original proposal was a bit hackish, I'd love to be able to specifiy "First try this auth method, and fall back to another if the first didn't succeed". I, for example, have a large ldap directory that contains one posixAccount entry for each of my customers. Postgres on my database server authenticates against that directory via pam, and my webservers are set up to run each customers cgi-scripts under his own account. To make things easier for customers, the webserver is running gidentd, and my database server uses ident authentication for connections from the webserver. Thus you only need to specify the database name and the hostname of my db server in cgi-scripts - no need for passwords (or usernames). Now, sometimes a customers cgi-scripts needs to be able to connect to another customers database. Currently, I need to change pg_hba.conf to let him do that. If I could chain authentication methods, I could just tell my customers they need a password to connect to a foreign database, but don't one one to connect to their own database. I believe it would be sufficient to add an additional column to pg_hba.conf called "On Failure". The value could either be "Continue" or "Abort", with the default being "Abort" to match the current behaviour. If there is a chance that a patch like that would be accepted I could try to modify Jeroen's patch to support that - but I have very little free time at the moment, so it might take me a while to get it done... greetings, Florian Pflug
"Florian G. Pflug" <fgp@phlo.org> writes: > I believe it would be sufficient to add an additional column to pg_hba.conf > called "On Failure". The value could either be "Continue" or "Abort", with > the default being "Abort" to match the current behaviour. Then you get into the problem that it has to work for *all* auth methods, which in general it will not, because the client probably isn't prepared for multiple auth challenges. Jeroen's kluge avoids that by only working for an auth method that doesn't involve a client challenge. The example you cited is easily implemented without any new features, anyway, using "samegroup": local all samegroup ident sameuserlocal all all md5 where users are made members of the group/role named after the database they are allowed to log into without a password. regards, tom lane
Tom Lane wrote: > "Florian G. Pflug" <fgp@phlo.org> writes: > >> I believe it would be sufficient to add an additional column to pg_hba.conf >> called "On Failure". The value could either be "Continue" or "Abort", with >> the default being "Abort" to match the current behaviour. >> > > Then you get into the problem that it has to work for *all* auth > methods, which in general it will not, because the client probably isn't > prepared for multiple auth challenges. Jeroen's kluge avoids that by > only working for an auth method that doesn't involve a client challenge. > Yes, if we did that we'd probably have to fix libpq to allow for it (and any native protocol implementations such as JDBC). Can the wire protocol handle it? > The example you cited is easily implemented without any new features, > anyway, using "samegroup": > > local all samegroup ident sameuser > local all all md5 > > where users are made members of the group/role named after the database > they are allowed to log into without a password. > > > I was just composing almost this identical example ;-) 'samegroup' is a much overlooked feature, I believe, and should be extremely useful for hosting providers especially. cheers andrew
Andrew Dunstan <andrew@dunslane.net> writes: > Tom Lane wrote: >> Then you get into the problem that it has to work for *all* auth >> methods, which in general it will not, because the client probably isn't >> prepared for multiple auth challenges. > Yes, if we did that we'd probably have to fix libpq to allow for it (and > any native protocol implementations such as JDBC). Can the wire protocol > handle it? Not really --- the problem is what does a client do if faced with an unanswerable challenge, eg password requested when it has no password. libpq currently just disconnects. You could maybe kluge it to send back an empty password or some such, but it'd be better if the protocol had an explicit "fail" response. In any case, "let's fix all the clients" isn't very practical --- what of clients running older copies of libpq? regards, tom lane
On Tue, November 28, 2006 22:21, Tom Lane wrote: > "Florian G. Pflug" <fgp@phlo.org> writes: >> I believe it would be sufficient to add an additional column to >> pg_hba.conf >> called "On Failure". The value could either be "Continue" or "Abort", >> with >> the default being "Abort" to match the current behaviour. > > Then you get into the problem that it has to work for *all* auth > methods, which in general it will not, because the client probably isn't > prepared for multiple auth challenges. Jeroen's kluge avoids that by > only working for an auth method that doesn't involve a client challenge. ...Or more precisely, by specifying that interactive auth methods shouldn't ever fall through. I think ident is fundamentally different from all the other auth methods, and frankly I think the real problem is that it doesn't quite fit in as one. Adding an "on failure" field to the config file isn't perfect either, IMHO, because it only works for failures. With ident, it might also make sense to stack auth methods in a restrictive way: "this particular login must be allowed by this ident map *and* authenticate through LDAP as usual." I think HBA configuration would work better if more arguments were possible on the *matching* side of pg_hba.conf, alongside "database" and "user." Things are already ugly because "ssl" didn't quite fit in there: that looks like it should've been an optional argument in matching connections to HBA rules. If we had optional matching arguments, I think ident would be a matching option by nature--not an authentication method at all. The existing "ident sameuser" would be shorthand for a "trust" rule matching on the ident map, followed by a "reject" rule for the same connections but without the ident argument. If you left out the "reject," you'd have the "ident sameuser" behaviour but with fallback to regular authentication. You could also have separate authentication methods based on what the system wants for a particular user, without requiring any coupling to databases or roles. Most of that job should probably be left to PAM where available, but it just so happens that "ident" does a job that PAM isn't able to. But I'll admit that all of that is making things a bit complex and therefore error-prone. > The example you cited is easily implemented without any new features, > anyway, using "samegroup": > > local all samegroup ident sameuser > local all all md5 > > where users are made members of the group/role named after the database > they are allowed to log into without a password. Nice one--at least that way you're not tying database names to user names (on a side note, I see that "samegroup" is obsolescent--it's "samerole" now). But AFAICS it still doesn't allow you to fall back to interactive authentication for "cross-identity" logins: those will just fail even if you would want the user on the other end to be able to log in, assuming he knows the password. Yes, you've shown that you can simulate that with the existing HBA format but I wouldn't want to maintain a configuration like that! Jeroen