mirror of https://github.com/yandex/odyssey.git
Access management to PostgreSQL with LDAP (#454)
This commit extends functionality of ldap authentication. It introduces LDAP server groups match feature, allowing r strict access between different users to different databases on same host. Odyssey now will receive optional attributes from LDAP server while authenticating user and use them to acquire backend connection under proper role.
This commit is contained in:
parent
1b2edf66fe
commit
ce3a777d2b
|
@ -18,6 +18,8 @@ EOF
|
|||
|
||||
cat >> /etc/postgresql/14/main/pg_hba.conf <<-EOF
|
||||
host ldap_db user1 127.0.0.1/32 trust
|
||||
host ldap_db1 ldap_readonly 127.0.0.1/32 password
|
||||
host ldap_db2 ldap_rw 127.0.0.1/32 md5
|
||||
host auth_query_db auth_query_user_scram_sha_256 127.0.0.1/32 trust
|
||||
host auth_query_db auth_query_user_md5 127.0.0.1/32 trust
|
||||
local all postgres trust
|
||||
|
@ -71,7 +73,6 @@ psql -h localhost -p 5432 -U postgres -c "set password_encryption TO 'md5'; crea
|
|||
exit 1
|
||||
}
|
||||
|
||||
|
||||
# Create users
|
||||
psql -h localhost -p 5432 -U postgres -c "set password_encryption = 'scram-sha-256'; create user auth_query_user_scram_sha_256 with password 'passwd'" -d postgres >> $SETUP_LOG 2>&1 || {
|
||||
echo "ERROR: users creation failed, examine the log"
|
||||
|
@ -122,3 +123,44 @@ do
|
|||
exit 1
|
||||
}
|
||||
done
|
||||
|
||||
# Create databases for ldap_storage_credentials
|
||||
for database_name in ldap_db1 ldap_db2; do
|
||||
sudo -u postgres createdb $database_name >> "$SETUP_LOG" 2>&1 || {
|
||||
echo "ERROR: 'createdb $database_name' failed, examine the log"
|
||||
cat "$SETUP_LOG"
|
||||
cat "$PG_LOG"
|
||||
exit 1
|
||||
}
|
||||
done
|
||||
|
||||
# Create users for ldap_storage_credentials
|
||||
psql -h localhost -p 5432 -U postgres -c "create user ldap_readonly with password 'ldap_pass_readonly'" -d ldap_db1 >> $SETUP_LOG 2>&1 || {
|
||||
echo "ERROR: users creation failed, examine the log"
|
||||
cat "$SETUP_LOG"
|
||||
cat "$PG_LOG"
|
||||
exit 1
|
||||
}
|
||||
|
||||
psql -h localhost -p 5432 -U postgres -c "set password_encryption TO 'md5'; create user ldap_rw with password 'ldap_pass_rw'" -d ldap_db2 >> $SETUP_LOG 2>&1 || {
|
||||
echo "ERROR: users creation failed, examine the log"
|
||||
cat "$SETUP_LOG"
|
||||
cat "$PG_LOG"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Grant access for ldap_storage_credentials
|
||||
|
||||
psql -h localhost -p 5432 -U postgres -c "GRANT ALL ON DATABASE ldap_db1 TO ldap_readonly" -d postgres >> $SETUP_LOG 2>&1 || {
|
||||
echo "ERROR: users creation failed, examine the log"
|
||||
cat "$SETUP_LOG"
|
||||
cat "$PG_LOG"
|
||||
exit 1
|
||||
}
|
||||
|
||||
psql -h localhost -p 5432 -U postgres -c "GRANT ALL ON DATABASE ldap_db2 TO ldap_rw" -d postgres >> $SETUP_LOG 2>&1 || {
|
||||
echo "ERROR: users creation failed, examine the log"
|
||||
cat "$SETUP_LOG"
|
||||
cat "$PG_LOG"
|
||||
exit 1
|
||||
}
|
||||
|
|
|
@ -18,6 +18,66 @@ ldap_endpoint "ldap1" {
|
|||
ldapport 389
|
||||
}
|
||||
|
||||
ldap_endpoint "ldap_storage_creds" {
|
||||
ldapscheme "ldap"
|
||||
ldapbasedn "dc=example,dc=org"
|
||||
ldapbinddn "cn=admin,dc=example,dc=org"
|
||||
ldapbindpasswd "admin"
|
||||
ldapsearchfilter "(memberOf=cn=localhost,ou=groups,dc=example,dc=org)"
|
||||
ldapsearchattribute "gecos"
|
||||
ldapserver "192.168.233.16"
|
||||
ldapport 389
|
||||
}
|
||||
|
||||
database default {
|
||||
user default {
|
||||
authentication "clear_text"
|
||||
|
||||
storage "postgres_server"
|
||||
pool "session"
|
||||
pool_size 10
|
||||
|
||||
ldap_pool_size 10
|
||||
ldap_pool_timeout 0
|
||||
|
||||
pool_timeout 0
|
||||
|
||||
pool_ttl 60
|
||||
|
||||
pool_discard no
|
||||
|
||||
pool_cancel yes
|
||||
|
||||
pool_rollback yes
|
||||
|
||||
client_fwd_error yes
|
||||
|
||||
application_name_add_host yes
|
||||
|
||||
reserve_session_server_connection no
|
||||
|
||||
server_lifetime 3600
|
||||
log_debug no
|
||||
ldap_endpoint_name "ldap_storage_creds"
|
||||
|
||||
ldap_storage_credentials_attr "memberof"
|
||||
|
||||
ldap_storage_credentials "group_ro" {
|
||||
ldap_storage_username "ldap_readonly"
|
||||
ldap_storage_password "ldap_pass_readonly"
|
||||
}
|
||||
|
||||
ldap_storage_credentials "group_rw" {
|
||||
ldap_storage_username "ldap_rw"
|
||||
ldap_storage_password "ldap_pass_rw"
|
||||
}
|
||||
|
||||
quantiles "0.99,0.95,0.5"
|
||||
client_max 107
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
database "ldap_db" {
|
||||
user "user1" {
|
||||
authentication "clear_text"
|
||||
|
|
|
@ -6,6 +6,9 @@ sleep 1
|
|||
ldapadd -x -H ldap://192.168.233.16 -D "cn=admin,dc=example,dc=org" -wadmin -f /ldap/usr3.ldif
|
||||
# wait for ldap server to do smt
|
||||
sleep 1
|
||||
ldapadd -x -H ldap://192.168.233.16 -D "cn=admin,dc=example,dc=org" -wadmin -f /ldap/usr4.ldif
|
||||
# wait for ldap server to do smt
|
||||
sleep 1
|
||||
|
||||
/usr/bin/odyssey /ldap/odyssey.conf
|
||||
|
||||
|
@ -37,4 +40,25 @@ PGPASSWORD=notdefault psql -h localhost -p 6432 -U user3 -c "select 1" ldap_db >
|
|||
exit 1
|
||||
}
|
||||
|
||||
PGPASSWORD=default psql -h localhost -p 6432 -U user4 -c "select current_user" ldap_db1 2>/dev/null | grep ldap_readonly | wc -l | grep -q '1' || {
|
||||
echo "error: failed to successfully auth with correct password and correct db"
|
||||
ody-stop
|
||||
cat /var/log/odyssey.log
|
||||
exit 1
|
||||
}
|
||||
|
||||
PGPASSWORD=default psql -h localhost -p 6432 -U user4 -c "select current_user" ldap_db2 2>/dev/null | grep ldap_rw | wc -l | grep -q '1' || {
|
||||
echo "error: failed to successfully auth with correct password and correct db"
|
||||
ody-stop
|
||||
cat /var/log/odyssey.log
|
||||
exit 1
|
||||
}
|
||||
|
||||
PGPASSWORD=notdefault psql -h localhost -p 6432 -U user4 -c "select 1" ldap_db1 >/dev/null 2>&1 && {
|
||||
echo "error: successfully auth with incorrect password"
|
||||
ody-stop
|
||||
cat /var/log/odyssey.log
|
||||
exit 1
|
||||
}
|
||||
|
||||
ody-stop
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
dn: uid=user4,dc=example,dc=org
|
||||
objectClass: top
|
||||
objectClass: account
|
||||
objectClass: posixAccount
|
||||
objectClass: shadowAccount
|
||||
cn: user4
|
||||
uid: user4
|
||||
memberof: cn=localhost,ou=groups,dc=example,dc=org
|
||||
memberof: cn=localhost_ldap_db1_group_ro,ou=groups,dc=example,dc=org
|
||||
memberof: cn=localhost_ldap_db2_group_rw,ou=groups,dc=example,dc=org
|
||||
uidNumber: 16860
|
||||
gidNumber: 101
|
||||
homeDirectory: /home/user4
|
||||
loginShell: /bin/bash
|
||||
gecos: user4
|
||||
userPassword: default
|
||||
shadowLastChange: 0
|
||||
shadowMax: 0
|
||||
shadowWarning: 0
|
|
@ -513,7 +513,102 @@ storage "postgres_server"
|
|||
#storage_user "test"
|
||||
#storage_password "test"
|
||||
```
|
||||
### ldap_storage_credentials
|
||||
|
||||
This subsection must located at subsection `user` and used to route clients to a remote PostgreSQL server with special credentials
|
||||
(`storage_user` and `storage_password`), depending in the client account attributes stored on the LDAP server
|
||||
(based on OpenLDAP, Active Directory or others). This routing method allows to grant access
|
||||
with different privileges to different databases located on the same host.
|
||||
|
||||
This routing method maybe used only if variables of ldap_endpoint_name and ldap_storage_credentials_attr
|
||||
are set. For example:
|
||||
|
||||
```
|
||||
storage "test_server" {
|
||||
type "remote"
|
||||
port 5432
|
||||
host "postgres_server"
|
||||
}
|
||||
ldap_endpoint "ldap1" {
|
||||
ldapscheme "ldap"
|
||||
ldapbasedn "dc=example,dc=org"
|
||||
ldapbinddn "cn=admin,dc=example,dc=org"
|
||||
ldapbindpasswd "admin"
|
||||
ldapsearchfilter "(memberOf=cn=localhost,ou=groups,dc=example,dc=org)"
|
||||
ldapsearchattribute "gecos"
|
||||
ldapserver "192.168.233.16"
|
||||
ldapport 389
|
||||
}
|
||||
database default {
|
||||
user default {
|
||||
authentication "clear_text"
|
||||
storage "test_server"
|
||||
|
||||
ldap_endpoint_name "ldap1"
|
||||
ldap_storage_credentials_attr "memberof"
|
||||
ldap_storage_credentials "group_ro" {
|
||||
ldap_storage_username "ldap_ro"
|
||||
ldap_storage_password "password1"
|
||||
}
|
||||
ldap_storage_credentials "group_rw" {
|
||||
ldap_storage_username "ldap_rw"
|
||||
ldap_storage_password "password2
|
||||
}
|
||||
|
||||
#other required regular parameters are hidden from this example
|
||||
}
|
||||
}
|
||||
```
|
||||
To successfully route client to PostgreSQL server with correct credentials, client account attributes
|
||||
stored on LDAP server must contain three required values separated by `_` character:
|
||||
hostname of PostgreSQL server (`host` value from `storage` section), name of target `database`,
|
||||
and name of `ldap_storage_credentials` in format `%host_%database_%ldap_storage_credentials`
|
||||
For example, look at `memberof` attributes in [usr4.ldiff](https://github.com/yandex/odyssey/tree/master/docker/ldap):
|
||||
```
|
||||
dn: uid=user4,dc=example,dc=org
|
||||
objectClass: top
|
||||
objectClass: account
|
||||
objectClass: posixAccount
|
||||
objectClass: shadowAccount
|
||||
cn: user4
|
||||
uid: user4
|
||||
memberof: cn=localhost,ou=groups,dc=example,dc=org
|
||||
memberof: cn=localhost_ldap_db1_group_ro,ou=groups,dc=example,dc=org
|
||||
memberof: cn=localhost_ldap_db2_group_rw,ou=groups,dc=example,dc=org
|
||||
uidNumber: 16860
|
||||
gidNumber: 101
|
||||
homeDirectory: /home/user4
|
||||
loginShell: /bin/bash
|
||||
gecos: user4
|
||||
userPassword: default
|
||||
shadowLastChange: 0
|
||||
shadowMax: 0
|
||||
shadowWarning: 0
|
||||
```
|
||||
|
||||
#### ldap_storage_credentials_attr *string*
|
||||
|
||||
Sets the value of the account attribute name from the LDAP server, the values
|
||||
of which will be used to determine the route and parameters for connecting the client to the PostgreSQL server.
|
||||
|
||||
#### ldap_endpoint_name *string*
|
||||
|
||||
Specifies the name of ldap_endpoint to be used to connect to the LDAP server.
|
||||
|
||||
#### ldap_endpoint
|
||||
|
||||
The ldap_endpoint section is used to configure the parameters for connecting to the LDAP server. For example:
|
||||
|
||||
```
|
||||
ldap_endpoint "ldap1" {
|
||||
ldapscheme "ldap"
|
||||
ldapbasedn "dc=example,dc=org"
|
||||
ldapbinddn "cn=admin,dc=example,dc=org"
|
||||
ldapbindpasswd "admin"
|
||||
ldapsearchattribute "gecos"
|
||||
ldapserver "192.168.233.16"
|
||||
ldapport 389
|
||||
}
|
||||
|
||||
#### password\_passthrough *bool*
|
||||
|
||||
|
|
|
@ -740,7 +740,12 @@ static inline int od_auth_backend_cleartext(od_server_t *server,
|
|||
route->rule->db_name, route->rule->user_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef LDAP_FOUND
|
||||
if (client->rule->ldap_storage_credentials_attr) {
|
||||
password = client->ldap_storage_password;
|
||||
password_len = client->ldap_storage_password_len;
|
||||
}
|
||||
#endif
|
||||
/* PasswordMessage */
|
||||
machine_msg_t *msg;
|
||||
msg = kiwi_fe_write_password(NULL, password, password_len + 1);
|
||||
|
@ -802,7 +807,14 @@ static inline int od_auth_backend_md5(od_server_t *server, char salt[4],
|
|||
route->rule->db_name, route->rule->user_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef LDAP_FOUND
|
||||
if (client->rule->ldap_storage_credentials_attr) {
|
||||
user = client->ldap_storage_username;
|
||||
user_len = client->ldap_storage_username_len;
|
||||
password = client->ldap_storage_password;
|
||||
password_len = client->ldap_storage_password_len;
|
||||
}
|
||||
#endif
|
||||
/* prepare md5 password using server supplied salt */
|
||||
kiwi_password_t client_password;
|
||||
kiwi_password_init(&client_password);
|
||||
|
@ -935,7 +947,11 @@ static inline int od_auth_backend_sasl_continue(od_server_t *server,
|
|||
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef LDAP_FOUND
|
||||
if (client->rule->ldap_storage_credentials_attr) {
|
||||
password = client->ldap_storage_password;
|
||||
}
|
||||
#endif
|
||||
od_debug(&instance->logger, "auth", NULL, server,
|
||||
"continue SASL authentication");
|
||||
|
||||
|
|
|
@ -63,6 +63,15 @@ struct od_client {
|
|||
od_global_t *global;
|
||||
od_list_t link_pool;
|
||||
od_list_t link;
|
||||
|
||||
/* storage_user & storage_password provided by ldapsearch result */
|
||||
#ifdef LDAP_FOUND
|
||||
char *ldap_storage_username;
|
||||
int ldap_storage_username_len;
|
||||
char *ldap_storage_password;
|
||||
int ldap_storage_password_len;
|
||||
char *ldap_auth_dn;
|
||||
#endif
|
||||
};
|
||||
|
||||
static const size_t OD_CLIENT_DEFAULT_HASHMAP_SZ = 420;
|
||||
|
@ -92,6 +101,13 @@ static inline void od_client_init(od_client_t *client)
|
|||
client->time_setup = 0;
|
||||
client->notify_io = NULL;
|
||||
client->ctl.op = OD_CLIENT_OP_NONE;
|
||||
#ifdef LDAP_FOUND
|
||||
client->ldap_storage_username = NULL;
|
||||
client->ldap_storage_username_len = 0;
|
||||
client->ldap_storage_password = NULL;
|
||||
client->ldap_storage_password_len = 0;
|
||||
client->ldap_auth_dn = NULL;
|
||||
#endif
|
||||
|
||||
kiwi_be_startup_init(&client->startup);
|
||||
kiwi_vars_init(&client->vars);
|
||||
|
|
|
@ -128,6 +128,10 @@ typedef enum {
|
|||
OD_LLDAP_SCOPE,
|
||||
OD_LLDAP_SEARCH_FILTER,
|
||||
OD_LLDAP_ENDPOINT_NAME,
|
||||
OD_LLDAP_STORAGE_CREDENTIALS_ATTR,
|
||||
OD_LLDAP_STORAGE_CREDENTIALS,
|
||||
OD_LLDAP_STORAGE_USERNAME,
|
||||
OD_LLDAP_STORAGE_PASSWORD,
|
||||
OD_LWATCHDOG,
|
||||
OD_LWATCHDOG_LAG_QUERY,
|
||||
OD_LWATCHDOG_LAG_INTERVAL,
|
||||
|
@ -279,6 +283,11 @@ static od_keyword_t od_config_keywords[] = {
|
|||
od_keyword("ldapsearchfilter", OD_LLDAP_SEARCH_FILTER),
|
||||
od_keyword("ldapscope", OD_LLDAP_SCOPE),
|
||||
od_keyword("ldap_endpoint_name", OD_LLDAP_ENDPOINT_NAME),
|
||||
od_keyword("ldap_storage_credentials_attr",
|
||||
OD_LLDAP_STORAGE_CREDENTIALS_ATTR),
|
||||
od_keyword("ldap_storage_credentials", OD_LLDAP_STORAGE_CREDENTIALS),
|
||||
od_keyword("ldap_storage_username", OD_LLDAP_STORAGE_USERNAME),
|
||||
od_keyword("ldap_storage_password", OD_LLDAP_STORAGE_PASSWORD),
|
||||
|
||||
/* watchdog */
|
||||
|
||||
|
@ -841,6 +850,124 @@ static inline int od_config_reader_pgoptions(od_config_reader_t *reader,
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef LDAP_FOUND
|
||||
|
||||
static inline od_retcode_t
|
||||
od_config_reader_ldap_storage_credentials(od_config_reader_t *reader,
|
||||
od_rule_t *rule)
|
||||
{
|
||||
od_ldap_storage_credentials_t *lsc_current;
|
||||
lsc_current = od_ldap_storage_credentials_alloc();
|
||||
if (!lsc_current) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* name */
|
||||
if (!od_config_reader_string(reader, &lsc_current->name)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (strlen(lsc_current->name) == 0) {
|
||||
od_config_reader_error(
|
||||
reader, NULL,
|
||||
"empty ldap storage credentials definition");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (od_ldap_storage_credentials_find(&rule->ldap_storage_creds_list,
|
||||
lsc_current->name) != NULL) {
|
||||
od_config_reader_error(
|
||||
reader, NULL,
|
||||
"duplicate ldap storage credentials definition: %s",
|
||||
lsc_current->name);
|
||||
goto error;
|
||||
}
|
||||
|
||||
od_rule_ldap_storage_credentials_add(rule, lsc_current);
|
||||
|
||||
/* { */
|
||||
if (!od_config_reader_symbol(reader, '{')) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
od_token_t token;
|
||||
int rc;
|
||||
rc = od_parser_next(&reader->parser, &token);
|
||||
switch (rc) {
|
||||
case OD_PARSER_SYMBOL:
|
||||
/* } */
|
||||
if (token.value.num == '}') {
|
||||
if (lsc_current->lsc_username == NULL) {
|
||||
od_config_reader_error(
|
||||
reader, NULL,
|
||||
"lsc_username in ldap_storage_credentials '%s' is not defined",
|
||||
lsc_current->name);
|
||||
goto error;
|
||||
}
|
||||
if (lsc_current->lsc_password == NULL) {
|
||||
od_config_reader_error(
|
||||
reader, NULL,
|
||||
"lsc_password in ldap_storage_credentials '%s' is not defined",
|
||||
lsc_current->name);
|
||||
goto error;
|
||||
}
|
||||
return OK_RESPONSE;
|
||||
}
|
||||
/* fall through */
|
||||
case OD_PARSER_KEYWORD:
|
||||
break;
|
||||
default:
|
||||
od_config_reader_error(reader, &token,
|
||||
"unexpected symbol or token");
|
||||
goto error;
|
||||
}
|
||||
od_keyword_t *keyword;
|
||||
keyword = od_keyword_match(od_config_keywords, &token);
|
||||
if (keyword == NULL) {
|
||||
od_config_reader_error(reader, &token,
|
||||
"unknown parameter");
|
||||
return NOT_OK_RESPONSE;
|
||||
}
|
||||
|
||||
switch (keyword->id) {
|
||||
case OD_LLDAP_STORAGE_USERNAME: {
|
||||
if (!od_config_reader_string(
|
||||
reader, &lsc_current->lsc_username))
|
||||
goto error;
|
||||
if (strlen(lsc_current->lsc_username) == 0) {
|
||||
od_config_reader_error(
|
||||
reader, &token,
|
||||
"lsc_username in ldap_storage_credentials '%s' cannot be empty",
|
||||
lsc_current->name);
|
||||
goto error;
|
||||
}
|
||||
|
||||
} break;
|
||||
case OD_LLDAP_STORAGE_PASSWORD: {
|
||||
if (!od_config_reader_string(
|
||||
reader, &lsc_current->lsc_password))
|
||||
goto error;
|
||||
if (strlen(lsc_current->lsc_password) == 0) {
|
||||
od_config_reader_error(
|
||||
reader, &token,
|
||||
"lsc_password in ldap_storage_credentials '%s' cannot be empty",
|
||||
lsc_current->name);
|
||||
goto error;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
return OK_RESPONSE;
|
||||
error:
|
||||
if (lsc_current) {
|
||||
od_ldap_storage_credentials_free(lsc_current);
|
||||
}
|
||||
return NOT_OK_RESPONSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int od_config_reader_rule_settings(od_config_reader_t *reader,
|
||||
od_rule_t *rule,
|
||||
od_extention_t *extentions,
|
||||
|
@ -1189,6 +1316,56 @@ static int od_config_reader_rule_settings(od_config_reader_t *reader,
|
|||
reader, NULL,
|
||||
"ldap is not supported, check if ldap library is available on the system");
|
||||
return NOT_OK_RESPONSE;
|
||||
#endif
|
||||
}
|
||||
case OD_LLDAP_STORAGE_CREDENTIALS_ATTR: {
|
||||
#ifdef LDAP_FOUND
|
||||
if (!od_config_reader_string(
|
||||
reader,
|
||||
&rule->ldap_storage_credentials_attr)) {
|
||||
return NOT_OK_RESPONSE;
|
||||
}
|
||||
if (rule->ldap_endpoint_name == NULL) {
|
||||
od_config_reader_error(
|
||||
reader, NULL,
|
||||
"ldap_endpoint_name is not defined for rule with ldap_storage_credentials_attr '%s'",
|
||||
rule->ldap_storage_credentials_attr);
|
||||
return NOT_OK_RESPONSE;
|
||||
}
|
||||
if (strlen(rule->ldap_storage_credentials_attr) == 0) {
|
||||
od_config_reader_error(
|
||||
reader, NULL,
|
||||
"ldap_storage_credentials_attr cannot be empty for rule with ldap_endpoint_name '%s'",
|
||||
rule->ldap_endpoint_name);
|
||||
return NOT_OK_RESPONSE;
|
||||
}
|
||||
continue;
|
||||
#else
|
||||
od_config_reader_error(
|
||||
reader, NULL,
|
||||
"ldap is not supported, check if ldap library is available on the system");
|
||||
return NOT_OK_RESPONSE;
|
||||
#endif
|
||||
}
|
||||
case OD_LLDAP_STORAGE_CREDENTIALS: {
|
||||
#ifdef LDAP_FOUND
|
||||
if (od_config_reader_ldap_storage_credentials(
|
||||
reader, rule) != OK_RESPONSE) {
|
||||
return NOT_OK_RESPONSE;
|
||||
}
|
||||
if (rule->ldap_storage_credentials_attr == NULL) {
|
||||
od_config_reader_error(
|
||||
reader, NULL,
|
||||
"ldap_storage_credentials_attr is not defined for rule with ldap_endpoint_name '%s'",
|
||||
rule->ldap_endpoint_name);
|
||||
return NOT_OK_RESPONSE;
|
||||
}
|
||||
continue;
|
||||
#else
|
||||
od_config_reader_error(
|
||||
reader, NULL,
|
||||
"ldap is not supported, check if ldap library is available on the system");
|
||||
return NOT_OK_RESPONSE;
|
||||
#endif
|
||||
}
|
||||
case OD_LWATCHDOG_LAG_QUERY:
|
||||
|
|
|
@ -1253,6 +1253,12 @@ static inline int od_console_show_clients_callback(od_client_t *client,
|
|||
else if (client->state == OD_CLIENT_QUEUE)
|
||||
state = "queue";
|
||||
rc = kiwi_be_write_data_row_add(stream, offset, state, strlen(state));
|
||||
if (rc == NOT_OK_RESPONSE)
|
||||
return NOT_OK_RESPONSE;
|
||||
/* storage_user */
|
||||
rc = kiwi_be_write_data_row_add(stream, offset,
|
||||
client->rule->storage_user,
|
||||
client->rule->storage_user_len);
|
||||
if (rc == NOT_OK_RESPONSE)
|
||||
return NOT_OK_RESPONSE;
|
||||
/* addr */
|
||||
|
@ -1348,10 +1354,10 @@ static inline int od_console_show_clients(od_client_t *client,
|
|||
|
||||
machine_msg_t *msg;
|
||||
msg = kiwi_be_write_row_descriptionf(
|
||||
stream, "sssssdsdssddssds", "type", "user", "database", "state",
|
||||
"addr", "port", "local_addr", "local_port", "connect_time",
|
||||
"request_time", "wait", "wait_us", "ptr", "link", "remote_pid",
|
||||
"tls");
|
||||
stream, "ssssssdsdssddssds", "type", "user", "database",
|
||||
"state", "storage_user", "addr", "port", "local_addr",
|
||||
"local_port", "connect_time", "request_time", "wait", "wait_us",
|
||||
"ptr", "link", "remote_pid", "tls");
|
||||
if (msg == NULL)
|
||||
return NOT_OK_RESPONSE;
|
||||
|
||||
|
|
|
@ -2058,6 +2058,17 @@ void od_frontend(void *arg)
|
|||
od_frontend_error(client, KIWI_SYSTEM_ERROR,
|
||||
"client routing failed");
|
||||
break;
|
||||
case OD_ROUTER_INSUFFICIENT_ACCESS:
|
||||
// disabling blind ldapsearch via odyssey error messages
|
||||
// to collect user account attributes
|
||||
od_error(
|
||||
&instance->logger, "startup", client, NULL,
|
||||
"route for '%s.%s' is not found by ldapsearch for '%s' client, closing",
|
||||
client->startup.database.value,
|
||||
client->startup.user.value, peer);
|
||||
od_frontend_error(client, KIWI_SYNTAX_ERROR,
|
||||
"incorrect password");
|
||||
break;
|
||||
case OD_ROUTER_ERROR_NOT_FOUND:
|
||||
od_error(
|
||||
&instance->logger, "startup", client, NULL,
|
||||
|
|
432
sources/ldap.c
432
sources/ldap.c
|
@ -8,8 +8,6 @@
|
|||
#include <machinarium.h>
|
||||
#include <odyssey.h>
|
||||
|
||||
#define USE_POOL
|
||||
|
||||
od_retcode_t od_ldap_server_free(od_ldap_server_t *serv)
|
||||
{
|
||||
od_list_unlink(&serv->link);
|
||||
|
@ -18,9 +16,6 @@ od_retcode_t od_ldap_server_free(od_ldap_server_t *serv)
|
|||
ldap_unbind(serv->conn);
|
||||
}
|
||||
|
||||
if (serv->auth_user) {
|
||||
free(serv->auth_user);
|
||||
}
|
||||
free(serv);
|
||||
return OK_RESPONSE;
|
||||
}
|
||||
|
@ -34,6 +29,12 @@ static inline od_retcode_t od_ldap_error_report_client(od_client_t *cl, int rc)
|
|||
return OK_RESPONSE;
|
||||
case LDAP_INVALID_CREDENTIALS:
|
||||
return NOT_OK_RESPONSE;
|
||||
case LDAP_INSUFFICIENT_ACCESS: {
|
||||
// disabling blind ldapsearch via odyssey error messages
|
||||
// to collect user account attributes
|
||||
od_frontend_error(cl, KIWI_SYNTAX_ERROR, "incorrect password");
|
||||
return NOT_OK_RESPONSE;
|
||||
}
|
||||
case LDAP_UNAVAILABLE:
|
||||
case LDAP_UNWILLING_TO_PERFORM:
|
||||
case LDAP_BUSY: {
|
||||
|
@ -104,9 +105,61 @@ od_retcode_t od_ldap_endpoint_prepare(od_ldap_endpoint_t *le)
|
|||
return OK_RESPONSE;
|
||||
}
|
||||
|
||||
static inline od_retcode_t od_ldap_server_prepare(od_logger_t *logger,
|
||||
od_ldap_server_t *serv,
|
||||
od_client_t *client)
|
||||
od_retcode_t
|
||||
od_ldap_change_storage_credentials(od_logger_t *logger,
|
||||
od_ldap_storage_credentials_t *lsc,
|
||||
od_client_t *client)
|
||||
{
|
||||
client->ldap_storage_username = lsc->lsc_username;
|
||||
client->ldap_storage_username_len = strlen(lsc->lsc_username);
|
||||
client->ldap_storage_password = lsc->lsc_password;
|
||||
client->ldap_storage_password_len = strlen(lsc->lsc_password);
|
||||
od_debug(logger, "auth_ldap", client, NULL,
|
||||
"storage_user changed to %s", lsc->lsc_username);
|
||||
return OK_RESPONSE;
|
||||
}
|
||||
|
||||
od_retcode_t od_ldap_search_storage_credentials(od_logger_t *logger,
|
||||
struct berval **values,
|
||||
od_rule_t *rule,
|
||||
od_client_t *client)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < ldap_count_values_len(values); i++) {
|
||||
char host_db[128];
|
||||
od_snprintf(host_db, sizeof(host_db), "%s_%s",
|
||||
rule->storage->host,
|
||||
client->startup.database.value);
|
||||
if (strstr((char *)values[i]->bv_val, host_db)) {
|
||||
od_list_t *j;
|
||||
od_list_foreach(&rule->ldap_storage_creds_list, j)
|
||||
{
|
||||
od_ldap_storage_credentials_t *lsc = NULL;
|
||||
lsc = od_container_of(
|
||||
j, od_ldap_storage_credentials_t, link);
|
||||
char host_db_user[128];
|
||||
od_snprintf(host_db_user, sizeof(host_db_user),
|
||||
"%s_%s", host_db, lsc->name);
|
||||
|
||||
if (strstr((char *)values[i]->bv_val,
|
||||
host_db_user)) {
|
||||
od_debug(logger, "auth_ldap", client,
|
||||
NULL, "matched group %s",
|
||||
(char *)values[i]->bv_val);
|
||||
od_ldap_change_storage_credentials(
|
||||
logger, lsc, client);
|
||||
return OK_RESPONSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
od_debug(logger, "auth_ldap", client, NULL,
|
||||
"error: route does not match any user attribute");
|
||||
return NOT_OK_RESPONSE;
|
||||
}
|
||||
|
||||
od_retcode_t od_ldap_server_prepare(od_logger_t *logger, od_ldap_server_t *serv,
|
||||
od_rule_t *rule, od_client_t *client)
|
||||
{
|
||||
od_retcode_t rc;
|
||||
char *auth_user = NULL;
|
||||
|
@ -120,20 +173,8 @@ static inline od_retcode_t od_ldap_server_prepare(od_logger_t *logger,
|
|||
char *dn;
|
||||
int count;
|
||||
|
||||
rc = ldap_simple_bind_s(serv->conn,
|
||||
serv->endpoint->ldapbinddn ?
|
||||
serv->endpoint->ldapbinddn :
|
||||
"",
|
||||
serv->endpoint->ldapbindpasswd ?
|
||||
serv->endpoint->ldapbindpasswd :
|
||||
"");
|
||||
|
||||
od_debug(logger, "auth_ldap", NULL, NULL,
|
||||
"basednn simple bind result: %d", rc);
|
||||
|
||||
if (rc != LDAP_SUCCESS) {
|
||||
return NOT_OK_RESPONSE;
|
||||
}
|
||||
if (rule->ldap_storage_credentials_attr)
|
||||
attributes[0] = rule->ldap_storage_credentials_attr;
|
||||
|
||||
if (serv->endpoint->ldapsearchattribute) {
|
||||
od_asprintf(&filter, "(%s=%s)",
|
||||
|
@ -166,7 +207,9 @@ static inline od_retcode_t od_ldap_server_prepare(od_logger_t *logger,
|
|||
"basedn search entries count: %d", count);
|
||||
if (count != 1) {
|
||||
if (count == 0) {
|
||||
// TODO: report err 2 client
|
||||
free(filter);
|
||||
ldap_msgfree(search_message);
|
||||
return LDAP_INSUFFICIENT_ACCESS;
|
||||
} else {
|
||||
}
|
||||
|
||||
|
@ -182,6 +225,31 @@ static inline od_retcode_t od_ldap_server_prepare(od_logger_t *logger,
|
|||
return NOT_OK_RESPONSE;
|
||||
}
|
||||
|
||||
if (rule->ldap_storage_credentials_attr) {
|
||||
struct berval **values = NULL;
|
||||
values = ldap_get_values_len(serv->conn, entry,
|
||||
attributes[0]);
|
||||
if (ldap_count_values_len(values) > 0) {
|
||||
rc = od_ldap_search_storage_credentials(
|
||||
logger, values, rule, client);
|
||||
if (rc != OK_RESPONSE) {
|
||||
free(filter);
|
||||
ldap_memfree(dn);
|
||||
ldap_value_free_len(values);
|
||||
ldap_msgfree(search_message);
|
||||
return LDAP_INSUFFICIENT_ACCESS;
|
||||
}
|
||||
} else {
|
||||
od_debug(logger, "auth_ldap", client, NULL,
|
||||
"error: empty search results");
|
||||
free(filter);
|
||||
ldap_memfree(dn);
|
||||
ldap_value_free_len(values);
|
||||
ldap_msgfree(search_message);
|
||||
return LDAP_INSUFFICIENT_ACCESS;
|
||||
}
|
||||
ldap_value_free_len(values);
|
||||
}
|
||||
auth_user = strdup(dn);
|
||||
|
||||
free(filter);
|
||||
|
@ -199,7 +267,7 @@ static inline od_retcode_t od_ldap_server_prepare(od_logger_t *logger,
|
|||
"");
|
||||
}
|
||||
|
||||
serv->auth_user = auth_user;
|
||||
client->ldap_auth_dn = auth_user;
|
||||
|
||||
return OK_RESPONSE;
|
||||
}
|
||||
|
@ -209,40 +277,45 @@ od_ldap_server_t *od_ldap_server_allocate()
|
|||
od_ldap_server_t *serv = malloc(sizeof(od_ldap_server_t));
|
||||
serv->conn = NULL;
|
||||
serv->endpoint = NULL;
|
||||
serv->auth_user = NULL;
|
||||
|
||||
return serv;
|
||||
}
|
||||
|
||||
static inline od_retcode_t od_ldap_server_init(od_logger_t *logger,
|
||||
od_ldap_server_t *server,
|
||||
od_route_t *route,
|
||||
od_client_t *client)
|
||||
od_retcode_t od_ldap_server_init(od_logger_t *logger, od_ldap_server_t *server,
|
||||
od_rule_t *rule)
|
||||
{
|
||||
od_retcode_t rc;
|
||||
od_id_generate(&server->id, "ls");
|
||||
od_list_init(&server->link);
|
||||
|
||||
server->global = NULL;
|
||||
server->route = route;
|
||||
|
||||
od_ldap_endpoint_t *le = route->rule->ldap_endpoint;
|
||||
od_ldap_endpoint_t *le = rule->ldap_endpoint;
|
||||
server->endpoint = le;
|
||||
|
||||
if (od_init_ldap_conn(&server->conn, le->ldapurl) != OK_RESPONSE) {
|
||||
return NOT_OK_RESPONSE;
|
||||
}
|
||||
|
||||
if (od_ldap_server_prepare(logger, server, client) != OK_RESPONSE) {
|
||||
return NOT_OK_RESPONSE;
|
||||
}
|
||||
return OK_RESPONSE;
|
||||
rc = ldap_simple_bind_s(server->conn,
|
||||
server->endpoint->ldapbinddn ?
|
||||
server->endpoint->ldapbinddn :
|
||||
"",
|
||||
server->endpoint->ldapbindpasswd ?
|
||||
server->endpoint->ldapbindpasswd :
|
||||
"");
|
||||
|
||||
od_debug(logger, "auth_ldap", NULL, NULL,
|
||||
"basednn simple bind result: %d", rc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static inline int od_ldap_server_auth(od_ldap_server_t *serv, od_client_t *cl,
|
||||
kiwi_password_t *tok)
|
||||
{
|
||||
int rc;
|
||||
rc = ldap_simple_bind_s(serv->conn, serv->auth_user, tok->password);
|
||||
rc = ldap_simple_bind_s(serv->conn, cl->ldap_auth_dn, tok->password);
|
||||
|
||||
od_route_t *route = cl->route;
|
||||
if (route->rule->client_fwd_error) {
|
||||
|
@ -252,41 +325,51 @@ static inline int od_ldap_server_auth(od_ldap_server_t *serv, od_client_t *cl,
|
|||
return rc;
|
||||
}
|
||||
|
||||
static inline od_ldap_server_t *od_ldap_server_attach(od_route_t *route,
|
||||
od_client_t *client,
|
||||
bool wait_for_idle)
|
||||
od_ldap_server_t *od_ldap_server_pull(od_logger_t *logger, od_rule_t *rule,
|
||||
bool auth_pool)
|
||||
{
|
||||
assert(route != NULL);
|
||||
od_instance_t *instance = client->global->instance;
|
||||
od_logger_t *logger = &instance->logger;
|
||||
|
||||
od_ldap_server_t *server = NULL;
|
||||
od_route_lock(route);
|
||||
|
||||
#ifdef USE_POOL
|
||||
od_retcode_t rc;
|
||||
od_ldap_endpoint_t *le = rule->ldap_endpoint;
|
||||
od_ldap_server_t *ldap_server = NULL;
|
||||
|
||||
od_server_pool_t *ldap_server_pool;
|
||||
if (auth_pool) {
|
||||
ldap_server_pool = le->ldap_auth_pool;
|
||||
} else {
|
||||
ldap_server_pool = le->ldap_search_pool;
|
||||
}
|
||||
|
||||
od_debug(logger, "auth_ldap", NULL, NULL,
|
||||
"total connections in selected pool: %d",
|
||||
od_server_pool_total(ldap_server_pool));
|
||||
od_ldap_endpoint_lock(le);
|
||||
|
||||
/* get client server from route server pool */
|
||||
for (;;) {
|
||||
server = od_ldap_server_pool_next(&route->ldap_pool,
|
||||
OD_SERVER_IDLE);
|
||||
if (server) {
|
||||
ldap_server = od_ldap_server_pool_next(ldap_server_pool,
|
||||
OD_SERVER_IDLE);
|
||||
if (ldap_server) {
|
||||
od_debug(logger, "auth_ldap", NULL, NULL,
|
||||
"pulling ldap_server from ldap_pool");
|
||||
od_ldap_server_pool_set(ldap_server_pool, ldap_server,
|
||||
OD_SERVER_ACTIVE);
|
||||
od_ldap_endpoint_unlock(le);
|
||||
break;
|
||||
}
|
||||
|
||||
if (wait_for_idle) {
|
||||
if (false) {
|
||||
/* special case, when we are interested only in an idle connection
|
||||
* and do not want to start a new one */
|
||||
// NOT IMPL
|
||||
od_route_unlock(route);
|
||||
od_ldap_endpoint_unlock(le);
|
||||
return NULL;
|
||||
} else {
|
||||
/* Maybe start new connection, if pool_size is zero */
|
||||
/* Maybe start new connection, if we still have capacity for it */
|
||||
|
||||
int connections_in_pool =
|
||||
od_server_pool_total(&route->ldap_pool);
|
||||
int pool_size = route->rule->ldap_pool_size;
|
||||
od_server_pool_total(ldap_server_pool);
|
||||
int pool_size = rule->ldap_pool_size;
|
||||
|
||||
if (pool_size == 0 || connections_in_pool < pool_size) {
|
||||
// TODO: better limit logic here
|
||||
|
@ -294,7 +377,7 @@ static inline od_ldap_server_t *od_ldap_server_attach(od_route_t *route,
|
|||
od_debug(
|
||||
logger, "auth_ldap", NULL, NULL,
|
||||
"spun new connection to ldap server %s",
|
||||
route->rule->ldap_endpoint_name);
|
||||
rule->ldap_endpoint_name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -305,63 +388,106 @@ static inline od_ldap_server_t *od_ldap_server_attach(od_route_t *route,
|
|||
* The condition triggered when a server connection
|
||||
* put into idle state by DETACH events.
|
||||
*/
|
||||
od_route_unlock(route);
|
||||
od_ldap_endpoint_unlock(le);
|
||||
|
||||
uint32_t timeout = route->rule->ldap_pool_timeout;
|
||||
uint32_t timeout = rule->ldap_pool_timeout;
|
||||
if (timeout == 0)
|
||||
timeout = UINT32_MAX;
|
||||
rc = od_route_wait(route, timeout);
|
||||
rc = od_ldap_endpoint_wait(le, timeout);
|
||||
|
||||
if (rc == -1) {
|
||||
od_ldap_endpoint_unlock(le);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
od_route_lock(route);
|
||||
od_ldap_endpoint_lock(le);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (server == NULL) {
|
||||
od_route_unlock(route);
|
||||
|
||||
if (ldap_server == NULL) {
|
||||
/* create new server object */
|
||||
server = od_ldap_server_allocate();
|
||||
ldap_server = od_ldap_server_allocate();
|
||||
|
||||
int ldap_rc =
|
||||
od_ldap_server_init(logger, server, route, client);
|
||||
|
||||
od_route_lock(route);
|
||||
od_ldap_server_pool_set(&route->ldap_pool, server,
|
||||
OD_SERVER_UNDEF);
|
||||
od_route_unlock(route);
|
||||
int ldap_rc = od_ldap_server_init(logger, ldap_server, rule);
|
||||
|
||||
if (ldap_rc != LDAP_SUCCESS) {
|
||||
if (route->rule->client_fwd_error) {
|
||||
od_ldap_error_report_client(client, ldap_rc);
|
||||
}
|
||||
od_ldap_server_free(server);
|
||||
od_ldap_server_free(ldap_server);
|
||||
od_ldap_endpoint_unlock(le);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
od_route_lock(route);
|
||||
od_ldap_server_pool_set(ldap_server_pool, ldap_server,
|
||||
OD_SERVER_ACTIVE);
|
||||
od_ldap_endpoint_unlock(le);
|
||||
}
|
||||
|
||||
od_ldap_server_pool_set(&route->ldap_pool, server, OD_SERVER_ACTIVE);
|
||||
return ldap_server;
|
||||
}
|
||||
|
||||
od_route_unlock(route);
|
||||
static inline od_retcode_t od_ldap_server_attach(od_client_t *client)
|
||||
{
|
||||
od_instance_t *instance = client->global->instance;
|
||||
od_logger_t *logger = &instance->logger;
|
||||
|
||||
return server;
|
||||
od_retcode_t rc;
|
||||
|
||||
/* get client server from route server pool */
|
||||
od_ldap_server_t *server =
|
||||
od_ldap_server_pull(logger, client->rule, false);
|
||||
|
||||
if (server == NULL) {
|
||||
od_debug(&instance->logger, "auth_ldap", client, NULL,
|
||||
"failed to get ldap connection");
|
||||
if (client->rule->client_fwd_error) {
|
||||
od_ldap_error_report_client(client, NOT_OK_RESPONSE);
|
||||
}
|
||||
return NOT_OK_RESPONSE;
|
||||
}
|
||||
|
||||
od_ldap_endpoint_lock(client->rule->ldap_endpoint);
|
||||
|
||||
rc = od_ldap_server_prepare(logger, server, client->rule, client);
|
||||
if (rc == NOT_OK_RESPONSE) {
|
||||
od_debug(&instance->logger, "auth_ldap", client, NULL,
|
||||
"closing bad ldap connection, need relogin");
|
||||
od_ldap_server_pool_set(
|
||||
client->rule->ldap_endpoint->ldap_search_pool, server,
|
||||
OD_SERVER_UNDEF);
|
||||
od_ldap_server_free(server);
|
||||
} else {
|
||||
od_ldap_server_pool_set(
|
||||
client->rule->ldap_endpoint->ldap_search_pool, server,
|
||||
OD_SERVER_IDLE);
|
||||
}
|
||||
|
||||
od_ldap_endpoint_unlock(client->rule->ldap_endpoint);
|
||||
if (rc != OK_RESPONSE) {
|
||||
if (client->rule->client_fwd_error) {
|
||||
od_ldap_error_report_client(client, rc);
|
||||
}
|
||||
return NOT_OK_RESPONSE;
|
||||
}
|
||||
return OK_RESPONSE;
|
||||
}
|
||||
|
||||
od_retcode_t od_auth_ldap(od_client_t *cl, kiwi_password_t *tok)
|
||||
{
|
||||
od_route_t *route = cl->route;
|
||||
od_instance_t *instance = cl->global->instance;
|
||||
od_retcode_t rc;
|
||||
|
||||
od_debug(&instance->logger, "auth_ldap", cl, NULL,
|
||||
"%d connections are currently issued to ldap",
|
||||
od_server_pool_active(&route->ldap_pool));
|
||||
if (cl->rule->ldap_storage_credentials_attr &&
|
||||
cl->rule->ldap_endpoint_name) {
|
||||
rc = OK_RESPONSE;
|
||||
} else {
|
||||
rc = od_ldap_server_attach(cl);
|
||||
}
|
||||
|
||||
if (rc != OK_RESPONSE) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
od_ldap_server_t *serv =
|
||||
od_ldap_server_pull(&instance->logger, cl->rule, true);
|
||||
|
||||
od_ldap_server_t *serv = od_ldap_server_attach(route, cl, false);
|
||||
if (serv == NULL) {
|
||||
od_debug(&instance->logger, "auth_ldap", cl, NULL,
|
||||
"failed to get ldap connection");
|
||||
|
@ -370,41 +496,36 @@ od_retcode_t od_auth_ldap(od_client_t *cl, kiwi_password_t *tok)
|
|||
|
||||
int ldap_rc = od_ldap_server_auth(serv, cl, tok);
|
||||
|
||||
od_ldap_endpoint_lock(cl->rule->ldap_endpoint);
|
||||
|
||||
switch (ldap_rc) {
|
||||
case LDAP_SUCCESS: {
|
||||
#ifndef USE_POOL
|
||||
od_ldap_conn_close(route, serv);
|
||||
#else
|
||||
od_route_lock(route);
|
||||
od_ldap_server_pool_set(&route->ldap_pool, serv,
|
||||
OD_SERVER_IDLE);
|
||||
od_route_unlock(route);
|
||||
#endif
|
||||
return OK_RESPONSE;
|
||||
od_ldap_server_pool_set(cl->rule->ldap_endpoint->ldap_auth_pool,
|
||||
serv, OD_SERVER_IDLE);
|
||||
rc = OK_RESPONSE;
|
||||
break;
|
||||
}
|
||||
case LDAP_INVALID_SYNTAX:
|
||||
case LDAP_INVALID_CREDENTIALS:
|
||||
#ifndef USE_POOL
|
||||
od_ldap_conn_close(route, serv);
|
||||
#else
|
||||
od_route_lock(route);
|
||||
od_ldap_server_pool_set(&route->ldap_pool, serv,
|
||||
OD_SERVER_IDLE);
|
||||
od_route_unlock(route);
|
||||
#endif
|
||||
return NOT_OK_RESPONSE;
|
||||
default:
|
||||
#ifndef USE_POOL
|
||||
od_ldap_conn_close(route, serv);
|
||||
#else
|
||||
od_route_lock(route);
|
||||
/*Need to rebind */
|
||||
od_ldap_server_pool_set(&route->ldap_pool, serv,
|
||||
OD_SERVER_UNDEF);
|
||||
od_route_unlock(route);
|
||||
#endif
|
||||
return NOT_OK_RESPONSE;
|
||||
/* fallthrough */
|
||||
case LDAP_INVALID_CREDENTIALS: {
|
||||
od_ldap_server_pool_set(cl->rule->ldap_endpoint->ldap_auth_pool,
|
||||
serv, OD_SERVER_IDLE);
|
||||
rc = NOT_OK_RESPONSE;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
/*Need to rebind */
|
||||
od_ldap_server_pool_set(cl->rule->ldap_endpoint->ldap_auth_pool,
|
||||
serv, OD_SERVER_UNDEF);
|
||||
od_ldap_server_free(serv);
|
||||
rc = NOT_OK_RESPONSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
od_ldap_endpoint_unlock(cl->rule->ldap_endpoint);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
od_retcode_t od_ldap_conn_close(od_attribute_unused() od_route_t *route,
|
||||
|
@ -445,6 +566,21 @@ od_ldap_endpoint_t *od_ldap_endpoint_alloc()
|
|||
// preparsed connect url
|
||||
le->ldapurl = NULL;
|
||||
|
||||
od_server_pool_t *ldap_auth_pool = malloc(sizeof(*ldap_auth_pool));
|
||||
od_server_pool_init(ldap_auth_pool);
|
||||
le->ldap_auth_pool = ldap_auth_pool;
|
||||
|
||||
od_server_pool_t *ldap_search_pool = malloc(sizeof(*ldap_search_pool));
|
||||
od_server_pool_init(ldap_search_pool);
|
||||
le->ldap_search_pool = ldap_search_pool;
|
||||
|
||||
le->wait_bus = machine_channel_create();
|
||||
if (le->wait_bus == NULL) {
|
||||
od_ldap_endpoint_free(le);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pthread_mutex_init(&le->lock, NULL);
|
||||
return le;
|
||||
}
|
||||
|
||||
|
@ -488,12 +624,62 @@ od_retcode_t od_ldap_endpoint_free(od_ldap_endpoint_t *le)
|
|||
}
|
||||
|
||||
od_list_unlink(&le->link);
|
||||
if (le->ldap_search_pool) {
|
||||
od_ldap_server_pool_free(le->ldap_search_pool);
|
||||
}
|
||||
|
||||
if (le->ldap_auth_pool) {
|
||||
od_ldap_server_pool_free(le->ldap_search_pool);
|
||||
}
|
||||
|
||||
pthread_mutex_destroy(&le->lock);
|
||||
if (le->wait_bus)
|
||||
machine_channel_free(le->wait_bus);
|
||||
|
||||
free(le);
|
||||
|
||||
return OK_RESPONSE;
|
||||
}
|
||||
|
||||
od_ldap_storage_credentials_t *od_ldap_storage_credentials_alloc()
|
||||
{
|
||||
od_ldap_storage_credentials_t *lsc =
|
||||
malloc(sizeof(od_ldap_storage_credentials_t));
|
||||
if (lsc == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
od_list_init(&lsc->link);
|
||||
|
||||
lsc->name = NULL;
|
||||
|
||||
lsc->lsc_username = NULL;
|
||||
lsc->lsc_password = NULL;
|
||||
|
||||
return lsc;
|
||||
}
|
||||
|
||||
od_retcode_t
|
||||
od_ldap_storage_credentials_free(od_ldap_storage_credentials_t *lsc)
|
||||
{
|
||||
if (lsc->name) {
|
||||
free(lsc->name);
|
||||
}
|
||||
|
||||
if (lsc->lsc_username) {
|
||||
free(lsc->lsc_username);
|
||||
}
|
||||
|
||||
if (lsc->lsc_password) {
|
||||
free(lsc->lsc_password);
|
||||
}
|
||||
|
||||
od_list_unlink(&lsc->link);
|
||||
|
||||
free(lsc);
|
||||
|
||||
return OK_RESPONSE;
|
||||
}
|
||||
|
||||
od_retcode_t od_ldap_endpoint_add(od_ldap_endpoint_t *ldaps,
|
||||
od_ldap_endpoint_t *target)
|
||||
{
|
||||
|
@ -549,3 +735,21 @@ od_retcode_t od_ldap_endpoint_remove(od_ldap_endpoint_t *ldaps,
|
|||
/* target ldap server was not found */
|
||||
return NOT_OK_RESPONSE;
|
||||
}
|
||||
|
||||
od_ldap_storage_credentials_t *
|
||||
od_ldap_storage_credentials_find(od_list_t *ldap_storage_creds_list, char *name)
|
||||
{
|
||||
od_list_t *i;
|
||||
|
||||
od_list_foreach(ldap_storage_creds_list, i)
|
||||
{
|
||||
od_ldap_storage_credentials_t *lsc =
|
||||
od_container_of(i, od_ldap_storage_credentials_t, link);
|
||||
if (strcmp(lsc->name, name) == 0) {
|
||||
return lsc;
|
||||
}
|
||||
}
|
||||
|
||||
/* target storage user was not found */
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#define OD_ODYSSEY_LDAP_ENDPOINT_H
|
||||
|
||||
typedef struct {
|
||||
pthread_mutex_t lock;
|
||||
char *name;
|
||||
|
||||
char *ldapserver;
|
||||
|
@ -23,6 +24,11 @@ typedef struct {
|
|||
// preparsed connect url
|
||||
char *ldapurl;
|
||||
|
||||
void *ldap_search_pool;
|
||||
void *ldap_auth_pool;
|
||||
|
||||
machine_channel_t *wait_bus;
|
||||
|
||||
od_list_t link;
|
||||
} od_ldap_endpoint_t;
|
||||
|
||||
|
@ -42,5 +48,54 @@ extern od_retcode_t od_ldap_endpoint_remove(od_ldap_endpoint_t *ldaps,
|
|||
extern od_ldap_endpoint_t *od_ldap_endpoint_alloc();
|
||||
extern od_retcode_t od_ldap_endpoint_init(od_ldap_endpoint_t *);
|
||||
extern od_retcode_t od_ldap_endpoint_free(od_ldap_endpoint_t *le);
|
||||
/* ldap_storage_credentials */
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
char *lsc_username;
|
||||
char *lsc_password;
|
||||
|
||||
od_list_t link;
|
||||
} od_ldap_storage_credentials_t;
|
||||
|
||||
static inline void od_ldap_endpoint_lock(od_ldap_endpoint_t *le)
|
||||
{
|
||||
pthread_mutex_lock(&le->lock);
|
||||
}
|
||||
|
||||
static inline void od_ldap_endpoint_unlock(od_ldap_endpoint_t *le)
|
||||
{
|
||||
pthread_mutex_unlock(&le->lock);
|
||||
}
|
||||
|
||||
static inline int od_ldap_endpoint_wait(od_ldap_endpoint_t *le,
|
||||
uint32_t time_ms)
|
||||
{
|
||||
machine_msg_t *msg;
|
||||
msg = machine_channel_read(le->wait_bus, time_ms);
|
||||
if (msg) {
|
||||
machine_msg_free(msg);
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int od_ldap_endpoint_signal(od_ldap_endpoint_t *le)
|
||||
{
|
||||
machine_msg_t *msg;
|
||||
msg = machine_msg_create(0);
|
||||
if (msg == NULL) {
|
||||
return -1;
|
||||
}
|
||||
machine_channel_write(le->wait_bus, msg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern od_ldap_storage_credentials_t *
|
||||
od_ldap_storage_credentials_find(od_list_t *storage_users, char *target);
|
||||
|
||||
// -------------------------------------------------------
|
||||
extern od_ldap_storage_credentials_t *od_ldap_storage_credentials_alloc();
|
||||
extern od_retcode_t
|
||||
od_ldap_storage_credentials_free(od_ldap_storage_credentials_t *lsc);
|
||||
#endif /* OD_ODYSSEY_LDAP_ENDPOINT_H */
|
||||
|
|
|
@ -14,8 +14,6 @@ typedef struct {
|
|||
od_global_t *global;
|
||||
void *route;
|
||||
|
||||
char *auth_user;
|
||||
|
||||
od_list_t link;
|
||||
} od_ldap_server_t;
|
||||
|
||||
|
@ -23,5 +21,13 @@ extern od_retcode_t od_auth_ldap(od_client_t *cl, kiwi_password_t *tok);
|
|||
|
||||
extern od_retcode_t od_ldap_server_free(od_ldap_server_t *serv);
|
||||
extern od_ldap_server_t *od_ldap_server_allocate();
|
||||
|
||||
extern od_retcode_t od_ldap_server_init(od_logger_t *logger,
|
||||
od_ldap_server_t *serv,
|
||||
od_rule_t *rule);
|
||||
extern od_retcode_t od_ldap_server_prepare(od_logger_t *logger,
|
||||
od_ldap_server_t *serv,
|
||||
od_rule_t *rule,
|
||||
od_client_t *client);
|
||||
extern od_ldap_server_t *od_ldap_server_pull(od_logger_t *logger,
|
||||
od_rule_t *rule, bool auth_pool);
|
||||
#endif /* ODYSSEY_LDAP_H */
|
||||
|
|
|
@ -20,10 +20,6 @@ struct od_route {
|
|||
od_server_pool_t server_pool;
|
||||
od_client_pool_t client_pool;
|
||||
|
||||
#ifdef LDAP_FOUND
|
||||
od_server_pool_t ldap_pool;
|
||||
#endif
|
||||
|
||||
kiwi_params_lock_t params;
|
||||
int64_t tcp_connections;
|
||||
int last_heartbeat;
|
||||
|
@ -45,10 +41,6 @@ static inline void od_route_init(od_route_t *route, bool extra_route_logging)
|
|||
od_route_id_init(&route->id);
|
||||
od_server_pool_init(&route->server_pool);
|
||||
|
||||
#ifdef LDAP_FOUND
|
||||
od_server_pool_init(&route->ldap_pool);
|
||||
#endif
|
||||
|
||||
od_client_pool_init(&route->client_pool);
|
||||
|
||||
/* stat init */
|
||||
|
@ -73,9 +65,7 @@ static inline void od_route_free(od_route_t *route)
|
|||
{
|
||||
od_route_id_free(&route->id);
|
||||
od_pg_server_pool_free(&route->server_pool);
|
||||
#ifdef LDAP_FOUND
|
||||
od_ldap_server_pool_free(&route->ldap_pool);
|
||||
#endif
|
||||
|
||||
kiwi_params_lock_free(&route->params);
|
||||
if (route->wait_bus)
|
||||
machine_channel_free(route->wait_bus);
|
||||
|
|
|
@ -354,7 +354,62 @@ od_router_status_t od_router_route(od_router_t *router, od_client_t *client)
|
|||
return OD_ROUTER_ERROR_REPLICATION;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef LDAP_FOUND
|
||||
if (rule->ldap_storage_credentials_attr) {
|
||||
od_ldap_server_t *ldap_server = NULL;
|
||||
ldap_server =
|
||||
od_ldap_server_pull(&instance->logger, rule, false);
|
||||
if (ldap_server == NULL) {
|
||||
od_debug(&instance->logger, "routing", client, NULL,
|
||||
"failed to get ldap connection");
|
||||
od_router_unlock(router);
|
||||
return OD_ROUTER_ERROR_NOT_FOUND;
|
||||
}
|
||||
int ldap_rc = od_ldap_server_prepare(&instance->logger,
|
||||
ldap_server, rule, client);
|
||||
switch (ldap_rc) {
|
||||
case OK_RESPONSE: {
|
||||
od_ldap_endpoint_lock(rule->ldap_endpoint);
|
||||
od_ldap_server_pool_set(
|
||||
rule->ldap_endpoint->ldap_search_pool,
|
||||
ldap_server, OD_SERVER_IDLE);
|
||||
od_ldap_endpoint_unlock(rule->ldap_endpoint);
|
||||
id.user = client->ldap_storage_username;
|
||||
id.user_len = client->ldap_storage_username_len + 1;
|
||||
rule->storage_user = client->ldap_storage_username;
|
||||
rule->storage_user_len =
|
||||
client->ldap_storage_username_len;
|
||||
rule->storage_password = client->ldap_storage_password;
|
||||
rule->storage_password_len =
|
||||
client->ldap_storage_password_len;
|
||||
od_debug(&instance->logger, "routing", client, NULL,
|
||||
"route->id.user changed to %s", id.user);
|
||||
break;
|
||||
}
|
||||
case LDAP_INSUFFICIENT_ACCESS: {
|
||||
od_ldap_endpoint_lock(rule->ldap_endpoint);
|
||||
od_ldap_server_pool_set(
|
||||
rule->ldap_endpoint->ldap_search_pool,
|
||||
ldap_server, OD_SERVER_IDLE);
|
||||
od_ldap_endpoint_unlock(rule->ldap_endpoint);
|
||||
od_router_unlock(router);
|
||||
return OD_ROUTER_INSUFFICIENT_ACCESS;
|
||||
}
|
||||
default: {
|
||||
od_debug(&instance->logger, "routing", client, NULL,
|
||||
"closing bad ldap connection, need relogin");
|
||||
od_ldap_endpoint_lock(rule->ldap_endpoint);
|
||||
od_ldap_server_pool_set(
|
||||
rule->ldap_endpoint->ldap_search_pool,
|
||||
ldap_server, OD_SERVER_UNDEF);
|
||||
od_ldap_endpoint_unlock(rule->ldap_endpoint);
|
||||
od_ldap_server_free(ldap_server);
|
||||
od_router_unlock(router);
|
||||
return OD_ROUTER_ERROR_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/* match or create dynamic route */
|
||||
od_route_t *route;
|
||||
route = od_route_pool_match(&router->route_pool, &id, rule);
|
||||
|
|
|
@ -40,6 +40,14 @@ od_ldap_endpoint_t *od_rules_ldap_endpoint_add(od_rules_t *rules,
|
|||
od_list_append(&rules->ldap_endpoints, &ldap->link);
|
||||
return ldap;
|
||||
}
|
||||
|
||||
od_ldap_storage_credentials_t *
|
||||
od_rule_ldap_storage_credentials_add(od_rule_t *rule,
|
||||
od_ldap_storage_credentials_t *lsc)
|
||||
{
|
||||
od_list_append(&rule->ldap_storage_creds_list, &lsc->link);
|
||||
return lsc;
|
||||
}
|
||||
#endif
|
||||
|
||||
od_rule_storage_t *od_rules_storage_add(od_rules_t *rules,
|
||||
|
@ -148,6 +156,8 @@ od_rule_t *od_rules_add(od_rules_t *rules)
|
|||
#ifdef LDAP_FOUND
|
||||
rule->ldap_endpoint_name = NULL;
|
||||
rule->ldap_endpoint = NULL;
|
||||
rule->ldap_storage_credentials_attr = NULL;
|
||||
od_list_init(&rule->ldap_storage_creds_list);
|
||||
#endif
|
||||
|
||||
kiwi_vars_init(&rule->vars);
|
||||
|
@ -200,6 +210,23 @@ void od_rules_rule_free(od_rule_t *rule)
|
|||
}
|
||||
#ifdef PAM_FOUND
|
||||
od_pam_auth_data_free(rule->auth_pam_data);
|
||||
#endif
|
||||
#ifdef LDAP_FOUND
|
||||
if (rule->ldap_endpoint_name)
|
||||
free(rule->ldap_endpoint_name);
|
||||
if (rule->ldap_storage_credentials_attr)
|
||||
free(rule->ldap_storage_credentials_attr);
|
||||
if (rule->ldap_endpoint)
|
||||
od_ldap_endpoint_free(rule->ldap_endpoint);
|
||||
if (&rule->ldap_storage_creds_list) {
|
||||
od_list_foreach_safe(&rule->ldap_storage_creds_list, i, n)
|
||||
{
|
||||
od_ldap_storage_credentials_t *lsc;
|
||||
lsc = od_container_of(i, od_ldap_storage_credentials_t,
|
||||
link);
|
||||
od_ldap_storage_credentials_free(lsc);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (rule->auth_module) {
|
||||
free(rule->auth_module);
|
||||
|
@ -1138,6 +1165,35 @@ void od_rules_print(od_rules_t *rules, od_logger_t *logger)
|
|||
" ldap_endpoint_name %s",
|
||||
rule->ldap_endpoint_name);
|
||||
}
|
||||
if (rule->ldap_storage_credentials_attr != NULL) {
|
||||
od_log(logger, "rules", NULL, NULL,
|
||||
" ldap_storage_credentials_attr %s",
|
||||
rule->ldap_storage_credentials_attr);
|
||||
}
|
||||
if (&rule->ldap_storage_creds_list) {
|
||||
od_list_t *f;
|
||||
od_list_foreach(&rule->ldap_storage_creds_list, f)
|
||||
{
|
||||
od_ldap_storage_credentials_t *lsc;
|
||||
lsc = od_container_of(
|
||||
f, od_ldap_storage_credentials_t, link);
|
||||
if (lsc->name) {
|
||||
od_log(logger, "rule", NULL, NULL,
|
||||
" lsc_name %s",
|
||||
lsc->name);
|
||||
}
|
||||
if (lsc->lsc_username) {
|
||||
od_log(logger, "rule", NULL, NULL,
|
||||
" lsc_username %s",
|
||||
lsc->lsc_username);
|
||||
}
|
||||
if (lsc->lsc_password) {
|
||||
od_log(logger, "rule", NULL, NULL,
|
||||
" lsc_password %s",
|
||||
lsc->lsc_password);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
od_log(logger, "rules", NULL, NULL,
|
||||
" storage %s",
|
||||
|
|
|
@ -90,6 +90,8 @@ struct od_rule {
|
|||
od_ldap_endpoint_t *ldap_endpoint;
|
||||
int ldap_pool_timeout;
|
||||
int ldap_pool_size;
|
||||
od_list_t ldap_storage_creds_list;
|
||||
char *ldap_storage_credentials_attr;
|
||||
#endif
|
||||
|
||||
char *auth_module;
|
||||
|
@ -175,6 +177,9 @@ od_retcode_t od_rules_storages_watchdogs_run(od_logger_t *logger,
|
|||
/* ldap endpoint */
|
||||
od_ldap_endpoint_t *od_rules_ldap_endpoint_add(od_rules_t *rules,
|
||||
od_ldap_endpoint_t *ldap);
|
||||
od_ldap_storage_credentials_t *
|
||||
od_rule_ldap_storage_credentials_add(od_rule_t *rule,
|
||||
od_ldap_storage_credentials_t *lsc);
|
||||
#endif
|
||||
|
||||
/* auth */
|
||||
|
|
|
@ -105,6 +105,7 @@ typedef enum {
|
|||
OD_ROUTER_ERROR_LIMIT_ROUTE,
|
||||
OD_ROUTER_ERROR_TIMEDOUT,
|
||||
OD_ROUTER_ERROR_REPLICATION,
|
||||
OD_ROUTER_INSUFFICIENT_ACCESS,
|
||||
} od_router_status_t;
|
||||
|
||||
static inline char *od_router_status_to_str(od_router_status_t status)
|
||||
|
|
Loading…
Reference in New Issue