Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit9afffcb

Browse files
committed
Add some information about authenticated identity via log_connections
The "authenticated identity" is the string used by an authenticationmethod to identify a particular user. In many common cases, this is thesame as the PostgreSQL username, but for some third-party authenticationmethods, the identifier in use may be shortened or otherwise translated(e.g. through pg_ident user mappings) before the server stores it.To help administrators see who has actually interacted with the system,this commit adds the capability to store the original identity whenauthentication succeeds within the backend's Port, and generates a logentry when log_connections is enabled. The log entries generated looksomething like this (where a local user named "foouser" is connecting tothe database as the database user called "admin"): LOG: connection received: host=[local] LOG: connection authenticated: identity="foouser" method=peer (/data/pg_hba.conf:88) LOG: connection authorized: user=admin database=postgres application_name=psqlPort->authn_id is set according to the authentication method: bsd: the PostgreSQL username (aka the local username) cert: the client's Subject DN gss: the user principal ident: the remote username ldap: the final bind DN pam: the PostgreSQL username (aka PAM username) password (and all pw-challenge methods): the PostgreSQL username peer: the peer's pw_name radius: the PostgreSQL username (aka the RADIUS username) sspi: either the down-level (SAM-compatible) logon name, if compat_realm=1, or the User Principal Name if compat_realm=0The trust auth method does not set an authenticated identity. Neitherdoes clientcert=verify-full.Port->authn_id could be used for other purposes, like a superuser-onlyextra column in pg_stat_activity, but this is left as future work.PostgresNode::connect_{ok,fails}() have been modified to let tests checkthe backend log files for required or prohibited patterns, using thenew log_like and log_unlike parameters. This uses a method based on atruncation of the existing server log file, like issues_sql_like().Tests are added to the ldap, kerberos, authentication and SSL testsuites.Author: Jacob ChampionReviewed-by: Stephen Frost, Magnus Hagander, Tom Lane, Michael PaquierDiscussion:https://postgr.es/m/c55788dd1773c521c862e8e0dddb367df51222be.camel@vmware.com
1 parent8ee9b66 commit9afffcb

File tree

11 files changed

+416
-74
lines changed

11 files changed

+416
-74
lines changed

‎doc/src/sgml/config.sgml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6755,7 +6755,8 @@ local0.* /var/log/postgresql
67556755
<listitem>
67566756
<para>
67576757
Causes each attempted connection to the server to be logged,
6758-
as well as successful completion of client authentication.
6758+
as well as successful completion of both client authentication (if
6759+
necessary) and authorization.
67596760
Only superusers can change this parameter at session start,
67606761
and it cannot be changed at all within a session.
67616762
The default is <literal>off</literal>.

‎src/backend/libpq/auth.c

Lines changed: 129 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,10 @@
3434
#include"libpq/scram.h"
3535
#include"miscadmin.h"
3636
#include"port/pg_bswap.h"
37+
#include"postmaster/postmaster.h"
3738
#include"replication/walsender.h"
3839
#include"storage/ipc.h"
40+
#include"utils/guc.h"
3941
#include"utils/memutils.h"
4042
#include"utils/timestamp.h"
4143

@@ -47,6 +49,7 @@ static void sendAuthRequest(Port *port, AuthRequest areq, const char *extradata,
4749
intextralen);
4850
staticvoidauth_failed(Port*port,intstatus,char*logdetail);
4951
staticchar*recv_password_packet(Port*port);
52+
staticvoidset_authn_id(Port*port,constchar*id);
5053

5154

