mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2026-10-25 22:50:12 -05:00
Merge branch 'upstream'
This commit is contained in:
commit
d19214ab8d
111 files changed
+18034
-15591
No files matched your search
+2
-14
@@ -4,9 +4,8 @@ set -ex
|
||||
FLAVOR="$1"
|
||||
ENVPYTHON="$(realpath -s "$2")"
|
||||
ENVSITEPACKAGESDIR="$(realpath -s "$3")"
|
||||
ENVDIR="$4"
|
||||
# 4...end are package requirements
|
||||
shift 4
|
||||
# 3...end are package requirements
|
||||
shift 3
|
||||
|
||||
TOXINIDIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
|
||||
@@ -26,21 +25,10 @@ if [ ! -f "${TOXINIDIR}/tox.ini" ]; then
|
||||
exit 3
|
||||
fi
|
||||
|
||||
if [ ! -d "${ENVDIR}" ]; then
|
||||
echo "${ENVDIR}: no such directory"
|
||||
exit 4
|
||||
fi
|
||||
|
||||
# https://pip.pypa.io/en/stable/user_guide/#environment-variables
|
||||
export PIP_CACHE_DIR="${TOXINIDIR}/.tox/cache"
|
||||
mkdir -p "${PIP_CACHE_DIR}"
|
||||
|
||||
# /tmp could be mounted with noexec option.
|
||||
# pip checks if path is executable and if not then doesn't set such
|
||||
# permission bits
|
||||
export PIP_BUILD="${ENVDIR}/pip_build"
|
||||
rm -rf "${PIP_BUILD}"
|
||||
|
||||
DISTBUNDLE="${TOXINIDIR}/dist/bundle"
|
||||
mkdir -p "${DISTBUNDLE}"
|
||||
|
||||
|
||||
@@ -1076,11 +1076,13 @@ args: 0,1,1
|
||||
option: Str('version?')
|
||||
output: Output('result')
|
||||
command: config_mod/1
|
||||
args: 0,29,3
|
||||
args: 0,32,3
|
||||
option: Flag('add_sids?', autofill=True, default=False)
|
||||
option: Str('addattr*', cli_name='addattr')
|
||||
option: Flag('all', autofill=True, cli_name='all', default=False)
|
||||
option: Str('ca_renewal_master_server?', autofill=False)
|
||||
option: Str('delattr*', cli_name='delattr')
|
||||
option: Flag('enable_sid?', autofill=True, default=False)
|
||||
option: StrEnum('ipaconfigstring*', autofill=False, cli_name='ipaconfigstring', values=[u'AllowNThash', u'KDC:Disable Last Success', u'KDC:Disable Lockout', u'KDC:Disable Default Preauth for SPNs'])
|
||||
option: Str('ipadefaultemaildomain?', autofill=False, cli_name='emaildomain')
|
||||
option: Str('ipadefaultloginshell?', autofill=False, cli_name='defaultshell')
|
||||
@@ -1102,6 +1104,7 @@ option: StrEnum('ipauserauthtype*', autofill=False, cli_name='user_auth_type', v
|
||||
option: Bool('ipauserdefaultsubordinateid?', autofill=False, cli_name='user_default_subid')
|
||||
option: Str('ipauserobjectclasses*', autofill=False, cli_name='userobjectclasses')
|
||||
option: IA5Str('ipausersearchfields?', autofill=False, cli_name='usersearch')
|
||||
option: Str('netbios_name?', autofill=False)
|
||||
option: Flag('raw', autofill=True, cli_name='raw', default=False)
|
||||
option: Flag('rights', autofill=True, default=False)
|
||||
option: Str('setattr*', cli_name='setattr')
|
||||
|
||||
@@ -81,6 +81,7 @@ Developers:
|
||||
Jeremy Frasier
|
||||
Jérôme Fenal
|
||||
Jim Meyering
|
||||
Jochen Kellner
|
||||
JoeDrane
|
||||
John Dennis
|
||||
John L
|
||||
@@ -134,6 +135,7 @@ Developers:
|
||||
Ondřej Hamada
|
||||
Orion Poplawski
|
||||
Patrice Duc-Jacquet
|
||||
Pavel Březina
|
||||
Pavel Picka
|
||||
Pavel Vomáčka
|
||||
Pavel Zůna
|
||||
|
||||
+31
-6
@@ -216,7 +216,7 @@ endif
|
||||
$(MAKE) $(AM_MAKEFLAGS) acilint apilint polint pylint jslint $(RPMLINT_TARGET) yamllint check
|
||||
@echo "All tests passed."
|
||||
|
||||
.PHONY: fastcheck fasttest fastlint
|
||||
.PHONY: fastcheck fasttest fastlint fastcodestyle
|
||||
fastcheck:
|
||||
@$(MAKE) -j1 $(AM_MAKEFLAGS) fastlint $(RPMLINT_TARGET) yamllint fasttest apilint acilint
|
||||
|
||||
@@ -229,7 +229,36 @@ fasttest: $(GENERATED_PYTHON_FILES) ipasetup.py
|
||||
--ignore $(abspath $(top_srcdir))/ipatests/test_integration \
|
||||
--ignore $(abspath $(top_srcdir))/ipatests/test_xmlrpc
|
||||
|
||||
fastlint: $(GENERATED_PYTHON_FILES) ipasetup.py acilint apilint
|
||||
fastcodestyle: $(GENERATED_PYTHON_FILES) ipasetup.py
|
||||
@ # keep Python files in sync to pycodestyle configuration in
|
||||
@ # tox.ini(filename=)
|
||||
@echo "Fast code style checking with $(PYTHON) from branch '$(GIT_BRANCH)'"
|
||||
|
||||
@MERGEBASE=$$(git merge-base --fork-point $(GIT_BRANCH)); \
|
||||
PYFILES=$$(git diff --name-only --diff-filter=d $${MERGEBASE} \
|
||||
| grep -E '\.py$$' ); \
|
||||
INFILES=$$(git diff --name-only --diff-filter=d $${MERGEBASE} \
|
||||
| grep -E '\.in$$' \
|
||||
| xargs -n1 file 2>/dev/null | grep Python \
|
||||
| cut -d':' -f1; ); \
|
||||
if [ -n "$${PYFILES}" ] && [ -n "$${INFILES}" ]; then \
|
||||
FILES="$$( printf $${PYFILES}\\n$${INFILES} )" ; \
|
||||
elif [ -n "$${PYFILES}" ]; then \
|
||||
FILES="$${PYFILES}" ; \
|
||||
else \
|
||||
FILES="$${INFILES}" ; \
|
||||
fi ; \
|
||||
if [ -n "$${FILES}" ]; then \
|
||||
echo -e "Fast code style checking for files:\n$${FILES}\n"; \
|
||||
echo "pycodestyle"; \
|
||||
echo "-----------"; \
|
||||
git diff -U0 $${MERGEBASE} -- $${FILES} | \
|
||||
$(PYTHON) -m pycodestyle -v --diff || exit $$?; \
|
||||
else \
|
||||
echo "No modified Python files found"; \
|
||||
fi
|
||||
|
||||
fastlint: $(GENERATED_PYTHON_FILES) ipasetup.py fastcodestyle acilint apilint
|
||||
if ! WITH_PYLINT
|
||||
@echo "ERROR: pylint not available"; exit 1
|
||||
endif
|
||||
@@ -251,10 +280,6 @@ endif
|
||||
fi ; \
|
||||
if [ -n "$${FILES}" ]; then \
|
||||
echo -e "Fast linting files:\n$${FILES}\n"; \
|
||||
echo "pycodestyle"; \
|
||||
echo "-----------"; \
|
||||
git diff -U0 $${MERGEBASE} | \
|
||||
$(PYTHON) -m pycodestyle --diff || exit $$?; \
|
||||
echo -e "\npylint"; \
|
||||
echo "------"; \
|
||||
$(PYTHON) -m pylint --version; \
|
||||
|
||||
+3
-3
@@ -21,7 +21,7 @@
|
||||
########################################################
|
||||
define(IPA_VERSION_MAJOR, 4)
|
||||
define(IPA_VERSION_MINOR, 9)
|
||||
define(IPA_VERSION_RELEASE, 7)
|
||||
define(IPA_VERSION_RELEASE, 8)
|
||||
|
||||
########################################################
|
||||
# For 'pre' releases the version will be #
|
||||
@@ -86,8 +86,8 @@ define(IPA_DATA_VERSION, 20100614120000)
|
||||
# #
|
||||
########################################################
|
||||
define(IPA_API_VERSION_MAJOR, 2)
|
||||
# Last change: add subordinate id feature
|
||||
define(IPA_API_VERSION_MINOR, 243)
|
||||
# Last change: add enable_sid to config
|
||||
define(IPA_API_VERSION_MINOR, 245)
|
||||
|
||||
|
||||
########################################################
|
||||
|
||||
@@ -172,6 +172,9 @@ Specifies the Kerberos realm.
|
||||
.B replication_wait_timeout <seconds>
|
||||
The time to wait for a new entry to be replicated during replica installation. The default value is 300 seconds.
|
||||
.TP
|
||||
.B schema_ttl <seconds>
|
||||
The number of seconds for the ipa tool to cache the IPA API and help schema. Reducing this value during development is helpful so that API changes are seen sooner in the tool. Setting this on a server will define the TTL for all client versions > 4.3.1. Client versions > 4.3.1 that connect to IPA servers older than 4.3.1 will use the client-side configuration value. The default is 3600 seconds. 0 disables the cache. A change in the ttl will not be immediately recognized by clients. They will use the new value once their current cache expires.
|
||||
.TP
|
||||
.B server <hostname>
|
||||
Specifies the IPA Server hostname.
|
||||
.TP
|
||||
|
||||
@@ -61,6 +61,7 @@ ipadb_la_LIBADD = \
|
||||
$(UNISTRING_LIBS) \
|
||||
$(SSSCERTMAP_LIBS) \
|
||||
$(top_builddir)/util/libutil.la \
|
||||
-lsamba-errors \
|
||||
$(NULL)
|
||||
|
||||
if HAVE_CMOCKA
|
||||
@@ -104,6 +105,7 @@ ipa_kdb_tests_LDADD = \
|
||||
-lkdb5 \
|
||||
-lsss_idmap \
|
||||
-lsamba-security-samba4 \
|
||||
-lsamba-errors \
|
||||
$(NULL)
|
||||
|
||||
appdir = $(libexecdir)/ipa
|
||||
|
||||
@@ -79,6 +79,7 @@
|
||||
#define IPA_USER_AUTH_TYPE "ipaUserAuthType"
|
||||
|
||||
struct ipadb_mspac;
|
||||
struct dom_sid;
|
||||
|
||||
enum ipadb_user_auth {
|
||||
IPADB_USER_AUTH_NONE = 0,
|
||||
@@ -155,6 +156,8 @@ struct ipadb_e_data {
|
||||
bool has_tktpolaux;
|
||||
enum ipadb_user_auth user_auth;
|
||||
struct ipadb_e_pol_limits pol_limits[IPADB_USER_AUTH_IDX_MAX];
|
||||
bool has_sid;
|
||||
struct dom_sid *sid;
|
||||
};
|
||||
|
||||
struct ipadb_context *ipadb_get_context(krb5_context kcontext);
|
||||
@@ -366,3 +369,8 @@ int ipadb_get_enc_salt_types(struct ipadb_context *ipactx, LDAPMessage *entry,
|
||||
/* CERTAUTH PLUGIN */
|
||||
void ipa_certauth_free_moddata(krb5_certauth_moddata *moddata);
|
||||
#endif
|
||||
|
||||
int ipadb_string_to_sid(const char *str, struct dom_sid *sid);
|
||||
void alloc_sid(struct dom_sid **sid);
|
||||
void free_sid(struct dom_sid **sid);
|
||||
bool dom_sid_check(const struct dom_sid *sid1, const struct dom_sid *sid2, bool exact_check);
|
||||
@@ -21,6 +21,8 @@
|
||||
*/
|
||||
|
||||
#include "ipa_kdb.h"
|
||||
#include <strings.h>
|
||||
#include <unicase.h>
|
||||
|
||||
static char *acl_attrs[] = {
|
||||
"objectClass",
|
||||
@@ -188,10 +190,41 @@ krb5_error_code ipadb_check_allowed_to_delegate(krb5_context kcontext,
|
||||
const krb5_db_entry *server,
|
||||
krb5_const_principal proxy)
|
||||
{
|
||||
krb5_error_code kerr;
|
||||
krb5_error_code kerr, result;
|
||||
char *srv_principal = NULL;
|
||||
krb5_db_entry *proxy_entry = NULL;
|
||||
struct ipadb_e_data *ied_server, *ied_proxy;
|
||||
LDAPMessage *res = NULL;
|
||||
|
||||
/* Handle the case where server == proxy, this is allowed in S4U*/
|
||||
kerr = ipadb_get_principal(kcontext, proxy,
|
||||
KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY,
|
||||
&proxy_entry);
|
||||
if (kerr) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
ied_server = (struct ipadb_e_data *) server->e_data;
|
||||
ied_proxy = (struct ipadb_e_data *) proxy_entry->e_data;
|
||||
|
||||
/* If we have SIDs for both entries, compare SIDs */
|
||||
if ((ied_server->has_sid && ied_server->sid != NULL) &&
|
||||
(ied_proxy->has_sid && ied_proxy->sid != NULL)) {
|
||||
|
||||
if (dom_sid_check(ied_server->sid, ied_proxy->sid, true)) {
|
||||
kerr = 0;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
/* Otherwise, compare entry DNs */
|
||||
kerr = ulc_casecmp(ied_server->entry_dn, strlen(ied_server->entry_dn),
|
||||
ied_proxy->entry_dn, strlen(ied_proxy->entry_dn),
|
||||
NULL, NULL, &result);
|
||||
if (kerr == 0 && result == 0) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
kerr = krb5_unparse_name(kcontext, server->princ, &srv_principal);
|
||||
if (kerr) {
|
||||
goto done;
|
||||
@@ -208,6 +241,7 @@ krb5_error_code ipadb_check_allowed_to_delegate(krb5_context kcontext,
|
||||
}
|
||||
|
||||
done:
|
||||
ipadb_free_principal(kcontext, proxy_entry);
|
||||
krb5_free_unparsed_name(kcontext, srv_principal);
|
||||
ldap_msgfree(res);
|
||||
return kerr;
|
||||
|
||||
@@ -88,7 +88,7 @@ ipa_kdcpolicy_check_as(krb5_context context, krb5_kdcpolicy_moddata moddata,
|
||||
}
|
||||
|
||||
ua = ied->user_auth;
|
||||
|
||||
|
||||
/* If no mechanisms are set, allow every auth method */
|
||||
if (ua == IPADB_USER_AUTH_NONE) {
|
||||
jitter(ONE_DAY_SECONDS, lifetime_out);
|
||||
@@ -128,7 +128,7 @@ ipa_kdcpolicy_check_as(krb5_context context, krb5_kdcpolicy_moddata moddata,
|
||||
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.";
|
||||
*status = "Password pre-authentication not allowed for this user.";
|
||||
kerr = KRB5KDC_ERR_POLICY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
+501
-45
@@ -80,7 +80,20 @@ static char *memberof_pac_attrs[] = {
|
||||
#define AUTHZ_DATA_TYPE_PAD "PAD"
|
||||
#define AUTHZ_DATA_TYPE_NONE "NONE"
|
||||
|
||||
int string_to_sid(const char *str, struct dom_sid *sid)
|
||||
void alloc_sid(struct dom_sid **sid)
|
||||
{
|
||||
*sid = malloc(sizeof(struct dom_sid));
|
||||
}
|
||||
|
||||
void free_sid(struct dom_sid **sid)
|
||||
{
|
||||
if (sid != NULL && *sid != NULL) {
|
||||
free(*sid);
|
||||
*sid = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int ipadb_string_to_sid(const char *str, struct dom_sid *sid)
|
||||
{
|
||||
unsigned long val;
|
||||
const char *s;
|
||||
@@ -223,7 +236,7 @@ static struct dom_sid *dom_sid_dup(TALLOC_CTX *memctx,
|
||||
* dom_sid_check() is supposed to be used with sid1 representing domain SID
|
||||
* and sid2 being either domain or resource SID in the domain
|
||||
*/
|
||||
static bool dom_sid_check(const struct dom_sid *sid1, const struct dom_sid *sid2, bool exact_check)
|
||||
bool dom_sid_check(const struct dom_sid *sid1, const struct dom_sid *sid2, bool exact_check)
|
||||
{
|
||||
int c, num;
|
||||
|
||||
@@ -372,7 +385,7 @@ static krb5_error_code ipadb_add_asserted_identity(struct ipadb_context *ipactx,
|
||||
|
||||
/* For S4U2Self, add Service Asserted Identity SID
|
||||
* otherwise, add Authentication Authority Asserted Identity SID */
|
||||
ret = string_to_sid((flags & KRB5_KDB_FLAG_PROTOCOL_TRANSITION) ?
|
||||
ret = ipadb_string_to_sid((flags & KRB5_KDB_FLAG_PROTOCOL_TRANSITION) ?
|
||||
"S-1-18-2" : "S-1-18-1",
|
||||
arr[sidcount].sid);
|
||||
if (ret) {
|
||||
@@ -635,27 +648,21 @@ static krb5_error_code ipadb_fill_info3(struct ipadb_context *ipactx,
|
||||
info3->base.logon_count = 0; /* we do not have this info yet */
|
||||
info3->base.bad_password_count = 0; /* we do not have this info yet */
|
||||
|
||||
if ((is_host || is_service)) {
|
||||
/* it is either host or service, so get the hostname first */
|
||||
char *sep = strchr(info3->base.account_name.string, '/');
|
||||
bool is_master = is_master_host(
|
||||
ipactx,
|
||||
sep ? sep + 1 : info3->base.account_name.string);
|
||||
if (is_master) {
|
||||
/* Well know RID of domain controllers group */
|
||||
info3->base.rid = 516;
|
||||
} else {
|
||||
/* Well know RID of domain computers group */
|
||||
info3->base.rid = 515;
|
||||
}
|
||||
} else {
|
||||
ret = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry,
|
||||
"ipaNTSecurityIdentifier", &strres);
|
||||
if (ret) {
|
||||
/* SID is mandatory */
|
||||
/* Use AES keys by default to detect changes.
|
||||
* This bit is not used by Windows clients and servers so we can
|
||||
* clear it after detecting the changes */
|
||||
info3->base.acct_flags = ACB_USE_AES_KEYS;
|
||||
|
||||
ret = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry,
|
||||
"ipaNTSecurityIdentifier", &strres);
|
||||
if (ret) {
|
||||
/* SID is mandatory for all but host/services */
|
||||
if (!(is_host || is_service)) {
|
||||
return ret;
|
||||
}
|
||||
ret = string_to_sid(strres, &sid);
|
||||
info3->base.rid = 0;
|
||||
} else {
|
||||
ret = ipadb_string_to_sid(strres, &sid);
|
||||
free(strres);
|
||||
if (ret) {
|
||||
return ret;
|
||||
@@ -666,6 +673,29 @@ static krb5_error_code ipadb_fill_info3(struct ipadb_context *ipactx,
|
||||
}
|
||||
}
|
||||
|
||||
/* If SID was present prefer using it even for hosts and services
|
||||
* but we still need to set the account flags correctly */
|
||||
if ((is_host || is_service)) {
|
||||
/* it is either host or service, so get the hostname first */
|
||||
char *sep = strchr(info3->base.account_name.string, '/');
|
||||
bool is_master = is_master_host(
|
||||
ipactx,
|
||||
sep ? sep + 1 : info3->base.account_name.string);
|
||||
if (is_master) {
|
||||
/* Well known RID of domain controllers group */
|
||||
if (info3->base.rid == 0) {
|
||||
info3->base.rid = 516;
|
||||
}
|
||||
info3->base.acct_flags |= ACB_SVRTRUST;
|
||||
} else {
|
||||
/* Well known RID of domain computers group */
|
||||
if (info3->base.rid == 0) {
|
||||
info3->base.rid = 515;
|
||||
}
|
||||
info3->base.acct_flags |= ACB_WSTRUST;
|
||||
}
|
||||
}
|
||||
|
||||
ret = ipadb_ldap_deref_results(ipactx->lcontext, lentry, &deref_results);
|
||||
switch (ret) {
|
||||
LDAPDerefRes *dres;
|
||||
@@ -700,7 +730,7 @@ static krb5_error_code ipadb_fill_info3(struct ipadb_context *ipactx,
|
||||
}
|
||||
}
|
||||
if (strcasecmp(dval->type, "ipaNTSecurityIdentifier") == 0) {
|
||||
ret = string_to_sid((char *)dval->vals[0].bv_val, &gsid);
|
||||
ret = ipadb_string_to_sid((char *)dval->vals[0].bv_val, &gsid);
|
||||
if (ret) {
|
||||
continue;
|
||||
}
|
||||
@@ -786,9 +816,13 @@ static krb5_error_code ipadb_fill_info3(struct ipadb_context *ipactx,
|
||||
/* always zero out, not used for Krb, only NTLM */
|
||||
memset(&info3->base.LMSessKey, '\0', sizeof(info3->base.LMSessKey));
|
||||
|
||||
/* TODO: fill based on objectclass, user vs computer, etc... */
|
||||
info3->base.acct_flags = ACB_NORMAL; /* samr_AcctFlags */
|
||||
/* If account type was not set before, default to ACB_NORMAL */
|
||||
if (!(info3->base.acct_flags & ~ACB_USE_AES_KEYS)) {
|
||||
info3->base.acct_flags |= ACB_NORMAL; /* samr_AcctFlags */
|
||||
}
|
||||
|
||||
/* Clear ACB_USE_AES_KEYS as it is not used by Windows */
|
||||
info3->base.acct_flags &= ~ACB_USE_AES_KEYS;
|
||||
info3->base.sub_auth_status = 0;
|
||||
info3->base.last_successful_logon = 0;
|
||||
info3->base.last_failed_logon = 0;
|
||||
@@ -799,6 +833,155 @@ static krb5_error_code ipadb_fill_info3(struct ipadb_context *ipactx,
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef HAVE_PAC_REQUESTER_SID
|
||||
static krb5_error_code ipadb_get_requester_sid(krb5_context context,
|
||||
krb5_pac pac,
|
||||
struct dom_sid *sid)
|
||||
{
|
||||
enum ndr_err_code ndr_err;
|
||||
krb5_error_code ret;
|
||||
DATA_BLOB pac_requester_sid_in;
|
||||
krb5_data k5pac_requester_sid_in;
|
||||
union PAC_INFO info;
|
||||
TALLOC_CTX *tmp_ctx;
|
||||
struct ipadb_context *ipactx;
|
||||
|
||||
ipactx = ipadb_get_context(context);
|
||||
if (!ipactx) {
|
||||
return KRB5_KDB_DBNOTINITED;
|
||||
}
|
||||
|
||||
tmp_ctx = talloc_new(NULL);
|
||||
if (tmp_ctx == NULL) {
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
ret = krb5_pac_get_buffer(context, pac, PAC_TYPE_REQUESTER_SID,
|
||||
&k5pac_requester_sid_in);
|
||||
if (ret != 0) {
|
||||
talloc_free(tmp_ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
pac_requester_sid_in = data_blob_const(k5pac_requester_sid_in.data,
|
||||
k5pac_requester_sid_in.length);
|
||||
|
||||
ndr_err = ndr_pull_union_blob(&pac_requester_sid_in, tmp_ctx, &info,
|
||||
PAC_TYPE_REQUESTER_SID,
|
||||
(ndr_pull_flags_fn_t)ndr_pull_PAC_INFO);
|
||||
krb5_free_data_contents(context, &k5pac_requester_sid_in);
|
||||
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
|
||||
talloc_free(tmp_ctx);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
*sid = info.requester_sid.sid;
|
||||
|
||||
talloc_free(tmp_ctx);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static krb5_error_code ipadb_get_sid_from_pac(TALLOC_CTX *ctx,
|
||||
struct PAC_LOGON_INFO *info,
|
||||
struct dom_sid *sid)
|
||||
{
|
||||
struct dom_sid *client_sid = NULL;
|
||||
/* Construct SID from the PAC */
|
||||
if (info->info3.base.rid == 0) {
|
||||
client_sid = info->info3.sids[0].sid;
|
||||
} else {
|
||||
client_sid = dom_sid_dup(ctx, info->info3.base.domain_sid);
|
||||
if (!client_sid) {
|
||||
return ENOMEM;
|
||||
}
|
||||
sid_append_rid(client_sid, info->info3.base.rid);
|
||||
}
|
||||
*sid = *client_sid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef HAVE_PAC_ATTRIBUTES_INFO
|
||||
static krb5_error_code ipadb_client_requested_pac(krb5_context context,
|
||||
krb5_pac pac,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
krb5_boolean *requested_pac)
|
||||
{
|
||||
enum ndr_err_code ndr_err;
|
||||
krb5_data k5pac_attrs_in;
|
||||
DATA_BLOB pac_attrs_in;
|
||||
union PAC_INFO pac_attrs;
|
||||
krb5_error_code ret;
|
||||
|
||||
*requested_pac = true;
|
||||
|
||||
ret = krb5_pac_get_buffer(context, pac, PAC_TYPE_ATTRIBUTES_INFO,
|
||||
&k5pac_attrs_in);
|
||||
if (ret != 0) {
|
||||
return ret == ENOENT ? 0 : ret;
|
||||
}
|
||||
|
||||
pac_attrs_in = data_blob_const(k5pac_attrs_in.data,
|
||||
k5pac_attrs_in.length);
|
||||
|
||||
ndr_err = ndr_pull_union_blob(&pac_attrs_in, mem_ctx, &pac_attrs,
|
||||
PAC_TYPE_ATTRIBUTES_INFO,
|
||||
(ndr_pull_flags_fn_t)ndr_pull_PAC_INFO);
|
||||
krb5_free_data_contents(context, &k5pac_attrs_in);
|
||||
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
|
||||
NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
|
||||
krb5_klog_syslog(LOG_ERR, "can't parse the PAC ATTRIBUTES_INFO: %s\n",
|
||||
nt_errstr(nt_status));
|
||||
return KRB5_KDB_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
if (pac_attrs.attributes_info.flags & (PAC_ATTRIBUTE_FLAG_PAC_WAS_GIVEN_IMPLICITLY
|
||||
| PAC_ATTRIBUTE_FLAG_PAC_WAS_REQUESTED)) {
|
||||
*requested_pac = true;
|
||||
} else {
|
||||
*requested_pac = false;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static krb5_error_code ipadb_get_pac_attrs_blob(TALLOC_CTX *mem_ctx,
|
||||
const krb5_boolean *pac_request,
|
||||
DATA_BLOB *pac_attrs_data)
|
||||
{
|
||||
union PAC_INFO pac_attrs;
|
||||
enum ndr_err_code ndr_err;
|
||||
|
||||
memset(&pac_attrs, 0, sizeof(pac_attrs));
|
||||
|
||||
*pac_attrs_data = data_blob_null;
|
||||
|
||||
/* Set the length of the flags in bits. */
|
||||
pac_attrs.attributes_info.flags_length = 2;
|
||||
|
||||
if (pac_request == NULL) {
|
||||
pac_attrs.attributes_info.flags
|
||||
|= PAC_ATTRIBUTE_FLAG_PAC_WAS_GIVEN_IMPLICITLY;
|
||||
} else if (*pac_request) {
|
||||
pac_attrs.attributes_info.flags
|
||||
|= PAC_ATTRIBUTE_FLAG_PAC_WAS_REQUESTED;
|
||||
}
|
||||
|
||||
ndr_err = ndr_push_union_blob(pac_attrs_data, mem_ctx, &pac_attrs,
|
||||
PAC_TYPE_ATTRIBUTES_INFO,
|
||||
(ndr_push_flags_fn_t)ndr_push_PAC_INFO);
|
||||
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
|
||||
NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
|
||||
krb5_klog_syslog(LOG_ERR, "can't create PAC ATTRIBUTES_INFO: %s\n",
|
||||
nt_errstr(nt_status));
|
||||
return KRB5_KDB_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static krb5_error_code ipadb_get_pac(krb5_context kcontext,
|
||||
krb5_db_entry *client,
|
||||
unsigned int flags,
|
||||
@@ -817,6 +1000,7 @@ static krb5_error_code ipadb_get_pac(krb5_context kcontext,
|
||||
enum ndr_err_code ndr_err;
|
||||
union PAC_INFO pac_upn;
|
||||
char *principal = NULL;
|
||||
struct dom_sid client_sid;
|
||||
|
||||
/* When no client entry is there, we cannot generate MS-PAC */
|
||||
if (!client) {
|
||||
@@ -917,6 +1101,18 @@ static krb5_error_code ipadb_get_pac(krb5_context kcontext,
|
||||
pac_upn.upn_dns_info.flags |= PAC_UPN_DNS_FLAG_CONSTRUCTED;
|
||||
}
|
||||
|
||||
kerr = ipadb_get_sid_from_pac(tmpctx, pac_info.logon_info.info, &client_sid);
|
||||
if (kerr) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
#ifdef HAVE_PAC_UPN_DNS_INFO_EX
|
||||
/* Add samAccountName and a SID */
|
||||
pac_upn.upn_dns_info.flags |= PAC_UPN_DNS_FLAG_HAS_SAM_NAME_AND_SID;
|
||||
pac_upn.upn_dns_info.ex.sam_name_and_sid.samaccountname = pac_info.logon_info.info->info3.base.account_name.string;
|
||||
pac_upn.upn_dns_info.ex.sam_name_and_sid.objectsid = &client_sid;
|
||||
#endif
|
||||
|
||||
ndr_err = ndr_push_union_blob(&pac_data, tmpctx, &pac_upn,
|
||||
PAC_TYPE_UPN_DNS_INFO,
|
||||
(ndr_push_flags_fn_t)ndr_push_PAC_INFO);
|
||||
@@ -931,6 +1127,53 @@ static krb5_error_code ipadb_get_pac(krb5_context kcontext,
|
||||
|
||||
kerr = krb5_pac_add_buffer(kcontext, *pac, KRB5_PAC_UPN_DNS_INFO, &data);
|
||||
|
||||
#ifdef HAVE_PAC_ATTRIBUTES_INFO
|
||||
/* == Add implicit PAC type attributes info as we always try to generate PAC == */
|
||||
{
|
||||
DATA_BLOB pac_attrs_data;
|
||||
|
||||
kerr = ipadb_get_pac_attrs_blob(tmpctx, NULL, &pac_attrs_data);
|
||||
if (kerr) {
|
||||
goto done;
|
||||
}
|
||||
data.magic = KV5M_DATA;
|
||||
data.data = (char *)pac_attrs_data.data;
|
||||
data.length = pac_attrs_data.length;
|
||||
|
||||
kerr = krb5_pac_add_buffer(kcontext, *pac, PAC_TYPE_ATTRIBUTES_INFO, &data);
|
||||
if (kerr) {
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_PAC_REQUESTER_SID
|
||||
{
|
||||
union PAC_INFO pac_requester_sid;
|
||||
/* == Package PAC_REQUESTER_SID == */
|
||||
memset(&pac_requester_sid, 0, sizeof(pac_requester_sid));
|
||||
|
||||
pac_requester_sid.requester_sid.sid = client_sid;
|
||||
|
||||
ndr_err = ndr_push_union_blob(&pac_data, tmpctx, &pac_requester_sid,
|
||||
PAC_TYPE_REQUESTER_SID,
|
||||
(ndr_push_flags_fn_t)ndr_push_PAC_INFO);
|
||||
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
|
||||
kerr = KRB5_KDB_INTERNAL_ERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
data.magic = KV5M_DATA;
|
||||
data.data = (char *)pac_data.data;
|
||||
data.length = pac_data.length;
|
||||
|
||||
kerr = krb5_pac_add_buffer(kcontext, *pac, PAC_TYPE_REQUESTER_SID, &data);
|
||||
if (kerr) {
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
done:
|
||||
ldap_msgfree(results);
|
||||
talloc_free(tmpctx);
|
||||
@@ -1189,7 +1432,7 @@ static int map_groups(TALLOC_CTX *memctx, krb5_context kcontext,
|
||||
}
|
||||
if (strcasecmp(dval->type,
|
||||
"ipaNTSecurityIdentifier") == 0) {
|
||||
kerr = string_to_sid((char *)dval->vals[0].bv_val, &sid);
|
||||
kerr = ipadb_string_to_sid((char *)dval->vals[0].bv_val, &sid);
|
||||
if (kerr != 0) {
|
||||
continue;
|
||||
}
|
||||
@@ -1391,6 +1634,124 @@ static void filter_logon_info_log_message_rid(struct dom_sid *sid, uint32_t rid)
|
||||
}
|
||||
}
|
||||
|
||||
static krb5_error_code check_logon_info_consistent(krb5_context context,
|
||||
TALLOC_CTX *memctx,
|
||||
krb5_const_principal client_princ,
|
||||
krb5_boolean is_s4u,
|
||||
struct PAC_LOGON_INFO_CTR *info)
|
||||
{
|
||||
krb5_error_code kerr = 0;
|
||||
struct ipadb_context *ipactx;
|
||||
bool result;
|
||||
bool is_from_trusted_domain = false;
|
||||
krb5_db_entry *client_actual = NULL;
|
||||
struct ipadb_e_data *ied = NULL;
|
||||
int flags = 0;
|
||||
struct dom_sid client_sid;
|
||||
#ifdef KRB5_KDB_FLAG_ALIAS_OK
|
||||
flags = KRB5_KDB_FLAG_ALIAS_OK;
|
||||
#endif
|
||||
|
||||
ipactx = ipadb_get_context(context);
|
||||
if (!ipactx || !ipactx->mspac) {
|
||||
return KRB5_KDB_DBNOTINITED;
|
||||
}
|
||||
|
||||
/* We are asked to verify the PAC for our own principal,
|
||||
* check that our own view on the PAC details is up to date */
|
||||
if (ipactx->mspac->domsid.num_auths == 0) {
|
||||
/* Force re-init of KDB's view on our domain */
|
||||
kerr = ipadb_reinit_mspac(ipactx, true);
|
||||
if (kerr != 0) {
|
||||
krb5_klog_syslog(LOG_ERR,
|
||||
"PAC issue: unable to update realm's view on PAC info");
|
||||
return KRB5KDC_ERR_POLICY;
|
||||
}
|
||||
}
|
||||
|
||||
/* check exact domain SID */
|
||||
result = dom_sid_check(&ipactx->mspac->domsid,
|
||||
info->info->info3.base.domain_sid, true);
|
||||
if (!result) {
|
||||
/* In S4U case we might be dealing with the PAC issued by the trusted domain */
|
||||
if (is_s4u && (ipactx->mspac->trusts != NULL)) {
|
||||
/* Iterate through list of trusts and check if this SID belongs to
|
||||
* one of the domains we trust */
|
||||
for(int i = 0 ; i < ipactx->mspac->num_trusts ; i++) {
|
||||
result = dom_sid_check(&ipactx->mspac->trusts[i].domsid,
|
||||
info->info->info3.base.domain_sid, true);
|
||||
if (result) {
|
||||
is_from_trusted_domain = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
/* memctx is freed by the caller */
|
||||
char *sid = dom_sid_string(memctx, info->info->info3.base.domain_sid);
|
||||
char *dom = dom_sid_string(memctx, &ipactx->mspac->domsid);
|
||||
krb5_klog_syslog(LOG_ERR, "PAC issue: PAC record claims domain SID different "
|
||||
"to local domain SID or any trusted domain SID: "
|
||||
"local [%s], PAC [%s]",
|
||||
dom ? dom : "<failed to display>",
|
||||
sid ? sid : "<failed to display>");
|
||||
return KRB5KDC_ERR_POLICY;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_s4u && is_from_trusted_domain) {
|
||||
/* If the PAC belongs to a user from the trusted domain, we cannot compare SIDs */
|
||||
return 0;
|
||||
}
|
||||
|
||||
kerr = ipadb_get_principal(context, client_princ, flags, &client_actual);
|
||||
if (kerr != 0) {
|
||||
krb5_klog_syslog(LOG_ERR, "PAC issue: ipadb_get_principal failed.");
|
||||
return KRB5KDC_ERR_POLICY;
|
||||
}
|
||||
|
||||
ied = (struct ipadb_e_data *)client_actual->e_data;
|
||||
if (ied == NULL || ied->magic != IPA_E_DATA_MAGIC) {
|
||||
krb5_klog_syslog(LOG_ERR, "PAC issue: client e_data fetching failed.");
|
||||
kerr = EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!ied->has_sid || ied->sid == NULL) {
|
||||
/* Kerberos principal might have no SID associated in the DB entry.
|
||||
* If this is host or service, we'll associate RID -515 or -516 in PAC
|
||||
* depending on whether this is a domain member or domain controller
|
||||
* but since this is not recorded in the DB entry, we the check for
|
||||
* SID is not needed */
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
||||
kerr = ipadb_get_sid_from_pac(memctx, info->info, &client_sid);
|
||||
if (kerr) {
|
||||
goto done;
|
||||
}
|
||||
result = dom_sid_check(ied->sid, &client_sid, true);
|
||||
if (!result) {
|
||||
/* memctx is freed by the caller */
|
||||
char *local_sid = dom_sid_string(memctx, ied->sid);
|
||||
char *pac_sid = dom_sid_string(memctx, &client_sid);
|
||||
krb5_klog_syslog(LOG_ERR, "PAC issue: client principal has a SID "
|
||||
"different from what PAC claims. "
|
||||
"local [%s] vs PAC [%s]",
|
||||
local_sid ? local_sid : "<failed to display>",
|
||||
pac_sid ? pac_sid : "<failed to display>");
|
||||
kerr = KRB5KDC_ERR_POLICY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
ipadb_free_principal(context, client_actual);
|
||||
|
||||
return kerr;
|
||||
}
|
||||
|
||||
krb5_error_code filter_logon_info(krb5_context context,
|
||||
TALLOC_CTX *memctx,
|
||||
krb5_data realm,
|
||||
@@ -1618,12 +1979,17 @@ krb5_error_code filter_logon_info(krb5_context context,
|
||||
|
||||
|
||||
static krb5_error_code ipadb_check_logon_info(krb5_context context,
|
||||
krb5_data origin_realm,
|
||||
krb5_data *pac_blob)
|
||||
krb5_const_principal client_princ,
|
||||
krb5_boolean is_cross_realm,
|
||||
krb5_boolean is_s4u,
|
||||
krb5_data *pac_blob,
|
||||
struct dom_sid *requester_sid)
|
||||
{
|
||||
struct PAC_LOGON_INFO_CTR info;
|
||||
krb5_error_code kerr;
|
||||
TALLOC_CTX *tmpctx;
|
||||
krb5_data origin_realm = client_princ->realm;
|
||||
bool result;
|
||||
|
||||
tmpctx = talloc_new(NULL);
|
||||
if (!tmpctx) {
|
||||
@@ -1635,6 +2001,38 @@ static krb5_error_code ipadb_check_logon_info(krb5_context context,
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Check that requester SID is the same as in the PAC entry */
|
||||
if (requester_sid != NULL) {
|
||||
struct dom_sid client_sid;
|
||||
kerr = ipadb_get_sid_from_pac(tmpctx, info.info, &client_sid);
|
||||
if (kerr) {
|
||||
goto done;
|
||||
}
|
||||
result = dom_sid_check(&client_sid, requester_sid, true);
|
||||
if (!result) {
|
||||
/* memctx is freed by the caller */
|
||||
char *pac_sid = dom_sid_string(tmpctx, &client_sid);
|
||||
char *req_sid = dom_sid_string(tmpctx, requester_sid);
|
||||
krb5_klog_syslog(LOG_ERR, "PAC issue: PAC has a SID "
|
||||
"different from what PAC requester claims. "
|
||||
"PAC [%s] vs PAC requester [%s]",
|
||||
pac_sid ? pac_sid : "<failed to display>",
|
||||
req_sid ? req_sid : "<failed to display>");
|
||||
kerr = KRB5KDC_ERR_POLICY;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_cross_realm) {
|
||||
/* For local realm case we need to check whether the PAC is for our user
|
||||
* but we don't need to process further. In S4U2Proxy case when the client
|
||||
* is ours but operates on behalf of the cross-realm principal, we will
|
||||
* search through the trusted domains but otherwise skip the exact SID check
|
||||
* as we are not responsible for the principal from the trusted domain */
|
||||
kerr = check_logon_info_consistent(context, tmpctx, client_princ, is_s4u, &info);
|
||||
goto done;
|
||||
}
|
||||
|
||||
kerr = filter_logon_info(context, tmpctx, origin_realm, &info);
|
||||
if (kerr) {
|
||||
goto done;
|
||||
@@ -1749,7 +2147,10 @@ static krb5_error_code ipadb_add_transited_service(krb5_context context,
|
||||
krb5_free_data_contents(context, &pac_blob);
|
||||
memset(&pac_blob, 0, sizeof(krb5_data));
|
||||
|
||||
kerr = krb5_unparse_name(context, proxy->princ, &tmpstr);
|
||||
kerr = krb5_unparse_name_flags(context, proxy->princ,
|
||||
KRB5_PRINCIPAL_UNPARSE_NO_REALM |
|
||||
KRB5_PRINCIPAL_UNPARSE_DISPLAY,
|
||||
&tmpstr);
|
||||
if (kerr != 0) {
|
||||
goto done;
|
||||
}
|
||||
@@ -1824,6 +2225,8 @@ static krb5_error_code ipadb_verify_pac(krb5_context context,
|
||||
krb5_data pac_blob = { 0 , 0, NULL};
|
||||
bool is_cross_realm = false;
|
||||
size_t i;
|
||||
struct dom_sid *requester_sid = NULL;
|
||||
struct dom_sid req_sid;
|
||||
|
||||
kerr = krb5_pac_parse(context,
|
||||
authdata[0]->contents,
|
||||
@@ -1860,19 +2263,30 @@ static krb5_error_code ipadb_verify_pac(krb5_context context,
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Now that the PAC is verified augment it with additional info if
|
||||
* it is coming from a different realm */
|
||||
if (is_cross_realm) {
|
||||
kerr = krb5_pac_get_buffer(context, old_pac,
|
||||
KRB5_PAC_LOGON_INFO, &pac_blob);
|
||||
if (kerr != 0) {
|
||||
goto done;
|
||||
}
|
||||
/* Now that the PAC is verified, do additional checks.
|
||||
* Augment it with additional info if it is coming from a different realm */
|
||||
kerr = krb5_pac_get_buffer(context, old_pac,
|
||||
KRB5_PAC_LOGON_INFO, &pac_blob);
|
||||
if (kerr != 0) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
kerr = ipadb_check_logon_info(context, client_princ->realm, &pac_blob);
|
||||
if (kerr != 0) {
|
||||
goto done;
|
||||
}
|
||||
memset(&req_sid, '\0', sizeof(struct dom_sid));
|
||||
#ifdef HAVE_PAC_REQUESTER_SID
|
||||
kerr = ipadb_get_requester_sid(context, old_pac, &req_sid);
|
||||
if (kerr == 0) {
|
||||
requester_sid = &req_sid;
|
||||
}
|
||||
#endif
|
||||
|
||||
kerr = ipadb_check_logon_info(context,
|
||||
client_princ,
|
||||
is_cross_realm,
|
||||
(flags & KRB5_KDB_FLAGS_S4U),
|
||||
&pac_blob,
|
||||
requester_sid);
|
||||
if (kerr != 0) {
|
||||
goto done;
|
||||
}
|
||||
/* extract buffers and rebuilt pac from scratch so that when re-signing
|
||||
* with a different cksum type does not cause issues due to mismatching
|
||||
@@ -1905,6 +2319,48 @@ static krb5_error_code ipadb_verify_pac(krb5_context context,
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef HAVE_PAC_ATTRIBUTES_INFO
|
||||
if (types[i] == PAC_TYPE_ATTRIBUTES_INFO &&
|
||||
pac_blob.length != 0) {
|
||||
/* == Check whether PAC was requested or given implicitly == */
|
||||
DATA_BLOB pac_attrs_data;
|
||||
krb5_boolean pac_requested;
|
||||
|
||||
TALLOC_CTX *tmpctx = talloc_new(NULL);
|
||||
if (tmpctx == NULL) {
|
||||
kerr = ENOMEM;
|
||||
krb5_pac_free(context, new_pac);
|
||||
goto done;
|
||||
}
|
||||
|
||||
kerr = ipadb_client_requested_pac(context, old_pac, tmpctx, &pac_requested);
|
||||
if (kerr != 0) {
|
||||
talloc_free(tmpctx);
|
||||
krb5_pac_free(context, new_pac);
|
||||
goto done;
|
||||
}
|
||||
|
||||
kerr = ipadb_get_pac_attrs_blob(tmpctx, &pac_requested, &pac_attrs_data);
|
||||
if (kerr) {
|
||||
talloc_free(tmpctx);
|
||||
krb5_pac_free(context, new_pac);
|
||||
goto done;
|
||||
}
|
||||
data.magic = KV5M_DATA;
|
||||
data.data = (char *)pac_attrs_data.data;
|
||||
data.length = pac_attrs_data.length;
|
||||
|
||||
kerr = krb5_pac_add_buffer(context, new_pac, PAC_TYPE_ATTRIBUTES_INFO, &data);
|
||||
if (kerr) {
|
||||
talloc_free(tmpctx);
|
||||
krb5_pac_free(context, new_pac);
|
||||
goto done;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (types[i] == KRB5_PAC_DELEGATION_INFO &&
|
||||
(flags & KRB5_KDB_FLAG_CONSTRAINED_DELEGATION)) {
|
||||
/* skip it here, we will add it explicitly later */
|
||||
@@ -2434,7 +2890,7 @@ ipadb_adtrusts_fill_sid_blacklist(char **source_sid_blacklist,
|
||||
}
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
(void) string_to_sid(source[i], &sid_blacklist[i]);
|
||||
(void) ipadb_string_to_sid(source[i], &sid_blacklist[i]);
|
||||
}
|
||||
|
||||
*result_sids = sid_blacklist;
|
||||
@@ -2594,7 +3050,7 @@ ipadb_mspac_get_trusted_domains(struct ipadb_context *ipactx)
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = string_to_sid(t[n].domain_sid, &t[n].domsid);
|
||||
ret = ipadb_string_to_sid(t[n].domain_sid, &t[n].domsid);
|
||||
if (ret && t[n].domain_sid != NULL) {
|
||||
ret = EINVAL;
|
||||
goto done;
|
||||
@@ -2812,7 +3268,7 @@ krb5_error_code ipadb_reinit_mspac(struct ipadb_context *ipactx, bool force_rein
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = string_to_sid(resstr, &ipactx->mspac->domsid);
|
||||
ret = ipadb_string_to_sid(resstr, &ipactx->mspac->domsid);
|
||||
if (ret) {
|
||||
kerr = ret;
|
||||
free(resstr);
|
||||
@@ -2865,7 +3321,7 @@ krb5_error_code ipadb_reinit_mspac(struct ipadb_context *ipactx, bool force_rein
|
||||
goto done;
|
||||
}
|
||||
if (ret == 0) {
|
||||
ret = string_to_sid(resstr, &gsid);
|
||||
ret = ipadb_string_to_sid(resstr, &gsid);
|
||||
if (ret) {
|
||||
free(resstr);
|
||||
kerr = ret;
|
||||
|
||||
@@ -51,7 +51,6 @@ struct ipadb_adtrusts {
|
||||
size_t *upn_suffixes_len;
|
||||
};
|
||||
|
||||
int string_to_sid(const char *str, struct dom_sid *sid);
|
||||
char *dom_sid_string(TALLOC_CTX *memctx, const struct dom_sid *dom_sid);
|
||||
krb5_error_code filter_logon_info(krb5_context context, TALLOC_CTX *memctx,
|
||||
krb5_data realm, struct PAC_LOGON_INFO_CTR *info);
|
||||
|
||||
@@ -79,6 +79,8 @@ static char *std_principal_attrs[] = {
|
||||
"ipatokenRadiusConfigLink",
|
||||
"krbAuthIndMaxTicketLife",
|
||||
"krbAuthIndMaxRenewableAge",
|
||||
"ipaNTSecurityIdentifier",
|
||||
"ipaUniqueID",
|
||||
|
||||
"objectClass",
|
||||
NULL
|
||||
@@ -594,6 +596,7 @@ static krb5_error_code ipadb_parse_ldap_entry(krb5_context kcontext,
|
||||
char *restring;
|
||||
char *uidstring;
|
||||
char **authz_data_list;
|
||||
char *princ_sid;
|
||||
krb5_timestamp restime;
|
||||
bool resbool;
|
||||
int result;
|
||||
@@ -963,6 +966,27 @@ static krb5_error_code ipadb_parse_ldap_entry(krb5_context kcontext,
|
||||
ipadb_parse_authind_policies(kcontext, lcontext, lentry, entry, ua);
|
||||
}
|
||||
|
||||
/* Add SID if it is associated with the principal account */
|
||||
ied->has_sid = false;
|
||||
ied->sid = NULL;
|
||||
ret = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry,
|
||||
"ipaNTSecurityIdentifier", &princ_sid);
|
||||
if (ret == 0 && princ_sid != NULL) {
|
||||
alloc_sid(&ied->sid);
|
||||
if (ied->sid == NULL) {
|
||||
kerr = KRB5_KDB_INTERNAL_ERROR;
|
||||
free(princ_sid);
|
||||
goto done;
|
||||
}
|
||||
ret = ipadb_string_to_sid(princ_sid, ied->sid);
|
||||
free(princ_sid);
|
||||
if (ret != 0) {
|
||||
kerr = ret;
|
||||
goto done;
|
||||
}
|
||||
ied->has_sid = true;
|
||||
}
|
||||
|
||||
kerr = 0;
|
||||
|
||||
done:
|
||||
@@ -1568,6 +1592,7 @@ void ipadb_free_principal_e_data(krb5_context kcontext, krb5_octet *e_data)
|
||||
}
|
||||
free(ied->authz_data);
|
||||
free(ied->pol);
|
||||
free_sid(&ied->sid);
|
||||
free(ied);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ static int setup(void **state)
|
||||
/* make sure data is not read from LDAP */
|
||||
ipa_ctx->mspac->last_update = time(NULL) - 1;
|
||||
|
||||
ret = string_to_sid(DOM_SID, &ipa_ctx->mspac->domsid);
|
||||
ret = ipadb_string_to_sid(DOM_SID, &ipa_ctx->mspac->domsid);
|
||||
assert_int_equal(ret, 0);
|
||||
|
||||
ipa_ctx->mspac->num_trusts = 1;
|
||||
@@ -121,7 +121,7 @@ static int setup(void **state)
|
||||
ipa_ctx->mspac->trusts[0].domain_sid = strdup(DOM_SID_TRUST);
|
||||
assert_non_null(ipa_ctx->mspac->trusts[0].domain_sid);
|
||||
|
||||
ret = string_to_sid(DOM_SID_TRUST, &ipa_ctx->mspac->trusts[0].domsid);
|
||||
ret = ipadb_string_to_sid(DOM_SID_TRUST, &ipa_ctx->mspac->trusts[0].domsid);
|
||||
assert_int_equal(ret, 0);
|
||||
|
||||
ipa_ctx->mspac->trusts[0].len_sid_blocklist_incoming = 1;
|
||||
@@ -129,7 +129,7 @@ static int setup(void **state)
|
||||
ipa_ctx->mspac->trusts[0].len_sid_blocklist_incoming,
|
||||
sizeof(struct dom_sid));
|
||||
assert_non_null(ipa_ctx->mspac->trusts[0].sid_blocklist_incoming);
|
||||
ret = string_to_sid(BLOCKLIST_SID,
|
||||
ret = ipadb_string_to_sid(BLOCKLIST_SID,
|
||||
&ipa_ctx->mspac->trusts[0].sid_blocklist_incoming[0]);
|
||||
assert_int_equal(ret, 0);
|
||||
|
||||
@@ -216,7 +216,7 @@ static void test_filter_logon_info(void **state)
|
||||
assert_int_equal(kerr, EINVAL);
|
||||
|
||||
/* wrong domain SID */
|
||||
ret = string_to_sid("S-1-5-21-1-1-1", &dom_sid);
|
||||
ret = ipadb_string_to_sid("S-1-5-21-1-1-1", &dom_sid);
|
||||
assert_int_equal(ret, 0);
|
||||
info->info->info3.base.domain_sid = &dom_sid;
|
||||
|
||||
@@ -224,7 +224,7 @@ static void test_filter_logon_info(void **state)
|
||||
assert_int_equal(kerr, EINVAL);
|
||||
|
||||
/* matching domain SID */
|
||||
ret = string_to_sid(DOM_SID_TRUST, &dom_sid);
|
||||
ret = ipadb_string_to_sid(DOM_SID_TRUST, &dom_sid);
|
||||
assert_int_equal(ret, 0);
|
||||
info->info->info3.base.domain_sid = &dom_sid;
|
||||
|
||||
@@ -292,7 +292,7 @@ static void test_filter_logon_info(void **state)
|
||||
}
|
||||
|
||||
for (d = 0; d < info->info->info3.sidcount; d++) {
|
||||
ret = string_to_sid(test_data[c].sids[d],
|
||||
ret = ipadb_string_to_sid(test_data[c].sids[d],
|
||||
info->info->info3.sids[d].sid);
|
||||
assert_int_equal(ret, 0);
|
||||
}
|
||||
@@ -434,7 +434,7 @@ static void test_get_authz_data_types(void **state)
|
||||
krb5_free_principal(test_ctx->krb5_ctx, non_nfs_princ);
|
||||
}
|
||||
|
||||
static void test_string_to_sid(void **state)
|
||||
static void test_ipadb_string_to_sid(void **state)
|
||||
{
|
||||
int ret;
|
||||
struct dom_sid sid;
|
||||
@@ -442,25 +442,25 @@ static void test_string_to_sid(void **state)
|
||||
{21, 2127521184, 1604012920, 1887927527, 72713,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
|
||||
|
||||
ret = string_to_sid(NULL, &sid);
|
||||
ret = ipadb_string_to_sid(NULL, &sid);
|
||||
assert_int_equal(ret, EINVAL);
|
||||
|
||||
ret = string_to_sid("abc", &sid);
|
||||
ret = ipadb_string_to_sid("abc", &sid);
|
||||
assert_int_equal(ret, EINVAL);
|
||||
|
||||
ret = string_to_sid("S-", &sid);
|
||||
ret = ipadb_string_to_sid("S-", &sid);
|
||||
assert_int_equal(ret, EINVAL);
|
||||
|
||||
ret = string_to_sid("S-ABC", &sid);
|
||||
ret = ipadb_string_to_sid("S-ABC", &sid);
|
||||
assert_int_equal(ret, EINVAL);
|
||||
|
||||
ret = string_to_sid("S-123", &sid);
|
||||
ret = ipadb_string_to_sid("S-123", &sid);
|
||||
assert_int_equal(ret, EINVAL);
|
||||
|
||||
ret = string_to_sid("S-1-123-1-2-3-4-5-6-7-8-9-0-1-2-3-4-5-6", &sid);
|
||||
ret = ipadb_string_to_sid("S-1-123-1-2-3-4-5-6-7-8-9-0-1-2-3-4-5-6", &sid);
|
||||
assert_int_equal(ret, EINVAL);
|
||||
|
||||
ret = string_to_sid("S-1-5-21-2127521184-1604012920-1887927527-72713",
|
||||
ret = ipadb_string_to_sid("S-1-5-21-2127521184-1604012920-1887927527-72713",
|
||||
&sid);
|
||||
assert_int_equal(ret, 0);
|
||||
assert_memory_equal(&exp_sid, &sid, sizeof(struct dom_sid));
|
||||
@@ -531,7 +531,7 @@ int main(int argc, const char *argv[])
|
||||
setup, teardown),
|
||||
cmocka_unit_test_setup_teardown(test_filter_logon_info,
|
||||
setup, teardown),
|
||||
cmocka_unit_test(test_string_to_sid),
|
||||
cmocka_unit_test(test_ipadb_string_to_sid),
|
||||
cmocka_unit_test_setup_teardown(test_dom_sid_string,
|
||||
setup, teardown),
|
||||
cmocka_unit_test_setup_teardown(test_check_trusted_realms,
|
||||
|
||||
@@ -542,7 +542,9 @@ int pack_ber_user(struct ipa_extdom_ctx *ctx,
|
||||
if (strcasecmp(locat+1, domain_name) == 0 ) {
|
||||
locat[0] = '\0';
|
||||
} else {
|
||||
ret = LDAP_INVALID_SYNTAX;
|
||||
/* The found object is from a different domain than requested,
|
||||
* that means it does not exist in the requested domain */
|
||||
ret = LDAP_NO_SUCH_OBJECT;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
@@ -655,7 +657,9 @@ int pack_ber_group(enum response_types response_type,
|
||||
if (strcasecmp(locat+1, domain_name) == 0 ) {
|
||||
locat[0] = '\0';
|
||||
} else {
|
||||
ret = LDAP_INVALID_SYNTAX;
|
||||
/* The found object is from a different domain than requested,
|
||||
* that means it does not exist in the requested domain */
|
||||
ret = LDAP_NO_SUCH_OBJECT;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@ All count and number attributes are single-value ``INTEGER`` type with
|
||||
standard integer matching rules. OIDs ``2.16.840.1.113730.3.8.23.8`` and
|
||||
``2.16.840.1.113730.3.8.23.11`` are reserved for future use.
|
||||
|
||||
```raw
|
||||
```text
|
||||
attributeTypes: (
|
||||
2.16.840.1.113730.3.8.23.7
|
||||
NAME 'ipaSubUidNumber'
|
||||
@@ -192,7 +192,7 @@ The ``ipaSubordinateId`` object class is an auxiliary subclass of
|
||||
``top`` and requires all four subordinate id attributes as well as
|
||||
``ipaOwner`` attribute``
|
||||
|
||||
```raw
|
||||
```text
|
||||
objectClasses: (
|
||||
2.16.840.1.113730.3.8.24.4
|
||||
NAME 'ipaSubordinateId'
|
||||
@@ -207,7 +207,7 @@ objectClasses: (
|
||||
The ``ipaSubordinateGid`` and ``ipaSubordinateUid`` are defined for
|
||||
future use. IPA always assumes the presence of ``ipaSubordinateId``.
|
||||
|
||||
```raw
|
||||
```text
|
||||
objectClasses: (
|
||||
2.16.840.1.113730.3.8.24.2
|
||||
NAME 'ipaSubordinateUid'
|
||||
@@ -233,7 +233,7 @@ Subordinate id entries have the structural object class
|
||||
classes ``ipaSubordinateId``, ``ipaSubordinateGid``, or
|
||||
``ipaSubordinateUid``. ``ipaUniqueId`` is used as a primary key (RDN).
|
||||
|
||||
```raw
|
||||
```text
|
||||
objectClasses: (
|
||||
2.16.840.1.113730.3.8.24.5
|
||||
NAME 'ipaSubordinateIdEntry'
|
||||
@@ -278,7 +278,7 @@ to use the value of entry attributes as step size.
|
||||
The config plugin has a new option to enable or disable generation of
|
||||
subordinate id entries for new users:
|
||||
|
||||
```raw
|
||||
```text
|
||||
$ ipa config-mod --user-default-subid=true
|
||||
```
|
||||
|
||||
@@ -286,7 +286,7 @@ Subordinate ids are managed by a new plugin class. The ``subid-add``
|
||||
and ``subid-del`` commands are hidden from command line. New subordinate
|
||||
ids are generated and auto-assigned with ``subid-generate``.
|
||||
|
||||
```raw
|
||||
```text
|
||||
$ ipa help subid
|
||||
Topic commands:
|
||||
subid-find Search for subordinate id.
|
||||
@@ -297,7 +297,7 @@ Topic commands:
|
||||
subid-stats Subordinate id statistics
|
||||
```
|
||||
|
||||
```raw
|
||||
```text
|
||||
$ ipa subid-generate --owner testuser9
|
||||
-----------------------------------------------------------
|
||||
Added subordinate id "aa28f132-457c-488b-82e1-d123727e4f81"
|
||||
@@ -312,7 +312,7 @@ Added subordinate id "aa28f132-457c-488b-82e1-d123727e4f81"
|
||||
```
|
||||
|
||||
|
||||
```raw
|
||||
```text
|
||||
$ ipa subid-find --owner testuser9
|
||||
------------------------
|
||||
1 subordinate id matched
|
||||
@@ -328,7 +328,7 @@ Number of entries returned 1
|
||||
----------------------------
|
||||
```
|
||||
|
||||
```raw
|
||||
```text
|
||||
$ ipa -vv subid-stats
|
||||
...
|
||||
ipa: INFO: Response: {
|
||||
@@ -432,7 +432,7 @@ The command uses automatic LDAPI EXTERNAL bind when it's executed as
|
||||
root user. Other it requires valid Kerberos TGT of an admin or user
|
||||
administrator.
|
||||
|
||||
```raw
|
||||
```text
|
||||
|
||||
# /usr/libexec/ipa/ipa-subids --help
|
||||
Usage: ipa-subids
|
||||
@@ -479,7 +479,7 @@ The ``user-find`` command search by start value of subordinate uid and
|
||||
gid range. The new command ``user-match-subid`` can be used to find a
|
||||
user by any subordinate id in their range.
|
||||
|
||||
```raw
|
||||
```text
|
||||
$ ipa subid-match --subuid=2147549183
|
||||
------------------------
|
||||
1 subordinate id matched
|
||||
@@ -528,7 +528,7 @@ attribute to fetch ``uidNumber`` from the user object.
|
||||
|
||||
### Deref control example
|
||||
|
||||
```raw
|
||||
```text
|
||||
$ ldapsearch -L -E '!deref=ipaOwner:uid,uidNumber' \
|
||||
-b 'cn=subids,cn=accounts,dc=ipasubid,dc=test' \
|
||||
'(ipaOwner=uid=testuser10,cn=users,cn=accounts,dc=ipasubid,dc=test)'
|
||||
|
||||
+9
-2
@@ -1,3 +1,5 @@
|
||||
%define ipa_requires_gt() %(LC_ALL="C" echo '%*' | xargs -r rpm -q --qf 'Requires: %%{name} >= %%{epoch}:%%{version}-%%{release}\\n' | sed -e 's/ (none):/ /' -e 's/ 0:/ /' | grep -v "is not")
|
||||
|
||||
# ipatests enabled by default, can be disabled with --without ipatests
|
||||
%bcond_without ipatests
|
||||
# default to not use XML-RPC in Rawhide, can be turned around with --with ipa_join_xml
|
||||
@@ -110,7 +112,7 @@
|
||||
%if 0%{?fedora} < 34
|
||||
%global ds_version 1.4.4.16-1
|
||||
%else
|
||||
%global ds_version 2.0.5-1
|
||||
%global ds_version 2.0.7-1
|
||||
%endif
|
||||
|
||||
# Fix for TLS 1.3 PHA, RHBZ#1775146
|
||||
@@ -473,6 +475,8 @@ Requires: gssproxy >= 0.7.0-2
|
||||
Requires: sssd-dbus >= %{sssd_version}
|
||||
Requires: libpwquality
|
||||
Requires: cracklib-dicts
|
||||
# NDR libraries are internal in Samba and change with version without changing SONAME
|
||||
%ipa_requires_gt samba-client-libs
|
||||
|
||||
Provides: %{alt_name}-server = %{version}
|
||||
Conflicts: %{alt_name}-server
|
||||
@@ -572,9 +576,11 @@ Requires: %{name}-server = %{version}-%{release}
|
||||
Requires: bind-dyndb-ldap >= 11.2-2
|
||||
Requires: bind >= %{bind_version}
|
||||
Requires: bind-utils >= %{bind_version}
|
||||
# bind-dnssec-utils is required by the OpenDNSSec integration
|
||||
# https://pagure.io/freeipa/issue/9026
|
||||
Requires: bind-dnssec-utils >= %{bind_version}
|
||||
%if %{with bind_pkcs11}
|
||||
Requires: bind-pkcs11 >= %{bind_version}
|
||||
Requires: bind-pkcs11-utils >= %{bind_version}
|
||||
%else
|
||||
Requires: softhsm >= %{softhsm_version}
|
||||
Requires: openssl-pkcs11 >= %{openssl_pkcs11_version}
|
||||
@@ -1378,6 +1384,7 @@ fi
|
||||
%dir %{_libexecdir}/ipa/oddjob
|
||||
%attr(0755,root,root) %{_libexecdir}/ipa/oddjob/org.freeipa.server.conncheck
|
||||
%attr(0755,root,root) %{_libexecdir}/ipa/oddjob/org.freeipa.server.trust-enable-agent
|
||||
%attr(0755,root,root) %{_libexecdir}/ipa/oddjob/org.freeipa.server.config-enable-sid
|
||||
%config(noreplace) %{_sysconfdir}/dbus-1/system.d/org.freeipa.server.conf
|
||||
%config(noreplace) %{_sysconfdir}/oddjobd.conf.d/ipa-server.conf
|
||||
%dir %{_libexecdir}/ipa/certmonger
|
||||
|
||||
@@ -7,6 +7,7 @@ dbusconfdir = $(sysconfdir)/dbus-1/system.d
|
||||
dist_noinst_DATA = \
|
||||
com.redhat.idm.trust-fetch-domains.in \
|
||||
org.freeipa.server.trust-enable-agent.in \
|
||||
org.freeipa.server.config-enable-sid.in \
|
||||
etc/oddjobd.conf.d/oddjobd-ipa-trust.conf.in \
|
||||
etc/oddjobd.conf.d/ipa-server.conf.in \
|
||||
$(NULL)
|
||||
@@ -18,6 +19,7 @@ dist_oddjob_SCRIPTS = \
|
||||
nodist_oddjob_SCRIPTS = \
|
||||
com.redhat.idm.trust-fetch-domains \
|
||||
org.freeipa.server.trust-enable-agent \
|
||||
org.freeipa.server.config-enable-sid \
|
||||
$(NULL)
|
||||
|
||||
|
||||
|
||||
@@ -17,6 +17,12 @@
|
||||
prepend_user_name="no"
|
||||
argument_passing_method="cmdline"/>
|
||||
</method>
|
||||
<method name="config_enable_sid">
|
||||
<helper exec="@ODDJOBDIR@/org.freeipa.server.config-enable-sid"
|
||||
arguments="10"
|
||||
prepend_user_name="no"
|
||||
argument_passing_method="cmdline"/>
|
||||
</method>
|
||||
</interface>
|
||||
<interface name="org.freedesktop.DBus.Introspectable">
|
||||
<allow min_uid="0" max_uid="0"/>
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
#!/usr/bin/python3
|
||||
#
|
||||
# Copyright (C) 2021 FreeIPA Contributors see COPYING for license
|
||||
#
|
||||
|
||||
import logging
|
||||
|
||||
from ipalib import api
|
||||
from ipalib.install import sysrestore
|
||||
from ipaplatform.paths import paths
|
||||
from ipapython import ipaldap
|
||||
from ipapython.admintool import AdminTool
|
||||
from ipaserver.install import adtrust, adtrustinstance
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class IPAConfigEnableSid(AdminTool):
|
||||
command_name = "ipa-enable-sid"
|
||||
log_file_name = paths.IPASERVER_ENABLESID_LOG
|
||||
usage = "%prog"
|
||||
description = "Enable SID generation"
|
||||
|
||||
@classmethod
|
||||
def add_options(cls, parser):
|
||||
super(IPAConfigEnableSid, cls).add_options(parser)
|
||||
|
||||
parser.add_option(
|
||||
"--add-sids",
|
||||
dest="add_sids", default=False, action="store_true",
|
||||
help="Add SIDs for existing users and groups as the final step"
|
||||
)
|
||||
|
||||
parser.add_option(
|
||||
"--netbios-name",
|
||||
dest="netbios_name", default=None,
|
||||
help="NetBIOS name of the IPA domain"
|
||||
)
|
||||
|
||||
parser.add_option(
|
||||
"--reset-netbios-name",
|
||||
dest="reset_netbios_name", default=False, action="store_true",
|
||||
help="Force reset of the existing NetBIOS name"
|
||||
)
|
||||
|
||||
|
||||
def validate_options(self):
|
||||
super(IPAConfigEnableSid, self).validate_options(needs_root=True)
|
||||
|
||||
def run(self):
|
||||
api.bootstrap(in_server=True, confdir=paths.ETC_IPA)
|
||||
api.finalize()
|
||||
|
||||
try:
|
||||
api.Backend.ldap2.connect()
|
||||
fstore = sysrestore.FileStore(paths.SYSRESTORE)
|
||||
|
||||
smb = adtrustinstance.ADTRUSTInstance(fstore, False)
|
||||
smb.realm = api.env.realm
|
||||
smb.autobind = ipaldap.AUTOBIND_ENABLED
|
||||
smb.setup(api.env.host, api.env.realm,
|
||||
self.options.netbios_name,
|
||||
self.options.reset_netbios_name,
|
||||
adtrust.DEFAULT_PRIMARY_RID_BASE,
|
||||
adtrust.DEFAULT_SECONDARY_RID_BASE,
|
||||
self.options.add_sids,
|
||||
enable_compat=False)
|
||||
smb.find_local_id_range()
|
||||
smb.create_instance()
|
||||
|
||||
finally:
|
||||
if api.Backend.ldap2.isconnected():
|
||||
api.Backend.ldap2.disconnect()
|
||||
|
||||
return 0
|
||||
|
||||
IPAConfigEnableSid.run_cli()
|
||||
@@ -19,6 +19,7 @@ $OTHER_LIBDEFAULTS
|
||||
$REALM = {
|
||||
kdc = $FQDN:88
|
||||
master_kdc = $FQDN:88
|
||||
kpasswd_server = $FQDN:464
|
||||
admin_server = $FQDN:749
|
||||
default_domain = $DOMAIN
|
||||
pkinit_anchors = FILE:$KDC_CA_BUNDLE_PEM
|
||||
|
||||
@@ -5,7 +5,7 @@ realm = $REALM
|
||||
kerberos method = dedicated keytab
|
||||
dedicated keytab file = /etc/samba/samba.keytab
|
||||
create krb5 conf = no
|
||||
server role = CLASSIC PRIMARY DOMAIN CONTROLLER
|
||||
server role = $SERVER_ROLE
|
||||
security = user
|
||||
domain master = yes
|
||||
domain logons = yes
|
||||
|
||||
@@ -64,10 +64,11 @@ def parse_options():
|
||||
parser.add_option("--no-msdcs", dest="no_msdcs", action="store_true",
|
||||
default=False, help=SUPPRESS_HELP)
|
||||
|
||||
parser.add_option("--rid-base", dest="rid_base", type=int, default=1000,
|
||||
parser.add_option("--rid-base", dest="rid_base", type=int,
|
||||
default=adtrust.DEFAULT_PRIMARY_RID_BASE,
|
||||
help="Start value for mapping UIDs and GIDs to RIDs")
|
||||
parser.add_option("--secondary-rid-base", dest="secondary_rid_base",
|
||||
type=int, default=100000000,
|
||||
type=int, default=adtrust.DEFAULT_SECONDARY_RID_BASE,
|
||||
help="Start value of the secondary range for mapping "
|
||||
"UIDs and GIDs to RIDs")
|
||||
parser.add_option("-U", "--unattended", dest="unattended",
|
||||
@@ -209,6 +210,8 @@ def main():
|
||||
raise ScriptError(
|
||||
"Unrecognized error during check of admin rights: %s" % e)
|
||||
|
||||
# Force options.setup_adtrust
|
||||
options.setup_adtrust = True
|
||||
adtrust.install_check(True, options, api)
|
||||
adtrust.install(True, options, fstore, api)
|
||||
|
||||
|
||||
@@ -205,10 +205,7 @@ Do not automatically create DNS SSHFP records.
|
||||
\fB\-\-no\-dnssec\-validation\fR
|
||||
Disable DNSSEC validation on this server.
|
||||
|
||||
.SS "AD TRUST OPTIONS"
|
||||
.TP
|
||||
\fB\-\-setup\-adtrust\fR
|
||||
Configure AD Trust capability on a replica.
|
||||
.SS "SID GENERATION OPTIONS"
|
||||
.TP
|
||||
\fB\-\-netbios\-name\fR=\fINETBIOS_NAME\fR
|
||||
The NetBIOS name for the IPA domain. If not provided then this is determined
|
||||
@@ -227,6 +224,21 @@ ipa\-adtrust\-install is run and scheduled independently. To start this task
|
||||
you have to load an edited version of ipa-sidgen-task-run.ldif with the
|
||||
ldapmodify command info the directory server.
|
||||
.TP
|
||||
\fB\-\-rid-base\fR=\fIRID_BASE\fR
|
||||
First RID value of the local domain. The first Posix ID of the local domain will
|
||||
be assigned to this RID, the second to RID+1 etc. See the online help of the
|
||||
idrange CLI for details.
|
||||
.TP
|
||||
\fB\-\-secondary-rid-base\fR=\fISECONDARY_RID_BASE\fR
|
||||
Start value of the secondary RID range, which is only used in the case a user
|
||||
and a group share numerically the same Posix ID. See the online help of the
|
||||
idrange CLI for details.
|
||||
|
||||
.SS "AD TRUST OPTIONS"
|
||||
.TP
|
||||
\fB\-\-setup\-adtrust\fR
|
||||
Configure AD Trust capability on a replica.
|
||||
.TP
|
||||
\fB\-\-add\-agents\fR
|
||||
Add IPA masters to the list that allows to serve information about
|
||||
users from trusted forests. Starting with IPA 4.2, a regular IPA master
|
||||
@@ -240,16 +252,6 @@ information about users from trusted forests only if they are enabled
|
||||
via \ipa-adtrust\-install run on any other IPA master. At least SSSD
|
||||
version 1.13 on IPA master is required to be able to perform as a trust agent.
|
||||
.TP
|
||||
\fB\-\-rid-base\fR=\fIRID_BASE\fR
|
||||
First RID value of the local domain. The first Posix ID of the local domain will
|
||||
be assigned to this RID, the second to RID+1 etc. See the online help of the
|
||||
idrange CLI for details.
|
||||
.TP
|
||||
\fB\-\-secondary-rid-base\fR=\fISECONDARY_RID_BASE\fR
|
||||
Start value of the secondary RID range, which is only used in the case a user
|
||||
and a group share numerically the same Posix ID. See the online help of the
|
||||
idrange CLI for details.
|
||||
.TP
|
||||
\fB\-\-enable\-compat\fR
|
||||
Enables support for trusted domains users for old clients through Schema Compatibility plugin.
|
||||
SSSD supports trusted domains natively starting with version 1.9. For platforms that
|
||||
|
||||
@@ -230,11 +230,7 @@ Disable DNSSEC validation on this server.
|
||||
\fB\-\-allow\-zone\-overlap\fR
|
||||
Allow creation of (reverse) zone even if the zone is already resolvable. Using this option is discouraged as it result in later problems with domain name resolution.
|
||||
|
||||
.SS "AD TRUST OPTIONS"
|
||||
|
||||
.TP
|
||||
\fB\-\-setup\-adtrust\fR
|
||||
Configure AD Trust capability.
|
||||
.SS "SID GENERATION OPTIONS"
|
||||
.TP
|
||||
\fB\-\-netbios\-name\fR=\fINETBIOS_NAME\fR
|
||||
The NetBIOS name for the IPA domain. If not provided, this is determined
|
||||
@@ -252,6 +248,11 @@ idrange CLI for details.
|
||||
Start value of the secondary RID range, which is only used in the case a user
|
||||
and a group share numerically the same POSIX ID. See the online help of the
|
||||
idrange CLI for details.
|
||||
|
||||
.SS "AD TRUST OPTIONS"
|
||||
.TP
|
||||
\fB\-\-setup\-adtrust\fR
|
||||
Configure AD Trust capability.
|
||||
.TP
|
||||
\fB\-\-enable\-compat\fR
|
||||
Enables support for trusted domains users for old clients through Schema Compatibility plugin.
|
||||
|
||||
@@ -840,7 +840,22 @@ IPA.host_dnsrecord_entity_link_widget = function(spec) {
|
||||
var first_dot = pkey.search(/\./);
|
||||
var pkeys = [];
|
||||
pkeys[1] = pkey.substring(0,first_dot);
|
||||
pkeys[0] = pkey.substring(first_dot+1);
|
||||
var dnszone = pkey.substring(first_dot+1);
|
||||
pkeys[0] = dnszone;
|
||||
|
||||
// Check whether DNS record associated with the host belongs to a
|
||||
// fully qualified DNS zone (has trailing '.'). If so, modify the
|
||||
// pkey to be correct in the link.
|
||||
if (that.check_data && dnszone[dnszone.length-1] !== '.') {
|
||||
var avas = that.check_data.dn.split(',');
|
||||
for (var i=0, j=avas.length; i<j; i++) {
|
||||
var ava = avas[i];
|
||||
if (ava.indexOf('idnsname') === 0 && ava.indexOf(dnszone + '.') > 0) {
|
||||
pkeys[0] = dnszone + '.';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pkeys;
|
||||
};
|
||||
|
||||
|
||||
@@ -5223,6 +5223,9 @@ IPA.link_widget = function(spec) {
|
||||
retry: false,
|
||||
on_success: function(data) {
|
||||
that.is_link = data.result && data.result.result;
|
||||
if (that.is_link) {
|
||||
that.check_data = data.result.result;
|
||||
}
|
||||
that.update_link();
|
||||
},
|
||||
on_error: function() {
|
||||
|
||||
@@ -16,7 +16,7 @@ only: nsslapd-pluginPrecedence: 60
|
||||
# Set limits to suite better IPA deployment sizes, defaults are too
|
||||
# conservative
|
||||
dn: cn=config
|
||||
default: nsslapd-sizelimit:100000
|
||||
replace: nsslapd-sizelimit:2000::100000
|
||||
|
||||
dn: cn=config,cn=ldbm database,cn=plugins,cn=config
|
||||
replace: nsslapd-lookthroughlimit:5000::100000
|
||||
|
||||
@@ -446,13 +446,17 @@ def uninstall(fstore, statestore, options):
|
||||
fstore.restore_file(paths.SMB_CONF)
|
||||
|
||||
# Remove samba's persistent and temporary tdb files
|
||||
tdb_files = [
|
||||
tdb_file
|
||||
for tdb_file in os.listdir(paths.SAMBA_DIR)
|
||||
if tdb_file.endswith(".tdb")
|
||||
]
|
||||
for tdb_file in tdb_files:
|
||||
ipautil.remove_file(tdb_file)
|
||||
# in /var/lib/samba and /var/lib/samba/private
|
||||
for smbpath in (paths.SAMBA_DIR,
|
||||
os.path.join(paths.SAMBA_DIR, "private"),
|
||||
os.path.join(paths.SAMBA_DIR, "lock")):
|
||||
tdb_files = [
|
||||
os.path.join(smbpath, tdb_file)
|
||||
for tdb_file in os.listdir(smbpath)
|
||||
if tdb_file.endswith(".tdb")
|
||||
]
|
||||
for tdb_file in tdb_files:
|
||||
ipautil.remove_file(tdb_file)
|
||||
|
||||
# Remove our keys from samba's keytab
|
||||
if os.path.exists(paths.SAMBA_KEYTAB):
|
||||
|
||||
@@ -34,6 +34,7 @@ class ServerInfo(MutableMapping):
|
||||
hostname = DNSName(api.env.server).ToASCII()
|
||||
self._path = os.path.join(self._DIR, hostname)
|
||||
self._force_check = api.env.force_schema_check
|
||||
self._now = time.time()
|
||||
self._dict = {}
|
||||
|
||||
# copy-paste from ipalib/rpc.py
|
||||
@@ -87,12 +88,11 @@ class ServerInfo(MutableMapping):
|
||||
def __len__(self):
|
||||
return len(self._dict)
|
||||
|
||||
def update_validity(self, ttl=None):
|
||||
if ttl is None:
|
||||
ttl = 3600
|
||||
self['expiration'] = time.time() + ttl
|
||||
self['language'] = self._language
|
||||
self._write()
|
||||
def update_validity(self, ttl):
|
||||
if not self.is_valid():
|
||||
self['expiration'] = self._now + ttl
|
||||
self['language'] = self._language
|
||||
self._write()
|
||||
|
||||
def is_valid(self):
|
||||
if self._force_check:
|
||||
@@ -105,8 +105,7 @@ class ServerInfo(MutableMapping):
|
||||
# if any of these is missing consider the entry expired
|
||||
return False
|
||||
|
||||
if expiration < time.time():
|
||||
# validity passed
|
||||
if expiration < self._now:
|
||||
return False
|
||||
|
||||
if language != self._language:
|
||||
|
||||
@@ -58,7 +58,10 @@ def get_package(server_info, client):
|
||||
else:
|
||||
server_version = '2.0'
|
||||
server_info['version'] = server_version
|
||||
server_info.update_validity()
|
||||
|
||||
# in compat mode we don't get the schema TTL from the server
|
||||
# so use the client context value.
|
||||
server_info.update_validity(client.api.env.schema_ttl)
|
||||
|
||||
server_version = APIVersion(server_version)
|
||||
|
||||
|
||||
@@ -375,7 +375,7 @@ class Schema:
|
||||
namespaces = {'classes', 'commands', 'topics'}
|
||||
_DIR = os.path.join(USER_CACHE_PATH, 'ipa', 'schema', FORMAT)
|
||||
|
||||
def __init__(self, client, fingerprint=None):
|
||||
def __init__(self, client, fingerprint=None, ttl=0):
|
||||
self._dict = {}
|
||||
self._namespaces = {}
|
||||
self._help = None
|
||||
@@ -384,7 +384,6 @@ class Schema:
|
||||
self._dict[ns] = {}
|
||||
self._namespaces[ns] = _SchemaNameSpace(self, ns)
|
||||
|
||||
ttl = None
|
||||
read_failed = False
|
||||
|
||||
if fingerprint is not None:
|
||||
@@ -554,10 +553,10 @@ def get_package(server_info, client):
|
||||
else:
|
||||
schema = Schema(client, fingerprint)
|
||||
except SchemaUpToDate as e:
|
||||
schema = Schema(client, e.fingerprint)
|
||||
schema = Schema(client, e.fingerprint, e.ttl)
|
||||
except NotAvailable:
|
||||
fingerprint = None
|
||||
ttl = None
|
||||
ttl = 3600 # set a ttl so we don't hammer the remote server
|
||||
except SchemaUpToDate as e:
|
||||
fingerprint = e.fingerprint
|
||||
ttl = e.ttl
|
||||
|
||||
@@ -23,6 +23,7 @@ All constants centralised in one file.
|
||||
"""
|
||||
|
||||
import os
|
||||
import string
|
||||
|
||||
from ipaplatform.constants import constants as _constants
|
||||
from ipapython.dn import DN
|
||||
@@ -182,6 +183,9 @@ DEFAULT_CONFIG = (
|
||||
# How long to wait for a certmonger request to finish
|
||||
('certmonger_wait_timeout', 300),
|
||||
|
||||
# Number of seconds before client should check for schema update.
|
||||
('schema_ttl', 3600),
|
||||
|
||||
# Web Application mount points
|
||||
('mount_ipa', '/ipa/'),
|
||||
|
||||
@@ -368,3 +372,5 @@ KRA_TRACKING_REQS = {
|
||||
'transportCert cert-pki-kra': 'caTransportCert',
|
||||
'storageCert cert-pki-kra': 'caStorageCert',
|
||||
}
|
||||
|
||||
ALLOWED_NETBIOS_CHARS = string.ascii_uppercase + string.digits + '-'
|
||||
@@ -259,7 +259,7 @@ class BasePathNamespace:
|
||||
IPA_PKI_RETRIEVE_KEY = "/usr/libexec/ipa/ipa-pki-retrieve-key"
|
||||
IPA_HTTPD_PASSWD_READER = "/usr/libexec/ipa/ipa-httpd-pwdreader"
|
||||
IPA_PKI_WAIT_RUNNING = "/usr/libexec/ipa/ipa-pki-wait-running"
|
||||
DNSSEC_KEYFROMLABEL = "/usr/sbin/dnssec-keyfromlabel-pkcs11"
|
||||
DNSSEC_KEYFROMLABEL = "/usr/sbin/dnssec-keyfromlabel"
|
||||
GETSEBOOL = "/usr/sbin/getsebool"
|
||||
GROUPADD = "/usr/sbin/groupadd"
|
||||
USERMOD = "/usr/sbin/usermod"
|
||||
@@ -364,6 +364,7 @@ class BasePathNamespace:
|
||||
IPAREPLICA_CONNCHECK_LOG = "/var/log/ipareplica-conncheck.log"
|
||||
IPAREPLICA_INSTALL_LOG = "/var/log/ipareplica-install.log"
|
||||
IPARESTORE_LOG = "/var/log/iparestore.log"
|
||||
IPASERVER_ENABLESID_LOG = "/var/log/ipaserver-enable-sid.log"
|
||||
IPASERVER_INSTALL_LOG = "/var/log/ipaserver-install.log"
|
||||
IPASERVER_ADTRUST_INSTALL_LOG = "/var/log/ipaserver-adtrust-install.log"
|
||||
IPASERVER_DNS_INSTALL_LOG = "/var/log/ipaserver-dns-install.log"
|
||||
|
||||
@@ -36,7 +36,6 @@ class FedoraPathNamespace(RedHatPathNamespace):
|
||||
NAMED_CRYPTO_POLICY_FILE = "/etc/crypto-policies/back-ends/bind.config"
|
||||
if HAS_NFS_CONF:
|
||||
SYSCONFIG_NFS = '/etc/nfs.conf'
|
||||
DNSSEC_KEYFROMLABEL = "/usr/sbin/dnssec-keyfromlabel"
|
||||
|
||||
|
||||
paths = FedoraPathNamespace()
|
||||
@@ -756,6 +756,9 @@ class RedHatTaskNamespace(BaseTaskNamespace):
|
||||
"{}.module".format(name))
|
||||
for name, _module, _disabled in PKCS11_MODULES)
|
||||
|
||||
def enable_sssd_sudo(self, _fstore):
|
||||
"""sudo enablement is handled by authselect"""
|
||||
|
||||
def enable_ldap_automount(self, statestore):
|
||||
"""
|
||||
Point automount to ldap in nsswitch.conf.
|
||||
|
||||
+12
-3
@@ -763,6 +763,7 @@ class LDAPClient:
|
||||
'nsslapd-enable-upgrade-hash': True,
|
||||
'nsslapd-db-locks': True,
|
||||
'nsslapd-logging-hr-timestamps-enabled': True,
|
||||
'nsslapd-sizelimit': True,
|
||||
})
|
||||
|
||||
time_limit = -1.0 # unlimited
|
||||
@@ -1820,9 +1821,17 @@ class LDAPCache(LDAPClient):
|
||||
entry=None, exception=None):
|
||||
# idnsname - caching prevents delete when mod value to None
|
||||
# cospriority - in a Class of Service object, uncacheable
|
||||
# TODO - usercertificate was banned at one point and I don't remember
|
||||
# why...
|
||||
BANNED_ATTRS = {'idnsname', 'cospriority'}
|
||||
# usercertificate* - caching subtypes is tricky, trade less
|
||||
# complexity for performance
|
||||
#
|
||||
# TODO: teach the cache about subtypes
|
||||
|
||||
BANNED_ATTRS = {
|
||||
'idnsname',
|
||||
'cospriority',
|
||||
'usercertificate',
|
||||
'usercertificate;binary'
|
||||
}
|
||||
if not self._enable_cache:
|
||||
return
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ logger = logging.getLogger(__name__)
|
||||
IPA_DEFAULT_MASTER_SRV_REC = (
|
||||
# srv record name, port
|
||||
(DNSName('_ldap._tcp'), 389),
|
||||
# Kerberos records are provided for MIT KRB5 < 1.15 and AD
|
||||
(DNSName('_kerberos._tcp'), 88),
|
||||
(DNSName('_kerberos._udp'), 88),
|
||||
(DNSName('_kerberos-master._tcp'), 88),
|
||||
@@ -40,6 +41,20 @@ IPA_DEFAULT_MASTER_SRV_REC = (
|
||||
(DNSName('_kpasswd._udp'), 464),
|
||||
)
|
||||
|
||||
IPA_DEFAULT_MASTER_URI_REC = (
|
||||
# URI record name, URI template
|
||||
|
||||
# MIT KRB5 1.15+ prefers URI records for service discovery
|
||||
# scheme: always krb5srv
|
||||
# flags: empty or 'm' for primary server
|
||||
# transport: 'tcp', 'udp', or 'kkdcp')
|
||||
# residual: 'hostname', 'hostname:port', or 'https://' URL
|
||||
(DNSName('_kerberos'), "krb5srv:m:tcp:{hostname}"),
|
||||
(DNSName('_kerberos'), "krb5srv:m:udp:{hostname}"),
|
||||
(DNSName('_kpasswd'), "krb5srv:m:tcp:{hostname}"),
|
||||
(DNSName('_kpasswd'), "krb5srv:m:udp:{hostname}"),
|
||||
)
|
||||
|
||||
IPA_DEFAULT_ADTRUST_SRV_REC = (
|
||||
# srv record name, port
|
||||
(DNSName('_ldap._tcp.Default-First-Site-Name._sites.dc._msdcs'), 389),
|
||||
@@ -67,6 +82,8 @@ class IPASystemRecords:
|
||||
# fixme do it configurable
|
||||
PRIORITY_HIGH = 0
|
||||
PRIORITY_LOW = 50
|
||||
# FIXME: use TTL from config
|
||||
TTL = 3600
|
||||
|
||||
def __init__(self, api_instance, all_servers=False):
|
||||
self.api_instance = api_instance
|
||||
@@ -134,7 +151,35 @@ class IPASystemRecords:
|
||||
|
||||
rdataset = zone_obj.get_rdataset(
|
||||
r_name, rdatatype.SRV, create=True)
|
||||
rdataset.add(rd, ttl=86400) # FIXME: use TTL from config
|
||||
rdataset.add(rd, ttl=self.TTL)
|
||||
|
||||
def __add_uri_records(
|
||||
self, zone_obj, hostname, rname_uri_map,
|
||||
weight=100, priority=0, location=None
|
||||
):
|
||||
assert isinstance(hostname, DNSName)
|
||||
assert isinstance(priority, int)
|
||||
assert isinstance(weight, int)
|
||||
|
||||
if location:
|
||||
suffix = self.__get_location_suffix(location)
|
||||
else:
|
||||
suffix = self.domain_abs
|
||||
|
||||
for name, uri_template in rname_uri_map:
|
||||
uri = uri_template.format(hostname=hostname.make_absolute())
|
||||
rd = rdata.from_text(
|
||||
rdataclass.IN, rdatatype.URI,
|
||||
'{0} {1} {2}'.format(
|
||||
priority, weight, uri
|
||||
)
|
||||
)
|
||||
|
||||
r_name = name.derelativize(suffix)
|
||||
|
||||
rdataset = zone_obj.get_rdataset(
|
||||
r_name, rdatatype.URI, create=True)
|
||||
rdataset.add(rd, ttl=self.TTL)
|
||||
|
||||
def __add_ca_records_from_hostname(self, zone_obj, hostname):
|
||||
assert isinstance(hostname, DNSName) and hostname.is_absolute()
|
||||
@@ -163,7 +208,7 @@ class IPASystemRecords:
|
||||
for rd in rrset:
|
||||
rdataset = zone_obj.get_rdataset(
|
||||
r_name, rd.rdtype, create=True)
|
||||
rdataset.add(rd, ttl=86400) # FIXME: use TTL from config
|
||||
rdataset.add(rd, ttl=self.TTL)
|
||||
|
||||
def __add_kerberos_txt_rec(self, zone_obj):
|
||||
# FIXME: with external DNS, this should generate records for all
|
||||
@@ -174,7 +219,7 @@ class IPASystemRecords:
|
||||
rdataset = zone_obj.get_rdataset(
|
||||
r_name, rdatatype.TXT, create=True
|
||||
)
|
||||
rdataset.add(rd, ttl=86400) # FIXME: use TTL from config
|
||||
rdataset.add(rd, ttl=self.TTL)
|
||||
|
||||
def _add_base_dns_records_for_server(
|
||||
self, zone_obj, hostname, roles=None, include_master_role=True,
|
||||
@@ -198,6 +243,12 @@ class IPASystemRecords:
|
||||
IPA_DEFAULT_MASTER_SRV_REC,
|
||||
weight=server['weight']
|
||||
)
|
||||
self.__add_uri_records(
|
||||
zone_obj,
|
||||
hostname_abs,
|
||||
IPA_DEFAULT_MASTER_URI_REC,
|
||||
weight=server['weight']
|
||||
)
|
||||
|
||||
if 'CA server' in eff_roles:
|
||||
self.__add_ca_records_from_hostname(zone_obj, hostname_abs)
|
||||
@@ -244,6 +295,14 @@ class IPASystemRecords:
|
||||
priority=priority,
|
||||
location=location
|
||||
)
|
||||
self.__add_uri_records(
|
||||
zone_obj,
|
||||
hostname_abs,
|
||||
IPA_DEFAULT_MASTER_URI_REC,
|
||||
weight=server['weight'],
|
||||
priority=priority,
|
||||
location=location
|
||||
)
|
||||
|
||||
if 'AD trust controller' in eff_roles:
|
||||
self.__add_srv_records(
|
||||
|
||||
@@ -127,6 +127,7 @@ class BINDMgr:
|
||||
)
|
||||
cmd = [
|
||||
paths.DNSSEC_KEYFROMLABEL,
|
||||
'-E', 'pkcs11',
|
||||
'-K', workdir,
|
||||
'-a', attrs['idnsSecAlgorithm'][0],
|
||||
'-l', uri
|
||||
|
||||
@@ -39,6 +39,9 @@ logger = logging.getLogger(__name__)
|
||||
netbios_name = None
|
||||
reset_netbios_name = False
|
||||
|
||||
DEFAULT_PRIMARY_RID_BASE = 1000
|
||||
DEFAULT_SECONDARY_RID_BASE = 100000000
|
||||
|
||||
|
||||
def netbios_name_error(name):
|
||||
logger.error("\nIllegal NetBIOS name [%s].\n", name)
|
||||
@@ -413,7 +416,7 @@ def install_check(standalone, options, api):
|
||||
global netbios_name
|
||||
global reset_netbios_name
|
||||
|
||||
if not standalone:
|
||||
if options.setup_adtrust and not standalone:
|
||||
check_for_installed_deps()
|
||||
|
||||
realm_not_matching_domain = (api.env.domain.upper() != api.env.realm)
|
||||
@@ -432,26 +435,27 @@ def install_check(standalone, options, api):
|
||||
# Check if /etc/samba/smb.conf already exists. In case it was not generated
|
||||
# by IPA, print a warning that we will break existing configuration.
|
||||
|
||||
if adtrustinstance.ipa_smb_conf_exists():
|
||||
if not options.unattended:
|
||||
print("IPA generated smb.conf detected.")
|
||||
if not ipautil.user_input("Overwrite smb.conf?",
|
||||
default=False,
|
||||
allow_empty=False):
|
||||
raise ScriptError("Aborting installation.")
|
||||
if options.setup_adtrust:
|
||||
if adtrustinstance.ipa_smb_conf_exists():
|
||||
if not options.unattended:
|
||||
print("IPA generated smb.conf detected.")
|
||||
if not ipautil.user_input("Overwrite smb.conf?",
|
||||
default=False,
|
||||
allow_empty=False):
|
||||
raise ScriptError("Aborting installation.")
|
||||
|
||||
elif os.path.exists(paths.SMB_CONF):
|
||||
print("WARNING: The smb.conf already exists. Running "
|
||||
"ipa-adtrust-install will break your existing samba "
|
||||
"configuration.\n\n")
|
||||
if not options.unattended:
|
||||
if not ipautil.user_input("Do you wish to continue?",
|
||||
default=False,
|
||||
allow_empty=False):
|
||||
raise ScriptError("Aborting installation.")
|
||||
elif os.path.exists(paths.SMB_CONF):
|
||||
print("WARNING: The smb.conf already exists. Running "
|
||||
"ipa-adtrust-install will break your existing samba "
|
||||
"configuration.\n\n")
|
||||
if not options.unattended:
|
||||
if not ipautil.user_input("Do you wish to continue?",
|
||||
default=False,
|
||||
allow_empty=False):
|
||||
raise ScriptError("Aborting installation.")
|
||||
|
||||
if not options.unattended and not options.enable_compat:
|
||||
options.enable_compat = enable_compat_tree()
|
||||
if not options.unattended and not options.enable_compat:
|
||||
options.enable_compat = enable_compat_tree()
|
||||
|
||||
netbios_name, reset_netbios_name = set_and_check_netbios_name(
|
||||
options.netbios_name, options.unattended, api)
|
||||
@@ -467,7 +471,7 @@ def install(standalone, options, fstore, api):
|
||||
print("Please wait until the prompt is returned.")
|
||||
print("")
|
||||
|
||||
smb = adtrustinstance.ADTRUSTInstance(fstore)
|
||||
smb = adtrustinstance.ADTRUSTInstance(fstore, options.setup_adtrust)
|
||||
smb.realm = api.env.realm
|
||||
smb.autobind = ipaldap.AUTOBIND_ENABLED
|
||||
smb.setup(api.env.host, api.env.realm,
|
||||
@@ -530,7 +534,41 @@ def generate_dns_service_records_help(api):
|
||||
|
||||
|
||||
@group
|
||||
class ADTrustInstallInterface(ServiceAdminInstallInterface):
|
||||
class SIDInstallInterface(ServiceAdminInstallInterface):
|
||||
"""
|
||||
Interface for the SID generation Installer
|
||||
|
||||
Knobs defined here will be available in:
|
||||
* ipa-server-install
|
||||
* ipa-replica-install
|
||||
* ipa-adtrust-install
|
||||
"""
|
||||
description = "SID generation"
|
||||
add_sids = knob(
|
||||
None,
|
||||
description="Add SIDs for existing users and groups as the final step"
|
||||
)
|
||||
add_sids = replica_install_only(add_sids)
|
||||
netbios_name = knob(
|
||||
str,
|
||||
None,
|
||||
description="NetBIOS name of the IPA domain"
|
||||
)
|
||||
rid_base = knob(
|
||||
int,
|
||||
DEFAULT_PRIMARY_RID_BASE,
|
||||
description="Start value for mapping UIDs and GIDs to RIDs"
|
||||
)
|
||||
secondary_rid_base = knob(
|
||||
int,
|
||||
DEFAULT_SECONDARY_RID_BASE,
|
||||
description="Start value of the secondary range for mapping "
|
||||
"UIDs and GIDs to RIDs"
|
||||
)
|
||||
|
||||
|
||||
@group
|
||||
class ADTrustInstallInterface(SIDInstallInterface):
|
||||
"""
|
||||
Interface for the AD trust installer
|
||||
|
||||
@@ -543,10 +581,6 @@ class ADTrustInstallInterface(ServiceAdminInstallInterface):
|
||||
|
||||
# the following knobs are provided on top of those specified for
|
||||
# admin credentials
|
||||
add_sids = knob(
|
||||
None,
|
||||
description="Add SIDs for existing users and groups as the final step"
|
||||
)
|
||||
add_agents = knob(
|
||||
None,
|
||||
description="Add IPA masters to a list of hosts allowed to "
|
||||
@@ -557,24 +591,8 @@ class ADTrustInstallInterface(ServiceAdminInstallInterface):
|
||||
None,
|
||||
description="Enable support for trusted domains for old clients"
|
||||
)
|
||||
netbios_name = knob(
|
||||
str,
|
||||
None,
|
||||
description="NetBIOS name of the IPA domain"
|
||||
)
|
||||
no_msdcs = knob(
|
||||
None,
|
||||
description="Deprecated: has no effect",
|
||||
deprecated=True
|
||||
)
|
||||
rid_base = knob(
|
||||
int,
|
||||
1000,
|
||||
description="Start value for mapping UIDs and GIDs to RIDs"
|
||||
)
|
||||
secondary_rid_base = knob(
|
||||
int,
|
||||
100000000,
|
||||
description="Start value of the secondary range for mapping "
|
||||
"UIDs and GIDs to RIDs"
|
||||
)
|
||||
@@ -25,7 +25,6 @@ import errno
|
||||
import ldap
|
||||
import tempfile
|
||||
import uuid
|
||||
import string
|
||||
import struct
|
||||
import re
|
||||
import socket
|
||||
@@ -36,7 +35,8 @@ from ipaserver.install import service
|
||||
from ipaserver.install import installutils
|
||||
from ipaserver.install.replication import wait_for_task
|
||||
from ipalib import errors, api
|
||||
from ipalib.constants import SUBID_RANGE_START
|
||||
from ipalib.constants import SUBID_RANGE_START, ALLOWED_NETBIOS_CHARS
|
||||
|
||||
from ipalib.util import normalize_zone
|
||||
from ipapython.dn import DN
|
||||
from ipapython import ipachangeconf
|
||||
@@ -54,8 +54,6 @@ if six.PY3:
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
ALLOWED_NETBIOS_CHARS = string.ascii_uppercase + string.digits + '-'
|
||||
|
||||
UPGRADE_ERROR = """
|
||||
Entry %(dn)s does not exist.
|
||||
This means upgrade from IPA 2.x to 3.x did not went well and required S4U2Proxy
|
||||
@@ -148,8 +146,10 @@ class ADTRUSTInstance(service.Service):
|
||||
OBJC_GROUP = "ipaNTGroupAttrs"
|
||||
OBJC_DOMAIN = "ipaNTDomainAttrs"
|
||||
FALLBACK_GROUP_NAME = u'Default SMB Group'
|
||||
SERVER_ROLE_OLD = "CLASSIC PRIMARY DOMAIN CONTROLLER"
|
||||
SERVER_ROLE_NEW = "IPA PRIMARY DOMAIN CONTROLLER"
|
||||
|
||||
def __init__(self, fstore=None):
|
||||
def __init__(self, fstore=None, fulltrust=True):
|
||||
self.netbios_name = None
|
||||
self.reset_netbios_name = None
|
||||
self.add_sids = None
|
||||
@@ -163,10 +163,15 @@ class ADTRUSTInstance(service.Service):
|
||||
|
||||
self.fqdn = None
|
||||
self.host_netbios_name = None
|
||||
self.fulltrust = fulltrust
|
||||
|
||||
super(ADTRUSTInstance, self).__init__(
|
||||
"smb", service_desc="CIFS", fstore=fstore, service_prefix=u'cifs',
|
||||
keytab=paths.SAMBA_KEYTAB)
|
||||
if self.fulltrust:
|
||||
super(ADTRUSTInstance, self).__init__(
|
||||
"smb", service_desc="CIFS", fstore=fstore,
|
||||
service_prefix=u'cifs',
|
||||
keytab=paths.SAMBA_KEYTAB)
|
||||
else:
|
||||
super(ADTRUSTInstance, self).__init__("SID generation")
|
||||
|
||||
self.__setup_default_attributes()
|
||||
|
||||
@@ -200,12 +205,13 @@ class ADTRUSTInstance(service.Service):
|
||||
api.env.container_cifsdomains,
|
||||
self.suffix)
|
||||
|
||||
self.cifs_agent = DN(('krbprincipalname', self.principal.lower()),
|
||||
api.env.container_service,
|
||||
self.suffix)
|
||||
self.host_princ = DN(('fqdn', self.fqdn),
|
||||
api.env.container_host,
|
||||
self.suffix)
|
||||
if self.fulltrust:
|
||||
self.cifs_agent = DN(('krbprincipalname', self.principal.lower()),
|
||||
api.env.container_service,
|
||||
self.suffix)
|
||||
self.host_princ = DN(('fqdn', self.fqdn),
|
||||
api.env.container_host,
|
||||
self.suffix)
|
||||
|
||||
|
||||
def __gen_sid_string(self):
|
||||
@@ -329,6 +335,8 @@ class ADTRUSTInstance(service.Service):
|
||||
# _ldap_mod does not return useful error codes, so we must check again
|
||||
# if the fallback group was created properly.
|
||||
try:
|
||||
# Remove entry from cache otherwise get_entry won't find it
|
||||
api.Backend.ldap2.remove_cache_entry(fb_group_dn)
|
||||
api.Backend.ldap2.get_entry(fb_group_dn)
|
||||
except errors.NotFound:
|
||||
self.print_msg("Failed to add fallback group.")
|
||||
@@ -546,7 +554,7 @@ class ADTRUSTInstance(service.Service):
|
||||
try:
|
||||
current = api.Backend.ldap2.get_entry(targets_dn)
|
||||
members = current.get('memberPrincipal', [])
|
||||
if not(self.principal in members):
|
||||
if self.principal not in members:
|
||||
current["memberPrincipal"] = members + [self.principal]
|
||||
api.Backend.ldap2.update_entry(current)
|
||||
else:
|
||||
@@ -567,7 +575,16 @@ class ADTRUSTInstance(service.Service):
|
||||
with tempfile.NamedTemporaryFile(mode='w') as tmp_conf:
|
||||
tmp_conf.write(conf)
|
||||
tmp_conf.flush()
|
||||
ipautil.run([paths.NET, "conf", "import", tmp_conf.name])
|
||||
try:
|
||||
ipautil.run([paths.NET, "conf", "import", tmp_conf.name])
|
||||
except ipautil.CalledProcessError as e:
|
||||
if e.returncode == 255:
|
||||
# We have old Samba that doesn't support IPA DC server role
|
||||
# re-try again with the older variant, upgrade code will
|
||||
# take care to change the role later when Samba is upgraded
|
||||
# as well.
|
||||
self.sub_dict['SERVER_ROLE'] = self.SERVER_ROLE_OLD
|
||||
self.__write_smb_registry()
|
||||
|
||||
def __map_Guests_to_nobody(self):
|
||||
map_Guests_to_nobody()
|
||||
@@ -769,6 +786,7 @@ class ADTRUSTInstance(service.Service):
|
||||
LDAPI_SOCKET=self.ldapi_socket,
|
||||
FQDN=self.fqdn,
|
||||
SAMBA_DIR=paths.SAMBA_DIR,
|
||||
SERVER_ROLE=self.SERVER_ROLE_NEW,
|
||||
)
|
||||
|
||||
def setup(self, fqdn, realm_name, netbios_name,
|
||||
@@ -838,45 +856,59 @@ class ADTRUSTInstance(service.Service):
|
||||
self.sub_dict['IPA_LOCAL_RANGE'] = get_idmap_range(self.realm)
|
||||
|
||||
def create_instance(self):
|
||||
self.step("validate server hostname",
|
||||
self.__validate_server_hostname)
|
||||
self.step("stopping smbd", self.__stop)
|
||||
if self.fulltrust:
|
||||
self.step("validate server hostname",
|
||||
self.__validate_server_hostname)
|
||||
self.step("stopping smbd", self.__stop)
|
||||
self.step("creating samba domain object", \
|
||||
self.__create_samba_domain_object)
|
||||
self.step("retrieve local idmap range", self.__retrieve_local_range)
|
||||
self.step("writing samba config file", self.__write_smb_conf)
|
||||
self.step("creating samba config registry", self.__write_smb_registry)
|
||||
self.step("adding cifs Kerberos principal",
|
||||
self.request_service_keytab)
|
||||
self.step("adding cifs and host Kerberos principals to the adtrust agents group", \
|
||||
if self.fulltrust:
|
||||
self.step("retrieve local idmap range",
|
||||
self.__retrieve_local_range)
|
||||
self.step("writing samba config file", self.__write_smb_conf)
|
||||
self.step("creating samba config registry",
|
||||
self.__write_smb_registry)
|
||||
self.step("adding cifs Kerberos principal",
|
||||
self.request_service_keytab)
|
||||
self.step("adding cifs and host Kerberos principals to the "
|
||||
"adtrust agents group",
|
||||
self.__setup_group_membership)
|
||||
self.step("check for cifs services defined on other replicas", self.__check_replica)
|
||||
self.step("adding cifs principal to S4U2Proxy targets", self.__add_s4u2proxy_target)
|
||||
self.step("check for cifs services defined on other replicas",
|
||||
self.__check_replica)
|
||||
self.step("adding cifs principal to S4U2Proxy targets",
|
||||
self.__add_s4u2proxy_target)
|
||||
self.step("adding admin(group) SIDs", self.__add_admin_sids)
|
||||
self.step("adding RID bases", self.__add_rid_bases)
|
||||
self.step("updating Kerberos config", self.__update_krb5_conf)
|
||||
self.step("activating CLDAP plugin", self.__add_cldap_module)
|
||||
if self.fulltrust:
|
||||
self.step("activating CLDAP plugin", self.__add_cldap_module)
|
||||
self.step("activating sidgen task", self.__add_sidgen_task)
|
||||
self.step("map BUILTIN\\Guests to nobody group",
|
||||
self.__map_Guests_to_nobody)
|
||||
self.step("configuring smbd to start on boot", self.__enable)
|
||||
if self.fulltrust:
|
||||
self.step("map BUILTIN\\Guests to nobody group",
|
||||
self.__map_Guests_to_nobody)
|
||||
self.step("configuring smbd to start on boot", self.__enable)
|
||||
|
||||
if self.enable_compat:
|
||||
self.step("enabling trusted domains support for older clients via Schema Compatibility plugin",
|
||||
self.step("enabling trusted domains support for older clients via "
|
||||
"Schema Compatibility plugin",
|
||||
self.__enable_compat_tree)
|
||||
|
||||
self.step("restarting Directory Server to take MS PAC and LDAP plugins changes into account", \
|
||||
self.step("restarting Directory Server to take MS PAC and LDAP "
|
||||
"plugins changes into account",
|
||||
self.__restart_dirsrv)
|
||||
self.step("adding fallback group", self.__add_fallback_group)
|
||||
self.step("adding Default Trust View", self.__add_default_trust_view)
|
||||
self.step("setting SELinux booleans", \
|
||||
self.__configure_selinux_for_smbd)
|
||||
self.step("starting CIFS services", self.__start)
|
||||
if self.fulltrust:
|
||||
self.step("adding Default Trust View",
|
||||
self.__add_default_trust_view)
|
||||
self.step("setting SELinux booleans",
|
||||
self.__configure_selinux_for_smbd)
|
||||
self.step("starting CIFS services", self.__start)
|
||||
|
||||
if self.add_sids:
|
||||
self.step("adding SIDs to existing users and groups",
|
||||
self.__add_sids)
|
||||
self.step("restarting smbd", self.__restart_smb)
|
||||
if self.fulltrust:
|
||||
self.step("restarting smbd", self.__restart_smb)
|
||||
|
||||
self.start_creation(show_service_name=False)
|
||||
|
||||
@@ -918,11 +950,18 @@ class ADTRUSTInstance(service.Service):
|
||||
ipautil.remove_file(self.smb_conf)
|
||||
|
||||
# Remove samba's persistent and temporary tdb files
|
||||
if os.path.isdir(paths.SAMBA_DIR):
|
||||
tdb_files = [tdb_file for tdb_file in os.listdir(paths.SAMBA_DIR)
|
||||
if tdb_file.endswith(".tdb")]
|
||||
for tdb_file in tdb_files:
|
||||
ipautil.remove_file(tdb_file)
|
||||
# in /var/lib/samba and /var/lib/samba/private
|
||||
for smbpath in (paths.SAMBA_DIR,
|
||||
os.path.join(paths.SAMBA_DIR, "private"),
|
||||
os.path.join(paths.SAMBA_DIR, "lock")):
|
||||
if os.path.isdir(smbpath):
|
||||
tdb_files = [
|
||||
os.path.join(smbpath, tdb_file)
|
||||
for tdb_file in os.listdir(smbpath)
|
||||
if tdb_file.endswith(".tdb")
|
||||
]
|
||||
for tdb_file in tdb_files:
|
||||
ipautil.remove_file(tdb_file)
|
||||
|
||||
# Remove our keys from samba's keytab
|
||||
self.clean_samba_keytab()
|
||||
@@ -1973,8 +1973,17 @@ def import_included_profiles():
|
||||
|
||||
# Create the profile, replacing any existing profile of same name
|
||||
profile_data = __get_profile_config(profile_id)
|
||||
_create_dogtag_profile(profile_id, profile_data, overwrite=True)
|
||||
logger.debug("Imported profile '%s'", profile_id)
|
||||
try:
|
||||
_create_dogtag_profile(profile_id, profile_data,
|
||||
overwrite=True)
|
||||
except errors.HTTPRequestError as e:
|
||||
logger.warning("Failed to import profile '%s': %s. Running "
|
||||
"ipa-server-upgrade when installation is "
|
||||
"completed may resolve this issue.",
|
||||
profile_id, e)
|
||||
conn.delete_entry(entry)
|
||||
else:
|
||||
logger.debug("Imported profile '%s'", profile_id)
|
||||
else:
|
||||
logger.debug(
|
||||
"Profile '%s' is already in LDAP; skipping", profile_id
|
||||
|
||||
@@ -36,8 +36,10 @@ from configparser import DEFAULTSECT, ConfigParser, RawConfigParser
|
||||
|
||||
import six
|
||||
|
||||
import pki
|
||||
from pki.client import PKIConnection
|
||||
import pki.system
|
||||
import pki.util
|
||||
|
||||
from ipalib import api, errors, x509
|
||||
from ipalib.install import certmonger
|
||||
@@ -202,6 +204,18 @@ class DogtagInstance(service.Service):
|
||||
"-f", cfg_file,
|
||||
"--debug"]
|
||||
|
||||
# specify --log-file <path> on PKI 11.0.0 or later
|
||||
|
||||
pki_version = pki.util.Version(pki.specification_version())
|
||||
if pki_version >= pki.util.Version("11.0.0"):
|
||||
timestamp = time.strftime(
|
||||
"%Y%m%d%H%M%S",
|
||||
time.localtime(time.time()))
|
||||
log_file = os.path.join(
|
||||
paths.VAR_LOG_PKI_DIR,
|
||||
"pki-%s-spawn.%s.log" % (self.subsystem.lower(), timestamp))
|
||||
args.extend(["--log-file", log_file])
|
||||
|
||||
with open(cfg_file) as f:
|
||||
logger.debug(
|
||||
'Contents of pkispawn configuration file (%s):\n%s',
|
||||
@@ -290,10 +304,25 @@ class DogtagInstance(service.Service):
|
||||
if self.is_installed():
|
||||
self.print_msg("Unconfiguring %s" % self.subsystem)
|
||||
|
||||
args = [paths.PKIDESTROY,
|
||||
"-i", "pki-tomcat",
|
||||
"-s", self.subsystem]
|
||||
|
||||
# specify --log-file <path> on PKI 11.0.0 or later
|
||||
|
||||
pki_version = pki.util.Version(pki.specification_version())
|
||||
if pki_version >= pki.util.Version("11.0.0"):
|
||||
timestamp = time.strftime(
|
||||
"%Y%m%d%H%M%S",
|
||||
time.localtime(time.time()))
|
||||
log_file = os.path.join(
|
||||
paths.VAR_LOG_PKI_DIR,
|
||||
"pki-%s-destroy.%s.log" % (self.subsystem.lower(), timestamp))
|
||||
args.extend(["--log-file", log_file])
|
||||
|
||||
try:
|
||||
ipautil.run([paths.PKIDESTROY,
|
||||
"-i", 'pki-tomcat',
|
||||
"-s", self.subsystem])
|
||||
ipautil.run(args)
|
||||
|
||||
except ipautil.CalledProcessError as e:
|
||||
logger.critical("failed to uninstall %s instance %s",
|
||||
self.subsystem, e)
|
||||
|
||||
@@ -432,11 +432,6 @@ class ServerInstallInterface(ServerCertificateInstallInterface,
|
||||
"You cannot specify an --enable-compat option without the "
|
||||
"--setup-adtrust option")
|
||||
|
||||
if self.netbios_name:
|
||||
raise RuntimeError(
|
||||
"You cannot specify a --netbios-name option without the "
|
||||
"--setup-adtrust option")
|
||||
|
||||
if self.no_msdcs:
|
||||
raise RuntimeError(
|
||||
"You cannot specify a --no-msdcs option without the "
|
||||
|
||||
@@ -443,6 +443,7 @@ def install_check(installer):
|
||||
print(" * Configure KRA (dogtag) for secret management")
|
||||
if options.setup_dns:
|
||||
print(" * Configure DNS (bind)")
|
||||
print(" * Configure SID generation")
|
||||
if options.setup_adtrust:
|
||||
print(" * Configure Samba (smb) and winbind for managing AD trusts")
|
||||
if not options.no_pkinit:
|
||||
@@ -703,8 +704,9 @@ def install_check(installer):
|
||||
logger.debug('Starting Directory Server')
|
||||
services.knownservices.dirsrv.start(instance_name)
|
||||
|
||||
if options.setup_adtrust:
|
||||
adtrust.install_check(False, options, api)
|
||||
# Always call adtrust.install_check
|
||||
# if --setup-adtrust is not specified, only the SID part is executed
|
||||
adtrust.install_check(False, options, api)
|
||||
|
||||
# installer needs to update hosts file when DNS subsystem will be
|
||||
# installed or custom addresses are used
|
||||
@@ -966,8 +968,9 @@ def install(installer):
|
||||
if options.setup_dns:
|
||||
dns.install(False, False, options)
|
||||
|
||||
if options.setup_adtrust:
|
||||
adtrust.install(False, options, fstore, api)
|
||||
# Always call adtrust installer to configure SID generation
|
||||
# if --setup-adtrust is not specified, only the SID part is executed
|
||||
adtrust.install(False, options, fstore, api)
|
||||
|
||||
# Set the admin user kerberos password
|
||||
ds.change_admin_password(admin_password)
|
||||
|
||||
@@ -1158,8 +1158,9 @@ def promote_check(installer):
|
||||
# check addresses here, dns module is doing own check
|
||||
no_matching_interface_for_ip_address_warning(config.ips)
|
||||
|
||||
if options.setup_adtrust:
|
||||
adtrust.install_check(False, options, remote_api)
|
||||
# Always call adtrust.install_check
|
||||
# if --setup-adtrust is not specified, only the SID part is executed
|
||||
adtrust.install_check(False, options, remote_api)
|
||||
|
||||
except errors.ACIError:
|
||||
logger.debug("%s", traceback.format_exc())
|
||||
@@ -1365,8 +1366,9 @@ def install(installer):
|
||||
if options.setup_dns:
|
||||
dns.install(False, True, options, api)
|
||||
|
||||
if options.setup_adtrust:
|
||||
adtrust.install(False, options, fstore, api)
|
||||
# Always call adtrust.install
|
||||
# if --setup-adtrust is not specified, only the SID part is executed
|
||||
adtrust.install(False, options, fstore, api)
|
||||
|
||||
if options.hidden_replica:
|
||||
# Set services to hidden
|
||||
|
||||
@@ -358,6 +358,21 @@ def upgrade_adtrust_config():
|
||||
else:
|
||||
logger.warning("Error updating Samba registry: %s", e)
|
||||
|
||||
logger.info("[Change 'server role' from "
|
||||
"'CLASSIC PRIMARY DOMAIN CONTROLLER' "
|
||||
"to 'IPA PRIMARY DOMAIN CONTROLLER' in Samba configuration]")
|
||||
|
||||
args = [paths.NET, "conf", "setparm", "global",
|
||||
"server role", "IPA PRIMARY DOMAIN CONTROLLER"]
|
||||
|
||||
try:
|
||||
ipautil.run(args)
|
||||
except ipautil.CalledProcessError as e:
|
||||
# Only report an error if return code is not 255
|
||||
# which indicates that the new server role is not supported
|
||||
# and we don't need to do anything
|
||||
if e.returncode != 255:
|
||||
logger.warning("Error updating Samba registry: %s", e)
|
||||
|
||||
def ca_configure_profiles_acl(ca):
|
||||
logger.info('[Authorizing RA Agent to modify profiles]')
|
||||
@@ -1262,6 +1277,29 @@ def enable_server_snippet():
|
||||
tasks.restore_context(paths.KRB5_FREEIPA_SERVER)
|
||||
|
||||
|
||||
def setup_kpasswd_server(krb):
|
||||
logger.info("[Setup kpasswd_server]")
|
||||
aug = Augeas(
|
||||
flags=Augeas.NO_LOAD | Augeas.NO_MODL_AUTOLOAD,
|
||||
loadpath=paths.USR_SHARE_IPA_DIR,
|
||||
)
|
||||
try:
|
||||
aug.transform("IPAKrb5", paths.KRB5_CONF)
|
||||
aug.load()
|
||||
|
||||
kpass_srv_path = "/files{}/realms/{}/kpasswd_server"
|
||||
kpass_srv_path = kpass_srv_path.format(paths.KRB5_CONF, krb.realm)
|
||||
|
||||
if aug.match(kpass_srv_path):
|
||||
return
|
||||
|
||||
aug.set(kpass_srv_path, f"{krb.fqdn}:464")
|
||||
aug.save()
|
||||
|
||||
finally:
|
||||
aug.close()
|
||||
|
||||
|
||||
def ntpd_cleanup(fqdn, fstore):
|
||||
sstore = sysrestore.StateFile(paths.SYSRESTORE)
|
||||
timeconf.restore_forced_timeservices(sstore, 'ntpd')
|
||||
@@ -1871,6 +1909,7 @@ def upgrade_configuration():
|
||||
setup_spake(krb)
|
||||
setup_pkinit(krb)
|
||||
enable_server_snippet()
|
||||
setup_kpasswd_server(krb)
|
||||
|
||||
# Must be executed after certificate_renewal_update
|
||||
# (see function docstring for details)
|
||||
|
||||
@@ -17,12 +17,16 @@
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import dbus
|
||||
import dbus.mainloop.glib
|
||||
import logging
|
||||
|
||||
from ipalib import api
|
||||
from ipalib import Bool, Int, Str, IA5Str, StrEnum, DNParam
|
||||
from ipalib import Bool, Int, Str, IA5Str, StrEnum, DNParam, Flag
|
||||
from ipalib import errors
|
||||
from ipalib.constants import MAXHOSTNAMELEN
|
||||
from ipalib.plugable import Registry
|
||||
from ipalib.request import context
|
||||
from ipalib.util import validate_domain_name
|
||||
from .baseldap import (
|
||||
LDAPObject,
|
||||
@@ -30,7 +34,12 @@ from .baseldap import (
|
||||
LDAPRetrieve)
|
||||
from .selinuxusermap import validate_selinuxuser
|
||||
from ipalib import _
|
||||
from ipapython.admintool import ScriptError
|
||||
from ipapython.dn import DN
|
||||
from ipaserver.plugins.privilege import principal_has_privilege
|
||||
from ipaserver.install.adtrust import set_and_check_netbios_name
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# 389-ds attributes that should be skipped in attribute checks
|
||||
OPERATIONAL_ATTRIBUTES = ('nsaccountlock', 'member', 'memberof',
|
||||
@@ -340,6 +349,24 @@ class config(LDAPObject):
|
||||
doc=_('DNSec key master'),
|
||||
flags={'virtual_attribute', 'no_create', 'no_update'}
|
||||
),
|
||||
Flag(
|
||||
'enable_sid?',
|
||||
label=_('Setup SID configuration'),
|
||||
doc=_('New users and groups automatically get a SID assigned'),
|
||||
flags={'virtual_attribute', 'no_create'}
|
||||
),
|
||||
Flag(
|
||||
'add_sids?',
|
||||
label=_('Add SIDs'),
|
||||
doc=_('Add SIDs for existing users and groups'),
|
||||
flags={'virtual_attribute', 'no_create'}
|
||||
),
|
||||
Str(
|
||||
'netbios_name?',
|
||||
label=_('NetBIOS name of the IPA domain'),
|
||||
doc=_('NetBIOS name of the IPA domain'),
|
||||
flags={'virtual_attribute', 'no_create'}
|
||||
),
|
||||
)
|
||||
|
||||
def get_dn(self, *keys, **kwargs):
|
||||
@@ -479,6 +506,60 @@ class config(LDAPObject):
|
||||
class config_mod(LDAPUpdate):
|
||||
__doc__ = _('Modify configuration options.')
|
||||
|
||||
def _enable_sid(self, ldap, options):
|
||||
# the user must have the Replication Administrators privilege
|
||||
privilege = 'Replication Administrators'
|
||||
if not principal_has_privilege(self.api, context.principal, privilege):
|
||||
raise errors.ACIError(
|
||||
info=_("not allowed to enable SID generation"))
|
||||
|
||||
# NetBIOS name is either taken from options or generated
|
||||
try:
|
||||
netbios_name, reset_netbios_name = set_and_check_netbios_name(
|
||||
options.get('netbios_name', None), True, self.api)
|
||||
except ScriptError:
|
||||
raise errors.ValidationError(name="NetBIOS name",
|
||||
error=_('Up to 15 characters and only uppercase ASCII letters'
|
||||
', digits and dashes are allowed. Empty string is '
|
||||
'not allowed.'))
|
||||
|
||||
_ret = 0
|
||||
_stdout = ''
|
||||
_stderr = ''
|
||||
|
||||
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
|
||||
|
||||
method_options = []
|
||||
if options.get('add_sids', False):
|
||||
method_options.extend(["--add-sids"])
|
||||
method_options.extend(["--netbios-name", netbios_name])
|
||||
if reset_netbios_name:
|
||||
method_options.append("--reset-netbios-name")
|
||||
# Dbus definition expects up to 10 arguments
|
||||
method_options.extend([''] * (10 - len(method_options)))
|
||||
|
||||
try:
|
||||
bus = dbus.SystemBus()
|
||||
obj = bus.get_object('org.freeipa.server', '/',
|
||||
follow_name_owner_changes=True)
|
||||
server = dbus.Interface(obj, 'org.freeipa.server')
|
||||
_ret, _stdout, _stderr = server.config_enable_sid(*method_options)
|
||||
except dbus.DBusException as e:
|
||||
logger.error('Failed to call org.freeipa.server.config_enable_sid.'
|
||||
'DBus exception is %s', str(e))
|
||||
raise errors.ExecutionError(message=_('Failed to call DBus'))
|
||||
|
||||
# The oddjob restarts dirsrv, we need to re-establish the conn
|
||||
if self.api.Backend.ldap2.isconnected():
|
||||
self.api.Backend.ldap2.disconnect()
|
||||
self.api.Backend.ldap2.connect(ccache=context.ccache_name)
|
||||
|
||||
if _ret != 0:
|
||||
logger.error("Helper config_enable_sid return code is %d", _ret)
|
||||
raise errors.ExecutionError(
|
||||
message=_('Configuration of SID failed. '
|
||||
'See details in the error log'))
|
||||
|
||||
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
|
||||
assert isinstance(dn, DN)
|
||||
if 'ipadefaultprimarygroup' in entry_attrs:
|
||||
@@ -606,13 +687,27 @@ class config_mod(LDAPUpdate):
|
||||
|
||||
self.obj.validate_domain_resolution_order(entry_attrs)
|
||||
|
||||
# The options add_sids or netbios_name need the enable_sid option
|
||||
for sid_option in ['add_sids', 'netbios_name']:
|
||||
if options.get(sid_option, None) and not options['enable_sid']:
|
||||
opt = "--" + sid_option.replace("_", "-")
|
||||
error_message = _("You cannot specify %s without "
|
||||
"the --enable-sid option" % opt)
|
||||
raise errors.ValidationError(
|
||||
name=opt,
|
||||
error=error_message)
|
||||
|
||||
if options['enable_sid']:
|
||||
self._enable_sid(ldap, options)
|
||||
|
||||
return dn
|
||||
|
||||
def exc_callback(self, keys, options, exc, call_func,
|
||||
*call_args, **call_kwargs):
|
||||
if (isinstance(exc, errors.EmptyModlist) and
|
||||
call_func.__name__ == 'update_entry' and
|
||||
'ca_renewal_master_server' in options):
|
||||
('ca_renewal_master_server' in options or
|
||||
'enable_sid' in options)):
|
||||
return
|
||||
|
||||
super(config_mod, self).exc_callback(
|
||||
|
||||
@@ -1832,7 +1832,8 @@ class ra(rabase.rabase, RestClient):
|
||||
method='POST',
|
||||
headers={'Accept-Encoding': 'gzip, deflate',
|
||||
'User-Agent': 'IPA',
|
||||
'Content-Type': 'application/xml'},
|
||||
'Content-Type': 'application/xml',
|
||||
'Accept': 'application/xml'},
|
||||
body=payload
|
||||
)
|
||||
|
||||
|
||||
@@ -922,7 +922,8 @@ migration process might be incomplete\n''')
|
||||
# check whether the compat plugin is enabled
|
||||
if not options.get('compat'):
|
||||
try:
|
||||
ldap.get_entry(DN(('cn', 'compat'), (api.env.basedn)))
|
||||
ldap.get_entry(DN(('cn', 'users'), ('cn', 'compat'),
|
||||
(api.env.basedn)))
|
||||
return dict(result={}, failed={}, enabled=True, compat=False)
|
||||
except errors.NotFound:
|
||||
pass
|
||||
|
||||
@@ -491,7 +491,10 @@ class pwpolicy(LDAPObject):
|
||||
if minlife > maxlife:
|
||||
raise errors.ValidationError(
|
||||
name='maxlife',
|
||||
error=_('Maximum password life must be greater than minimum.'),
|
||||
error=_(
|
||||
"Maximum password life must be equal to "
|
||||
"or greater than the minimum."
|
||||
),
|
||||
)
|
||||
|
||||
def add_cospriority(self, entry, pwpolicy_name, rights=True):
|
||||
|
||||
+15
-12
@@ -20,12 +20,6 @@ from ipalib.request import context
|
||||
from ipalib.text import _
|
||||
from ipapython.version import API_VERSION
|
||||
|
||||
# Schema TTL sent to clients in response to schema call.
|
||||
# Number of seconds before client should check for schema update.
|
||||
# This should be long enough to not slow down regular work or skripts
|
||||
# but also short enough to ensure schema will be retvieved soon after
|
||||
# it was updated
|
||||
SCHEMA_TTL = 3600 # default: 1 hour
|
||||
|
||||
__doc__ = _("""
|
||||
API Schema
|
||||
@@ -129,8 +123,8 @@ class BaseMetaSearch(Search):
|
||||
"(\"%s\")") % 'name',
|
||||
)
|
||||
|
||||
def execute(self, command, criteria=None, **options):
|
||||
result = list(self.obj.search(command, criteria, **options))
|
||||
def execute(self, criteria=None, **options):
|
||||
result = list(self.obj.search(criteria, **options))
|
||||
return dict(result=result, count=len(result), truncated=False)
|
||||
|
||||
|
||||
@@ -292,6 +286,13 @@ class command_defaults(PKQuery):
|
||||
)
|
||||
|
||||
def execute(self, name, **options):
|
||||
if name not in self.api.Command:
|
||||
raise errors.NotFound(
|
||||
reason=_("{oname}: {command_name} not found").format(
|
||||
oname=self.name, command_name=name
|
||||
)
|
||||
)
|
||||
|
||||
command = self.api.Command[name]
|
||||
|
||||
params = options.get('params') or []
|
||||
@@ -494,7 +495,9 @@ class BaseParamRetrieve(BaseParamMethod, BaseMetaRetrieve):
|
||||
|
||||
|
||||
class BaseParamSearch(BaseParamMethod, BaseMetaSearch):
|
||||
pass
|
||||
def execute(self, command, criteria=None, **options):
|
||||
result = list(self.obj.search(command, criteria, **options))
|
||||
return dict(result=result, count=len(result), truncated=False)
|
||||
|
||||
|
||||
@register()
|
||||
@@ -592,7 +595,7 @@ class param(BaseParam):
|
||||
obj[key] = unicode(value)
|
||||
elif key in ('exclude',
|
||||
'include'):
|
||||
obj[key] = list(unicode(v) for v in value)
|
||||
obj[key] = sorted(list(unicode(v) for v in value))
|
||||
if isinstance(metaobj, Command):
|
||||
if key == 'alwaysask':
|
||||
obj.setdefault(key, value)
|
||||
@@ -839,14 +842,14 @@ class schema(Command):
|
||||
langs = "".join(getattr(context, "languages", []))
|
||||
|
||||
if getattr(self.api, "_schema", None) is None:
|
||||
setattr(self.api, "_schema", {})
|
||||
object.__setattr__(self.api, "_schema", {})
|
||||
|
||||
schema = self.api._schema.get(langs)
|
||||
if schema is None:
|
||||
schema = self._generate_schema(**kwargs)
|
||||
self.api._schema[langs] = schema
|
||||
|
||||
schema['ttl'] = SCHEMA_TTL
|
||||
schema['ttl'] = self.api.env.schema_ttl
|
||||
|
||||
if schema['fingerprint'] in kwargs.get('known_fingerprints', []):
|
||||
raise errors.SchemaUpToDate(
|
||||
|
||||
@@ -479,7 +479,7 @@ class server_del(LDAPDelete):
|
||||
)
|
||||
)
|
||||
else:
|
||||
raise errors.ServerRemovalError(reason=_(msg))
|
||||
raise errors.ServerRemovalError(reason=msg)
|
||||
|
||||
ipa_config = self.api.Command.config_show()['result']
|
||||
|
||||
@@ -509,7 +509,6 @@ class server_del(LDAPDelete):
|
||||
if self.api.Command.ca_is_enabled()['result']:
|
||||
try:
|
||||
roles = self.api.Command.server_role_find(
|
||||
server_server=hostname,
|
||||
role_servrole='KRA server',
|
||||
status='enabled',
|
||||
include_master=True,
|
||||
|
||||
@@ -524,6 +524,7 @@ class subid_match(subid_find):
|
||||
osubuid = options["ipasubuidnumber"]
|
||||
new_entries = []
|
||||
for entry in entries:
|
||||
self.obj.convert_owner(entry, options)
|
||||
esubuid = int(entry.single_value["ipasubuidnumber"])
|
||||
esubcount = int(entry.single_value["ipasubuidcount"])
|
||||
minsubuid = esubuid
|
||||
|
||||
@@ -659,6 +659,10 @@ class user_add(baseuser_add):
|
||||
|
||||
entry_attrs.update(newentry)
|
||||
|
||||
# delete ipantsecurityidentifier if present
|
||||
if ('ipantsecurityidentifier' in entry_attrs):
|
||||
del entry_attrs['ipantsecurityidentifier']
|
||||
|
||||
if options.get('random', False):
|
||||
try:
|
||||
entry_attrs['randompassword'] = unicode(getattr(context, 'randompassword'))
|
||||
@@ -1002,6 +1006,7 @@ class user_stage(LDAPMultiQuery):
|
||||
u'ipauniqueid', u'krbcanonicalname',
|
||||
u'sshpubkeyfp', u'krbextradata',
|
||||
u'ipacertmapdata',
|
||||
'ipantsecurityidentifier',
|
||||
u'nsaccountlock']
|
||||
|
||||
def execute(self, *keys, **options):
|
||||
|
||||
@@ -383,6 +383,8 @@ class WSGIExecutioner(Executioner):
|
||||
if self.api.env.debug:
|
||||
time_start = time.perf_counter_ns()
|
||||
try:
|
||||
if 'KRB5CCNAME' in environ:
|
||||
setattr(context, "ccache_name", environ['KRB5CCNAME'])
|
||||
if ('HTTP_ACCEPT_LANGUAGE' in environ):
|
||||
lang_reg_w_q = environ['HTTP_ACCEPT_LANGUAGE'].split(',')[0]
|
||||
lang_reg = lang_reg_w_q.split(';')[0]
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"__defaultAction": "Change defaultAction to SCMP_ACT_LOG and then check Host's journal for SECCOMP",
|
||||
"defaultAction": "SCMP_ACT_ERRNO",
|
||||
"defaultAction": "SCMP_ACT_ERRNO",
|
||||
"defaultErrnoRet": 38,
|
||||
"archMap": [
|
||||
{
|
||||
"architecture": "SCMP_ARCH_X86_64",
|
||||
@@ -53,6 +54,46 @@
|
||||
"syscalls": [
|
||||
{
|
||||
"names": [
|
||||
"bdflush",
|
||||
"io_pgetevents",
|
||||
"kexec_file_load",
|
||||
"kexec_load",
|
||||
"migrate_pages",
|
||||
"move_pages",
|
||||
"nfsservctl",
|
||||
"nice",
|
||||
"oldfstat",
|
||||
"oldlstat",
|
||||
"oldolduname",
|
||||
"oldstat",
|
||||
"olduname",
|
||||
"pciconfig_iobase",
|
||||
"pciconfig_read",
|
||||
"pciconfig_write",
|
||||
"sgetmask",
|
||||
"ssetmask",
|
||||
"swapcontext",
|
||||
"swapoff",
|
||||
"swapon",
|
||||
"sysfs",
|
||||
"uselib",
|
||||
"userfaultfd",
|
||||
"ustat",
|
||||
"vm86",
|
||||
"vm86old",
|
||||
"vmsplice"
|
||||
],
|
||||
"action": "SCMP_ACT_ERRNO",
|
||||
"args": [],
|
||||
"comment": "",
|
||||
"includes": {},
|
||||
"excludes": {},
|
||||
"errnoRet": 1
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"_llseek",
|
||||
"_newselect",
|
||||
"accept",
|
||||
"accept4",
|
||||
"access",
|
||||
@@ -67,10 +108,17 @@
|
||||
"chown",
|
||||
"chown32",
|
||||
"clock_adjtime",
|
||||
"clock_adjtime64",
|
||||
"clock_getres",
|
||||
"clock_getres_time64",
|
||||
"clock_gettime",
|
||||
"clock_gettime64",
|
||||
"clock_nanosleep",
|
||||
"clock_nanosleep_time64",
|
||||
"clone",
|
||||
"clone3",
|
||||
"close",
|
||||
"close_range",
|
||||
"connect",
|
||||
"copy_file_range",
|
||||
"creat",
|
||||
@@ -82,6 +130,7 @@
|
||||
"epoll_ctl",
|
||||
"epoll_ctl_old",
|
||||
"epoll_pwait",
|
||||
"epoll_pwait2",
|
||||
"epoll_wait",
|
||||
"epoll_wait_old",
|
||||
"eventfd",
|
||||
@@ -110,7 +159,11 @@
|
||||
"flock",
|
||||
"fork",
|
||||
"fremovexattr",
|
||||
"fsconfig",
|
||||
"fsetxattr",
|
||||
"fsmount",
|
||||
"fsopen",
|
||||
"fspick",
|
||||
"fstat",
|
||||
"fstat64",
|
||||
"fstatat64",
|
||||
@@ -120,7 +173,10 @@
|
||||
"ftruncate",
|
||||
"ftruncate64",
|
||||
"futex",
|
||||
"futex_time64",
|
||||
"futimesat",
|
||||
"get_robust_list",
|
||||
"get_thread_area",
|
||||
"getcpu",
|
||||
"getcwd",
|
||||
"getdents",
|
||||
@@ -134,6 +190,7 @@
|
||||
"getgroups",
|
||||
"getgroups32",
|
||||
"getitimer",
|
||||
"get_mempolicy",
|
||||
"getpeername",
|
||||
"getpgid",
|
||||
"getpgrp",
|
||||
@@ -146,12 +203,10 @@
|
||||
"getresuid",
|
||||
"getresuid32",
|
||||
"getrlimit",
|
||||
"get_robust_list",
|
||||
"getrusage",
|
||||
"getsid",
|
||||
"getsockname",
|
||||
"getsockopt",
|
||||
"get_thread_area",
|
||||
"gettid",
|
||||
"gettimeofday",
|
||||
"getuid",
|
||||
@@ -162,14 +217,15 @@
|
||||
"inotify_init1",
|
||||
"inotify_rm_watch",
|
||||
"io_cancel",
|
||||
"ioctl",
|
||||
"io_destroy",
|
||||
"io_getevents",
|
||||
"ioprio_get",
|
||||
"ioprio_set",
|
||||
"io_setup",
|
||||
"io_submit",
|
||||
"ioctl",
|
||||
"ioprio_get",
|
||||
"ioprio_set",
|
||||
"ipc",
|
||||
"keyctl",
|
||||
"kill",
|
||||
"lchown",
|
||||
"lchown32",
|
||||
@@ -179,14 +235,15 @@
|
||||
"listen",
|
||||
"listxattr",
|
||||
"llistxattr",
|
||||
"_llseek",
|
||||
"lremovexattr",
|
||||
"lseek",
|
||||
"lsetxattr",
|
||||
"lstat",
|
||||
"lstat64",
|
||||
"madvise",
|
||||
"mbind",
|
||||
"memfd_create",
|
||||
"memfd_secret",
|
||||
"mincore",
|
||||
"mkdir",
|
||||
"mkdirat",
|
||||
@@ -197,12 +254,16 @@
|
||||
"mlockall",
|
||||
"mmap",
|
||||
"mmap2",
|
||||
"mount",
|
||||
"move_mount",
|
||||
"mprotect",
|
||||
"mq_getsetattr",
|
||||
"mq_notify",
|
||||
"mq_open",
|
||||
"mq_timedreceive",
|
||||
"mq_timedreceive_time64",
|
||||
"mq_timedsend",
|
||||
"mq_timedsend_time64",
|
||||
"mq_unlink",
|
||||
"mremap",
|
||||
"msgctl",
|
||||
@@ -213,33 +274,47 @@
|
||||
"munlock",
|
||||
"munlockall",
|
||||
"munmap",
|
||||
"name_to_handle_at",
|
||||
"nanosleep",
|
||||
"newfstatat",
|
||||
"_newselect",
|
||||
"open",
|
||||
"openat",
|
||||
"openat2",
|
||||
"open_tree",
|
||||
"pause",
|
||||
"pidfd_getfd",
|
||||
"pidfd_open",
|
||||
"pidfd_send_signal",
|
||||
"pipe",
|
||||
"pipe2",
|
||||
"pivot_root",
|
||||
"pkey_alloc",
|
||||
"pkey_free",
|
||||
"pkey_mprotect",
|
||||
"poll",
|
||||
"ppoll",
|
||||
"ppoll_time64",
|
||||
"prctl",
|
||||
"pread64",
|
||||
"preadv",
|
||||
"preadv2",
|
||||
"prlimit64",
|
||||
"pselect6",
|
||||
"pselect6_time64",
|
||||
"pwrite64",
|
||||
"pwritev",
|
||||
"pwritev2",
|
||||
"read",
|
||||
"readahead",
|
||||
"readdir",
|
||||
"readlink",
|
||||
"readlinkat",
|
||||
"readv",
|
||||
"reboot",
|
||||
"recv",
|
||||
"recvfrom",
|
||||
"recvmmsg",
|
||||
"recvmmsg_time64",
|
||||
"recvmsg",
|
||||
"remap_file_pages",
|
||||
"removexattr",
|
||||
@@ -248,6 +323,7 @@
|
||||
"renameat2",
|
||||
"restart_syscall",
|
||||
"rmdir",
|
||||
"rseq",
|
||||
"rt_sigaction",
|
||||
"rt_sigpending",
|
||||
"rt_sigprocmask",
|
||||
@@ -255,14 +331,16 @@
|
||||
"rt_sigreturn",
|
||||
"rt_sigsuspend",
|
||||
"rt_sigtimedwait",
|
||||
"rt_sigtimedwait_time64",
|
||||
"rt_tgsigqueueinfo",
|
||||
"sched_get_priority_max",
|
||||
"sched_get_priority_min",
|
||||
"sched_getaffinity",
|
||||
"sched_getattr",
|
||||
"sched_getparam",
|
||||
"sched_get_priority_max",
|
||||
"sched_get_priority_min",
|
||||
"sched_getscheduler",
|
||||
"sched_rr_get_interval",
|
||||
"sched_rr_get_interval_time64",
|
||||
"sched_setaffinity",
|
||||
"sched_setattr",
|
||||
"sched_setparam",
|
||||
@@ -274,12 +352,18 @@
|
||||
"semget",
|
||||
"semop",
|
||||
"semtimedop",
|
||||
"semtimedop_time64",
|
||||
"send",
|
||||
"sendfile",
|
||||
"sendfile64",
|
||||
"sendmmsg",
|
||||
"sendmsg",
|
||||
"sendto",
|
||||
"setns",
|
||||
"set_mempolicy",
|
||||
"set_robust_list",
|
||||
"set_thread_area",
|
||||
"set_tid_address",
|
||||
"setfsgid",
|
||||
"setfsgid32",
|
||||
"setfsuid",
|
||||
@@ -300,11 +384,8 @@
|
||||
"setreuid",
|
||||
"setreuid32",
|
||||
"setrlimit",
|
||||
"set_robust_list",
|
||||
"setsid",
|
||||
"setsockopt",
|
||||
"set_thread_area",
|
||||
"set_tid_address",
|
||||
"setuid",
|
||||
"setuid32",
|
||||
"setxattr",
|
||||
@@ -317,7 +398,6 @@
|
||||
"signalfd",
|
||||
"signalfd4",
|
||||
"sigreturn",
|
||||
"socket",
|
||||
"socketcall",
|
||||
"socketpair",
|
||||
"splice",
|
||||
@@ -332,41 +412,44 @@
|
||||
"sync_file_range",
|
||||
"syncfs",
|
||||
"sysinfo",
|
||||
"syslog",
|
||||
"tee",
|
||||
"tgkill",
|
||||
"time",
|
||||
"timer_create",
|
||||
"timer_delete",
|
||||
"timerfd_create",
|
||||
"timerfd_gettime",
|
||||
"timerfd_settime",
|
||||
"timer_getoverrun",
|
||||
"timer_gettime",
|
||||
"timer_gettime64",
|
||||
"timer_settime",
|
||||
"timer_settime64",
|
||||
"timerfd_create",
|
||||
"timerfd_gettime",
|
||||
"timerfd_gettime64",
|
||||
"timerfd_settime",
|
||||
"timerfd_settime64",
|
||||
"times",
|
||||
"tkill",
|
||||
"truncate",
|
||||
"truncate64",
|
||||
"ugetrlimit",
|
||||
"umask",
|
||||
"umount",
|
||||
"umount2",
|
||||
"uname",
|
||||
"unlink",
|
||||
"unlinkat",
|
||||
"unshare",
|
||||
"utime",
|
||||
"utimensat",
|
||||
"utimensat_time64",
|
||||
"utimes",
|
||||
"vfork",
|
||||
"vmsplice",
|
||||
"wait4",
|
||||
"waitid",
|
||||
"waitpid",
|
||||
"write",
|
||||
"writev",
|
||||
"mount",
|
||||
"umount2",
|
||||
"reboot",
|
||||
"name_to_handle_at",
|
||||
"unshare"
|
||||
"writev"
|
||||
],
|
||||
"action": "SCMP_ACT_ALLOW",
|
||||
"args": [],
|
||||
@@ -555,23 +638,31 @@
|
||||
},
|
||||
"excludes": {}
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"open_by_handle_at"
|
||||
],
|
||||
"action": "SCMP_ACT_ERRNO",
|
||||
"args": [],
|
||||
"comment": "",
|
||||
"includes": {},
|
||||
"excludes": {
|
||||
"caps": [
|
||||
"CAP_DAC_READ_SEARCH"
|
||||
]
|
||||
},
|
||||
"errnoRet": 1
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"bpf",
|
||||
"clone",
|
||||
"fanotify_init",
|
||||
"lookup_dcookie",
|
||||
"mount",
|
||||
"name_to_handle_at",
|
||||
"perf_event_open",
|
||||
"quotactl",
|
||||
"setdomainname",
|
||||
"sethostname",
|
||||
"setns",
|
||||
"syslog",
|
||||
"umount",
|
||||
"umount2",
|
||||
"unshare"
|
||||
"setns"
|
||||
],
|
||||
"action": "SCMP_ACT_ALLOW",
|
||||
"args": [],
|
||||
@@ -585,68 +676,25 @@
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"clone"
|
||||
],
|
||||
"action": "SCMP_ACT_ALLOW",
|
||||
"args": [
|
||||
{
|
||||
"index": 0,
|
||||
"value": 2080505856,
|
||||
"valueTwo": 0,
|
||||
"op": "SCMP_CMP_MASKED_EQ"
|
||||
}
|
||||
"bpf",
|
||||
"fanotify_init",
|
||||
"lookup_dcookie",
|
||||
"perf_event_open",
|
||||
"quotactl",
|
||||
"setdomainname",
|
||||
"sethostname",
|
||||
"setns"
|
||||
],
|
||||
"action": "SCMP_ACT_ERRNO",
|
||||
"args": [],
|
||||
"comment": "",
|
||||
"includes": {},
|
||||
"excludes": {
|
||||
"caps": [
|
||||
"CAP_SYS_ADMIN"
|
||||
],
|
||||
"arches": [
|
||||
"s390",
|
||||
"s390x"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"clone"
|
||||
],
|
||||
"action": "SCMP_ACT_ALLOW",
|
||||
"args": [
|
||||
{
|
||||
"index": 1,
|
||||
"value": 2080505856,
|
||||
"valueTwo": 0,
|
||||
"op": "SCMP_CMP_MASKED_EQ"
|
||||
}
|
||||
],
|
||||
"comment": "s390 parameter ordering for clone is different",
|
||||
"includes": {
|
||||
"arches": [
|
||||
"s390",
|
||||
"s390x"
|
||||
]
|
||||
},
|
||||
"excludes": {
|
||||
"caps": [
|
||||
"CAP_SYS_ADMIN"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"reboot"
|
||||
],
|
||||
"action": "SCMP_ACT_ALLOW",
|
||||
"args": [],
|
||||
"comment": "",
|
||||
"includes": {
|
||||
"caps": [
|
||||
"CAP_SYS_BOOT"
|
||||
]
|
||||
},
|
||||
"excludes": {}
|
||||
"errnoRet": 1
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
@@ -662,6 +710,21 @@
|
||||
},
|
||||
"excludes": {}
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"chroot"
|
||||
],
|
||||
"action": "SCMP_ACT_ERRNO",
|
||||
"args": [],
|
||||
"comment": "",
|
||||
"includes": {},
|
||||
"excludes": {
|
||||
"caps": [
|
||||
"CAP_SYS_CHROOT"
|
||||
]
|
||||
},
|
||||
"errnoRet": 1
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"delete_module",
|
||||
@@ -679,6 +742,24 @@
|
||||
},
|
||||
"excludes": {}
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"delete_module",
|
||||
"init_module",
|
||||
"finit_module",
|
||||
"query_module"
|
||||
],
|
||||
"action": "SCMP_ACT_ERRNO",
|
||||
"args": [],
|
||||
"comment": "",
|
||||
"includes": {},
|
||||
"excludes": {
|
||||
"caps": [
|
||||
"CAP_SYS_MODULE"
|
||||
]
|
||||
},
|
||||
"errnoRet": 1
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"acct"
|
||||
@@ -693,9 +774,25 @@
|
||||
},
|
||||
"excludes": {}
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"acct"
|
||||
],
|
||||
"action": "SCMP_ACT_ERRNO",
|
||||
"args": [],
|
||||
"comment": "",
|
||||
"includes": {},
|
||||
"excludes": {
|
||||
"caps": [
|
||||
"CAP_SYS_PACCT"
|
||||
]
|
||||
},
|
||||
"errnoRet": 1
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"kcmp",
|
||||
"process_madvise",
|
||||
"process_vm_readv",
|
||||
"process_vm_writev",
|
||||
"ptrace"
|
||||
@@ -710,6 +807,25 @@
|
||||
},
|
||||
"excludes": {}
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"kcmp",
|
||||
"process_madvise",
|
||||
"process_vm_readv",
|
||||
"process_vm_writev",
|
||||
"ptrace"
|
||||
],
|
||||
"action": "SCMP_ACT_ERRNO",
|
||||
"args": [],
|
||||
"comment": "",
|
||||
"includes": {},
|
||||
"excludes": {
|
||||
"caps": [
|
||||
"CAP_SYS_PTRACE"
|
||||
]
|
||||
},
|
||||
"errnoRet": 1
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"iopl",
|
||||
@@ -725,11 +841,28 @@
|
||||
},
|
||||
"excludes": {}
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"iopl",
|
||||
"ioperm"
|
||||
],
|
||||
"action": "SCMP_ACT_ERRNO",
|
||||
"args": [],
|
||||
"comment": "",
|
||||
"includes": {},
|
||||
"excludes": {
|
||||
"caps": [
|
||||
"CAP_SYS_RAWIO"
|
||||
]
|
||||
},
|
||||
"errnoRet": 1
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"settimeofday",
|
||||
"stime",
|
||||
"clock_settime"
|
||||
"clock_settime",
|
||||
"clock_settime64"
|
||||
],
|
||||
"action": "SCMP_ACT_ALLOW",
|
||||
"args": [],
|
||||
@@ -741,6 +874,24 @@
|
||||
},
|
||||
"excludes": {}
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"settimeofday",
|
||||
"stime",
|
||||
"clock_settime",
|
||||
"clock_settime64"
|
||||
],
|
||||
"action": "SCMP_ACT_ERRNO",
|
||||
"args": [],
|
||||
"comment": "",
|
||||
"includes": {},
|
||||
"excludes": {
|
||||
"caps": [
|
||||
"CAP_SYS_TIME"
|
||||
]
|
||||
},
|
||||
"errnoRet": 1
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"vhangup"
|
||||
@@ -757,30 +908,120 @@
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"get_mempolicy",
|
||||
"mbind",
|
||||
"set_mempolicy"
|
||||
"vhangup"
|
||||
],
|
||||
"action": "SCMP_ACT_ALLOW",
|
||||
"action": "SCMP_ACT_ERRNO",
|
||||
"args": [],
|
||||
"comment": "",
|
||||
"includes": {
|
||||
"includes": {},
|
||||
"excludes": {
|
||||
"caps": [
|
||||
"CAP_SYS_NICE"
|
||||
"CAP_SYS_TTY_CONFIG"
|
||||
]
|
||||
},
|
||||
"excludes": {}
|
||||
"errnoRet": 1
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"syslog"
|
||||
"socket"
|
||||
],
|
||||
"action": "SCMP_ACT_ERRNO",
|
||||
"args": [
|
||||
{
|
||||
"index": 0,
|
||||
"value": 16,
|
||||
"valueTwo": 0,
|
||||
"op": "SCMP_CMP_EQ"
|
||||
},
|
||||
{
|
||||
"index": 2,
|
||||
"value": 9,
|
||||
"valueTwo": 0,
|
||||
"op": "SCMP_CMP_EQ"
|
||||
}
|
||||
],
|
||||
"comment": "",
|
||||
"includes": {},
|
||||
"excludes": {
|
||||
"caps": [
|
||||
"CAP_AUDIT_WRITE"
|
||||
]
|
||||
},
|
||||
"errnoRet": 22
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"socket"
|
||||
],
|
||||
"action": "SCMP_ACT_ALLOW",
|
||||
"args": [],
|
||||
"args": [
|
||||
{
|
||||
"index": 2,
|
||||
"value": 9,
|
||||
"valueTwo": 0,
|
||||
"op": "SCMP_CMP_NE"
|
||||
}
|
||||
],
|
||||
"comment": "",
|
||||
"includes": {},
|
||||
"excludes": {
|
||||
"caps": [
|
||||
"CAP_AUDIT_WRITE"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"socket"
|
||||
],
|
||||
"action": "SCMP_ACT_ALLOW",
|
||||
"args": [
|
||||
{
|
||||
"index": 0,
|
||||
"value": 16,
|
||||
"valueTwo": 0,
|
||||
"op": "SCMP_CMP_NE"
|
||||
}
|
||||
],
|
||||
"comment": "",
|
||||
"includes": {},
|
||||
"excludes": {
|
||||
"caps": [
|
||||
"CAP_AUDIT_WRITE"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"socket"
|
||||
],
|
||||
"action": "SCMP_ACT_ALLOW",
|
||||
"args": [
|
||||
{
|
||||
"index": 2,
|
||||
"value": 9,
|
||||
"valueTwo": 0,
|
||||
"op": "SCMP_CMP_NE"
|
||||
}
|
||||
],
|
||||
"comment": "",
|
||||
"includes": {},
|
||||
"excludes": {
|
||||
"caps": [
|
||||
"CAP_AUDIT_WRITE"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"socket"
|
||||
],
|
||||
"action": "SCMP_ACT_ALLOW",
|
||||
"args": null,
|
||||
"comment": "",
|
||||
"includes": {
|
||||
"caps": [
|
||||
"CAP_SYSLOG"
|
||||
"CAP_AUDIT_WRITE"
|
||||
]
|
||||
},
|
||||
"excludes": {}
|
||||
|
||||
@@ -20,12 +20,6 @@ jobs:
|
||||
steps:
|
||||
- template: templates/${{ variables.PREPARE_BUILD_TEMPLATE }}
|
||||
- template: templates/${{ variables.AUTOCONF_TEMPLATE }}
|
||||
- script: |
|
||||
set -e
|
||||
git update-ref refs/heads/$(System.PullRequest.TargetBranch) origin/$(System.PullRequest.TargetBranch)
|
||||
make V=0 "GIT_BRANCH=$(System.PullRequest.TargetBranch)" fastlint
|
||||
displayName: Quick code style check
|
||||
condition: eq(variables['Build.Reason'], 'PullRequest')
|
||||
- template: templates/${{ variables.BUILD_TEMPLATE }}
|
||||
- template: templates/publish-build.yml
|
||||
parameters:
|
||||
@@ -75,6 +69,12 @@ jobs:
|
||||
echo "Running make target 'lint'"
|
||||
make V=0 lint
|
||||
displayName: Lint sources
|
||||
- script: |
|
||||
set -e
|
||||
git update-ref refs/heads/$(System.PullRequest.TargetBranch) origin/$(System.PullRequest.TargetBranch)
|
||||
make V=0 "GIT_BRANCH=$(System.PullRequest.TargetBranch)" fastcodestyle
|
||||
displayName: Quick code style check
|
||||
condition: eq(variables['Build.Reason'], 'PullRequest')
|
||||
|
||||
- job: Docs
|
||||
pool:
|
||||
@@ -144,7 +144,9 @@ jobs:
|
||||
- job: BASE_XMLRPC
|
||||
pool:
|
||||
vmImage: $(VM_IMAGE)
|
||||
dependsOn: Build
|
||||
dependsOn:
|
||||
- Build
|
||||
- Lint
|
||||
variables:
|
||||
IPA_IMAGE_ARTIFACT: $[ dependencies.Build.outputs['artifacts_image.image'] ]
|
||||
IPA_PACKAGES_ARTIFACT: $[ dependencies.Build.outputs['artifacts_packages.packages'] ]
|
||||
@@ -158,7 +160,9 @@ jobs:
|
||||
- job: GATING
|
||||
pool:
|
||||
vmImage: $(VM_IMAGE)
|
||||
dependsOn: Build
|
||||
dependsOn:
|
||||
- Build
|
||||
- Lint
|
||||
variables:
|
||||
IPA_IMAGE_ARTIFACT: $[ dependencies.Build.outputs['artifacts_image.image'] ]
|
||||
IPA_PACKAGES_ARTIFACT: $[ dependencies.Build.outputs['artifacts_packages.packages'] ]
|
||||
|
||||
@@ -22,7 +22,8 @@ function collect_logs() {
|
||||
/var/log/pki \
|
||||
/var/log/samba \
|
||||
"$BIND_DATADIR" \
|
||||
systemd_journal.log
|
||||
systemd_journal.log \
|
||||
||:
|
||||
}
|
||||
|
||||
server_password=Secret123
|
||||
@@ -95,6 +96,8 @@ if [ "$install_result" -eq 0 ] ; then
|
||||
else
|
||||
echo "ipa-server-install failed with code ${install_result}, skip IPA tests"
|
||||
fi
|
||||
# let the services gracefully flush their logs
|
||||
ipactl stop ||:
|
||||
collect_logs ipaserver_install_logs.tar.gz
|
||||
|
||||
echo "Potential Python 3 incompatibilities in the IPA framework:"
|
||||
|
||||
@@ -30,8 +30,8 @@ jobs:
|
||||
git_repo: '{git_repo}'
|
||||
git_refspec: '{git_refspec}'
|
||||
template: &ci-ipa-4-9-latest
|
||||
name: freeipa/ci-ipa-4-9-f34
|
||||
version: 0.0.3
|
||||
name: freeipa/ci-ipa-4-9-f35
|
||||
version: 0.0.1
|
||||
timeout: 1800
|
||||
topology: *build
|
||||
|
||||
|
||||
@@ -50,8 +50,8 @@ jobs:
|
||||
git_repo: '{git_repo}'
|
||||
git_refspec: '{git_refspec}'
|
||||
template: &ci-ipa-4-9-latest
|
||||
name: freeipa/ci-ipa-4-9-f34
|
||||
version: 0.0.3
|
||||
name: freeipa/ci-ipa-4-9-f35
|
||||
version: 0.0.1
|
||||
timeout: 1800
|
||||
topology: *build
|
||||
|
||||
@@ -1699,7 +1699,7 @@ jobs:
|
||||
build_url: '{fedora-latest-ipa-4-9/build_url}'
|
||||
test_suite: test_integration/test_ipa_cert_fix.py
|
||||
template: *ci-ipa-4-9-latest
|
||||
timeout: 7200
|
||||
timeout: 10800
|
||||
topology: *master_1repl
|
||||
|
||||
fedora-latest-ipa-4-9/test_subids:
|
||||
|
||||
@@ -50,8 +50,8 @@ jobs:
|
||||
git_repo: '{git_repo}'
|
||||
git_refspec: '{git_refspec}'
|
||||
template: &ci-ipa-4-9-latest
|
||||
name: freeipa/ci-ipa-4-9-f34
|
||||
version: 0.0.3
|
||||
name: freeipa/ci-ipa-4-9-f35
|
||||
version: 0.0.1
|
||||
timeout: 1800
|
||||
topology: *build
|
||||
|
||||
@@ -1821,7 +1821,7 @@ jobs:
|
||||
selinux_enforcing: True
|
||||
test_suite: test_integration/test_ipa_cert_fix.py
|
||||
template: *ci-ipa-4-9-latest
|
||||
timeout: 7200
|
||||
timeout: 10800
|
||||
topology: *master_1repl
|
||||
|
||||
fedora-latest-ipa-4-9/test_subids:
|
||||
|
||||
@@ -50,8 +50,8 @@ jobs:
|
||||
git_repo: '{git_repo}'
|
||||
git_refspec: '{git_refspec}'
|
||||
template: &ci-ipa-4-9-previous
|
||||
name: freeipa/ci-ipa-4-9-f33
|
||||
version: 0.0.7
|
||||
name: freeipa/ci-ipa-4-9-f34
|
||||
version: 0.0.4
|
||||
timeout: 1800
|
||||
topology: *build
|
||||
|
||||
@@ -1699,7 +1699,7 @@ jobs:
|
||||
build_url: '{fedora-previous-ipa-4-9/build_url}'
|
||||
test_suite: test_integration/test_ipa_cert_fix.py
|
||||
template: *ci-ipa-4-9-previous
|
||||
timeout: 7200
|
||||
timeout: 10800
|
||||
topology: *master_1repl
|
||||
|
||||
fedora-previous-ipa-4-9/test_subids:
|
||||
|
||||
@@ -56,8 +56,8 @@ jobs:
|
||||
git_repo: '{git_repo}'
|
||||
git_refspec: '{git_refspec}'
|
||||
template: &ci-ipa-4-9-latest
|
||||
name: freeipa/ci-ipa-4-9-f34
|
||||
version: 0.0.3
|
||||
name: freeipa/ci-ipa-4-9-f35
|
||||
version: 0.0.1
|
||||
timeout: 1800
|
||||
topology: *build
|
||||
|
||||
|
||||
@@ -764,7 +764,13 @@ def remove_trust_info_from_ad(master, ad_domain, ad_hostname):
|
||||
kinit_as_user(master,
|
||||
'Administrator@{}'.format(ad_domain.upper()),
|
||||
master.config.ad_admin_password)
|
||||
master.run_command(['rpcclient', '-k', ad_hostname,
|
||||
# Detect whether rpcclient supports -k or --use-kerberos option
|
||||
res = master.run_command(['rpcclient', '-h'], raiseonerr=False)
|
||||
if "--use-kerberos" in res.stderr_text:
|
||||
rpcclient_krb5_knob = "--use-kerberos=desired"
|
||||
else:
|
||||
rpcclient_krb5_knob = "-k"
|
||||
master.run_command(['rpcclient', rpcclient_krb5_knob, ad_hostname,
|
||||
'-c', 'deletetrustdom {}'.format(master.domain.name)],
|
||||
raiseonerr=False)
|
||||
|
||||
@@ -2093,13 +2099,15 @@ def ldapsearch_dm(host, base, ldap_args, scope='sub', **kwargs):
|
||||
return host.run_command(args, **kwargs)
|
||||
|
||||
|
||||
def create_temp_file(host, directory=None, create_file=True):
|
||||
"""Creates temporary file using mktemp."""
|
||||
def create_temp_file(host, directory=None, suffix=None, create_file=True):
|
||||
"""Creates temporary file using mktemp. See `man 1 mktemp`."""
|
||||
cmd = ['mktemp']
|
||||
if create_file is False:
|
||||
cmd += ['--dry-run']
|
||||
if directory is not None:
|
||||
cmd += ['-p', directory]
|
||||
if suffix is not None:
|
||||
cmd.extend(["--suffix", suffix])
|
||||
return host.run_command(cmd).stdout_text.strip()
|
||||
|
||||
|
||||
@@ -2121,7 +2129,7 @@ def create_active_user(host, login, password, first='test', last='user',
|
||||
# Note raiseonerr=False:
|
||||
# the assert is located after kdcinfo retrieval.
|
||||
result = host.run_command(
|
||||
"KRB5_TRACE=/dev/stdout kinit %s" % login,
|
||||
f"KRB5_TRACE=/dev/stdout SSSD_KRB5_LOCATOR_DEBUG=1 kinit {login}",
|
||||
stdin_text='{0}\n{1}\n{1}\n'.format(
|
||||
temp_password, password
|
||||
), raiseonerr=False
|
||||
@@ -2158,8 +2166,8 @@ def run_command_as_user(host, user, command, *args, **kwargs):
|
||||
|
||||
def kinit_as_user(host, user, password, krb5_trace=False, raiseonerr=True):
|
||||
"""Launch kinit as user on host.
|
||||
If krb5_trace, then set KRB5_TRACE=/dev/stdout and collect
|
||||
/var/lib/sss/pubconf/kdcinfo.$REALM
|
||||
If krb5_trace, then set KRB5_TRACE=/dev/stdout, SSSD_KRB5_LOCATOR_DEBUG=1
|
||||
and collect /var/lib/sss/pubconf/kdcinfo.$REALM
|
||||
as this file contains the list of KRB5KDC IPs SSSD uses.
|
||||
https://pagure.io/freeipa/issue/8510
|
||||
"""
|
||||
@@ -2175,7 +2183,7 @@ def kinit_as_user(host, user, password, krb5_trace=False, raiseonerr=True):
|
||||
# Note raiseonerr=False:
|
||||
# the assert is located after kdcinfo retrieval.
|
||||
result = host.run_command(
|
||||
"KRB5_TRACE=/dev/stdout kinit %s" % user,
|
||||
f"KRB5_TRACE=/dev/stdout SSSD_KRB5_LOCATOR_DEBUG=1 kinit {user}",
|
||||
stdin_text='{0}\n'.format(password),
|
||||
raiseonerr=False
|
||||
)
|
||||
@@ -2761,8 +2769,11 @@ def run_ssh_cmd(
|
||||
|
||||
if auth_method == "password":
|
||||
if expect_auth_success is True:
|
||||
assert "Authentication succeeded (keyboard-interactive)" in \
|
||||
stderr
|
||||
patterns = [
|
||||
r'Authenticated to .* using "keyboard-interactive"',
|
||||
r'Authentication succeeded \(keyboard-interactive\)'
|
||||
]
|
||||
assert any(re.search(pattern, stderr) for pattern in patterns)
|
||||
# do not assert the return code:
|
||||
# it can be >0 if the command failed.
|
||||
elif expect_auth_failure is True:
|
||||
@@ -2771,7 +2782,11 @@ def run_ssh_cmd(
|
||||
assert "Authentication succeeded" not in stderr
|
||||
elif auth_method == "key":
|
||||
if expect_auth_success is True:
|
||||
assert "Authentication succeeded (publickey)" in stderr
|
||||
patterns = [
|
||||
r'Authenticated to .* using "publickey"',
|
||||
r'Authentication succeeded \(publickey\)'
|
||||
]
|
||||
assert any(re.search(pattern, stderr) for pattern in patterns)
|
||||
# do not assert the return code:
|
||||
# it can be >0 if the command failed.
|
||||
elif expect_auth_failure is True:
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
#
|
||||
# Copyright (C) 2021 FreeIPA Contributors see COPYING for license
|
||||
#
|
||||
import pytest
|
||||
import time
|
||||
|
||||
from ipaclient.remote_plugins import ServerInfo
|
||||
|
||||
|
||||
class TestServerInfo(ServerInfo):
|
||||
"""Simplified ServerInfo class with hardcoded values"""
|
||||
def __init__(self, fingerprint='deadbeef', hostname='ipa.example.test',
|
||||
force_check=False, language='en_US',
|
||||
version='2.0', expiration=None):
|
||||
self._force_check = force_check
|
||||
self._language = language
|
||||
self._now = time.time()
|
||||
self._dict = {
|
||||
'fingerprint': fingerprint,
|
||||
'expiration': expiration or time.time() + 3600,
|
||||
'language': language,
|
||||
'version': version,
|
||||
}
|
||||
|
||||
def _read(self):
|
||||
"""Running on test controller, this is a no-op"""
|
||||
|
||||
def _write(self):
|
||||
"""Running on test controller, this is a no-op"""
|
||||
|
||||
|
||||
@pytest.mark.tier0
|
||||
class TestIPAServerInfo:
|
||||
"""Test that ServerInfo detects changes in remote configuration"""
|
||||
|
||||
def test_valid(self):
|
||||
server_info = TestServerInfo()
|
||||
assert server_info.is_valid() is True
|
||||
|
||||
def test_force_check(self):
|
||||
server_info = TestServerInfo(force_check=True)
|
||||
assert server_info.is_valid() is False
|
||||
|
||||
def test_language_change(self):
|
||||
server_info = TestServerInfo()
|
||||
assert server_info.is_valid() is True
|
||||
server_info._language = 'fr_FR'
|
||||
assert server_info.is_valid() is False
|
||||
server_info._language = 'en_US'
|
||||
|
||||
def test_expired(self):
|
||||
server_info = TestServerInfo(expiration=time.time() + 2)
|
||||
assert server_info.is_valid() is True
|
||||
|
||||
# skip past the expiration time
|
||||
server_info._now = time.time() + 5
|
||||
assert server_info.is_valid() is False
|
||||
|
||||
# set a new expiration time in the future
|
||||
server_info.update_validity(10)
|
||||
assert server_info.is_valid() is True
|
||||
|
||||
# move to the future beyond expiration
|
||||
server_info._now = time.time() + 15
|
||||
assert server_info.is_valid() is False
|
||||
|
||||
def test_update_validity(self):
|
||||
server_info = TestServerInfo(expiration=time.time() + 1)
|
||||
|
||||
# Expiration and time are one second off so the cache is ok
|
||||
assert server_info.is_valid() is True
|
||||
|
||||
# Simulate time passing by
|
||||
server_info._now = time.time() + 2
|
||||
|
||||
# the validity should be updated because it is now expired
|
||||
server_info.update_validity(3600)
|
||||
|
||||
# the cache is now valid for another hour
|
||||
assert server_info.is_valid() is True
|
||||
@@ -585,7 +585,7 @@ class TestACMERenew(IntegrationTest):
|
||||
# Note raiseonerr=False:
|
||||
# the assert is located after kdcinfo retrieval.
|
||||
result = host.run_command(
|
||||
"KRB5_TRACE=/dev/stdout kinit %s" % 'admin',
|
||||
"KRB5_TRACE=/dev/stdout kinit admin",
|
||||
stdin_text='{0}\n{0}\n{0}\n'.format(
|
||||
self.clients[0].config.admin_password
|
||||
),
|
||||
@@ -619,8 +619,6 @@ class TestACMERenew(IntegrationTest):
|
||||
cert = x509.load_pem_x509_certificate(data, backend=default_backend())
|
||||
initial_expiry = cert.not_valid_after
|
||||
|
||||
tasks.kinit_admin(self.clients[0])
|
||||
|
||||
self.clients[0].run_command(['certbot', 'renew'])
|
||||
|
||||
data = self.clients[0].get_file_contents(
|
||||
|
||||
@@ -311,6 +311,11 @@ class BaseBackupAndRestoreWithDNS(IntegrationTest):
|
||||
tasks.install_master(self.master, setup_dns=True)
|
||||
self.master.run_command(['ipa-restore', backup_path],
|
||||
stdin_text=dirman_password + '\nyes')
|
||||
if reinstall:
|
||||
# If the server was reinstalled, reinstall may have changed
|
||||
# the uid and restore reverts to the original value.
|
||||
# clear the cache to make sure we get up-to-date values
|
||||
tasks.clear_sssd_cache(self.master)
|
||||
tasks.resolve_record(self.master.ip, self.example_test_zone)
|
||||
|
||||
tasks.kinit_admin(self.master)
|
||||
@@ -380,6 +385,12 @@ class BaseBackupAndRestoreWithDNSSEC(IntegrationTest):
|
||||
self.master.run_command(['ipa-restore', backup_path],
|
||||
stdin_text=dirman_password + '\nyes')
|
||||
|
||||
if reinstall:
|
||||
# If the server was reinstalled, reinstall may have changed
|
||||
# the uid and restore reverts to the original value.
|
||||
# clear the cache to make sure we get up-to-date values
|
||||
tasks.clear_sssd_cache(self.master)
|
||||
|
||||
assert (
|
||||
wait_until_record_is_signed(
|
||||
self.master.ip, self.example_test_zone)
|
||||
@@ -464,6 +475,12 @@ class BaseBackupAndRestoreWithKRA(IntegrationTest):
|
||||
self.master.run_command(['ipa-restore', backup_path],
|
||||
stdin_text=dirman_password + '\nyes')
|
||||
|
||||
if reinstall:
|
||||
# If the server was reinstalled, reinstall may have changed
|
||||
# the uid and restore reverts to the original value.
|
||||
# clear the cache to make sure we get up-to-date values
|
||||
tasks.clear_sssd_cache(self.master)
|
||||
|
||||
tasks.kinit_admin(self.master)
|
||||
# retrieve secret after restore
|
||||
self.master.run_command([
|
||||
|
||||
@@ -60,6 +60,7 @@ def get_install_stdin(cert_passwords=()):
|
||||
'', # Server host name (has default)
|
||||
]
|
||||
lines.extend(cert_passwords) # Enter foo.p12 unlock password
|
||||
lines.extend('IPA') # NetBios name
|
||||
lines += [
|
||||
'no', # configure chrony with NTP server or pool address?
|
||||
'yes', # Continue with these values?
|
||||
|
||||
@@ -16,6 +16,7 @@ import string
|
||||
import time
|
||||
|
||||
from ipaplatform.paths import paths
|
||||
from ipapython.dn import DN
|
||||
from cryptography import x509
|
||||
from cryptography.x509.oid import ExtensionOID
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
@@ -69,7 +70,7 @@ class TestInstallMasterClient(IntegrationTest):
|
||||
|
||||
# time to look into journal logs in
|
||||
# test_certmonger_ipa_responder_jsonrpc
|
||||
cls.since = time.strftime('%H:%M:%S')
|
||||
cls.since = time.strftime('%Y-%m-%d %H:%M:%S')
|
||||
|
||||
def test_cacert_file_appear_with_option_F(self):
|
||||
"""Test if getcert creates cacert file with -F option
|
||||
@@ -183,6 +184,34 @@ class TestInstallMasterClient(IntegrationTest):
|
||||
)
|
||||
assert "profile: caServerCert" in result.stdout_text
|
||||
|
||||
def test_multiple_user_certificates(self):
|
||||
"""Test that a user may be issued multiple certificates"""
|
||||
ldap = self.master.ldap_connect()
|
||||
|
||||
user = 'user1'
|
||||
|
||||
tasks.kinit_admin(self.master)
|
||||
tasks.user_add(self.master, user)
|
||||
|
||||
for id in (0,1):
|
||||
csr_file = f'{id}.csr'
|
||||
key_file = f'{id}.key'
|
||||
cert_file = f'{id}.crt'
|
||||
openssl_cmd = [
|
||||
'openssl', 'req', '-newkey', 'rsa:2048', '-keyout', key_file,
|
||||
'-nodes', '-out', csr_file, '-subj', '/CN=' + user]
|
||||
self.master.run_command(openssl_cmd)
|
||||
|
||||
cmd_args = ['ipa', 'cert-request', '--principal', user,
|
||||
'--certificate-out', cert_file, csr_file]
|
||||
self.master.run_command(cmd_args)
|
||||
|
||||
# easier to count by pulling the LDAP entry
|
||||
entry = ldap.get_entry(DN(('uid', user), ('cn', 'users'),
|
||||
('cn', 'accounts'), self.master.domain.basedn))
|
||||
|
||||
assert len(entry.get('usercertificate')) == 2
|
||||
|
||||
@pytest.fixture
|
||||
def test_subca_certs(self):
|
||||
"""
|
||||
@@ -517,3 +546,41 @@ class TestCertmongerInterruption(IntegrationTest):
|
||||
|
||||
assert ca_error is None
|
||||
assert state == 'CA_WORKING'
|
||||
|
||||
|
||||
class TestCAShowErrorHandling(IntegrationTest):
|
||||
num_replicas = 1
|
||||
|
||||
@classmethod
|
||||
def install(cls, mh):
|
||||
tasks.install_master(cls.master)
|
||||
tasks.install_replica(cls.master, cls.replicas[0])
|
||||
|
||||
def test_ca_show_error_handling(self):
|
||||
"""
|
||||
Test to verify if the case of a request
|
||||
for /ca/rest/authority/{id}/cert (or .../chain)
|
||||
where {id} is an unknown authority ID.
|
||||
Test Steps:
|
||||
1. Setup a freeipa server and a replica
|
||||
2. Stop ipa-custodia service on replica
|
||||
3. Create a LWCA on the replica
|
||||
4. Verify LWCA is recognized on the server
|
||||
5. Run `ipa ca-show <LWCA>`
|
||||
PKI Github Link: https://github.com/dogtagpki/pki/pull/3605/
|
||||
"""
|
||||
self.replicas[0].run_command(['systemctl', 'stop', 'ipa-custodia'])
|
||||
lwca = 'lwca1'
|
||||
result = self.replicas[0].run_command([
|
||||
'ipa', 'ca-add', lwca, '--subject', 'CN=LWCA 1'
|
||||
])
|
||||
assert 'Created CA "{}"'.format(lwca) in result.stdout_text
|
||||
result = self.master.run_command(['ipa', 'ca-find'])
|
||||
assert 'Name: {}'.format(lwca) in result.stdout_text
|
||||
result = self.master.run_command(
|
||||
['ipa', 'ca-show', lwca, ],
|
||||
raiseonerr=False
|
||||
)
|
||||
error_msg = 'ipa: ERROR: The certificate for ' \
|
||||
'{} is not available on this server.'.format(lwca)
|
||||
assert error_msg in result.stderr_text
|
||||
@@ -84,43 +84,41 @@ isrgrootx1 = (
|
||||
)
|
||||
isrgrootx1_nick = 'CN=ISRG Root X1,O=Internet Security Research Group,C=US'
|
||||
|
||||
# This sub-CA expires on Oct 6, 2021 but it is functional for our
|
||||
# purposes of testing, the date validity is not considered (yet).
|
||||
letsencryptauthorityx3 = (
|
||||
# This sub-CA expires on Sep 15, 2025 and will need to be replaced
|
||||
# after this date. Otherwise TestIPACommand::test_cacert_manage fails.
|
||||
letsencryptauthorityr3 = (
|
||||
b'-----BEGIN CERTIFICATE-----\n'
|
||||
b'MIIFjTCCA3WgAwIBAgIRANOxciY0IzLc9AUoUSrsnGowDQYJKoZIhvcNAQELBQAw\n'
|
||||
b'MIIFFjCCAv6gAwIBAgIRAJErCErPDBinU/bWLiWnX1owDQYJKoZIhvcNAQELBQAw\n'
|
||||
b'TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh\n'
|
||||
b'cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTYxMDA2MTU0MzU1\n'
|
||||
b'WhcNMjExMDA2MTU0MzU1WjBKMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg\n'
|
||||
b'RW5jcnlwdDEjMCEGA1UEAxMaTGV0J3MgRW5jcnlwdCBBdXRob3JpdHkgWDMwggEi\n'
|
||||
b'MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCc0wzwWuUuR7dyXTeDs2hjMOrX\n'
|
||||
b'NSYZJeG9vjXxcJIvt7hLQQWrqZ41CFjssSrEaIcLo+N15Obzp2JxunmBYB/XkZqf\n'
|
||||
b'89B4Z3HIaQ6Vkc/+5pnpYDxIzH7KTXcSJJ1HG1rrueweNwAcnKx7pwXqzkrrvUHl\n'
|
||||
b'Npi5y/1tPJZo3yMqQpAMhnRnyH+lmrhSYRQTP2XpgofL2/oOVvaGifOFP5eGr7Dc\n'
|
||||
b'Gu9rDZUWfcQroGWymQQ2dYBrrErzG5BJeC+ilk8qICUpBMZ0wNAxzY8xOJUWuqgz\n'
|
||||
b'uEPxsR/DMH+ieTETPS02+OP88jNquTkxxa/EjQ0dZBYzqvqEKbbUC8DYfcOTAgMB\n'
|
||||
b'AAGjggFnMIIBYzAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADBU\n'
|
||||
b'BgNVHSAETTBLMAgGBmeBDAECATA/BgsrBgEEAYLfEwEBATAwMC4GCCsGAQUFBwIB\n'
|
||||
b'FiJodHRwOi8vY3BzLnJvb3QteDEubGV0c2VuY3J5cHQub3JnMB0GA1UdDgQWBBSo\n'
|
||||
b'SmpjBH3duubRObemRWXv86jsoTAzBgNVHR8ELDAqMCigJqAkhiJodHRwOi8vY3Js\n'
|
||||
b'LnJvb3QteDEubGV0c2VuY3J5cHQub3JnMHIGCCsGAQUFBwEBBGYwZDAwBggrBgEF\n'
|
||||
b'BQcwAYYkaHR0cDovL29jc3Aucm9vdC14MS5sZXRzZW5jcnlwdC5vcmcvMDAGCCsG\n'
|
||||
b'AQUFBzAChiRodHRwOi8vY2VydC5yb290LXgxLmxldHNlbmNyeXB0Lm9yZy8wHwYD\n'
|
||||
b'VR0jBBgwFoAUebRZ5nu25eQBc4AIiMgaWPbpm24wDQYJKoZIhvcNAQELBQADggIB\n'
|
||||
b'ABnPdSA0LTqmRf/Q1eaM2jLonG4bQdEnqOJQ8nCqxOeTRrToEKtwT++36gTSlBGx\n'
|
||||
b'A/5dut82jJQ2jxN8RI8L9QFXrWi4xXnA2EqA10yjHiR6H9cj6MFiOnb5In1eWsRM\n'
|
||||
b'UM2v3e9tNsCAgBukPHAg1lQh07rvFKm/Bz9BCjaxorALINUfZ9DD64j2igLIxle2\n'
|
||||
b'DPxW8dI/F2loHMjXZjqG8RkqZUdoxtID5+90FgsGIfkMpqgRS05f4zPbCEHqCXl1\n'
|
||||
b'eO5HyELTgcVlLXXQDgAWnRzut1hFJeczY1tjQQno6f6s+nMydLN26WuU4s3UYvOu\n'
|
||||
b'OsUxRlJu7TSRHqDC3lSE5XggVkzdaPkuKGQbGpny+01/47hfXXNB7HntWNZ6N2Vw\n'
|
||||
b'p7G6OfY+YQrZwIaQmhrIqJZuigsrbe3W+gdn5ykE9+Ky0VgVUsfxo52mwFYs1JKY\n'
|
||||
b'2PGDuWx8M6DlS6qQkvHaRUo0FMd8TsSlbF0/v965qGFKhSDeQoMpYnwcmQilRh/0\n'
|
||||
b'ayLThlHLN81gSkJjVrPI0Y8xCVPB4twb1PFUd2fPM3sA1tJ83sZ5v8vgFv2yofKR\n'
|
||||
b'PB0t6JzUA81mSqM3kxl5e+IZwhYAyO0OTg3/fs8HqGTNKd9BqoUwSRBzp06JMg5b\n'
|
||||
b'rUCGwbCUDI0mxadJ3Bz4WxR6fyNpBK2yAinWEsikxqEt\n'
|
||||
b'cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjAwOTA0MDAwMDAw\n'
|
||||
b'WhcNMjUwOTE1MTYwMDAwWjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg\n'
|
||||
b'RW5jcnlwdDELMAkGA1UEAxMCUjMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK\n'
|
||||
b'AoIBAQC7AhUozPaglNMPEuyNVZLD+ILxmaZ6QoinXSaqtSu5xUyxr45r+XXIo9cP\n'
|
||||
b'R5QUVTVXjJ6oojkZ9YI8QqlObvU7wy7bjcCwXPNZOOftz2nwWgsbvsCUJCWH+jdx\n'
|
||||
b'sxPnHKzhm+/b5DtFUkWWqcFTzjTIUu61ru2P3mBw4qVUq7ZtDpelQDRrK9O8Zutm\n'
|
||||
b'NHz6a4uPVymZ+DAXXbpyb/uBxa3Shlg9F8fnCbvxK/eG3MHacV3URuPMrSXBiLxg\n'
|
||||
b'Z3Vms/EY96Jc5lP/Ooi2R6X/ExjqmAl3P51T+c8B5fWmcBcUr2Ok/5mzk53cU6cG\n'
|
||||
b'/kiFHaFpriV1uxPMUgP17VGhi9sVAgMBAAGjggEIMIIBBDAOBgNVHQ8BAf8EBAMC\n'
|
||||
b'AYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMBIGA1UdEwEB/wQIMAYB\n'
|
||||
b'Af8CAQAwHQYDVR0OBBYEFBQusxe3WFbLrlAJQOYfr52LFMLGMB8GA1UdIwQYMBaA\n'
|
||||
b'FHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcw\n'
|
||||
b'AoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzAnBgNVHR8EIDAeMBygGqAYhhZodHRw\n'
|
||||
b'Oi8veDEuYy5sZW5jci5vcmcvMCIGA1UdIAQbMBkwCAYGZ4EMAQIBMA0GCysGAQQB\n'
|
||||
b'gt8TAQEBMA0GCSqGSIb3DQEBCwUAA4ICAQCFyk5HPqP3hUSFvNVneLKYY611TR6W\n'
|
||||
b'PTNlclQtgaDqw+34IL9fzLdwALduO/ZelN7kIJ+m74uyA+eitRY8kc607TkC53wl\n'
|
||||
b'ikfmZW4/RvTZ8M6UK+5UzhK8jCdLuMGYL6KvzXGRSgi3yLgjewQtCPkIVz6D2QQz\n'
|
||||
b'CkcheAmCJ8MqyJu5zlzyZMjAvnnAT45tRAxekrsu94sQ4egdRCnbWSDtY7kh+BIm\n'
|
||||
b'lJNXoB1lBMEKIq4QDUOXoRgffuDghje1WrG9ML+Hbisq/yFOGwXD9RiX8F6sw6W4\n'
|
||||
b'avAuvDszue5L3sz85K+EC4Y/wFVDNvZo4TYXao6Z0f+lQKc0t8DQYzk1OXVu8rp2\n'
|
||||
b'yJMC6alLbBfODALZvYH7n7do1AZls4I9d1P4jnkDrQoxB3UqQ9hVl3LEKQ73xF1O\n'
|
||||
b'yK5GhDDX8oVfGKF5u+decIsH4YaTw7mP3GFxJSqv3+0lUFJoi5Lc5da149p90Ids\n'
|
||||
b'hCExroL1+7mryIkXPeFM5TgO9r0rvZaBFOvV2z0gp35Z0+L4WPlbuEjN/lxPFin+\n'
|
||||
b'HlUjr8gRsI3qfJOQFy/9rKIJR0Y/8Omwt/8oTWgy1mdeHmmjk7j1nYsvC9JSQ6Zv\n'
|
||||
b'MldlTTKB3zhThV1+XWYp6rjd5JW1zbVWEkLNxE7GJThEUG3szgBVGP7pSWTUTsqX\n'
|
||||
b'nLRbwHOoq7hHwg==\n'
|
||||
b'-----END CERTIFICATE-----\n'
|
||||
)
|
||||
le_x3_nick = "CN=Let's Encrypt Authority X3,O=Let's Encrypt,C=US"
|
||||
le_r3_nick = "CN=R3,O=Let's Encrypt,C=US"
|
||||
|
||||
|
||||
class TestIPACommand(IntegrationTest):
|
||||
@@ -1113,7 +1111,7 @@ class TestIPACommand(IntegrationTest):
|
||||
result.stderr_text
|
||||
|
||||
# Install 3rd party CA's, Let's Encrypt in this case
|
||||
for cert in (isrgrootx1, letsencryptauthorityx3):
|
||||
for cert in (isrgrootx1, letsencryptauthorityr3):
|
||||
certfile = os.path.join(self.master.config.test_dir, 'cert.pem')
|
||||
self.master.put_file_contents(certfile, cert)
|
||||
result = self.master.run_command(
|
||||
@@ -1140,7 +1138,7 @@ class TestIPACommand(IntegrationTest):
|
||||
|
||||
# deletion of a subca
|
||||
result = self.master.run_command(
|
||||
['ipa-cacert-manage', 'delete', le_x3_nick],
|
||||
['ipa-cacert-manage', 'delete', le_r3_nick],
|
||||
raiseonerr=False
|
||||
)
|
||||
assert result.returncode == 0
|
||||
@@ -1208,7 +1206,8 @@ class TestIPACommand(IntegrationTest):
|
||||
# start to look at logs a bit before "now"
|
||||
# https://pagure.io/freeipa/issue/8432
|
||||
since = time.strftime(
|
||||
'%H:%M:%S', (datetime.now() - timedelta(seconds=10)).timetuple()
|
||||
'%Y-%m-%d %H:%M:%S',
|
||||
(datetime.now() - timedelta(seconds=10)).timetuple()
|
||||
)
|
||||
|
||||
password = 'WrongPassword'
|
||||
@@ -1374,7 +1373,9 @@ class TestIPACommand(IntegrationTest):
|
||||
stdin_text='{0}\n{0}\n'.format(original_passwd)
|
||||
)
|
||||
|
||||
ldap = self.master.ldap_connect()
|
||||
# Wait for the password update to be replicated from replicas[0]
|
||||
# to other servers
|
||||
ldap = self.replicas[0].ldap_connect()
|
||||
tasks.wait_for_replication(ldap)
|
||||
|
||||
# The user can log in again
|
||||
@@ -1578,6 +1579,46 @@ class TestIPACommandWithoutReplica(IntegrationTest):
|
||||
tasks.ldapsearch_dm(self.master, base, ldap_args=[], scope='sub')
|
||||
tasks.ldapsearch_dm(self.master, base, ldap_args=[], scope='base')
|
||||
|
||||
def test_sid_generation(self):
|
||||
"""
|
||||
Test SID generation
|
||||
|
||||
Check that new users are created with a SID and PAC data is
|
||||
added in their Kerberos tickets.
|
||||
"""
|
||||
user = "pacuser"
|
||||
passwd = "Secret123"
|
||||
|
||||
try:
|
||||
# Create a nonadmin user
|
||||
tasks.create_active_user(
|
||||
self.master, user, passwd, first=user, last=user,
|
||||
krb5_trace=True)
|
||||
|
||||
# Check SID is present in the new entry
|
||||
base_dn = str(self.master.domain.basedn)
|
||||
result = tasks.ldapsearch_dm(
|
||||
self.master,
|
||||
'uid={user},cn=users,cn=accounts,{base_dn}'.format(
|
||||
user=user, base_dn=base_dn),
|
||||
['ipantsecurityidentifier'],
|
||||
scope='base'
|
||||
)
|
||||
assert 'ipantsecurityidentifier' in result.stdout_text
|
||||
|
||||
# Defaults: host/... principal for service
|
||||
# keytab in /etc/krb5.keytab
|
||||
self.master.run_command(["kinit", '-k'])
|
||||
result = self.master.run_command(
|
||||
[os.path.join(paths.LIBEXEC_IPA_DIR, "ipa-print-pac"),
|
||||
"ticket", user],
|
||||
stdin_text=(passwd + '\n')
|
||||
)
|
||||
assert "PAC_DATA" in result.stdout_text
|
||||
finally:
|
||||
tasks.kinit_admin(self.master)
|
||||
self.master.run_command(['ipa', 'user-del', user])
|
||||
|
||||
|
||||
class TestIPAautomount(IntegrationTest):
|
||||
@classmethod
|
||||
|
||||
@@ -28,6 +28,17 @@ IPA_DEFAULT_MASTER_SRV_REC = (
|
||||
(DNSName(u'_kpasswd._udp'), 464),
|
||||
)
|
||||
|
||||
IPA_DEFAULT_MASTER_URI_REC = (
|
||||
(
|
||||
DNSName('_kerberos'),
|
||||
("krb5srv:m:tcp:{hostname}", "krb5srv:m:udp:{hostname}")
|
||||
),
|
||||
(
|
||||
DNSName('_kpasswd'),
|
||||
("krb5srv:m:tcp:{hostname}", "krb5srv:m:udp:{hostname}")
|
||||
),
|
||||
)
|
||||
|
||||
IPA_DEFAULT_ADTRUST_SRV_REC = (
|
||||
# srv record name, port
|
||||
(DNSName(u'_ldap._tcp.Default-First-Site-Name._sites.dc._msdcs'), 389),
|
||||
@@ -79,6 +90,21 @@ def _gen_expected_srv_rrset(rname, port, servers, ttl=86400):
|
||||
)
|
||||
|
||||
|
||||
def _gen_expected_uri_rrset(rname, uri_templates, servers, ttl=86400):
|
||||
rdata_list = [
|
||||
"{prio} {weight} {uri}".format(
|
||||
prio=prio,
|
||||
weight=weight,
|
||||
uri=uri_template.format(hostname=servername.make_absolute()),
|
||||
)
|
||||
for uri_template in uri_templates
|
||||
for prio, weight, servername in servers
|
||||
]
|
||||
return dns.rrset.from_text_list(
|
||||
rname, ttl, dns.rdataclass.IN, dns.rdatatype.URI, rdata_list
|
||||
)
|
||||
|
||||
|
||||
def _gen_expected_a_rrset(rname, servers, ttl=86400):
|
||||
return dns.rrset.from_text_list(rname, ttl, dns.rdataclass.IN,
|
||||
dns.rdatatype.A, servers)
|
||||
@@ -174,6 +200,20 @@ class TestDNSLocations(IntegrationTest):
|
||||
"with IP: '{}' for name '{}' (expected:\n{}\ngot:\n{})".
|
||||
format(server_ip, name_abs, expected, query))
|
||||
|
||||
def _test_URI_rec_against_server(self, server_ip, domain, expected_servers,
|
||||
rec_list=IPA_DEFAULT_MASTER_URI_REC):
|
||||
for rname, uri_templates in rec_list:
|
||||
name_abs = rname.derelativize(domain)
|
||||
expected = _gen_expected_uri_rrset(
|
||||
name_abs, uri_templates, expected_servers)
|
||||
query = resolve_records_from_server(
|
||||
name_abs, 'URI', server_ip)
|
||||
|
||||
assert expected == query, (
|
||||
"Expected and received DNS data do not match on server "
|
||||
"with IP: '{}' for name '{}' (expected:\n{}\ngot:\n{})".
|
||||
format(server_ip, name_abs, expected, query))
|
||||
|
||||
def test_without_locations(self):
|
||||
"""Servers are not in locations, this tests if basic system records
|
||||
are generated properly"""
|
||||
@@ -185,6 +225,9 @@ class TestDNSLocations(IntegrationTest):
|
||||
for ip in (self.master.ip, self.replicas[0].ip, self.replicas[1].ip):
|
||||
self._test_SRV_rec_against_server(ip, self.domain,
|
||||
expected_servers)
|
||||
self._test_URI_rec_against_server(
|
||||
ip, self.domain, expected_servers
|
||||
)
|
||||
|
||||
def test_nsupdate_without_locations(self):
|
||||
"""Test nsupdate file generated by dns-update-system-records
|
||||
@@ -227,11 +270,19 @@ class TestDNSLocations(IntegrationTest):
|
||||
)
|
||||
|
||||
self._test_SRV_rec_against_server(
|
||||
self.replicas[0].ip, domain_prague_loc, servers_prague_loc)
|
||||
self.replicas[0].ip, domain_prague_loc, servers_prague_loc
|
||||
)
|
||||
self._test_URI_rec_against_server(
|
||||
self.replicas[0].ip, domain_prague_loc, servers_prague_loc
|
||||
)
|
||||
|
||||
for ip in (self.master.ip, self.replicas[1].ip):
|
||||
self._test_SRV_rec_against_server(
|
||||
ip, domain_without_loc, servers_without_loc)
|
||||
ip, domain_without_loc, servers_without_loc
|
||||
)
|
||||
self._test_URI_rec_against_server(
|
||||
ip, domain_without_loc, servers_without_loc
|
||||
)
|
||||
|
||||
def test_two_replicas_in_location(self):
|
||||
"""Put second replica to location and test if records changed properly
|
||||
@@ -270,13 +321,25 @@ class TestDNSLocations(IntegrationTest):
|
||||
self.master.domain.name).make_absolute())
|
||||
|
||||
self._test_SRV_rec_against_server(
|
||||
self.replicas[0].ip, domain_prague_loc, servers_prague_loc)
|
||||
self.replicas[0].ip, domain_prague_loc, servers_prague_loc
|
||||
)
|
||||
self._test_URI_rec_against_server(
|
||||
self.replicas[0].ip, domain_prague_loc, servers_prague_loc
|
||||
)
|
||||
|
||||
self._test_SRV_rec_against_server(
|
||||
self.replicas[1].ip, domain_paris_loc, servers_paris_loc)
|
||||
self.replicas[1].ip, domain_paris_loc, servers_paris_loc
|
||||
)
|
||||
self._test_URI_rec_against_server(
|
||||
self.replicas[1].ip, domain_paris_loc, servers_paris_loc
|
||||
)
|
||||
|
||||
self._test_SRV_rec_against_server(
|
||||
self.master.ip, domain_without_loc, servers_without_loc)
|
||||
self.master.ip, domain_without_loc, servers_without_loc
|
||||
)
|
||||
self._test_URI_rec_against_server(
|
||||
self.master.ip, domain_without_loc, servers_without_loc
|
||||
)
|
||||
|
||||
def test_all_servers_in_location(self):
|
||||
"""Put master (as second server) to location and test if records
|
||||
@@ -308,11 +371,19 @@ class TestDNSLocations(IntegrationTest):
|
||||
self.master.domain.name).make_absolute())
|
||||
|
||||
self._test_SRV_rec_against_server(
|
||||
self.replicas[0].ip, domain_prague_loc, servers_prague_loc)
|
||||
self.replicas[0].ip, domain_prague_loc, servers_prague_loc
|
||||
)
|
||||
self._test_URI_rec_against_server(
|
||||
self.replicas[0].ip, domain_prague_loc, servers_prague_loc
|
||||
)
|
||||
|
||||
for ip in (self.replicas[1].ip, self.master.ip):
|
||||
self._test_SRV_rec_against_server(ip, domain_paris_loc,
|
||||
servers_paris_loc)
|
||||
self._test_SRV_rec_against_server(
|
||||
ip, domain_paris_loc, servers_paris_loc
|
||||
)
|
||||
self._test_URI_rec_against_server(
|
||||
ip, domain_paris_loc, servers_paris_loc
|
||||
)
|
||||
|
||||
def test_change_weight(self):
|
||||
"""Change weight of master and test if records changed properly
|
||||
@@ -347,11 +418,19 @@ class TestDNSLocations(IntegrationTest):
|
||||
self.master.domain.name).make_absolute())
|
||||
|
||||
self._test_SRV_rec_against_server(
|
||||
self.replicas[0].ip, domain_prague_loc, servers_prague_loc)
|
||||
self.replicas[0].ip, domain_prague_loc, servers_prague_loc
|
||||
)
|
||||
self._test_URI_rec_against_server(
|
||||
self.replicas[0].ip, domain_prague_loc, servers_prague_loc
|
||||
)
|
||||
|
||||
for ip in (self.replicas[1].ip, self.master.ip):
|
||||
self._test_SRV_rec_against_server(ip, domain_paris_loc,
|
||||
servers_paris_loc)
|
||||
self._test_SRV_rec_against_server(
|
||||
ip, domain_paris_loc, servers_paris_loc
|
||||
)
|
||||
self._test_URI_rec_against_server(
|
||||
ip, domain_paris_loc, servers_paris_loc
|
||||
)
|
||||
|
||||
def test_change_weight_relative_zero_0(self):
|
||||
"""Change weight of one master and check on relative weight %
|
||||
|
||||
@@ -20,7 +20,6 @@ from __future__ import absolute_import
|
||||
import os
|
||||
import re
|
||||
import time
|
||||
import tempfile
|
||||
|
||||
from cryptography import x509
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
@@ -464,8 +463,12 @@ class TestMultipleExternalCA(IntegrationTest):
|
||||
def test_master_install_ca1(self):
|
||||
install_server_external_ca_step1(self.master)
|
||||
# Sign CA, transport it to the host and get ipa a root ca paths.
|
||||
root_ca_fname1 = tempfile.mkdtemp(suffix='root_ca.crt', dir=paths.TMP)
|
||||
ipa_ca_fname1 = tempfile.mkdtemp(suffix='ipa_ca.crt', dir=paths.TMP)
|
||||
root_ca_fname1 = tasks.create_temp_file(
|
||||
self.master, directory=paths.TMP, suffix="root_ca.crt"
|
||||
)
|
||||
ipa_ca_fname1 = tasks.create_temp_file(
|
||||
self.master, directory=paths.TMP, suffix="ipa_ca.crt"
|
||||
)
|
||||
|
||||
ipa_csr = self.master.get_file_contents(paths.ROOT_IPA_CSR)
|
||||
|
||||
@@ -485,8 +488,12 @@ class TestMultipleExternalCA(IntegrationTest):
|
||||
assert "CN=RootCA1" in result.stdout_text
|
||||
|
||||
def test_master_install_ca2(self):
|
||||
root_ca_fname2 = tempfile.mkdtemp(suffix='root_ca.crt', dir=paths.TMP)
|
||||
ipa_ca_fname2 = tempfile.mkdtemp(suffix='ipa_ca.crt', dir=paths.TMP)
|
||||
root_ca_fname2 = tasks.create_temp_file(
|
||||
self.master, directory=paths.TMP, suffix="root_ca.crt"
|
||||
)
|
||||
ipa_ca_fname2 = tasks.create_temp_file(
|
||||
self.master, directory=paths.TMP, suffix="ipa_ca.crt"
|
||||
)
|
||||
|
||||
self.master.run_command([
|
||||
paths.IPA_CACERT_MANAGE, 'renew', '--external-ca'])
|
||||
|
||||
@@ -22,6 +22,7 @@ from cryptography import x509 as crypto_x509
|
||||
from ipalib import x509
|
||||
from ipalib.constants import DOMAIN_LEVEL_0, KRA_TRACKING_REQS
|
||||
from ipalib.constants import IPA_CA_RECORD
|
||||
from ipalib.constants import ALLOWED_NETBIOS_CHARS
|
||||
from ipalib.sysrestore import SYSRESTORE_STATEFILE, SYSRESTORE_INDEXFILE
|
||||
from ipapython.dn import DN
|
||||
from ipaplatform.constants import constants
|
||||
@@ -69,6 +70,17 @@ def server_cleanup(request):
|
||||
tasks.uninstall_master(host)
|
||||
|
||||
|
||||
def create_netbios_name(host):
|
||||
"""
|
||||
Create a NetBIOS name based on the provided host
|
||||
"""
|
||||
netbios = ''.join(
|
||||
c for c in host.domain.name.split('.')[0].upper() \
|
||||
if c in ALLOWED_NETBIOS_CHARS
|
||||
)[:15]
|
||||
return netbios
|
||||
|
||||
|
||||
class InstallTestBase1(IntegrationTest):
|
||||
|
||||
num_replicas = 3
|
||||
@@ -570,6 +582,10 @@ class TestInstallWithCA_DNS3(CALessBase):
|
||||
ticket 7239
|
||||
"""
|
||||
|
||||
@pytest.mark.xfail(
|
||||
osinfo.id == 'fedora' and osinfo.version_number >= (33,)
|
||||
and osinfo.version_number < (35,),
|
||||
reason='freeipa ticket 8700', strict=True)
|
||||
@server_install_setup
|
||||
def test_number_of_zones(self):
|
||||
"""There should be two zones: one forward, one reverse"""
|
||||
@@ -1171,6 +1187,8 @@ class TestInstallMaster(IntegrationTest):
|
||||
hosts = self.master.get_file_contents(paths.HOSTS, encoding='utf-8')
|
||||
new_hosts = hosts.replace(original_hostname, new_hostname)
|
||||
self.master.put_file_contents(paths.HOSTS, new_hosts)
|
||||
netbios = create_netbios_name(self.master)
|
||||
|
||||
try:
|
||||
cmd = ['ipa-server-install', '--hostname', new_hostname]
|
||||
with self.master.spawn_expect(cmd) as e:
|
||||
@@ -1193,6 +1211,8 @@ class TestInstallMaster(IntegrationTest):
|
||||
e.sendline(self.master.config.admin_password)
|
||||
e.expect_exact('Password (confirm): ')
|
||||
e.sendline(self.master.config.admin_password)
|
||||
e.expect_exact('NetBIOS domain name [{}]: '.format(netbios))
|
||||
e.sendline(netbios)
|
||||
e.expect_exact('Do you want to configure chrony with '
|
||||
'NTP server or pool address? [no]: ')
|
||||
e.sendline('no')
|
||||
@@ -1367,6 +1387,7 @@ class TestInstallMasterDNS(IntegrationTest):
|
||||
https://pagure.io/freeipa/issue/2575
|
||||
"""
|
||||
cmd = ['ipa-server-install']
|
||||
netbios = create_netbios_name(self.master)
|
||||
with self.master.spawn_expect(cmd) as e:
|
||||
e.expect_exact('Do you want to configure integrated '
|
||||
'DNS (BIND)? [no]: ')
|
||||
@@ -1398,6 +1419,8 @@ class TestInstallMasterDNS(IntegrationTest):
|
||||
e.expect_exact('Do you want to search for missing reverse '
|
||||
'zones? [yes]: ')
|
||||
e.sendline('no') # irrelevant for this test
|
||||
e.expect_exact('NetBIOS domain name [{}]: '.format(netbios))
|
||||
e.sendline(netbios)
|
||||
e.expect_exact('Do you want to configure chrony with NTP '
|
||||
'server or pool address? [no]: ')
|
||||
e.sendline('no') # irrelevant for this test
|
||||
|
||||
@@ -5,15 +5,19 @@
|
||||
"""
|
||||
Module provides tests for ipa-cert-fix CLI.
|
||||
"""
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
from cryptography import x509
|
||||
from datetime import datetime, date
|
||||
import pytest
|
||||
import time
|
||||
|
||||
import logging
|
||||
from ipaplatform.paths import paths
|
||||
from ipapython.ipaldap import realm_to_serverid
|
||||
from ipatests.pytest_ipa.integration import tasks
|
||||
from ipatests.test_integration.base import IntegrationTest
|
||||
from ipatests.test_integration.test_caless import CALessBase, ipa_certs_cleanup
|
||||
|
||||
from ipatests.test_integration.test_cert import get_certmonger_fs_id
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -48,14 +52,47 @@ def check_status(host, cert_count, state, timeout=600):
|
||||
return count
|
||||
|
||||
|
||||
def move_date(host, chrony_state, date_str):
|
||||
"""Helper method to move the date on given host
|
||||
:param host: The host on which date is to be moved
|
||||
:param chrony_state: State to which chrony service to be moved
|
||||
:param date_str: date string to move the date i.e 2years1month1days
|
||||
def needs_resubmit(host, req_id):
|
||||
"""Helper method to identify if cert request needs to be resubmitted
|
||||
:param host: the host
|
||||
:param req_id: request id to perform operation for
|
||||
|
||||
Returns True if resubmit needed else False
|
||||
"""
|
||||
host.run_command(['systemctl', chrony_state, 'chronyd'])
|
||||
host.run_command(['date', '-s', date_str])
|
||||
# check if cert is in monitoring state
|
||||
tasks.wait_for_certmonger_status(
|
||||
host, ('MONITORING'), req_id, timeout=600
|
||||
)
|
||||
|
||||
# check if cert is valid and not expired
|
||||
cmd = host.run_command(
|
||||
'getcert list -i {} | grep expires'.format(req_id)
|
||||
)
|
||||
cert_expiry = cmd.stdout_text.split(' ')
|
||||
cert_expiry = datetime.strptime(cert_expiry[1], '%Y-%m-%d').date()
|
||||
if cert_expiry > date.today():
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
|
||||
def get_cert_expiry(host, nssdb_path, cert_nick):
|
||||
"""Method to get cert expiry date of given certificate
|
||||
|
||||
:param host: the host
|
||||
:param nssdb_path: nssdb path of certificate
|
||||
:param cert_nick: certificate nick name for extracting cert from nssdb
|
||||
"""
|
||||
# get initial expiry date to compare later with renewed cert
|
||||
host.run_command([
|
||||
'certutil', '-L', '-a',
|
||||
'-d', nssdb_path,
|
||||
'-n', cert_nick,
|
||||
'-o', '/root/cert.pem'
|
||||
])
|
||||
data = host.get_file_contents('/root/cert.pem')
|
||||
cert = x509.load_pem_x509_certificate(data, backend=default_backend())
|
||||
return cert.not_valid_after
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@@ -74,15 +111,15 @@ def expire_cert_critical():
|
||||
extra_args=['--no-ntp'])
|
||||
if setup_kra:
|
||||
tasks.install_kra(host)
|
||||
host.run_command(['systemctl', 'stop', 'chronyd'])
|
||||
host.run_command(['date', '-s', '+3Years+1day'])
|
||||
|
||||
# move date to expire certs
|
||||
tasks.move_date(host, 'stop', '+3Years+1day')
|
||||
|
||||
yield _expire_cert_critical
|
||||
|
||||
host = hosts.pop('host')
|
||||
tasks.uninstall_master(host)
|
||||
host.run_command(['date', '-s', '-3Years-1day'])
|
||||
host.run_command(['systemctl', 'start', 'chronyd'])
|
||||
tasks.move_date(host, 'start', '-3Years-1day')
|
||||
|
||||
|
||||
class TestIpaCertFix(IntegrationTest):
|
||||
@@ -96,12 +133,12 @@ class TestIpaCertFix(IntegrationTest):
|
||||
def expire_ca_cert(self):
|
||||
tasks.install_master(self.master, setup_dns=False,
|
||||
extra_args=['--no-ntp'])
|
||||
move_date(self.master, 'stop', '+20Years+1day')
|
||||
tasks.move_date(self.master, 'stop', '+20Years+1day')
|
||||
|
||||
yield
|
||||
|
||||
tasks.uninstall_master(self.master)
|
||||
move_date(self.master, 'start', '-20Years-1day')
|
||||
tasks.move_date(self.master, 'start', '-20Years-1day')
|
||||
|
||||
def test_missing_csr(self, expire_cert_critical):
|
||||
"""
|
||||
@@ -336,3 +373,138 @@ class TestCertFixKRA(IntegrationTest):
|
||||
self.master.run_command(['ipa-cert-fix', '-v'], stdin_text='yes\n')
|
||||
|
||||
check_status(self.master, 12, "MONITORING")
|
||||
|
||||
|
||||
class TestCertFixReplica(IntegrationTest):
|
||||
|
||||
num_replicas = 1
|
||||
|
||||
@classmethod
|
||||
def install(cls, mh):
|
||||
tasks.install_master(
|
||||
mh.master, setup_dns=False, extra_args=['--no-ntp']
|
||||
)
|
||||
tasks.install_replica(
|
||||
mh.master, mh.replicas[0],
|
||||
setup_dns=False, extra_args=['--no-ntp']
|
||||
)
|
||||
|
||||
@pytest.fixture
|
||||
def expire_certs(self):
|
||||
# move system date to expire certs
|
||||
for host in self.master, self.replicas[0]:
|
||||
tasks.move_date(host, 'stop', '+3years+1days')
|
||||
|
||||
yield
|
||||
|
||||
# move date back on replica and master
|
||||
for host in self.master, self.replicas[0]:
|
||||
tasks.move_date(host, 'start', '-3years-1days')
|
||||
|
||||
def test_renew_expired_cert_replica(self, expire_certs):
|
||||
"""Test renewal of certificates on replica with ipa-cert-fix
|
||||
|
||||
This is to check that ipa-cert-fix renews the certificates
|
||||
on replica
|
||||
|
||||
related: https://pagure.io/freeipa/issue/7885
|
||||
"""
|
||||
# wait for cert expiry
|
||||
check_status(self.master, 8, "CA_UNREACHABLE")
|
||||
|
||||
self.master.run_command(['ipa-cert-fix', '-v'], stdin_text='yes\n')
|
||||
|
||||
check_status(self.master, 9, "MONITORING")
|
||||
|
||||
# replica operations
|
||||
# 'Server-Cert cert-pki-ca' cert will be in CA_UNREACHABLE state
|
||||
cmd = self.replicas[0].run_command(
|
||||
['getcert', 'list',
|
||||
'-d', paths.PKI_TOMCAT_ALIAS_DIR,
|
||||
'-n', 'Server-Cert cert-pki-ca']
|
||||
)
|
||||
req_id = get_certmonger_fs_id(cmd.stdout_text)
|
||||
tasks.wait_for_certmonger_status(
|
||||
self.replicas[0], ('CA_UNREACHABLE'), req_id, timeout=600
|
||||
)
|
||||
# get initial expiry date to compare later with renewed cert
|
||||
initial_expiry = get_cert_expiry(
|
||||
self.replicas[0],
|
||||
paths.PKI_TOMCAT_ALIAS_DIR,
|
||||
'Server-Cert cert-pki-ca'
|
||||
)
|
||||
|
||||
# check that HTTP,LDAP,PKINIT are renewed and in MONITORING state
|
||||
instance = realm_to_serverid(self.master.domain.realm)
|
||||
dirsrv_cert = paths.ETC_DIRSRV_SLAPD_INSTANCE_TEMPLATE % instance
|
||||
for cert in (paths.KDC_CERT, paths.HTTPD_CERT_FILE):
|
||||
cmd = self.replicas[0].run_command(
|
||||
['getcert', 'list', '-f', cert]
|
||||
)
|
||||
req_id = get_certmonger_fs_id(cmd.stdout_text)
|
||||
tasks.wait_for_certmonger_status(
|
||||
self.replicas[0], ('MONITORING'), req_id, timeout=600
|
||||
)
|
||||
|
||||
cmd = self.replicas[0].run_command(
|
||||
['getcert', 'list', '-d', dirsrv_cert]
|
||||
)
|
||||
req_id = get_certmonger_fs_id(cmd.stdout_text)
|
||||
tasks.wait_for_certmonger_status(
|
||||
self.replicas[0], ('MONITORING'), req_id, timeout=600
|
||||
)
|
||||
|
||||
# check if replication working fine
|
||||
testuser = 'testuser1'
|
||||
password = 'Secret@123'
|
||||
stdin = (f"{self.master.config.admin_password}\n"
|
||||
f"{self.master.config.admin_password}\n"
|
||||
f"{self.master.config.admin_password}\n")
|
||||
self.master.run_command(['kinit', 'admin'], stdin_text=stdin)
|
||||
tasks.user_add(self.master, testuser, password=password)
|
||||
self.replicas[0].run_command(['kinit', 'admin'], stdin_text=stdin)
|
||||
self.replicas[0].run_command(['ipa', 'user-show', testuser])
|
||||
|
||||
# renew shared certificates by resubmitting to certmonger
|
||||
cmd = self.replicas[0].run_command(
|
||||
['getcert', 'list', '-f', paths.RA_AGENT_PEM]
|
||||
)
|
||||
req_id = get_certmonger_fs_id(cmd.stdout_text)
|
||||
if needs_resubmit(self.replicas[0], req_id):
|
||||
self.replicas[0].run_command(
|
||||
['getcert', 'resubmit', '-i', req_id]
|
||||
)
|
||||
tasks.wait_for_certmonger_status(
|
||||
self.replicas[0], ('MONITORING'), req_id, timeout=600
|
||||
)
|
||||
for cert_nick in ('auditSigningCert cert-pki-ca',
|
||||
'ocspSigningCert cert-pki-ca',
|
||||
'subsystemCert cert-pki-ca'):
|
||||
cmd = self.replicas[0].run_command(
|
||||
['getcert', 'list',
|
||||
'-d', paths.PKI_TOMCAT_ALIAS_DIR,
|
||||
'-n', cert_nick]
|
||||
)
|
||||
req_id = get_certmonger_fs_id(cmd.stdout_text)
|
||||
if needs_resubmit(self.replicas[0], req_id):
|
||||
self.replicas[0].run_command(
|
||||
['getcert', 'resubmit', '-i', req_id]
|
||||
)
|
||||
tasks.wait_for_certmonger_status(
|
||||
self.replicas[0], ('MONITORING'), req_id, timeout=600
|
||||
)
|
||||
|
||||
self.replicas[0].run_command(
|
||||
['ipa-cert-fix', '-v'], stdin_text='yes\n'
|
||||
)
|
||||
|
||||
check_status(self.replicas[0], 9, "MONITORING")
|
||||
|
||||
# Sometimes certmonger takes time to update the cert status
|
||||
# So check in nssdb instead of relying on getcert command
|
||||
renewed_expiry = get_cert_expiry(
|
||||
self.replicas[0],
|
||||
paths.PKI_TOMCAT_ALIAS_DIR,
|
||||
'Server-Cert cert-pki-ca'
|
||||
)
|
||||
assert renewed_expiry > initial_expiry
|
||||
@@ -1221,7 +1221,7 @@ class TestIpaHealthCheck(IntegrationTest):
|
||||
"--case-id",
|
||||
caseid,
|
||||
"--batch",
|
||||
"-v",
|
||||
"-vv",
|
||||
"--build",
|
||||
]
|
||||
)
|
||||
@@ -2415,7 +2415,10 @@ class TestIpaHealthCheckWithExternalCA(IntegrationTest):
|
||||
"""
|
||||
Test for IPAOpenSSLChainValidation when httpd cert is moved.
|
||||
"""
|
||||
error_msg = "Can't open {} for reading".format(paths.HTTPD_CERT_FILE)
|
||||
error_msg1 = "Can't open {} for reading".format(paths.HTTPD_CERT_FILE)
|
||||
# OpenSSL3 has a different error message
|
||||
error_msg3 = "Could not open file or uri for loading certificate " \
|
||||
"file from {}".format(paths.HTTPD_CERT_FILE)
|
||||
returncode, data = run_healthcheck(
|
||||
self.master,
|
||||
"ipahealthcheck.ipa.certs",
|
||||
@@ -2425,7 +2428,8 @@ class TestIpaHealthCheckWithExternalCA(IntegrationTest):
|
||||
for check in data:
|
||||
if check["kw"]["key"] == paths.HTTPD_CERT_FILE:
|
||||
assert check["result"] == "ERROR"
|
||||
assert error_msg in check["kw"]["reason"]
|
||||
assert (error_msg1 in check["kw"]["reason"]
|
||||
or error_msg3 in check["kw"]["reason"])
|
||||
|
||||
@pytest.fixture()
|
||||
def replace_ipa_chain(self):
|
||||
|
||||
@@ -130,7 +130,7 @@ class TestNFS(IntegrationTest):
|
||||
nfsclt = self.clients[1]
|
||||
|
||||
# for journalctl --since
|
||||
since = time.strftime('%H:%M:%S')
|
||||
since = time.strftime('%Y-%m-%d %H:%M:%S')
|
||||
nfsclt.run_command(["systemctl", "restart", "rpc-gssd"])
|
||||
time.sleep(WAIT_AFTER_INSTALL)
|
||||
mountpoints = ("/mnt/krb", "/mnt/std", "/home")
|
||||
|
||||
@@ -260,6 +260,8 @@ class TestNTPoptions(IntegrationTest):
|
||||
"No\n"
|
||||
# Server host name [hostname]:
|
||||
"\n"
|
||||
# Enter the NetBIOS name for the IPA domain
|
||||
"IPA\n"
|
||||
# Do you want to configure chrony with NTP server
|
||||
# or pool address? [no]:
|
||||
"Yes\n"
|
||||
@@ -372,6 +374,7 @@ class TestNTPoptions(IntegrationTest):
|
||||
server_input = (
|
||||
"\n" +
|
||||
"\n"
|
||||
"IPA\n"
|
||||
"No\n"
|
||||
"Yes"
|
||||
)
|
||||
|
||||
@@ -571,9 +571,6 @@ class TestTrust(BaseTestTrust):
|
||||
|
||||
client = self.clients[0]
|
||||
tasks.backup_file(self.master, paths.SSSD_CONF)
|
||||
log_file = '{0}/sssd_{1}.log'.format(paths.VAR_LOG_SSSD_DIR,
|
||||
client.domain.name)
|
||||
logsize = len(client.get_file_contents(log_file))
|
||||
res = self.master.run_command(['pidof', 'sssd_be'])
|
||||
pid = res.stdout_text.strip()
|
||||
test_id = 'id testuser@%s' % self.ad_domain
|
||||
@@ -595,6 +592,10 @@ class TestTrust(BaseTestTrust):
|
||||
self.master.run_command(remove_cache)
|
||||
client.run_command(remove_cache)
|
||||
|
||||
log_file = '{0}/sssd_{1}.log'.format(paths.VAR_LOG_SSSD_DIR,
|
||||
client.domain.name)
|
||||
logsize = len(client.get_file_contents(log_file))
|
||||
|
||||
try:
|
||||
# stop sssd_be, needed to simulate a timeout in the extdom plugin.
|
||||
stop_sssdbe = self.master.run_command('kill -STOP %s' % pid)
|
||||
@@ -943,12 +944,12 @@ class TestTrust(BaseTestTrust):
|
||||
['chown', '--reference', paths.NAMED_CONF, ad_zone_file])
|
||||
named_conf = self.master.get_file_contents(paths.NAMED_CONF,
|
||||
encoding='utf-8')
|
||||
named_conf += textwrap.dedent('''
|
||||
zone "ad.test" {{
|
||||
named_conf += textwrap.dedent(f'''
|
||||
zone "{self.ad.domain.name}" {{
|
||||
type master;
|
||||
file "{}";
|
||||
file "{ad_zone_file}";
|
||||
}};
|
||||
'''.format(ad_zone_file))
|
||||
''')
|
||||
self.master.put_file_contents(paths.NAMED_CONF, named_conf)
|
||||
tasks.restart_named(self.master)
|
||||
try:
|
||||
|
||||
@@ -24,7 +24,7 @@ DNS tests
|
||||
from ipatests.test_webui.ui_driver import UI_driver
|
||||
from ipatests.test_webui.ui_driver import screenshot
|
||||
from ipatests.test_webui.data_dns import (
|
||||
ZONE_ENTITY, FORWARD_ZONE_ENTITY, CONFIG_ENTITY,
|
||||
ZONE_ENTITY, FORWARD_ZONE_ENTITY, CONFIG_ENTITY, RECORD_ENTITY,
|
||||
ZONE_DEFAULT_FACET, ZONE_PKEY, ZONE_DATA, FORWARD_ZONE_PKEY,
|
||||
FORWARD_ZONE_DATA, RECORD_PKEY, A_IP, RECORD_ADD_DATA, RECORD_MOD_DATA,
|
||||
CONFIG_MOD_DATA
|
||||
@@ -113,3 +113,69 @@ class test_dns(UI_driver):
|
||||
self.init_app()
|
||||
self.navigate_by_menu('network_services/dns/dnsconfig')
|
||||
self.mod_record(CONFIG_ENTITY, CONFIG_MOD_DATA)
|
||||
|
||||
def test_ptr_from_host_creation(self):
|
||||
"""
|
||||
Test scenario for RHBZ 2009114 - a PTR record is created correctly
|
||||
with trailing dot when navigated to DNS Records page from host details
|
||||
page.
|
||||
"""
|
||||
self.init_app()
|
||||
|
||||
zone = "ptrzone.test."
|
||||
reverse_zone = "12.168.192.in-addr.arpa."
|
||||
hostname = "server"
|
||||
fqdn = "server.ptrzone.test"
|
||||
dns_fqdn = fqdn + "."
|
||||
ip = "192.168.12.20"
|
||||
zone_add_data = {
|
||||
"add": [
|
||||
("textbox", "idnsname", zone),
|
||||
],
|
||||
}
|
||||
reverse_zone_add_data = {
|
||||
"add": [
|
||||
("radio", "dnszone_name_type", "name_from_ip"),
|
||||
("textbox", "name_from_ip", ip + "/24"),
|
||||
],
|
||||
}
|
||||
record_add_data = {
|
||||
"add": [
|
||||
("textbox", "idnsname", "server"),
|
||||
("textbox", "a_part_ip_address", ip),
|
||||
]
|
||||
}
|
||||
host_add_data = {
|
||||
"add": [
|
||||
("textbox", "hostname", hostname),
|
||||
("combobox", "dnszone", zone),
|
||||
],
|
||||
}
|
||||
|
||||
# Create needed DNS zones and record
|
||||
self.add_record(ZONE_ENTITY, zone_add_data, navigate=True)
|
||||
self.add_record(ZONE_ENTITY, reverse_zone_add_data, navigate=False)
|
||||
self.navigate_to_record(zone)
|
||||
self.add_record(ZONE_ENTITY, record_add_data,
|
||||
facet=ZONE_DEFAULT_FACET)
|
||||
|
||||
# Create host record
|
||||
self.navigate_by_menu("identity/host")
|
||||
self.add_record("host", host_add_data, navigate=False)
|
||||
self.navigate_to_record(fqdn)
|
||||
self.click_on_link(fqdn)
|
||||
self.wait_for_request(n=2, d=0.5)
|
||||
self.assert_facet(RECORD_ENTITY, "details")
|
||||
self.click_on_link(ip)
|
||||
self.wait_for_request(n=2, d=0.5)
|
||||
self.assert_dialog()
|
||||
self.click_on_link("Create dns record")
|
||||
self.wait_for_request(n=3, d=0.5)
|
||||
self.assert_facet(RECORD_ENTITY, "details")
|
||||
self.assert_record(dns_fqdn, table_name="ptrrecord")
|
||||
|
||||
# Cleanup
|
||||
self.navigate_to_entity(ZONE_ENTITY)
|
||||
self.delete_record([zone, reverse_zone])
|
||||
self.navigate_to_entity("host")
|
||||
self.delete_record([fqdn])
|
||||
@@ -297,8 +297,13 @@ class test_range(range_tasks):
|
||||
|
||||
# Without primary and secondary RID bases
|
||||
data = self.get_data(pkey, base_rid='', secondary_base_rid='')
|
||||
self.add_record(ENTITY, data, navigate=False)
|
||||
self.delete_record(pkey)
|
||||
self.add_record(ENTITY, data, navigate=False, negative=True)
|
||||
try:
|
||||
assert self.has_form_error('ipabaserid')
|
||||
finally:
|
||||
self.delete_record(pkey)
|
||||
|
||||
self.dialog_button_click('cancel')
|
||||
|
||||
@screenshot
|
||||
def test_modify_range_with_invalid_or_missing_values(self):
|
||||
|
||||
@@ -356,6 +356,7 @@ class test_selinuxusermap(UI_driver):
|
||||
self.fill_fields(selinuxmap.DATA['mod'], undo=True)
|
||||
self.click_on_link('SELinux User Maps')
|
||||
self.dialog_button_click('save')
|
||||
self.close_notifications()
|
||||
self.navigate_to_record(selinuxmap.PKEY)
|
||||
self.verify_btn_action(mod_description, negative=True)
|
||||
self.wait_for_request(n=2)
|
||||
|
||||
@@ -192,7 +192,7 @@ class UI_driver:
|
||||
if not NO_YAML and os.path.isfile(path):
|
||||
try:
|
||||
with open(path, 'r') as conf:
|
||||
cls.config = yaml.load(conf)
|
||||
cls.config = yaml.load(stream=conf, Loader=yaml.FullLoader)
|
||||
except yaml.YAMLError as e:
|
||||
pytest.skip("Invalid Web UI config.\n%s" % e)
|
||||
except IOError as e:
|
||||
@@ -1057,7 +1057,7 @@ class UI_driver:
|
||||
|
||||
# Chrome does not close search area on click
|
||||
if list_cnt.is_displayed():
|
||||
self.driver.switch_to_active_element().send_keys(Keys.RETURN)
|
||||
self.driver.switch_to.active_element.send_keys(Keys.RETURN)
|
||||
|
||||
self.wait()
|
||||
|
||||
@@ -1441,10 +1441,6 @@ class UI_driver:
|
||||
|
||||
last_element = data[len(data) - 1]
|
||||
|
||||
pkeys = []
|
||||
|
||||
for record in data:
|
||||
pkeys.append(record['pkey'])
|
||||
if navigate:
|
||||
self.navigate_to_entity(entity, facet)
|
||||
|
||||
|
||||
@@ -2,55 +2,10 @@
|
||||
#
|
||||
# Copyright (C) 2016 FreeIPA Contributors see COPYING for license
|
||||
#
|
||||
from contextlib import contextmanager
|
||||
import six
|
||||
|
||||
from ipalib import api
|
||||
from ipatests.util import MockLDAP
|
||||
|
||||
trust_container_dn = "cn=ad,cn=trusts,{basedn}".format(
|
||||
basedn=api.env.basedn)
|
||||
trust_container_add = dict(
|
||||
objectClass=[b"nsContainer", b"top"]
|
||||
)
|
||||
|
||||
smb_cont_dn = "{cifsdomains},{basedn}".format(
|
||||
cifsdomains=api.env.container_cifsdomains,
|
||||
basedn=api.env.basedn)
|
||||
smb_cont_add = dict(
|
||||
objectClass=[b"nsContainer", b"top"]
|
||||
)
|
||||
|
||||
|
||||
def create_mock_trust_containers():
|
||||
with MockLDAP() as ldap:
|
||||
ldap.add_entry(trust_container_dn, trust_container_add)
|
||||
ldap.add_entry(smb_cont_dn, smb_cont_add)
|
||||
|
||||
|
||||
def remove_mock_trust_containers():
|
||||
with MockLDAP() as ldap:
|
||||
ldap.del_entry(trust_container_dn)
|
||||
ldap.del_entry(smb_cont_dn)
|
||||
|
||||
|
||||
@contextmanager
|
||||
def mocked_trust_containers():
|
||||
"""Mocked trust containers
|
||||
|
||||
Provides containers for the RPC tests:
|
||||
cn=ad,cn=trusts,BASEDN
|
||||
cn=ad,cn=etc,BASEDN
|
||||
|
||||
Upon exiting, it tries to remove the container entries.
|
||||
If the user of the context manager failed to remove
|
||||
all child entries, exiting the context manager will fail.
|
||||
"""
|
||||
create_mock_trust_containers()
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
remove_mock_trust_containers()
|
||||
|
||||
def get_range_dn(name):
|
||||
format_str = "cn={name},cn=ranges,cn=etc,{basedn}"
|
||||
|
||||
@@ -35,7 +35,7 @@ user_base = [
|
||||
u'ipaSshGroupOfPubKeys',
|
||||
]
|
||||
|
||||
user = user_base + [u'mepOriginEntry']
|
||||
user = user_base + [u'mepOriginEntry', 'ipantuserattrs',]
|
||||
|
||||
group = [
|
||||
u'top',
|
||||
@@ -46,7 +46,7 @@ group = [
|
||||
]
|
||||
|
||||
externalgroup = group + [u'ipaexternalgroup']
|
||||
posixgroup = group + [u'posixgroup']
|
||||
posixgroup = group + [u'posixgroup', 'ipantgroupattrs']
|
||||
|
||||
host = [
|
||||
u'ipasshhost',
|
||||
|
||||
@@ -25,6 +25,7 @@ from ipalib import api
|
||||
from ipatests.test_xmlrpc import objectclasses
|
||||
from ipatests.util import Fuzzy, assert_deepequal
|
||||
from ipatests.test_xmlrpc.xmlrpc_test import (Declarative, fuzzy_digits,
|
||||
fuzzy_set_optional_oc,
|
||||
fuzzy_uuid)
|
||||
from ipapython.dn import DN
|
||||
import pytest
|
||||
@@ -97,7 +98,8 @@ class test_batch(Declarative):
|
||||
result=dict(
|
||||
cn=[group1],
|
||||
description=[u'Test desc 1'],
|
||||
objectclass=objectclasses.group + [u'posixgroup'],
|
||||
objectclass=fuzzy_set_optional_oc(
|
||||
objectclasses.posixgroup, 'ipantgroupattrs'),
|
||||
ipauniqueid=[fuzzy_uuid],
|
||||
gidnumber=[fuzzy_digits],
|
||||
dn=DN(('cn', 'testgroup1'),
|
||||
@@ -168,7 +170,8 @@ class test_batch(Declarative):
|
||||
result=dict(
|
||||
cn=[group1],
|
||||
description=[u'Test desc 1'],
|
||||
objectclass=objectclasses.group + [u'posixgroup'],
|
||||
objectclass=fuzzy_set_optional_oc(
|
||||
objectclasses.posixgroup, 'ipantgroupattrs'),
|
||||
ipauniqueid=[fuzzy_uuid],
|
||||
gidnumber=[fuzzy_digits],
|
||||
dn=DN(('cn', 'testgroup1'),
|
||||
|
||||
@@ -27,7 +27,8 @@ import pytest
|
||||
from ipalib import errors
|
||||
from ipatests.test_xmlrpc import objectclasses
|
||||
from ipatests.test_xmlrpc.xmlrpc_test import (
|
||||
fuzzy_digits, fuzzy_uuid, fuzzy_set_ci, add_oc,
|
||||
fuzzy_digits, fuzzy_uuid, fuzzy_set_ci,
|
||||
fuzzy_user_or_group_sid,
|
||||
XMLRPC_test, raises_exact
|
||||
)
|
||||
from ipatests.test_xmlrpc.tracker.group_plugin import GroupTracker
|
||||
@@ -61,6 +62,8 @@ def managed_group(request, user):
|
||||
tracker.exists = True
|
||||
# Managed group gets created when user is created
|
||||
tracker.track_create()
|
||||
# Managed groups don't have a SID
|
||||
del tracker.attrs['ipantsecurityidentifier']
|
||||
return tracker
|
||||
|
||||
|
||||
@@ -79,7 +82,7 @@ def user_npg2(request, group):
|
||||
del tracker.attrs['mepmanagedentry']
|
||||
tracker.attrs.update(
|
||||
gidnumber=[u'1000'], description=[], memberof_group=[group.cn],
|
||||
objectclass=add_oc(objectclasses.user_base, u'ipantuserattrs')
|
||||
objectclass=objectclasses.user_base + ['ipantuserattrs']
|
||||
)
|
||||
return tracker.make_fixture(request)
|
||||
|
||||
@@ -314,9 +317,9 @@ class TestFindGroup(XMLRPC_test):
|
||||
'gidnumber': [fuzzy_digits],
|
||||
'cn': [u'admins'],
|
||||
'description': [u'Account administrators group'],
|
||||
'objectclass': fuzzy_set_ci(add_oc(
|
||||
objectclasses.posixgroup, u'ipantgroupattrs')),
|
||||
'objectclass': fuzzy_set_ci(objectclasses.posixgroup),
|
||||
'ipauniqueid': [fuzzy_uuid],
|
||||
'ipantsecurityidentifier': [fuzzy_user_or_group_sid],
|
||||
},
|
||||
{
|
||||
'dn': get_group_dn('editors'),
|
||||
@@ -324,27 +327,27 @@ class TestFindGroup(XMLRPC_test):
|
||||
'cn': [u'editors'],
|
||||
'description':
|
||||
[u'Limited admins who can edit other users'],
|
||||
'objectclass': fuzzy_set_ci(add_oc(
|
||||
objectclasses.posixgroup, u'ipantgroupattrs')),
|
||||
'objectclass': fuzzy_set_ci(objectclasses.posixgroup),
|
||||
'ipauniqueid': [fuzzy_uuid],
|
||||
'ipantsecurityidentifier': [fuzzy_user_or_group_sid],
|
||||
},
|
||||
{
|
||||
'dn': get_group_dn(group.cn),
|
||||
'cn': [group.cn],
|
||||
'description': [u'Test desc1'],
|
||||
'gidnumber': [fuzzy_digits],
|
||||
'objectclass': fuzzy_set_ci(add_oc(
|
||||
objectclasses.posixgroup, u'ipantgroupattrs')),
|
||||
'objectclass': fuzzy_set_ci(objectclasses.posixgroup),
|
||||
'ipauniqueid': [fuzzy_uuid],
|
||||
'ipantsecurityidentifier': [fuzzy_user_or_group_sid],
|
||||
},
|
||||
{
|
||||
'dn': get_group_dn(group2.cn),
|
||||
'cn': [group2.cn],
|
||||
'description': [u'Test desc2'],
|
||||
'gidnumber': [fuzzy_digits],
|
||||
'objectclass': fuzzy_set_ci(add_oc(
|
||||
objectclasses.posixgroup, u'ipantgroupattrs')),
|
||||
'objectclass': fuzzy_set_ci(objectclasses.posixgroup),
|
||||
'ipauniqueid': [fuzzy_uuid],
|
||||
'ipantsecurityidentifier': [fuzzy_user_or_group_sid],
|
||||
},
|
||||
]), result)
|
||||
|
||||
@@ -498,6 +501,8 @@ class TestExternalGroup(XMLRPC_test):
|
||||
group.track_create()
|
||||
del group.attrs['gidnumber']
|
||||
group.attrs.update(objectclass=objectclasses.externalgroup)
|
||||
# External group don't have a SID
|
||||
del group.attrs['ipantsecurityidentifier']
|
||||
command = group.make_create_command(**dict(external=True))
|
||||
result = command()
|
||||
group.check_create(result)
|
||||
|
||||
@@ -27,7 +27,8 @@ import six
|
||||
|
||||
from ipalib import api, errors
|
||||
from ipatests.test_xmlrpc import objectclasses
|
||||
from ipatests.test_xmlrpc.xmlrpc_test import (Declarative, uuid_re, add_oc,
|
||||
from ipatests.test_xmlrpc.xmlrpc_test import (Declarative, uuid_re,
|
||||
fuzzy_set_optional_oc,
|
||||
fuzzy_uuid, fuzzy_digits)
|
||||
from ipatests.test_xmlrpc.test_user_plugin import get_user_result
|
||||
from ipatests.test_xmlrpc.test_group_plugin import get_group_dn
|
||||
@@ -216,10 +217,8 @@ class test_idviews(Declarative):
|
||||
u'Test',
|
||||
u'User1',
|
||||
'add',
|
||||
objectclass=add_oc(
|
||||
objectclasses.user,
|
||||
u'ipantuserattrs'
|
||||
)
|
||||
objectclass=fuzzy_set_optional_oc(
|
||||
objectclasses.user, 'ipantuserattrs'),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -237,7 +236,8 @@ class test_idviews(Declarative):
|
||||
result=dict(
|
||||
cn=[idoverridegroup1],
|
||||
description=[u'Test desc 1'],
|
||||
objectclass=objectclasses.posixgroup,
|
||||
objectclass=fuzzy_set_optional_oc(
|
||||
objectclasses.posixgroup, 'ipantgroupattrs'),
|
||||
ipauniqueid=[fuzzy_uuid],
|
||||
gidnumber=[fuzzy_digits],
|
||||
dn=get_group_dn(idoverridegroup1),
|
||||
@@ -1624,10 +1624,8 @@ class test_idviews(Declarative):
|
||||
u'Removed',
|
||||
u'User',
|
||||
'add',
|
||||
objectclass=add_oc(
|
||||
objectclasses.user,
|
||||
u'ipantuserattrs'
|
||||
)
|
||||
objectclass=fuzzy_set_optional_oc(
|
||||
objectclasses.user, 'ipantuserattrs'),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -1645,7 +1643,8 @@ class test_idviews(Declarative):
|
||||
result=dict(
|
||||
cn=[idoverridegroup_removed],
|
||||
description=[u'Removed group'],
|
||||
objectclass=objectclasses.posixgroup,
|
||||
objectclass=fuzzy_set_optional_oc(
|
||||
objectclasses.posixgroup, 'ipantgroupattrs'),
|
||||
ipauniqueid=[fuzzy_uuid],
|
||||
gidnumber=[fuzzy_digits],
|
||||
dn=get_group_dn(idoverridegroup_removed),
|
||||
|
||||
@@ -19,7 +19,7 @@ from ipatests.test_xmlrpc.tracker.host_plugin import HostTracker
|
||||
from ipatests.test_xmlrpc.tracker.service_plugin import ServiceTracker
|
||||
from ipatests.test_xmlrpc.tracker.stageuser_plugin import StageUserTracker
|
||||
from ipatests.test_xmlrpc.mock_trust import (
|
||||
mocked_trust_containers, get_trust_dn, get_trusted_dom_dict,
|
||||
get_trust_dn, get_trusted_dom_dict,
|
||||
encode_mockldap_value)
|
||||
from ipatests.util import unlock_principal_password, change_principal
|
||||
|
||||
@@ -62,7 +62,7 @@ def trusted_domain():
|
||||
trusted_dom = TRUSTED_DOMAIN_MOCK
|
||||
|
||||
# Write the changes
|
||||
with mocked_trust_containers(), MockLDAP() as ldap:
|
||||
with MockLDAP() as ldap:
|
||||
ldap.add_entry(trusted_dom['dn'], trusted_dom['ldif'])
|
||||
yield trusted_dom
|
||||
ldap.del_entry(trusted_dom['dn'])
|
||||
@@ -83,7 +83,7 @@ def trusted_domain_with_suffix():
|
||||
)
|
||||
|
||||
# Write the changes
|
||||
with mocked_trust_containers(), MockLDAP() as ldap:
|
||||
with MockLDAP() as ldap:
|
||||
ldap.add_entry(trusted_dom['dn'], trusted_dom['ldif'])
|
||||
yield trusted_dom
|
||||
ldap.del_entry(trusted_dom['dn'])
|
||||
|
||||
@@ -24,6 +24,7 @@ Test the `ipaserver/plugins/netgroup.py` module.
|
||||
from ipalib import api
|
||||
from ipalib import errors
|
||||
from ipatests.test_xmlrpc.xmlrpc_test import (Declarative, fuzzy_digits,
|
||||
fuzzy_set_optional_oc,
|
||||
fuzzy_uuid, fuzzy_netgroupdn)
|
||||
from ipatests.test_xmlrpc import objectclasses
|
||||
from ipapython.dn import DN
|
||||
@@ -300,7 +301,8 @@ class test_netgroup(Declarative):
|
||||
cn=[group1],
|
||||
description=[u'Test desc 1'],
|
||||
gidnumber=[fuzzy_digits],
|
||||
objectclass=objectclasses.group + [u'posixgroup'],
|
||||
objectclass=fuzzy_set_optional_oc(
|
||||
objectclasses.posixgroup, 'ipantgroupattrs'),
|
||||
ipauniqueid=[fuzzy_uuid],
|
||||
dn=DN(('cn',group1),('cn','groups'),('cn','accounts'),
|
||||
api.env.basedn),
|
||||
|
||||
@@ -502,6 +502,7 @@ class test_range(Declarative):
|
||||
user1, u'Test', u'User1', 'add',
|
||||
uidnumber=[unicode(user1_uid)],
|
||||
gidnumber=[unicode(user1_uid)],
|
||||
objectclass=objectclasses.user_base + [u'mepOriginEntry'],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -8,22 +8,24 @@ Test the `ipaserver/plugins/schema.py` module.
|
||||
|
||||
import pytest
|
||||
|
||||
from ipalib import errors
|
||||
from ipatests.test_xmlrpc.tracker.base import Tracker
|
||||
from ipalib import api, errors
|
||||
from ipapython.dnsutil import DNSName
|
||||
from ipatests.test_xmlrpc.xmlrpc_test import XMLRPC_test
|
||||
|
||||
|
||||
@pytest.mark.tier1
|
||||
class TestParamFindAndShowCommand(XMLRPC_test):
|
||||
"""Test functionality of the ipa param-{find,show} command"""
|
||||
|
||||
tracker = Tracker()
|
||||
def run_command(self, command, *args, **options):
|
||||
cmd = api.Command[command]
|
||||
cmd_result = cmd(*args, **options)
|
||||
return cmd_result
|
||||
|
||||
def test_param_find(self):
|
||||
"""Test param-find command"""
|
||||
|
||||
cmd = "param_find"
|
||||
# right command without criteria
|
||||
result = self.tracker.run_command('param_find', u'user-add')
|
||||
result = self.run_command(cmd, "user-add")
|
||||
assert len(result['result']) != 0, result
|
||||
assert result['result'][0]['name'] == 'uid', result
|
||||
assert result['result'][0]['cli_name'] == 'login', result
|
||||
@@ -31,26 +33,30 @@ class TestParamFindAndShowCommand(XMLRPC_test):
|
||||
|
||||
# right command, right criteria
|
||||
criteria = u'postalcode'
|
||||
result = self.tracker.run_command('param_find', u'user-add', criteria)
|
||||
result = self.run_command(cmd, "user-add", criteria)
|
||||
assert len(result['result']) != 0, result
|
||||
for item in result['result']:
|
||||
assert (criteria in item['name'].lower() or
|
||||
criteria in item['doc'].lower()), item
|
||||
|
||||
# right command, wrong criteria
|
||||
result = self.tracker.run_command('param_find', u'user-add', u'fake')
|
||||
result = self.run_command(cmd, "user-add", "fake")
|
||||
assert len(result['result']) == 0, result
|
||||
|
||||
# wrong command, wrong criteria
|
||||
result = self.tracker.run_command('param_find', u'fake', u'fake')
|
||||
result = self.run_command(cmd, "fake", "fake")
|
||||
assert len(result['result']) == 0, result
|
||||
|
||||
# too many args
|
||||
with pytest.raises(errors.MaxArgumentError):
|
||||
self.run_command(cmd, "arg1", "arg2", "arg3")
|
||||
|
||||
def test_param_show(self):
|
||||
"""Test param-show command"""
|
||||
|
||||
# right command, right criteria
|
||||
criteria = u'uid'
|
||||
result = self.tracker.run_command('param_show', u'user-add', criteria)
|
||||
criteria = "uid"
|
||||
cmd = "param_show"
|
||||
result = self.run_command(cmd, "user-add", criteria)
|
||||
assert result['result'] is not None, result
|
||||
assert result['result']['name'] == 'uid', result
|
||||
assert result['result']['cli_name'] == 'login', result
|
||||
@@ -58,26 +64,33 @@ class TestParamFindAndShowCommand(XMLRPC_test):
|
||||
|
||||
# right command without criteria
|
||||
with pytest.raises(errors.RequirementError):
|
||||
self.tracker.run_command('param_show', u'user-add')
|
||||
self.run_command(cmd, "user-add")
|
||||
|
||||
# right command, wrong criteria
|
||||
with pytest.raises(errors.NotFound):
|
||||
self.tracker.run_command('param_show', u'user-add', u'fake')
|
||||
self.run_command(cmd, "user-add", "fake")
|
||||
|
||||
# wrong command, wrong criteria
|
||||
with pytest.raises(errors.NotFound):
|
||||
self.tracker.run_command('param_show', u'fake', u'fake')
|
||||
self.run_command(cmd, "fake", "fake")
|
||||
|
||||
# too many args
|
||||
with pytest.raises(errors.MaxArgumentError):
|
||||
self.run_command(cmd, "arg1", "arg2", "arg3")
|
||||
|
||||
|
||||
class TestOutputFindAndShowCommand(XMLRPC_test):
|
||||
"""Test functionality of the ipa output-{find,show} command"""
|
||||
tracker = Tracker()
|
||||
def run_command(self, command, *args, **options):
|
||||
cmd = api.Command[command]
|
||||
cmd_result = cmd(*args, **options)
|
||||
return cmd_result
|
||||
|
||||
def test_output_find(self):
|
||||
"""Test output-find command"""
|
||||
|
||||
cmd = "output_find"
|
||||
# right command without criteria
|
||||
result = self.tracker.run_command('output_find', u'user-add')
|
||||
result = self.run_command(cmd, "user-add")
|
||||
assert len(result['result']) != 0, result
|
||||
assert result['result'][0]['name'] == 'summary', result
|
||||
assert result['result'][0]['doc'] == \
|
||||
@@ -85,24 +98,29 @@ class TestOutputFindAndShowCommand(XMLRPC_test):
|
||||
|
||||
# right command, right criteria
|
||||
criteria = u'result'
|
||||
result = self.tracker.run_command('output_find', u'user-add', criteria)
|
||||
result = self.run_command(cmd, "user-add", criteria)
|
||||
assert len(result['result']) == 1, result
|
||||
assert criteria in result['result'][0]['name'].lower(), result
|
||||
|
||||
# right command, wrong criteria
|
||||
result = self.tracker.run_command('output_find', u'user-add', u'fake')
|
||||
result = self.run_command(cmd, "user-add", "fake")
|
||||
assert len(result['result']) == 0, result
|
||||
|
||||
# wrong command, wrong criteria
|
||||
result = self.tracker.run_command('output_find', u'fake', u'fake')
|
||||
result = self.run_command(cmd, "fake", "fake")
|
||||
assert len(result['result']) == 0, result
|
||||
|
||||
# too many args
|
||||
with pytest.raises(errors.MaxArgumentError):
|
||||
self.run_command(cmd, "arg1", "arg2", "arg3")
|
||||
|
||||
def test_output_show(self):
|
||||
"""Test output-show command"""
|
||||
|
||||
# right command, right criteria
|
||||
criteria = u'value'
|
||||
result = self.tracker.run_command('output_show', u'user-add', criteria)
|
||||
criteria = "value"
|
||||
cmd = "output_show"
|
||||
result = self.run_command(cmd, "user-add", criteria)
|
||||
assert len(result['result']) != 0, result
|
||||
assert criteria in result['result']['name'].lower(), result
|
||||
assert result['result']['doc'] == \
|
||||
@@ -110,12 +128,329 @@ class TestOutputFindAndShowCommand(XMLRPC_test):
|
||||
|
||||
# right command without criteria
|
||||
with pytest.raises(errors.RequirementError):
|
||||
self.tracker.run_command('output_show', u'user-add')
|
||||
self.run_command(cmd, "user-add")
|
||||
|
||||
# right command, wrong criteria
|
||||
with pytest.raises(errors.NotFound):
|
||||
self.tracker.run_command('output_show', u'user-add', u'fake')
|
||||
self.run_command(cmd, "user-add", "fake")
|
||||
|
||||
# wrong command, wrong criteria
|
||||
with pytest.raises(errors.NotFound):
|
||||
self.tracker.run_command('output_show', u'fake', u'fake')
|
||||
self.run_command(cmd, "fake", "fake")
|
||||
|
||||
# too many args
|
||||
with pytest.raises(errors.MaxArgumentError):
|
||||
self.run_command(cmd, "arg1", "arg2", "arg3")
|
||||
|
||||
|
||||
class TestSchemaCommand(XMLRPC_test):
|
||||
"""Test functionality of the ipa schema Command(no cli)"""
|
||||
expected_keys = {
|
||||
"classes", "commands", "fingerprint", "topics", "ttl", "version"
|
||||
}
|
||||
|
||||
def run_command(self, command, *args, **options):
|
||||
cmd = api.Command[command]
|
||||
cmd_result = cmd(*args, **options)
|
||||
return cmd_result
|
||||
|
||||
def test_schema_no_args(self):
|
||||
"""Test schema command without any args"""
|
||||
cmd_result = self.run_command("schema")
|
||||
result = cmd_result["result"]
|
||||
assert result.keys() == self.expected_keys
|
||||
|
||||
def test_schema_known_valid_fp(self):
|
||||
"""Test schema command with valid fingerprint"""
|
||||
# first, fetch current FP to reuse it
|
||||
cmd_result = self.run_command("schema")
|
||||
result = cmd_result["result"]
|
||||
fp_valid = result["fingerprint"]
|
||||
|
||||
with pytest.raises(errors.SchemaUpToDate):
|
||||
self.run_command("schema", known_fingerprints=(fp_valid,))
|
||||
|
||||
def test_schema_known_wrong_fp(self):
|
||||
"""Test schema command with wrong fingerprint"""
|
||||
fp_wrong = "wrong FP"
|
||||
cmd_result = self.run_command("schema", known_fingerprints=(fp_wrong,))
|
||||
result = cmd_result["result"]
|
||||
assert result.keys() == self.expected_keys
|
||||
|
||||
def test_schema_too_many_args(self):
|
||||
"""Test schema with too many args"""
|
||||
with pytest.raises(errors.ZeroArgumentError):
|
||||
self.run_command("schema", "arg1")
|
||||
|
||||
|
||||
class TestCommandCommand(XMLRPC_test):
|
||||
"""Test functionality of the ipa 'command' command"""
|
||||
expected_keys = {
|
||||
"doc",
|
||||
"full_name",
|
||||
"name",
|
||||
"topic_topic",
|
||||
"version",
|
||||
}
|
||||
|
||||
def run_command(self, command, *args, **options):
|
||||
cmd = api.Command[command]
|
||||
cmd_result = cmd(*args, **options)
|
||||
return cmd_result
|
||||
|
||||
def test_command_find_all(self):
|
||||
"""Test command-find without any args"""
|
||||
cmd_result = self.run_command("command_find")
|
||||
result = cmd_result["result"]
|
||||
assert len(result) != 0, result
|
||||
for item in result:
|
||||
assert self.expected_keys.issubset(item.keys()), item
|
||||
|
||||
def test_command_find_existent_command(self):
|
||||
"""Test 'command' with existent command as arg"""
|
||||
criteria = "user_add"
|
||||
cmd_result = self.run_command("command_find", criteria)
|
||||
result = cmd_result["result"]
|
||||
assert len(result) != 0, result
|
||||
for item in result:
|
||||
assert self.expected_keys.issubset(item.keys()), item
|
||||
name = item["name"].lower()
|
||||
doc = item.get("doc", "").lower()
|
||||
assert criteria in name or criteria in doc, item
|
||||
|
||||
def test_command_find_nonexistent_command(self):
|
||||
"""Test command-find with nonexistent command as arg"""
|
||||
cmd_result = self.run_command("command_find", "nonextentcommand")
|
||||
result = cmd_result["result"]
|
||||
assert len(result) == 0, result
|
||||
|
||||
def test_command_find_too_many_args(self):
|
||||
"""Test command-find with too many args"""
|
||||
with pytest.raises(errors.MaxArgumentError):
|
||||
self.run_command("command_find", "arg1", "arg2")
|
||||
|
||||
def test_command_show_no_args(self):
|
||||
"""Test command-show without args"""
|
||||
with pytest.raises(errors.RequirementError):
|
||||
self.run_command("command_show")
|
||||
|
||||
def test_command_show_existent_command(self):
|
||||
"""Test command-show with existent command as arg"""
|
||||
criteria = "user_add"
|
||||
cmd_result = self.run_command("command_show", criteria)
|
||||
result = cmd_result["result"]
|
||||
assert self.expected_keys.issubset(result.keys()), result
|
||||
assert result["name"] == criteria
|
||||
|
||||
def test_command_show_nonexistent_command(self):
|
||||
"""Test command-show with nonexistent command as arg"""
|
||||
with pytest.raises(errors.NotFound):
|
||||
self.run_command("command_show", "nonextentcommand")
|
||||
|
||||
def test_command_show_too_many_args(self):
|
||||
"""Test command-show with too many args"""
|
||||
with pytest.raises(errors.MaxArgumentError):
|
||||
self.run_command("command_show", "arg1", "arg2")
|
||||
|
||||
def test_command_defaults_no_args(self):
|
||||
"""Test command_defaults without args"""
|
||||
with pytest.raises(errors.RequirementError):
|
||||
self.run_command("command_defaults")
|
||||
|
||||
def test_command_defaults_existent_command(self):
|
||||
"""Test command_defaults with existent command as arg"""
|
||||
criteria = "user_add"
|
||||
cmd_result = self.run_command("command_defaults", criteria)
|
||||
# 9c19dd350: do not validate unrequested params in command_defaults
|
||||
result = cmd_result["result"]
|
||||
assert len(result) == 0, result
|
||||
|
||||
def test_command_defaults_existent_command_params(self):
|
||||
"""Test command_defaults with existent command as arg with params"""
|
||||
criteria = "user_add"
|
||||
params = ["all"]
|
||||
cmd_result = self.run_command(
|
||||
"command_defaults", criteria, params=params
|
||||
)
|
||||
result = cmd_result["result"]
|
||||
assert len(result) == len(params), result
|
||||
assert isinstance(result["all"], bool)
|
||||
|
||||
def test_command_defaults_existent_command_several_params(self):
|
||||
"""
|
||||
Test command_defaults with existent command as arg with several params
|
||||
"""
|
||||
criteria = "user_add"
|
||||
params = ["all", "raw"]
|
||||
cmd_result = self.run_command(
|
||||
"command_defaults", criteria, params=params
|
||||
)
|
||||
result = cmd_result["result"]
|
||||
assert len(result) == len(params), result
|
||||
assert isinstance(result["all"], bool), result
|
||||
assert isinstance(result["raw"], bool), result
|
||||
|
||||
def test_command_defaults_existent_command_kw(self):
|
||||
"""Test command_defaults with existent command as arg with kw"""
|
||||
criteria = "dnszone_add"
|
||||
params = ["idnsname"]
|
||||
kw = {"name_from_ip": "127.0.0.1"}
|
||||
cmd_result = self.run_command(
|
||||
"command_defaults", criteria, params=params
|
||||
)
|
||||
result = cmd_result["result"]
|
||||
assert len(result) == 0, result
|
||||
|
||||
cmd_result = self.run_command(
|
||||
"command_defaults", criteria, params=params, kw=kw
|
||||
)
|
||||
result = cmd_result["result"]
|
||||
assert len(result) == len(params), result
|
||||
assert isinstance(result["idnsname"], DNSName)
|
||||
|
||||
def test_command_defaults_nonexistent_command(self):
|
||||
"""Test command-show with nonexistent command as arg"""
|
||||
with pytest.raises(errors.NotFound):
|
||||
self.run_command("command_defaults", "nonextentcommand")
|
||||
|
||||
def test_command_defaults_too_many_args(self):
|
||||
"""Test command-show with too many args"""
|
||||
with pytest.raises(errors.MaxArgumentError):
|
||||
self.run_command("command_defaults", "arg1", "arg2")
|
||||
|
||||
|
||||
class TestClassCommand(XMLRPC_test):
|
||||
"""Test functionality of the ipa 'class' command"""
|
||||
expected_keys = {
|
||||
"name",
|
||||
"full_name",
|
||||
"version",
|
||||
}
|
||||
|
||||
def run_command(self, command, *args, **options):
|
||||
cmd = api.Command[command]
|
||||
cmd_result = cmd(*args, **options)
|
||||
return cmd_result
|
||||
|
||||
def test_class_find_all(self):
|
||||
"""Test class-find without any args"""
|
||||
cmd_result = self.run_command("class_find")
|
||||
result = cmd_result["result"]
|
||||
assert len(result) != 0, result
|
||||
for item in result:
|
||||
assert item.keys() == self.expected_keys, item
|
||||
|
||||
def test_class_find_existent_class(self):
|
||||
"""Test class-find with existent class as arg"""
|
||||
criteria = "user"
|
||||
cmd_result = self.run_command("class_find", criteria)
|
||||
result = cmd_result["result"]
|
||||
assert len(result) != 0, result
|
||||
for item in result:
|
||||
assert item.keys() == self.expected_keys, item
|
||||
name = item["name"].lower()
|
||||
doc = item.get("doc", "").lower()
|
||||
assert criteria in name or criteria in doc, item
|
||||
|
||||
def test_class_find_nonexistent_class(self):
|
||||
"""Test class-find with nonexistent class as arg"""
|
||||
cmd_result = self.run_command("class_find", "nonextentclass")
|
||||
result = cmd_result["result"]
|
||||
assert len(result) == 0, result
|
||||
|
||||
def test_class_find_too_many_args(self):
|
||||
"""Test class-find with too many args"""
|
||||
with pytest.raises(errors.MaxArgumentError):
|
||||
self.run_command("class_find", "arg1", "arg2")
|
||||
|
||||
def test_class_show_no_args(self):
|
||||
"""Test class-show without args"""
|
||||
with pytest.raises(errors.RequirementError):
|
||||
self.run_command("class_show")
|
||||
|
||||
def test_class_show_existent_class(self):
|
||||
"""Test class-show with existent class as arg"""
|
||||
criteria = "user"
|
||||
cmd_result = self.run_command("class_show", criteria)
|
||||
result = cmd_result["result"]
|
||||
assert result.keys() == self.expected_keys, result
|
||||
assert result["name"] == criteria
|
||||
|
||||
def test_class_show_nonexistent_class(self):
|
||||
"""Test class-show with nonexistent class as arg"""
|
||||
with pytest.raises(errors.NotFound):
|
||||
self.run_command("class_show", "nonextentclass")
|
||||
|
||||
def test_class_show_too_many_args(self):
|
||||
"""Test class-show with too many args"""
|
||||
with pytest.raises(errors.MaxArgumentError):
|
||||
self.run_command("class_show", "arg1", "arg2")
|
||||
|
||||
|
||||
class TestTopicCommand(XMLRPC_test):
|
||||
"""Test functionality of the ipa 'topic' command"""
|
||||
expected_keys = {
|
||||
"name",
|
||||
"full_name",
|
||||
"version",
|
||||
"doc",
|
||||
}
|
||||
|
||||
def run_command(self, command, *args, **options):
|
||||
cmd = api.Command[command]
|
||||
cmd_result = cmd(*args, **options)
|
||||
return cmd_result
|
||||
|
||||
def test_topic_find_all(self):
|
||||
"""Test topic-find without any args"""
|
||||
cmd_result = self.run_command("topic_find")
|
||||
result = cmd_result["result"]
|
||||
assert len(result) != 0, result
|
||||
for item in result:
|
||||
assert self.expected_keys.issubset(item.keys()), item
|
||||
|
||||
def test_topic_find_existent_topic(self):
|
||||
"""Test topic-find with existent topic as arg"""
|
||||
criteria = "user"
|
||||
cmd_result = self.run_command("topic_find", criteria)
|
||||
result = cmd_result["result"]
|
||||
assert len(result) != 0, result
|
||||
for item in result:
|
||||
assert self.expected_keys.issubset(item.keys()), item
|
||||
name = item["name"].lower()
|
||||
doc = item.get("doc", "").lower()
|
||||
assert criteria in name or criteria in doc, item
|
||||
|
||||
def test_topic_find_nonexistent_topic(self):
|
||||
"""Test topic-find with nonexistent topic as arg"""
|
||||
cmd_result = self.run_command("topic_find", "nonextenttopic")
|
||||
result = cmd_result["result"]
|
||||
assert len(result) == 0, result
|
||||
|
||||
def test_topic_find_too_many_args(self):
|
||||
"""Test topic-find with too many args"""
|
||||
with pytest.raises(errors.MaxArgumentError):
|
||||
self.run_command("topic_find", "arg1", "arg2")
|
||||
|
||||
def test_topic_show_no_args(self):
|
||||
"""Test topic-show without args"""
|
||||
with pytest.raises(errors.RequirementError):
|
||||
self.run_command("topic_show")
|
||||
|
||||
def test_topic_show_existent_topic(self):
|
||||
"""Test topic-show with existent topic as arg"""
|
||||
criteria = "user"
|
||||
cmd_result = self.run_command("topic_show", criteria)
|
||||
result = cmd_result["result"]
|
||||
assert self.expected_keys.issubset(result.keys()), result
|
||||
assert result["name"] == criteria
|
||||
|
||||
def test_topic_show_nonexistent_topic(self):
|
||||
"""Test topic-show with nonexistent topic as arg"""
|
||||
with pytest.raises(errors.NotFound):
|
||||
self.run_command("topic_show", "nonextenttopic")
|
||||
|
||||
def test_topic_show_too_many_args(self):
|
||||
"""Test topic-show with too many args"""
|
||||
with pytest.raises(errors.MaxArgumentError):
|
||||
self.run_command("topic_show", "arg1", "arg2")
|
||||
@@ -25,6 +25,7 @@ from ipaplatform.constants import constants as platformconstants
|
||||
|
||||
from ipatests.test_xmlrpc import objectclasses
|
||||
from ipatests.test_xmlrpc.xmlrpc_test import (Declarative, fuzzy_digits,
|
||||
fuzzy_set_optional_oc,
|
||||
fuzzy_uuid)
|
||||
from ipapython.dn import DN
|
||||
from ipatests.util import Fuzzy
|
||||
@@ -230,7 +231,8 @@ class test_selinuxusermap(Declarative):
|
||||
cn=[group1],
|
||||
description=[u'Test desc 1'],
|
||||
gidnumber=[fuzzy_digits],
|
||||
objectclass=objectclasses.group + [u'posixgroup'],
|
||||
objectclass=fuzzy_set_optional_oc(
|
||||
objectclasses.posixgroup, 'ipantgroupattrs'),
|
||||
ipauniqueid=[fuzzy_uuid],
|
||||
dn=DN(('cn', group1), ('cn', 'groups'), ('cn', 'accounts'),
|
||||
api.env.basedn),
|
||||
|
||||
@@ -25,6 +25,7 @@ from ipalib import api, errors
|
||||
from ipatests.test_xmlrpc.xmlrpc_test import Declarative, fuzzy_uuid, fuzzy_hash
|
||||
from ipatests.test_xmlrpc.xmlrpc_test import fuzzy_digits, fuzzy_date, fuzzy_issuer
|
||||
from ipatests.test_xmlrpc.xmlrpc_test import fuzzy_hex, XMLRPC_test
|
||||
from ipatests.test_xmlrpc.xmlrpc_test import fuzzy_set_optional_oc
|
||||
from ipatests.test_xmlrpc.xmlrpc_test import raises_exact
|
||||
from ipatests.test_xmlrpc import objectclasses
|
||||
from ipatests.test_xmlrpc.testcert import get_testcert, subject_base
|
||||
@@ -1113,7 +1114,8 @@ class test_service_allowed_to(Declarative):
|
||||
summary=u'Added group "%s"' % group1,
|
||||
result=dict(
|
||||
cn=[group1],
|
||||
objectclass=objectclasses.group + [u'posixgroup'],
|
||||
objectclass=fuzzy_set_optional_oc(
|
||||
objectclasses.posixgroup, 'ipantgroupattrs'),
|
||||
ipauniqueid=[fuzzy_uuid],
|
||||
gidnumber=[fuzzy_digits],
|
||||
dn=group1_dn
|
||||
@@ -1165,7 +1167,8 @@ class test_service_allowed_to(Declarative):
|
||||
summary=u'Added group "%s"' % group2,
|
||||
result=dict(
|
||||
cn=[group2],
|
||||
objectclass=objectclasses.group + [u'posixgroup'],
|
||||
objectclass=fuzzy_set_optional_oc(
|
||||
objectclasses.posixgroup, 'ipantgroupattrs'),
|
||||
ipauniqueid=[fuzzy_uuid],
|
||||
gidnumber=[fuzzy_digits],
|
||||
dn=group2_dn
|
||||
|
||||
@@ -27,6 +27,7 @@ from ipapython.dn import DN
|
||||
from ipatests.test_xmlrpc import objectclasses
|
||||
from ipatests.test_xmlrpc.xmlrpc_test import (
|
||||
Declarative, fuzzy_guid, fuzzy_domain_sid, fuzzy_string, fuzzy_uuid,
|
||||
fuzzy_set_optional_oc,
|
||||
fuzzy_digits)
|
||||
import pytest
|
||||
|
||||
@@ -110,7 +111,8 @@ class test_trustconfig(Declarative):
|
||||
cn=[testgroup],
|
||||
description=[u'Test group'],
|
||||
gidnumber=[fuzzy_digits],
|
||||
objectclass=objectclasses.group + [u'posixgroup'],
|
||||
objectclass=fuzzy_set_optional_oc(
|
||||
objectclasses.posixgroup, 'ipantgroupattrs'),
|
||||
ipauniqueid=[fuzzy_uuid],
|
||||
dn=testgroup_dn,
|
||||
),
|
||||
|
||||
@@ -38,7 +38,8 @@ from ipatests.util import (
|
||||
assert_deepequal, assert_equal, assert_not_equal, raises)
|
||||
from ipatests.test_xmlrpc.xmlrpc_test import (
|
||||
XMLRPC_test, fuzzy_digits, fuzzy_uuid, fuzzy_password,
|
||||
Fuzzy, fuzzy_dergeneralizedtime, add_sid, add_oc, raises_exact)
|
||||
fuzzy_user_or_group_sid, fuzzy_set_optional_oc,
|
||||
Fuzzy, fuzzy_dergeneralizedtime, raises_exact)
|
||||
from ipapython.dn import DN
|
||||
from ipapython.ipaldap import ldap_initialize
|
||||
|
||||
@@ -124,7 +125,7 @@ def user_npg(request, group):
|
||||
del tracker.attrs['mepmanagedentry']
|
||||
tracker.attrs.update(
|
||||
description=[], memberof_group=[group.cn],
|
||||
objectclass=add_oc(objectclasses.user_base, u'ipantuserattrs')
|
||||
objectclass=objectclasses.user_base + [u'ipantuserattrs'],
|
||||
)
|
||||
return tracker.make_fixture(request)
|
||||
|
||||
@@ -138,7 +139,7 @@ def user_npg2(request, group):
|
||||
del tracker.attrs['mepmanagedentry']
|
||||
tracker.attrs.update(
|
||||
gidnumber=[u'1000'], description=[], memberof_group=[group.cn],
|
||||
objectclass=add_oc(objectclasses.user_base, u'ipantuserattrs')
|
||||
objectclass=objectclasses.user_base + [u'ipantuserattrs'],
|
||||
)
|
||||
return tracker.make_fixture(request)
|
||||
|
||||
@@ -645,7 +646,7 @@ class TestCreate(XMLRPC_test):
|
||||
testuser.attrs.update(gidnumber=[u'1000'])
|
||||
testuser.attrs.update(
|
||||
description=[],
|
||||
objectclass=add_oc(objectclasses.user_base, u'ipantuserattrs')
|
||||
objectclass=objectclasses.user_base + [u'ipantuserattrs']
|
||||
)
|
||||
command = testuser.make_create_command()
|
||||
result = command()
|
||||
@@ -659,9 +660,12 @@ class TestCreate(XMLRPC_test):
|
||||
name=u'tuser1', givenname=u'Test', sn=u'Tuser1', uidnumber=999
|
||||
)
|
||||
testuser.track_create()
|
||||
# When uid is outside of IPA id range, no SID is generated
|
||||
del testuser.attrs['ipantsecurityidentifier']
|
||||
testuser.attrs.update(
|
||||
uidnumber=[u'999'],
|
||||
gidnumber=[u'999']
|
||||
gidnumber=[u'999'],
|
||||
objectclass=objectclasses.user_base + ['mepOriginEntry']
|
||||
)
|
||||
command = testuser.make_create_command()
|
||||
result = command()
|
||||
@@ -837,7 +841,7 @@ class TestUserWithUPGDisabled(XMLRPC_test):
|
||||
testuser.attrs.update(gidnumber=[u'1000'])
|
||||
testuser.attrs.update(
|
||||
description=[],
|
||||
objectclass=add_oc(objectclasses.user_base, u'ipantuserattrs')
|
||||
objectclass=objectclasses.user_base + [u'ipantuserattrs'],
|
||||
)
|
||||
command = testuser.make_create_command()
|
||||
result = command()
|
||||
@@ -860,7 +864,7 @@ class TestUserWithUPGDisabled(XMLRPC_test):
|
||||
testuser.attrs.update(gidnumber=[u'1000'])
|
||||
testuser.attrs.update(
|
||||
description=[],
|
||||
objectclass=add_oc(objectclasses.user_base, u'ipantuserattrs')
|
||||
objectclass=objectclasses.user_base + [u'ipantuserattrs'],
|
||||
)
|
||||
command = testuser.make_create_command()
|
||||
result = command()
|
||||
@@ -1147,7 +1151,7 @@ def get_user_result(uid, givenname, sn, operation='show', omit=[],
|
||||
# sn can be None; this should only be used from `get_admin_result`
|
||||
cn = overrides.get('cn', ['%s %s' % (givenname, sn or '')])
|
||||
cn[0] = cn[0].strip()
|
||||
result = add_sid(dict(
|
||||
result = dict(
|
||||
homedirectory=[u'/home/%s' % uid],
|
||||
loginshell=[platformconstants.DEFAULT_SHELL],
|
||||
uid=[uid],
|
||||
@@ -1158,7 +1162,7 @@ def get_user_result(uid, givenname, sn, operation='show', omit=[],
|
||||
mail=[u'%s@%s' % (uid, api.env.domain)],
|
||||
has_keytab=False,
|
||||
has_password=False,
|
||||
))
|
||||
)
|
||||
if sn:
|
||||
result['sn'] = [sn]
|
||||
if givenname:
|
||||
@@ -1175,9 +1179,14 @@ def get_user_result(uid, givenname, sn, operation='show', omit=[],
|
||||
initials=[givenname[0] + (sn or '')[:1]],
|
||||
ipauniqueid=[fuzzy_uuid],
|
||||
mepmanagedentry=[get_group_dn(uid)],
|
||||
objectclass=add_oc(objectclasses.user, u'ipantuserattrs'),
|
||||
objectclass=fuzzy_set_optional_oc(
|
||||
objectclasses.user, 'ipantuserattrs'),
|
||||
krbprincipalname=[u'%s@%s' % (uid, api.env.realm)],
|
||||
krbcanonicalname=[u'%s@%s' % (uid, api.env.realm)]
|
||||
krbcanonicalname=[u'%s@%s' % (uid, api.env.realm)],
|
||||
)
|
||||
if operation == 'show-all':
|
||||
result.update(
|
||||
ipantsecurityidentifier=[fuzzy_user_or_group_sid],
|
||||
)
|
||||
if operation in ('show', 'show-all', 'find', 'mod'):
|
||||
result.update(
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
from ipatests.test_xmlrpc import objectclasses
|
||||
from ipatests.test_xmlrpc.xmlrpc_test import fuzzy_digits, fuzzy_uuid
|
||||
from ipatests.test_xmlrpc.xmlrpc_test import fuzzy_user_or_group_sid
|
||||
from ipatests.test_xmlrpc.xmlrpc_test import fuzzy_set_optional_oc
|
||||
|
||||
from ipatests.test_xmlrpc.tracker.base import Tracker
|
||||
from ipatests.util import assert_deepequal, get_group_dn
|
||||
@@ -21,9 +23,10 @@ class GroupTracker(Tracker):
|
||||
'idoverrideuser'
|
||||
}
|
||||
|
||||
retrieve_all_keys = retrieve_keys | {u'ipauniqueid', u'objectclass'}
|
||||
retrieve_all_keys = retrieve_keys | {u'ipauniqueid', u'objectclass',
|
||||
'ipantsecurityidentifier'}
|
||||
|
||||
create_keys = retrieve_all_keys
|
||||
create_keys = retrieve_all_keys - {u'ipantsecurityidentifier'}
|
||||
update_keys = retrieve_keys - {u'dn'}
|
||||
|
||||
add_member_keys = retrieve_keys | {u'description'}
|
||||
@@ -91,7 +94,9 @@ class GroupTracker(Tracker):
|
||||
description=[self.description],
|
||||
gidnumber=[fuzzy_digits],
|
||||
ipauniqueid=[fuzzy_uuid],
|
||||
objectclass=objectclasses.posixgroup,
|
||||
objectclass=fuzzy_set_optional_oc(
|
||||
objectclasses.posixgroup, 'ipantgroupattrs'),
|
||||
ipantsecurityidentifier=[fuzzy_user_or_group_sid],
|
||||
)
|
||||
self.exists = True
|
||||
|
||||
|
||||
@@ -11,7 +11,8 @@ import six
|
||||
from ipatests.util import assert_deepequal, get_group_dn
|
||||
from ipatests.test_xmlrpc import objectclasses
|
||||
from ipatests.test_xmlrpc.xmlrpc_test import (
|
||||
fuzzy_digits, fuzzy_uuid, raises_exact)
|
||||
fuzzy_set_optional_oc,
|
||||
fuzzy_digits, fuzzy_uuid, fuzzy_user_or_group_sid, raises_exact)
|
||||
from ipatests.test_xmlrpc.tracker.base import Tracker
|
||||
from ipatests.test_xmlrpc.tracker.kerberos_aliases import KerberosAliasMixin
|
||||
from ipatests.test_xmlrpc.tracker.certmapdata import CertmapdataMixin
|
||||
@@ -40,7 +41,8 @@ class UserTracker(CertmapdataMixin, KerberosAliasMixin, Tracker):
|
||||
u'l', u'mobile', u'krbextradata', u'krblastpwdchange',
|
||||
u'krbpasswordexpiration', u'pager', u'st', u'manager', u'cn',
|
||||
u'ipauniqueid', u'objectclass', u'mepmanagedentry',
|
||||
u'displayname', u'gecos', u'initials', u'preserved'}
|
||||
u'displayname', u'gecos', u'initials', u'preserved',
|
||||
'ipantsecurityidentifier'}
|
||||
|
||||
retrieve_preserved_keys = (retrieve_keys - {u'memberof_group'}) | {
|
||||
u'preserved'}
|
||||
@@ -50,6 +52,7 @@ class UserTracker(CertmapdataMixin, KerberosAliasMixin, Tracker):
|
||||
u'krbextradata', u'krbpasswordexpiration', u'krblastpwdchange',
|
||||
u'krbprincipalkey', u'userpassword', u'randompassword'}
|
||||
create_keys = create_keys - {u'nsaccountlock'}
|
||||
create_keys = create_keys - {'ipantsecurityidentifier'}
|
||||
|
||||
update_keys = retrieve_keys - {u'dn'}
|
||||
activate_keys = retrieve_keys
|
||||
@@ -122,7 +125,8 @@ class UserTracker(CertmapdataMixin, KerberosAliasMixin, Tracker):
|
||||
api.env.container_deleteuser,
|
||||
api.env.basedn
|
||||
)
|
||||
self.attrs[u'objectclass'] = objectclasses.user_base
|
||||
self.attrs[u'objectclass'] = objectclasses.user_base \
|
||||
+ ['ipantuserattrs']
|
||||
|
||||
return self.make_command(
|
||||
'user_del', self.uid,
|
||||
@@ -173,7 +177,8 @@ class UserTracker(CertmapdataMixin, KerberosAliasMixin, Tracker):
|
||||
displayname=[u'%s %s' % (self.givenname, self.sn)],
|
||||
cn=[u'%s %s' % (self.givenname, self.sn)],
|
||||
initials=[u'%s%s' % (self.givenname[0], self.sn[0])],
|
||||
objectclass=objectclasses.user,
|
||||
objectclass=fuzzy_set_optional_oc(
|
||||
objectclasses.user, 'ipantuserattrs'),
|
||||
description=[u'__no_upg__'],
|
||||
ipauniqueid=[fuzzy_uuid],
|
||||
uidnumber=[fuzzy_digits],
|
||||
@@ -188,6 +193,7 @@ class UserTracker(CertmapdataMixin, KerberosAliasMixin, Tracker):
|
||||
mepmanagedentry=[get_group_dn(self.uid)],
|
||||
memberof_group=[u'ipausers'],
|
||||
nsaccountlock=[u'false'],
|
||||
ipantsecurityidentifier=[fuzzy_user_or_group_sid],
|
||||
)
|
||||
|
||||
for key in self.kwargs:
|
||||
|
||||
@@ -137,6 +137,12 @@ fuzzy_bytes = Fuzzy(type=bytes)
|
||||
def fuzzy_set_ci(s):
|
||||
return Fuzzy(test=lambda other: set(x.lower() for x in other) == set(y.lower() for y in s))
|
||||
|
||||
|
||||
def fuzzy_set_optional_oc(s, oc):
|
||||
return Fuzzy(test=lambda other: set(x.lower() for x in other if x != oc)
|
||||
== set(y.lower() for y in s if y != oc))
|
||||
|
||||
|
||||
try:
|
||||
if not api.Backend.rpcclient.isconnected():
|
||||
api.Backend.rpcclient.connect()
|
||||
@@ -152,12 +158,6 @@ adtrust_is_enabled = api.Command['adtrust_is_enabled']()['result']
|
||||
sidgen_was_run = api.Command['sidgen_was_run']()['result']
|
||||
|
||||
|
||||
def add_sid(d, check_sidgen=False):
|
||||
if adtrust_is_enabled and (not check_sidgen or sidgen_was_run):
|
||||
d['ipantsecurityidentifier'] = (fuzzy_user_or_group_sid,)
|
||||
return d
|
||||
|
||||
|
||||
def add_oc(l, oc, check_sidgen=False):
|
||||
if adtrust_is_enabled and (not check_sidgen or sidgen_was_run):
|
||||
return l + [oc]
|
||||
|
||||
@@ -9,7 +9,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: freeipa 4.9.0.dev201908140712+gitc9938e3d8\n"
|
||||
"Report-Msgid-Bugs-To: https://pagure.io/freeipa/new_issue\n"
|
||||
"POT-Creation-Date: 2021-03-31 09:12+0300\n"
|
||||
"POT-Creation-Date: 2021-11-25 18:48+0100\n"
|
||||
"PO-Revision-Date: 2021-01-27 07:52+0000\n"
|
||||
"Last-Translator: Alexander Bokovoy <abokovoy@redhat.com>\n"
|
||||
"Language-Team: German <https://translate.fedoraproject.org/projects/freeipa/"
|
||||
@@ -2368,9 +2368,6 @@ msgstr "Maximale Anzahl der zurückgegebenen Einträge"
|
||||
msgid "Maximum number of records to search (-1 is unlimited)"
|
||||
msgstr "Maximale Anzahl an Ergebnissen für Suche (-1 ist unbegrenzt)"
|
||||
|
||||
msgid "Maximum password life must be greater than minimum."
|
||||
msgstr "Maximale Lebensdauer muss größer als das Minimum sein."
|
||||
|
||||
msgid "Maximum password lifetime (in days)"
|
||||
msgstr "Maximale Passwortlebensdauer (in Tagen)"
|
||||
|
||||
@@ -4625,3 +4622,6 @@ msgstr "Benutzer und Host können nicht gleichzeitig gesetzt sein."
|
||||
|
||||
msgid "users cannot be set when type is 'hostgroup'"
|
||||
msgstr "users kann nicht gesetzt sein wenn Typ 'hostgroup' ist"
|
||||
|
||||
#~ msgid "Maximum password life must be greater than minimum."
|
||||
#~ msgstr "Maximale Lebensdauer muss größer als das Minimum sein."
|
||||
Loaded 100 of 111 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user