mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
Implement user pre-authentication control with kdcpolicy plugin
We created a Kerberos kdcpolicy plugin to enforce user pre-authentication policy for newly added pkinit and hardened policy. In the past version of freeIPA, password enforcement exists but was done by removing key data for a principal while parsing LDAP entry for it. This hack is also removed and is now also enforced by kdcpolicy plugin instead. Resolves: https://pagure.io/freeipa/issue/8001 Signed-off-by: Changmin Teng <cteng@redhat.com> Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com> Reviewed-By: Simo Sorce <ssorce@redhat.com> Reviewed-By: Robbie Harwood <rharwood@redhat.com>
This commit is contained in:
parent
179c8f4009
commit
15ff9c8fec
@ -141,6 +141,7 @@ struct ipadb_e_data {
|
|||||||
time_t last_admin_unlock;
|
time_t last_admin_unlock;
|
||||||
char **authz_data;
|
char **authz_data;
|
||||||
bool has_tktpolaux;
|
bool has_tktpolaux;
|
||||||
|
enum ipadb_user_auth user_auth;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ipadb_context *ipadb_get_context(krb5_context kcontext);
|
struct ipadb_context *ipadb_get_context(krb5_context kcontext);
|
||||||
|
@ -18,12 +18,82 @@ ipa_kdcpolicy_check_as(krb5_context context, krb5_kdcpolicy_moddata moddata,
|
|||||||
const char **status, krb5_deltat *lifetime_out,
|
const char **status, krb5_deltat *lifetime_out,
|
||||||
krb5_deltat *renew_lifetime_out)
|
krb5_deltat *renew_lifetime_out)
|
||||||
{
|
{
|
||||||
|
krb5_error_code kerr;
|
||||||
|
enum ipadb_user_auth ua;
|
||||||
|
struct ipadb_e_data *ied;
|
||||||
|
int valid_auth_indicators = 0;
|
||||||
|
|
||||||
*status = NULL;
|
*status = NULL;
|
||||||
*lifetime_out = 0;
|
*lifetime_out = 0;
|
||||||
*renew_lifetime_out = 0;
|
*renew_lifetime_out = 0;
|
||||||
|
|
||||||
krb5_klog_syslog(LOG_INFO, "IPA kdcpolicy: checking AS-REQ.");
|
krb5_klog_syslog(LOG_INFO, "IPA kdcpolicy: checking AS-REQ.");
|
||||||
|
|
||||||
|
ied = (struct ipadb_e_data *)client->e_data;
|
||||||
|
if (ied == NULL || ied->magic != IPA_E_DATA_MAGIC) {
|
||||||
|
/* e-data is not availble, getting user auth from LDAP */
|
||||||
|
krb5_klog_syslog(LOG_INFO, "IPA kdcpolicy: client e_data not availble. Try fetching...");
|
||||||
|
kerr = ipadb_get_principal(context, request->client, KRB5_KDB_FLAG_ALIAS_OK, &client);
|
||||||
|
if (kerr != 0) {
|
||||||
|
krb5_klog_syslog(LOG_ERR, "IPA kdcpolicy: ipadb_find_principal failed.");
|
||||||
|
return kerr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ied = (struct ipadb_e_data *)client->e_data;
|
||||||
|
if (ied == NULL && ied->magic != IPA_E_DATA_MAGIC) {
|
||||||
|
krb5_klog_syslog(LOG_ERR, "IPA kdcpolicy: client e_data fetching failed.");
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ua = ied->user_auth;
|
||||||
|
|
||||||
|
/* If no mechanisms are set, allow every auth method */
|
||||||
|
if (ua == IPADB_USER_AUTH_NONE) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For each auth indicator, see if it is allowed for that user */
|
||||||
|
for (int i = 0; auth_indicators[i] != NULL; i++) {
|
||||||
|
const char *auth_indicator = auth_indicators[i];
|
||||||
|
|
||||||
|
if (strcmp(auth_indicator, "otp") == 0) {
|
||||||
|
valid_auth_indicators++;
|
||||||
|
if (!(ua & IPADB_USER_AUTH_OTP)) {
|
||||||
|
*status = "OTP pre-authentication not allowed for this user.";
|
||||||
|
return KRB5KDC_ERR_POLICY;
|
||||||
|
}
|
||||||
|
} else if (strcmp(auth_indicator, "radius") == 0) {
|
||||||
|
valid_auth_indicators++;
|
||||||
|
if (!(ua & IPADB_USER_AUTH_RADIUS)) {
|
||||||
|
*status = "OTP pre-authentication not allowed for this user.";
|
||||||
|
return KRB5KDC_ERR_POLICY;
|
||||||
|
}
|
||||||
|
} else if (strcmp(auth_indicator, "pkinit") == 0) {
|
||||||
|
valid_auth_indicators++;
|
||||||
|
if (!(ua & IPADB_USER_AUTH_PKINIT)) {
|
||||||
|
*status = "PKINIT pre-authentication not allowed for this user.";
|
||||||
|
return KRB5KDC_ERR_POLICY;
|
||||||
|
}
|
||||||
|
} else if (strcmp(auth_indicator, "hardened") == 0) {
|
||||||
|
valid_auth_indicators++;
|
||||||
|
/* Allow hardened even if only password pre-auth is allowed */
|
||||||
|
if (!(ua & (IPADB_USER_AUTH_HARDENED | IPADB_USER_AUTH_PASSWORD))) {
|
||||||
|
*status = "Password pre-authentication not not allowed for this user.";
|
||||||
|
return KRB5KDC_ERR_POLICY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* There is no auth indicator assigned for non-hardened password authentication
|
||||||
|
* so we assume password is used when no supported indicator exists */
|
||||||
|
if (!valid_auth_indicators) {
|
||||||
|
if (!(ua & IPADB_USER_AUTH_PASSWORD)) {
|
||||||
|
*status = "Non-hardened password authentication not allowed for this user.";
|
||||||
|
return KRB5KDC_ERR_POLICY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -318,15 +318,6 @@ static void ipadb_validate_radius(struct ipadb_context *ipactx,
|
|||||||
ldap_value_free_len(vals);
|
ldap_value_free_len(vals);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ipadb_validate_password(struct ipadb_context *ipactx,
|
|
||||||
LDAPMessage *lentry,
|
|
||||||
enum ipadb_user_auth *ua)
|
|
||||||
{
|
|
||||||
/* If no mechanisms are set, use password. */
|
|
||||||
if (*ua == IPADB_USER_AUTH_NONE)
|
|
||||||
*ua |= IPADB_USER_AUTH_PASSWORD;
|
|
||||||
}
|
|
||||||
|
|
||||||
static enum ipadb_user_auth ipadb_get_user_auth(struct ipadb_context *ipactx,
|
static enum ipadb_user_auth ipadb_get_user_auth(struct ipadb_context *ipactx,
|
||||||
LDAPMessage *lentry)
|
LDAPMessage *lentry)
|
||||||
{
|
{
|
||||||
@ -354,7 +345,6 @@ static enum ipadb_user_auth ipadb_get_user_auth(struct ipadb_context *ipactx,
|
|||||||
/* Perform flag validation. */
|
/* Perform flag validation. */
|
||||||
ipadb_validate_otp(ipactx, lentry, &ua);
|
ipadb_validate_otp(ipactx, lentry, &ua);
|
||||||
ipadb_validate_radius(ipactx, lentry, &ua);
|
ipadb_validate_radius(ipactx, lentry, &ua);
|
||||||
ipadb_validate_password(ipactx, lentry, &ua);
|
|
||||||
|
|
||||||
return ua;
|
return ua;
|
||||||
}
|
}
|
||||||
@ -708,13 +698,6 @@ static krb5_error_code ipadb_parse_ldap_entry(krb5_context kcontext,
|
|||||||
&res_key_data, &result, &mkvno);
|
&res_key_data, &result, &mkvno);
|
||||||
switch (ret) {
|
switch (ret) {
|
||||||
case 0:
|
case 0:
|
||||||
/* Only set a principal's key if password auth should be used. */
|
|
||||||
if (!(ua & IPADB_USER_AUTH_PASSWORD)) {
|
|
||||||
/* This is the same behavior as ENOENT below. */
|
|
||||||
ipa_krb5_free_key_data(res_key_data, result);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
entry->key_data = res_key_data;
|
entry->key_data = res_key_data;
|
||||||
entry->n_key_data = result;
|
entry->n_key_data = result;
|
||||||
if (mkvno) {
|
if (mkvno) {
|
||||||
@ -851,6 +834,8 @@ static krb5_error_code ipadb_parse_ldap_entry(krb5_context kcontext,
|
|||||||
ied->authz_data = authz_data_list;
|
ied->authz_data = authz_data_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ied->user_auth = ua;
|
||||||
|
|
||||||
/* If enabled, set the otp user string, enabling otp. */
|
/* If enabled, set the otp user string, enabling otp. */
|
||||||
if (ua & IPADB_USER_AUTH_OTP) {
|
if (ua & IPADB_USER_AUTH_OTP) {
|
||||||
kerr = ipadb_set_tl_data(entry, KRB5_TL_STRING_ATTRS,
|
kerr = ipadb_set_tl_data(entry, KRB5_TL_STRING_ATTRS,
|
||||||
|
Loading…
Reference in New Issue
Block a user