5255
/*----------------------------------------------------------------
@@ -337,6 +340,51 @@ auth_failed(Port *port, int status, char *logdetail)
337340
}
338341

339342

343+
/*
344+
* Sets the authenticated identity for the current user. The provided string
345+
* will be copied into the TopMemoryContext. The ID will be logged if
346+
* log_connections is enabled.
347+
*
348+
* Auth methods should call this routine exactly once, as soon as the user is
349+
* successfully authenticated, even if they have reasons to know that
350+
* authorization will fail later.
351+
*
352+
* The provided string will be copied into TopMemoryContext, to match the
353+
* lifetime of the Port, so it is safe to pass a string that is managed by an
354+
* external library.
355+
*/
356+
staticvoid
357+
set_authn_id(Port*port,constchar*id)
358+
{
359+
Assert(id);
360+
361+
if (port->authn_id)
362+
{
363+
/*
364+
* An existing authn_id should never be overwritten; that means two
365+
* authentication providers are fighting (or one is fighting itself).
366+
* Don't leak any authn details to the client, but don't let the
367+
* connection continue, either.
368+
*/
369+
ereport(FATAL,
370+
(errmsg("connection was re-authenticated"),
371+
errdetail_log("previous ID: \"%s\"; new ID: \"%s\"",
372+
port->authn_id,id)));
373+
}
374+
375+
port->authn_id=MemoryContextStrdup(TopMemoryContext,id);
376+
377+
if (Log_connections)
378+
{
379+
ereport(LOG,
380+
errmsg("connection authenticated: identity=\"%s\" method=%s "
381+
"(%s:%d)",
382+
port->authn_id,hba_authname(port),HbaFileName,
383+
port->hba->linenumber));
384+
}
385+
}
386+
387+
340388
/*
341389
* Client authentication starts here. If there is an error, this
342390
* function does not return and the backend process is terminated.
@@ -757,6 +805,9 @@ CheckPasswordAuth(Port *port, char **logdetail)
757805
pfree(shadow_pass);
758806
pfree(passwd);
759807

808+
if (result==STATUS_OK)
809+
set_authn_id(port,port->user_name);
810+
760811
returnresult;
761812
}
762813

@@ -816,6 +867,10 @@ CheckPWChallengeAuth(Port *port, char **logdetail)
816867
Assert(auth_result!=STATUS_OK);
817868
returnSTATUS_ERROR;
818869
}
870+
871+
if (auth_result==STATUS_OK)
872+
set_authn_id(port,port->user_name);
873+
819874
returnauth_result;
820875
}
821876

@@ -1174,8 +1229,13 @@ pg_GSS_checkauth(Port *port)
11741229
/*
11751230
* Copy the original name of the authenticated principal into our backend
11761231
* memory for display later.
1232+
*
1233+
* This is also our authenticated identity. Set it now, rather than
1234+
* waiting for the usermap check below, because authentication has already
1235+
* succeeded and we want the log file to reflect that.
11771236
*/
11781237
port->gss->princ=MemoryContextStrdup(TopMemoryContext,gbuf.value);
1238+
set_authn_id(port,gbuf.value);
11791239

11801240
/*
11811241
* Split the username at the realm separator
@@ -1285,6 +1345,7 @@ pg_SSPI_recvauth(Port *port)
12851345
DWORDdomainnamesize=sizeof(domainname);
12861346
SID_NAME_USEaccountnameuse;
12871347
HMODULEsecur32;
1348+
char*authn_id;
12881349

12891350
QUERY_SECURITY_CONTEXT_TOKEN_FN_QuerySecurityContextToken;
12901351

@@ -1514,6 +1575,26 @@ pg_SSPI_recvauth(Port *port)
15141575
returnstatus;
15151576
}
15161577

1578+
/*
1579+
* We have all of the information necessary to construct the authenticated
1580+
* identity. Set it now, rather than waiting for check_usermap below,
1581+
* because authentication has already succeeded and we want the log file
1582+
* to reflect that.
1583+
*/
1584+
if (port->hba->compat_realm)
1585+
{
1586+
/* SAM-compatible format. */
1587+
authn_id=psprintf("%s\\%s",domainname,accountname);
1588+
}
1589+
else
1590+
{
1591+
/* Kerberos principal format. */
1592+
authn_id=psprintf("%s@%s",accountname,domainname);
1593+
}
1594+
1595+
set_authn_id(port,authn_id);
1596+
pfree(authn_id);
1597+
15171598
/*
15181599
* Compare realm/domain if requested. In SSPI, always compare case
15191600
* insensitive.
@@ -1901,8 +1982,15 @@ ident_inet(hbaPort *port)
19011982
pg_freeaddrinfo_all(local_addr.addr.ss_family,la);
19021983

19031984
if (ident_return)
1904-
/* Success! Check the usermap */
1985+
{
1986+
/*
1987+
* Success! Store the identity, then check the usermap. Note that
1988+
* setting the authenticated identity is done before checking the
1989+
* usermap, because at this point authentication has succeeded.
1990+
*/
1991+
set_authn_id(port,ident_user);
19051992
returncheck_usermap(port->hba->usermap,port->user_name,ident_user, false);
1993+
}
19061994
returnSTATUS_ERROR;
19071995
}
19081996

@@ -1926,7 +2014,6 @@ auth_peer(hbaPort *port)
19262014
gid_tgid;
19272015
#ifndefWIN32
19282016
structpasswd*pw;
1929-
char*peer_user;
19302017
intret;
19312018
#endif
19322019

@@ -1958,12 +2045,14 @@ auth_peer(hbaPort *port)
19582045
returnSTATUS_ERROR;
19592046
}
19602047

1961-
/* Make a copy of static getpw*() result area. */
1962-
peer_user=pstrdup(pw->pw_name);
1963-
1964-
ret=check_usermap(port->hba->usermap,port->user_name,peer_user, false);
2048+
/*
2049+
* Make a copy of static getpw*() result area; this is our authenticated
2050+
* identity. Set it before calling check_usermap, because authentication
2051+
* has already succeeded and we want the log file to reflect that.
2052+
*/
2053+
set_authn_id(port,pw->pw_name);
19652054

1966-
pfree(peer_user);
2055+
ret=check_usermap(port->hba->usermap,port->user_name,port->authn_id, false);
19672056

19682057
returnret;
19692058
#else
@@ -2220,6 +2309,9 @@ CheckPAMAuth(Port *port, const char *user, const char *password)
22202309

22212310
pam_passwd=NULL;/* Unset pam_passwd */
22222311

2312+
if (retval==PAM_SUCCESS)
2313+
set_authn_id(port,user);
2314+
22232315
return (retval==PAM_SUCCESS ?STATUS_OK :STATUS_ERROR);
22242316
}
22252317
#endif/* USE_PAM */
@@ -2255,6 +2347,7 @@ CheckBSDAuth(Port *port, char *user)
22552347
if (!retval)
22562348
returnSTATUS_ERROR;
22572349

2350+
set_authn_id(port,user);
22582351
returnSTATUS_OK;
22592352
}
22602353
#endif/* USE_BSD_AUTH */
@@ -2761,6 +2854,9 @@ CheckLDAPAuth(Port *port)
27612854
returnSTATUS_ERROR;
27622855
}
27632856

2857+
/* Save the original bind DN as the authenticated identity. */
2858+
set_authn_id(port,fulluser);
2859+
27642860
ldap_unbind(ldap);
27652861
pfree(passwd);
27662862
pfree(fulluser);
@@ -2824,6 +2920,30 @@ CheckCertAuth(Port *port)
28242920
returnSTATUS_ERROR;
28252921
}
28262922

2923+
if (port->hba->auth_method==uaCert)
2924+
{
2925+
/*
2926+
* For cert auth, the client's Subject DN is always our authenticated
2927+
* identity, even if we're only using its CN for authorization. Set
2928+
* it now, rather than waiting for check_usermap() below, because
2929+
* authentication has already succeeded and we want the log file to
2930+
* reflect that.
2931+
*/
2932+
if (!port->peer_dn)
2933+
{
2934+
/*
2935+
* This should not happen as both peer_dn and peer_cn should be
2936+
* set in this context.
2937+
*/
2938+
ereport(LOG,
2939+
(errmsg("certificate authentication failed for user \"%s\": unable to retrieve subject DN",
2940+
port->user_name)));
2941+
returnSTATUS_ERROR;
2942+
}
2943+
2944+
set_authn_id(port,port->peer_dn);
2945+
}
2946+
28272947
/* Just pass the certificate cn/dn to the usermap check */
28282948
status_check_usermap=check_usermap(port->hba->usermap,port->user_name,peer_username, false);
28292949
if (status_check_usermap!=STATUS_OK)
@@ -2995,6 +3115,8 @@ CheckRADIUSAuth(Port *port)
29953115
*/
29963116
if (ret==STATUS_OK)
29973117
{
3118+
set_authn_id(port,port->user_name);
3119+
29983120
pfree(passwd);
29993121
returnSTATUS_OK;
30003122
}

‎src/backend/libpq/hba.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3141,3 +3141,27 @@ hba_getauthmethod(hbaPort *port)
31413141
{
31423142
check_hba(port);
31433143
}
3144+
3145+
3146+
/*
3147+
* Return the name of the auth method in use ("gss", "md5", "trust", etc.).
3148+
*
3149+
* The return value is statically allocated (see the UserAuthName array) and
3150+
* should not be freed.
3151+
*/
3152+
constchar*
3153+
hba_authname(hbaPort*port)
3154+
{
3155+
UserAuthauth_method;
3156+
3157+
Assert(port->hba);
3158+
auth_method=port->hba->auth_method;
3159+
3160+
if (auth_method<0||USER_AUTH_LAST<auth_method)
3161+
{
3162+
/* Should never happen. */
3163+
elog(FATAL,"port has out-of-bounds UserAuth: %d",auth_method);
3164+
}
3165+
3166+
returnUserAuthName[auth_method];
3167+
}

‎src/include/libpq/hba.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ typedef struct Port hbaPort;
137137

138138
externboolload_hba(void);
139139
externboolload_ident(void);
140+
externconstchar*hba_authname(hbaPort*port);
140141
externvoidhba_getauthmethod(hbaPort*port);
141142
externintcheck_usermap(constchar*usermap_name,
142143
constchar*pg_role,constchar*auth_user,

‎src/include/libpq/libpq-be.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,19 @@ typedef struct Port
159159
*/
160160
HbaLine*hba;
161161

162+
/*
163+
* Authenticated identity. The meaning of this identifier is dependent on
164+
* hba->auth_method; it is the identity (if any) that the user presented
165+
* during the authentication cycle, before they were assigned a database
166+
* role. (It is effectively the "SYSTEM-USERNAME" of a pg_ident usermap
167+
* -- though the exact string in use may be different, depending on pg_hba
168+
* options.)
169+
*
170+
* authn_id is NULL if the user has not actually been authenticated, for
171+
* example if the "trust" auth method is in use.
172+
*/
173+
constchar*authn_id;
174+
162175
/*
163176
* TCP keepalive and user timeout settings.
164177
*

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp