233 Commits
Author SHA1 Message Date
zpericic 0b4badd451 ipaserver: Use apache VirtualHost for IPA UI 2022-08-17 08:43:12 +02:00
zpericic e2d7602c1d ipaserver: Put WSGI config to ipa-wsgi.conf 2022-08-17 08:43:12 +02:00
Florence Blanc-Renaud a7369944d8 gitignore: add install/oddjob/org.freeipa.server.config-enable-sid
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Stanislav Levin <slev@altlinux.org>
2022-08-16 19:35:37 +02:00
Florence Blanc-Renaud 2385d1d90a ipatests: Fix expected object classes
Because the sidgen plugin is a postop plugin, it is not
always triggered before the result of an ADD is returned
and the objectclasses of the user may / may not contain
ipantuserattrs.
Fix the expected object classes.

Related: https://pagure.io/freeipa/issue/9062
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Stanislav Levin <slev@altlinux.org>
2022-08-16 19:35:37 +02:00
Thomas Woerner 5e2e4664ae DNSResolver: Fix use of nameservers with ports
IPA DNS zone and forwardzone commands allow to use nameservers with ports
as "SERVER_IP port PORT_NUMBER". bind is supporting this syntax, but the
Resolver in dnspython that is used to verify the list of forwarders
(nameservers) is only allowing to have IP addresses in this list. With
dnspython version 2.20 there is a new validator in dns.resolver.BaseResolver
that ensures this.

Refs:
- https://bind9.readthedocs.io/en/v9_18_4/reference.html#zone-statement-grammar
- https://github.com/rthalley/dnspython/blob/master/dns/resolver.py#L1094

ipapython/dnsutil.DNSResolver derives from dns.resolver.Resolver. The setter
for nameservers has been overloaded in the DNSResolver class to split out
the port numbers into the nameserver_ports dict { SERVER_IP: PORT_NUMBER }.
After the setter for nameservers succeeded, nameserver_ports is set.
nameserver_ports is used in the resolve() method of dns.resolver.Resolver.

Additional tests have been added to verify that nameservers and also
nameserver_ports are properly set and also valid.

Fixes: https://pagure.io/freeipa/issue/9158

Signed-off-by: Thomas Woerner <twoerner@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
2022-08-16 19:31:18 +02:00
Rob Crittenden aaf57185a2 upgrades: Don't restart the CA on ACME and profile schema change
There are currently three sets of CA schema changes applied
in ipa-server-upgrade:

* addition of ACME schema
* addition of certificate profile schema
* addition of lightweight CA schema

None of these require a restart of the CA to be supported.

There is an issue in schema parsing such that it doesn't handle
X-ORIGIN properly. A difference is detected and a change applied
but no change is recorded in LDAP so every time upgrade is
run it thinks a CA restart is needed. The CA is not quick to
restart so avoiding one is best, particularly when the update is
run as part of an rpm transaction where a user with an itchy finger
may think things have hung and break out of it.

https://github.com/389ds/389-ds-base/issues/5366 was
filed to track this.

Related: https://pagure.io/freeipa/issue/9204

Signed-off-by: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
2022-08-16 13:15:41 +02:00
Florence Blanc-Renaud 05a298f564 check_repl_update: in progress is a boolean
With the fix for https://pagure.io/freeipa/issue/9171,
nsds5replicaUpdateInProgress is now handled as a boolean.
One remaining occurrence was still handling it as a string
and calling lower() on its value.

Replace with direct boolean comparison.

Fixes: https://pagure.io/freeipa/issue/9218
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
2022-08-16 13:10:10 +02:00
Carla Martinez ade5093b08 webui: Allow grace login limit
There was no support for setting the grace login limit on the WebUI. The
only way to so was only via CLI:

   `ipa pwpolicy-mod --gracelimit=2 global_policy`

Thus, the grace login limit must be updated from the policy section and
this will reflect also on the user settings (under the 'Password Policy'
section)

Fixes: https://pagure.io/freeipa/issue/9211

Signed-off-by: Carla Martinez <carlmart@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
2022-08-09 12:00:00 +02:00
Sudhir Menon a5762621ef ipatests: ipa-client-install --subid adds entry in nsswitch.conf
This testcase checks that when ipa-client-install command
is run with --subid option, /etc/nsswitch.conf file is updated
with the below entry

subid: nss
Related: https://pagure.io/freeipa/issue/9159

Since the newly added testsuite required client
system, hence modified the below yaml files to change the topology
from *master_1repl to *master_1repl_1client in the below files

gating.yaml
nightly_latest.yaml
nightly_previous.yaml
nightly_rawhide.yaml

Reviewed-By: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Michal Polovka <mpolovka@redhat.com>
Reviewed-By: Stanislav Levin <slev@altlinux.org>
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
2022-08-09 08:35:07 +02:00
Florence Blanc-Renaud d40fd28783 azure tests: disable TestInstallDNSSECFirst
The test TestInstallDNSSECFirst is failing because of one of its
dependencies (the most likely suspect is the update of openssl-pkcs11).
Disable the test from azure gating until the issue is solved.

Related: https://pagure.io/freeipa/issue/9216
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
Reviewed-By: Carla Martinez <carlmart@redhat.com>
2022-08-08 14:35:11 +02:00
David Pascual 6483f33389 ipatest: fix prci checker target masked return code & add pylint
In the yamllint target of makefile, prci_checker result was being masked by echo statement.
Aditionally, prci_checker script has been added to the list of Python sources to be Pylinted.

Addressing comments of recently merged PR:
https://github.com/freeipa/freeipa/pull/6301#discussion_r923163970
https://github.com/freeipa/freeipa/pull/6301#issuecomment-1187037261

Signed-off-by: David Pascual <davherna@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Stanislav Levin <slev@altlinux.org>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
2022-08-04 13:23:26 -04:00
Rob Crittenden 1316cd8b22 Disabling gracelimit does not prevent LDAP binds
Originally the code treated 0 as disabled. This was
changed during the review process to -1 but one remnant
was missed effetively allowing gracelimit 0 to also mean
disabled.

Add explicit tests for testing with gracelimit = 0 and
gracelimit = -1.

Also remove some extranous "str(self.master.domain.basedn)"
lines from some of the tests.

Fixes: https://pagure.io/freeipa/issue/9206

Signed-off-by: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
2022-08-01 13:03:51 -04:00
Erik f962a0c283 ipatests: healthcheck: test if system is FIPS enabled
Test if FIPS is enabled and the check exists.

Related: https://pagure.io/freeipa/issue/8951

Signed-off-by: Erik Belko <ebelko@redhat.com>
Reviewed-By: Michal Polovka <mpolovka@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-08-01 09:22:37 -04:00
Stanislav Levin 1ada42e3bc ap: Constrain supported docutils
New Sphinx 5.1.0 (Released: Jul 24, 2022) bumped supported docutils
to 0.19:
https://github.com/sphinx-doc/sphinx/pull/10656

But m2r2 doesn't support it yet:
https://github.com/CrossNox/m2r2/issues/52

Thereby, docutils must be constrained to < 0.19.

This should be fixed by m2r2 and after they do it the restriction
can be removed.

Fixes: https://pagure.io/freeipa/issue/9208
Signed-off-by: Stanislav Levin <slev@altlinux.org>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-07-26 16:57:54 -04:00
Stanislav Levin b59baf31bc ap: Rearrange overloaded jobs
With some recent changes the Azure Agent has decreased performance.
For example, `InstallDNSSECFirst_1_to_5` (5 subjobs) job took ~33min
and now it takes ~40min. In the same time there are jobs having only
1 or 2 subjobs and they should be used more.

Fixes: https://pagure.io/freeipa/issue/9207
Signed-off-by: Stanislav Levin <slev@altlinux.org>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-07-26 16:57:54 -04:00
Stanislav Levin 98c6e96e8d ap: Disable azure's security daemon
This daemon run clamav which is resource aggressive.
No point to run Windows virus scanner on Ubuntu in Linux-only
environment.

Fixes: https://pagure.io/freeipa/issue/9207
Signed-off-by: Stanislav Levin <slev@altlinux.org>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-07-26 16:57:54 -04:00
Stanislav Levin e77b0b08d7 ap: Raise dbus timeout
With some recent changes on Azure Agent the default DBus call
timeout is not good enough. For example, in case of
`InstallDNSSECFirst_1_to_5` job hostnamectl received reply in ~20sec,
but later it increased to ~30sec (more subjobs - more time to reply).
It's good to raise this timeout to be more protected against minimum
performance times.

https://www.freedesktop.org/software/systemd/man/sd_bus_set_method_call_timeout.html#Description

Fixes: https://pagure.io/freeipa/issue/9207
Signed-off-by: Stanislav Levin <slev@altlinux.org>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-07-26 16:57:54 -04:00
Rob Crittenden b31631ad69 Warn for permissions with read/write/search/compare and no attrs
An ACI with rights of read, write, search and/or compare without
attributes to apply the rights to is effectively a no-op. Allow
the ACI to be created but include a warning. Ignore the add
and delete rights. While they make no sense in the context of
the other rights we should still warn that they are a no-op
with no attributes.

Use the existing make_aci() object method to create the
message and update the add/mod callers to capture and add the
message to the result if one is provided.

When updating an existing ACI the effective attributes will
not be included so fall back to the attributes in the resulting
permission.

Prior to checking for rights and attributes convert any deprecated
names for older clients into the newer values needed by make_aci

This is exercised by existing xmlrpc permission tests that
create such permissions without attributes.

https://pagure.io/freeipa/issue/9188

Signed-off-by: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
2022-07-16 07:57:49 +02:00
David Pascual f33266c2ba ipatests: Checker script for prci definitions
This script allows developers to check if prci definition jobs have the correct format,
which is defined in prci_jobs_spec.yaml
Useful when adding new jobs to the definitions.

Signed-off-by: David Pascual <davherna@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Petr Vobornik <pvoborni@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Stanislav Levin <slev@altlinux.org>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Petr Vobornik <pvoborni@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Stanislav Levin <slev@altlinux.org>
2022-07-16 07:53:57 +02:00
Armando Neto 991849cf58 webui: Do not allow empty pagination size
Pagination size must be required, the current validators are triggered after
form is submitted, thus the only way for check if data is not empty is by making
the field required.

Fixes: https://pagure.io/freeipa/issue/9192

Signed-off-by: Armando Neto <abiagion@redhat.com>
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
2022-07-12 13:53:54 -03:00
Fraser Tweedale cbf2614d8a install: suggest --skip-mem-check when mem check fails
In the memory check failure message, add a hint to the administrator
that they can use the --skip-mem-check flag to skip the check.

Related: https://pagure.io/freeipa/issue/8404

Signed-off-by: Fraser Tweedale <frase@frase.id.au>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
2022-07-06 09:48:18 +02:00
Fraser Tweedale 585cebb1a9 man: add --skip-mem-check to man pages
Document the --skip-mem-check flag in the ipa-server-install(1) and
ipa-replica-install(1) man pages.

Related: https://pagure.io/freeipa/issue/8404

Signed-off-by: Fraser Tweedale <frase@frase.id.au>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
2022-07-06 09:48:18 +02:00
Rob Crittenden 3675bd1d7a Only calculate LDAP password grace when the password is expired
The user's pwd expiration was retrieved but inadvertently was never
compared to current time. So any LDAP bind, including from the
IPA API, counted against the grace period. There is no need to go
through the graceperiod code for non-expired passwords.

https://pagure.io/freeipa/issue/1539

Signed-off-by: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
2022-06-30 14:56:06 -04:00
Rob Crittenden de64d6724e Fix test_secure_ajp_connector.py failing with Python 3.6.8
Some of the test data are not expected to cause a rewrite in
the upgrade code. Those that do will set the rewrite flag.

In that case there is a new server.xml to be read. This is
handled with mock_open(). The contents can be retrieved via
mocked_file().write.call_args but the repr() of it is:

call(b'<Server port="1234" shutdown="SHUTDOWN">\n  ...')

In at least Python 3.10 one can use write.call_args.args to get
just the raw data. This does not work with Python 3.6.8 and
returns the string 'args' instead results in a TypeError.

TypeError: a bytes-like object is required, not 'str'

Instead drop the args and use the data directly.

For the case of x = mocked_file().write.call_args:

   x[0] is a tuple with the first element being the data
   x[0][0] is the raw data

So use x[0][0] to get at the data instead of x.args[0]

Fixes: https://pagure.io/freeipa/issue/9190

Signed-off-by: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
2022-06-24 11:36:39 +02:00
Matthew Davis 4f15804270 Add missing parameter to Suse modify_nsswitch_pam_stack
Add missing subid parameter for Suse.

Fixes: https://pagure.io/freeipa/issue/9185
Signed-off-by: Matthew Davis <github@virtual.drop.net>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-06-23 17:46:03 -04:00
Anuja More 15f454f6f8 ipatests: Fix install_master for test_idp.py
For install_master added --no-dnssec-validation.

Fixes: https://pagure.io/freeipa/issue/9189

Signed-off-by: Anuja More <amore@redhat.com>
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
2022-06-23 17:45:16 -04:00
Timo Aaltonen 56c8270997 ipaplatform/debian: Drop the path for ldap.so
Named is able to find plugins if they are installed in the plugindir,
so drop the hardcoded path from named.conf.

Signed-off-by: Timo Aaltonen <tjaalton@debian.org>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-06-23 17:44:11 -04:00
Timo Aaltonen c39c2ee80d ipaplatform/debian: Use multiarch path for libsofthsm2.so
The library moved there some years ago, and the compat symlink might go
away at some point. Better prepare for it.

Signed-off-by: Timo Aaltonen <tjaalton@debian.org>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-06-23 17:44:11 -04:00
Michal Polovka afa94c7995 ipatests: Healthcheck use subject base from IPA not REALM
Test if healthcheck uses cert subject base from IPA and not from
REALM. This prevents false-positive errors when the subject base is
customized.

Related: https://github.com/freeipa/freeipa-healthcheck/issues/253

Signed-off-by: Michal Polovka <mpolovka@redhat.com>
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-06-23 17:43:08 -04:00
Anuja More 50b4d9ab3f ipatests: update prci definitions for test_idp.py
Signed-off-by: Anuja More <amore@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
2022-06-23 13:44:02 +02:00
Anuja More 857713c5a9 Add end to end integration tests for external IdP
Added tests for HBAC and SUDO rule and other
test scenarios.

Related : https://pagure.io/freeipa/issue/8805
Related: https://pagure.io/freeipa/issue/8803
Related: https://pagure.io/freeipa/issue/8804

Signed-off-by: Anuja More <amore@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
2022-06-23 13:44:02 +02:00
Florence Blanc-Renaud 4984ff210a xmlrpc tests: updated expected output for preserved user
Update the expected summary for the command
ipa user-del --preserve

The command now displays: Preserved user: user1
instead of                Deleted user: user1

Related: https://pagure.io/freeipa/issue/9187

Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Michal Polovka <mpolovka@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-06-23 08:39:14 +02:00
Florence Blanc-Renaud ff4152539b Preserve user: fix the confusing summary
When ipa user-del --preserve is called, the command output
prints a summary with:
    Deleted user: user1
although the user was preserved.
Replace the summary with
    Preserved user: user1
to reflect what was actually done.

Fixes: https://pagure.io/freeipa/issue/9187
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Michal Polovka <mpolovka@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-06-23 08:39:14 +02:00
Michal Polovka 206e08d811 ipatests: Healthcheck should ignore pki errors when CA is not configured
Test if ipa-healthcheck complains about pki.server.healthcheck errors
when CA is not configured on the replica.

Related: https://github.com/freeipa/freeipa-healthcheck/issues/201

Signed-off-by: Michal Polovka <mpolovka@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-06-17 16:41:08 +02:00
Michal Polovka a6a6781284 ipatests: Increase expect timeout for interactive mode
Increase the default timeout for expect function when testing
interactive mode to mitigate an issue when the tests are failing
on the slow systems.

Fixes: https://pagure.io/freeipa/issue/9183

Signed-off-by: Michal Polovka <mpolovka@redhat.com>
Reviewed-By: Mohammad Rizwan Yusuf <myusuf@redhat.com>
2022-06-17 16:39:08 +02:00
Antonio Torres 3e90842b3d Back to git snapshots
Signed-off-by: Antonio Torres <antorres@redhat.com>
2022-06-15 16:42:51 +02:00
Antonio Torres 61a64aef6d Become IPA 4.9.10 2022-06-15 16:33:21 +02:00
Antonio Torres dabea80f3a Update list of contributors
Signed-off-by: Antonio Torres <antorres@redhat.com>
2022-06-15 16:28:00 +02:00
Antonio Torres 553b84c60a Update translations to FreeIPA ipa-4-9 state
Signed-off-by: Antonio Torres <antorres@redhat.com>
2022-06-15 16:22:50 +02:00
Matthew Davis 70d23b225d Create missing SSSD_PUBCONF_KRB5_INCLUDE_D_DIR
One some distributions, namely Suse, the SSSD_PUBCONF_KRB5_INCLUDE_D_DIR
does not exist by default. Ipa-client-install will fail to initialize
the kerberos ticket and error when this directory does not exist.

This patch simply creates the directory if it does not exist before
adding the include statement into /etc/krb5.conf

Fixes: https://pagure.io/freeipa/issue/9174
Signed-off-by: Matthew Davis github@virtual.drop.net
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-06-15 14:12:47 +03:00
Michal Polovka 60739ce483 ipatests: xfail for test_ipahealthcheck_hidden_replica to respect pki version
Change xfail for test_replica_promotion.py/TestHiddenReplicaPromotion/test_ipahealthcheck_hidden_replica
to respect platform and pki version as the related issue is fixed.

Implement tasks/get_platform_version which returns a platform version
number(s) of a provided host in a form of a tuple.

Related: https://pagure.io/freeipa/issue/8582

Signed-off-by: Michal Polovka <mpolovka@redhat.com>
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
2022-06-15 12:13:15 +02:00
Matthew Davis fe048d83cb Suse compatibility fix
Removes authselect requirement for Suse
    Use Suse 'pam-config' to configure PAM
    Configures nsswitch.conf
    Removes domainname service since it does not exist on Suse

Fixes: https://pagure.io/freeipa/issue/9174
Signed-off-by: Matthew Davis github@virtual.drop.net
Reviewed-By: Christian Heimes <cheimes@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
2022-06-15 08:34:01 +02:00
Alexander Bokovoy cfca49c469 idviews: use cached ipaOriginalUid value when resolving ID override anchor
For ID overrides 'ipaOriginalUid' value should be the human-readable
version of the ID override anchor. Since we would have it already set in
the ID override entry, prefer using it instead of looking up the
override anchor.

This should speed up significantly operations which list all ID
overrides in the view, like Web UI views.

Fixes: https://pagure.io/freeipa/issue/9178
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-06-14 14:14:16 -04:00
Rob Crittenden d062dc9da8 Add switch for LDAP cache debug output
The LDAP cache log is rather chatty and a bit overwhelming when
looking for error messages. Disable it by default but allow it
to be enabled when a new config option, ldap_cache_debug, is
enabled.

Fixes: https://pagure.io/freeipa/issue/9180

Signed-off-by: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
2022-06-14 13:20:36 -04:00
Rob Crittenden deaaaaf149 Remove extraneous AJP secret from server.xml on upgrades
PKI 10.10 unconditionally added an upgrade script for the AJP
connector which replaced the AJP secret regardless of tomcat
version.  It replaced requiredSecret with secret. IPA expects
the attribute by version so this could make the secrets out of
date and/or have connectors with both secrets and different
values.

PKI commit e70373ab131aba810f318c1d917896392b49ff4b has since
been reverted but there may be servers with both secrets still.
On next IPA upgrade clean them up.

Also allow re-writing ipa-pki-proxy.conf in case the secret
changes to ensure they remain in sync.

Fixes: https://pagure.io/freeipa/issue/9176

Signed-off-by: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
2022-06-14 16:51:13 +02:00
Florence Blanc-Renaud 4b8b032ed5 ACI: define "Read DNS entries from a zone" aci during install
The ACI "Read DNS entries from a zone" is defined when
ipa-server-upgrade is run but not for new installations.
In order to have consistent ACI (same set for new install
and for install + upgrade), define this ACI in
install/share/dns.ldif instead of "Allow read access".

Fixes: https://pagure.io/freeipa/issue/9173
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-06-14 08:12:10 +02:00
Armando Neto f325539318 ipatests: bump pr-ci templates
Packages updated to include `freeipa-healthcheck-0.11-2`.

Signed-off-by: Armando Neto <abiagion@redhat.com>
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
2022-06-13 16:05:18 -03:00
Florence Blanc-Renaud c6bc8fd4c8 ipatests: update expected output for boolean attribute
Now that IPA API properly maps LDAP boolean attributes to the
python bool type, they are displayed as True/False instead
of TRUE/FALSE in the ipa *-show outputs.

Update the expected output for DNS Active Zone.

Related: https://pagure.io/freeipa/issue/9171
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
2022-06-13 12:51:09 +02:00
Florence Blanc-Renaud 23d56bb952 ipa-replica-install: nsds5replicaUpdateInProgress is a Boolean
nsds5replicaUpdateInProgress is defined in LDAP schema as a boolean.
Now that IPA API is able to properly map booleans to the python
bool type, this attribute is not a string any more and
comparisons can be done directly based on its real type.

The code in ipa-replica-install was reading nsds5replicaUpdateInProgress
and calling value.tolower() == 'true' but should now use
value == True instead.

Related: https://pagure.io/freeipa/issue/9171
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
2022-06-13 12:51:09 +02:00
Francisco Trivino 8abc0a22a8 Update subordinate design doc
This commit updates the subordinate design document to reflect the current state
and remove "outdated" message.

Signed-off-by: Francisco Trivino <ftrivino@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
2022-06-10 17:13:18 +02:00
Sudhir Menon 3488276649 ipatests: ipahealthcheck tests to check change in permission of ipaserver log files
This testscase checks that when permission of
ipaserver-upgrade.log
file is changed healtcheck tool reports the correct warning message.

Signed-off-by: Sudhir Menon <sumenon@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
2022-06-10 14:00:16 +02:00
Florence Blanc-Renaud 6147f877a5 ipatest: update expected out for ipa-healthcheck's DogtagCertsConnectivityCheck
Pre ipa-healthcheck 0.11, failures detected by DogtagCertsConnectivityCheck
were reported as:
"msg": "Request for certificate failed, <error>"
but the output is now the following:
"msg": "Request for certificate failed: {error}"
"error": <error>

Update the expected output to be compatible with both versions.

Fixes: https://pagure.io/freeipa/issue/9175
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Michal Polovka <mpolovka@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-06-10 12:19:11 +02:00
Alexander Bokovoy faeb656c77 ipaldap: fix conversion from boolean OID to Python
In IPA framework we don't properly convert to Python bool type and just
return a string (TRUE or FALSE). This can be seen with many boolean
attributes, like

        Bool('idnsallowdynupdate?',
            cli_name='dynamic_update',
            label=_('Dynamic update'),
            doc=_('Allow dynamic updates.'),
            attribute=True,
            default=False,
            autofill=True
        ),

in 'ipa dnszone-show':

> > > api.Command.dnszone_show('ipa.test')['result']['idnsallowdynupdate']
['TRUE']

This is because we don't have the reverse (from LDAP to Python) mapping
for the LDAP boolean OID 1.3.6.1.4.1.1466.115.121.1.7.

When Web UI asks for the entry, it gets back JSON output that contains
this 'TRUE' value:

            "idnsallowdynupdate": [
                "TRUE"
            ],

Add proper mapping from LDAP to Python bool type. With this, a simple
'checkbox' type can be used in Web UI instead of a complex radio-box
setup.

Note that when IPA API is asked to return raw values, 'TRUE' and 'FALSE'
still returned. These are the actual LDAP boolean attribute values. Care
needs to be done in tests:

 - if output is from a command with --raw option, 'TRUE' or 'FALSE'
   should be expected

 - if output if from a normal (non-raw) command, True or False would be
   returned

Fixes: https://pagure.io/freeipa/issue/9171

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
2022-06-10 11:10:51 +02:00
Rob Crittenden e6cc41094b graceperiod: ignore case when checking for missing objectclass
Don't assume that all objectclasses are lower-case. Some are
camel-cased.

Fixes: https://pagure.io/freeipa/issue/1539

Signed-off-by: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
2022-06-07 08:15:04 +02:00
Rob Crittenden 9b0fbdc37b Set default LDAP password grace period to -1
This will retain existing behavior where LDAP passwords are
allowed to bind past expiration.

Fixes: https://pagure.io/freeipa/issue/1539

Signed-off-by: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
2022-06-07 08:15:04 +02:00
Rob Crittenden d2b296454c doc: Design document for LDAP graceperiod
Implement part of RFC https://tools.ietf.org/id/draft-behera-ldap-password-policy-10.html

Related: https://pagure.io/freeipa/issue/1539

Signed-off-by: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
2022-06-07 08:15:04 +02:00
Rob Crittenden 8b2edd5b4e Don't duplicate the LDAP gracelimit set in the previous test
Remove a duplicated policy change which sets the gracelimit
to 3.

We don't typically run tests individually but as a whole. If
we ever need to call this one test directly we can ignore
failures.

Fixes: https://pagure.io/freeipa/issue/9167

Signed-off-by: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
2022-06-03 17:01:51 +02:00
Rob Crittenden 62bafcc53d Configure and enable the graceperiod plugin on upgrades
The graceperiod plugin was only being enabled on new
installations. Enable also on upgrade.

Loading a new plugin requires a restart. Do so if a
new one is configured.

Fixes: https://pagure.io/freeipa/issue/1539

Signed-off-by: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
2022-06-03 09:53:27 +02:00
Rob Crittenden c002864621 dnssec daemons: read the dns context config file for debug state
This had been hardcoded to debug=True but it spams the logs
with a lot of unnecessary information.

Allow it to be enabled for troubleshooting purposes but keep it
disabled by default.

Enabling debug would involve created /etc/ipa/dns.conf:

[global]
debug = True

I didn't add a more generic mechanism because for now we only need
the value of debug and it introduces a lot of type conversion
headaches. ipalib handles this automatically but to duplicate this
would be corner-case city.

Fixes: https://pagure.io/freeipa/issue/9128

Signed-off-by: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
2022-06-02 14:15:30 +02:00
Michal Polovka 58ddcffc41 ipatests: tasks: add ipactl start, stop and restart
Include functions to manage IdM service using ipactl, in particular
starting, stopping and restarting the service.

Signed-off-by: Michal Polovka <mpolovka@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
2022-06-02 14:03:01 +02:00
Michal Polovka 352b9dfb49 ipatests: RFE: Improve ipa-replica-install error message
Test for RFE: Improve error message with more detail for
ipa-replica-install command. If the replication agreement already
exists, check if the error message contains
a particular command needed to delete it.

Related: https://pagure.io/freeipa/issue/9162

Signed-off-by: Michal Polovka <mpolovka@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
2022-06-02 14:03:01 +02:00
Rob Crittenden 0e8350e0dd healthcheck: add tests for setting cli options in config file
Fixes: https://pagure.io/freeipa/issue/9136

Signed-off-by: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
2022-06-02 13:59:50 +02:00
Michal Polovka ab0e67d1f5 ipatests: test_subids: test subid-match shows UID of the owner
ipa subid-match should show UID of the owner instead of DN.

Related: https://pagure.io/freeipa/issue/8977

Signed-off-by: Michal Polovka <mpolovka@redhat.com>
Reviewed-By: Anuja More <amore@redhat.com>
2022-06-01 16:04:58 +02:00
Rob Crittenden 87fe3fbba6 Exclude passwordgraceusertime from replication
Treat this like other failed login attributes and don't
replicate them.

https://pagure.io/freeipa/issue/1539

Signed-off-by: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
2022-05-30 18:24:37 +02:00
Rob Crittenden 6b3ab98b90 Remove the replicated attribute constants
These pre-existed in ipaserver/install/replication.py.

The constants were only originally used in ldapupdate.py
but have subsequently been switched to the replication.py
versions so they are not used anywhere in the code.

https://pagure.io/freeipa/issue/1539

Signed-off-by: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
2022-05-30 18:24:37 +02:00
Rob Crittenden 4fcbf2ded2 Implement LDAP bind grace period 389-ds plugin
Add support for bind grace limiting per
https://datatracker.ietf.org/doc/html/draft-behera-ldap-password-policy-06

389-ds provides for alternative naming than the draft, using those
instead: passwordGraceUserTime for pwdGraceUserTime and
passwordGraceLimit for pwdGraceLoginLimit.

passwordGraceLimit is a policy variable that an administrator
sets to determine the maximum number of LDAP binds allowed when
a password is marked as expired. This is suported for both the
global and per-group password policies.

passwordGraceUserTime is a count per-user of the number of binds.

When the passwordGraceUserTime exceeds the passwordGraceLimit then
all subsequent binds will be denied and an administrator will need
to reset the user password.

If passwordGraceLimit is less than 0 then grace limiting is disabled
and unlimited binds are allowed.

Grace login limitations only apply to entries with the objectclass
posixAccount or simplesecurityobject in order to limit this to
IPA users and system accounts.

Some basic support for the LDAP ppolicy control is enabled such that
if the ppolicy control is in the bind request then the number of
remaining grace binds will be returned with the request.

The passwordGraceUserTime attribute is reset to 0 upon a password
reset.

user-status has been extended to display the number of grace binds
which is stored centrally and not per-server.

Note that passwordGraceUserTime is an operational attribute.

https://pagure.io/freeipa/issue/1539

Signed-off-by: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
2022-05-30 18:24:37 +02:00
Alexander Bokovoy 6c6fc7db61 ipa-kdb: avoid additional checks for a well-known anonymous principal
For a well-known anonymous principal an Anonymous PKINIT method is used
which ignores the password set in the principal entry. For these
principals any defined user auth type is irrelevant, their use is
defined in RFC 6112. This gets confusing when a default user auth type
requires a particular authentication method.

When AS request for Anonymous PKINIT is used, a TGT would contain no
authentication indicator. It means we cannot apply any specific
indicator policy and must skip the checks.

Fixes: https://pagure.io/freeipa/issue/9165

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
2022-05-30 17:10:44 +03:00
Alexander Bokovoy 35c720cab0 Ignore dnssec-enable-related named-checkonf errors in test
Check and skip dnssec-enable-related issues in 9.18+ where dnssec-enable
option was removed completely.

Fixes: https://pagure.io/freeipa/issue/9157

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
2022-05-26 17:59:08 +02:00
Alexander Bokovoy 1c6bdf9759 Support dnssec utils from bind 9.17.2+
In bind 9.17.2+ all dnssec utilities were moved to /usr/bin with
commit 4419606c9d2a52536a6dd0882ac0c7068ac27f30.

Since we only use those utilities in the specialized tool, do a fixup of
the paths in the tool.

Fixes: https://pagure.io/freeipa/issue/9157

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
2022-05-26 17:59:08 +02:00
Rob Crittenden 300f1301bb If the password auth type is enabled also enable the hardened policy
This will allow custom hardened password policy to be applied.
Without this then the policy will be skipped because the UA
is not enabled.

The KDC and client will prefer SPAKE any time it is available.
For IPA this should mean we should choose hardened setting over a
default one any time SPAKE is used.

Related: https://pagure.io/freeipa/issue/9121

Signed-off-by: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
2022-05-25 15:14:39 -04:00
Rob Crittenden ed1447ab61 kdb: The jitter offset should always be positive
Otherwise the resulting value could be outside the valid
bounds of the time value.

Related: https://pagure.io/freeipa/issue/9121

Signed-off-by: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
2022-05-25 15:14:39 -04:00
Alexander Bokovoy a2baae42f8 ipa-kdb: apply per-indicator settings from inherited ticket policy
Fixes: https://pagure.io/freeipa/issue/9121

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
2022-05-25 15:14:39 -04:00
Thorsten Scherf 84c88b69fe workshop: add freeipa version requirements
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-05-25 15:13:51 -04:00
Thorsten Scherf 7e596fd16c workshop: add freeipa version requirements
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-05-25 15:13:51 -04:00
Florence Blanc-Renaud 0193498f68 ipatests: add new test with --subid installer option
Add a new test for ipa-client-install --subid
Add a new test for ipa-server-install --subid

Related: https://pagure.io/freeipa/issue/9159
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
2022-05-25 15:08:03 -04:00
Florence Blanc-Renaud e10f3385d0 man pages: document the --subid installer option
Document --subid in the man pages for
- ipa-client-install
- ipa-replica-install
- ipa-server-install

Related: https://pagure.io/freeipa/issue/9159
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
2022-05-25 15:08:03 -04:00
Florence Blanc-Renaud 74b2fd06d9 Installer: add --subid option to select the sssd profile with-subid
Add the --subid option to client, server and replica installers.
This option allows to configure authselect with the sssd
profile + with-subid feature, in order to have SSSD setup as
a datasource for subid in /etc/nsswitch.conf.

The default behavior remains unchanged: without the option,
/etc/nsswitch.conf keeps the line subid: files

Fixes: https://pagure.io/freeipa/issue/9159
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
2022-05-25 15:08:03 -04:00
Francisco Trivino c03a8c3c06 Update ipa-replica-install replication agreement error message
So that it prints out a valid command:
- replace "ipa-replica-manage del" by "ipa server-del" (only domain-level1 is now supported)
- the commands needs to be run on a working server, not on the host where ipa-replica-install failed

Fixes: https://pagure.io/freeipa/issue/9162
Reviewed-By: Michal Polovka <mpolovka@redhat.com>
2022-05-25 07:20:10 +02:00
Anuja More b39f9336fa pr-ci definitions: add external idp related jobs.
Signed-off-by: Anuja More <amore@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Mohammad Rizwan Yusuf <myusuf@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Mohammad Rizwan Yusuf <myusuf@redhat.com>
2022-05-23 14:45:44 +03:00
Anuja More b979dd91f1 ipatests: Add integration tests for External IdP support
Tests for [RFE]: Added integration tests for external IdP
authentication with keycloak-17 as identity provider.

Related : https://pagure.io/freeipa/issue/8805
Related: https://pagure.io/freeipa/issue/8803
Related: https://pagure.io/freeipa/issue/8804

Signed-off-by: Anuja More <amore@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Mohammad Rizwan Yusuf <myusuf@redhat.com>
Signed-off-by: Anuja More <amore@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Mohammad Rizwan Yusuf <myusuf@redhat.com>
2022-05-23 14:45:44 +03:00
Francisco Trivino 9ae6ef549f ipatests: Bump PR-CI latest templates to Fedora 36
Moving 'latest' to Fedora 36 and 'previous' to Fedora 35.

Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
Reviewed-By: Armando Neto <abiagion@redhat.com>
2022-05-19 14:52:41 -03:00
Florence Blanc-Renaud d39e232e9e client uninstall: handle uninstall with authconfig
If the client was installed with authconfig, with
automount configured to use ldap (--no-sssd), and later
updated to a version using authselect, the uninstaller
tries to disable the authselect feature with-custom-automount
but fails because there is no authselect profile in use.

(Upgrade of a client does not transform authconfig settings
into authselect settings because we don't have any client
upgrader, as opposed to the ipa-server-upgrade for the
servers).

To avoid uninstallation failure, ignore the error and log a
warning.

The second part of the commit leverages the "complete" state
stored in the statestore, in order to fix issues when
a client installation fails and the installation is reverted
by the ipa-client-install tool itself.
The fix checks if the statestore shows an incomplete
installation. If the install was incomplete and failed before
any attempt to configure authselect, then unconfigure doesn't
need to do anything. In the other cases, unconfigure needs
to revert to the pre-ipa state.

Fixes: https://pagure.io/freeipa/issue/9147
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-05-14 12:44:46 +02:00
Alexander Bokovoy 979163bff2 freeipa.spec.in: Depend on sssd-idp directly to help RHEL BaseOS/AppStream repository split
In RHEL there is a split of packages between Base OS and AppStream
repositories. While both repositories are accessible and enabled by
default, there are different requirements towards binary packages in
both. Namely, Base OS packages cannot have runtime dependencies to
AppStream packages and they should have a stricter lifecycle promises in
terms of API and ABI stability.

SSSD 2.7.0 adds sssd-idp package which provides actual implementation of
OAuth 2.0 integration. Since SSSD is provided as part of Base OS, if
sssd-idp is placed there, then all its dependencies would have to be in
Base OS. Unfortunately, libjose is already part of AppStream.

SSSD team currently pulls sssd-idp as a dependency of sssd-ipa so
FreeIPA didn't need to change anything. However, Base OS requirements
will force SSSD team to drop sssd-idp dependency from sssd-ipa. This
means FreeIPA will have to explicitly depend on sssd-idp.

Fixes:https://pagure.io/freeipa/issue/9155

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
2022-05-11 16:46:07 +03:00
Alexander Bokovoy 40a257f1e6 docs: tune RTD to display lists with disc and left margin
RTD default theme removes discs from the section list items which makes
design pages look strange. Add them back via small CSS override.
Also, add 1em on the left side of the disc to provide visual cue that
this is a list item.

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
Reviewed-By: Sumit Bose <sbose@redhat.com>
(cherry picked from commit 79a4073730)
2022-05-10 23:43:13 +03:00
Alexander Bokovoy 5f9e0d3ff3 workshop: add chapter 12: External IdP support
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
Reviewed-By: Sumit Bose <sbose@redhat.com>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
Reviewed-By: Sumit Bose <sbose@redhat.com>
2022-05-10 23:09:17 +03:00
Alexander Bokovoy d49aa7103b freeipa.spec.in: use SSSD 2.7.0 to add IdP pre-auth mechanism
SSSD 2.7.0 provides oidc_child and 'idp' Kerberos pre-auth mechanism as
a part of sssd-idp package which is required by sssd-ipa.

Fixes: https://pagure.io/freeipa/issue/8805

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
Reviewed-By: Sumit Bose <sbose@redhat.com>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
Reviewed-By: Sumit Bose <sbose@redhat.com>
2022-05-10 23:09:17 +03:00
Alexander Bokovoy d0eab8fe76 doc/workshop: document use of pam_sss_gss PAM module
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
Reviewed-By: Sumit Bose <sbose@redhat.com>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
Reviewed-By: Sumit Bose <sbose@redhat.com>
2022-05-10 23:09:17 +03:00
Alexander Bokovoy 660c3dc249 External IdP: initial SELinux policy
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
Reviewed-By: Sumit Bose <sbose@redhat.com>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
Reviewed-By: Sumit Bose <sbose@redhat.com>
2022-05-10 23:09:17 +03:00
Alexander Bokovoy 51a4e42dd7 External IdP: add Web UI to manage IdP references
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
Reviewed-By: Sumit Bose <sbose@redhat.com>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
Reviewed-By: Sumit Bose <sbose@redhat.com>
2022-05-10 23:09:17 +03:00
Alexander Bokovoy 673478b1cf KDB: support external IdP configuration
When IdP configuration is provided, take it into account:

 - idp-specific Kerberos ticket policy would be applied

 - Presence of IdP link in a Kerberos principal entry would cause KDB to
   enable `idp` pre-authentication method on KDC side.

The latter requires additional pre-authentication method supplied with
SSSD 2.7.0.

Fixes: https://pagure.io/freeipa/issue/8804

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Signed-off-by: Pavel Březina <pbrezina@redhat.com>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
Reviewed-By: Sumit Bose <sbose@redhat.com>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
Reviewed-By: Sumit Bose <sbose@redhat.com>
2022-05-10 23:09:17 +03:00
Alexander Bokovoy bf8e2bb99f ipa-otpd: add support for SSSD OIDC helper
SSSD OIDC helper is used for negotiating with OAUTH2 or OIDC end points
of external identity providers (IdPs).

ipa-otpd daemon now is capable to take either Issuer URL or individual
endpoints and call SSSD OIDC helper accordingly.

Communication with SSSD OIDC helper can be debugged with the use of a
debug variable set in /etc/ipa/default.conf. Man page for
default.conf(5) has been updated to provide this information.

Fixes: https://pagure.io/freeipa/issue/8805

Signed-off-by: Sumit Bose <sbose@redhat.com>
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
Reviewed-By: Sumit Bose <sbose@redhat.com>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
Reviewed-By: Sumit Bose <sbose@redhat.com>
2022-05-10 23:09:17 +03:00
Alexander Bokovoy b77015b7a3 external-idp: add XMLRPC tests for External IdP objects and idp indicator
Fixes: https://pagure.io/freeipa/issue/8804
Fixes: https://pagure.io/freeipa/issue/8803

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
Reviewed-By: Sumit Bose <sbose@redhat.com>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
Reviewed-By: Sumit Bose <sbose@redhat.com>
2022-05-10 23:09:17 +03:00
Alexander Bokovoy 2136bd5d00 external-idp: add support to manage external IdP objects
Fixes: https://pagure.io/freeipa/issue/8804
Fixes: https://pagure.io/freeipa/issue/8803

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
Reviewed-By: Sumit Bose <sbose@redhat.com>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
Reviewed-By: Sumit Bose <sbose@redhat.com>
2022-05-10 23:09:17 +03:00
Alexander Bokovoy 1df7b82ac1 external-idp: add LDAP schema, indices and other LDAP objects
Fixes: https://pagure.io/freeipa/issue/8803

Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
Reviewed-By: Sumit Bose <sbose@redhat.com>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
Reviewed-By: Sumit Bose <sbose@redhat.com>
2022-05-10 23:09:17 +03:00
Alexander Bokovoy 8d81338cb9 doc/designs: add External IdP support design documents
External IdP objects represent OAuth 2.0 clients that can be used to
perform OAuth 2.0 device authorization grant flow.

Related: https://pagure.io/freeipa/issue/8805
Related: https://pagure.io/freeipa/issue/8804
Related: https://pagure.io/freeipa/issue/8803

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
Reviewed-By: Sumit Bose <sbose@redhat.com>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
Reviewed-By: Sumit Bose <sbose@redhat.com>
2022-05-10 23:09:17 +03:00
Armando Neto 42afcc95be workshop: Update docs and support default cloud image
Update instructions on how to build images starting with Fedora 34 using
kickstart files used by Fedora to build its cloud images.

Change vagrant provisioning steps to support both prebuilt and default
cloud images, removing the burden of maintaining boxes up-to-date, but
also providing a way to build fresh images without external packer
templates.

Signed-off-by: Armando Neto <abiagion@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
Reviewed-By: Sumit Bose <sbose@redhat.com>
2022-05-10 23:09:17 +03:00
Florence Blanc-Renaud 7f814d9f54 ipatests: --no-dnssec-validation requires --setup-dns
The test test_ipahealthcheck.py::TestIpaHealthCheckWithoutDNS
is installing the server without DNS but calls the installer
with --no-dnssec-validation option.

Remove the --no-dnssec-validation option as it is incompatible
with a non-DNS setup.

Fixes: https://pagure.io/freeipa/issue/9152
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
2022-05-09 09:05:51 +02:00
Sudhir Menon f11b7b3bf5 ipatests: Adding --no-dnssec-validation option for healthcheck
healthcheck related tests are failing because of the below issue
"client @0x7f8ee47c4d48 : servfail cache hit (CD=0)"
and as a result healthcheck related packages are not downloaded on test
system.
Hence adding the --no-dnssec-validation option to install_master
and install_replica function

https://pagure.io/freeipa/issue/9151

Signed-off-by: Sudhir Menon <sumenon@redhat.com>
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
Reviewed-By: Anuja More <amore@redhat.com>
Reviewed-By: Michal Polovka <mpolovka@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-05-06 12:06:33 -04:00
Alexander Bokovoy ea0275f611 js tests: use latest grunt
Allow npm to install and use latest grunt that is compatible with newer
OpenSSL.

This, in turn, requires ATK interfaces to be present for the chromium
installed by puppeteer.

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
2022-05-05 17:44:04 +03:00
Alexander Bokovoy c2434c4e52 Azure CI: don't force non-existing OpenSSL configuration anymore
Newer grunt will pull a PhantomJS that is compatible with newer OpenSSL
so the workaround is not needed anymore.

Additionally, OpenSSL 3.0 is more strict and does not tolerate
non-existing default configuration file.

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
2022-05-05 17:44:04 +03:00
Alexander Bokovoy 137e62cc2f Azure CI: temporarily add libldap_r.so symlink for python-ldap PIP use
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
2022-05-05 17:44:04 +03:00
Alexander Bokovoy 1e882144bb Switch Azure CI to Fedora 36 pre-release
Use fedora-toolbox:36 image as it is prepared to work with systemd and
sudo

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
2022-05-05 17:44:04 +03:00
Alexander Bokovoy 59cf9017a0 web ui: do not provide Remove button in subid page
subid range management does not allow to delete ranges

If subid range was allocated, it cannot be removed because there might
be file objects associated with it on one of IPA clients.

In Web UI a button to remove the range should not be shown.

Remove corresponding test from the Web UI test for subid as the button
to remove the subid range is not present anymore.

Fixes: https://pagure.io/freeipa/issue/9150

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Armando Neto <abiagion@redhat.com>
2022-05-05 15:02:38 +03:00
Florence Blanc-Renaud b3093d9c39 ipatests: remove test_rekey_keytype_DSA
The test is calling getcert rekey -G DSA in order to rekey
a certificate with a DSA key, but DSA support has been disabled
in the default crypto policy, and certmonger does not support it
any more (see the BZ
https://bugzilla.redhat.com/show_bug.cgi?id=2066439)

Remove the test as it's not relevant anymore. The rekey
operation is tested anyway in other tests:
- test_certmonger_rekey_keysize
- test_rekey_keytype_RSA
- test_rekey_request_id

Fixes: https://pagure.io/freeipa/issue/9140
Reviewed-By: Mohammad Rizwan <myusuf@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-05-04 15:00:04 -04:00
Alexander Bokovoy 5ea1866f1b docs: force sphinx version above 3.0 to avoid caching in RTD
ReadTheDocs somehow caches requirements and insists in using old
version of Sphinx (1.8). We have to force using newer one (4.5)

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
2022-05-04 15:50:39 +03:00
Alexander Bokovoy ffd8f14af2 docs: update Sphinx requirements in ipasphinx package
One-liner rule to update ipasphinx dependency as we are using m2r2
package which is compatible with newer Sphinx.

Fixes: https://pagure.io/freeipa/issue/9148

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
2022-05-04 15:50:39 +03:00
Alexander Bokovoy 68c20846cf docs: add the readthedocs configuration
We need to install additional plantuml package before the build

Fixes: https://pagure.io/freeipa/issue/9148

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
2022-05-04 15:50:39 +03:00
Alexander Bokovoy 7ddef72fbb docs: add plantuml and use virtual environment to generate docs
Documentation generator can be run inside Python virtual environment.
This allows to isolate from the system-wide changes and add Sphinx
extensions that aren't packaged in a distribution.

The only exception right now is plantuml package. We rely on plantuml to
generate diagrams and since it is written in Java, it cannot be
installed directly into the Python venv through 'pip' tool.

Fixes: https://pagure.io/freeipa/issue/9148

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
2022-05-04 15:50:39 +03:00
Alexander Bokovoy de918aea19 doc: migrate to m2r2 and newer sphinx, add plantuml to venv
m2r project was forked to m2r2 which is actively developed.
m2r2 works with new Sphinx versions.

Update our list of documentation requirements and add support for
plantuml to be able to integrate diagrams.

Fixes: https://pagure.io/freeipa/issue/9148

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
2022-05-04 15:50:39 +03:00
Florence Blanc-Renaud 5877c4e17a ipatests: update the expected sha256sum of epn.conf file
The file epn.conf has been updated when fixing issue 9145
and the test test_epn.py::TestEPN::test_EPN_config_file
is comparing its sha256sum with the checksum of the
shipped file from the package ipa-client-epn.

The expected checksum needs to be updated.

Fixes: https://pagure.io/freeipa/issue/9146
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-05-03 08:32:26 +02:00
Florence Blanc-Renaud d37d1f717e EPN: document missing option msg_subject
In /etc/ipa/epn.conf it is possible to customize the
e-mail subject by setting msg_subject=<value> but this
setting is not documented in the man page.

Add the options in epn.conf man page and in the template.

Fixes: https://pagure.io/freeipa/issue/9145
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-05-03 08:31:07 +02:00
Antonio Torres 0cdbe00a72 Back to git snapshots
Signed-off-by: Antonio Torres <antorres@redhat.com>
2022-04-26 17:04:41 +02:00
Antonio Torres 029c4fc6e6 Become IPA 4.9.9 2022-04-26 16:53:46 +02:00
Antonio Torres 8a28154a32 Update list of contributors
Signed-off-by: Antonio Torres <antorres@redhat.com>
2022-04-26 16:44:11 +02:00
Antonio Torres 2ffa2b4254 Update translations to FreeIPA ipa-4-9 state
Signed-off-by: Antonio Torres <antorres@redhat.com>
2022-04-26 16:40:35 +02:00
Florence Blanc-Renaud 5ba5143f9e ipatests: fix wrong condition in xfail_context for auto private grp
The tests
TestNonPosixAutoPrivateGroup::test_idoverride_with_auto_private_group
and
TestPosixAutoPrivateGroup::test_gidnumber_not_corresponding_existing_group
are expected to fail until SSSD fixes issues 5988 and 5989.
They currently define an xfail_context with a condition based on
sssd version but that condition is wrong (as of today, no version
of sssd provides the fix).

Remove the wrong condition so that the test is always expected to fail.

Fixes: https://pagure.io/freeipa/issue/9141
Reviewed-By: Anuja More <amore@redhat.com>
2022-04-26 10:00:54 +02:00
Alexander Bokovoy ee6472cee2 ipatests: collect samba logs when setting up trust to AD
In many cases it is impossible to investigate test failures of
environments where a trust to Active Directory is establishe without
Samba logs.

Collect Samba logs by default and make sure Samba is configured with
higher log levels if we are going to configure IPA to setup trust to
Active Directory.

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
2022-04-14 21:33:53 +02:00
Alexander Bokovoy 91d083c36e ipa-sam: retrieve trusted domain account credential from the TDO itself
When NRPC netr_ServerAuthenticate3 call is performed, a trusted AD DC
would use trusted domain account to authenticate to Samba. This means
that Samba would do internally samr_QueryUserInfo2 request with level 16
(UserControlInformation), coming to PDB module via pdb_getsampwsid()
call.

For normal user or workstation accounts we expect to have Kerberos keys
available and may be able to extract NTLM hash data from them. However,
trusted domain account is not a normal Kebreros principal. It stores TDO
credential in a different way. Since we never processed it through the
pdb_getsampwsid() call, it was not possible to retrieve the NTLM hash
for TDO account at all, hence netr_ServerAuthenticate3 call was failing.

NTLM hash is used internally in Samba. An external communication with AD
DC will use an AES-based session key that is derived from the TDO
credential. The credential itself can  be treated as a plaintext here.

Fix it by adding a recognition of the trusted domain object account and
retrieve the NTLM hash from the correct attribute of the TDO.

Fixes: https://pagure.io/freeipa/issue/9134

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
2022-04-14 21:33:53 +02:00
Alexander Bokovoy 710314a794 ipa-pwd-extop: allow ipasam to request RC4-HMAC in Kerberos keys for trusted domain objects
This is a problem since we added commit b5fbbd1 in 2019. Its logic
allowed to add RC4-HMAC keys for cifs/.. service principal but it didn't
account for the case when cifs/.. principal initiates the request.

Since ipasam only uses GETKEYTAB control, provide this extension only
here and don't allow the same for SETKEYTAB. At the point of check for
the bind DN, we already have verified that the DN is allowed to write to
the krbPrincipalKey attribute so there is no leap of faith to 'any
cifs/... principal' here.

A principal must be member of cn=adtrust
agents,cn=sysaccounts,cn=etc,$SUFFIX to allow perform this operation

Fixes: https://pagure.io/freeipa/issue/9134

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
2022-04-14 21:33:53 +02:00
Mohammad Rizwan de1f4467fb ipatests: extend find_segment with suffix param
topologysegment name can be different depending on suffix.
This patch determines and supply the name of topologysgement
as per the suffix

Signed-off-by: Mohammad Rizwan <myusuf@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
2022-04-08 10:31:27 +02:00
Mohammad Rizwan c3bd6908fa ipatests: fix the topologysegment-reinitialize command
There is no guarantee for the topologysegement name, it could be
master-to-replica or replica-to-master. If it is master-to-replica
then --right should be used with the command else --left.

Fixes: https://pagure.io/freeipa/issue/9137

Signed-off-by: Mohammad Rizwan <myusuf@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
2022-04-08 10:31:27 +02:00
Sumit Bose 9cd48d1854 ipa-kdb: fix make check
The recent refactoring split out code into two new files which are
needed for the test binary as well.

Related: https://pagure.io/freeipa/issue/9083
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
2022-04-01 09:44:06 +02:00
Alexander Bokovoy b6b5f6073b ipatests: fix check for AD topology being present
Fixes: https://pagure.io/freeipa/issue/9133

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
2022-03-28 20:33:54 +03:00
Alexander Bokovoy 09481117b5 tests: ensure AD-SUPPORT subpolicy is active in more cases
Continuation of the commit 2eee5931d7:

    Use AD-SUPPORT subpolicy when testing trust to Active Directory in FIPS
    mode. This is required in FIPS mode due to AD not supporting Kerberos
    AES-bases encryption types using FIPS-compliant PBKDF2 and KDF, as
    defined in RFC 8009.

Fixes: https://pagure.io/freeipa/issue/9119

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Anuja More <amore@redhat.com>
2022-03-25 14:34:54 +01:00
Sudhir Menon 98eb661fd8 ipatests: Test for pki.server.healthcheck.clones.connectivity_and_data
This test checks that when
'pki.server.healthcheck.clones.connectivity_and_data' check is run
'Source 'pki.server.healthcheck.clones.connectivity_and_data' not found'
is not displayed.

Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2041995

Signed-off-by: Sudhir Menon <sumenon@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
2022-03-22 13:51:02 +01:00
Florence Blanc-Renaud 85b2c8191b ipatests: Fix a call to run_command with wildcard
The test is calling run_command with a list of arguments:
run_command(['rm', '-f', paths.CERTMONGER_REQUESTS_DIR + '/*'])
but this format does not support shell expansion.

Replace with a str parameter:
run_command('rm -fv' + paths.CERTMONGER_REQUESTS_DIR + '/*')

to make sure all the files in the directory are actually removed.

Fixes: https://pagure.io/freeipa/issue/8506
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-03-19 17:36:33 +01:00
Florence Blanc-Renaud 12785a3657 ipatests: remove certmonger tracking before uninstall
test_ipahealthcheck_expiring is moving the date in the future
in order to check that certmonger properly warns about expiring
certificates, then uninstalls the master.

The uninstallation randomly fails with a DBus error communicating
with certmonger because of a contention between certmonger being
waken up by the call to stop tracking certs and the certmonger
helpers trying to renew the certs.

The test is stopping PKI server, then moves the date in the future.
At this point, certmonger is still running (we are testing that
getcert list properly warns about near expiration). This means that
chances are high that certmonger has enough time to launch the CA helper
for renewal, that takes the lock. But since PKI is down, the helper
remains running for a while and does not release the lock. Then
certmonger is stopped, the tracking files are removed, certmonger is
restarted.

To avoid the contention, manually remove the tracking before
calling uninstall and remove the renewal lock file.

Fixes: https://pagure.io/freeipa/issue/9123
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-03-19 17:36:33 +01:00
Rob Crittenden c46ea21ed3 Remove the --no-sssd option from ipa-client-automount
This makes automount configurable only using sssd and not LDAP.
The reason is that authselect 1.3 no longer supports
user-nsswitch.conf which is where we made direct changes to the
nss configuration on Fedora/RHEL.

The equivalent option was removed from ipa-client-install in
https://pagure.io/freeipa/issue/7671

Fixes: https://pagure.io/freeipa/issue/9084

Signed-off-by: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
2022-03-18 14:28:11 +01:00
Alexander Bokovoy 3e8a355dd4 ipalib/util.py: switch to ssl.PROTOCOL_TLS_CLIENT by default
Python 3.10 deprecated ssl.PROTOCOL_TLS and ssl.PROTOCOL_SSLv23
constants which were aliases to each other. Use of them now causes a
warning to be displayed:

/usr/lib/python3.10/site-packages/ipalib/util.py:347: DeprecationWarning: ssl.PROTOCOL_TLS is deprecated
  ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)

Use ssl.PROTOCOL_TLS_CLIENT instead, this constant is available since
Python 3.6.

Fixes: https://pagure.io/freeipa/issue/9129

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-03-18 09:38:05 +01:00
Rob Crittenden bd8748f6b7 Convert values using _SYNTAX_MAPPING with --delattr
When an entry is loaded the incoming values are converted
into python datatypes automatically based on the _SYNTAX_MAPPING
value in ipaldap.

When using delattr to remove a mapped value it will fail because
the datatypes do not match up. For example date types are
datetime.datetime structions and won't match a generalized time
string.

So try to map the value to delete using _SYNTAX_MAPPING before
trying to remove the value. Fall back to trying to remove the
raw value if the mapping fails.

This won't work for some mapping types, DNs for example. Providing
only the RDN value for a DN-type, manager for example, lacks the
context to know how to construct the DN (RDN and contaner).

Fixes: https://pagure.io/freeipa/issue/9004

Signed-off-by: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
2022-03-16 16:27:20 +02:00
Mohammad Rizwan 83551693b3 ipatests: Check maxlife error message where minlife > maxlife specified
When minlife > maxlife specified on commandline, it says:
"ipa: ERROR: invalid 'maxlife': Maximum password life must be
greater than minimum."

But when minlife == maxlife specfied, It works.
This test check that error message says what exactly it does

related: https://pagure.io/freeipa/issue/9038

Signed-off-by: Mohammad Rizwan <myusuf@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
2022-03-16 16:26:03 +02:00
Francisco Trivino 984190eea0 Set AES as default for KRA archival wrapping
This commit sets AES-128-CBC as default wrapping algorithm as
TripleDES (des-ede3-cbc) is not supported anymore in C9S.

Fixes: https://pagure.io/freeipa/issue/6524

Signed-off-by: Francisco Trivino <ftrivino@redhat.com>
Reviewed-By: Christian Heimes <cheimes@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
2022-03-16 16:24:02 +02:00
Christian Heimes 895e99b684 Support AES for KRA archival wrapping
The vault plugin has used TripleDES (des-ede3-cbc) as default wrapping
algorithm since the plugin was introduced. Allow use of AES-128-CBC as
alternative wrapping algorithm for transport of secrets.

Fixes: https://pagure.io/freeipa/issue/6524

Signed-off-by: Christian Heimes <cheimes@redhat.com>
Reviewed-By: Christian Heimes <cheimes@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
2022-03-16 16:24:02 +02:00
Alexander Bokovoy 2e70535f74 test_krbtpolicy: skip SPAKE-related tests in FIPS mode
SPAKE is based on the crypto primitives which are not FIPS compliant
yet. This means that in FIPS mode use of 'hardened' authentication
indicator is not possible. Skip corresponding tests in FIPS mode.

Related: https://pagure.io/freeipa/issue/9119

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
2022-03-16 16:21:52 +02:00
Alexander Bokovoy 3baae8d1bd test_otp: do not use paramiko unless it is really needed
paramiko cannot be used in FIPS mode. We have few tests that import
generic methods from test_otp (add_token/del_token) and those tests fail
in FIPS mode due to unconditional 'import paramiko'.

Instead, move 'import paramiko' to the ssh_2f() helper which is not used
in FIPS mode (the whole SSH 2FA test is skipped then).

Related: https://pagure.io/freeipa/issue/9119

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
2022-03-16 16:21:52 +02:00
Alexander Bokovoy 3e54c43624 Kerberos instance: default to AES256-SHA2 for master key encryption
KDC configuration in /var/kerberos/krb5kdc/kdc.conf is generated from
the template in install/share/kdc.conf.template. Master key encryption
type specified there is used to bootstrap the master key in LDAP
database. Once it is done, actual deployment does not rely on the
master_key_type value anymore. The actual master key(s) get loaded from
LDAP database where they stored in a BER-encoded format, preserving all
parameters, including encryption type.

This means we can safely migrate to AES256-SHA2 as the default master
key encryption type for new installations. Replicas will get their
master key encryption type details from the server they were provisioned
from.

MIT Kerberos supports AES256-SHA2 since 1.15 (2015), meaning RHEL 7.4 is
the earliest supported version as it provides krb5 1.15.1. Current
supported RHEL 7 version is RHEL 7.9. Since RHEL 6 already cannot be
used as a replica to IPA 4.5+ due to a domain level 1 upgrade, this
change does not affect old releases.

Migration from the previously deployed master key encryption type is
described by MIT Kerberos upstream in
http://web.mit.edu/kerberos/krb5-latest/doc/admin/advanced/retiring-des.html#the-database-master-key

One would need to use '-x ipa-setup-override-restrictions' to allow
the `kdb5_util` utility to modify the data over IPA KDB driver.

Fixes: https://pagure.io/freeipa/issue/9119

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
2022-03-16 16:21:52 +02:00
Sumit Bose cedca75f4f extdom: user getorigby{user|group}name if available
New calls, getorigbyusername() and getorigbygroupname(), are added to
libsss_nss_idmap. They allow to query the AD specific attributes for a
user or a group directly. Besides a minor performance benefit it helps
to avoid issues if there are users and groups with the same name and the
group is not a user-private group but a real group with members.

Fixes: https://pagure.io/freeipa/issue/9127
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
2022-03-16 16:19:02 +02:00
Rob Crittenden 3a4238ba96 ipatests: Give the subCA more time to be loaded by the CA
The subCA keys are loaded out-of-band after creation into the
CA so they may have been replicated but not loaded. Give more
time for them to appear in the remote CA.

Use a loop for the checking instead of a raw sleep because most
of the time this is very fast (< 15 seconds) but sometimes it
requires just a bit more. Allow up to 60 seconds.

To avoid output difference, strip the token name out of certutil
output. We don't care about the token a certificate is stored
in, the internal or the FIPS token. We just care that they exist
on both servers and that the keys match.

Apparently in some cases the token name is displayed and not in
others so lets normalize the output to make comparisons more
consistent.

Fixes: https://pagure.io/freeipa/issue/9096

Signed-off-by: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Mohammad Rizwan Yusuf <myusuf@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Stanislav Levin <slev@altlinux.org>
2022-03-16 11:07:24 +02:00
Fraser Tweedale b413a327f3 allow overriding systemd-tmpfiles program
In some contexts, filesystem mounts may be owned by unmapped users
(e.g. `emptyDir` mounts in Kubernetes / OpenShift when using user
namespaces).  This causes `systemd-tmpfiles(8)` to fail, as a
consequence of systemd's path processing routines which reject this
scenario.  Therefore, in Fedora container context, if the
`IPA_TMPFILES_PROG` environment value is set, use the program
specified by its value instead of `/bin/systemd-tmpfiles`.

Signed-off-by: Fraser Tweedale <ftweedal@redhat.com>
Fixes: https://pagure.io/freeipa/issue/9126
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-03-15 08:32:56 +01:00
Stanislav Levin 1e2cf55150 azure: Bump supported Pylint
Fixes: https://pagure.io/freeipa/issue/9117
Signed-off-by: Stanislav Levin <slev@altlinux.org>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-03-14 10:44:55 -04:00
Stanislav Levin b58ec49da9 pylint: Skip false-positive invalid-sequence-index
Pylint doesn't handle flow control and thus, doesn't understand
that a key of type `str` is not reachable at this point:

> ipalib/base.py:472: [E1126(invalid-sequence-index),
  NameSpace.__getitem__] Sequence index is not an int, slice, or instance
  with __index__)

Note: I faced this error on Python3.9 and didn't see it using
Python3.10.

Fixes: https://pagure.io/freeipa/issue/9117
Signed-off-by: Stanislav Levin <slev@altlinux.org>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-03-14 10:44:55 -04:00
Stanislav Levin 6202a7d85b pylint: Fix useless-suppression
Cleanup up no longer used Pylint's disables where possible.

Fixes: https://pagure.io/freeipa/issue/9117
Signed-off-by: Stanislav Levin <slev@altlinux.org>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-03-14 10:44:55 -04:00
Stanislav Levin c5b4657869 pylint: Fix format-string-without-interpolation
Found by new Pylint:
> ipaclient/install/client.py:1926:
[W1310(format-string-without-interpolation), get_ca_certs] Using
formatting for a string that does not have any interpolated variables)

Fixes: https://pagure.io/freeipa/issue/9117
Signed-off-by: Stanislav Levin <slev@altlinux.org>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-03-14 10:44:55 -04:00
Stanislav Levin bfb233185a pylint: Skip unsupported-assignment-operation
Pylint thinks that the values are None because doesn't support
flow analysis.

Fixes: https://pagure.io/freeipa/issue/9117
Signed-off-by: Stanislav Levin <slev@altlinux.org>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-03-14 10:44:55 -04:00
Stanislav Levin fd99e4d47a pylint: Fix deprecated-method for threading
As of Python3 `currentThread`, `thread.getName` are aliases for
`threading.current_thread()` and `threading.Thread.name`
respectively.

In Python3.10:
> bpo-43723: The following threading methods are now deprecated and
  should be replaced:
  currentThread => threading.current_thread()
  activeCount => threading.active_count()
  Condition.notifyAll => threading.Condition.notify_all()
  Event.isSet => threading.Event.is_set()
  Thread.setName => threading.Thread.name
  thread.getName => threading.Thread.name
  Thread.isDaemon => threading.Thread.daemon
  Thread.setDaemon => threading.Thread.daemon

Fixes: https://pagure.io/freeipa/issue/9117
Signed-off-by: Stanislav Levin <slev@altlinux.org>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-03-14 10:44:55 -04:00
Stanislav Levin 1f17ade67f pylint: Skip deprecated-method for match_hostname
Python3.7 switched to
`X509_VERIFY_PARAM_set1_host`/`X509_VERIFY_PARAM_set1_ip`
and deprecated `match_hostname` without replacement. Probably,
on removal `match_hostname` the similar functionality may be
implemented on IPA side.

https://docs.python.org/3/library/ssl.html#ssl.match_hostname

Fixes: https://pagure.io/freeipa/issue/9117
Signed-off-by: Stanislav Levin <slev@altlinux.org>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-03-14 10:44:55 -04:00
Stanislav Levin 3ea0e1bd8d pylint: Fix consider-using-in
Pylint 2.11.0 extends consider-using-in check to work for
attribute access.

> To check if a variable is equal to one of many values,combine the
  values into a tuple and check if the variable is contained "in" it
  instead of checking for equality against each of the values.This
  is faster and less verbose.

Fixes: https://pagure.io/freeipa/issue/9117
Signed-off-by: Stanislav Levin <slev@altlinux.org>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-03-14 10:44:55 -04:00
Stanislav Levin a960adc6c2 pylint: Fix arguments-renamed
Pylint 2.9.0 introduced new checker which was a subset of
arguments-differ:

> Used when a method parameter has a different name than in the
  implemented interface or in an overridden method.

Fixes: https://pagure.io/freeipa/issue/9117
Signed-off-by: Stanislav Levin <slev@altlinux.org>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-03-14 10:44:55 -04:00
Stanislav Levin 03cd914381 pylint: Skip use-implicit-booleaness-not-comparison
Pylint 2.12.0 introduced new checker:
> Used when Pylint detects that collection literal comparison is being
  used to check for emptiness; Use implicit booleaness insteadof a
  collection classes; empty collections are considered as false

Comparison of variable to equality to collection:
> Lexicographical comparison between built-in collections works as follows:
  For two collections to compare equal, they must be of the same type,
  have the same length, and each pair of corresponding elements must
  compare equal (for example, [1,2] == (1,2) is false because the type is
  not the same).
  Collections that support order comparison are ordered the same as their
  first unequal elements (for example, [1,2,x] <= [1,2,y] has the same
  value as x <= y). If a corresponding element does not exist, the shorter
  collection is ordered first (for example, [1,2] < [1,2,3] is true).

So, `assert value == {}` is not the same as `assert not value`.

Fixes: https://pagure.io/freeipa/issue/9117
Signed-off-by: Stanislav Levin <slev@altlinux.org>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-03-14 10:44:55 -04:00
Stanislav Levin 2db2c6cb32 pylint: Enable useless-suppression
https://pylint.pycqa.org/en/latest/user_guide/message-control.html#detecting-useless-disables:

> As pylint gets better and false positives are removed, disables that
  became useless can accumulate and clutter the code. In order to clean
  them you can enable the useless-suppression warning.

This doesn't enforce useless-suppression warnings as errors. The idea is
cleanup of these warings on every Pylint's bump.

Fixes: https://pagure.io/freeipa/issue/9117
Signed-off-by: Stanislav Levin <slev@altlinux.org>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-03-14 10:44:55 -04:00
Stanislav Levin bb515f41b3 pylint: Skip raising-bad-type
See https://github.com/PyCQA/pylint/issues/4772 for details.

Fixes: https://pagure.io/freeipa/issue/9117
Signed-off-by: Stanislav Levin <slev@altlinux.org>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-03-14 10:44:55 -04:00
Stanislav Levin 322d08921a pylint: Fix consider-using-dict-items
Pylint 2.9 introduced new check:
> New checker consider-using-dict-items. Emitted when iterating over
dictionary keys and then indexing the same dictionary with the key
within loop body.

Fixes: https://pagure.io/freeipa/issue/9117
Signed-off-by: Stanislav Levin <slev@altlinux.org>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-03-14 10:44:55 -04:00
Stanislav Levin 13e5720d18 pylint: Skip not-callable
The klass property is referenced to class attribute.
Today's Pylint doesn't support this.

Fixes: https://pagure.io/freeipa/issue/9117
Signed-off-by: Stanislav Levin <slev@altlinux.org>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-03-14 10:44:55 -04:00
Stanislav Levin 76c2c08fdb pylint: Fix unused-variable
Fixed newly exposed unused variables.

Fixes: https://pagure.io/freeipa/issue/9117
Signed-off-by: Stanislav Levin <slev@altlinux.org>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-03-14 10:44:55 -04:00
Stanislav Levin 08f2db7855 pylint: Fix no-member
Teach pylint or skip newly exposed no-members.

Fixes: https://pagure.io/freeipa/issue/9117
Signed-off-by: Stanislav Levin <slev@altlinux.org>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-03-14 10:44:55 -04:00
Stanislav Levin afba414770 pylint: Skip isinstance-second-argument-not-valid-type
The type of value to be compared is class attribute.
Today's Pylint doesn't support this.

Fixes: https://pagure.io/freeipa/issue/9117
Signed-off-by: Stanislav Levin <slev@altlinux.org>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-03-14 10:44:55 -04:00
Stanislav Levin 054376c1a0 pylint: Fix deprecated-decorator
Pylint 2.9 introduced new checker:
> The decorator is marked as deprecated and will be removed in the
  future.

- @abstractproperty has been deprecated since Python3.3 [0]
- @abstractclassmethod has been deprecated since Python3.3 [1]

[0]: https://docs.python.org/3/library/abc.html#abc.abstractproperty
[1]: https://docs.python.org/3/library/abc.html#abc.abstractclassmethod

Fixes: https://pagure.io/freeipa/issue/9117
Signed-off-by: Stanislav Levin <slev@altlinux.org>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-03-14 10:44:55 -04:00
Stanislav Levin d3b384b5ca pylint: Fix unnecessary-dict-index-lookup
Pylint 2.9 introduced new check:
> Emitted when iterating over the dictionary items (key-item pairs) and
accessing the value by index lookup. The value can be accessed directly
instead.

Note: in Python3 removing from dict during an iteration is not
possible even. For example,
```
cat a.py
d = {"a": 1}

for k, v in d.items():
    if v is not None:
        del d[k]

python3 a.py
Traceback (most recent call last):
  File "/usr/src/RPM/BUILD/freeipa/a.py", line 3, in <module>
    for k, v in d.items():
RuntimeError: dictionary changed size during iteration
```

Fixes: https://pagure.io/freeipa/issue/9117
Signed-off-by: Stanislav Levin <slev@altlinux.org>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-03-14 10:44:55 -04:00
Stanislav Levin ccf9334da9 pylint: Fix deprecated-class
There is no actual usage of deprecated classes for Python3.
Pylint complains about such for Python2. Since Python2 is no
longer supported these imports were removed.

Fixes: https://pagure.io/freeipa/issue/9117
Signed-off-by: Stanislav Levin <slev@altlinux.org>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-03-14 10:44:55 -04:00
Stanislav Levin 0ebf09e061 pylint: Remove unused __convert_iter
__convert_iter was added in 24b6cb89d, but it was never used.

Found by Pylint:
```
ipalib/frontend.py:696: [W0238(unused-private-member),
Command.__convert_iter] Unused private member
`Command.__convert_iter(self, kw)`)
```

Fixes: https://pagure.io/freeipa/issue/9117
Signed-off-by: Stanislav Levin <slev@altlinux.org>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-03-14 10:44:55 -04:00
Stanislav Levin 91ff7b87d9 pylint: Drop no longer used __home
`__home` has been added in 8ca44bcbfa,
later `tests.util` was refactored in
fd43b39145, but `__home` wasn't cleaned
up.

Fixes: https://pagure.io/freeipa/issue/9117
Signed-off-by: Stanislav Levin <slev@altlinux.org>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-03-14 10:44:55 -04:00
Stanislav Levin 4da897c3dc pylint: Fix unused-private-member
Pylint 2.9.0 introduced new checker:
> Emitted when a private member of a class is defined but not used

Fixes: https://pagure.io/freeipa/issue/9117
Signed-off-by: Stanislav Levin <slev@altlinux.org>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-03-14 10:44:55 -04:00
Stanislav Levin bffde84c81 pylint: Skip unused-private-member for unsupported cases
> This mangling is done without regard to the syntactic position of the
identifier, as long as it occurs within the definition of a class.

`__set_attr` is called for instance of the class within its
classmethod.

Fixes: https://pagure.io/freeipa/issue/9117
Signed-off-by: Stanislav Levin <slev@altlinux.org>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-03-14 10:44:55 -04:00
Stanislav Levin 9ca818b179 pylint: Skip unused-private-member for property case
See https://github.com/PyCQA/pylint/issues/4756 for details

Fixes: https://pagure.io/freeipa/issue/9117
Signed-off-by: Stanislav Levin <slev@altlinux.org>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-03-14 10:44:55 -04:00
Stanislav Levin dfa1ceac6f pylint: Drop no longer used __finalized
The private member `__finalized` has been added in
7db3aae1b2, later removed in
6b8abb0d78, but `_API__finalized`
(access via mangled attribute name) was not cleaned up and finally
refactored back to `__finalized` in
b1fc875c3a.

Found by Pylint:
```
ipalib/plugable.py:807: [W0238(unused-private-member), API.finalize]
Unused private member `API.__finalized`)
```

Fixes: https://pagure.io/freeipa/issue/9117
Signed-off-by: Stanislav Levin <slev@altlinux.org>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-03-14 10:44:55 -04:00
Stanislav Levin 3c77949ab4 pylint: Drop never used __remove_lightweight_ca_key_retrieval_custodia
__remove_lightweight_ca_key_retrieval_custodia has been added in
8700101d9, but it was never used.

Caught by Pylint:
```
ipaserver/install/cainstance.py:1308: [W0238(unused-private-member),
CAInstance.__remove_lightweight_ca_key_retrieval_custodia]
Unused private member
`CAInstance.__remove_lightweight_ca_key_retrieval_custodia(self)`)
```

Fixes: https://pagure.io/freeipa/issue/9117
Signed-off-by: Stanislav Levin <slev@altlinux.org>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-03-14 10:44:55 -04:00
Stanislav Levin 04c4032370 pylint: Clean up __convert_to_gssapi_replication
__convert_to_gssapi_replication has been added in a0bfbec19 and
then removed in ce2bb47cc without clean up.

Found by Pylint:
```
ipaserver/install/krbinstance.py:589: [W0238(unused-private-member),
KrbInstance.__convert_to_gssapi_replication] Unused private member
`KrbInstance.__convert_to_gssapi_replication(self)`)
```

Fixes: https://pagure.io/freeipa/issue/9117
Signed-off-by: Stanislav Levin <slev@altlinux.org>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-03-14 10:44:55 -04:00
Stanislav Levin 6fd75de5a7 pylint: Fix use-maxsplit-arg
Pylint 2.9.0 new checker:
> Emitted when accessing only the first or last element of str.split().
  The first and last element can be accessed by using str.split(sep,
  maxsplit=1)[0] or str.rsplit(sep, maxsplit=1)[-1] instead.

Fixes: https://pagure.io/freeipa/issue/9117
Signed-off-by: Stanislav Levin <slev@altlinux.org>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-03-14 10:44:55 -04:00
Stanislav Levin 106d011e5f pylint: Skip unspecified-encoding
Pylint 2.10 introduced new checker:
> It is better to specify an encoding when opening documents. Using the
  system default implicitly can create problems on other operating
  systems. See https://www.python.org/dev/peps/pep-0597/

According to that PEP:
> open(filename) isn't explicit about which encoding is expected:
  - If ASCII is assumed, this isn't a bug, but may result in decreased
    performance on Windows, particularly with non-Latin-1 locale
    encodings
  - If UTF-8 is assumed, this may be a bug or a platform-specific script
  - If the locale encoding is assumed, the behavior is as expected (but
    could change if future versions of Python modify the default)

IPA requires UTF-8 environments.

Fixes: https://pagure.io/freeipa/issue/9117
Signed-off-by: Stanislav Levin <slev@altlinux.org>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-03-14 10:44:55 -04:00
Stanislav Levin 40ee6a47ac pylint: Skip use-dict-literal/use-list-literal
Pylint 2.10 introduced new checkers:
> Emitted when using dict() to create an empty dictionary instead of the
  literal {}. The literal is faster as it avoids an additional function
  call.

> Emitted when using list() to create an empty list instead of the
  literal []. The literal is faster as it avoids an additional function
  call.

Too many unessential changes.

Fixes: https://pagure.io/freeipa/issue/9117
Signed-off-by: Stanislav Levin <slev@altlinux.org>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-03-14 10:44:55 -04:00
Stanislav Levin b5fc2eeff9 pylint: Skip consider-using-f-string
Pylint 2.11 introduced new checker:
> Used when we detect a string that is being formatted with format() or
  % which could potentially be a f-string. The use of f-strings is
  preferred. Requires Python 3.6 and ``py-version >= 3.6``.

- f-strings are not mandatory
- format can be more readable
- there are ~5.5K spotted issues

Fixes: https://pagure.io/freeipa/issue/9117
Signed-off-by: Stanislav Levin <slev@altlinux.org>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-03-14 10:44:55 -04:00
Stanislav Levin 7f8b4f0368 pylint: Skip redundant-u-string-prefix
Pylint 2.10 introduced new checker `redundant-u-string-prefix`:
> Used when we detect a string with a u prefix. These prefixes were
  necessary in Python 2 to indicate a string was Unicode, but since Python
  3.0 strings are Unicode by default.

There are ~31K emitted warnings right now. They can be fixed on
refactorings without any rush.

Fixes: https://pagure.io/freeipa/issue/9117
Signed-off-by: Stanislav Levin <slev@altlinux.org>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-03-14 10:44:55 -04:00
Alexander Bokovoy ee39de46a1 freeipa.spec: bump crypto-policies dependency for CentOS 9 Stream
Fixes: https://pagure.io/freeipa/issue/9119

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Julien Rische <jrische@redhat.com>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
2022-03-08 17:15:55 +01:00
Alexander Bokovoy 49d9147e38 ipatests: extend AES keyset to SHA2-based ones
Fixes: https://pagure.io/freeipa/issue/9119

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Julien Rische <jrische@redhat.com>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
2022-03-08 17:15:55 +01:00
Alexander Bokovoy b016683552 tests: ensure AD-SUPPORT subpolicy is active
Use AD-SUPPORT subpolicy when testing trust to Active Directory in FIPS
mode. This is required in FIPS mode due to AD not supporting Kerberos
AES-bases encryption types using FIPS-compliant PBKDF2 and KDF, as
defined in RFC 8009.

Fixes: https://pagure.io/freeipa/issue/9119

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Julien Rische <jrische@redhat.com>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
2022-03-08 17:15:55 +01:00
Alexander Bokovoy a51900819b KRB instance: make provision to work with crypto policy without SHA-1 HMAC types
RHEL 9 system-wide crypto policies aim at eventual removal of SHA-1 use.

Due to bootstrapping process, force explicitly supported encryption
types in kdc.conf or we may end up with AES128-SHA1 and AES256-SHA2 only
in FIPS mode at bootstrap time which then fails to initialize kadmin
principals requiring use of AES256-SHA2 and AES128-SHA2.

Camellia ciphers must be filtered out in FIPS mode, we do that already
in the kerberos.ldif.

At this point we are not changing the master key encryption type to
AES256-SHA2 because upgrading existing deployments is complicated and
at the time when a replica configuration is deployed, we don't know what
is the encryption type of the master key of the original server as well.

Fixes: https://pagure.io/freeipa/issue/9119

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Julien Rische <jrische@redhat.com>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
2022-03-08 17:15:55 +01:00
Florence Blanc-Renaud 42f41ff637 ipatests: add missing test in the nightly defs
The test
test_integration/test_installation.py::TestInstallWithoutNamed
was missing in some nightly definitions.
Add the job definition for nightly_ipa-4-9_latest_selinux.yaml

Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-03-03 08:12:58 +01:00
Rob Crittenden 57de18e914 Strip off trailing period of a user-provided FQDN in installer
The example text included a trailing dot which isn't actually
allowed in a system hostname (just DNS). Remove the suggestion
to include it and strip off any trailing dot so that the install
can proceed.

Related: https://pagure.io/freeipa/issue/9111

Signed-off-by: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
2022-02-25 11:15:39 +01:00
Rob Crittenden 7ac8e9696e Verify the user-provided hostname in the server installer
The refactor change 9094dfc had a slight error where the
user-input provided value in input wasn't being validated. Only
the command-line or the current FQDN was being verified so
if the FQDN was bad any value input by the user was being skipped.

Fixes: https://pagure.io/freeipa/issue/9111

Signed-off-by: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
2022-02-25 11:15:39 +01:00
Rob Crittenden ab9e7dac41 ipa-restore: Mark a restored server as enabled
There is no use-case to keep a restored server in a hidden
state. It can be re-marked as hidden once the installation is
recovered from the restore. So mark all restored services as
enabled so they are visible to existing clients during the
remaining recovery.

Fixes: https://pagure.io/freeipa/issue/9095

Signed-off-by: Rob Crittenden <rcritten@redhat.com>
2022-02-24 08:53:34 +01:00
Anuja More 7ad500e5d3 Mark xfail test_gidnumber_not_corresponding_existing_group[true,hybrid]
Related : https://github.com/SSSD/sssd/issues/5988

Signed-off-by: Anuja More <amore@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Anuja More <amore@redhat.com>
2022-02-24 08:46:15 +01:00
Anuja More 84381001d2 mark xfail for test_idoverride_with_auto_private_group[hybrid]
Related : https://github.com/SSSD/sssd/issues/5989

Signed-off-by: Anuja More <amore@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Anuja More <amore@redhat.com>
2022-02-24 08:46:15 +01:00
Anuja More 6b70e3c49a ipatests: Tests for Autoprivate group.
Added tests using posix AD trust and non posix AD trust.
For option --auto-private-groups=[hybrid/true/false]

Related : https://pagure.io/freeipa/issue/8807

Signed-off-by: Anuja More <amore@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Anuja More <amore@redhat.com>
2022-02-24 08:46:15 +01:00
Rob Crittenden d8174b0ca6 Set the mode on ipaupgrade.log during RPM %post snipppet
The IPA tools will create /var/log/ipaupgrade.log with mode
0600. If for some reason this file doesn't exist during
upgrade then it will be created by the RPM transaction with
mode 0644 (because of umask).

So always set the mode once the snippets are done. This
will ensure that a newly created log will have the expected
mode and also fix any previous incorrectly set mode.

Fixes: https://pagure.io/freeipa/issue/8899

Signed-off-by: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Stanislav Levin <slev@altlinux.org>
2022-02-23 10:04:19 +01:00
Florence Blanc-Renaud f2731107db Commit template: use either Fixes or Related
Update the commit template to be consistent with the
commit message requirements described at
https://www.freeipa.org/page/Contribute/Code#Commit_message_requirements

Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Mohammad Rizwan <myusuf@redhat.com>
2022-02-22 14:46:44 +01:00
Francisco Trivino 186ebe311b ipa_cldap: fix memory leak
ipa_cldap_encode_netlogon() allocates memory to store binary data as part of
berval (bv_val) when processing a CLDAP packet request from a worker. The
data is used by ipa_cldap_respond() but bv_val is not freed later on.

This commit is adding the corresponding free() after ipa_cldap_respond()
is completed.

Discovered by LeakSanitizer

Fixes: https://pagure.io/freeipa/issue/9110
Signed-off-by: Francisco Trivino <ftrivino@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Thierry Bordaz <tbordaz@redhat.com>
2022-02-14 11:33:05 +02:00
Brian Turek 837702199c ipalib: Handle percent signs in saved values
Turn off string interpolation on the FileStore class to avoid
exceptions when a value to be saved contains a percent sign (%).
The underlying SafeConfigParser that is used interprets percent
signs as placeholders to be interpolated which then causes an
exception as the placeholder isn't properly formatted.

ipa-client-install uses the FileStore class to backup certain
values that it overwrites as part of the installation. If those
pre-existing, backed-up values contained a percent sign,
ipa-client-install would throw an exception and thus prevent
installation.

https://pagure.io/freeipa/issue/9085

Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-02-14 11:18:07 +02:00
Anuja More b36bcf4ea5 ipatests: remove additional check for failed units.
On RHEL tests are randomly failing because of this check
and the test doesn't need to check this.

Related : https://pagure.io/freeipa/issue/9108

Signed-off-by: Anuja More <amore@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
2022-02-14 11:13:55 +02:00
Rob Crittenden cc2348aedb ipatests: Remove certmonger tracking before uninstall in cert tests
There is some contention between certmonger starting during the
uninstallation process in order to stop the tracking and activity
going on within certmonger helpers.

As near as I can tell certmonger is not running, then IPA is
stopped in order to uninstall, then certmonger is started to stop
the tracking. certmonger checks cert status on startup but since
IPA isn't running it can't get a host ticket. During this time any
request over DBus may time out, causing a test to fail when we're
just trying to clean up.

https://pagure.io/freeipa/issue/8506

Signed-off-by: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
2022-02-14 11:09:46 +02:00
Stanislav Levin 86b98b86f6 ipatests: healthcheck: Sync the expected system RRs
The support for the DNS URI RRs has been added in freeipa-healthcheck:
https://github.com/freeipa/freeipa-healthcheck/issues/222

Fixes: https://pagure.io/freeipa/issue/9054
Signed-off-by: Stanislav Levin <slev@altlinux.org>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-02-10 08:39:47 +01:00
Mohammad Rizwan 0d9eb3d515 Test ipa-ccache-sweep.timer enabled by default during installation
This test checks that ipa-ccache-sweep.timer is enabled by default
during the ipa installation.

related: https://pagure.io/freeipa/issue/9107

Signed-off-by: Mohammad Rizwan <myusuf@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
2022-02-10 08:33:14 +01:00
Rob Crittenden 9b6d0bb124 Enable the ccache sweep timer during installation
The timer was only being enabled during package installation
if IPA was configured. So effectively only on upgrade.

Add as a separate installation step after the ccache directory
is configured.

Fixes: https://pagure.io/freeipa/issue/9107

Signed-off-by: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
2022-02-10 08:33:14 +01:00
Florence Blanc-Renaud 896d0f3516 ipatests: update images for f34 and f35
The new images include 389-ds-base 2.0.14-1
which contains the fixes for  the following tickets:

389-ds-base #5079 Freeipa nightly test failure with winsync agreement
389-ds-base #5031 ipa-restore broken in selinux enforcing mode

Fixes: https://pagure.io/freeipa/issue/9069
Fixes: https://pagure.io/freeipa/issue/9051

Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Armando Neto <abiagion@redhat.com>
2022-02-08 18:32:24 +01:00
Alexander Bokovoy 0d034d7fd4 translations: regenerate translations after changes in help message in sudorule
A change to replace -h and -p options in OpenLDAP command line utilities
causes also an update in the help text in sudorule plugin. This, sadly,
makes existing translations of that text not valid anymore. However, we
have to change the text as OpenLDAP 2.6+ will make the command
referenced in the help text incorrect.

The change in OpenLDAP 2.6+ implements deprecation that was announced by
OpenLDAP project around 20 years ago, so all existing tools support -H
option.

See also: https://bugs.openldap.org/show_bug.cgi?id=8618

Related: https://pagure.io/freeipa/issue/9106

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
2022-02-07 13:03:47 +02:00
Alexander Bokovoy 10d32d43e4 pylint: workaround incorrect pylint detection of a local function
pylint 2.9 thinks that __add_principal is a class-level method that is
unused. It is a local function inside one of class methods and is used
directly inside that method.

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
2022-02-07 13:03:47 +02:00
Alexander Bokovoy 85ce7acb73 OpenLDAP 2.6+: use only -H option to specify LDAP url
OpenLDAP 2.6+ finally deprecated -h and -p options in all its command
line tools. They are not allowed anymore and cause ldap* tools to stop
hard with 'unknown option' error.

Fix this by always using -H url option instead. Deriving default value
for -H url from the configuration file still works, it is only -h and -p
that were deprecated.

See also: https://bugs.openldap.org/show_bug.cgi?id=8618

Fixes: https://pagure.io/freeipa/issue/9106

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
2022-02-07 13:03:47 +02:00
Rob Crittenden 7c5540bb47 Remove ipa-join errors from behind the debug option
This brings it inline with the previous XML-RPC output which
only hid the request and response from the output and not
any errors returned.

https://pagure.io/freeipa/issue/9103

Signed-off-by: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
Reviewed-By: Peter Keresztes Schmidt <carbenium@outlook.com>
2022-02-07 09:16:32 +01:00
Rob Crittenden edb216849e Don't always override the port in import_included_profiles
I can only guess to the original purpose of this override. I
believe it was because this is called in the installer prior
to Apache being set up. The expectation was that this would
only be called locally. It predates the RestClient class.

RestClient will attempt to find an available service. In this
case, during a CA installation, the local server is not
considered available because it lacks an entry in
cn=masters. So it will never be returned as an option.

So by overriding the port to 8443 the remote connection will
likely fail because we don't require that the port be open.

So instead, instantiate a RestClient and see what happens.

There are several use-cases:

1. Installing an initial server. The RestClient connection
   should fail, so we will fall back to the override port and
   use the local server. If Apache happens to be running with
   a globally-issued certificate then the RestClient will
   succeed. In this case if the connected host and the local
   hostname are the same, override in that case as well.

2. Installing as a replica. In this case the local server should
   be ignored in all cases and a remote CA will be picked with
   no override done.

3. Switching from CA-less to CA-ful. The web server will be
   trusted but the RestClient login will fail with a 404. Fall
   back to the override port in this case.

The motivation for this is trying to install an EL 8.x replica
against an EL 7.9 server. 8.5+ includes the ACME service and
a new profile is needed which doesn't exist in 7. This was
failing because the RestClient determined that the local server
wasn't running a CA so tried the remote one (7.9) on the override
port 8443. Since this port isn't open: failure.

Chances are that adding the profile is still going to fail
because again, 7.9 lacks ACME capabilities, but it will fail in
a way that allows the installation to continue.

I suspect that all of the overrides can similarly handled, or
handled directly within the RestClient class, but for the sake
of "do no harm" I'm only changing this instance for now.

https://pagure.io/freeipa/issue/9100

Signed-off-by: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
2022-02-04 09:32:30 +01:00
Julien Rische 294ae35a61 ipatests: add case for hardened-only ticket policy
Signed-off-by: Julien Rische <jrische@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
2022-02-02 21:51:44 +01:00
Julien Rische 6d70421f57 ipa-kdb: do not remove keys for hardened auth-enabled users
Since 5d51ae5, principal keys were dropped in case user auth indicator
was not including password. Thereafter, the key removal behavior was
removed by 15ff9c8 in the context of the kdcpolicy plugin introduction.
Support for hardened pre-auth methods (FAST and SPAKE) was added in
d057040, and the removal of principal keys was restored afterwards by
f0d12b7, but not taking the new hardened auth indicator into account.

Fixes: https://pagure.io/freeipa/issue/9065
Related to: https://pagure.io/freeipa/issue/8001

Signed-off-by: Julien Rische <jrische@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
2022-02-02 21:51:44 +01:00
Francisco Trivino 653a7fe028 Custodia: use a stronger encryption algo when exporting keys
The Custodia key export handler is using the default's OpenSSL encryption
scheme for PKCS#12.

This represents an issue when performing a migration from CentOS Stream 8 (C8S)
to CentOS Steam 9 (C9S) where the Custodia client running in the new C9S
replica talks to the Custodia server on C8S source server. The later creates an
encrypted PKCS#12 file that contains the cert and the key using the OpenSSL's
default encryption scheme, which is no longer supported on C9S.

This commit enforces a stronger encryption algorigthm by adding following
arguments to the Custodia server handler:

-keypbe AES-256-CBC -certpbe AES-256-CBC -macalg sha384

The new arguments enforce stronger PBEv2 instead of the insecure PBEv1.

Fixes: https://pagure.io/freeipa/issue/9101

Signed-off-by: Francisco Trivino <ftrivino@redhat.com>
Reviewed-By: Christian Heimes <cheimes@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
2022-02-01 08:57:24 +01:00
Florence Blanc-Renaud 9bae549227 ipa-pki-proxy.conf: provide access to /kra/admin/kra/getStatus
The access to /kra/admin/kra/getStatus will be needed
in order to fix pki-healthcheck.
Note that this commit is a pre-requisite for the fix
to be done on PKI side. No test added since the full
integration test already exists in test_replica_promotion.py,
in TestHiddenReplicaPromotion::test_ipahealthcheck_hidden_replica

Fixes: https://pagure.io/freeipa/issue/9099
Related: https://pagure.io/freeipa/issue/8582

Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-02-01 08:53:30 +01:00
Florence Blanc-Renaud cd8e9ce173 ipatests: fix expected automount config in nsswitch.conf
The test TestIpaClientAutomountFileRestore expects a
specific order for the automount sources to query
in /etc/nsswitch.conf.

With authselect update 1.3.0, the databases are sorted in
order of likelihood and the following line in seen:
automount: files sss
instead of
automount: sss files

Since the test doesn't care about the order but rather about
the list of sources, ignore the order.

Fixes: https://pagure.io/freeipa/issue/9067
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-01-25 17:33:23 +01:00
Alexander Bokovoy ace0bbfdc8 ipa-kdb: refactor KDB driver to prepare for KDB version 9
MIT Kerberos 1.20 changes DAL interface around PAC record issuance:
sign_authdata callback is removed and replaced with issue_pac one.
The signatures are different and logic changed as well.

Prepare for KDB version 9 by moving PAC implementation into separate
source files. ipa_kdb_mspac.c is left with most of the common code.

FreeIPA supports sign_authdata callback since KDB version 6, move current
implementation to ipa_kdb_mspac_v6.c.

KDB version 8 actually changed sign_authdata interface and we accounted
to that in ipa_kdb.c with a stub that re-uses v6 version. Keep it as it
is right now.

Finally, add KDB version 9 stub files. Compiling against MIT Kerberos
1.20 does not work yet, thus explicit #error message in ipa_kdb.c. This
will be worked on later.

Related: https://pagure.io/freeipa/issue/9083

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-01-25 09:09:22 +01:00
Florence Blanc-Renaud d8a7f15e32 ipatests: update images for f34 and f35
The new images contain the pkg kernel-modules
Fixes: https://pagure.io/freeipa/issue/9087

Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Armando Neto <abiagion@redhat.com>
2022-01-20 16:42:18 +01:00
Sumedh Sidhaye ef43ea03ef Added nightly job definitions
Signed-off-by: Sumedh Sidhaye <ssidhaye@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Antonio Torres <antorres@redhat.com>
2022-01-17 13:36:22 +01:00
Sumedh Sidhaye 0edf915efb Added test automation for SHA384withRSA CSR support
Scenario 1:
Setup master with --ca-signing-algorithm=SHA384withRSA
Run certutil and check Signing Algorithm

Scenario 2:
Setup a master
Stop services
Modify default.params.signingAlg in CS.cfg
Restart services
Resubmit cert (Resubmitted cert should have new Algorithm)

Pagure Link: https://pagure.io/freeipa/issue/8906

Signed-off-by: Sumedh Sidhaye <ssidhaye@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Antonio Torres <antorres@redhat.com>
2022-01-17 13:36:22 +01:00
jh23453 e11cf7f489 Remove deprecation warning when installing a CA replica
I got the following message when installing a replica with CA:

2021-11-22T21:15:35Z DEBUG   [5/30]: configuring certificate server instance

...
WARNING: The 'pki_ssl_server_token' in [CA] has been deprecated. Use 'pki_sslserver_token' instead.
Installation log: /var/log/pki/pki-ca-spawn.20211122221535.log
Installing CA into /var/lib/pki/pki-tomcat.

With the following change the message no longer appears when installing a replica.

This commit fixes the firt (and simple) part of https://pagure.io/freeipa/issue/9056

Signed-off-by: Jochen Kellner <jochen@jochen.org>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
2022-01-17 10:27:12 +01:00
Michal Polovka 419d7fd6e5 ipatests: webui: Use safe-loader for loading YAML configuration file
FullLoader class for YAML loader was introduced in version 5.1 which
also deprecated default loader. SafeLoader, however, stays consistent
across the versions and brings added security.

This fix is necessary as PyYAML > 5.1 is not available in downstream.

Related: https://pagure.io/freeipa/issue/9009

Signed-off-by: Michal Polovka <mpolovka@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-01-14 16:57:36 +01:00
Florence Blanc-Renaud cd735099e8 config plugin: add a test ensuring EmptyModlist is returned
Add a test to test_config_plugin, that calls ipa config-mod
with the same value as already present in LDAP.
The call must return EmptyModlist.

Related: https://pagure.io/freeipa/issue/9063
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-01-14 09:50:46 +01:00
Florence Blanc-Renaud b9c42fed9b Config plugin: return EmptyModlist when no change is applied
When ipa config-mod is called with the option --enable-sid,
the code needs to trap EmptyModlist exception (it is expected
that no LDAP attribute is modified by this operation).
The code had a flaw and was checking:
    'enable_sid' in options
instead of
    options['enable_sid']

"'enable_sid' in options" always returns true as this option
is a Flag with a default value, hence always present even if
not specified on the command line.

Fixes: https://pagure.io/freeipa/issue/9063
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-01-14 09:50:46 +01:00
Florence Blanc-Renaud 6ff7491172 automember default group: remove --desc parameter
The automember-default-group commands inherit from
the automember commands but should not provide the
--desc parameter.
Remove 'description' from the list of parameters.

Fixes: https://pagure.io/freeipa/issue/9068
Reviewed-By: Thomas Woerner <twoerner@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2022-01-14 09:47:41 +01:00
Michal Polovka 878859f4a2 pr-ci definitions: add web-ui subid-related jobs
Related: https://pagure.io/freeipa/issue/8361

Signed-off-by: Michal Polovka <mpolovka@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
2022-01-13 08:26:57 +01:00
Anuja More edbd8f692a ipatests: webui: Tests for subordinate ids.
Added web-ui tests to verify where operations
using subordinate ids are working as expected.

Related : https://pagure.io/freeipa/issue/8361

Signed-off-by: Anuja More <amore@redhat.com>
Reviewed-By: Michal Polovka <mpolovka@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
2022-01-13 08:26:57 +01:00
Florence Blanc-Renaud 1efdda078e ipatests: update images for f34 and f35
New versions of pki-server fix the following issues:
Fixes: https://pagure.io/freeipa/issue/9024
Fixes: https://pagure.io/freeipa/issue/8865

Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Armando Neto <abiagion@redhat.com>
2022-01-13 08:22:56 +01:00
Mohammad Rizwan 5444da016e PEP8 Fixes
Signed-off-by: Mohammad Rizwan <myusuf@redhat.com>
2022-01-12 15:03:38 +01:00
Mohammad Rizwan 1d19b860d4 Test cases for ipa-replica-conncheck command
Following test cases would be checked:
- when called with --principal (it should then prompt for a password)
- when called with --principal / --password
- when called without principal and password but with a kerberos TGT,
  kinit admin done before calling ipa-replica-conncheck
- when called without principal and password, and without any kerberos
  TGT (it should default to principal=admin and prompt for a password)

related: https://pagure.io/freeipa/issue/9047

Signed-off-by: Mohammad Rizwan <myusuf@redhat.com>
2022-01-12 15:03:38 +01:00
Alexander Bokovoy ce112e68bd Support building against OpenLDAP 2.6+
OpenLDAP 2.6 deprecated separate libldap/libldap_r, there is only one
(reentrant) variant for the library.

Attempt to use _r variant by default. In case it is missing, assume we
are using OpenLDAP 2.6 which has libraries without _r suffix. The
functions are still reentrant so there is not functional difference.

Fixes: https://pagure.io/freeipa/issue/9080

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
2022-01-12 11:19:14 +01:00
Mohammad Rizwan cbd9ac6ab0 ipatests: Test empty cert request doesn't force certmonger to segfault
When empty cert request is submitted to certmonger, it goes to
segfault. This fix test that if something like this happens,
certmonger should gracefuly handle it

and some PEP8 fixes

related: https://pagure.io/certmonger/issue/191

Signed-off-by: Mohammad Rizwan <myusuf@redhat.com>
2021-12-18 08:25:27 +01:00
Anuja More 465f1669a6 ipatests: Test default value of nsslapd-sizelimit.
related : https://pagure.io/freeipa/issue/8962

Signed-off-by: Anuja More <amore@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
2021-12-16 13:52:12 +01:00
Florence Blanc-Renaud 4c54e9d6dd ipatests: fix TestOTPToken::test_check_otpd_after_idle_timeout
The test sets 389-ds nsslapd-idletimeout to 60s, then does a
kinit with an otp token (which makes ipa-otpd create a LDAP
connection), then sleeps for 60s. The expectation is that
ns-slapd will detect that the LDAP conn from ipa-otpd is idle
and close the connection.
According to 389ds doc, the idle timeout is enforced when the
connection table is walked. By doing a ldapsearch, the test
"wakes up" ns-slapd and forces the detection of ipa-otpd
idle connection.

Fixes: https://pagure.io/freeipa/issue/9044
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Anuja More <amore@redhat.com>
2021-12-14 15:13:43 +01:00
Sumedh Sidhaye 8b22ee018c Extend test to see if replica is not shown when running ipa-replica-manage list -v <FQDN>
Related: https://pagure.io/freeipa/issue/8605

Signed-off-by: Sumedh Sidhaye <ssidhaye@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
2021-11-30 09:58:29 +01:00
Mohammad Rizwan ba7ec71ba9 ipatests: Fix test_ipa_cert_fix.py::TestCertFixReplica teardown
Fixture `expire_certs` moves date back after renewing the certs.
This is causing the ipa-replica to fail. This fix first uninstalls
the server then moves back the date.

Fixes: https://pagure.io/freeipa/issue/9052

Signed-off-by: Mohammad Rizwan <myusuf@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
2021-11-30 09:56:38 +01:00
Alexander Bokovoy 7d93bda31c ipa-kdb: fix requester SID check according to MS-KILE and MS-SFU updates
New versions of MS-KILE and MS-SFU after Windows Server November 2021
security updates add PAC_REQUESTER_SID buffer check behavior:

 - PAC_REQUESTER_SID should only be added for TGT requests

 - if PAC_REQUESTER_SID is present, KDC must verify that the cname on
   the ticket resolves to the account with the same SID as the
   PAC_REQUESTER_SID. If it doesn't KDC must respond with
   KDC_ERR_TKT_REVOKED

Change requester SID check to skip exact check for non-local
PAC_REQUESTER_SID but harden to ensure it comes from the trusted domains
we know about.

If requester SID is the same as in PAC, we already do cname vs PAC SID
verification.

With these changes FreeIPA works against Windows Server 2019 with
November 2021 security fixes in cross-realm S4U2Self operations.

Fixes: https://pagure.io/freeipa/issue/9031

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2021-11-30 09:51:21 +01:00
Alexander Bokovoy 669f3d7116 ipa-kdb: issue PAC_REQUESTER_SID only for TGTs
MS-KILE 3.3.5.6.4.8 in revision after Windows Server November 2021
security fixes added the following requirement:

- PAC_REQUESTER_SID is only added in TGT case (including referrals and
  tickets to RODCs)

Fixes: https://pagure.io/freeipa/issue/9031

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2021-11-30 09:51:21 +01:00
Timo Aaltonen 69f5f319d1 configure: Use HTTPD_GROUP in init/tmpfiles/ipa.conf.in
This is a platform specific value.

Fixes: https://pagure.io/freeipa/issue/9014

Signed-off-by: Timo Aaltonen <tjaalton@debian.org>
Reviewed-By: Christian Heimes <cheimes@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2021-11-29 15:27:50 +01:00
Timo Aaltonen 739d356695 ipaplatform: Modify paths to fips-mode-setup and systemd-tmpfiles
Debian hasn't yet migrated to a unified /usr.

Signed-off-by: Timo Aaltonen <tjaalton@debian.org>
Reviewed-By: Christian Heimes <cheimes@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2021-11-29 15:27:50 +01:00
Timo Aaltonen e99870f7d0 ipatests/test_ipaplatform: Skip test_ipa_version on Debian
Signed-off-by: Timo Aaltonen <tjaalton@debian.org>
Reviewed-By: Christian Heimes <cheimes@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2021-11-29 15:27:50 +01:00
Timo Aaltonen dcdc31b6f9 ipaplatform/debian: Fix ntpd service name
Signed-off-by: Timo Aaltonen <tjaalton@debian.org>
Reviewed-By: Christian Heimes <cheimes@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2021-11-29 15:27:50 +01:00
Timo Aaltonen da9be70f70 ipaplatform/debian: Fix named keytab name
This was changed in bind9 9.16 packaging

Signed-off-by: Timo Aaltonen <tjaalton@debian.org>
Reviewed-By: Christian Heimes <cheimes@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2021-11-29 15:27:50 +01:00
Timo Aaltonen cf9c4cc7da ipaplatform: Add support for recognizing systemd-timesyncd
Signed-off-by: Timo Aaltonen <tjaalton@debian.org>
Reviewed-By: Christian Heimes <cheimes@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2021-11-29 15:27:50 +01:00
Timo Aaltonen a0eb02cfb6 ipaplatform/debian: Fix HTTPD_ALIAS_DIR, and drop some obsolete paths.
Signed-off-by: Timo Aaltonen <tjaalton@debian.org>
Reviewed-By: Christian Heimes <cheimes@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2021-11-29 15:27:50 +01:00
Antonio Torres 8042bdc90c Back to git snapshots
Signed-off-by: Antonio Torres <antorres@redhat.com>
2021-11-25 19:23:38 +01:00
361 changed files with 20097 additions and 10598 deletions

No files matched your search

+10 -1
View File
@@ -1,5 +1,14 @@
component: Subject
# component: Subject is a single-line summary
Explanation
# Explanation must describe the fix or feature + the method
# chosen to implement it, and can span across multiple lines.
Fixes: https://pagure.io/freeipa/issue/XXXX
or
Related: https://pagure.io/freeipa/issue/XXXX
# Fixes: means that the commit fixes the referenced issue(s).
# Related: means that the commit is related to the issue(s)
# in some way, but does not resolve it/them.
https://pagure.io/freeipa/issue/XXXX
+7
View File
@@ -57,6 +57,12 @@ py-compile
freeipa2-dev-doc
~/doc/guide/Makefile
# Workshop
doc/workshop/.vagrant/
doc/workshop/packer_cache/
doc/workshop/output-*/
doc/workshop/anaconda-ks.cfg
# Root directory
/freeipa.spec
/dist/
@@ -149,6 +155,7 @@ install/custodia/ipa-custodia-dmldap
install/custodia/ipa-custodia-pki-tomcat
install/custodia/ipa-custodia-pki-tomcat-wrapped
install/custodia/ipa-custodia-ra-agent
install/oddjob/org.freeipa.server.config-enable-sid
install/oddjob/org.freeipa.server.trust-enable-agent
install/oddjob/com.redhat.idm.trust-fetch-domains
install/oddjob/etc/oddjobd.conf.d/ipa-server.conf
+30
View File
@@ -0,0 +1,30 @@
# .readthedocs.yaml
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
# Required
version: 2
# Set the version of Python and other tools you might need
build:
os: ubuntu-20.04
tools:
python: "3.8"
apt_packages:
- plantuml
- graphviz
- fonts-ipafont
- fonts-ipaexfont
# Build documentation in the doc/ directory with Sphinx
sphinx:
configuration: doc/conf.py
# If using Sphinx, optionally build your docs in additional formats such as PDF
# formats:
# - pdf
# Optionally declare the Python requirements required to build your docs
python:
install:
- requirements: doc/requirements.txt
+2 -2
View File
@@ -10,6 +10,6 @@ ipaserver == @VERSION@
ipatests == @VERSION@
# keep pylint version in sync with current Fedora release
# F34 has 2.6
# F36 has 2.12.2
# https://pagure.io/freeipa/issue/8818 added pylint 2.8 support
pylint < 2.9
pylint ~= 2.12.2
+12 -2
View File
@@ -180,6 +180,16 @@ dn: cn=views,cn=accounts,dc=ipa,dc=example
aci: (targetattr = "cn || createtimestamp || description || entryusn || gidnumber || ipaanchoruuid || modifytimestamp || objectclass")(targetfilter = "(objectclass=ipaGroupOverride)")(version 3.0;acl "permission:System: Read Group ID Overrides";allow (compare,read,search) userdn = "ldap:///all";)
dn: cn=views,cn=accounts,dc=ipa,dc=example
aci: (targetattr = "createtimestamp || description || entryusn || gecos || gidnumber || homedirectory || ipaanchoruuid || ipaoriginaluid || ipasshpubkey || loginshell || memberof || modifytimestamp || objectclass || uid || uidnumber || usercertificate")(targetfilter = "(objectclass=ipaUserOverride)")(version 3.0;acl "permission:System: Read User ID Overrides";allow (compare,read,search) userdn = "ldap:///all";)
dn: cn=idp,dc=ipa,dc=example
aci: (targetfilter = "(objectclass=ipaidp)")(version 3.0;acl "permission:System: Add External IdP server";allow (add) groupdn = "ldap:///cn=System: Add External IdP server,cn=permissions,cn=pbac,dc=ipa,dc=example";)
dn: cn=idp,dc=ipa,dc=example
aci: (targetfilter = "(objectclass=ipaidp)")(version 3.0;acl "permission:System: Delete External IdP server";allow (delete) groupdn = "ldap:///cn=System: Delete External IdP server,cn=permissions,cn=pbac,dc=ipa,dc=example";)
dn: cn=idp,dc=ipa,dc=example
aci: (targetattr = "cn || ipaidpauthendpoint || ipaidpclientid || ipaidpclientsecret || ipaidpdevauthendpoint || ipaidpissuerurl || ipaidpkeysendpoint || ipaidpscope || ipaidpsub || ipaidptokenendpoint || ipaidpuserinfoendpoint || objectclass")(targetfilter = "(objectclass=ipaidp)")(version 3.0;acl "permission:System: Modify External IdP server";allow (write) groupdn = "ldap:///cn=System: Modify External IdP server,cn=permissions,cn=pbac,dc=ipa,dc=example";)
dn: cn=idp,dc=ipa,dc=example
aci: (targetattr = "cn || createtimestamp || entryusn || ipaidpauthendpoint || ipaidpclientid || ipaidpdevauthendpoint || ipaidpissuerurl || ipaidpkeysendpoint || ipaidpscope || ipaidpsub || ipaidptokenendpoint || ipaidpuserinfoendpoint || modifytimestamp || objectclass")(targetfilter = "(objectclass=ipaidp)")(version 3.0;acl "permission:System: Read External IdP server";allow (compare,read,search) groupdn = "ldap:///cn=System: Read External IdP server,cn=permissions,cn=pbac,dc=ipa,dc=example";)
dn: cn=idp,dc=ipa,dc=example
aci: (targetattr = "cn || createtimestamp || entryusn || ipaidpauthendpoint || ipaidpclientid || ipaidpclientsecret || ipaidpdevauthendpoint || ipaidpissuerurl || ipaidpkeysendpoint || ipaidpscope || ipaidpsub || ipaidptokenendpoint || ipaidpuserinfoendpoint || modifytimestamp || objectclass")(targetfilter = "(objectclass=ipaidp)")(version 3.0;acl "permission:System: Read External IdP server client secret";allow (compare,read,search) groupdn = "ldap:///cn=System: Read External IdP server client secret,cn=permissions,cn=pbac,dc=ipa,dc=example";)
dn: cn=ranges,cn=etc,dc=ipa,dc=example
aci: (targetattr = "cn || createtimestamp || entryusn || ipaautoprivategroups || ipabaseid || ipabaserid || ipaidrangesize || ipanttrusteddomainsid || iparangetype || ipasecondarybaserid || modifytimestamp || objectclass")(targetfilter = "(objectclass=ipaidrange)")(version 3.0;acl "permission:System: Read ID Ranges";allow (compare,read,search) userdn = "ldap:///all";)
dn: cn=views,cn=accounts,dc=ipa,dc=example
@@ -231,9 +241,9 @@ aci: (targetfilter = "(|(objectclass=ipapwdpolicy)(objectclass=krbpwdpolicy))")(
dn: cn=IPA.EXAMPLE,cn=kerberos,dc=ipa,dc=example
aci: (targetfilter = "(|(objectclass=ipapwdpolicy)(objectclass=krbpwdpolicy))")(version 3.0;acl "permission:System: Delete Group Password Policy";allow (delete) groupdn = "ldap:///cn=System: Delete Group Password Policy,cn=permissions,cn=pbac,dc=ipa,dc=example";)
dn: cn=IPA.EXAMPLE,cn=kerberos,dc=ipa,dc=example
aci: (targetattr = "ipapwddictcheck || ipapwdmaxrepeat || ipapwdmaxsequence || ipapwdusercheck || krbmaxpwdlife || krbminpwdlife || krbpwdfailurecountinterval || krbpwdhistorylength || krbpwdlockoutduration || krbpwdmaxfailure || krbpwdmindiffchars || krbpwdminlength")(targetfilter = "(|(objectclass=ipapwdpolicy)(objectclass=krbpwdpolicy))")(version 3.0;acl "permission:System: Modify Group Password Policy";allow (write) groupdn = "ldap:///cn=System: Modify Group Password Policy,cn=permissions,cn=pbac,dc=ipa,dc=example";)
aci: (targetattr = "ipapwddictcheck || ipapwdmaxrepeat || ipapwdmaxsequence || ipapwdusercheck || krbmaxpwdlife || krbminpwdlife || krbpwdfailurecountinterval || krbpwdhistorylength || krbpwdlockoutduration || krbpwdmaxfailure || krbpwdmindiffchars || krbpwdminlength || passwordgracelimit")(targetfilter = "(|(objectclass=ipapwdpolicy)(objectclass=krbpwdpolicy))")(version 3.0;acl "permission:System: Modify Group Password Policy";allow (write) groupdn = "ldap:///cn=System: Modify Group Password Policy,cn=permissions,cn=pbac,dc=ipa,dc=example";)
dn: cn=IPA.EXAMPLE,cn=kerberos,dc=ipa,dc=example
aci: (targetattr = "cn || cospriority || createtimestamp || entryusn || ipapwddictcheck || ipapwdmaxrepeat || ipapwdmaxsequence || ipapwdusercheck || krbmaxpwdlife || krbminpwdlife || krbpwdfailurecountinterval || krbpwdhistorylength || krbpwdlockoutduration || krbpwdmaxfailure || krbpwdmindiffchars || krbpwdminlength || modifytimestamp || objectclass")(targetfilter = "(|(objectclass=ipapwdpolicy)(objectclass=krbpwdpolicy))")(version 3.0;acl "permission:System: Read Group Password Policy";allow (compare,read,search) groupdn = "ldap:///cn=System: Read Group Password Policy,cn=permissions,cn=pbac,dc=ipa,dc=example";)
aci: (targetattr = "cn || cospriority || createtimestamp || entryusn || ipapwddictcheck || ipapwdmaxrepeat || ipapwdmaxsequence || ipapwdusercheck || krbmaxpwdlife || krbminpwdlife || krbpwdfailurecountinterval || krbpwdhistorylength || krbpwdlockoutduration || krbpwdmaxfailure || krbpwdmindiffchars || krbpwdminlength || modifytimestamp || objectclass || passwordgracelimit")(targetfilter = "(|(objectclass=ipapwdpolicy)(objectclass=krbpwdpolicy))")(version 3.0;acl "permission:System: Read Group Password Policy";allow (compare,read,search) groupdn = "ldap:///cn=System: Read Group Password Policy,cn=permissions,cn=pbac,dc=ipa,dc=example";)
dn: cn=radiusproxy,dc=ipa,dc=example
aci: (targetattr = "cn || createtimestamp || description || entryusn || ipatokenradiusretries || ipatokenradiusserver || ipatokenradiustimeout || ipatokenusermapattribute || modifytimestamp || objectclass")(targetfilter = "(objectclass=ipatokenradiusconfiguration)")(version 3.0;acl "permission:System: Read Radius Servers";allow (compare,read,search) groupdn = "ldap:///cn=System: Read Radius Servers,cn=permissions,cn=pbac,dc=ipa,dc=example";)
dn: cn=Realm Domains,cn=ipa,cn=etc,dc=ipa,dc=example
+143 -29
View File
@@ -136,9 +136,8 @@ output: Entry('result')
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
output: PrimaryKey('value')
command: automember_default_group_remove/1
args: 0,5,3
args: 0,4,3
option: Flag('all', autofill=True, cli_name='all', default=False)
option: Str('description?', autofill=False, cli_name='desc')
option: Flag('raw', autofill=True, cli_name='raw', default=False)
option: StrEnum('type', values=[u'group', u'hostgroup'])
option: Str('version?')
@@ -146,10 +145,9 @@ output: Entry('result')
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
output: Output('value', type=[<type 'unicode'>])
command: automember_default_group_set/1
args: 0,6,3
args: 0,5,3
option: Flag('all', autofill=True, cli_name='all', default=False)
option: Str('automemberdefaultgroup', cli_name='default_group')
option: Str('description?', autofill=False, cli_name='desc')
option: Flag('raw', autofill=True, cli_name='raw', default=False)
option: StrEnum('type', values=[u'group', u'hostgroup'])
option: Str('version?')
@@ -1100,7 +1098,7 @@ option: Int('ipasearchrecordslimit?', autofill=False, cli_name='searchrecordslim
option: Int('ipasearchtimelimit?', autofill=False, cli_name='searchtimelimit')
option: Str('ipaselinuxusermapdefault?', autofill=False)
option: Str('ipaselinuxusermaporder?', autofill=False)
option: StrEnum('ipauserauthtype*', autofill=False, cli_name='user_auth_type', values=[u'password', u'radius', u'otp', u'pkinit', u'hardened', u'disabled'])
option: StrEnum('ipauserauthtype*', autofill=False, cli_name='user_auth_type', values=[u'password', u'radius', u'otp', u'pkinit', u'hardened', u'idp', u'disabled'])
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')
@@ -2479,7 +2477,7 @@ option: Bool('ipakrbokasdelegate?', cli_name='ok_as_delegate')
option: Bool('ipakrboktoauthasdelegate?', cli_name='ok_to_auth_as_delegate')
option: Bool('ipakrbrequirespreauth?', cli_name='requires_pre_auth')
option: Str('ipasshpubkey*', cli_name='sshpubkey')
option: StrEnum('krbprincipalauthind*', cli_name='auth_ind', values=[u'radius', u'otp', u'pkinit', u'hardened'])
option: StrEnum('krbprincipalauthind*', cli_name='auth_ind', values=[u'radius', u'otp', u'pkinit', u'hardened', u'idp'])
option: Str('l?', cli_name='locality')
option: Str('macaddress*')
option: Flag('no_members', autofill=True, default=False)
@@ -2615,7 +2613,7 @@ option: Str('in_netgroup*', cli_name='in_netgroups')
option: Str('in_role*', cli_name='in_roles')
option: Str('in_sudorule*', cli_name='in_sudorules')
option: Str('ipaassignedidview?', autofill=False)
option: StrEnum('krbprincipalauthind*', autofill=False, cli_name='auth_ind', values=[u'radius', u'otp', u'pkinit', u'hardened'])
option: StrEnum('krbprincipalauthind*', autofill=False, cli_name='auth_ind', values=[u'radius', u'otp', u'pkinit', u'hardened', u'idp'])
option: Str('l?', autofill=False, cli_name='locality')
option: Str('macaddress*', autofill=False)
option: Str('man_by_host*', cli_name='man_by_hosts')
@@ -2655,7 +2653,7 @@ option: Bool('ipakrbokasdelegate?', autofill=False, cli_name='ok_as_delegate')
option: Bool('ipakrboktoauthasdelegate?', autofill=False, cli_name='ok_to_auth_as_delegate')
option: Bool('ipakrbrequirespreauth?', autofill=False, cli_name='requires_pre_auth')
option: Str('ipasshpubkey*', autofill=False, cli_name='sshpubkey')
option: StrEnum('krbprincipalauthind*', autofill=False, cli_name='auth_ind', values=[u'radius', u'otp', u'pkinit', u'hardened'])
option: StrEnum('krbprincipalauthind*', autofill=False, cli_name='auth_ind', values=[u'radius', u'otp', u'pkinit', u'hardened', u'idp'])
option: Principal('krbprincipalname*', autofill=False)
option: Str('l?', autofill=False, cli_name='locality')
option: Str('macaddress*', autofill=False)
@@ -3053,6 +3051,96 @@ option: Str('version?')
output: Entry('result')
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
output: PrimaryKey('value')
command: idp_add/1
args: 1,18,3
arg: Str('cn', cli_name='name')
option: Str('addattr*', cli_name='addattr')
option: Flag('all', autofill=True, cli_name='all', default=False)
option: Str('ipaidpauthendpoint?', alwaysask=False, cli_name='auth_uri')
option: Str('ipaidpbaseurl?', cli_name='base_url')
option: Str('ipaidpclientid', cli_name='client_id')
option: Password('ipaidpclientsecret?', cli_name='secret', confirm=True)
option: Str('ipaidpdevauthendpoint?', alwaysask=False, cli_name='dev_auth_uri')
option: Str('ipaidpissuerurl?', cli_name='issuer_url')
option: Str('ipaidpkeysendpoint?', alwaysask=False, cli_name='keys_uri')
option: Str('ipaidporg?', cli_name='organization')
option: StrEnum('ipaidpprovider?', cli_name='provider', values=[u'google', u'github', u'microsoft', u'okta', u'keycloak'])
option: Str('ipaidpscope?', cli_name='scope')
option: Str('ipaidpsub?', cli_name='idp_user_id')
option: Str('ipaidptokenendpoint?', alwaysask=False, cli_name='token_uri')
option: Str('ipaidpuserinfoendpoint?', alwaysask=False, cli_name='userinfo_uri')
option: Flag('raw', autofill=True, cli_name='raw', default=False)
option: Str('setattr*', cli_name='setattr')
option: Str('version?')
output: Entry('result')
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
output: PrimaryKey('value')
command: idp_del/1
args: 1,2,3
arg: Str('cn+', cli_name='name')
option: Flag('continue', autofill=True, cli_name='continue', default=False)
option: Str('version?')
output: Output('result', type=[<type 'dict'>])
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
output: ListOfPrimaryKeys('value')
command: idp_find/1
args: 1,17,4
arg: Str('criteria?')
option: Flag('all', autofill=True, cli_name='all', default=False)
option: Str('cn?', autofill=False, cli_name='name')
option: Str('ipaidpauthendpoint?', autofill=False, cli_name='auth_uri')
option: Str('ipaidpclientid?', autofill=False, cli_name='client_id')
option: Password('ipaidpclientsecret?', autofill=False, cli_name='secret', confirm=True)
option: Str('ipaidpdevauthendpoint?', autofill=False, cli_name='dev_auth_uri')
option: Str('ipaidpissuerurl?', autofill=False, cli_name='issuer_url')
option: Str('ipaidpkeysendpoint?', autofill=False, cli_name='keys_uri')
option: Str('ipaidpscope?', autofill=False, cli_name='scope')
option: Str('ipaidpsub?', autofill=False, cli_name='idp_user_id')
option: Str('ipaidptokenendpoint?', autofill=False, cli_name='token_uri')
option: Str('ipaidpuserinfoendpoint?', autofill=False, cli_name='userinfo_uri')
option: Flag('pkey_only?', autofill=True, default=False)
option: Flag('raw', autofill=True, cli_name='raw', default=False)
option: Int('sizelimit?', autofill=False)
option: Int('timelimit?', autofill=False)
option: Str('version?')
output: Output('count', type=[<type 'int'>])
output: ListOfEntries('result')
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
output: Output('truncated', type=[<type 'bool'>])
command: idp_mod/1
args: 1,18,3
arg: Str('cn', cli_name='name')
option: Str('addattr*', cli_name='addattr')
option: Flag('all', autofill=True, cli_name='all', default=False)
option: Str('delattr*', cli_name='delattr')
option: Str('ipaidpauthendpoint?', autofill=False, cli_name='auth_uri')
option: Str('ipaidpclientid?', autofill=False, cli_name='client_id')
option: Password('ipaidpclientsecret?', autofill=False, cli_name='secret', confirm=True)
option: Str('ipaidpdevauthendpoint?', autofill=False, cli_name='dev_auth_uri')
option: Str('ipaidpissuerurl?', autofill=False, cli_name='issuer_url')
option: Str('ipaidpkeysendpoint?', autofill=False, cli_name='keys_uri')
option: Str('ipaidpscope?', autofill=False, cli_name='scope')
option: Str('ipaidpsub?', autofill=False, cli_name='idp_user_id')
option: Str('ipaidptokenendpoint?', autofill=False, cli_name='token_uri')
option: Str('ipaidpuserinfoendpoint?', autofill=False, cli_name='userinfo_uri')
option: Flag('raw', autofill=True, cli_name='raw', default=False)
option: Str('rename?', cli_name='rename')
option: Flag('rights', autofill=True, default=False)
option: Str('setattr*', cli_name='setattr')
option: Str('version?')
output: Entry('result')
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
output: PrimaryKey('value')
command: idp_show/1
args: 1,4,3
arg: Str('cn', cli_name='name')
option: Flag('all', autofill=True, cli_name='all', default=False)
option: Flag('raw', autofill=True, cli_name='raw', default=False)
option: Flag('rights', autofill=True, default=False)
option: Str('version?')
output: Entry('result')
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
output: PrimaryKey('value')
command: idrange_add/1
args: 1,13,3
arg: Str('cn', cli_name='name')
@@ -3238,16 +3326,18 @@ output: Output('result', type=[<type 'bool'>])
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
output: PrimaryKey('value')
command: krbtpolicy_mod/1
args: 1,17,3
args: 1,19,3
arg: Str('uid?', cli_name='user')
option: Str('addattr*', cli_name='addattr')
option: Flag('all', autofill=True, cli_name='all', default=False)
option: Str('delattr*', cli_name='delattr')
option: Int('krbauthindmaxrenewableage_hardened?', autofill=False, cli_name='hardened_maxrenew')
option: Int('krbauthindmaxrenewableage_idp?', autofill=False, cli_name='idp_maxrenew')
option: Int('krbauthindmaxrenewableage_otp?', autofill=False, cli_name='otp_maxrenew')
option: Int('krbauthindmaxrenewableage_pkinit?', autofill=False, cli_name='pkinit_maxrenew')
option: Int('krbauthindmaxrenewableage_radius?', autofill=False, cli_name='radius_maxrenew')
option: Int('krbauthindmaxticketlife_hardened?', autofill=False, cli_name='hardened_maxlife')
option: Int('krbauthindmaxticketlife_idp?', autofill=False, cli_name='idp_maxlife')
option: Int('krbauthindmaxticketlife_otp?', autofill=False, cli_name='otp_maxlife')
option: Int('krbauthindmaxticketlife_pkinit?', autofill=False, cli_name='pkinit_maxlife')
option: Int('krbauthindmaxticketlife_radius?', autofill=False, cli_name='radius_maxlife')
@@ -3968,7 +4058,7 @@ output: Entry('result')
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
output: PrimaryKey('value')
command: pwpolicy_add/1
args: 1,18,3
args: 1,19,3
arg: Str('cn', cli_name='group')
option: Str('addattr*', cli_name='addattr')
option: Flag('all', autofill=True, cli_name='all', default=False)
@@ -3985,6 +4075,7 @@ option: Int('krbpwdlockoutduration?', cli_name='lockouttime')
option: Int('krbpwdmaxfailure?', cli_name='maxfail')
option: Int('krbpwdmindiffchars?', cli_name='minclasses')
option: Int('krbpwdminlength?', cli_name='minlength')
option: Int('passwordgracelimit?', cli_name='gracelimit', default=-1)
option: Flag('raw', autofill=True, cli_name='raw', default=False)
option: Str('setattr*', cli_name='setattr')
option: Str('version?')
@@ -4000,7 +4091,7 @@ output: Output('result', type=[<type 'dict'>])
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
output: ListOfPrimaryKeys('value')
command: pwpolicy_find/1
args: 1,20,4
args: 1,21,4
arg: Str('criteria?')
option: Flag('all', autofill=True, cli_name='all', default=False)
option: Str('cn?', autofill=False, cli_name='group')
@@ -4017,6 +4108,7 @@ option: Int('krbpwdlockoutduration?', autofill=False, cli_name='lockouttime')
option: Int('krbpwdmaxfailure?', autofill=False, cli_name='maxfail')
option: Int('krbpwdmindiffchars?', autofill=False, cli_name='minclasses')
option: Int('krbpwdminlength?', autofill=False, cli_name='minlength')
option: Int('passwordgracelimit?', autofill=False, cli_name='gracelimit', default=-1)
option: Flag('pkey_only?', autofill=True, default=False)
option: Flag('raw', autofill=True, cli_name='raw', default=False)
option: Int('sizelimit?', autofill=False)
@@ -4027,7 +4119,7 @@ output: ListOfEntries('result')
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
output: Output('truncated', type=[<type 'bool'>])
command: pwpolicy_mod/1
args: 1,20,3
args: 1,21,3
arg: Str('cn?', cli_name='group')
option: Str('addattr*', cli_name='addattr')
option: Flag('all', autofill=True, cli_name='all', default=False)
@@ -4045,6 +4137,7 @@ option: Int('krbpwdlockoutduration?', autofill=False, cli_name='lockouttime')
option: Int('krbpwdmaxfailure?', autofill=False, cli_name='maxfail')
option: Int('krbpwdmindiffchars?', autofill=False, cli_name='minclasses')
option: Int('krbpwdminlength?', autofill=False, cli_name='minlength')
option: Int('passwordgracelimit?', autofill=False, cli_name='gracelimit', default=-1)
option: Flag('raw', autofill=True, cli_name='raw', default=False)
option: Flag('rights', autofill=True, default=False)
option: Str('setattr*', cli_name='setattr')
@@ -4590,7 +4683,7 @@ option: StrEnum('ipakrbauthzdata*', cli_name='pac_type', values=[u'MS-PAC', u'PA
option: Bool('ipakrbokasdelegate?', cli_name='ok_as_delegate')
option: Bool('ipakrboktoauthasdelegate?', cli_name='ok_to_auth_as_delegate')
option: Bool('ipakrbrequirespreauth?', cli_name='requires_pre_auth')
option: StrEnum('krbprincipalauthind*', cli_name='auth_ind', values=[u'radius', u'otp', u'pkinit', u'hardened'])
option: StrEnum('krbprincipalauthind*', cli_name='auth_ind', values=[u'radius', u'otp', u'pkinit', u'hardened', u'idp'])
option: Flag('no_members', autofill=True, default=False)
option: Flag('raw', autofill=True, cli_name='raw', default=False)
option: Str('setattr*', cli_name='setattr')
@@ -4726,7 +4819,7 @@ arg: Str('criteria?')
option: Flag('all', autofill=True, cli_name='all', default=False)
option: StrEnum('ipakrbauthzdata*', autofill=False, cli_name='pac_type', values=[u'MS-PAC', u'PAD', u'NONE'])
option: Principal('krbcanonicalname?', autofill=False, cli_name='canonical_principal')
option: StrEnum('krbprincipalauthind*', autofill=False, cli_name='auth_ind', values=[u'radius', u'otp', u'pkinit', u'hardened'])
option: StrEnum('krbprincipalauthind*', autofill=False, cli_name='auth_ind', values=[u'radius', u'otp', u'pkinit', u'hardened', u'idp'])
option: Principal('krbprincipalname*', autofill=False, cli_name='principal')
option: Str('man_by_host*', cli_name='man_by_hosts')
option: Flag('no_members', autofill=True, default=True)
@@ -4750,7 +4843,7 @@ option: StrEnum('ipakrbauthzdata*', autofill=False, cli_name='pac_type', values=
option: Bool('ipakrbokasdelegate?', autofill=False, cli_name='ok_as_delegate')
option: Bool('ipakrboktoauthasdelegate?', autofill=False, cli_name='ok_to_auth_as_delegate')
option: Bool('ipakrbrequirespreauth?', autofill=False, cli_name='requires_pre_auth')
option: StrEnum('krbprincipalauthind*', autofill=False, cli_name='auth_ind', values=[u'radius', u'otp', u'pkinit', u'hardened'])
option: StrEnum('krbprincipalauthind*', autofill=False, cli_name='auth_ind', values=[u'radius', u'otp', u'pkinit', u'hardened', u'idp'])
option: Principal('krbprincipalname*', autofill=False, cli_name='principal')
option: Flag('no_members', autofill=True, default=False)
option: Flag('raw', autofill=True, cli_name='raw', default=False)
@@ -4978,7 +5071,7 @@ output: Entry('result')
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
output: PrimaryKey('value')
command: stageuser_add/1
args: 1,45,3
args: 1,47,3
arg: Str('uid', cli_name='login')
option: Str('addattr*', cli_name='addattr')
option: Flag('all', autofill=True, cli_name='all', default=False)
@@ -4995,10 +5088,12 @@ option: Int('gidnumber?')
option: Str('givenname', cli_name='first')
option: Str('homedirectory?', cli_name='homedir')
option: Str('initials?', autofill=True)
option: Str('ipaidpconfiglink?', cli_name='idp')
option: Str('ipaidpsub?', cli_name='idp_user_id')
option: Str('ipasshpubkey*', cli_name='sshpubkey')
option: Str('ipatokenradiusconfiglink?', cli_name='radius')
option: Str('ipatokenradiususername?', cli_name='radius_username')
option: StrEnum('ipauserauthtype*', cli_name='user_auth_type', values=[u'password', u'radius', u'otp', u'pkinit', u'hardened'])
option: StrEnum('ipauserauthtype*', cli_name='user_auth_type', values=[u'password', u'radius', u'otp', u'pkinit', u'hardened', u'idp'])
option: DateTime('krbpasswordexpiration?', cli_name='password_expiration')
option: DateTime('krbprincipalexpiration?', cli_name='principal_expiration')
option: Principal('krbprincipalname*', autofill=True, cli_name='principal')
@@ -5084,7 +5179,7 @@ output: Output('result', type=[<type 'dict'>])
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
output: ListOfPrimaryKeys('value')
command: stageuser_find/1
args: 1,60,4
args: 1,62,4
arg: Str('criteria?')
option: Flag('all', autofill=True, cli_name='all', default=False)
option: Str('carlicense*', autofill=False)
@@ -5105,13 +5200,15 @@ option: Str('in_role*', cli_name='in_roles')
option: Str('in_subid*', cli_name='in_subids')
option: Str('in_sudorule*', cli_name='in_sudorules')
option: Str('initials?', autofill=False)
option: Str('ipaidpconfiglink?', autofill=False, cli_name='idp')
option: Str('ipaidpsub?', autofill=False, cli_name='idp_user_id')
option: Str('ipanthomedirectory?', autofill=False, cli_name='smb_home_dir')
option: StrEnum('ipanthomedirectorydrive?', autofill=False, cli_name='smb_home_drive', values=[u'A:', u'B:', u'C:', u'D:', u'E:', u'F:', u'G:', u'H:', u'I:', u'J:', u'K:', u'L:', u'M:', u'N:', u'O:', u'P:', u'Q:', u'R:', u'S:', u'T:', u'U:', u'V:', u'W:', u'X:', u'Y:', u'Z:'])
option: Str('ipantlogonscript?', autofill=False, cli_name='smb_logon_script')
option: Str('ipantprofilepath?', autofill=False, cli_name='smb_profile_path')
option: Str('ipatokenradiusconfiglink?', autofill=False, cli_name='radius')
option: Str('ipatokenradiususername?', autofill=False, cli_name='radius_username')
option: StrEnum('ipauserauthtype*', autofill=False, cli_name='user_auth_type', values=[u'password', u'radius', u'otp', u'pkinit', u'hardened'])
option: StrEnum('ipauserauthtype*', autofill=False, cli_name='user_auth_type', values=[u'password', u'radius', u'otp', u'pkinit', u'hardened', u'idp'])
option: DateTime('krbpasswordexpiration?', autofill=False, cli_name='password_expiration')
option: DateTime('krbprincipalexpiration?', autofill=False, cli_name='principal_expiration')
option: Principal('krbprincipalname*', autofill=False, cli_name='principal')
@@ -5151,7 +5248,7 @@ output: ListOfEntries('result')
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
output: Output('truncated', type=[<type 'bool'>])
command: stageuser_mod/1
args: 1,51,3
args: 1,53,3
arg: Str('uid', cli_name='login')
option: Str('addattr*', cli_name='addattr')
option: Flag('all', autofill=True, cli_name='all', default=False)
@@ -5168,6 +5265,8 @@ option: Int('gidnumber?', autofill=False)
option: Str('givenname?', autofill=False, cli_name='first')
option: Str('homedirectory?', autofill=False, cli_name='homedir')
option: Str('initials?', autofill=False)
option: Str('ipaidpconfiglink?', autofill=False, cli_name='idp')
option: Str('ipaidpsub?', autofill=False, cli_name='idp_user_id')
option: Str('ipanthomedirectory?', autofill=False, cli_name='smb_home_dir')
option: StrEnum('ipanthomedirectorydrive?', autofill=False, cli_name='smb_home_drive', values=[u'A:', u'B:', u'C:', u'D:', u'E:', u'F:', u'G:', u'H:', u'I:', u'J:', u'K:', u'L:', u'M:', u'N:', u'O:', u'P:', u'Q:', u'R:', u'S:', u'T:', u'U:', u'V:', u'W:', u'X:', u'Y:', u'Z:'])
option: Str('ipantlogonscript?', autofill=False, cli_name='smb_logon_script')
@@ -5175,7 +5274,7 @@ option: Str('ipantprofilepath?', autofill=False, cli_name='smb_profile_path')
option: Str('ipasshpubkey*', autofill=False, cli_name='sshpubkey')
option: Str('ipatokenradiusconfiglink?', autofill=False, cli_name='radius')
option: Str('ipatokenradiususername?', autofill=False, cli_name='radius_username')
option: StrEnum('ipauserauthtype*', autofill=False, cli_name='user_auth_type', values=[u'password', u'radius', u'otp', u'pkinit', u'hardened'])
option: StrEnum('ipauserauthtype*', autofill=False, cli_name='user_auth_type', values=[u'password', u'radius', u'otp', u'pkinit', u'hardened', u'idp'])
option: DateTime('krbpasswordexpiration?', autofill=False, cli_name='password_expiration')
option: DateTime('krbprincipalexpiration?', autofill=False, cli_name='principal_expiration')
option: Principal('krbprincipalname*', autofill=False, cli_name='principal')
@@ -6158,7 +6257,7 @@ output: Entry('result')
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
output: PrimaryKey('value')
command: user_add/1
args: 1,46,3
args: 1,48,3
arg: Str('uid', cli_name='login')
option: Str('addattr*', cli_name='addattr')
option: Flag('all', autofill=True, cli_name='all', default=False)
@@ -6174,10 +6273,12 @@ option: Int('gidnumber?')
option: Str('givenname', cli_name='first')
option: Str('homedirectory?', cli_name='homedir')
option: Str('initials?', autofill=True)
option: Str('ipaidpconfiglink?', cli_name='idp')
option: Str('ipaidpsub?', cli_name='idp_user_id')
option: Str('ipasshpubkey*', cli_name='sshpubkey')
option: Str('ipatokenradiusconfiglink?', cli_name='radius')
option: Str('ipatokenradiususername?', cli_name='radius_username')
option: StrEnum('ipauserauthtype*', cli_name='user_auth_type', values=[u'password', u'radius', u'otp', u'pkinit', u'hardened'])
option: StrEnum('ipauserauthtype*', cli_name='user_auth_type', values=[u'password', u'radius', u'otp', u'pkinit', u'hardened', u'idp'])
option: DateTime('krbpasswordexpiration?', cli_name='password_expiration')
option: DateTime('krbprincipalexpiration?', cli_name='principal_expiration')
option: Principal('krbprincipalname*', autofill=True, cli_name='principal')
@@ -6280,7 +6381,7 @@ output: Output('result', type=[<type 'bool'>])
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
output: PrimaryKey('value')
command: user_find/1
args: 1,63,4
args: 1,65,4
arg: Str('criteria?')
option: Flag('all', autofill=True, cli_name='all', default=False)
option: Str('carlicense*', autofill=False)
@@ -6301,13 +6402,15 @@ option: Str('in_role*', cli_name='in_roles')
option: Str('in_subid*', cli_name='in_subids')
option: Str('in_sudorule*', cli_name='in_sudorules')
option: Str('initials?', autofill=False)
option: Str('ipaidpconfiglink?', autofill=False, cli_name='idp')
option: Str('ipaidpsub?', autofill=False, cli_name='idp_user_id')
option: Str('ipanthomedirectory?', autofill=False, cli_name='smb_home_dir')
option: StrEnum('ipanthomedirectorydrive?', autofill=False, cli_name='smb_home_drive', values=[u'A:', u'B:', u'C:', u'D:', u'E:', u'F:', u'G:', u'H:', u'I:', u'J:', u'K:', u'L:', u'M:', u'N:', u'O:', u'P:', u'Q:', u'R:', u'S:', u'T:', u'U:', u'V:', u'W:', u'X:', u'Y:', u'Z:'])
option: Str('ipantlogonscript?', autofill=False, cli_name='smb_logon_script')
option: Str('ipantprofilepath?', autofill=False, cli_name='smb_profile_path')
option: Str('ipatokenradiusconfiglink?', autofill=False, cli_name='radius')
option: Str('ipatokenradiususername?', autofill=False, cli_name='radius_username')
option: StrEnum('ipauserauthtype*', autofill=False, cli_name='user_auth_type', values=[u'password', u'radius', u'otp', u'pkinit', u'hardened'])
option: StrEnum('ipauserauthtype*', autofill=False, cli_name='user_auth_type', values=[u'password', u'radius', u'otp', u'pkinit', u'hardened', u'idp'])
option: DateTime('krbpasswordexpiration?', autofill=False, cli_name='password_expiration')
option: DateTime('krbprincipalexpiration?', autofill=False, cli_name='principal_expiration')
option: Principal('krbprincipalname*', autofill=False, cli_name='principal')
@@ -6350,7 +6453,7 @@ output: ListOfEntries('result')
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
output: Output('truncated', type=[<type 'bool'>])
command: user_mod/1
args: 1,52,3
args: 1,54,3
arg: Str('uid', cli_name='login')
option: Str('addattr*', cli_name='addattr')
option: Flag('all', autofill=True, cli_name='all', default=False)
@@ -6367,6 +6470,8 @@ option: Int('gidnumber?', autofill=False)
option: Str('givenname?', autofill=False, cli_name='first')
option: Str('homedirectory?', autofill=False, cli_name='homedir')
option: Str('initials?', autofill=False)
option: Str('ipaidpconfiglink?', autofill=False, cli_name='idp')
option: Str('ipaidpsub?', autofill=False, cli_name='idp_user_id')
option: Str('ipanthomedirectory?', autofill=False, cli_name='smb_home_dir')
option: StrEnum('ipanthomedirectorydrive?', autofill=False, cli_name='smb_home_drive', values=[u'A:', u'B:', u'C:', u'D:', u'E:', u'F:', u'G:', u'H:', u'I:', u'J:', u'K:', u'L:', u'M:', u'N:', u'O:', u'P:', u'Q:', u'R:', u'S:', u'T:', u'U:', u'V:', u'W:', u'X:', u'Y:', u'Z:'])
option: Str('ipantlogonscript?', autofill=False, cli_name='smb_logon_script')
@@ -6374,7 +6479,7 @@ option: Str('ipantprofilepath?', autofill=False, cli_name='smb_profile_path')
option: Str('ipasshpubkey*', autofill=False, cli_name='sshpubkey')
option: Str('ipatokenradiusconfiglink?', autofill=False, cli_name='radius')
option: Str('ipatokenradiususername?', autofill=False, cli_name='radius_username')
option: StrEnum('ipauserauthtype*', autofill=False, cli_name='user_auth_type', values=[u'password', u'radius', u'otp', u'pkinit', u'hardened'])
option: StrEnum('ipauserauthtype*', autofill=False, cli_name='user_auth_type', values=[u'password', u'radius', u'otp', u'pkinit', u'hardened', u'idp'])
option: DateTime('krbpasswordexpiration?', autofill=False, cli_name='password_expiration')
option: DateTime('krbprincipalexpiration?', autofill=False, cli_name='principal_expiration')
option: Principal('krbprincipalname*', autofill=False, cli_name='principal')
@@ -6550,7 +6655,7 @@ output: Output('completed', type=[<type 'int'>])
output: Output('failed', type=[<type 'dict'>])
output: Entry('result')
command: vault_archive_internal/1
args: 1,9,3
args: 1,10,3
arg: Str('cn', cli_name='name')
option: Flag('all', autofill=True, cli_name='all', default=False)
option: Bytes('nonce')
@@ -6561,6 +6666,7 @@ option: Flag('shared?', autofill=True, default=False)
option: Str('username?', cli_name='user')
option: Bytes('vault_data')
option: Str('version?')
option: StrEnum('wrapping_algo?', autofill=True, default=u'aes-128-cbc', values=[u'aes-128-cbc', u'des-ede3-cbc'])
output: Entry('result')
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
output: PrimaryKey('value')
@@ -6651,7 +6757,7 @@ output: Output('completed', type=[<type 'int'>])
output: Output('failed', type=[<type 'dict'>])
output: Entry('result')
command: vault_retrieve_internal/1
args: 1,7,3
args: 1,8,3
arg: Str('cn', cli_name='name')
option: Flag('all', autofill=True, cli_name='all', default=False)
option: Flag('raw', autofill=True, cli_name='raw', default=False)
@@ -6660,6 +6766,7 @@ option: Bytes('session_key')
option: Flag('shared?', autofill=True, default=False)
option: Str('username?', cli_name='user')
option: Str('version?')
option: StrEnum('wrapping_algo?', autofill=True, default=u'aes-128-cbc', values=[u'aes-128-cbc', u'des-ede3-cbc'])
output: Entry('result')
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
output: PrimaryKey('value')
@@ -7023,6 +7130,12 @@ default: idoverrideuser_find/1
default: idoverrideuser_mod/1
default: idoverrideuser_remove_cert/1
default: idoverrideuser_show/1
default: idp/1
default: idp_add/1
default: idp_del/1
default: idp_find/1
default: idp_mod/1
default: idp_show/1
default: idrange/1
default: idrange_add/1
default: idrange_del/1
@@ -7329,6 +7442,7 @@ default: vaultcontainer_del/1
default: vaultcontainer_remove_owner/1
default: vaultcontainer_show/1
default: whoami/1
capability: vault_aes_keywrap 2.246
capability: messages 2.52
capability: optional_uid_params 2.54
capability: permissions2 2.69
+4
View File
@@ -31,6 +31,7 @@ Developers:
Benjamin Drung
Brian Cook
Brian J. Murrell
Brian Turek
Carl George
Cédric Jeanneret
Changmin Teng
@@ -80,6 +81,7 @@ Developers:
Jayesh Garg
Jeremy Frasier
Jérôme Fenal
jh23453
Jim Meyering
Jochen Kellner
JoeDrane
@@ -88,6 +90,7 @@ Developers:
John Morris
Jr Aquino
Julian Gethmann
Julien Rische
Justin Stephenson
Kaleemullah Siddiqui
Karl MacMillan
@@ -110,6 +113,7 @@ Developers:
Martin Košek
Martin Nagy
Matt Rogers
Matthew Davis
Michael Simacek
Michal Polovka
Michal Reznik
+9 -2
View File
@@ -23,6 +23,8 @@ PYTHON_SCRIPT_SUBDIRS = \
$(top_builddir)/install/tools \
$(NULL)
PRCI_DEFINITIONS_DIR = $(top_srcdir)/ipatests/prci_definitions
AZURE_PYTHON_SCRIPT_SUBDIR = $(top_builddir)/ipatests/azure
IPA_PLACEHOLDERS = freeipa ipa ipaserver ipatests
@@ -336,6 +338,8 @@ endif # WITH_RPMLINT
# There are Jinja yaml templates, which differ from reqular ones. These
# files should be placed on skip list (YAML_TEMPLATE_FILES), otherwise
# safe_load fails.
# Also check PRCI definitions yaml files jobs format and content with
# prci_checker script
.PHONY: yamllint
yamllint:
YAML_TEMPLATE_FILES="\
@@ -357,7 +361,10 @@ yamllint:
echo $${YAML}; \
$(PYTHON) -c "import yaml; f = open('$${YAML}'); yaml.safe_load(f); f.close()" || { echo Your YAML file: $${YAML} has a wrong syntax or this is a Jinja template. In the latter clause, consider to add your YAML file to the YAML_TEMPLATE_FILES list in Makefile.am.; exit 1; } \
done; \
echo "-----------"
echo -e "\nCheck PRCI definitions";
@echo "-----------"
$(PYTHON) $(PRCI_DEFINITIONS_DIR)/prci_checker.py -d $(PRCI_DEFINITIONS_DIR) -s $(PRCI_DEFINITIONS_DIR)/prci_jobs_spec.yaml;
@echo "-----------"
# Build & lint documentation.
#
@@ -389,7 +396,7 @@ pylint: $(GENERATED_PYTHON_FILES) ipasetup.py python_scripts
-name '*~' -o \
-name '*.py' -print -o \
-type f -exec grep -qsm1 '^#!.*\bpython' '{}' \; -print`; \
FILES=`echo -e "$${FILES}\n$(AZURE_PYTHON_SCRIPT_SUBDIR)"`; \
FILES=`echo -e "$${FILES}\n$(AZURE_PYTHON_SCRIPT_SUBDIR)\n$(PRCI_DEFINITIONS_DIR)"`; \
echo -e "Pylint on $(PYTHON) is running over files:\n$${FILES}\nPlease wait ...\n"; \
$(PYTHON) -m pylint --version; \
PYTHONPATH=$(top_srcdir) $(PYTHON) -m pylint \
+4 -5
View File
@@ -21,7 +21,7 @@
########################################################
define(IPA_VERSION_MAJOR, 4)
define(IPA_VERSION_MINOR, 9)
define(IPA_VERSION_RELEASE, 8)
define(IPA_VERSION_RELEASE, 11)
########################################################
# For 'pre' releases the version will be #
@@ -49,7 +49,7 @@ define(IPA_VERSION_PRE_RELEASE,)
# This option works only with GNU m4: #
# it requires esyscmd m4 macro. #
########################################################
define(IPA_VERSION_IS_GIT_SNAPSHOT, no)
define(IPA_VERSION_IS_GIT_SNAPSHOT, yes)
########################################################
# git development branch: #
@@ -86,9 +86,8 @@ define(IPA_DATA_VERSION, 20100614120000)
# #
########################################################
define(IPA_API_VERSION_MAJOR, 2)
# Last change: add enable_sid to config
define(IPA_API_VERSION_MINOR, 245)
# Last change: add graceperiodlimit
define(IPA_API_VERSION_MINOR, 248)
########################################################
# Following values are auto-generated from values above
+9 -18
View File
@@ -743,8 +743,7 @@ jsonrpc_request(const char *ipaserver, const json_t *json, curl_buffer *response
json_str = json_dumps(json, 0);
if (!json_str) {
if (debug)
fprintf(stderr, _("json_dumps() failed\n"));
fprintf(stderr, _("json_dumps() failed\n"));
rval = 17;
goto cleanup;
@@ -758,8 +757,7 @@ jsonrpc_request(const char *ipaserver, const json_t *json, curl_buffer *response
CURLcode res = curl_easy_perform(curl);
if (res != CURLE_OK)
{
if (debug)
fprintf(stderr, _("JSON-RPC call failed: %s\n"), curl_easy_strerror(res));
fprintf(stderr, _("JSON-RPC call failed: %s\n"), curl_easy_strerror(res));
rval = 17;
goto cleanup;
@@ -769,8 +767,7 @@ jsonrpc_request(const char *ipaserver, const json_t *json, curl_buffer *response
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &resp_code);
if (resp_code != 200) {
if (debug)
fprintf(stderr, _("JSON-RPC call failed with status code: %li\n"), resp_code);
fprintf(stderr, _("JSON-RPC call failed with status code: %li\n"), resp_code);
if (!quiet && resp_code == 401)
fprintf(stderr, _("JSON-RPC call was unauthorized. Check your credentials.\n"));
@@ -848,8 +845,7 @@ jsonrpc_parse_response(const char *payload, json_t** j_result_obj, bool quiet) {
j_root = json_loads(payload, 0, &j_error);
if (!j_root) {
if (debug)
fprintf(stderr, _("Parsing JSON-RPC response failed: %s\n"), j_error.text);
fprintf(stderr, _("Parsing JSON-RPC response failed: %s\n"), j_error.text);
rval = 17;
goto cleanup;
@@ -864,8 +860,7 @@ jsonrpc_parse_response(const char *payload, json_t** j_result_obj, bool quiet) {
*j_result_obj = json_object_get(j_root, "result");
if (!*j_result_obj) {
if (debug)
fprintf(stderr, _("Parsing JSON-RPC response failed: no 'result' value found.\n"));
fprintf(stderr, _("Parsing JSON-RPC response failed: no 'result' value found.\n"));
rval = 17;
goto cleanup;
@@ -897,8 +892,7 @@ jsonrpc_parse_join_response(const char *payload, join_info *join_i, bool quiet)
&tmp_hostdn,
"krbprincipalname", &tmp_princ,
"krblastpwdchange", &tmp_pwdch) != 0) {
if (debug)
fprintf(stderr, _("Extracting the data from the JSON-RPC response failed: %s\n"), j_error.text);
fprintf(stderr, _("Extracting the data from the JSON-RPC response failed: %s\n"), j_error.text);
rval = 17;
goto cleanup;
@@ -941,8 +935,7 @@ join_krb5_jsonrpc(const char *ipaserver, const char *hostname, char **hostdn, co
"nshardwareplatform", uinfo.machine);
if (!json_req) {
if (debug)
fprintf(stderr, _("json_pack_ex() failed: %s\n"), j_error.text);
fprintf(stderr, _("json_pack_ex() failed: %s\n"), j_error.text);
rval = 17;
goto cleanup;
@@ -990,8 +983,7 @@ jsonrpc_parse_unenroll_response(const char *payload, bool* result, bool quiet) {
if (json_unpack_ex(j_result_obj, &j_error, 0, "{s:b}",
"result", result) != 0) {
if (debug)
fprintf(stderr, _("Extracting the data from the JSON-RPC response failed: %s\n"), j_error.text);
fprintf(stderr, _("Extracting the data from the JSON-RPC response failed: %s\n"), j_error.text);
rval = 20;
goto cleanup;
@@ -1021,8 +1013,7 @@ jsonrpc_unenroll_host(const char *ipaserver, const char *host, bool quiet) {
host);
if (!json_req) {
if (debug)
fprintf(stderr, _("json_pack_ex() failed: %s\n"), j_error.text);
fprintf(stderr, _("json_pack_ex() failed: %s\n"), j_error.text);
rval = 17;
goto cleanup;
+16 -2
View File
@@ -78,7 +78,7 @@ Specifies the insecure CA end user port. The default is 8080.
The time to wait for a certmonger request to complete during installation. The default value is 300 seconds.
.TP
.B context <context>
Specifies the context that IPA is being executed in. IPA may operate differently depending on the context. The current defined contexts are cli and server. Additionally this value is used to load /etc/ipa/\fBcontext\fR.conf to provide context\-specific configuration. For example, if you want to always perform client requests in verbose mode but do not want to have verbose enabled on the server, add the verbose option to \fI/etc/ipa/cli.conf\fR.
Specifies the context that IPA is being executed in. IPA may operate differently depending on the context. The current defined contexts are cli, server and dns. Additionally this value is used to load /etc/ipa/\fBcontext\fR.conf to provide context\-specific configuration. For example, if you want to always perform client requests in verbose mode but do not want to have verbose enabled on the server, add the verbose option to \fI/etc/ipa/cli.conf\fR.
.TP
.B debug <boolean>
When True provides detailed information. Specifically this set the global log level to "debug". Default is False.
@@ -119,6 +119,9 @@ Enable a per-request LDAP cache. The default is True.
.B ldap_cache_size <integer>
The maximum number of entries cached if ldap_cache is True. Since this cache is per-request it is not expected to be very large. The default is 100. Setting the value < 1 effectively disables the cache regardless of the ldap_cache setting
.TP
.B ldap_cache_debug <boolean>
Log details on hits, misses, etc. for the LDAP cache if the cache is enabled.
.TP
.B ldap_uri <URI>
Specifies the URI of the IPA LDAP server to connect to. The URI scheme may be one of \fBldap\fR or \fBldapi\fR. The default is to use ldapi, e.g. ldapi://%2fvar%2frun%2fslapd\-EXAMPLE\-COM.socket
.TP
@@ -160,6 +163,9 @@ Specifies the mode the server is running in. The currently support values are \f
.B mount_ipa <URI>
Specifies the mount point that the development server will register. The default is /ipa/
.TP
.B oidc_child_debug_level <debuglevel>
Specifies the debug level of \fBoidc_child\fR, a helper process used by \fBipa-otpd\fR for OIDC/OAuth2 authentication. Level can be between 0 and 10, the higher the more details. If the level is 6 or higher HTTP debug output is added as well.
.TP
.B prompt_all <boolean>
Specifies that all options should be prompted for in the IPA client, even optional values. Default is False.
.TP
@@ -247,12 +253,20 @@ system\-wide IPA configuration file
.I $HOME/.ipa/default.conf
user IPA configuration file
.TP
It is also possible to define context\-specific configuration files. The \fBcontext\fR is set when the IPA api is initialized. The two currently defined contexts in IPA are \fBcli\fR and \fBserver\fR. This is helpful, for example, if you only want \fBdebug\fR enabled on the server and not in the client. If this is set to True in \fIdefault.conf\fR it will affect both the ipa client tool and the IPA server. If it is only set in \fIserver.conf\fR then only the server will have \fBdebug\fR set. These files will be loaded if they exist:
It is also possible to define context\-specific configuration files. The \fBcontext\fR is set when the IPA api is initialized. The currently defined contexts in IPA are \fBcli\fR, \fBserver\fR and \fBdns\fR. This is helpful, for example, if you only want \fBdebug\fR enabled on the server and not in the client. If this is set to True in \fIdefault.conf\fR it will affect both the ipa client tool and the IPA server. If it is only set in \fIserver.conf\fR then only the server will have \fBdebug\fR set. These files will be loaded if they exist:
.TP
.I /etc/ipa/cli.conf
system\-wide IPA client configuration file
.TP
.I /etc/ipa/server.conf
system\-wide IPA server configuration file
.SH "EXAMPLES"
.TP
An example of a context-specific configuration file is \fB/etc/ipa/dns.conf\fR to be used to increase debug output of the IPA DNSSEC daemons.
.TP
.RS L
[global]
debug = True
.RE
.SH "SEE ALSO"
.BR ipa (1)
+3
View File
@@ -89,6 +89,9 @@ Specifies the From: e-mail address value in the e-mails sent. The default is nor
.B notify_ttls <list of days>
This is the list of days before a password expiration when ipa-epn should notify a user that their password will soon require a reset. If this value is not specified then the default list will be used: 28, 14, 7, 3, 1.
.TP
.B msg_subject <subject>
Specifies the subject of the e-mails sent. The default is "Your password will expire soon."
.TP
.B msg_charset <type>
Set the character set of the message. The default is utf8. This will result in he body of the message being base64-encoded.
.TP
+4 -18
View File
@@ -24,14 +24,12 @@ ipa\-client\-automount [\fIOPTION\fR]... <location>
.SH "DESCRIPTION"
Configures automount for IPA.
The automount configuration consists of three files:
The automount configuration consists of two files:
.PP
.IP o
/etc/nsswitch.conf
.IP o
/etc/sysconfig/autofs
.IP o
/etc/autofs_ldap_auth.conf
.TP
By default this will use DNS discovery to attempt to determine the IPA server(s) to use. If IPA servers are discovered then the automount client will be configured to use DNS discovery.
@@ -42,9 +40,9 @@ The default automount location is named default. To specify a different one use
.TP
The IPA client must already be configured in order to configure automount. The IPA client is configured as part of a server installation.
.TP
There are two ways to configure automount. The default is to use sssd to manage the automount maps. Alternatively autofs can configured to bind to LDAP over GSSAPI and authenticate using the machine's host principal.
SSSD is configured to manage the automount maps.
.TP
The nsswitch automount service is configured to use either sss or ldap and files depending on whether SSSD is configured or not.
The nss automount service is configured to use sss and files.
.TP
NFSv4 is also configured. The rpc.gssd and rpc.idmapd are started on clients to support Kerberos\-secured mounts.
.SH "OPTIONS"
@@ -54,9 +52,6 @@ Set the FQDN of the IPA server to connect to.
\fB\-\-location\fR=\fILOCATION\fR
Automount location.
.TP
\fB\-S\fR, \fB\-\-no\-sssd\fR
Do not configure the client to use SSSD for automount.
.TP
\fB\-\-idmap\-domain\fR=\fIIDMAP_DOMAIN\fR
NFS domain for idmapd.conf. If unset, defaults to the IPA domain. If set to DNS, let idmapd or nfsidmap determine the domain from DNS (see idmapd(8) or nfsidmap(5) for details). If set to anything else, set idmapd.conf's Domain entry to that value.
.TP
@@ -71,21 +66,12 @@ Restore the automount configuration files.
.SH "FILES"
.TP
Files that will be always be configured:
Files that will be configured:
/etc/nsswitch.conf
.TP
Files that will be configured when SSSD is the automount client (default):
/etc/sssd/sssd.conf
.TP
Files that will be configured when using the ldap automount client:
/etc/sysconfig/autofs
/etc/autofs_ldap_auth.conf
.SH "EXIT STATUS"
0 if the installation was successful
+3
View File
@@ -136,6 +136,9 @@ Do not configure OpenSSH server.
\fB\-\-no\-sudo\fR
Do not configure SSSD as a data source for sudo.
.TP
\fB\-\-subid\fR
Configure SSSD as data source for subid.
.TP
\fB\-\-no\-dns\-sshfp\fR
Do not automatically create DNS SSHFP records.
.TP
+3
View File
@@ -64,6 +64,9 @@ smtp_delay = 0
# a user that their password will soon require a reset.
notify_ttls = 28, 14, 7, 3, 1
# Set the subject of the message
# msg_subject =
# Set the character set of the message.
msg_charset = utf8
+17 -3
View File
@@ -101,9 +101,13 @@ dnl ---------------------------------------------------------------------------
SAVE_CPPFLAGS=$CPPFLAGS
CPPFLAGS="$NSPR_CFLAGS $NSS_CFLAGS"
AC_CHECK_LIB([ldap_r], [ldap_search], [ ], AC_MSG_ERROR([libldap_r not found]))
AC_CHECK_LIB([lber], [ber_peek_tag], [ ], AC_MSG_ERROR([liblber not found]))
LDAP_LIBS="-lldap_r -llber"
SAVE_LIBS="$LIBS"
LIBS=
AC_SEARCH_LIBS([ldap_search], [ldap_r ldap], [], [AC_MSG_ERROR([libldap or libldap_r not found])])
AC_SEARCH_LIBS([ber_peek_tag], [lber], [], [AC_MSG_ERROR([liblber not found])])
LDAP_LIBS="$LIBS"
LDAP_CFLAGS=""
LIBS="$SAVE_LIBS"
LDAP_CFLAGS=""
AC_SUBST(LDAP_LIBS)
AC_SUBST(LDAP_CFLAGS)
@@ -289,6 +293,9 @@ AM_COND_IF([BUILD_IPA_CERTAUTH_PLUGIN], [
AM_CONDITIONAL([BUILD_IPA_KDCPOLICY_PLUGIN],
[test x$have_kdcpolicy_plugin = xyes])
AM_CONDITIONAL([BUILD_IPA_ISSUE_PAC],
[test x$have_kdb_issue_pac = xyes])
dnl ---------------------------------------------------------------------------
dnl - Check for program paths
dnl ---------------------------------------------------------------------------
@@ -384,6 +391,7 @@ AC_SUBST([IPAPLATFORM])
AC_MSG_RESULT([${IPAPLATFORM}])
if test "x${IPAPLATFORM}" == "xdebian"; then
HTTPD_GROUP="www-data"
KRB5KDC_SERVICE="krb5-kdc.service"
NAMED_GROUP="bind"
ODS_USER="opendnssec"
@@ -391,6 +399,7 @@ if test "x${IPAPLATFORM}" == "xdebian"; then
# see https://www.debian.org/doc/packaging-manuals/python-policy/ap-packaging_tools.html
PYTHON_INSTALL_EXTRA_OPTIONS="--install-layout=deb"
else
HTTPD_GROUP="apache"
KRB5KDC_SERVICE="krb5kdc.service"
NAMED_GROUP="named"
ODS_USER="ods"
@@ -398,6 +407,10 @@ else
PYTHON_INSTALL_EXTRA_OPTIONS=""
fi
AC_MSG_CHECKING([HTTPD_GROUP])
AC_SUBST([HTTPD_GROUP])
AC_MSG_RESULT([${HTTPD_GROUP}])
AC_SUBST([KRB5KDC_SERVICE])
AC_MSG_CHECKING([NAMED_GROUP])
@@ -633,6 +646,7 @@ AC_CONFIG_FILES([
daemons/ipa-slapi-plugins/ipa-cldap/Makefile
daemons/ipa-slapi-plugins/ipa-dns/Makefile
daemons/ipa-slapi-plugins/ipa-enrollment/Makefile
daemons/ipa-slapi-plugins/ipa-graceperiod/Makefile
daemons/ipa-slapi-plugins/ipa-lockout/Makefile
daemons/ipa-slapi-plugins/ipa-otp-counter/Makefile
daemons/ipa-slapi-plugins/ipa-otp-lasttoken/Makefile
+6 -1
View File
@@ -19,6 +19,7 @@ from ipalib.constants import SOFTHSM_DNSSEC_TOKEN_LABEL
from ipalib.install.kinit import kinit_keytab
from ipapython.dn import DN
from ipapython.ipa_log_manager import standard_logging_setup
from ipapython.ipautil import get_config_debug
from ipapython import ipaldap
from ipaplatform.paths import paths
from ipaserver.dnssec.abshsm import (sync_pkcs11_metadata,
@@ -145,7 +146,11 @@ def ldap2replica_zone_keys_sync(ldapkeydb, localhsm):
# IPA framework initialization
standard_logging_setup(debug=True)
debug = get_config_debug('dns')
standard_logging_setup(debug=debug, verbose=True)
if not debug:
logger.info("To increase debugging set debug=True in dns.conf "
"See default.conf(5) for details")
ipalib.api.bootstrap(context='dns', confdir=paths.ETC_IPA, in_server=True)
ipalib.api.finalize()
+18 -1
View File
@@ -16,14 +16,31 @@ from ipalib.install.kinit import kinit_keytab
from ipapython.dn import DN
from ipapython.ipa_log_manager import standard_logging_setup
from ipapython import ipaldap
from ipapython.ipautil import get_config_debug
from ipaplatform.paths import paths
from ipaserver.dnssec.keysyncer import KeySyncer
logger = logging.getLogger(os.path.basename(__file__))
def fixup_dnssec_utils(self):
try:
os.stat(self.DNSSEC_KEYFROMLABEL)
except FileNotFoundError:
try:
os.stat(self.DNSSEC_KEYFROMLABEL_9_17)
except FileNotFoundError:
pass
else:
self.DNSSEC_KEYFROMLABEL = self.DNSSEC_KEYFROMLABEL_9_17
fixup_dnssec_utils(paths)
# IPA framework initialization
standard_logging_setup(debug=True)
debug = get_config_debug('dns')
standard_logging_setup(debug=debug, verbose=True)
if not debug:
logger.info("To increase debugging set debug=True in dns.conf "
"See default.conf(5) for details")
api.bootstrap(context='dns', confdir=paths.ETC_IPA, in_server=True)
api.finalize()
+6 -1
View File
@@ -36,6 +36,7 @@ from ipalib.install.kinit import kinit_keytab
from ipapython.dn import DN
from ipapython.ipa_log_manager import standard_logging_setup
from ipapython import ipaldap
from ipapython.ipautil import get_config_debug
from ipaplatform.paths import paths
from ipaserver import p11helper
from ipaserver.dnssec.abshsm import sync_pkcs11_metadata, wrappingmech_name2id
@@ -675,7 +676,11 @@ def cleanup_ldap_zone(ldap, dns_dn, zone_name):
# IPA framework initialization
standard_logging_setup(debug=True)
debug = get_config_debug('dns')
standard_logging_setup(debug=debug, verbose=True)
if not debug:
logger.info("To increase debugging set debug=True in dns.conf "
"See default.conf(5) for details")
ipalib.api.bootstrap(context='dns', confdir=paths.ETC_IPA, in_server=True)
ipalib.api.finalize()
+13 -1
View File
@@ -33,7 +33,7 @@ ipadb_la_SOURCES = \
ipa_kdb_passwords.c \
ipa_kdb_principals.c \
ipa_kdb_pwdpolicy.c \
ipa_kdb_mspac.c \
ipa_kdb_mspac.c \
ipa_kdb_mspac_private.h \
ipa_kdb_delegation.c \
ipa_kdb_audit_as.c \
@@ -41,6 +41,12 @@ ipadb_la_SOURCES = \
dist_noinst_DATA = ipa_kdb.exports
if BUILD_IPA_ISSUE_PAC
ipadb_la_SOURCES += ipa_kdb_mspac_v9.c
else
ipadb_la_SOURCES += ipa_kdb_mspac_v6.c
endif
if BUILD_IPA_CERTAUTH_PLUGIN
ipadb_la_SOURCES += ipa_kdb_certauth.c
endif
@@ -84,6 +90,12 @@ ipa_kdb_tests_SOURCES = \
ipa_kdb_audit_as.c \
$(NULL)
if BUILD_IPA_ISSUE_PAC
ipa_kdb_tests_SOURCES += ipa_kdb_mspac_v9.c
else
ipa_kdb_tests_SOURCES += ipa_kdb_mspac_v6.c
endif
if BUILD_IPA_CERTAUTH_PLUGIN
ipa_kdb_tests_SOURCES += ipa_kdb_certauth.c
endif
+45 -1
View File
@@ -199,6 +199,7 @@ static const struct {
{ "otp", IPADB_USER_AUTH_OTP },
{ "pkinit", IPADB_USER_AUTH_PKINIT },
{ "hardened", IPADB_USER_AUTH_HARDENED },
{ "idp", IPADB_USER_AUTH_IDP },
{ }
};
@@ -221,6 +222,10 @@ void ipadb_parse_user_auth(LDAP *lcontext, LDAPMessage *le,
}
}
}
/* If password auth is enabled, enable hardened policy too. */
if (*userauth & IPADB_USER_AUTH_PASSWORD) {
*userauth |= IPADB_USER_AUTH_HARDENED;
}
ldap_value_free_len(vals);
}
@@ -792,8 +797,47 @@ kdb_vftabl kdb_function_table = {
};
#endif
#if (KRB5_KDB_DAL_MAJOR_VERSION == 9)
#error DAL version 9 is not supported yet
/* Version 9 removes sign_authdata and adds issue_pac method. It is a complete
* revamp of how PAC is issued, so we need to implement it differently to previous
* versions. */
kdb_vftabl kdb_function_table = {
.maj_ver = KRB5_KDB_DAL_MAJOR_VERSION,
.min_ver = 0,
.init_library = ipadb_init_library,
.fini_library = ipadb_fini_library,
.init_module = ipadb_init_module,
.fini_module = ipadb_fini_module,
.create = ipadb_create,
.get_age = ipadb_get_age,
.get_principal = ipadb_get_principal,
.put_principal = ipadb_put_principal,
.delete_principal = ipadb_delete_principal,
.iterate = ipadb_iterate,
.create_policy = ipadb_create_pwd_policy,
.get_policy = ipadb_get_pwd_policy,
.put_policy = ipadb_put_pwd_policy,
.iter_policy = ipadb_iterate_pwd_policy,
.delete_policy = ipadb_delete_pwd_policy,
.fetch_master_key = ipadb_fetch_master_key,
.store_master_key_list = ipadb_store_master_key_list,
.change_pwd = ipadb_change_pwd,
.check_transited_realms = ipadb_check_transited_realms,
.check_policy_as = ipadb_check_policy_as,
.audit_as_req = ipadb_audit_as_req,
.check_allowed_to_delegate = ipadb_check_allowed_to_delegate,
.free_principal_e_data = ipadb_free_principal_e_data,
.get_s4u_x509_principal = NULL,
.allowed_to_delegate_from = NULL,
.issue_pac = NULL,
};
#endif
#if (KRB5_KDB_DAL_MAJOR_VERSION != 6) && \
(KRB5_KDB_DAL_MAJOR_VERSION != 7) && \
(KRB5_KDB_DAL_MAJOR_VERSION != 8)
(KRB5_KDB_DAL_MAJOR_VERSION != 8) && \
(KRB5_KDB_DAL_MAJOR_VERSION != 9)
#error unsupported DAL major version
#endif
+2
View File
@@ -89,6 +89,7 @@ enum ipadb_user_auth {
IPADB_USER_AUTH_OTP = 1 << 3,
IPADB_USER_AUTH_PKINIT = 1 << 4,
IPADB_USER_AUTH_HARDENED = 1 << 5,
IPADB_USER_AUTH_IDP = 1 << 6,
};
enum ipadb_user_auth_idx {
@@ -96,6 +97,7 @@ enum ipadb_user_auth_idx {
IPADB_USER_AUTH_IDX_RADIUS,
IPADB_USER_AUTH_IDX_PKINIT,
IPADB_USER_AUTH_IDX_HARDENED,
IPADB_USER_AUTH_IDX_IDP,
IPADB_USER_AUTH_IDX_MAX,
};
+14 -4
View File
@@ -40,7 +40,7 @@ jitter(krb5_deltat baseline, krb5_deltat *lifetime_out)
return;
}
*lifetime_out = baseline - offset % JITTER_WINDOW_SECONDS;
*lifetime_out = baseline - abs(offset) % JITTER_WINDOW_SECONDS;
}
static krb5_error_code
@@ -89,8 +89,9 @@ 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) {
/* If no mechanisms are set, or it is anonymous PKINIT, allow every auth method */
if ((ua == IPADB_USER_AUTH_NONE) ||
(request->kdc_options & KDC_OPT_REQUEST_ANONYMOUS)) {
jitter(ONE_DAY_SECONDS, lifetime_out);
kerr = 0;
goto done;
@@ -133,6 +134,15 @@ ipa_kdcpolicy_check_as(krb5_context context, krb5_kdcpolicy_moddata moddata,
goto done;
}
pol_limits = &(ied->pol_limits[IPADB_USER_AUTH_IDX_HARDENED]);
} else if (strcmp(auth_indicator, "idp") == 0) {
valid_auth_indicators++;
/* Allow hardened even if only password pre-auth is allowed */
if (!(ua & IPADB_USER_AUTH_IDP)) {
*status = "IdP pre-authentication not allowed for this user.";
kerr = KRB5KDC_ERR_POLICY;
goto done;
}
pol_limits = &(ied->pol_limits[IPADB_USER_AUTH_IDX_IDP]);
}
}
@@ -152,7 +162,7 @@ ipa_kdcpolicy_check_as(krb5_context context, krb5_kdcpolicy_moddata moddata,
if (pol_limits->max_life != 0) {
jitter(pol_limits->max_life, lifetime_out);
} else {
jitter(ONE_DAY_SECONDS, lifetime_out);
jitter(client->max_life, lifetime_out);
}
if (pol_limits->max_renewable_life != 0) {
+54 -311
View File
@@ -982,11 +982,11 @@ static krb5_error_code ipadb_get_pac_attrs_blob(TALLOC_CTX *mem_ctx,
#endif
static krb5_error_code ipadb_get_pac(krb5_context kcontext,
krb5_db_entry *client,
unsigned int flags,
krb5_timestamp authtime,
krb5_pac *pac)
krb5_error_code ipadb_get_pac(krb5_context kcontext,
krb5_db_entry *client,
unsigned int flags,
krb5_timestamp authtime,
krb5_pac *pac)
{
TALLOC_CTX *tmpctx;
struct ipadb_e_data *ied;
@@ -1148,7 +1148,8 @@ static krb5_error_code ipadb_get_pac(krb5_context kcontext,
#endif
#ifdef HAVE_PAC_REQUESTER_SID
{
/* MS-KILE 3.3.5.6.4.8: add PAC_REQUESTER_SID only in TGT case */
if ((flags & KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY) != 0) {
union PAC_INFO pac_requester_sid;
/* == Package PAC_REQUESTER_SID == */
memset(&pac_requester_sid, 0, sizeof(pac_requester_sid));
@@ -1180,7 +1181,7 @@ done:
return kerr;
}
static bool is_cross_realm_krbtgt(krb5_const_principal princ)
bool ipadb_is_cross_realm_krbtgt(krb5_const_principal princ)
{
if ((princ->length != 2) ||
(princ->data[0].length != 6) ||
@@ -1696,7 +1697,7 @@ static krb5_error_code check_logon_info_consistent(krb5_context context,
"local [%s], PAC [%s]",
dom ? dom : "<failed to display>",
sid ? sid : "<failed to display>");
return KRB5KDC_ERR_POLICY;
return KRB5KDC_ERR_TGT_REVOKED;
}
}
@@ -1708,7 +1709,7 @@ static krb5_error_code check_logon_info_consistent(krb5_context context,
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;
return KRB5KDC_ERR_TGT_REVOKED;
}
ied = (struct ipadb_e_data *)client_actual->e_data;
@@ -1742,7 +1743,7 @@ static krb5_error_code check_logon_info_consistent(krb5_context context,
"local [%s] vs PAC [%s]",
local_sid ? local_sid : "<failed to display>",
pac_sid ? pac_sid : "<failed to display>");
kerr = KRB5KDC_ERR_POLICY;
kerr = KRB5KDC_ERR_TGT_REVOKED;
goto done;
}
@@ -2004,22 +2005,43 @@ static krb5_error_code ipadb_check_logon_info(krb5_context context,
/* Check that requester SID is the same as in the PAC entry */
if (requester_sid != NULL) {
struct dom_sid client_sid;
bool is_from_trusted_domain = false;
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;
struct ipadb_context *ipactx = ipadb_get_context(context);
if (!ipactx || !ipactx->mspac) {
return KRB5_KDB_DBNOTINITED;
}
/* 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,
requester_sid, false);
if (result) {
is_from_trusted_domain = true;
break;
}
}
}
if (!is_from_trusted_domain) {
/* 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_TGT_REVOKED;
goto done;
}
}
}
@@ -2202,17 +2224,17 @@ done:
return kerr;
}
static krb5_error_code ipadb_verify_pac(krb5_context context,
unsigned int flags,
krb5_const_principal client_princ,
krb5_db_entry *proxy,
krb5_db_entry *server,
krb5_db_entry *krbtgt,
krb5_keyblock *server_key,
krb5_keyblock *krbtgt_key,
krb5_timestamp authtime,
krb5_authdata **authdata,
krb5_pac *pac)
krb5_error_code ipadb_verify_pac(krb5_context context,
unsigned int flags,
krb5_const_principal client_princ,
krb5_db_entry *proxy,
krb5_db_entry *server,
krb5_db_entry *krbtgt,
krb5_keyblock *server_key,
krb5_keyblock *krbtgt_key,
krb5_timestamp authtime,
krb5_authdata **authdata,
krb5_pac *pac)
{
krb5_keyblock *srv_key = NULL;
krb5_keyblock *priv_key = NULL;
@@ -2242,7 +2264,7 @@ static krb5_error_code ipadb_verify_pac(krb5_context context,
* But when a trusted realm passes us a PAC the kdc checksum is
* generated with that realm krbtgt key, so we need to use the cross
* realm krbtgt to check the 'server' checksum instead. */
if (is_cross_realm_krbtgt(krbtgt->princ)) {
if (ipadb_is_cross_realm_krbtgt(krbtgt->princ)) {
/* krbtgt from a trusted realm */
is_cross_realm = true;
@@ -2403,104 +2425,6 @@ done:
return kerr;
}
static krb5_error_code ipadb_sign_pac(krb5_context context,
unsigned int flags,
krb5_const_principal client_princ,
krb5_db_entry *server,
krb5_db_entry *krbtgt,
krb5_keyblock *server_key,
krb5_keyblock *krbtgt_key,
krb5_timestamp authtime,
krb5_pac pac,
krb5_data *pac_data)
{
krb5_keyblock *right_krbtgt_signing_key = NULL;
krb5_key_data *right_krbtgt_key;
krb5_db_entry *right_krbtgt = NULL;
krb5_principal krbtgt_princ = NULL;
krb5_error_code kerr;
char *princ = NULL;
bool is_issuing_referral = false;
int ret;
/* for cross realm trusts cases we need to sign with the right key.
* we need to fetch the right key on our own until the DAL is fixed
* to pass us separate check tgt keys and sign tgt keys */
/* We can only ever create the kdc checksum with our realm tgt key.
* So, if we get a cross realm tgt we have to fetch our realm tgt
* instead. */
if (is_cross_realm_krbtgt(krbtgt->princ)) {
ret = asprintf(&princ, "krbtgt/%.*s@%.*s",
server->princ->realm.length,
server->princ->realm.data,
server->princ->realm.length,
server->princ->realm.data);
if (ret == -1) {
princ = NULL;
kerr = ENOMEM;
goto done;
}
kerr = krb5_parse_name(context, princ, &krbtgt_princ);
if (kerr) {
goto done;
}
kerr = ipadb_get_principal(context, krbtgt_princ, 0, &right_krbtgt);
if (kerr) {
goto done;
}
kerr = krb5_dbe_find_enctype(context, right_krbtgt,
-1, -1, 0, &right_krbtgt_key);
if (kerr) {
goto done;
}
if (!right_krbtgt_key) {
kerr = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
goto done;
}
right_krbtgt_signing_key = malloc(sizeof(krb5_keyblock));
if (!right_krbtgt_signing_key) {
kerr = ENOMEM;
goto done;
}
kerr = krb5_dbe_decrypt_key_data(context, NULL, right_krbtgt_key,
right_krbtgt_signing_key, NULL);
if (kerr) {
goto done;
}
} else {
right_krbtgt_signing_key = krbtgt_key;
}
#ifdef KRB5_KDB_FLAG_ISSUING_REFERRAL
is_issuing_referral = (flags & KRB5_KDB_FLAG_ISSUING_REFERRAL) != 0;
#endif
/* only pass with_realm TRUE when it is cross-realm ticket and S4U2Self
* was requested */
kerr = krb5_pac_sign_ext(context, pac, authtime, client_princ, server_key,
right_krbtgt_signing_key,
(is_issuing_referral &&
(flags & KRB5_KDB_FLAG_PROTOCOL_TRANSITION)),
pac_data);
done:
free(princ);
krb5_free_principal(context, krbtgt_princ);
ipadb_free_principal(context, right_krbtgt);
if (right_krbtgt_signing_key != krbtgt_key) {
krb5_free_keyblock(context, right_krbtgt_signing_key);
}
return kerr;
}
void get_authz_data_types(krb5_context context, krb5_db_entry *entry,
bool *_with_pac, bool *_with_pad)
{
@@ -2630,187 +2554,6 @@ done:
}
krb5_error_code ipadb_sign_authdata(krb5_context context,
unsigned int flags,
krb5_const_principal client_princ,
krb5_db_entry *client,
krb5_db_entry *server,
krb5_db_entry *krbtgt,
krb5_keyblock *client_key,
krb5_keyblock *server_key,
krb5_keyblock *krbtgt_key,
krb5_keyblock *session_key,
krb5_timestamp authtime,
krb5_authdata **tgt_auth_data,
krb5_authdata ***signed_auth_data)
{
krb5_const_principal ks_client_princ;
krb5_authdata **pac_auth_data = NULL;
krb5_authdata *authdata[2] = { NULL, NULL };
krb5_authdata ad;
krb5_boolean is_as_req;
krb5_error_code kerr;
krb5_pac pac = NULL;
krb5_data pac_data;
struct ipadb_context *ipactx;
bool with_pac;
bool with_pad;
bool make_ad = false;
int result;
krb5_db_entry *client_entry = NULL;
krb5_boolean is_equal;
bool force_reinit_mspac = false;
is_as_req = ((flags & KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY) != 0);
/* When using s4u2proxy client_princ actually refers to the proxied user
* while client->princ to the proxy service asking for the TGS on behalf
* of the proxied user. So always use client_princ in preference */
if (client_princ != NULL) {
ks_client_princ = client_princ;
if (!is_as_req) {
is_equal = false;
if ((client != NULL) && (client->princ != NULL)) {
is_equal = krb5_principal_compare(context, client_princ, client->princ);
}
if (!is_equal) {
kerr = ipadb_get_principal(context, client_princ, flags, &client_entry);
/* If we didn't find client_princ in our database, it might be:
* - a principal from another realm, handle it down in ipadb_get/verify_pac()
*/
if (kerr != 0) {
client_entry = NULL;
}
}
}
} else {
if (client == NULL) {
*signed_auth_data = NULL;
return 0;
}
ks_client_princ = client->princ;
}
if (client_entry == NULL) client_entry = client;
if (is_as_req) {
get_authz_data_types(context, client_entry, &with_pac, &with_pad);
} else {
get_authz_data_types(context, server, &with_pac, &with_pad);
}
if (with_pad) {
krb5_klog_syslog(LOG_ERR, "PAD authorization data is requested but " \
"currently not supported.");
}
/* we need to create a PAC if we are requested one and this is an AS REQ,
* or we are doing protocol transition (S4USelf) but not over cross-realm
*/
if ((is_as_req && (flags & KRB5_KDB_FLAG_INCLUDE_PAC)) ||
((flags & KRB5_KDB_FLAG_PROTOCOL_TRANSITION) && (client != NULL))) {
make_ad = true;
}
if (with_pac && make_ad) {
ipactx = ipadb_get_context(context);
if (!ipactx) {
kerr = ENOMEM;
goto done;
}
/* Be aggressive here: special case for discovering range type
* immediately after establishing the trust by IPA framework. For all
* other cases call ipadb_reinit_mspac() with force_reinit_mspac set
* to 'false' to make sure the information about trusted domains is
* updated on a regular basis for all worker processes. */
if ((krb5_princ_size(context, ks_client_princ) == 2) &&
(strncmp(krb5_princ_component(context, ks_client_princ, 0)->data, "HTTP",
krb5_princ_component(context, ks_client_princ, 0)->length) == 0) &&
(ulc_casecmp(krb5_princ_component(context, ks_client_princ, 1)->data,
krb5_princ_component(context, ks_client_princ, 1)->length,
ipactx->kdc_hostname, strlen(ipactx->kdc_hostname),
NULL, NULL, &result) == 0)) {
force_reinit_mspac = true;
}
(void)ipadb_reinit_mspac(ipactx, force_reinit_mspac);
kerr = ipadb_get_pac(context, client, flags, authtime, &pac);
if (kerr != 0 && kerr != ENOENT) {
goto done;
}
} else if (with_pac && !is_as_req) {
/* find the existing PAC, if present */
kerr = krb5_find_authdata(context, tgt_auth_data, NULL,
KRB5_AUTHDATA_WIN2K_PAC, &pac_auth_data);
if (kerr != 0) {
goto done;
}
/* check or generate pac data */
if ((pac_auth_data == NULL) || (pac_auth_data[0] == NULL)) {
if (flags & KRB5_KDB_FLAG_CONSTRAINED_DELEGATION) {
kerr = ipadb_get_pac(context, client_entry, flags, authtime, &pac);
if (kerr != 0 && kerr != ENOENT) {
goto done;
}
}
} else {
if (pac_auth_data[1] != NULL) {
kerr = KRB5KDC_ERR_BADOPTION; /* FIXME: right error ? */
goto done;
}
kerr = ipadb_verify_pac(context, flags, ks_client_princ, client,
server, krbtgt, server_key, krbtgt_key,
authtime, pac_auth_data, &pac);
if (kerr != 0) {
goto done;
}
}
}
if (pac == NULL) {
/* No PAC to deal with, proceed */
*signed_auth_data = NULL;
kerr = 0;
goto done;
}
kerr = ipadb_sign_pac(context, flags, ks_client_princ, server, krbtgt,
server_key, krbtgt_key, authtime, pac, &pac_data);
if (kerr != 0) {
goto done;
}
/* put in signed data */
ad.magic = KV5M_AUTHDATA;
ad.ad_type = KRB5_AUTHDATA_WIN2K_PAC;
ad.contents = (krb5_octet *)pac_data.data;
ad.length = pac_data.length;
authdata[0] = &ad;
kerr = krb5_encode_authdata_container(context,
KRB5_AUTHDATA_IF_RELEVANT,
authdata,
signed_auth_data);
krb5_free_data_contents(context, &pac_data);
if (kerr != 0) {
goto done;
}
kerr = 0;
done:
if (client_entry != NULL && client_entry != client) {
ipadb_free_principal(context, client_entry);
}
krb5_pac_free(context, pac);
return kerr;
}
static char *get_server_netbios_name(struct ipadb_context *ipactx)
{
+19 -1
View File
@@ -55,4 +55,22 @@ 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);
void get_authz_data_types(krb5_context context, krb5_db_entry *entry,
bool *_with_pac, bool *_with_pad);
bool *_with_pac, bool *_with_pad);
bool ipadb_is_cross_realm_krbtgt(krb5_const_principal princ);
krb5_error_code ipadb_get_pac(krb5_context kcontext,
krb5_db_entry *client,
unsigned int flags,
krb5_timestamp authtime,
krb5_pac *pac);
krb5_error_code ipadb_verify_pac(krb5_context context,
unsigned int flags,
krb5_const_principal client_princ,
krb5_db_entry *proxy,
krb5_db_entry *server,
krb5_db_entry *krbtgt,
krb5_keyblock *server_key,
krb5_keyblock *krbtgt_key,
krb5_timestamp authtime,
krb5_authdata **authdata,
krb5_pac *pac);
+315
View File
@@ -0,0 +1,315 @@
/*
* MIT Kerberos KDC database backend for FreeIPA
*
* Authors: Simo Sorce <ssorce@redhat.com>
*
* Copyright (C) 2011 Simo Sorce, Red Hat
* see file 'COPYING' for use and warranty information
*
* This program is free software you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "ipa_hostname.h"
#include "ipa_kdb.h"
#include <talloc.h>
#include <unicase.h>
#include "util/time.h"
#include "gen_ndr/ndr_krb5pac.h"
#include "ipa_kdb_mspac_private.h"
static krb5_error_code ipadb_sign_pac(krb5_context context,
unsigned int flags,
krb5_const_principal client_princ,
krb5_db_entry *server,
krb5_db_entry *krbtgt,
krb5_keyblock *server_key,
krb5_keyblock *krbtgt_key,
krb5_timestamp authtime,
krb5_pac pac,
krb5_data *pac_data)
{
krb5_keyblock *right_krbtgt_signing_key = NULL;
krb5_key_data *right_krbtgt_key;
krb5_db_entry *right_krbtgt = NULL;
krb5_principal krbtgt_princ = NULL;
krb5_error_code kerr;
char *princ = NULL;
bool is_issuing_referral = false;
int ret;
/* for cross realm trusts cases we need to sign with the right key.
* we need to fetch the right key on our own until the DAL is fixed
* to pass us separate check tgt keys and sign tgt keys */
/* We can only ever create the kdc checksum with our realm tgt key.
* So, if we get a cross realm tgt we have to fetch our realm tgt
* instead. */
if (ipadb_is_cross_realm_krbtgt(krbtgt->princ)) {
ret = asprintf(&princ, "krbtgt/%.*s@%.*s",
server->princ->realm.length,
server->princ->realm.data,
server->princ->realm.length,
server->princ->realm.data);
if (ret == -1) {
princ = NULL;
kerr = ENOMEM;
goto done;
}
kerr = krb5_parse_name(context, princ, &krbtgt_princ);
if (kerr) {
goto done;
}
kerr = ipadb_get_principal(context, krbtgt_princ, 0, &right_krbtgt);
if (kerr) {
goto done;
}
kerr = krb5_dbe_find_enctype(context, right_krbtgt,
-1, -1, 0, &right_krbtgt_key);
if (kerr) {
goto done;
}
if (!right_krbtgt_key) {
kerr = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
goto done;
}
right_krbtgt_signing_key = malloc(sizeof(krb5_keyblock));
if (!right_krbtgt_signing_key) {
kerr = ENOMEM;
goto done;
}
kerr = krb5_dbe_decrypt_key_data(context, NULL, right_krbtgt_key,
right_krbtgt_signing_key, NULL);
if (kerr) {
goto done;
}
} else {
right_krbtgt_signing_key = krbtgt_key;
}
#ifdef KRB5_KDB_FLAG_ISSUING_REFERRAL
is_issuing_referral = (flags & KRB5_KDB_FLAG_ISSUING_REFERRAL) != 0;
#endif
/* only pass with_realm TRUE when it is cross-realm ticket and S4U2Self
* was requested */
kerr = krb5_pac_sign_ext(context, pac, authtime, client_princ, server_key,
right_krbtgt_signing_key,
(is_issuing_referral &&
(flags & KRB5_KDB_FLAG_PROTOCOL_TRANSITION)),
pac_data);
done:
free(princ);
krb5_free_principal(context, krbtgt_princ);
ipadb_free_principal(context, right_krbtgt);
if (right_krbtgt_signing_key != krbtgt_key) {
krb5_free_keyblock(context, right_krbtgt_signing_key);
}
return kerr;
}
krb5_error_code ipadb_sign_authdata(krb5_context context,
unsigned int flags,
krb5_const_principal client_princ,
krb5_db_entry *client,
krb5_db_entry *server,
krb5_db_entry *krbtgt,
krb5_keyblock *client_key,
krb5_keyblock *server_key,
krb5_keyblock *krbtgt_key,
krb5_keyblock *session_key,
krb5_timestamp authtime,
krb5_authdata **tgt_auth_data,
krb5_authdata ***signed_auth_data)
{
krb5_const_principal ks_client_princ;
krb5_authdata **pac_auth_data = NULL;
krb5_authdata *authdata[2] = { NULL, NULL };
krb5_authdata ad;
krb5_boolean is_as_req;
krb5_error_code kerr;
krb5_pac pac = NULL;
krb5_data pac_data;
struct ipadb_context *ipactx;
bool with_pac;
bool with_pad;
bool make_ad = false;
int result;
krb5_db_entry *client_entry = NULL;
krb5_boolean is_equal;
bool force_reinit_mspac = false;
is_as_req = ((flags & KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY) != 0);
/* When using s4u2proxy client_princ actually refers to the proxied user
* while client->princ to the proxy service asking for the TGS on behalf
* of the proxied user. So always use client_princ in preference */
if (client_princ != NULL) {
ks_client_princ = client_princ;
if (!is_as_req) {
is_equal = false;
if ((client != NULL) && (client->princ != NULL)) {
is_equal = krb5_principal_compare(context, client_princ, client->princ);
}
if (!is_equal) {
kerr = ipadb_get_principal(context, client_princ, flags, &client_entry);
/* If we didn't find client_princ in our database, it might be:
* - a principal from another realm, handle it down in ipadb_get/verify_pac()
*/
if (kerr != 0) {
client_entry = NULL;
}
}
}
} else {
if (client == NULL) {
*signed_auth_data = NULL;
return 0;
}
ks_client_princ = client->princ;
}
if (client_entry == NULL) client_entry = client;
if (is_as_req) {
get_authz_data_types(context, client_entry, &with_pac, &with_pad);
} else {
get_authz_data_types(context, server, &with_pac, &with_pad);
}
if (with_pad) {
krb5_klog_syslog(LOG_ERR, "PAD authorization data is requested but " \
"currently not supported.");
}
/* we need to create a PAC if we are requested one and this is an AS REQ,
* or we are doing protocol transition (S4USelf) but not over cross-realm
*/
if ((is_as_req && (flags & KRB5_KDB_FLAG_INCLUDE_PAC)) ||
((flags & KRB5_KDB_FLAG_PROTOCOL_TRANSITION) && (client != NULL))) {
make_ad = true;
}
if (with_pac && make_ad) {
ipactx = ipadb_get_context(context);
if (!ipactx) {
kerr = ENOMEM;
goto done;
}
/* Be aggressive here: special case for discovering range type
* immediately after establishing the trust by IPA framework. For all
* other cases call ipadb_reinit_mspac() with force_reinit_mspac set
* to 'false' to make sure the information about trusted domains is
* updated on a regular basis for all worker processes. */
if ((krb5_princ_size(context, ks_client_princ) == 2) &&
(strncmp(krb5_princ_component(context, ks_client_princ, 0)->data, "HTTP",
krb5_princ_component(context, ks_client_princ, 0)->length) == 0) &&
(ulc_casecmp(krb5_princ_component(context, ks_client_princ, 1)->data,
krb5_princ_component(context, ks_client_princ, 1)->length,
ipactx->kdc_hostname, strlen(ipactx->kdc_hostname),
NULL, NULL, &result) == 0)) {
force_reinit_mspac = true;
}
(void)ipadb_reinit_mspac(ipactx, force_reinit_mspac);
kerr = ipadb_get_pac(context, client, flags, authtime, &pac);
if (kerr != 0 && kerr != ENOENT) {
goto done;
}
} else if (with_pac && !is_as_req) {
/* find the existing PAC, if present */
kerr = krb5_find_authdata(context, tgt_auth_data, NULL,
KRB5_AUTHDATA_WIN2K_PAC, &pac_auth_data);
if (kerr != 0) {
goto done;
}
/* check or generate pac data */
if ((pac_auth_data == NULL) || (pac_auth_data[0] == NULL)) {
if (flags & KRB5_KDB_FLAG_CONSTRAINED_DELEGATION) {
kerr = ipadb_get_pac(context, client_entry, flags, authtime, &pac);
if (kerr != 0 && kerr != ENOENT) {
goto done;
}
}
} else {
if (pac_auth_data[1] != NULL) {
kerr = KRB5KDC_ERR_BADOPTION; /* FIXME: right error ? */
goto done;
}
kerr = ipadb_verify_pac(context, flags, ks_client_princ, client,
server, krbtgt, server_key, krbtgt_key,
authtime, pac_auth_data, &pac);
if (kerr != 0) {
goto done;
}
}
}
if (pac == NULL) {
/* No PAC to deal with, proceed */
*signed_auth_data = NULL;
kerr = 0;
goto done;
}
kerr = ipadb_sign_pac(context, flags, ks_client_princ, server, krbtgt,
server_key, krbtgt_key, authtime, pac, &pac_data);
if (kerr != 0) {
goto done;
}
/* put in signed data */
ad.magic = KV5M_AUTHDATA;
ad.ad_type = KRB5_AUTHDATA_WIN2K_PAC;
ad.contents = (krb5_octet *)pac_data.data;
ad.length = pac_data.length;
authdata[0] = &ad;
kerr = krb5_encode_authdata_container(context,
KRB5_AUTHDATA_IF_RELEVANT,
authdata,
signed_auth_data);
krb5_free_data_contents(context, &pac_data);
if (kerr != 0) {
goto done;
}
kerr = 0;
done:
if (client_entry != NULL && client_entry != client) {
ipadb_free_principal(context, client_entry);
}
krb5_pac_free(context, pac);
return kerr;
}
+34
View File
@@ -0,0 +1,34 @@
/*
* MIT Kerberos KDC database backend for FreeIPA
*
* Authors: Simo Sorce <ssorce@redhat.com>
*
* Copyright (C) 2011 Simo Sorce, Red Hat
* see file 'COPYING' for use and warranty information
*
* This program is free software you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "ipa_hostname.h"
#include "ipa_kdb.h"
#include <talloc.h>
#include <unicase.h>
#include "util/time.h"
#include "gen_ndr/ndr_krb5pac.h"
#include "ipa_kdb_mspac_private.h"
+67 -14
View File
@@ -77,6 +77,7 @@ static char *std_principal_attrs[] = {
IPA_KRB_AUTHZ_DATA_ATTR,
IPA_USER_AUTH_TYPE,
"ipatokenRadiusConfigLink",
"ipaIdpConfigLink",
"krbAuthIndMaxTicketLife",
"krbAuthIndMaxRenewableAge",
"ipaNTSecurityIdentifier",
@@ -316,8 +317,31 @@ static void ipadb_validate_radius(struct ipadb_context *ipactx,
"ipatokenRadiusConfigLink");
if (vals == NULL || vals[0] == NULL)
*ua &= ~IPADB_USER_AUTH_RADIUS;
else
*ua = IPADB_USER_AUTH_RADIUS;
else {
/* OTP use implies presence of password in IPA LDAP,
* this is incompatible with RADIUS proxy case where
* a password in LDAP is not used anymore. */
*ua &= ~IPADB_USER_AUTH_OTP;
}
if (vals != NULL)
ldap_value_free_len(vals);
}
static void ipadb_validate_idp(struct ipadb_context *ipactx,
LDAPMessage *lentry,
enum ipadb_user_auth *ua)
{
struct berval **vals;
if (!(*ua & IPADB_USER_AUTH_IDP))
return;
/* Ensure that the user has a link to an IdP config. */
vals = ldap_get_values_len(ipactx->lcontext, lentry,
"ipaIdpConfigLink");
if (vals == NULL || vals[0] == NULL)
*ua &= ~IPADB_USER_AUTH_IDP;
if (vals != NULL)
ldap_value_free_len(vals);
@@ -355,6 +379,7 @@ static enum ipadb_user_auth ipadb_get_user_auth(struct ipadb_context *ipactx,
/* Perform flag validation. */
ipadb_validate_otp(ipactx, lentry, &ua);
ipadb_validate_radius(ipactx, lentry, &ua);
ipadb_validate_idp(ipactx, lentry, &ua);
return ua;
}
@@ -537,6 +562,8 @@ static void ipadb_parse_authind_policies(krb5_context kcontext,
IPADB_USER_AUTH_PKINIT, IPADB_USER_AUTH_IDX_PKINIT},
{"krbAuthIndMaxTicketLife;hardened",
IPADB_USER_AUTH_HARDENED, IPADB_USER_AUTH_IDX_HARDENED},
{"krbAuthIndMaxTicketLife;idp",
IPADB_USER_AUTH_IDP, IPADB_USER_AUTH_IDX_IDP},
{NULL, IPADB_USER_AUTH_NONE, IPADB_USER_AUTH_IDX_MAX},
}, age_authind_map[] = {
{"krbAuthIndMaxRenewableAge;otp",
@@ -547,6 +574,8 @@ static void ipadb_parse_authind_policies(krb5_context kcontext,
IPADB_USER_AUTH_PKINIT, IPADB_USER_AUTH_IDX_PKINIT},
{"krbAuthIndMaxRenewableAge;hardened",
IPADB_USER_AUTH_HARDENED, IPADB_USER_AUTH_IDX_HARDENED},
{"krbAuthIndMaxRenewableAge;idp",
IPADB_USER_AUTH_IDP, IPADB_USER_AUTH_IDX_IDP},
{NULL, IPADB_USER_AUTH_NONE, IPADB_USER_AUTH_IDX_MAX},
};
@@ -556,7 +585,13 @@ static void ipadb_parse_authind_policies(krb5_context kcontext,
}
for (size_t i = 0; life_authind_map[i].attribute != NULL; i++) {
if (ua & life_authind_map[i].flag) {
/* Only change max_life/max_renewable_life per indicator
* if the value wasn't set yet. This function gets called twice:
* - for the principal entry
* - for the associated policy lookup */
if ((ua & life_authind_map[i].flag) &&
(ied->pol_limits[life_authind_map[i].idx].max_life == 0)) {
ret = ipadb_ldap_attr_to_int(lcontext, lentry,
life_authind_map[i].attribute,
&result);
@@ -583,6 +618,7 @@ static krb5_error_code ipadb_parse_ldap_entry(krb5_context kcontext,
{
const krb5_octet rad_string[] = "otp\0[{\"indicators\": [\"radius\"]}]";
const krb5_octet otp_string[] = "otp\0[{\"indicators\": [\"otp\"]}]";
const krb5_octet idp_string[] = "idp\0[{\"type\":\"oauth2\",\"indicators\": [\"idp\"]}]";
struct ipadb_context *ipactx;
enum ipadb_user_auth ua;
LDAP *lcontext;
@@ -788,17 +824,18 @@ static krb5_error_code ipadb_parse_ldap_entry(krb5_context kcontext,
&res_key_data, &result, &mkvno);
switch (ret) {
case 0:
/* Only set a principal's key if password auth can be used. Otherwise
* the KDC would add pre-authentication methods to the NEEDED_PREAUTH
* reply for AS-REQs which indicate the password authentication is
* available. This might confuse applications like e.g. SSSD which try
* to determine suitable authentication methods and corresponding
* prompts with the help of MIT Kerberos' responder interface which
* acts on the returned pre-authentication methods. A typical example
* is enforced OTP authentication where of course keys are available
* for the first factor but password authentication should not be
* advertised by the KDC. */
if (!(ua & IPADB_USER_AUTH_PASSWORD) && (ua != IPADB_USER_AUTH_NONE)) {
/* Only set a principal's key if password or hardened auth can be used.
* Otherwise the KDC would add pre-authentication methods to the
* NEEDED_PREAUTH reply for AS-REQs which indicate the password
* authentication is available. This might confuse applications like
* e.g. SSSD which try to determine suitable authentication methods and
* corresponding prompts with the help of MIT Kerberos' responder
* interface which acts on the returned pre-authentication methods. A
* typical example is enforced OTP authentication where of course keys
* are available for the first factor but password authentication
* should not be advertised by the KDC. */
if (!(ua & (IPADB_USER_AUTH_PASSWORD | IPADB_USER_AUTH_HARDENED)) &&
(ua != IPADB_USER_AUTH_NONE)) {
/* This is the same behavior as ENOENT below. */
ipa_krb5_free_key_data(res_key_data, result);
break;
@@ -960,6 +997,11 @@ static krb5_error_code ipadb_parse_ldap_entry(krb5_context kcontext,
sizeof(rad_string), rad_string);
if (kerr)
goto done;
} else if (ua & IPADB_USER_AUTH_IDP) {
kerr = ipadb_set_tl_data(entry, KRB5_TL_STRING_ATTRS,
sizeof(idp_string), idp_string);
if (kerr)
goto done;
}
if (ua & ~IPADB_USER_AUTH_NONE) {
@@ -1251,6 +1293,8 @@ static krb5_error_code ipadb_fetch_tktpolicy(krb5_context kcontext,
if (!first) {
kerr = KRB5_KDB_NOENTRY;
} else {
struct ipadb_e_data *ied;
if (polmask & MAXTKTLIFE_BIT) {
ret = ipadb_ldap_attr_to_int(ipactx->lcontext, first,
"krbmaxticketlife", &result);
@@ -1278,6 +1322,15 @@ static krb5_error_code ipadb_fetch_tktpolicy(krb5_context kcontext,
entry->attributes |= maybe_require_preauth(ipactx, entry);
}
}
ied = (struct ipadb_e_data *)entry->e_data;
if (ied && ied->ipa_user == true) {
/* Apply default policy to indicators, if any */
if (ied->user_auth & ~IPADB_USER_AUTH_NONE) {
ipadb_parse_authind_policies(kcontext, ipactx->lcontext,
first, entry, ied->user_auth);
}
}
}
}
+2 -1
View File
@@ -9,7 +9,8 @@ ipa_otpd_LDADD = $(top_builddir)/util/libutil.la
dist_noinst_DATA = ipa-otpd.socket.in ipa-otpd@.service.in test.py
systemdsystemunit_DATA = ipa-otpd.socket ipa-otpd@.service
ipa_otpd_SOURCES = bind.c forward.c main.c parse.c query.c queue.c stdio.c
ipa_otpd_SOURCES = bind.c forward.c main.c parse.c query.c queue.c stdio.c \
oauth2.c
%.socket: %.socket.in
@sed -e 's|@krb5rundir[@]|$(krb5rundir)|g' \
+58
View File
@@ -28,6 +28,13 @@
#include <errno.h>
#ifndef UCHAR_MAX
#define UCHAR_MAX 255
#endif
/* RFC 2865 */
#define MAX_ATTRSIZE (UCHAR_MAX - 2)
#define SECRET ""
#define otpd_log_req(req, ...) \
otpd_log_req_(__FILE__, __LINE__, (req), __VA_ARGS__)
@@ -36,11 +43,28 @@
struct otpd_queue_iter;
enum ldap_query {
LDAP_QUERY_EMPTY = 0,
LDAP_QUERY_USER,
LDAP_QUERY_RADIUS,
LDAP_QUERY_RADIUS_USERMAP,
LDAP_QUERY_IDP,
LDAP_QUERY_END
};
enum oauth2_state {
OAUTH2_NO = 0,
OAUTH2_GET_ISSUER,
OAUTH2_GET_DEVICE_CODE,
OAUTH2_GET_ACCESS_TOKEN
};
struct otpd_queue_item {
struct otpd_queue_item *next;
krad_packet *req;
krad_packet *rsp;
size_t sent;
enum ldap_query ldap_query;
char *error;
struct {
@@ -48,6 +72,9 @@ struct otpd_queue_item {
char *uid;
char *ipatokenRadiusUserName;
char *ipatokenRadiusConfigLink;
char *ipaidpSub;
char *ipaidpConfigLink;
char **ipauserauthtypes;
char *other;
} user;
@@ -58,6 +85,28 @@ struct otpd_queue_item {
time_t ipatokenRadiusTimeout;
size_t ipatokenRadiusRetries;
} radius;
struct {
char *name;
char *ipaidpIssuerURL;
char *ipaidpDevAuthEndpoint;
char *ipaidpTokenEndpoint;
char *ipaidpUserInfoEndpoint;
char *ipaidpKeysEndpoint;
char *ipaidpClientID;
char *ipaidpClientSecret;
char *ipaidpScope;
char *ipaidpSub;
krb5_boolean valid;
char* ipaidpDebugLevelStr;
krb5_boolean ipaidpDebugCurl;
} idp;
struct {
char *device_code_reply;
krb5_data state;
} oauth2;
int msgid;
};
@@ -98,6 +147,10 @@ struct otpd_context {
struct otpd_queue requests;
struct otpd_queue responses;
} bind;
struct {
struct otpd_queue states;
} oauth2_state;
};
extern struct otpd_context ctx;
@@ -143,8 +196,13 @@ krb5_error_code otpd_forward(struct otpd_queue_item **i);
const char *otpd_parse_user(LDAP *ldp, LDAPMessage *entry,
struct otpd_queue_item *item);
const char *otpd_parse_idp(LDAP *ldp, LDAPMessage *entry,
struct otpd_queue_item *item);
const char *otpd_parse_radius(LDAP *ldp, LDAPMessage *entry,
struct otpd_queue_item *item);
const char *otpd_parse_radius_username(LDAP *ldp, LDAPMessage *entry,
struct otpd_queue_item *item);
int oauth2(struct otpd_queue_item **item, enum oauth2_state);
+2 -2
View File
@@ -242,7 +242,8 @@ int main(int argc, char **argv)
goto error;
}
ctx.vctx = verto_new(NULL, VERTO_EV_TYPE_IO | VERTO_EV_TYPE_SIGNAL);
ctx.vctx = verto_default(NULL, VERTO_EV_TYPE_IO | VERTO_EV_TYPE_SIGNAL
| VERTO_EV_TYPE_CHILD);
if (ctx.vctx == NULL) {
otpd_log_err(ENOMEM, "Unable to initialize event loop");
goto error;
@@ -342,4 +343,3 @@ error:
krb5_free_context(ctx.kctx);
return ctx.exitstatus;
}
+614
View File
@@ -0,0 +1,614 @@
/*
* FreeIPA 2FA companion daemon
*
* Authors: Sumit Bose <sbose@redhat.com>
*
* Copyright (C) 2021 Red Hat
* see file 'COPYING' for use and warranty information
*
* This program is free software you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* This file reaches out to a third-party IdP to handle an OAuth2
* authentication request (stdio.c/query.c) if the user is configured
* accordingly. The result is placed in the stdout queue (stdio.c).
*/
#include <krb5/krb5.h>
#include <stdbool.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/random.h>
#include "internal.h"
#define OIDC_CHILD_PATH "/usr/libexec/sssd/oidc_child"
struct child_ctx {
int read_from_child;
int write_to_child;
verto_ev *read_ev;
verto_ev *write_ev;
verto_ev *child_ev;
struct otpd_queue_item *item;
struct otpd_queue_item *saved_item;
enum oauth2_state oauth2_state;
};
static int set_fd_nonblocking(int fd)
{
int flags;
int ret;
flags = fcntl(fd, F_GETFL, 0);
if (flags == -1) {
ret = errno;
return ret;
}
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
ret = errno;
return ret;
}
return 0;
}
static void free_child_ctx(verto_ctx *vctx, verto_ev *ev)
{
(void)vctx; /* Unused */
struct child_ctx *child_ctx;
child_ctx = verto_get_private(ev);
free(child_ctx);
}
static void oauth2_on_child_exit(verto_ctx *vctx, verto_ev *ev)
{
(void)vctx; /* Unused */
verto_proc_status st;
st = verto_get_proc_status(ev);
/* The krad req might not be available at this stage anymore, so
* otpd_log_err() is used. */
otpd_log_err(0, "Child finished with status [%d].", WEXITSTATUS(st));
}
static void oauth2_on_child_writable(verto_ctx *vctx, verto_ev *ev)
{
(void)vctx; /* Unused */
ssize_t io;
struct child_ctx *child_ctx;
child_ctx = verto_get_private(ev);
if (child_ctx == NULL) {
otpd_log_err(EINVAL, "Lost child context");
verto_del(ev);
return;
}
if (child_ctx->oauth2_state == OAUTH2_GET_DEVICE_CODE) {
/* no input needed */
verto_del(ev);
return;
}
io = write(verto_get_fd(ev),
child_ctx->saved_item->oauth2.device_code_reply,
strlen(child_ctx->saved_item->oauth2.device_code_reply));
otpd_queue_item_free(child_ctx->saved_item);
if (io < 0) {
switch (errno) {
#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || EAGAIN - EWOULDBLOCK != 0)
case EWOULDBLOCK:
#endif
#if defined(EAGAIN)
case EAGAIN:
#endif
case ENOBUFS:
case EINTR:
/* In this case, we just need to try again. */
return;
default:
/* Unrecoverable. */
break;
}
otpd_log_err(errno, "Failed to send to child");
}
verto_del(ev);
}
#define min(a,b) ((a) > (b) ? (b) : (a))
static int add_krad_attr_to_set(struct child_ctx *child_ctx,
krad_attrset *attrset,
krb5_data *datap,
krad_attr attr, const char *message)
{
krb5_data state = {0};
char *p = datap->data;
unsigned int len = datap->length;
int ret = 0;
do {
state.data = p;
state.length = min(MAX_ATTRSIZE - 5, len);
p += state.length;
ret = krad_attrset_add(attrset, attr, &(state));
if (ret != 0) {
otpd_log_req(child_ctx->item->req, message);
break;
}
len -= state.length;
} while (len > 0);
return ret;
}
/* Most attributes have limited length (MAX_ATTRSIZE). In order to accept longer
* values, we will concatenate all the attribute values to single krb5_data. */
static int get_krad_attr_from_packet(const krad_packet *rres,
krad_attr attr, krb5_data *_data)
{
const krb5_data *rmsg;
krb5_data data = {0};
unsigned int memindex;
unsigned int i;
i = 0;
do {
rmsg = krad_packet_get_attr(rres, attr, i);
if (rmsg != NULL) {
data.length += rmsg->length;
}
i++;
} while (rmsg != NULL);
if (data.length == 0) {
return ENOENT;
}
data.data = malloc(data.length);
if (data.data == NULL) {
return ENOMEM;
}
i = 0;
memindex = 0;
do {
rmsg = krad_packet_get_attr(rres, attr, i);
if (rmsg != NULL) {
memcpy(&data.data[memindex], rmsg->data, rmsg->length);
memindex += rmsg->length;
}
i++;
} while (rmsg != NULL);
if (memindex != data.length) {
free(data.data);
return ERANGE;
}
*_data = data;
return 0;
}
/* oidc_child will return two lines.
* The first is a JSON formatted string containing the device code and other
* data needed to get the access token in the second round. This will be
* returned to the caller as Radius Proxy-State so that the caller will send
* it back in the next round.
* The second line is the string expected by the krb5 oauth2 pre-auth plugin
* and will be send to the caller as Radius Reply-Message.
*/
static int handle_device_code_reply(struct child_ctx *child_ctx,
const char *dc_reply, char *rad_reply)
{
krad_attrset *attrset = NULL;
int ret;
krb5_data data = { 0 };
struct otpd_queue_item *state_item;
ret = otpd_queue_item_new(NULL, &state_item);
if (ret != 0) {
otpd_log_req(child_ctx->item->req, "Failed to allocate state item");
goto done;
}
state_item->oauth2.device_code_reply = strdup(dc_reply);
if (state_item->oauth2.device_code_reply == NULL) {
otpd_log_req(child_ctx->item->req, "Failed to copy device code reply.");
goto done;
}
ret = krad_attrset_new(ctx.kctx, &attrset);
if (ret != 0) {
otpd_log_req(child_ctx->item->req,
"Failed to create radius attribute set");
goto done;
}
state_item->oauth2.state.magic = 0;
state_item->oauth2.state.data = strdup(dc_reply);
if (state_item->oauth2.state.data == NULL) {
otpd_log_req(child_ctx->item->req,
"Failed to copy device code reply to krad.");
goto done;
}
state_item->oauth2.state.length = strlen(dc_reply);
ret = add_krad_attr_to_set(child_ctx, attrset, &(state_item->oauth2.state),
krad_attr_name2num("Proxy-State"),
"Failed to serialize state to attribute set");
if (ret != 0) {
goto done;
}
data.magic = 0;
data.data = rad_reply;
data.length = strlen(rad_reply);
ret = add_krad_attr_to_set(child_ctx, attrset, &data,
krad_attr_name2num("Reply-Message"),
"Failed to serialize reply to attribute set");
if (ret != 0) {
goto done;
}
ret = krad_packet_new_response(ctx.kctx, SECRET,
krad_code_name2num("Access-Challenge"),
attrset,
child_ctx->item->req, &child_ctx->item->rsp);
if (ret != 0) {
otpd_log_err(ret, "Failed to create radius response");
child_ctx->item->rsp = NULL;
}
otpd_queue_push(&ctx.oauth2_state.states, state_item);
ret = 0;
done:
krad_attrset_free(attrset);
if (ret != 0) {
if (state_item != NULL) {
free(state_item->oauth2.state.data);
free(state_item->oauth2.device_code_reply);
free(state_item);
}
}
return ret;
}
static int check_access_token_reply(struct child_ctx *child_ctx,
const char *buf, size_t len)
{
int ret;
if (strlen(child_ctx->item->user.ipaidpSub) != len
|| memcmp(child_ctx->item->user.ipaidpSub, buf, len) != 0) {
return EPERM;
}
ret = krad_packet_new_response(ctx.kctx, SECRET,
krad_code_name2num("Access-Accept"), NULL,
child_ctx->item->req, &child_ctx->item->rsp);
if (ret != 0) {
otpd_log_err(ret, "Failed to create radius response");
child_ctx->item->rsp = NULL;
}
return ret;
}
static void oauth2_on_child_readable(verto_ctx *, verto_ev *ev)
{
static char buf[10240];
ssize_t io = 0;
struct child_ctx *child_ctx = NULL;
int ret;
char *rad_reply;
char *end;
child_ctx = (struct child_ctx *) verto_get_private(ev);
if (child_ctx == NULL) {
otpd_log_err(EINVAL, "Lost child context");
verto_del(ev);
return;
}
/* Make sure ctx.stdio.responses will at least return an error */
child_ctx->item->rsp = NULL;
child_ctx->item->sent = 0;
io = read(verto_get_fd(ev), buf, 10240);
if (io < 0) {
otpd_log_err(errno, "Failed to read from child");
goto done;
}
if (io >= 0) {
buf[io] = '\0';
otpd_log_req(child_ctx->item->req, "Received: [%s]", buf);
}
verto_del(ev);
if (child_ctx->oauth2_state == OAUTH2_GET_DEVICE_CODE) {
/* expect 2 lines of output. First the orginal JSON string return by
* the IdP from the devicecode request which will be used as input to
* the child process in the second run. Second the JSON string returned
* in the radius reply. */
rad_reply = memchr(buf, '\n', io);
if (rad_reply != NULL) {
*rad_reply = '\0';
rad_reply++;
end = memchr(rad_reply, '\n', io - (rad_reply - 1 - buf));
if (end == NULL) {
otpd_log_req(child_ctx->item->req, "Missing second new-line.");
goto done;
}
*end = '\0';
ret = handle_device_code_reply(child_ctx, buf, rad_reply);
if (ret != 0) {
otpd_log_req(child_ctx->item->req,
"Failed to handle device code reply.");
}
}
} else if (child_ctx->oauth2_state == OAUTH2_GET_ACCESS_TOKEN) {
ret = check_access_token_reply(child_ctx, buf, (size_t) io);
if (ret != 0) {
otpd_log_req(child_ctx->item->req,
"Failed to check access token reply.");
}
} else {
/* error */
otpd_log_req(child_ctx->item->req, "Unexpected state [%d].",
child_ctx->oauth2_state);
}
done:
otpd_queue_push(&ctx.stdio.responses, child_ctx->item);
verto_set_flags(ctx.stdio.writer, VERTO_EV_FLAG_PERSIST |
VERTO_EV_FLAG_IO_ERROR |
VERTO_EV_FLAG_IO_READ |
VERTO_EV_FLAG_IO_WRITE);
}
static const char *oauth2_state_to_str(enum oauth2_state oauth2_state)
{
switch (oauth2_state) {
case OAUTH2_NO:
return "OAuth2 not available";
break;
case OAUTH2_GET_ISSUER:
return "Get issuer from LDAP";
break;
case OAUTH2_GET_DEVICE_CODE:
return "Get device code";
break;
case OAUTH2_GET_ACCESS_TOKEN:
return "Get access token";
break;
default:
return "Unknown OAuth2 state";
}
}
int oauth2(struct otpd_queue_item **item, enum oauth2_state oauth2_state)
{
int ret;
pid_t child_pid;
int pipefd_to_child[2] = { -1, -1};
int pipefd_from_child[2] = { -1, -1};
struct child_ctx *child_ctx;
/* Up to 50 arguments to the helper supported. The amount of arguments
* is controlled inside this function. Right now max used is below 20 */
char *args[50] = {NULL};
size_t args_idx = 0;
krb5_data data_state = {0};
struct otpd_queue_item *saved_item;
if (oauth2_state != OAUTH2_GET_DEVICE_CODE
&& oauth2_state != OAUTH2_GET_ACCESS_TOKEN) {
otpd_log_req((*item)->req, "Unexpected OAuth2 state [%d][%s]",
oauth2_state, oauth2_state_to_str(oauth2_state));
return EINVAL;
}
if (oauth2_state == OAUTH2_GET_ACCESS_TOKEN) {
ret = get_krad_attr_from_packet((*item)->req,
krad_attr_name2num("Proxy-State"),
&data_state);
if ((ret != 0) || (data_state.length == 0)) {
otpd_log_req((*item)->req, "Missing Radius Proxy-State attribute");
return EINVAL;
}
saved_item = calloc(sizeof(struct otpd_queue_item), 1);
if (saved_item == NULL) {
otpd_log_req((*item)->req, "No matching saved state found");
return EINVAL;
}
saved_item->oauth2.device_code_reply = strndup(data_state.data,
data_state.length);
if (saved_item->oauth2.device_code_reply == NULL) {
otpd_log_req((*item)->req, "Failed to copy device code reply");
return EINVAL;
}
krb5_free_data_contents(NULL, &data_state);
}
child_ctx = calloc(sizeof(struct child_ctx), 1);
if (child_ctx == NULL) {
ret = ENOMEM;
goto done;
}
child_ctx->item = (*item);
child_ctx->saved_item = saved_item;
child_ctx->oauth2_state = oauth2_state;
otpd_log_req((*item)->req, "oauth2 start: %s",
oauth2_state_to_str(oauth2_state));
args[args_idx++] = OIDC_CHILD_PATH;
if (oauth2_state == OAUTH2_GET_DEVICE_CODE) {
args[args_idx++] = "--get-device-code";
} else {
args[args_idx++] = "--get-access-token";
}
if ((*item)->idp.ipaidpIssuerURL != NULL) {
args[args_idx++] = "--issuer-url";
args[args_idx++] = (*item)->idp.ipaidpIssuerURL;
} else {
args[args_idx++] = "--device-auth-endpoint";
args[args_idx++] = (*item)->idp.ipaidpDevAuthEndpoint;
args[args_idx++] = "--token-endpoint";
args[args_idx++] = (*item)->idp.ipaidpTokenEndpoint;
args[args_idx++] = "--userinfo-endpoint";
args[args_idx++] = (*item)->idp.ipaidpUserInfoEndpoint;
if ((*item)->idp.ipaidpKeysEndpoint) {
args[args_idx++] = "--jwks-uri";
args[args_idx++] = (*item)->idp.ipaidpKeysEndpoint;
}
}
args[args_idx++] = "--client-id";
args[args_idx++] = (*item)->idp.ipaidpClientID;
if ((*item)->idp.ipaidpClientSecret) {
args[args_idx++] = "--client-secret";
args[args_idx++] = (*item)->idp.ipaidpClientSecret;
}
if ((*item)->idp.ipaidpScope) {
args[args_idx++] = "--scope";
args[args_idx++] = (*item)->idp.ipaidpScope;
}
if ((*item)->idp.ipaidpSub) {
args[args_idx++] = "--user-identifier-attribute";
args[args_idx++] = (*item)->idp.ipaidpSub;
}
if ((*item)->idp.ipaidpDebugLevelStr != NULL) {
args[args_idx++] = "--debug-level";
args[args_idx++] = (*item)->idp.ipaidpDebugLevelStr;
}
if ((*item)->idp.ipaidpDebugCurl) {
args[args_idx++] = "--libcurl-debug";
}
#if 0
for (int i; args[i]; i++) {
otpd_log_req((*item)->req, "oidc_child exec: %s", args[i]);
}
#endif
ret = pipe(pipefd_from_child);
if (ret == -1) {
ret = errno;
goto done;
}
ret = pipe(pipefd_to_child);
if (ret == -1) {
ret = errno;
goto done;
}
child_pid = fork();
if (child_pid == 0) { /* child */
close(pipefd_to_child[1]);
ret = dup2(pipefd_to_child[0], STDIN_FILENO);
if (ret == -1) {
exit(EXIT_FAILURE);
}
close(pipefd_from_child[0]);
ret = dup2(pipefd_from_child[1], STDOUT_FILENO);
if (ret == -1) {
exit(EXIT_FAILURE);
}
execv(OIDC_CHILD_PATH, args);
exit(EXIT_FAILURE);
} else if (child_pid > 0) { /* parent */
close(pipefd_to_child[0]);
set_fd_nonblocking(pipefd_to_child[1]);
child_ctx->write_to_child = pipefd_to_child[1];
close(pipefd_from_child[1]);
set_fd_nonblocking(pipefd_from_child[0]);
child_ctx->read_from_child = pipefd_from_child[0];
child_ctx->write_ev = verto_add_io(ctx.vctx, VERTO_EV_FLAG_PERSIST |
VERTO_EV_FLAG_IO_CLOSE_FD |
VERTO_EV_FLAG_IO_ERROR |
VERTO_EV_FLAG_IO_WRITE,
oauth2_on_child_writable,
child_ctx->write_to_child);
if (child_ctx->write_ev == NULL) {
ret = ENOMEM;
otpd_log_err(ret, "Unable to initialize oauth2 writer event");
goto done;
}
verto_set_private(child_ctx->write_ev, child_ctx, NULL);
child_ctx->read_ev = verto_add_io(ctx.vctx, VERTO_EV_FLAG_PERSIST |
VERTO_EV_FLAG_IO_CLOSE_FD |
VERTO_EV_FLAG_IO_ERROR |
VERTO_EV_FLAG_IO_READ,
oauth2_on_child_readable,
child_ctx->read_from_child);
if (child_ctx->read_ev == NULL) {
ret = ENOMEM;
otpd_log_err(ret, "Unable to initialize oauth2 writer event");
goto done;
}
verto_set_private(child_ctx->read_ev, child_ctx, NULL);
child_ctx->child_ev = verto_add_child(ctx.vctx, VERTO_EV_FLAG_NONE,
oauth2_on_child_exit, child_pid);
verto_set_private(child_ctx->child_ev, child_ctx, free_child_ctx);
} else { /* error */
ret = errno;
otpd_log_err(ret, "Failed to fork oidc_child");
goto done;
}
ret = 0;
done:
if (ret == 0) {
*item = NULL;
}
return ret;
}
+176
View File
@@ -24,8 +24,11 @@
* This file parses the user's configuration received from LDAP (see query.c).
*/
#define _GNU_SOURCE /* for asprintf() */
#include "internal.h"
#include <asm-generic/errno-base.h>
#include <ctype.h>
#include <krb5/krb5.h>
#define DEFAULT_TIMEOUT 15
#define DEFAULT_RETRIES 3
@@ -65,6 +68,69 @@ static int get_string(LDAP *ldp, LDAPMessage *entry, const char *name,
return 0;
}
/* Convert an LDAP entry into an allocated string array. */
static int get_string_array(LDAP *ldp, LDAPMessage *entry, const char *name,
char ***out)
{
struct berval **vals;
ber_len_t i;
char **buf;
int tmp;
size_t count;
size_t c;
int ret;
vals = ldap_get_values_len(ldp, entry, name);
if (vals == NULL)
return ENOENT;
tmp = ldap_count_values_len(vals);
if (tmp < 0) {
ret = ENOENT;
goto done;
}
count = (size_t) tmp;
buf = calloc(count + 1, sizeof(char *));
if (buf == NULL) {
ret = ENOMEM;
goto done;
}
for (c = 0; c < count; c++) {
buf[c] = calloc(vals[c]->bv_len + 1, sizeof(char));
if (buf[c] == NULL) {
ret = ENOMEM;
goto done;
}
for (i = 0; i < vals[c]->bv_len; i++) {
if (!isprint(vals[c]->bv_val[i])) {
ret = EINVAL;
goto done;
}
buf[c][i] = vals[c]->bv_val[i];
}
}
if (*out != NULL)
free(*out);
*out = buf;
ret = 0;
done:
if (ret != 0 && buf != NULL) {
for (c = 0; buf[c] != NULL; c++) {
free(buf[c]);
}
free(buf);
}
ldap_value_free_len(vals);
return ret;
}
/* Convert an LDAP entry into an unsigned long. */
static int get_ulong(LDAP *ldp, LDAPMessage *entry, const char *name,
unsigned long *out)
@@ -112,6 +178,21 @@ const char *otpd_parse_user(LDAP *ldp, LDAPMessage *entry,
if (i != 0 && i != ENOENT)
return strerror(i);
i = get_string(ldp, entry, "ipaidpSub",
&item->user.ipaidpSub);
if (i != 0 && i != ENOENT)
return strerror(i);
i = get_string(ldp, entry, "ipaidpConfigLink",
&item->user.ipaidpConfigLink);
if (i != 0 && i != ENOENT)
return strerror(i);
i = get_string_array(ldp, entry, "ipauserauthtype",
&item->user.ipauserauthtypes);
if (i != 0 && i != ENOENT)
return strerror(i);
/* Get the DN. */
item->user.dn = ldap_get_dn(ldp, entry);
if (item->user.dn == NULL) {
@@ -122,6 +203,101 @@ const char *otpd_parse_user(LDAP *ldp, LDAPMessage *entry,
return NULL;
}
#define ENV_OIDC_CHILD_DEBUG_LEVEL "oidc_child_debug_level"
/* Parse the IdP configuration */
const char *otpd_parse_idp(LDAP *ldp, LDAPMessage *entry,
struct otpd_queue_item *item)
{
int i;
long dbg_lvl = 0;
const char *dbg_env = NULL;
char *endptr = NULL;
item->idp.valid = FALSE;
i = get_string(ldp, entry, "cn", &item->idp.name);
if (i != 0) {
return strerror(i);
}
i = get_string(ldp, entry, "ipaidpIssuerURL", &item->idp.ipaidpIssuerURL);
if ((i != 0) && (i != ENOENT)) {
return strerror(i);
}
/* We support either passing issuer URL or individual end-points */
if (i == ENOENT) {
i = get_string(ldp, entry, "ipaidpDevAuthEndpoint", &item->idp.ipaidpDevAuthEndpoint);
if (i != 0) {
return strerror(i);
}
i = get_string(ldp, entry, "ipaidpTokenEndpoint", &item->idp.ipaidpTokenEndpoint);
if (i != 0) {
return strerror(i);
}
i = get_string(ldp, entry, "ipaidpUserInfoEndpoint", &item->idp.ipaidpUserInfoEndpoint);
if (i != 0) {
return strerror(i);
}
/* JWKS end-point may be optional */
i = get_string(ldp, entry, "ipaidpKeysEndpoint", &item->idp.ipaidpKeysEndpoint);
if ((i != 0) && (i != ENOENT)) {
return strerror(i);
}
}
i = get_string(ldp, entry, "ipaidpClientID", &item->idp.ipaidpClientID);
if (i != 0) {
return strerror(i);
}
i = get_string(ldp, entry, "ipaidpClientSecret", &item->idp.ipaidpClientSecret);
if ((i != 0) && (i != ENOENT)) {
return strerror(i);
}
i = get_string(ldp, entry, "ipaidpScope", &item->idp.ipaidpScope);
if ((i != 0) && (i != ENOENT)) {
return strerror(i);
}
i = get_string(ldp, entry, "ipaidpSub", &item->idp.ipaidpSub);
if ((i != 0) && (i != ENOENT)) {
return strerror(i);
}
item->idp.ipaidpDebugLevelStr = NULL;
item->idp.ipaidpDebugCurl = FALSE;
dbg_env = getenv(ENV_OIDC_CHILD_DEBUG_LEVEL);
if (dbg_env != NULL && *dbg_env != '\0') {
errno = 0;
dbg_lvl = strtoul(dbg_env, &endptr, 10);
if (errno == 0 && *endptr == '\0') {
if (dbg_lvl < 0) {
dbg_lvl = 0;
} else if (dbg_lvl > 10) {
dbg_lvl = 10;
}
if (asprintf(&item->idp.ipaidpDebugLevelStr, "%ld", dbg_lvl) != -1) {
if (dbg_lvl > 5) {
item->idp.ipaidpDebugCurl = TRUE;
}
} else {
otpd_log_req(item->req, "Failed to copy debug level");
}
} else {
otpd_log_req(item->req,
"Cannot parse value [%s] from environment variable [%s]",
dbg_env, ENV_OIDC_CHILD_DEBUG_LEVEL);
}
}
item->idp.valid = TRUE;
return NULL;
}
/* Parse the user's RADIUS configuration. */
const char *otpd_parse_radius(LDAP *ldp, LDAPMessage *entry,
struct otpd_queue_item *item)
+162 -14
View File
@@ -31,6 +31,7 @@
#define _GNU_SOURCE 1 /* for asprintf() */
#include "internal.h"
#include <ctype.h>
#include <stdbool.h>
#define DEFAULT_TIMEOUT 15
#define DEFAULT_RETRIES 3
@@ -39,6 +40,9 @@ static char *user[] = {
"uid",
"ipatokenRadiusUserName",
"ipatokenRadiusConfigLink",
"ipaidpSub",
"ipaidpConfigLink",
"ipauserauthtype",
NULL
};
@@ -51,6 +55,37 @@ static char *radius[] = {
NULL
};
static char *idp[] = {
"ipaidpClientID",
"ipaidpClientSecret",
"ipaidpIssuerURL",
"ipaidpDevAuthEndpoint",
"ipaidpTokenEndpoint",
"ipaidpUserInfoEndpoint",
"ipaidpKeysEndpoint",
"ipaidpScope",
"ipaidpSub",
"cn",
NULL
};
static bool auth_type_is(char **auth_types, const char *check)
{
size_t c;
if (auth_types == NULL || check == NULL) {
return false;
}
for(c = 0; auth_types[c] != NULL; c++) {
if (strcasecmp(auth_types[c], check) == 0) {
return true;
}
}
return false;
}
/* Send queued LDAP requests to the server. */
static void on_query_writable(verto_ctx *vctx, verto_ev *ev)
{
@@ -76,6 +111,7 @@ static void on_query_writable(verto_ctx *vctx, verto_ev *ev)
goto error;
otpd_log_req(item->req, "user query start");
item->ldap_query = LDAP_QUERY_USER;
if (asprintf(&filter, "(&(objectClass=Person)(krbPrincipalName=%*s))",
princ->length, princ->data) < 0)
@@ -86,9 +122,20 @@ static void on_query_writable(verto_ctx *vctx, verto_ev *ev)
NULL, NULL, 1, &item->msgid);
free(filter);
} else if (auth_type_is(item->user.ipauserauthtypes, "idp")) {
otpd_log_req(item->req, "idp query start: %s",
item->user.ipaidpConfigLink);
item->ldap_query = LDAP_QUERY_IDP;
i = ldap_search_ext(verto_get_private(ev),
item->user.ipaidpConfigLink,
LDAP_SCOPE_BASE, NULL, idp, 0, NULL,
NULL, NULL, 1, &item->msgid);
} else if (item->radius.ipatokenRadiusSecret == NULL) {
otpd_log_req(item->req, "radius query start: %s",
item->user.ipatokenRadiusConfigLink);
item->ldap_query = LDAP_QUERY_RADIUS;
i = ldap_search_ext(verto_get_private(ev),
item->user.ipatokenRadiusConfigLink,
@@ -98,6 +145,7 @@ static void on_query_writable(verto_ctx *vctx, verto_ev *ev)
} else if (item->radius.ipatokenUserMapAttribute != NULL) {
otpd_log_req(item->req, "username query start: %s",
item->radius.ipatokenUserMapAttribute);
item->ldap_query = LDAP_QUERY_RADIUS_USERMAP;
attrs[0] = item->radius.ipatokenUserMapAttribute;
attrs[1] = NULL;
@@ -107,7 +155,6 @@ static void on_query_writable(verto_ctx *vctx, verto_ev *ev)
}
if (i == LDAP_SUCCESS) {
item->sent++;
push = &ctx.query.responses;
}
@@ -115,6 +162,78 @@ error:
otpd_queue_push(push, item);
}
static enum oauth2_state get_oauth2_state(enum ldap_query ldap_query,
struct otpd_queue_item *item)
{
const krb5_data *data_pwd;
const krb5_data *data_state;
enum oauth2_state oauth2_state = OAUTH2_NO;
data_pwd = krad_packet_get_attr(item->req,
krad_attr_name2num("User-Password"), 0);
data_state = krad_packet_get_attr(item->req,
krad_attr_name2num("Proxy-State"), 0);
if (data_pwd == NULL && data_state == NULL) {
oauth2_state = OAUTH2_GET_DEVICE_CODE;
} else if (data_pwd == NULL && data_state != NULL) {
oauth2_state = OAUTH2_GET_ACCESS_TOKEN;
}
/* Looks like caller does not expect oauth2 authentication */
if (oauth2_state == OAUTH2_NO) {
return oauth2_state;
}
if (ldap_query == LDAP_QUERY_USER) {
/* Check the user entry for required attributes */
if (item->user.ipaidpSub == NULL) {
oauth2_state = OAUTH2_NO;
otpd_log_req(item->req,
"OAuth2 not possible, Missing 'sub' in user entry");
}
if (item->user.ipaidpConfigLink == NULL) {
oauth2_state = OAUTH2_NO;
otpd_log_req(item->req,
"OAuth2 not possible, Missing issuer in user entry");
}
if (oauth2_state != OAUTH2_NO) {
/* Next step is to lookup IdP data */
oauth2_state = OAUTH2_GET_ISSUER;
}
} else if (ldap_query == LDAP_QUERY_IDP) {
/* Check the idp entry for required attributes */
if (item->idp.ipaidpIssuerURL == NULL) {
if (item->idp.ipaidpDevAuthEndpoint == NULL) {
oauth2_state = OAUTH2_NO;
otpd_log_req(item->req,
"OAuth2 not possible, "
"Missing authentication end-point in idp entry");
}
if (item->idp.ipaidpTokenEndpoint == NULL) {
oauth2_state = OAUTH2_NO;
otpd_log_req(item->req,
"OAuth2 not possible, "
"Missing access token end-point in idp entry");
}
if (item->idp.ipaidpUserInfoEndpoint == NULL) {
oauth2_state = OAUTH2_NO;
otpd_log_req(item->req,
"OAuth2 not possible, "
"Missing userinfo end-point in idp entry");
}
}
if (item->idp.ipaidpClientID == NULL) {
oauth2_state = OAUTH2_NO;
otpd_log_req(item->req,
"OAuth2 not possible, Missing client ID in idp entry");
}
}
return oauth2_state;
}
/* Read LDAP responses from the server. */
static void on_query_readable(verto_ctx *vctx, verto_ev *ev)
{
@@ -126,6 +245,7 @@ static void on_query_readable(verto_ctx *vctx, verto_ev *ev)
LDAP *ldp;
int i;
(void)vctx;
enum oauth2_state oauth2_state;
ldp = verto_get_private(ev);
@@ -150,16 +270,19 @@ static void on_query_readable(verto_ctx *vctx, verto_ev *ev)
goto egress;
err = NULL;
switch (item->sent) {
case 1:
switch (item->ldap_query) {
case LDAP_QUERY_USER:
err = otpd_parse_user(ldp, entry, item);
break;
case 2:
case LDAP_QUERY_RADIUS:
err = otpd_parse_radius(ldp, entry, item);
break;
case 3:
case LDAP_QUERY_RADIUS_USERMAP:
err = otpd_parse_radius_username(ldp, entry, item);
break;
case LDAP_QUERY_IDP:
err = otpd_parse_idp(ldp, entry, item);
break;
default:
ldap_msgfree(entry);
goto egress;
@@ -181,14 +304,14 @@ static void on_query_readable(verto_ctx *vctx, verto_ev *ev)
item->msgid = -1;
switch (item->sent) {
case 1:
switch (item->ldap_query) {
case LDAP_QUERY_USER:
otpd_log_req(item->req, "user query end: %s",
item->error == NULL ? item->user.dn : item->error);
if (item->user.dn == NULL || item->user.uid == NULL)
goto egress;
break;
case 2:
case LDAP_QUERY_RADIUS:
otpd_log_req(item->req, "radius query end: %s",
item->error == NULL
? item->radius.ipatokenRadiusServer
@@ -197,22 +320,47 @@ static void on_query_readable(verto_ctx *vctx, verto_ev *ev)
item->radius.ipatokenRadiusSecret == NULL)
goto egress;
break;
case 3:
case LDAP_QUERY_RADIUS_USERMAP:
otpd_log_req(item->req, "username query end: %s",
item->error == NULL ? item->user.other : item->error);
break;
case LDAP_QUERY_IDP:
otpd_log_req(item->req, "idp query end: %s",
item->error == NULL ? item->idp.name : item->error);
if (!item->idp.valid) {
goto egress;
}
break;
default:
goto egress;
}
if (item->error != NULL)
goto egress;
if (item->sent == 1 && item->user.ipatokenRadiusConfigLink != NULL) {
/* Check for oauth2 */
oauth2_state = get_oauth2_state(item->ldap_query, item);
if (oauth2_state == OAUTH2_GET_ISSUER) {
push = &ctx.query.requests;
event = ctx.query.io;
goto egress;
} else if (item->sent == 2 &&
} else if (oauth2_state != OAUTH2_NO) {
i = oauth2(&item, oauth2_state);
if (i != 0) {
goto egress;
} else {
/* oauth2 will call ctx.stdio.writer, so we can return here */
return;
}
}
if (item->error != NULL)
goto egress;
if (item->ldap_query == LDAP_QUERY_USER &&
item->user.ipatokenRadiusConfigLink != NULL) {
push = &ctx.query.requests;
event = ctx.query.io;
goto egress;
} else if (item->ldap_query == LDAP_QUERY_RADIUS &&
item->radius.ipatokenUserMapAttribute != NULL &&
item->user.ipatokenRadiusUserName == NULL) {
push = &ctx.query.requests;
+27
View File
@@ -46,6 +46,8 @@ krb5_error_code otpd_queue_item_new(krad_packet *req,
void otpd_queue_item_free(struct otpd_queue_item *item)
{
size_t c;
if (item == NULL)
return;
@@ -54,9 +56,34 @@ void otpd_queue_item_free(struct otpd_queue_item *item)
free(item->user.ipatokenRadiusUserName);
free(item->user.ipatokenRadiusConfigLink);
free(item->user.other);
free(item->user.ipaidpSub);
free(item->user.ipaidpConfigLink);
if (item->user.ipauserauthtypes != NULL) {
for (c = 0; item->user.ipauserauthtypes[c] != NULL; c++) {
free(item->user.ipauserauthtypes[c]);
}
free(item->user.ipauserauthtypes);
}
free(item->radius.ipatokenRadiusServer);
free(item->radius.ipatokenRadiusSecret);
free(item->radius.ipatokenUserMapAttribute);
free(item->idp.ipaidpIssuerURL);
free(item->idp.ipaidpDevAuthEndpoint);
free(item->idp.ipaidpTokenEndpoint);
free(item->idp.ipaidpUserInfoEndpoint);
free(item->idp.ipaidpKeysEndpoint);
free(item->idp.name);
free(item->idp.ipaidpClientID);
if (item->idp.ipaidpClientSecret != NULL) {
size_t len = strlen(item->idp.ipaidpClientSecret);
(void*) memset(item->idp.ipaidpClientSecret, 0, len);
free(item->idp.ipaidpClientSecret);
}
free(item->idp.ipaidpScope);
free(item->idp.ipaidpSub);
free(item->idp.ipaidpDebugLevelStr);
free(item->oauth2.device_code_reply);
free(item->oauth2.state.data);
free(item->error);
krad_packet_free(item->req);
krad_packet_free(item->rsp);
+2
View File
@@ -166,6 +166,7 @@ void otpd_on_stdout_writable(verto_ctx *vctx, verto_ev *ev)
/* Send the packet. */
data = krad_packet_encode(item->rsp);
otpd_log_req(item->req, "sent: %d data: %d", item->sent, data->length);
i = write(verto_get_fd(ev), data->data + item->sent,
data->length - item->sent);
if (i < 0) {
@@ -191,6 +192,7 @@ void otpd_on_stdout_writable(verto_ctx *vctx, verto_ev *ev)
/* If the packet was completely sent, free the response. */
item->sent += i;
otpd_log_req(item->req, "..sent: %d data: %d", item->sent, data->length);
if (item->sent == data->length) {
otpd_log_req(item->req, "response sent: %s",
krad_code_num2name(krad_packet_get_code(item->rsp)));
+1 -1
View File
@@ -59,7 +59,7 @@ def main():
rsp.DecodePacket(buf)
pkt.VerifyReply(rsp)
proc.terminate() # pylint: disable=E1101
proc.terminate()
proc.wait()
if __name__ == '__main__':
+117 -40
View File
@@ -2728,7 +2728,7 @@ static NTSTATUS get_trust_pwd(TALLOC_CTX *mem_ctx, const DATA_BLOB *auth_blob,
if (iopw.count != 0 && iopw.current.count != 0 &&
iopw.current.array[0].AuthType == TRUST_AUTH_TYPE_CLEAR) {
if (pwd != NULL) {
if (!convert_string_talloc(tmp_ctx, CH_UTF16, CH_UNIX,
if (!convert_string_talloc(tmp_ctx, CH_UTF16LE, CH_UNIX,
iopw.current.array[0].AuthInfo.clear.password,
iopw.current.array[0].AuthInfo.clear.size,
&trustpw, &converted_size)) {
@@ -3581,12 +3581,14 @@ static bool init_sam_from_ldap(struct ipasam_private *ipasam_state,
bool ret = false;
bool retval = false;
bool machine_account = false;
bool trusted_domain = false;
int status;
int len = 0;
int idx = 0;
size_t conv_size = 0;
DATA_BLOB nthash;
struct dom_sid *group_sid;
uint32_t acct_flags = 0;
TALLOC_CTX *tmp_ctx = talloc_init("init_sam_from_ldap");
if (!tmp_ctx) {
@@ -3613,17 +3615,15 @@ static bool init_sam_from_ldap(struct ipasam_private *ipasam_state,
}
len = ldap_count_values_len(usernames);
if (len > 1) {
/* Extract machine account as a user name if exists.
* If not, extract the first returned value */
for (int i=0; i < len; i++) {
if (usernames[i] != NULL &&
usernames[i]->bv_len > 0 &&
usernames[i]->bv_val[usernames[i]->bv_len-1] == '$') {
idx = i;
machine_account = true;
break;
}
/* Extract machine account as a user name if exists.
* If not, extract the first returned value */
for (int i=0; i < len; i++) {
if (usernames[i] != NULL &&
usernames[i]->bv_len > 0 &&
usernames[i]->bv_val[usernames[i]->bv_len-1] == '$') {
idx = i;
machine_account = true;
break;
}
}
@@ -3644,6 +3644,31 @@ static bool init_sam_from_ldap(struct ipasam_private *ipasam_state,
DEBUG(2, ("init_sam_from_ldap: Entry found for user: %s\n", username));
if (machine_account) {
/* it may also be a TDO account */
struct berval **oclasses = NULL;
oclasses = ldap_get_values_len(priv2ld(ipasam_state), entry,
LDAP_ATTRIBUTE_OBJECTCLASS);
int c = 0;
if (oclasses == NULL) {
DEBUG(1, ("Cannot find any objectclasses.\n"));
goto fn_exit;
}
for (c = 0; oclasses[c] != NULL; c++) {
if (strncasecmp(LDAP_OBJ_TRUSTED_DOMAIN, oclasses[c]->bv_val,
oclasses[c]->bv_len) == 0) {
break;
}
}
if (oclasses[c] != NULL) {
trusted_domain = true;
}
ldap_value_free_len(oclasses);
}
nt_username = talloc_strdup(tmp_ctx, username);
if (!nt_username) {
goto fn_exit;
@@ -3712,41 +3737,93 @@ static bool init_sam_from_ldap(struct ipasam_private *ipasam_state,
}
/* Force machine accounts to be workstation trust type */
pdb_set_acct_ctrl(sampass, machine_account ? ACB_WSTRUST : ACB_NORMAL,
PDB_SET);
/* set correct account type */
acct_flags = trusted_domain ? ACB_DOMTRUST :
(machine_account ? ACB_WSTRUST : ACB_NORMAL);
pdb_set_acct_ctrl(sampass, acct_flags, PDB_SET);
retval = smbldap_talloc_single_blob(tmp_ctx,
priv2ld(ipasam_state),
entry, LDAP_ATTRIBUTE_NTHASH,
&nthash);
if (!retval) {
/* NT Hash is not in place. Attempt to retrieve it from
* the RC4-HMAC key if that exists in Kerberos credentials.
* IPA 389-ds plugin allows to ask for it by setting
* ipaNTHash to MagicRegen value.
* */
temp = smbldap_talloc_dn(tmp_ctx, priv2ld(ipasam_state), entry);
if (temp) {
retval = ipasam_nthash_regen(ipasam_state,
tmp_ctx, temp);
if (retval) {
retval = ipasam_nthash_retrieve(ipasam_state,
tmp_ctx, temp, &nthash);
if (trusted_domain) {
DATA_BLOB trust_auth_incoming = {0};
char *pass = NULL;
NTSTATUS xstatus;
retval = false;
if (smbldap_talloc_single_blob(tmp_ctx,
priv2ld(ipasam_state), entry,
LDAP_ATTRIBUTE_TRUST_AUTH_INCOMING,
&trust_auth_incoming)) {
xstatus = get_trust_pwd(tmp_ctx, &trust_auth_incoming,
&pass, NULL);
if (NT_STATUS_IS_OK(xstatus)) {
uint8_t key[NT_HASH_LEN];
volatile char *p = (void *) pass;
size_t plen = strlen(pass);
if (E_md4hash(pass, key)) {
volatile char *q = (void *) key;
size_t qlen = NT_HASH_LEN;
nthash.data = talloc_memdup(tmp_ctx, key, NT_HASH_LEN);
nthash.length = NT_HASH_LEN;
retval = nthash.data != NULL;
while (qlen--) {
*q++ = '\0';
}
}
while (plen--) {
*p++ = '\0';
}
}
} else {
DEBUG(9, ("Failed to get incoming auth info.\n"));
}
} else {
retval = smbldap_talloc_single_blob(tmp_ctx,
priv2ld(ipasam_state),
entry, LDAP_ATTRIBUTE_NTHASH,
&nthash);
if (!retval) {
/* NT Hash is not in place. Attempt to retrieve it from
* the RC4-HMAC key if that exists in Kerberos credentials.
* IPA 389-ds plugin allows to ask for it by setting
* ipaNTHash to MagicRegen value.
* */
temp = smbldap_talloc_dn(tmp_ctx, priv2ld(ipasam_state), entry);
if (temp) {
retval = ipasam_nthash_regen(ipasam_state,
tmp_ctx, temp);
if (retval) {
retval = ipasam_nthash_retrieve(ipasam_state,
tmp_ctx, temp, &nthash);
}
}
}
}
if (!retval) {
DEBUG(5, ("Failed to read NT hash form LDAP response.\n"));
}
if (retval) {
if (nthash.length != NT_HASH_LEN && nthash.length != 0) {
DEBUG(5, ("NT hash from LDAP has the wrong size. "
"Perhaps password was not re-set?\n"));
} else {
volatile char *q = (void *) nthash.data;
size_t qlen = nthash.length;
if (nthash.length != NT_HASH_LEN && nthash.length != 0) {
DEBUG(5, ("NT hash from LDAP has the wrong size. Perhaps password was not re-set?\n"));
} else {
if (!pdb_set_nt_passwd(sampass, nthash.data, PDB_SET)) {
DEBUG(5, ("Failed to set NT hash.\n"));
if (!pdb_set_nt_passwd(sampass, nthash.data, PDB_SET)) {
DEBUG(5, ("Failed to set NT hash.\n"));
}
if (q != NULL) {
/* nthash.length might be 0 on this path,
* we want to skip in this case */
while (nthash.length && qlen--) {
*q++ = '\0';
}
}
}
} else {
DEBUG(5, ("Failed to read NT hash form LDAP response.\n"));
}
/* FIXME: */
if (!pdb_set_pass_last_set_time(sampass, (time_t) 1, PDB_SET)) {
+1
View File
@@ -5,6 +5,7 @@ SUBDIRS = \
ipa-cldap \
ipa-dns \
ipa-enrollment \
ipa-graceperiod \
ipa-lockout \
ipa-modrdn \
ipa-otp-counter \
@@ -287,6 +287,7 @@ done:
ipa_cldap_respond(ctx, req, &reply);
ipa_cldap_free_kvps(&req->kvps);
free(reply.bv_val);
free(req);
return;
}
@@ -49,6 +49,14 @@
#include "back_extdom.h"
#include "util.h"
#if defined HAVE_DECL_SSS_NSS_GETORIGBYUSERNAME_TIMEOUT && !HAVE_DECL_SSS_NSS_GETORIGBYUSERNAME_TIMEOUT
#define sss_nss_getorigbyusername_timeout sss_nss_getorigbyname_timeout
#endif
#if defined HAVE_DECL_SSS_NSS_GETORIGBYGROUPNAME_TIMEOUT && !HAVE_DECL_SSS_NSS_GETORIGBYGROUPNAME_TIMEOUT
#define sss_nss_getorigbygroupname_timeout sss_nss_getorigbyname_timeout
#endif
#define SSSD_DOMAIN_SEPARATOR '@'
int get_buffer(size_t *_buf_len, char **_buf)
@@ -886,8 +894,8 @@ static int handle_uid_request(struct ipa_extdom_ctx *ctx,
}
if (request_type == REQ_FULL_WITH_GROUPS) {
ret = sss_nss_getorigbyname_timeout(pwd.pw_name, get_timeout(ctx),
&kv_list, &id_type);
ret = sss_nss_getorigbyusername_timeout(pwd.pw_name, get_timeout(ctx),
&kv_list, &id_type);
if (ret != 0 || !(id_type == SSS_ID_TYPE_UID
|| id_type == SSS_ID_TYPE_BOTH)) {
set_err_msg(req, "Failed to read original data");
@@ -965,8 +973,8 @@ static int handle_gid_request(struct ipa_extdom_ctx *ctx,
}
if (request_type == REQ_FULL_WITH_GROUPS) {
ret = sss_nss_getorigbyname_timeout(grp.gr_name, get_timeout(ctx),
&kv_list, &id_type);
ret = sss_nss_getorigbygroupname_timeout(grp.gr_name, get_timeout(ctx),
&kv_list, &id_type);
if (ret != 0 || !(id_type == SSS_ID_TYPE_GID
|| id_type == SSS_ID_TYPE_BOTH)) {
set_err_msg(req, "Failed to read original data");
@@ -1115,8 +1123,8 @@ static int handle_sid_request(struct ipa_extdom_ctx *ctx,
}
if (request_type == REQ_FULL_WITH_GROUPS) {
ret = sss_nss_getorigbyname_timeout(pwd.pw_name, get_timeout(ctx),
&kv_list, &id_type);
ret = sss_nss_getorigbyusername_timeout(pwd.pw_name, get_timeout(ctx),
&kv_list, &id_type);
if (ret != 0 || !(id_type == SSS_ID_TYPE_UID
|| id_type == SSS_ID_TYPE_BOTH)) {
set_err_msg(req, "Failed to read original data");
@@ -1152,8 +1160,8 @@ static int handle_sid_request(struct ipa_extdom_ctx *ctx,
}
if (request_type == REQ_FULL_WITH_GROUPS) {
ret = sss_nss_getorigbyname_timeout(grp.gr_name, get_timeout(ctx),
&kv_list, &id_type);
ret = sss_nss_getorigbygroupname_timeout(grp.gr_name, get_timeout(ctx),
&kv_list, &id_type);
if (ret != 0 || !(id_type == SSS_ID_TYPE_GID
|| id_type == SSS_ID_TYPE_BOTH)) {
set_err_msg(req, "Failed to read original data");
@@ -1266,9 +1274,9 @@ static int handle_username_request(struct ipa_extdom_ctx *ctx,
switch(ret) {
case 0:
if (request_type == REQ_FULL_WITH_GROUPS) {
ret = sss_nss_getorigbyname_timeout(pwd.pw_name,
get_timeout(ctx),
&kv_list, &id_type);
ret = sss_nss_getorigbyusername_timeout(pwd.pw_name,
get_timeout(ctx),
&kv_list, &id_type);
if (ret != 0 || !(id_type == SSS_ID_TYPE_UID
|| id_type == SSS_ID_TYPE_BOTH)) {
set_err_msg(req, "Failed to read original data");
@@ -1357,8 +1365,8 @@ static int handle_groupname_request(struct ipa_extdom_ctx *ctx,
}
if (request_type == REQ_FULL_WITH_GROUPS) {
ret = sss_nss_getorigbyname_timeout(grp.gr_name, get_timeout(ctx),
&kv_list, &id_type);
ret = sss_nss_getorigbygroupname_timeout(grp.gr_name, get_timeout(ctx),
&kv_list, &id_type);
if (ret != 0 || !(id_type == SSS_ID_TYPE_GID
|| id_type == SSS_ID_TYPE_BOTH)) {
if (ret == ENOENT) {
@@ -0,0 +1,42 @@
NULL =
PLUGIN_COMMON_DIR = $(srcdir)/../common
AM_CPPFLAGS = \
-I$(srcdir) \
-I$(PLUGIN_COMMON_DIR) \
-DPREFIX=\""$(prefix)"\" \
-DBINDIR=\""$(bindir)"\" \
-DLIBDIR=\""$(libdir)"\" \
-DLIBEXECDIR=\""$(libexecdir)"\" \
-DDATADIR=\""$(datadir)"\" \
-I$(top_srcdir)/util \
$(DIRSRV_CFLAGS) \
$(LDAP_CFLAGS) \
$(WARN_CFLAGS) \
$(NULL)
plugindir = $(libdir)/dirsrv/plugins
plugin_LTLIBRARIES = \
libipa_graceperiod.la \
$(NULL)
libipa_graceperiod_la_SOURCES = \
ipa_graceperiod.c \
$(NULL)
libipa_graceperiod_la_LDFLAGS = -avoid-version
libipa_graceperiod_la_LIBADD = \
$(LDAP_LIBS) \
$(top_builddir)/util/libutil.la \
$(NULL)
appdir = $(IPA_DATA_DIR)
app_DATA = \
graceperiod-conf.ldif \
$(NULL)
EXTRA_DIST = \
$(app_DATA) \
$(NULL)
@@ -0,0 +1,15 @@
dn: cn=IPA Graceperiod,cn=plugins,cn=config
changetype: add
objectclass: top
objectclass: nsSlapdPlugin
objectclass: extensibleObject
cn: IPA Graceperiod
nsslapd-pluginpath: libipa_graceperiod
nsslapd-plugininitfunc: ipagraceperiod_init
nsslapd-plugintype: object
nsslapd-pluginenabled: on
nsslapd-pluginid: ipagraceperiod_version
nsslapd-pluginversion: 1.0
nsslapd-pluginvendor: Red Hat, Inc.
nsslapd-plugindescription: IPA Graceperiod plugin
nsslapd-plugin-depends-on-type: database
@@ -0,0 +1,513 @@
/** BEGIN COPYRIGHT BLOCK
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional permission under GPLv3 section 7:
*
* In the following paragraph, "GPL" means the GNU General Public
* License, version 3 or any later version, and "Non-GPL Code" means
* code that is governed neither by the GPL nor a license
* compatible with the GPL.
*
* You may link the code of this Program with Non-GPL Code and convey
* linked combinations including the two, provided that such Non-GPL
* Code only links to the code of this Program through those well
* defined interfaces identified in the file named EXCEPTION found in
* the source code files (the "Approved Interfaces"). The files of
* Non-GPL Code may instantiate templates or use macros or inline
* functions from the Approved Interfaces without causing the resulting
* work to be covered by the GPL. Only the copyright holders of this
* Program may make changes or additions to the list of Approved
* Interfaces.
*
* Copyright (C) 2022 Red Hat, Inc.
* All rights reserved.
* END COPYRIGHT BLOCK **/
/**
* IPA Graceperiod plug-in
*
* Limit LDAP operations to password changes while in the grace period.
*
*/
#ifndef _GNU_SOURCE
#define _GNU_SOURCE 1
#endif
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <time.h>
#include "slapi-plugin.h"
#include "nspr.h"
#include <krb5.h>
#include "util.h"
#include "ipa_pwd.h"
#define IPAGRACEPERIOD_PLUGIN_NAME "ipa-graceperiod-plugin"
#define IPAGRACEPERIOD_PLUGIN_VERSION 0x00010000
#define IPA_PLUGIN_NAME IPAGRACEPERIOD_PLUGIN_NAME
#define IPAGRACEPERIOD_FEATURE_DESC "IPA Graceperiod"
#define IPAGRACEPERIOD_PLUGIN_DESC "IPA Graceperiod plugin"
#define IPAGRACEPERIOD_PREOP_DESC "IPA Graceperiod preop plugin"
static Slapi_PluginDesc pdesc = {
IPAGRACEPERIOD_FEATURE_DESC,
"Red Hat, Inc.",
"1.0",
IPAGRACEPERIOD_PLUGIN_DESC
};
struct ipa_context {
bool disable_last_success;
bool disable_lockout;
};
static void *_PluginID = NULL;
static int g_plugin_started = 0;
#if 0
static struct ipa_context *global_ipactx = NULL;
#endif
static char *ipa_global_policy = NULL;
int ipagraceperiod_getpolicy(Slapi_Entry *target_entry, Slapi_Entry **policy_entry,
Slapi_ValueSet** values, char **actual_type_name,
const char **policy_dn, int *attr_free_flags,
char **errstr);
int ipagraceperiod_version(void);
static void *getPluginID(void);
static void setPluginID(void *pluginID);
#define GENERALIZED_TIME_LENGTH 15
/**
*
* management functions
*
*/
int ipagraceperiod_init(Slapi_PBlock * pb);
static int ipagraceperiod_start(Slapi_PBlock * pb);
static int ipagraceperiod_close(Slapi_PBlock * pb);
static int ipagraceperiod_preop_init(Slapi_PBlock * pb);
static int ipagraceperiod_get_global_config(void);
/**
*
* the ops (where the real work is done)
*
*/
static int ipagraceperiod_preop(Slapi_PBlock *pb);
/**
*
* Get the plug-in version
*
*/
int ipagraceperiod_version(void)
{
return IPAGRACEPERIOD_PLUGIN_VERSION;
}
/**
* Plugin identity mgmt
*/
static void setPluginID(void *pluginID)
{
_PluginID = pluginID;
}
static void *getPluginID(void)
{
return _PluginID;
}
static int
ipagraceperiod_get_global_config(void)
{
char *dn = NULL;
char *basedn = NULL;
char *realm = NULL;
Slapi_DN *sdn;
Slapi_Entry *config_entry = NULL;
krb5_context krbctx = NULL;
krb5_error_code krberr;
int ret;
/* Get cn=config so we can get the default naming context */
sdn = slapi_sdn_new_dn_byref("cn=config");
ret = slapi_search_internal_get_entry(sdn, NULL, &config_entry,
getPluginID());
slapi_sdn_free(&sdn);
if (ret) {
goto done;
}
basedn = slapi_entry_attr_get_charptr(config_entry,
"nsslapd-defaultnamingcontext");
slapi_entry_free(config_entry);
config_entry = NULL;
if (!basedn) {
goto done;
}
krberr = krb5_init_context(&krbctx);
if (krberr) {
LOG_FATAL("krb5_init_context failed (%d)\n", krberr);
/* Yes, we failed, but it is because /etc/krb5.conf doesn't exist
* or is misconfigured. Start up in a degraded mode.
*/
} else {
krberr = krb5_get_default_realm(krbctx, &realm);
if (krberr) {
LOG_FATAL("Failed to get default realm (%d)\n", krberr);
} else {
ipa_global_policy =
slapi_ch_smprintf("cn=global_policy,cn=%s,cn=kerberos,%s",
realm, basedn);
if (!ipa_global_policy) {
LOG_OOM();
ret = LDAP_OPERATIONS_ERROR;
goto done;
}
}
}
ret = 0;
done:
if (config_entry)
slapi_entry_free(config_entry);
free(realm);
krb5_free_context(krbctx);
free(dn);
free(basedn);
return ret;
}
int ipagraceperiod_getpolicy(Slapi_Entry *target_entry, Slapi_Entry **policy_entry,
Slapi_ValueSet** values, char **actual_type_name,
const char **policy_dn, int *attr_free_flags,
char **errstr)
{
int ldrc = 0;
int type_name_disposition = 0;
Slapi_DN *pdn = NULL;
/* Only continue if there is a password policy */
ldrc = slapi_vattr_values_get(target_entry, "krbPwdPolicyReference",
values,
&type_name_disposition, actual_type_name,
SLAPI_VIRTUALATTRS_REQUEST_POINTERS,
attr_free_flags);
if (ldrc == 0) {
Slapi_Value *sv = NULL;
if (values != NULL) {
slapi_valueset_first_value(*values, &sv);
*policy_dn = slapi_value_get_string(sv);
}
} else {
*policy_dn = ipa_global_policy;
}
if (*policy_dn == NULL) {
LOG_TRACE("No kerberos password policy\n");
return LDAP_SUCCESS;
} else {
pdn = slapi_sdn_new_dn_byref(*policy_dn);
ldrc = slapi_search_internal_get_entry(pdn, NULL, policy_entry,
getPluginID());
slapi_sdn_free(&pdn);
if (ldrc != LDAP_SUCCESS) {
LOG_FATAL("Failed to retrieve entry \"%s\": %d\n", *policy_dn, ldrc);
*errstr = "Failed to retrieve account policy.";
return LDAP_OPERATIONS_ERROR;
}
}
return LDAP_SUCCESS;
}
int
ipagraceperiod_init(Slapi_PBlock *pb)
{
int status = EOK;
char *plugin_identity = NULL;
LOG_TRACE("--in-->\n");
slapi_pblock_get(pb, SLAPI_PLUGIN_IDENTITY, &plugin_identity);
PR_ASSERT(plugin_identity);
setPluginID(plugin_identity);
if (slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION,
SLAPI_PLUGIN_VERSION_01) != 0 ||
slapi_pblock_set(pb, SLAPI_PLUGIN_START_FN,
(void *) ipagraceperiod_start) != 0 ||
slapi_pblock_set(pb, SLAPI_PLUGIN_CLOSE_FN,
(void *) ipagraceperiod_close) != 0 ||
slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION,
(void *) &pdesc) != 0 ||
slapi_register_plugin("preoperation",
1,
"ipagraceperiod_init",
ipagraceperiod_preop_init,
IPAGRACEPERIOD_PREOP_DESC,
NULL,
plugin_identity
)
) {
LOG_FATAL("failed to register plugin\n");
status = EFAIL;
}
LOG_TRACE("<--out--\n");
return status;
}
static int
ipagraceperiod_preop_init(Slapi_PBlock *pb)
{
int status = EOK;
if (slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION,
SLAPI_PLUGIN_VERSION_01) != 0 ||
slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION,
(void *) &pdesc) != 0 ||
slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_BIND_FN,
(void *) ipagraceperiod_preop) != 0) {
status = EFAIL;
}
return status;
}
static int
ipagraceperiod_start(Slapi_PBlock * pb)
{
LOG_TRACE("--in-->\n");
/* Check if we're already started */
if (g_plugin_started) {
goto done;
}
g_plugin_started = 1;
ipagraceperiod_get_global_config();
LOG("ready for service\n");
done:
LOG_TRACE("<--out--\n");
return EOK;
}
static int
ipagraceperiod_close(Slapi_PBlock * pb)
{
LOG_TRACE( "--in-->\n");
slapi_ch_free_string(&ipa_global_policy);
LOG_TRACE("<--out--\n");
return EOK;
}
/*
* In the pre-op stage the bind hasn't occurred yet. It is here that
* we do the lockout enforcement.
*/
static int ipagraceperiod_preop(Slapi_PBlock *pb)
{
char *dn = NULL;
const char *policy_dn = NULL;
Slapi_Entry *target_entry = NULL;
Slapi_Entry *policy_entry = NULL;
Slapi_Value *objectclass = NULL;
Slapi_DN *sdn = NULL;
char *errstr = NULL;
int ldrc = 0;
int rc = 0;
int ret = LDAP_SUCCESS;
char *actual_type_name = NULL;
int attr_free_flags = 0;
Slapi_ValueSet *values = NULL;
long grace_limit = 0;
int grace_user_time;
char *tmpstr = NULL;
time_t pwd_expiration;
int pwresponse_requested = 0;
Slapi_PBlock *pbtm = NULL;
Slapi_Mods *smods = NULL;
LOG_TRACE("--in-->\n");
/* Just bail if we aren't ready to service requests yet. */
if (!g_plugin_started) {
goto done;
}
if (slapi_pblock_get(pb, SLAPI_BIND_TARGET, &dn) != 0) {
LOG_FATAL("Error retrieving target DN\n");
ret = LDAP_OPERATIONS_ERROR;
goto done;
}
/* Client is anonymously bound */
if (dn == NULL) {
LOG_TRACE("anonymous bind\n");
goto done;
}
/* Get the entry */
sdn = slapi_sdn_new_dn_byref(dn);
if (sdn == NULL) {
LOG_OOM();
errstr = "Out of memory.\n";
ret = LDAP_OPERATIONS_ERROR;
goto done;
}
ldrc = slapi_search_internal_get_entry(sdn, NULL, &target_entry,
getPluginID());
if (ldrc != LDAP_SUCCESS) {
LOG_TRACE("Failed to retrieve entry \"%s\": %d\n", dn, ldrc);
goto done;
}
/* Only deal with users and sysaccount entries */
objectclass = slapi_value_new_string("posixAccount");
if ((slapi_entry_attr_has_syntax_value(target_entry, SLAPI_ATTR_OBJECTCLASS, objectclass)) != 1) {
LOG_TRACE("Not a posix user\n");
slapi_value_free(&objectclass);
objectclass = slapi_value_new_string("simplesecurityobject");
if ((slapi_entry_attr_has_syntax_value(target_entry, SLAPI_ATTR_OBJECTCLASS, objectclass)) != 1) {
LOG_TRACE("Not a sysaccount user\n");
slapi_value_free(&objectclass);
goto done;
}
}
slapi_value_free(&objectclass);
tmpstr = slapi_entry_attr_get_charptr(target_entry, "krbPasswordExpiration");
if (tmpstr == NULL) {
/* No expiration means nothing to do */
LOG_TRACE("No krbPasswordExpiration for %s, nothing to do\n", dn);
goto done;
}
pwd_expiration = ipapwd_gentime_to_time_t(tmpstr);
if (pwd_expiration > time(NULL)) {
/* Not expired, nothing to see here */
goto done;
}
ldrc = ipagraceperiod_getpolicy(target_entry, &policy_entry,
&values, &actual_type_name,
&policy_dn, &attr_free_flags,
&errstr);
if (ldrc != LDAP_SUCCESS || policy_dn == NULL) {
goto done;
}
slapi_pblock_get(pb, SLAPI_PWPOLICY, &pwresponse_requested);
/* This returns 0 if the attribute doesn't exist, so no grace but
* report that logins are not allowed.
*/
grace_limit = slapi_entry_attr_get_int(policy_entry, "passwordGraceLimit");
/* -1 means disable grace limit */
if (grace_limit == -1) {
LOG_TRACE("grace limit disabled, skipping\n");
goto done;
} else if (grace_limit < -1) {
LOG_FATAL("Invalid passwordGraceLimit value %d\n", grace_limit);
return LDAP_OPERATIONS_ERROR;
}
grace_user_time = slapi_entry_attr_get_int(target_entry, "passwordGraceUserTime");
if ((grace_limit > 0) && (grace_user_time < grace_limit)) {
char graceUserTime[16] = {0};
grace_user_time++;
sprintf(graceUserTime, "%d", grace_user_time);
smods = slapi_mods_new();
slapi_mods_add_string(smods, LDAP_MOD_REPLACE,
"passwordGraceUserTime", graceUserTime);
pbtm = slapi_pblock_new();
slapi_modify_internal_set_pb(pbtm,
slapi_entry_get_dn_const(target_entry),
slapi_mods_get_ldapmods_byref(smods),
NULL, NULL, getPluginID(), 0);
slapi_modify_internal_pb(pbtm);
slapi_pblock_get(pbtm, SLAPI_PLUGIN_INTOP_RESULT, &rc);
if (rc != LDAP_SUCCESS) {
LOG_TRACE("WARNING: modify error %d on entry '%s'\n",
rc, slapi_entry_get_dn_const(target_entry));
}
if (pwresponse_requested) {
slapi_pwpolicy_make_response_control(pb, -1, grace_limit - grace_user_time , -1);
}
} else if (grace_user_time >= grace_limit) {
LOG_TRACE("%s password is expired and out of grace limit\n", dn);
errstr = "Password is expired.\n";
ret = LDAP_INVALID_CREDENTIALS;
if (pwresponse_requested) {
slapi_pwpolicy_make_response_control(pb, -1, 0, LDAP_PWPOLICY_PWDEXPIRED);
}
goto done;
}
slapi_add_pwd_control(pb, LDAP_CONTROL_PWEXPIRED, 0);
done:
slapi_pblock_destroy(pbtm);
slapi_mods_free(&smods);
slapi_entry_free(target_entry);
slapi_entry_free(policy_entry);
if (values != NULL) {
slapi_vattr_values_free(&values, &actual_type_name, attr_free_flags);
}
if (sdn) slapi_sdn_free(&sdn);
LOG("preop returning %d: %s\n", ret, errstr ? errstr : "success\n");
if (ret) {
slapi_send_ldap_result(pb, ret, NULL, errstr, 0, NULL);
}
LOG_TRACE("<--out--\n");
return (ret == 0 ? EOK : EFAIL);
}
@@ -96,6 +96,14 @@ void *ipapwd_get_plugin_id(void)
return ipapwd_plugin_id;
}
static bool is_nthash_allowed(const char *service_name, const char *bind_dn)
{
#define CIFS_PRINCIPAL_PREFIX "krbprincipalname=cifs/"
return (0 == strncmp("cifs/", service_name, 5)) ||
(0 == strncmp(CIFS_PRINCIPAL_PREFIX, bind_dn,
sizeof(CIFS_PRINCIPAL_PREFIX) - 1));
}
static void filter_keys(struct ipapwd_krbcfg *krbcfg,
struct ipapwd_keyset *kset,
bool allow_nthash)
@@ -1228,7 +1236,7 @@ static int ipapwd_setkeytab(Slapi_PBlock *pb, struct ipapwd_krbcfg *krbcfg)
int kvno;
char *svcname;
bool allowed_access = false;
bool is_nthash_allowed = false;
bool nthash_allowed = false;
struct berval *bvp = NULL;
LDAPControl new_ctrl;
@@ -1305,8 +1313,8 @@ static int ipapwd_setkeytab(Slapi_PBlock *pb, struct ipapwd_krbcfg *krbcfg)
/* Only allow generating arcfour-hmac keys for cifs/.. services
* unless the enctype is allowed by the IPA configuration for use
* by the all principals */
is_nthash_allowed = (0 == strncmp("cifs/", serviceName, 5));
filter_keys(krbcfg, kset, is_nthash_allowed);
nthash_allowed = is_nthash_allowed(serviceName, bindDN);
filter_keys(krbcfg, kset, nthash_allowed);
/* check if we have any left */
if (kset->num_keys == 0) {
@@ -1615,7 +1623,7 @@ static int ipapwd_getkeytab(Slapi_PBlock *pb, struct ipapwd_krbcfg *krbcfg)
struct berval *bvp = NULL;
LDAPControl new_ctrl;
bool wantold = false;
bool is_nthash_allowed = false;
bool nthash_allowed = false;
/* Get Bind DN */
slapi_pblock_get(pb, SLAPI_CONN_DN, &bind_dn);
@@ -1712,8 +1720,8 @@ static int ipapwd_getkeytab(Slapi_PBlock *pb, struct ipapwd_krbcfg *krbcfg)
/* Only allow generating arcfour-hmac keys for cifs/.. services
* unless the enctype is allowed by the IPA configuration for use
* by the all principals */
is_nthash_allowed = (0 == strncmp("cifs/", service_name, 5));
filter_enctypes(krbcfg, kenctypes, &num_kenctypes, is_nthash_allowed);
nthash_allowed = is_nthash_allowed(service_name, bind_dn);
filter_enctypes(krbcfg, kenctypes, &num_kenctypes, nthash_allowed);
/* check if we have any left */
if (num_kenctypes == 0 && kenctypes != NULL) {
@@ -1071,6 +1071,7 @@ static int ipapwd_post_modadd(Slapi_PBlock *pb)
struct ipapwd_krbcfg *krbcfg = NULL;
char *principal = NULL;
Slapi_Value *ipahost;
Slapi_Value *zero;
LOG_TRACE("=>\n");
@@ -1167,6 +1168,13 @@ static int ipapwd_post_modadd(Slapi_PBlock *pb)
}
slapi_value_free(&ipahost);
}
zero = slapi_value_new_string("0");
if (!slapi_entry_attr_has_syntax_value(pwdop->pwdata.target,
"passwordgraceusertime", zero)) {
/* Clear the passwordgraceusertime from the user entry */
slapi_mods_add_string(smods, LDAP_MOD_REPLACE, "passwordgraceusertime", "0");
}
slapi_value_free(&zero);
ret = ipapwd_apply_mods(pwdop->pwdata.dn, smods);
if (ret)
+2 -7
View File
@@ -23,12 +23,6 @@ help:
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.PHONY: workshop-remote workshop-pull
workshop-remote:
git remote add -f freeipa-workshop https://github.com/freeipa/freeipa-workshop.git
workshop-pull:
git pull -s subtree freeipa-workshop master
.PHONY: lint
lint:
$(MAKE) html SPHINXOPTS="$(SPHINXOPTS) -E -a"
@@ -41,4 +35,5 @@ distclean: clean
venv:
$(PYTHON) -m venv $(VENVDIR)
$(VENVDIR)/bin/python3 -m pip install -U pip setuptools
$(VENVDIR)/bin/python3 -m pip install -U -r ./requirements.txt
$(VENVDIR)/bin/python3 -m pip install -U -r ./requirements.txt \
-c constraints.txt
+4
View File
@@ -0,0 +1,4 @@
section ul.simple li {
list-style: disc;
margin-left: 1em;
}
+7 -2
View File
@@ -40,7 +40,8 @@ extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.intersphinx',
'sphinx.ext.viewcode',
'm2r',
'sphinxcontrib.plantuml',
'm2r2',
]
# Add any paths that contain templates here, relative to this directory.
@@ -71,7 +72,11 @@ html_theme = 'default'
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
# html_static_path = ['_static']
html_static_path = ['_static']
html_css_files = [
'css/ipa.css',
]
# -- Options for sources -----------------------------------------------------
+1
View File
@@ -0,0 +1 @@
docutils < 0.19
+499
View File
@@ -0,0 +1,499 @@
# FreeIPA and an external identity provider integration
FreeIPA provides an integrated identity management solution for POSIX-alike
environments. Its implementation has been based on a number of assumptions about
the usage and the representation of users and groups in a generalized POSIX
environment. Users and groups consumed by the applications running in POSIX
environment in several common ways:
- application processes run under some user identity;
- application processes create or access files attributed to specific users and
groups;
- a set of groups a user belongs to is fixed at the login time and does not
change until that login session is completed;
- an authentication flow of a user is directly tied with the login session that
is instantiated as a result of authentication.
Consumption patterns described above equate presence of POSIX user and group IDs
with ability to run application processes under these identities. Interfacing
with the applications was typically done inside shell sessions initiated by the
users represented by the POSIX identities. With the move to web- and
mobile-oriented user interfaces, the POSIX user consumption patterns have become
less prominent. Applications consumed through interfaces that aren't expressed
through POSIX environments as in the past. POSIX identities, instead, relegated
to be a support mechanism for running isolated applications. This is especially
visible in Android application model or containerized environments.
Application-level identities are not necessarily the same as the system level
users anymore.
Usage shift does not, however, dictate an exclusion between the two models in
enterprise environments. The same users need to access both operating
system-level applications and be able to authenticate as application-level
identities. This is typically achieved by forming a single sign-on environment
where a user would be authenticated directly once and then the fact of
authentication is consumed by other services for a certain amount of time,
regardless of how the applications that represent these services are operating.
In this document discussion of 'application-level identities' really means
resource owner identities visible through OAuth 2.0 Authorization Framework.
This level of abstraction allows discussion of authentication and access to
resources regardless of internal details of a specific application.
There are two major use cases to be considered:
- FreeIPA serves as a backend to provide identities to an identity provider
(IdP) to authenticate and authorize access to OAuth 2.0 clients. This IdP
would be called 'an integrated IdP' to FreeIPA. A subset of user properties
would be stored in IdP itself, another part retained in FreeIPA.
- FreeIPA communicates with an external IdP to perform identity verification and
ask for an access grant to itself. Authentication and authorization of the
identity is delegated to the external IdP and the user information in FreeIPA
is used as an anchor to map external IdP identity to a system-level user
identity.
The scope of this document is to address the second use case.
## Use of an external IdP to verify external identities for FreeIPA
OAuth 2.0 authorization framework concerns access control to resource owner
identities from OAuth clients. OAuth 2.0 authorization server arbitrates the
access by the OAuth clients. It also authenticates the resource owner identity
when OAuth client redirects a user (often a web browser) to the Authorization
Server to request the access grant.
In this document we would not look into details how OAuth 2.0 Authorization
Server would authenticate the resource owner identity. We assume this part is
implemented by the IdP.
In POSIX-like system environment access to resources often combines both
authentication and authorization steps. Two most common examples would be access
over a secure shell protocol variant and local system privilege escalation with
PAM interface. SSH protocol implementation often combines these two, allowing to
either authenticate with native SSH methods, with SSH key-pairs, GSSAPI
authentication, or delegate authentication to PAM (`keyboard-interactive`
method). Access control is then can be offloaded to PAM as well.
Locally, granting access to other resources often involves PAM stack processing
as well. `sudo` performs PAM authentication and authorization prior to applying
own access rules, for example.
FreeIPA already implements authorization part through PAM stack with the help of
SSSD suite. `pam_sss` PAM module allows using HBAC rules to grant access which
otherwise is denied. It also implements authentication pass-through mechanism,
allowing SSSD to handle a variety of authentication methods: LDAP binds,
Kerberos, etc.
When SSSD on FreeIPA-enrolled client needs to authenticate a user, it performs
mutual authentication with FreeIPA KDC. Mutual authentication relies on the fact
that each FreeIPA client is registered with the KDC in FreeIPA domain. In order
to request an access grant to a resource owner identity with an OAuth 2.0
authorization flow to FreeIPA-enrolled clients, this particular client has to be
registered as an OAuth client against an IdP that knows about the user. This is
impractical for FreeIPA deployments. What happens in many OAuth2 environments is
that instead of registering every single application system to the user's IdP, a
single client identity representing the whole 'application environment' is
registered. Once a user did log in into an application environment, an
application environment-specific access token is issued and used by the
application backend to access other resources in its own domain. In a sense,
this is similar to Kerberos protocol authentication process to obtain a ticket
granting ticket (TGT) and later request individual service tickets based on a
TGT.
To reduce authorization complexity we can view the whole FreeIPA deployment as a
single OAuth 2.0 client registered with an integrated IdP. The integrated IdP
would then handle authentication of the user identity and authorize access to
it. If that process would require, in turn, access to a federated identity
provider, the latter would not need to be known to FreeIPA OAuth 2.0 client.
Use of a single OAuth 2.0 client identity still presents an issue with multiple
FreeIPA-enrolled clients because they cannot easily share the client identity
while retaining a certain level of security.
Instead, in this design we consider IPA replicas to share OAuth 2.0 client
credentials in a way similar to how they do already share Kerberos realm master
keys: each IPA replica would be able to operate on its own using the same OAuth
2.0 client identity which is stored in a replicated IPA LDAP tree.
### OAuth 2.0 Device Authorization Grant
OAuth 2.0 Device Authorization Grant is defined in [RFC
8628](https://www.rfc-editor.org/rfc/rfc8628) and allows devices that either
lack a browser or input constrained to obtain user authorization to access
protected resources. Instead of performing the authorization flow right at the
device where OAuth authorization grant is requested, a user would perform it at
a separate device that has required rich browsing or input capabilities.
Following figure demonstrates a generic device authorization flow:
.. uml::
participant "End User at Browser"
participant "Device Client"
participant "Authorization Server"
"Device Client" -> "Authorization Server": (A) Client Identifier
"Authorization Server" -> "Device Client": (B) Device Code, User Code & Verification URI
"Device Client" -> "End User at Browser": (C) User Code & Verification URI
"End User at Browser" <-> "Authorization Server": (D) End user reviews authorization request
"Device Client" -> "Authorization Server": (E) Polling with Device Code and Client Identifier
"Authorization Server" -> "Device Client": (F) Access Token (& Optional Refresh Token)
With the help of OAuth 2.0 Device Authorization Grant, OAuth authentication
process can be integrated into Kerberos authentication protocol and would allow
to not depend on OAuth2 support in all 'traditional' applications running in
FreeIPA deployment.
Since OAuth 2.0 Device Authorization Grant is not universally supported, a
federated access can be used to organize access for users who are authenticated
against an IdP without OAuth 2.0 Device Authorization Grant support. In such
case the IdP where FreeIPA OAuth 2.0 client is registered would be called "an
integrated IdP."
The use of an integrated IdP instance allows requiring support for OAuth 2.0
Device Authorization Grant flow. Since integrated IdP would have the required
capability, it is not necessary that the same capability would be supported by
all external IdPs. It also does not require registration of the individual IPA
OAuth 2.0 clients to the external IdPs.
Setting up an integrated IdP with FreeIPA is beyond scope of this document.
### High-level authentication overview
External IdP integration with FreeIPA is designed with the following
assumptions. Identities for users authenticated through the external IdPs stored
in FreeIPA as user accounts. They have no passwords associated and instead are
forced to authenticate to external IdPs over Kerberos-based authentication flow.
The user accounts for externally-authenticated users to be created in advance;
this can be achieved manually or automatically. The way how they created is out
of scope for this document.
With the following preconditions:
- FreeIPA is registered as an OAuth 2.0 client with an external IdP
- user account is associated with the external IdP
- user account entry contains mapping to some resource owner identity in the
external IdP
- user authentication type for this user includes possibility to authenticate
against IdP
a general authentication workflow for a user registered in External IdP would
involve following steps:
- the user performs a prompt-based authentication to the IPA-enrolled system
- upon login, a prompt is shown that guides the user to use a separate device
to login to a specified URI and verify a device code shown at a prompt
- once logged into a specified URI, the user would be asked to confirm the
login intent
- An empty response is entered to the original prompt following the login and
confirmation at a specified URI
- A backend process behind the login would perform the validation of the
response
- Once the response is validated, a Kerberos ticket is issued for this login
attempt
- successful Kerberos authentication leads to an authorization step which is
performed using standard IPA facilities (HBAC rules, group membership, etc)
- if both authentication and authorization are successful, user is logged into
the system
Upon successful login, the user with External IdP identity would have an initial
Kerberos ticket granting ticket in the login session's credentials cache. This
ticket is further can be used to perform required authentication to other
IPA-provided services during its validity time.
### OpenID Connect Client-initiated backchannel authentication
An alternative to OAuth 2.0 Device Authorization Grant Flow would be to use
CIBA, OpenID Connect Client-initiated backchannel authentication flow, as
defined in
https://openid.net/specs/openid-client-initiated-backchannel-authentication-core-1_0.html.
CIBA flow is not yet supported in Keycloak. For the initial implementation of
the OAuth 2.0 authorization in FreeIPA, we would skip implementation of CIBA flow.
### OAuth 2.0 access token exchange
Another method to authorize and verify resource owner identity is to exchange
already existing OAuth 2.0 access token obtained by a different OAuth 2.0
client. This is most useful if the latter client is capable to initiate OAuth
2.0 authorization flow using a web browser.
For the initial implementation of the OAuth 2.0 authorization in FreeIPA, we
would skip this method.
### Authentication flow for OAuth2 proxying over Kerberos protocol
MIT Kerberos implements a mechanism for one-time password (OTP)
pre-authentication, as described in [RFC
6560](https://tools.ietf.org/html/rfc6560). The implementation in MIT Kerberos
allows a KDC to ask an external RADIUS server for the authentication decision
for a specific Kerberos principal. MIT Kerberos client, upon receiving a
pre-authentication mechanism response from the KDC, interacts with a user by
asking individual questions for OTP factors and further communicating back with
KDC.
FreeIPA implements a shim RADIUS proxy, called `ipa-otpd`, which listens on a
UNIX domain socket configured by default for KDC. If OTP pre-authentication
method is allowed for the requested Kerberos principal, KDC queries a RADIUS
server.
`ipa-otpd` implements two authentication flows:
- TOTP/HOTP token authentication, performed against FreeIPA LDAP server as an
LDAP BIND operation;
- proxying RADIUS request to a remote RADIUS server
In either flow, `ipa-otpd` responds to a KDC request with a RADIUS packet
constructed out of the result of authentication. KDC then performs the remaining
communication as defined in the RFC 6560.
This approach can be used to implement other authentication flows that can fit
into a RADIUS exchange with `Accept-Request` and `Accept-Response` messages. An
example of this approach is an Azure AD multi-factor authentication (MFA)
extension to Microsoft's RADIUS server, NPS. The detailed flow is described
[Azure AD Multi-factor authentication how-to
guide](https://docs.microsoft.com/en-us/azure/active-directory/authentication/howto-mfa-nps-extension).
Together with MIT Kerberos developers during a prototype investigation it was
decided to not extend existing OTP pre-authentication mechanism to add support
for external IdPs support but rather implement a separate Kerberos
pre-authentication mechanism based on similar ideas.
Original design for `idp` pre-authentication mechanism used RADIUS attribute
`State` to pass through the state of OAuth 2.0 flow. In RADIUS packets, size of
RADIUS attributes is limited up to 254 bytes. For many IdPs, the state can be
larger than 253 bytes. MIT Kerberos `krad` library supports concatenating
multiple appearances of the same attribute in the packet when retrieving the
value. `State` attribute semantics are defined in [RFC
2865](https://tools.ietf.org/html/rfc2865), where `State` attribute can only be
present at most once. Therefore, was decided to utilize `Proxy-State` attribute
instead. `Proxy-State` allows multiple appearances in a single RADIUS packet.
Additionally, a bug was found in `krad` library implementation which prevented
to use RADIUS attribute values larger than 127 bytes. As of now, the fix for MIT
Kerberos is expected to be released with MIT Kerberos 1.20. Those fixes include
commits from upstream pull requests
[krb5#1229](https://github.com/krb5/krb5/pull/1229) and
[krb5#1230](https://github.com/krb5/krb5/pull/1230). They were backported to
RHEL 8.7, RHEL 9.1, and Fedora 34-37 releases ahead of MIT Kerberos 1.20
release.
Finally, as with `otp` pre-authentication mechanism, use of `idp` method
requires a FAST channel. Any valid Kerberos ticket can be used to form the FAST
channel. SSSD would automatically use host principal's keytab to generate one.
Anonymous PKINIT can also be used. The following sequence of `kinit` commands
can be used to prepare for use of `idp` pre-authentication mechanism:
```
kinit -n -c $TMPDIR/anonymous.ccache
kinit -T $TMPDIR/anonymous.ccache idpuser
```
The new pre-authentication mechanism was released in [SSSD 2.7.0
release](https://sssd.io/release-notes/sssd-2.7.0.html).
The `idp` pre-authentication mechanism flow can be described with the following
sequence diagram:
.. uml::
:scale: 50%
participant Operator
participant "Kerberos client"
box "FreeIPA server" #LightBlue
participant "Kerberos KDC"
participant "ipa-otpd"
participant "oidc_child"
end box
box "External IdP" #LightYellow
participant "Authorization Server"
participant "Device code portal"
end box
Operator -> "Kerberos client": kinit -Tsome-ccache idp-user
"Kerberos client" -> "Kerberos KDC" : AP-REQ
"Kerberos KDC" -> "ipa-otpd": Access-Request
"ipa-otpd" -> "oidc_child": Provide Device auth state
"oidc_child" -> "Authorization Server": Initiate OAuth 2.0 Device authorization grant flow
"Authorization Server" -> "oidc_child": device_code: ..., user_code: XXXXX, verification_uri: ....
"oidc_child" -> "ipa-otpd": Device auth state: device_code: ...., user_code: XXXXX, verification_uri: ....
"ipa-otpd" -> "Kerberos KDC": Access-Challenge with idp state
"Kerberos KDC" -> "Kerberos client": idp state returned
"Kerberos client" -> Operator: Please visit https://... and enter device code XXXXX
Operator -> "Device code portal": visit https://... in browser and authorize access
"Device code portal" -> Operator: Now you can close this window and continue
"Operator" -> "Kerberos client": <ENTER>
"Kerberos client" -> "Kerberos KDC": idp state returned
"Kerberos KDC" -> "ipa-otpd": Access-Request with idp state as Proxy-State attribute
"ipa-otpd" -> "oidc_child": Request access token with idp state provided
"oidc_child" -> "Authorization Server": request access token
"Authorization Server" -> "oidc_child": access token YYYY given
"oidc_child" -> "Authorization Server": request userinfo using access token YYYY
"Authorization Server" -> "oidc_child": userinfo details
"oidc_child" -> "ipa-otpd": user information
"ipa-otpd" -> "Kerberos KDC": Access-Response or Access-Reject
"Kerberos KDC" -> "Kerberos client": AP-REP with a ticket or an error
"Kerberos client" -> Operator: kinit: success or error message
- Kerberos client advertises 'idp' pre-authentication mechanism in the initial
request to KDC
- KDC will look up Kerberos principal to initiate processing of AP-REQ request
- IPA KDB driver is expected to set JSON metadata named `idp` for the Kerberos
principal which is allowed to use IdP method
- KDC side of the 'idp' pre-authentication method will notice `idp` metadata and
will request default RADIUS end-point to authenticate the Kerberos principal.
Default RADIUS end-point on FreeIPA KDC points to `ipa-otpd` daemon over UNIX
domain socket, activated with the help of systemd.
- Upon receiving RADIUS request for Kerberos principal authentication,
`ipa-otpd` will discover that the user entry is associated with a particular
IdP.
- `ipa-otpd` will collect details for the OAuth 2.0 client associated with the
IdP and will launch a helper `oidc_child`, provided by SSSD, to communicate
with the IdP
- `oidc_child` will perform a request to initiate OAuth 2.0 Device
Authorization Grant flow against the IdP
- Device authorization end-point of the IdP will return an initial information
about the transaction state
- `oidc_child` will relay this information to `ipa-otpd`
- `ipa-otpd` will re-pack this information in a `Access-Challenge` RADIUS packet
with a number of `Proxy-State` attributes representing the transaction state
and return it to the KDC.
- KDC side of the pre-authentication method will re-pack the transaction state
into a JSON metadata to send it as a part of the KDC response to the Kerberos
client
- Kerberos client will receive a KDC response and will allow pre-authentication
methods to handle it one by one. `idp` method will be triggered because the
response contains `idp` method response.
- `idp` pre-authentication method will display the message to instruct a user to
visit an IdP-specific URL and enter provided device code. It then waits for
the user to press `<ENTER>` to continue.
- Once user completed authentication and authorization flow as defined by the
IdP, `<ENTER>` is pressed to allow Kerberos client to complete the TGT
acquisition.
- `idp` pre-authentication method sends back the same metadata it received from
the KDC side.
- Upon receiving the transaction state metadata, KDC side of the `idp`
pre-authentication method will perform another request to the default RADIUS
end-point, sending `Proxy-State` attribute with the state as a part of the
RADIUS package
- Upon receiving the transaction state, `ipa-otpd` will launch `oidc_child`
again to verify completion of the authorization step.
- `oidc_child` will perform verification of the authorization step and would
obtain an OAuth 2.0 token to access `userinfo` OAuth 2.0 end-point
- `oidc_child` will retrieve information about the resource owner identity from
the `userinfo` OAuth 2.0 end-point using scopes defined for this IdP.
- The user information is then returned to `ipa-otpd` daemon which performs
comparison of the identity subject against the one recorded in the user entry
in LDAP.
- If the comparison is successful, `Access-Response` RADIUS packet is returned,
allowing KDC to issue Kerberos ticket.
## Authentication to IPA web UI
At this point, no direct login to Web UI would be available for users
authenticated against an external IdP. They can obtain Kerberos ticket first and
then login to Web UI.
In the future, we may implement OAuth 2.0 native flow to redirect to an IdP-provided
Authorization Server and rely on OAuth 2.0 authorization flow with PKCE. There
are several unsolved issues at the moment that prevent this to be done.
### Stable callback URI
OAuth 2.0 authorization flows rely on HTTP redirects handled by the resource
owner's browser to complete the authorization. Once Authorization Server has
done its job, it would redirect the resource owner's browser to the web resource
define as a callback URI in the OAuth 2.0 client definition. This callback is
not expected to change dynamically and is set as a part of the OAuth 2.0 client
registration.
The IPA servers provide Web UI access on their own individual URIs. There is
already a precedent to provide a stable URI for ACME operations with
`ipa-ca.$DOMAIN` host. Each IPA server's HTTP certificate includes
`ipa-ca.$DOMAIN` SAN dNSName. A similar extension could be added to provide a
stable `ipa-idp.$DOMAIN` stable URI.
### OAuth 2.0 proxy app
Adding a stable `ipa-idp.$DOMAIN` stable URI would need to be complemented by a
web application that would respond at that URI. This application would
essentially need to implement a specialized OAuth 2.0 proxy flow to allow a web
application in IPA domain to initiate OAuth 2.0-based login on behalf of that
application.
Such OAuth 2.0 proxy would be hosted on IPA servers and would have access to the
definition of IdPs associated with the specific users. A user, effectively,
would be redirected to the OAuth 2.0 proxy, then redirected to their IdP for the
authorization, then logged in into the OAuth 2.0 proxy and, finally, redirected
back to the original web app.
An OAuth 2.0 proxy app would need to mutually authenticate the original web app.
If it were to use OAuth 2.0 token issued by IPA deployment itself, it would, in
fact, be an integrated IdP. It is a tempting option but it would require
additional infrastructure overhead on IPA side.
On the other hand, each host enrolled into IPA domain already has means to
authenticate any other Kerberos service with the help of Kerberos
infrastructure. Such OAuth 2.0 proxy might be able to accept HTTPS connections
authenticated by the Kerberos ticket of the requester service. Once OAuth 2.0
authorization of the resource owner (user) is done through the OAuth 2.0 proxy
app, following outcomes are possible:
- OAuth 2.0 proxy app returns a state that can describe a user from the external
IdP in IPA Kerberos point of view and the requester service then uses S4U2Self
to acquire a Kerberos ticket to itself on the resource owner's identity
behalf;
- OAuth 2.0 proxy app returns a limited access token that the requester service
then passes into `idp` pre-authentication method through AP-REQ to turn it
into a normal Kerberos ticket of the resource owner's identity.
Initial implementation does not include support for this approach.
## Individual tasks
### Manage IdP references in IPA
Implement a method to manage IdP references in IPA. It can be done similarly to
how RADIUS proxy links are managed but with more complex data structures
specific for OAuth2.
Topic commands:
```
idp-add Add new external IdP server.
idp-del Delete an external IdP server.
idp-find Search for external IdP servers.
idp-mod Modify an external IdP server.
idp-show Display information about an external IdP server.
```
For more details about IPA API and Web UI implementation please refer to
[idp-api].
### Extend supported user authentication methods in IPA
In order to recognize new authentication method to perform OAuth 2.0 Device
Authorization Grant flow, IPA needs to be extended to support the new method:
- in IPA API, to allow managing the method in `ipa user-mod --user-auth-type`
and similar commands;
- in IPA KDB driver, to recognize that the user has IdP authentication method
and trigger OTP pre-authentication response;
- in IPA KDB driver, to associate a new authentication indicator with the IdP
authentication method.
Both the authentication method and the authentication indicator are called
`idp`. This would allow to distinguish it from the regular RADIUS or OTP
authentication indicators.
### Extend `ipa-otpd` daemon to recognize IdP references
`ipa-otpd` supports two methods at the moment:
- native IPA OTP authentication
- RADIUS proxy authentication
`ipa-otpd` itself does not implement any OAuth 2.0 calls. Instead, configuration
of the OAuth 2.0 client and IdP reference passed to the `oidc_child` process
provided by SSSD in `sssd-idp` package. `oidc_child` uses `curl` and `cjose`
libraries to implement OAuth 2.0 communication.
`ipa-otpd` retrieves IdP references associated with the user being authenticated
and calls out to the `oidc_child` process to verify the user identity against an
associated IdP.
[idp-api]: idp-api.html
+403
View File
@@ -0,0 +1,403 @@
# IPA and an external identity provider integration - idp objects
IPA needs to store and manage IdP references. As a new IPA object, IdP reference needs:
* creation of an LDAP object class and LDAP attribute types used to store IdP
information
* creation of a new IPA API managing the IdP references
* definition of access control lists protecting access to the IdP references
* upgrade and backward compatibility.
## LDAP Schema
### New attribute types
The external IdP reference object needs to contain the following information:
* name (string)
* authorization endpoint (URI mapped as a case-sensitive string),
* device authorization endpoint (URI mapped as a case-sensitive string), for instance https://oauth2.googleapis.com/device/code
* token endpoint (URI mapped as a case-sensitive string), for instance https://oauth2.googleapis.com/token
* userinfo endpoint (URI mapped as a case-sensitive string)
* JWKS endpoint (URI mapped as a case-sensitive string)
* OIDC URL (URI mapped as a case-sensitive string)
* `client_id` (case-sensitive string)
* `client_secret` (optional, may be an empty string, must be protected as a password)
* scope (case sensitive string)
* user subject attribute (case-sensitive string)
Additionally, an idp object needs to be referenced from a user object, thus a link attribute has to be defined. This translates into the following attribute type definitions:
```text
attributeTypes: (2.16.840.1.113730.3.8.23.15 NAME 'ipaIdpDevAuthEndpoint' DESC 'Identity Provider Device Authorization Endpoint' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v4.9' )
attributeTypes: (2.16.840.1.113730.3.8.23.16 NAME 'ipaIdpAuthEndpoint' DESC 'Identity Provider Authorization Endpoint' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v4.9' )
attributeTypes: (2.16.840.1.113730.3.8.23.17 NAME 'ipaIdpTokenEndpoint' DESC 'Identity Provider Token Endpoint' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v4.9' )
attributeTypes: (2.16.840.1.113730.3.8.23.18 NAME 'ipaIdpClientId' DESC 'Identity Provider Client Identifier' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v4.9' )
attributeTypes: (2.16.840.1.113730.3.8.23.19 NAME 'ipaIdpClientSecret' DESC 'Identity Provider Client Secret' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 X-ORIGIN 'IPA v4.9' )
attributeTypes: (2.16.840.1.113730.3.8.23.20 NAME 'ipaIdpScope' DESC 'Identity Provider Scope' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v4.9' )
attributeTypes: (2.16.840.1.113730.3.8.23.21 NAME 'ipaIdpConfigLink' DESC 'Corresponding Identity Provider Configuration link' SUP distinguishedName EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE X-ORIGIN 'IPA v4.9')
attributeTypes: (2.16.840.1.113730.3.8.23.22 NAME 'ipaIdpSub' DESC 'Identity Provider User Subject' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v4.9' )
attributeTypes: (2.16.840.1.113730.3.8.23.23 NAME 'ipaIdpIssuerURL' DESC 'Identity Provider OIDC URL' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v4.9' )
attributeTypes: (2.16.840.1.113730.3.8.23.24 NAME 'ipaIdpUserInfoEndpoint' DESC 'Identity Provider UserInfo Endpoint' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v4.9' )
attributeTypes: (2.16.840.1.113730.3.8.23.25 NAME 'ipaIdpKeysEndpoint' DESC 'Identity Provider JWKS Endpoint' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v4.9' )
```
### New objectclasses for idp
In addition to IdP configuration object, a special object class is added to be able to store IdP configuration link in a user object:
```text
objectClasses: (2.16.840.1.113730.3.8.24.6 NAME 'ipaIdP' SUP top STRUCTURAL DESC 'Identity Provider Configuration' MUST ( cn ) MAY ( ipaIdpDevAuthEndpoint $ ipaIdpAuthEndpoint $ ipaIdpTokenEndpoint $ ipaIdpUserInfoEndpoint $ ipaIdpKeysEndpoint $ ipaIdpClientId $ description $ ipaIdpClientSecret $ ipaIdpScope $ ipaIdpIssuerURL $ ipaIdpSub ) X-ORIGIN 'IPA v4.9' )
objectClasses: (2.16.840.1.113730.3.8.24.7 NAME 'ipaIdpUser' SUP top AUXILIARY DESC 'User from an external Identity Provider ' MAY ( ipaIdpConfigLink $ ipaIdpSub ) X-ORIGIN 'IPA v4.9' )
```
In the current implementation, a user can be connected to a single IdP
reference. This is similar to RADIUS proxy references already used in IPA. For
both RADIUS and IdP cases IPA needs to know a particular user identity within
the context of the referred resource (IdP or RADIUS server). Without associated
IdP user information authentication of the IPA user will not be triggered.
### LDAP indices
Indices need to be defined for all the attributes that can be used in
`ipa idp-find` command.
- The `cn` attribute is already indexed.
- The `ipaidpdevauthendpoint`, `ipaidpauthendpoint`, `idaidptokenendpoint`, and `idpidpscope` attributes
need indices (equality and substring indices).
## IdP reference API
### Command Line Interface
```
idp-add Add new external IdP server.
idp-del Delete an external IdP server.
idp-find Search for external IdP servers.
idp-mod Modify an external IdP server.
idp-show Display information about an external IdP server.
```
Following common options defined for the external IdP server object:
| Option | Description |
|:--------------------- | :--------------------- |
| `--dev-auth-uri`=URI | Device authorization endpoint |
| `--auth-uri`=URI | General OAuth 2.0 authorization endpoint |
| `--token-uri`=URI | Token endpoint |
| `--userinfo-uri`=URI | User information endpoint |
| `--keys-uri`=URI | JWKS endpoint |
| `--issuer-url`=URI | The Identity Provider OIDC URL |
| `--client-id`=STR | The client identifier issued by the IdP during registration |
| `--secret` | The client secret, asked interactively |
| `--scope`=STR | OAuth 2.0 scopes of the access request |
| `--idp-user-id`=STR | Attribute holding user identity in User info |
`--scope` option expects space-separated list of OAuth 2.0 scopes. Since the
value includes space, it has to be enclosed in quotes:
```
ipa idp-mod foo --scope="openid email"
```
Not all common options are required at the same time in the context of different commands.
`ipa idp-add` command adds three more options:
| Option | Description |
|:--------------------- | :--------------------- |
| `--provider`=STR | One of [google, github, microsoft, okta, keycloak] |
| `--org`=STR | IdP-specific organization (tenant or realm) ID |
| `--base-url`=URI | IdP-specific base URL (e.g. `idp-host.$DOMAIN:$PORT/prefix`)|
In order to ease the creation of idp, IPA pre-populates a set of
templates for well-known IdPs so that the user does not need to provide the
individual endpoint details.
For instance, for `google` provider, adding a new IdP would look like:
```
ipa idp-add MyGoogleIdP --provider google \
--client-id nZ8JDrV8Hklf3JumewRl2ke3ovPZn5Ho \
```
This call would be equivalent to the following:
```
ipa idp-add MyGoogleIdP \
--dev-auth-uri https://oauth2.googleapis.com/device/code \
--token-uri https://oauth2.googleapis.com/token \
--client-id nZ8JDrV8Hklf3JumewRl2ke3ovPZn5Ho \
--scope "profile email"
```
As a consequence, `--provider` option and URI-specific options `--auth-uri`,
`--dev-auth-uri`, `--keys-uri`, and `--token-uri` are mutually exclusive.
`ipa idp-add` command does not currently use `--issuer-url` option URL
to dynamically look up other URIs through a well-known OIDC endpoints. Some of
the IdPs do not provide well-known OIDC endpoints URL at all. This option can
be used in `ipa idp-mod` to set `ipaIdpIssuerURL` LDAP attribute. If this
attribute is set, it will be passed to SSSD's `oidc_child` helper during actual
authorization processing.
The `scope` is optional, and the `client_id` is mandatory.
The `client_secret` must not be displayed by `ipa idp-find` or `ipa idp-show`
commands unless permission 'System: Read External IdP client secret' is
assigned to the authenticated user running the command.
### Pre-populated IdP templates
List of pre-populated IdP types is currently limited by the following provider
"names":
* google
* github
* microsoft
* okta
* keycloak
Some IdP providers support parametrized URIs which include organization or a
realm name, or specific base URL, or both.
One notable omission in the pre-populated IdP types above is Gitlab.
FreeIPA only supports IdPs that implement OAuth 2.0 Device authorization
grant flow as defined by the [RFC 8628](https://www.rfc-editor.org/rfc/rfc8628).
If required IdP cannot be made to support Device authorization grant flow, it
is recommended to use OAuth 2.0 federation within an IdP that supports this
method. Gitlab does not support OAuth 2.0 Device authorization grant flow and
thus is not supported directly.
SSSD 2.7.0 implements Kerberos pre-authentication method `idp` (registered as a
pre-authentication type 152, PA-REDHAT-IDP-OAUTH2). It relies on IPA KDB driver
to provide a metadata in the Kerberos principal entry to specify use of IdP.
KDC side of the pre-authentication method 'idp' then communicates with IPA
`ipa-otpd` daemon which reads external IdP reference object associated with the
user and spawns `oidc_child` helper from SSSD to complete authorization.
`oidc_child` helper performs OAuth 2.0 device authorization grant flow. Since
it only supports a single authorization method, not all endpoints are required.
In order to authenticate users associated with external IdPs to access IPA Web
UI, a general OAuth 2.0 authorization endpoint is required. Thus, this endpoint
information is stored in the object but not otherwise used by the Kerberos
flow.
#### Google IdPs
Choosing `--provider=google` would expand to use the following options:
| Option | Value |
|:--------------------- | :--------------------- |
| `--auth-uri`=URI | `https://accounts.google.com/o/oauth2/auth` |
| `--dev-auth-uri`=URI | `https://oauth2.googleapis.com/device/code` |
| `--token-uri`=URI | `https://oauth2.googleapis.com/token` |
| `--userinfo-uri`=URI | `https://openidconnect.googleapis.com/v1/userinfo` |
| `--keys-uri`=URI | `https://www.googleapis.com/oauth2/v3/certs` |
| `--scope`=STR | `openid email` |
| `--idp-user-id`=STR | `email` |
#### Github IdPs
Choosing `--provider=github` would expand to use the following options:
| Option | Value |
|:--------------------- | :--------------------- |
| `--auth-uri`=URI | `https://github.com/login/oauth/authorize` |
| `--dev-auth-uri`=URI | `https://github.com/login/device/code` |
| `--token-uri`=URI | `https://github.com/login/oauth/access_token` |
| `--userinfo-uri`=URI | `https://openidconnect.googleapis.com/v1/userinfo` |
| `--keys-uri`=URI | `https://api.github.com/user` |
| `--scope`=STR | `user` |
| `--idp-user-id`=STR | `login` |
Please note that Github explicitly states that a user login is not unique and
can be reused after a user account was deleted. The configuration above aims
for an easy setup for testing. If production deployment with Github IdP would
be required, it is recommended to change `--idp-user-id` to a more unique subject
like `id`. Unfortunately, Github UI does not give an easy way to discover a
user ID. Other IdPs also lack an easy way to resolve these internal identifiers
when not authorized by the user themselves.
For Github, user's ID can be looked up without authentication through the Users
API. Assuming we have `curl` and `jq` utilities available, a request to
discover an ID of a Github user named `test` would look like:
```
$ curl --silent \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/users/test | jq .id
383316
```
#### Microsoft IdPs
Microsoft Azure IdPs allow parametrization based on the Azure tenant ID
which can be specified with `--org` option to `ipa idp-add`. If support for
live.com IdP is required, specify organization ID `common`, e.g.
```
ipa idp-add LiveCom --provider microsoft --org common --client-id some-client-id
```
Choosing `--provider=microsoft` would expand to use the following options. A string
`${ipaidporg}` will be replaced by the value of `--org` option.
| Option | Value |
|:--------------------- | :--------------------- |
| `--auth-uri`=URI | `https://login.microsoftonline.com/${ipaidporg}/oauth2/v2.0/authorize` |
| `--dev-auth-uri`=URI | `https://login.microsoftonline.com/${ipaidporg}/oauth2/v2.0/devicecode`|
| `--token-uri`=URI | `https://login.microsoftonline.com/${ipaidporg}/oauth2/v2.0/token` |
| `--userinfo-uri`=URI | `https://graph.microsoft.com/oidc/userinfo` |
| `--keys-uri`=URI | `https://login.microsoftonline.com/common/discovery/v2.0/keys` |
| `--scope`=STR | `openid email` |
| `--idp-user-id`=STR | `email` |
#### Okta IdPs
Upon registration of a new organization in Okta, a new base URL is associated
with it. It can be specified with `--base-url` option to `ipa idp-add`:
```
ipa idp-add MyOkta --provider okta --base-url dev-12345.okta.com --client-id some-client-id
```
Choosing `--provider=okta` would expand to use the following options. A string
`${ipaidpbaseurl}` will be replaced by the value of `--base-url` option.
| Option | Value |
|:--------------------- | :--------------------- |
| `--auth-uri`=URI | `https://${ipaidpbaseurl}/oauth2/v1/authorize` |
| `--dev-auth-uri`=URI | `https://${ipaidpbaseurl}/oauth2/v1/device/authorize` |
| `--token-uri`=URI | `https://${ipaidpbaseurl}/oauth2/v1/token` |
| `--userinfo-uri`=URI | `https://${ipaidpbaseurl}/oauth2/v1/userinfo` |
| `--scope`=STR | `openid email` |
| `--idp-user-id`=STR | `email` |
#### Keycloak IdPs
Keycloak allows defining multiple realms (organizations). Since it is often a
part of a custom deployment, both base URL and realm ID are required and
can be specified with `--base-url` and `--org` options to `ipa idp-add`:
```
ipa idp-add MySSO --provider keycloak \
--org master --base-url keycloak.$DOMAIN:$PORT/prefix \
--client-id some-client-id
```
Quarkus version of the Keycloak 17 or later has removed `/auth/` part of the URI. If
your deployment is using non-Quarkus distribution of the Keycloak, `--base-url`
would need to include `/auth/` component as well.
Choosing `--provider=keycloak` would expand to use the following options. A string
`${ipaidpbaseurl}` will be replaced by the value of `--base-url` option. A string
`${ipaidporg}` will be replaced by the value of `--org` option.
| Option | Value |
|:--------------------- | :--------------------- |
| `--auth-uri`=URI | `https://${ipaidpbaseurl}/realms/${ipaidporg}/protocol/openid-connect/auth` |
| `--dev-auth-uri`=URI | `https://${ipaidpbaseurl}/realms/${ipaidporg}/protocol/openid-connect/auth/device` |
| `--token-uri`=URI | `https://${ipaidpbaseurl}/realms/${ipaidporg}/protocol/openid-connect/token` |
| `--userinfo-uri`=URI | `https://${ipaidpbaseurl}/realms/${ipaidporg}/protocol/openid-connect/userinfo` |
| `--scope`=STR | `openid email` |
| `--idp-user-id`=STR | `email` |
#### User-specific options
Similar to RADIUS proxy support, external IdP authentication only triggered
when the following three conditions are true:
* user entry contains external IdP reference
* user entry has external IdP user name (subject) set
* either global user authentication type or per-user authentication type includes `idp` method
Therefore, two additional attributes available for User object in IPA API:
| Option | Description |
|:--------------------- | :--------------------- |
| `--idp`=STR | External IdP object reference |
| `--idp-user-id`=STR | External IdP's user name (subject) |
External IdP user name format is specific to individual IdPs. Most OAuth 2.0
IdPs provide `email` scope to retrieve email associated with the OAuth 2.0
resource owner (user) subject. Pre-populated IdP templates described above
include `email` scope by default. If external IdP references were created with
the help of these templates, user's email can be set to `--idp-user-id` to match
the resource owner subject. Please read Security section for details on when
this is inappropriate.
Below is an example how to associate a user account with a specific IdP reference:
```
ipa user-mod test --user-auth-type=idp --idp google --idp-user-id test@example.test
```
### WebUI
The IdP server objects need to be accessible in the WebUI. A new tab for
IdP will be created in the "Authentication" section, similar to
the existing _RADIUS servers_ tab. It will contain a table with the
list of IdP objects, enabling to add or delete an object.
Each object must be clickable in order to be edited.
In the _settings_ page for IdP objects, all the properties must be editable
but the client secret must not be displayed unless the authenticated user permitted
with the help of the `System: Read External IdP client secret` permission.
In order to change the client secret, the admin will click on
_Actions:Reset secret_.
Web UI for user entry attributes have to be extended to include both external
IdP reference and IdP user subject.
## Access control
Specific permissions need to be created to protect access to the IdP objects:
* System: Add External IdP
* System: Read External IdP (does not provide access to the client secret)
* System: Modify External IdP
* System: Delete External IdP
* System: Read External IdP client secret
Specific Privileges:
* External IdP Administrator: all the permissions related to external idp
except _System: Read External IdP client secret_
Any user who is a member of the admins group will be able to manage the
IdP server objects.
## Security
IPA objects representing external IdP references are OAuth 2.0 clients. The
client ID and client secret details can be used to impersonate OAuth 2.0
client. For public OAuth 2.0 client access to Client ID is enough. It is not
considered secure as it is typically a part of the HTTP redirect in OAuth 2.0
authorization flows.
Client secret has to be protected as it is typically used for private (trusted)
OAuth 2.0 clients.
Kerberos pre-authentication method `idp` relies on the user subject
(`ipaIdpSub` LDAP attribute) defined in the LDAP object entry to match the
Kerberos principal and the OAuth 2.0 resource owner. When `openid` OAuth 2.0
scope is used, this typically maps to `sub` value. Since there are no ways to
pull this value for all users in advance, pre-populated IdP templates set OAuth
2.0 scopes to include `email` and then use `email` to map IdP subject where possible.
There are some well-known IdPs which allow reuse of user accounts and emails, this
applies to both Github and Gitlab. Since Gitlab does not support OAuth 2.0
Device authorization grant flow, it is not an issue in itself for this project. However,
for Github it is known that user accounts can be recycled after their removal. In
this case we would recommend to use internal Github identifier instead.
## Upgrade and backward compatibility
As the new object class and attribute types are added in the LDAP schema, there
is no need for a specific upgrade task.
Upon normal upgrade, the new schema is applied and replicated to the other
servers, even if they are installed with a version which does not define the
new object class / attribute types.
In a mixed topology containing old and new servers, the new API is provided
only by the new servers.
+3
View File
@@ -13,8 +13,11 @@ FreeIPA design documentation
krb-ticket-policy.md
extdom-plugin-protocol.md
expiring-password-notification.md
ldap_grace_period.md
libpwquality.md
membermanager.md
hidden-replicas.md
disable-stale-users.md
subordinate-ids.md
external-idp/external-idp.md
external-idp/idp-api.md
+1
View File
@@ -18,6 +18,7 @@ Indicators and corresponding mechanisms are listed below:
| otp | Two factor authentication (password + OTP) |
| pkinit | PKINIT |
| hardened | Hardened Password (by SPAKE or FAST) |
| idp | External Identity Provider |
Hardened password means a password authentication with either SPAKE or FAST armoring enabled.
Although it is possible to assign separate indicators to SPAKE and FAST, when both SPAKE and FAST are used,
+96
View File
@@ -0,0 +1,96 @@
# LDAP Grace Period
## Overview
IPA previously allowed LDAP authentications past expiration to prevent a chicken-and-egg problem. Because all administratively-set passwords are expired a user must be given an opportunity to authenticate in order to reset their password. This allowed for unlimited authentications.
## Use Cases
Many IPA users have asked for a mechanism to deny LDAP authentications once expired.
## How to Use
A new option is added to password policies, --gracelimit. This specifies the number of allowed BINDs past expiration.
To set the global policy:
ipa pwpolicy-mod --gracelimit 3
This will allow 3 additional logins past expiration.
Setting to -1 disables the grace limit check.
Setting to 0 will do a grace limit check but will always fail because no further logins are allowed. The distinction between 0 and -1 is that with 0 a password policy control is returned.
## Design
An expired draft around LDAP password policies describes two methods for limiting account access past expiration, https://tools.ietf.org/id/draft-behera-ldap-password-policy-10.html
The RFE provides two options (which can be use simultaneously).
1. Limit the number of authentications past expiration
2. Limit by time past the expiration
This implements the first part only. 389-ds already implements this so we can reuse existing schema, using their alternative attribute names passwordGraceLimit (system) and passwordGraceUserTime (user).
A 389-ds plugin will be registered as a bind preop function which will compare the policy grace period with the user's grace period
The password policy plugin will have a new attribute added, passwordGraceLimit, to store the policy maximum.
The basic flow is:
- Register preop BIND plugin
- On BIND, get the DN
- Get the password policy for that DN
- If the policy grace limit == -1 then exit
- Compare the policy grace limit to the user's passwordGraceUserTime
- If the user's grace limit exceeds policy, fail
- If the grace limit == 0, fail
- Set a password policy control with the number of remaining logins
- Set the time in the policy to -1 to indicate no value
On successful password reset (by anyone) reset the user's passwordGraceUserTime to 0.
The default value on install/upgrade will be -1 to retail existing behavior.
The per-user attempts will not be replicated.
## Implementation
N/A
## Feature Management
### UI
The new option is not visible in the UI yet.
### CLI
Overview of the CLI commands. Example:
| Command | Options |
| --- | ----- |
| pwpolicy-mod | --gracelimit=<-1 to MAXINT> |
### Configuration
The plugin will be registered on new installations.
## Upgrade
The plugin will be registered on upgrades.
## Test plan
1. Set a grace limit on a custom policy, ldapsearch a few times, verify that the limit is set to what is expected
2. Keep going until authentication fails
3. Reset password, verify that authentication can happen
4. With two servers verify that an authentication one one server doesn't trigger a replication event to the other.
## Troubleshooting and debugging
$ ldapsearch -LLL -x -D 'uid=tuser,cn=users,cn=accounts,dc=example,dc=test' -w password -e ppolicy -b uid=tuser,cn=users,cn=accounts,dc=example,dc=test dn
# PasswordExpired control
ldap_bind: Success (0) (Password expired, 3 grace logins remain)
dn: uid=tuser,cn=users,cn=accounts,dc=example,dc=test
+167 -76
View File
@@ -1,12 +1,8 @@
# Central management of subordinate user and group ids
## OUTDATED
**The design document does not reflect new implementation yet!**
Subordinate ids are a Linux Kernel feature to grant a user additional
user and group id ranges. Amongst others the feature can be used
by container runtime engies to implement rootless containers.
by container runtime engines to implement rootless containers.
Traditionally subordinate id ranges are configured in ``/etc/subuid``
and ``/etc/subgid``.
@@ -68,6 +64,7 @@ and don't auto-map or auto-assign subordinate ids by default. Instead
we give the admin several options to assign them manually, semi-manual,
or automatically.
### Revision 1 limitation
The first revision of the feature is deliberately limited and
@@ -76,14 +73,13 @@ basic use cases. Some restrictions may be lifted in the future.
* subuid and subgids cannot be set independently. They are always set
to the same value.
* counts are hard-coded to value 65536
* once assigned subids cannot be removed
* counts are hard-coded to value 65536.
* once assigned subids cannot be removed.
* IPA does not support multiple subordinate id ranges, yet. Contrary to
``/etc/subuid``, users are limited to one set of subordinate ids. The
limitation is implemented with a unique index on owner reference and
can be lifted in the future.
* subids are auto-assigned. Auto-assignment is currently emulated
until 389-DS has been extended to support DNA with step interval.
* subids are auto-assigned from 389-DS DNA plugin (dnaInterval).
* subids are allocated from hard-coded range
``[2147483648..4294901767]`` (``2^31`` to ``2^32-1-65536``), which
is the upper 2.1 billion uids of ``uid_t`` (``uint32_t``). The range
@@ -91,6 +87,29 @@ basic use cases. Some restrictions may be lifted in the future.
* Active Directory support is out of scope and may be provided in the
future.
Finally, it is important to note that new installations come with a new
idrange for subordinate ids. The new ``$REALM_subid_range`` entry uses
range type ``ipa-ad-trust`` instead of range type ``ipa-local-subid``
for backwards compatibility with older SSSD clients, see [SSSD #5571](https://github.com/SSSD/sssd/issues/5571).
```text
dn: cn=TESTREALM.TEST_subid_range,cn=ranges,cn=etc,dc=testrealm,dc=test
objectClass: top
objectClass: ipaIDrange
objectClass: ipaTrustedADDomainRange
cn: TESTREALM.TEST_subid_range
ipaBaseID: 2147483648
ipaIDRangeSize: 2147352576
ipaBaseRID: 2147283648
ipaNTTrustedDomainSID: S-1-5-21-738065-838566-1351619967
ipaRangeType: ipa-ad-trust
```
The additional idrange entry is defined as: ``cn=$REALM_subid_range,cn=ranges,cn=etc,dc=ipa,dc=test``,
which is visible with ``ipa idrange-find``.
### Subid assignment example
```
@@ -244,11 +263,51 @@ objectClasses: (
)
```
Finally, setting ``ipaUserDefaultSubordinateId`` to TRUE will cause
new user entries to gain subordinate id by default:
```text
attributeTypes: (
2.16.840.1.113730.3.8.23.14
NAME 'ipaUserDefaultSubordinateId'
DESC 'Enable adding user entries with subordinate id'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
SINGLE-VALUE
X-ORIGIN 'IPA v4.9'
)
```
### cn=subids,cn=accounts,$SUFFIX
Subordiante ids and ACIs are stored in the new subtree
Subordinate ids and ACIs are stored in the new subtree
``cn=subids,cn=accounts,$SUFFIX``.
The following is an example of a subordinate id entry:
```text
dn: ipauniqueid=8a7c0808-375b-4643-9582-e9c851a4b45d,cn=subids,cn=accounts,dc=
testrealm,dc=test
ipaOwner: uid=asmith-auto,cn=users,cn=accounts,dc=testrealm,dc=test
ipaUniqueID: 8a7c0808-375b-4643-9582-e9c851a4b45d
description: auto-assigned subid
objectClass: ipasubordinateidentry
objectClass: ipasubordinateuid
objectClass: ipasubordinateid
objectClass: ipasubordinategid
objectClass: top
ipaSubUidCount: 65536
ipaSubGidCount: 65536
ipaSubUidNumber: 2147745792
ipaSubGidNumber: 2147745792
```
where as can be seen, it shows the link to the ipa user ``asmith-auto`` throught
the ipaOwner attribute:
```text
ipaOwner: uid=asmith-auto,cn=users,cn=accounts,dc=testrealm,dc=test
```
### Index, integrity, memberOf
The attributes ``ipaSubUidNumber`` and ``ipaSubGidNumber`` are index
@@ -268,9 +327,8 @@ Subordinate id auto-assignment requires an extension of 389-DS'
plug-in. The DNA plug-in is responsible for safely assigning unique
numeric ids across all replicas.
Currently the DNA plug-in only supports a step size of ``1``. A new
option ``dnaStepAttr`` (name is tentative) will tell the DNA plug-in
to use the value of entry attributes as step size.
A new option ``dnaInterval`` will tell the DNA plug-in to use the value of
entry attributes as interval size.
## IPA plugins and commands
@@ -298,30 +356,30 @@ Topic commands:
```
```text
$ ipa subid-generate --owner testuser9
$ ipa subid-generate --owner testuser
-----------------------------------------------------------
Added subordinate id "aa28f132-457c-488b-82e1-d123727e4f81"
Added subordinate id "2cf2c0db-aa9d-45d8-acbd-118aba0c1db3"
-----------------------------------------------------------
Unique ID: aa28f132-457c-488b-82e1-d123727e4f81
Unique ID: 2cf2c0db-aa9d-45d8-acbd-118aba0c1db3
Description: auto-assigned subid
Owner: testuser9
SubUID range start: 3922132992
Owner: testuser
SubUID range start: 2147680256
SubUID range size: 65536
SubGID range start: 3922132992
SubGID range start: 2147680256
SubGID range size: 65536
```
```text
$ ipa subid-find --owner testuser9
$ ipa subid-find --owner testuser
------------------------
1 subordinate id matched
------------------------
Unique ID: aa28f132-457c-488b-82e1-d123727e4f81
Owner: testuser9
SubUID range start: 3922132992
Unique ID: 2cf2c0db-aa9d-45d8-acbd-118aba0c1db3
Owner: testuser
SubUID range start: 2147680256
SubUID range size: 65536
SubGID range start: 3922132992
SubGID range start: 2147680256
SubGID range size: 65536
----------------------------
Number of entries returned 1
@@ -334,22 +392,22 @@ $ ipa -vv subid-stats
ipa: INFO: Response: {
"error": null,
"id": 0,
"principal": "admin@IPASUBID.TEST",
"principal": "admin@TESTREALM.TEST",
"result": {
"result": {
"assigned_subids": 20,
"assigned_subids": 1,
"baseid": 2147483648,
"dna_remaining": 4293394434,
"dna_remaining": 65527,
"rangesize": 2147352576,
"remaining_subids": 65512
"remaining_subids": 0
},
"summary": "65532 remaining subordinate id ranges"
"summary": "0 remaining subordinate id ranges"
},
"version": "4.10.0.dev"
"version": "4.9.9"
}
-------------------------------------
65532 remaining subordinate id ranges
-------------------------------------
---------------------------------
0 remaining subordinate id ranges
---------------------------------
```
## Permissions, Privileges, Roles
@@ -418,8 +476,8 @@ $ ipa role-add-member "Subordinate ID Selfservice User" --groups=ipausers
This allows members of ``ipausers`` to request subordinate ids with
the ``subid-generate`` command or the *Auto assign subordinate ids*
action in the web UI (**TODO** not implemented yet). The command picks
the name of the current user principal automatically.
action in the web UI. The command picks the name of the current user
principal automatically.
```shell
$ ipa subid-generate
@@ -453,7 +511,7 @@ Options:
-q, --quiet output only errors
--log-file=FILE log to the given file
# # /usr/libexec/ipa/ipa-subids --group ipausers
# /usr/libexec/ipa/ipa-subids --group ipausers
Processing user 'testsubordinated1' (1/15)
Processing user 'testsubordinated2' (2/15)
Processing user 'testsubordinated3' (3/15)
@@ -475,30 +533,65 @@ The ipa-subids command was successful
### Find and match users by any subordinate id
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.
The ``user-find`` command is now able to search for users matching a
particular subordinate id when using ``--in-subids`` option:
```text
$ ipa subid-match --subuid=2147549183
------------------------
1 subordinate id matched
------------------------
Name: asmith-auto
Owner: asmith
SubUID range start: 2147483648
SubUID range size: 65536
SubGID range start: 2147483648
SubGID range size: 65536
$ ipa user-find --in-subids=8a7c0808-375b-4643-9582-e9c851a4b45d
--------------
1 user matched
--------------
User login: asmith-auto
First name: asmith
Last name: auto
Home directory: /home/asmith-auto
Login shell: /bin/sh
Principal name: asmith-auto@TESTREALM.TEST
Principal alias: asmith-auto@TESTREALM.TEST
Email address: asmith-auto@testrealm.test
UID: 1242200006
GID: 1242200006
Account disabled: False
----------------------------
Number of entries returned 1
----------------------------
$ ipa user-match-subid --subuid=2147549184
Name: bjones-auto
Owner: bjones
SubUID range start: 2147549184
```
and search for users not matching a particular subordinate id when
using ``--not-in-subids`` option:
```text
$ ipa user-find --not-in-subids=8a7c0808-375b-4643-9582-e9c851a4b45d
--------------
1 user matched
--------------
User login: bjones-auto
First name: bjones
Last name: auto
Home directory: /home/bjones-auto
Login shell: /bin/sh
Principal name: bjones-auto@TESTREALM.TEST
Principal alias: bjones-auto@TESTREALM.TEST
Email address: bjones-auto@testrealm.test
UID: 1242200007
GID: 1242200007
Account disabled: False
```
Additionally, the new command ``subid-match`` can be used to find a user
by any subordinate id in their range when using the ``--subuid`` option:
```text
$ ipa subid-match --subuid=2147745792
------------------------
1 subordinate id matched
------------------------
Unique ID: 8a7c0808-375b-4643-9582-e9c851a4b45d
Owner: asmith-auto
SubUID range start: 2147745792
SubUID range size: 65536
SubGID range start: 2147549184
SubGID range start: 2147745792
SubGID range size: 65536
----------------------------
Number of entries returned 1
@@ -553,6 +646,18 @@ ipaSubUidCount: 65536
ipaSubGidCount: 65536
```
### Configure subid managed at IPA level
Starting in FreeIPA 4.10.0 release, ipa-client-install provides a new option that
allows to configure the client subid managed at IPA level. This way, ipa-client-install
can configure the sssd profile and customize /etc/nsswitch.conf in such a way the subid
database relies on IPA instead of both of the local files /etc/subuid and /etc/subgid.
It is important to note that the default behavior remains unchanged and ``--subid`` option
must be provided to the client, server and replica installers in order to have SSSD setup
as a datasource for subid in /etc/nsswitch.conf
## Implementation details
* ``ipaSubordinateId`` object class does not subclass the other two
@@ -586,27 +691,13 @@ ipaSubGidCount: 65536
### TODO
* enable configuration for ``dnaStepAttr``
* remove ``fake_dna_plugin`` hack from ``baseuser`` plug-in.
* add custom range type for idranges and teach AD trust, sidgen, and
range overlap check code to deal with new range type.
#### user-del --preserve
Preserving a user with ``ipa user-del --preserve`` currently fails with
an ObjectclassViolation error (err=65). The problem is caused by
configuration of referential integrity postoperation plug-in. The
plug-in excludes the subtree
``nsslapd-pluginexcludeentryscope: cn=provisioning,$SUFFX``. Preserved
users are moved into the staging area of the provisioning subtree.
Since the ``ipaOwner`` DN target is now out of scope, the plug-in
attempts to delete references. However ``ipaOwner`` is a required
attribute, which triggers the objectclass violation.
Possible solutions
* Don't preserve subid entries
* Implement preserve feature for subid entries and move subids of
preserved users into
``cn=deleted subids,cn=accounts,cn=provisioning,$SUFFIX`` subtree.
* Change ``nsslapd-pluginexcludeentryscope`` setting
* ipa subid-stats should include assigned_subids value as output, since
the remaning_subids value is always seen as 0, its better to display
assigned_subids as output for #ipa subid-stats which will be more useful
([RFE#2063176](https://bugzilla.redhat.com/show_bug.cgi?id=2063176))
* user-del --preserve and user-undel. Preserving a user with
``ipa user-del --preserve`` is possible however it deletes the
associated subid, meaning that ``ipa user-undel <ipauser>``
is not able to restore the subid of the deleted user ([RFE#2063168](https://bugzilla.redhat.com/show_bug.cgi?id=2063168)).
+11 -4
View File
@@ -1,8 +1,11 @@
## m2r is not compatible with Sphinx 3.x yet
sphinx >2.1,<3.0
wheel
## convert markdown to rest
m2r
sphinx > 3.0
# convert markdown to rest
# m2r2 fork is active in development and works with
# newer sphinx versions
m2r2
## ipa dependencies
dnspython
@@ -26,3 +29,7 @@ lxml
## No sufficient PyPI packages
# dogtag-pki
# Sequence diagrams generator
sphinxcontrib-plantuml
pillow
+7 -1
View File
@@ -6,7 +6,6 @@ FreeIPA workshop
:caption: Workshop:
workshop/workshop.rst
workshop/building.rst
workshop/1-server-install.rst
workshop/2-client-install.rst
workshop/3-user-management.rst
@@ -18,4 +17,11 @@ FreeIPA workshop
workshop/9-selinux-user-map.rst
workshop/10-ssh-key-management.rst
workshop/11-kerberos-ticket-policy.rst
workshop/12-external-idp-support.rst
.. toctree::
:includehidden:
workshop/troubleshooting.rst
workshop/building.rst
workshop/facilitators.rst
+68 -7
View File
@@ -8,6 +8,8 @@ Unit 11: Kerberos ticket policy
In this module you will explore how to manage properties of Kerberos
authentication and authorization in FreeIPA.
**Note:** To complete this module, FreeIPA-4.8.4 or later is needed.
Kerberos ticket policies
------------------------
@@ -97,6 +99,7 @@ radius RADIUS
otp FreeIPA two factor authentication (password + OTP)
pkinit PKINIT, smart-card or certificate authentication
hardened Hardened Password (by SPAKE or FAST)
idp External Identity Provider
========================= ========================
**Hardened** authentication indicator is set by FreeIPA KDC when a Kerberos
@@ -126,7 +129,7 @@ pre-authenticate the initial ticket granting ticket exchange using chosen
mechanism. This fact can further be used to differentiate the issued ticket life
time and renewal age.
With FreeIPA 4.8.3 or later, Kerberos ticket policy allows an administrator to
With FreeIPA 4.8.4 or later, Kerberos ticket policy allows an administrator to
set different life time and renewal age for ticket granting tickets obtained
with different pre-authentication methods. Each policy setting may include
authentication indicator to say that the life time or renewal age applies to
@@ -253,12 +256,70 @@ For example, an application might decide to only allow access to a specialized
resource to people who used smart-card authentication initially, even if the
application itself only supports Kerberos authentication.
At the moment, there are no known applications that implement authentication
indicator-based authorization. Instead, FreeIPA provides a check for an
authentication indicator at KDC side. This means that a lack of a specific
authentication indicator in TGT can result in denying an issuance of a requested
service ticket. A consequence is that an application will never see any user
with a ticket that does not contain a specified authentication indicator.
At the moment, there is only one known application that implements
authentication indicator-based authorization. Since version 2.6.0, SSSD provides
a PAM module ``pam_sss_gss`` which allows to authenticate users with GSSAPI
(Kerberos ticket) and optionally check authentication indicator that was used to
obtain this ticket. More information can be found in the man page for
``pam_sss_gss` and for ``sssd.conf`` where options starting with ``pam_gssapi_``
prefix are documented. This feature was also backported to SSSD 2.4.2 and 2.5.0.
For example, setting the following in SSSD configuration would allow GSSAPI
authentication to ``sudo`` and ``sudo -i`` only if the Kerberos ticket was
obtained with the use of a smartcard or certificate-based authentcation::
[pam]
pam_gssapi_services = sudo, sudo-i
pam_gssapi_indicators_map = sudo:pkinit, sudo-i:pkinit
The actual enforcement requires use of ``pam_sss_gss`` module in the PAM stack.
Fedora and RHEL distributions provide ``authselect`` tool to handle PAM and NSS
configuration. ``authselect`` was extended to allow use of ``pam_sss_gss`` as
SSSD feature ``with-gssapi``::
[root@client ~]# authselect enable-feature with-gssapi
Make sure that SSSD service is configured and enabled. See SSSD documentation for more information.
- with-gssapi is selected, make sure that GSSAPI authenticaiton is enabled in SSSD
- set pam_gssapi_services to a list of allowed services in /etc/sssd/sssd.conf
- see additional information in pam_sss_gss(8)
Once this change made and SSSD configuration updated to allow PAM services to
use GSSAPI authentication, it will be possible to use Kerberos ticket to
authenticate over a chosen PAM service. A session below demonstrates it::
[root@client ~]# vim /etc/sssd/sssd.conf
[root@client ~]# systemctl restart sssd
[root@client ~]# id testuser
uid=167200003(testuser) gid=167200003(testuser) groups=167200003(testuser)
[root@client ~]# ssh testuser@`hostname`
(testuser@client.ipa.test) password:
Last login: Thu Mar 24 13:54:21 2022 from 192.168.122.141
-sh-5.1$ klist
Ticket cache: KCM:167200003:41683
Default principal: testuser@IPA.TEST
Valid starting Expires Service principal
03/25/22 13:47:55 03/26/22 13:04:47 krbtgt/IPA.TEST@IPA.TEST
-sh-5.1$ sudo -l
Matching Defaults entries for testuser on client:
!visiblepw, always_set_home, match_group_by_gid,
always_query_group_plugin, env_reset, env_keep="COLORS DISPLAY HOSTNAME
HISTSIZE KDEDIR LS_COLORS", env_keep+="MAIL QTDIR USERNAME LANG LC_ADDRESS
LC_CTYPE", env_keep+="LC_COLLATE LC_IDENTIFICATION LC_MEASUREMENT
LC_MESSAGES", env_keep+="LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER
LC_TELEPHONE", env_keep+="LC_TIME LC_ALL LANGUAGE LINGUAS _XKB_CHARSET
XAUTHORITY",
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/var/lib/snapd/snap/bin
User testuser may run the following commands on dc:
(ALL) ALL
FreeIPA also provides a check for an authentication indicator at KDC side. This
means that a lack of a specific authentication indicator in TGT can result in
denying an issuance of a requested service ticket. A consequence is that an
application will never see any user with a ticket that does not contain a
specified authentication indicator.
In order to enable the check, add authentication indicator to a service using
``ipa service-mod`` command. We can create a new service and associate
+772
View File
@@ -0,0 +1,772 @@
Unit 12: Authentication against external Identity Providers
===========================================================
**Prerequisites:**
- `Unit 11: Kerberos ticket policy <11-kerberos-ticket-policy.rst>`_
In this module you will explore how to manage use external OAuth 2.0 servers to
authorize issuance of Kerberos tickets in FreeIPA.
**Note:** To complete this module, FreeIPA-4.10 or later is needed.
Authentication using external Identity Providers
------------------------------------------------
It is possible to let FreeIPA to delegate authentication and authorization
process of issuing Kerberos tickets to an external entity. FreeIPA has been
supporting RADIUS server proxying for some time. This is exposed over
Kerberos with the help of 'otp' pre-authentication mechanism.
Configuration of the RADIUS proxy authentication is done in two steps: first,
create a RADIUS proxy object in FreeIPA and then associate the user account with
this RADIUS proxy object.
There is no specific requirement as to how RADIUS proxy actually authenticates
the user. It is left outside the FreeIPA scope. The connection to the RADIUS
server becomes critical and is important to protect.
This approach has been extended to allow FreeIPA to contact an OAuth 2.0
Authorization Server instead of RADIUS server. OAuth 2.0 authorization framework
is a modern way to delegate authorization decisions between loosely coupled
parties. It heavily relies on the ability to use HTTP redirects to guide a
user's browser to hop between OAuth 2.0 parties and reach the one that logs user
in and the one that authorizes the access.
Traditionally, it was hard to integrate with OAuth 2.0-enabled systems in POSIX
environment because there is no way to run a browser session from within the
shell or console. Most of OAuth 2.0 identity providers (IdP) heavily rely on
JavaScript and other modern browser features to provide an enhanced user
experience. Emulating the login pages as part of line- and packet-oriented SSH
protocol or console login script is not possible.
OAuth 2.0 Device Authorization Grant is defined in
[RFC 8628](https://www.rfc-editor.org/rfc/rfc8628) and allows devices that either
lack a browser or input constrained to obtain user authorization to access
protected resources. Instead of performing the authorization flow right at the
device where OAuth authorization grant is requested, a user would perform it at
a separate device that has required rich browsing or input capabilities.
Following figure demonstrates a generic device authorization flow:
.. uml::
participant "End User at Browser"
participant "Device Client"
participant "Authorization Server"
"Device Client" -> "Authorization Server": (A) Client Identifier
"Authorization Server" -> "Device Client": (B) Device Code, User Code & Verification URI
"Device Client" -> "End User at Browser": (C) User Code & Verification URI
"End User at Browser" <-> "Authorization Server": (D) End user reviews authorization request
"Device Client" -> "Authorization Server": (E) Polling with Device Code and Client Identifier
"Authorization Server" -> "Device Client": (F) Access Token (& Optional Refresh Token)
FreeIPA implements a variation of this flow and hides it behind Kerberos KDC. A
special pre-authentication method in MIT Kerberos, ``idp`` is implemented in
SSSD 2.7.0 to facilitate the process outlined above.
Device authorization grant flow decouples the process into several steps:
- the device initiates OAuth 2.0 flow and receives a response from the
Authorization Server that contains a special code and a link to a website user
needs to visit to authorize the device;
- user opens this website somewhere else (mobile, desktop, etc) where a proper
browser is available;
- user is asked to enter the special code;
- if needed, user would be asked login into an OAuth 2.0-based IdP;
- once logged in, IdP would ask user if they authorize this device to access
certain user information;
- once the access request is granted, user comes back to the device's prompt and
confirms it;
- the device at this point would poll OAuth 2.0 Authorization Server on whether
it is allowed to access user information already.
Set up external IdP integration in FreeIPA
------------------------------------------
In order to perform OAuth 2.0 device authorization grant flow against an IdP, an
OAuth 2.0 client has to be registered with the IdP and a capability to allow the
device authorization grant has to be given to it. Not all IdPs support this
feature. Out of the known public ones, following IdPs do support device
authorization grant flow:
* Microsoft Identity Platform, including Azure AD
* Google
* Github
* Keycloak, including Red Hat SSO
* Okta
Many OAuth 2.0 platforms do not support device authorization grant flow and
cannot be directly enabled to operate with FreeIPA. However, one can always
chain (federate) IdPs. It means that, for example, one can deploy Keycloak
locally to allow users to sign in with identities from a different IdP. In that
case the local Keycloak instance would need to be registered as an OAuth 2.0
client with the remote IdP. Local Keycloak instance would then be registered
with IPA.
Setting up IdP references (OAuth 2.0 clients) in IPA can be done with ``ipa
idp-add`` command. The command accepts an option to specify a pre-defined
template for one of the known IdPs. If none of the pre-defined templates is
suitable, individual parameters can also be added::
ipa help idp-add
Usage: ipa [global-options] idp-add NAME [options]
Add a new Identity Provider server.
Options:
-h, --help show this help message and exit
--auth-uri=STR OAuth 2.0 authorization endpoint
--dev-auth-uri=STR Device authorization endpoint
--token-uri=STR Token endpoint
--userinfo-uri=STR User information endpoint
--keys-uri=STR JWKS endpoint
--issuer-url=STR The Identity Provider OIDC URL
--client-id=STR OAuth 2.0 client identifier
--secret OAuth 2.0 client secret
--scope=STR OAuth 2.0 scope. Multiple scopes separated by space
--idp-user-id=STR Attribute for user identity in OAuth 2.0 userinfo
--setattr=STR Set an attribute to a name/value pair. Format is
attr=value. For multi-valued attributes, the command
replaces the values already present.
--addattr=STR Add an attribute/value pair. Format is attr=value. The
attribute must be part of the schema.
--provider=['google', 'github', 'microsoft', 'okta', 'keycloak']
Choose a pre-defined template to use
--organization=STR Organization ID or Realm name for IdP provider
templates
--base-url=STR Base URL for IdP provider templates
--all Retrieve and print all attributes from the server.
Affects command output.
--raw Print entries as stored on the server. Only affects
output format.
In this part we would use Keycloak IdP to integrate with IPA. Next section shows
how to set up Keycloak on a host enrolled into IPA domain. All shell scripts
below assume execution under ``root`` privileges.
Set up Keycloak IdP on enrolled IPA client
------------------------------------------
In this section, we set up `Keycloak <https://www.keycloak.org>`_ IdP on IPA
client and use it to authenticate IPA users. User database in Keycloak would be
different from the one in IPA, one would need to keep user accounts duplicated
in both places but this would simplify our configuration. We also would use
automation provided by the Keycloak to set up OAuth 2.0 clients and user
accounts.
First, we would download keycloak and unpack it into ``/opt/keycloak-<VERSION>`` as ``root``::
[root@client ~]# dnf -y install java-11-openjdk-headless openssl
#### download keycloak ####
[root@client ~]# export KEYCLOAK_VERSION=18.0.0
[root@client ~]# wget https://github.com/keycloak/keycloak/releases/download/${KEYCLOAK_VERSION}/keycloak-${KEYCLOAK_VERSION}.tar.gz
[root@client ~]# tar zxf keycloak-${KEYCLOAK_VERSION}.tar.gz -C /opt
#### add keycloak system user/group and folder ####
[root@client ~]# groupadd keycloak
[root@client ~]# useradd -r -g keycloak -d /opt/keycloak-${KEYCLOAK_VERSION} keycloak
[root@client ~]# chown -R keycloak:keycloak /opt/keycloak-${KEYCLOAK_VERSION}
[root@client ~]# chmod o+x /opt/keycloak-${KEYCLOAK_VERSION}/bin/
[root@client ~]# restorecon -R /opt/keycloak-${KEYCLOAK_VERSION}
Next step would be to prepare a TLS certificate to be used to protect HTTPS
connections in Keycloak. Since our system is already enrolled into IPA, we can
rely on two features:
* Enrolled IPA client has Kerberos host principal registered with keytab in ``/etc/krb5.keytab``
* Enrolled IPA client host Kerberos principal can manage Kerberos services on the same host
This means we can create ``HTTP/client...`` Kerberos service right from the IPA
client and use ``certmonger`` to issue TLS certificate for it. Certmonger would
automatically renew the certificate. The following sequence of commands
demonstrates how to achieve this, run as root::
########## setup TLS certificate using IPA CA ###############################
[root@client ~]# kinit -k
[root@client ~]# ipa service-add HTTP/$(hostname)
[root@client ~]# ipa-getcert request -K HTTP/$(hostname) -D $(hostname) \
-o keycloak -O keycloak \
-m 0600 -M 0644 \
-k /etc/pki/tls/private/keycloak.key \
-f /etc/pki/tls/certs/keycloak.crt \
-w
[root@client ~]# keytool -import \
-keystore /etc/pki/tls/private/keycloak.store \
-file /etc/ipa/ca.crt \
-alias ipa_ca \
-trustcacerts -storepass Secret123 -noprompt
[root@client ~]# chown keycloak:keycloak /etc/pki/tls/private/keycloak.store
The private key for this certificate is stored in
``/etc/pki/tls/private/keycloak.key``, only accessible to the keycloak user.
Public part of the certificate is stored in ``/etc/pki/tls/certs/keycloak.crt``
and has permissions 0644.
We also import IPA CA's chain to a Java keystore that would be used by Keycloak,
stored at ``/etc/pki/tls/private/keycloak.store``.
Finally, we need to set up ``systemd`` service to run Keycloak::
# Setup keycloak service and config files
[root@client ~]# cat > /etc/sysconfig/keycloak <<EOF
KEYCLOAK_ADMIN=admin
KEYCLOAK_ADMIN_PASSWORD=Secret123
#KC_LOG_LEVEL=debug
KC_HOSTNAME=$(hostname):8443
KC_HTTPS_CERTIFICATE_FILE=/etc/pki/tls/certs/keycloak.crt
KC_HTTPS_CERTIFICATE_KEY_FILE=/etc/pki/tls/private/keycloak.key
KC_HTTPS_TRUST_STORE_FILE=/etc/pki/tls/private/keycloak.store
KC_HTTPS_TRUST_STORE_PASSWORD=Secret123
KC_HTTP_RELATIVE_PATH=/auth
EOF
[root@client ~]# cat > /etc/systemd/system/keycloak.service <<EOF
[Unit]
Description=Keycloak Server
After=network.target
[Service]
Type=idle
EnvironmentFile=/etc/sysconfig/keycloak
User=keycloak
Group=keycloak
ExecStart=/opt/keycloak-${KEYCLOAK_VERSION}/bin/kc.sh start
TimeoutStartSec=600
TimeoutStopSec=600
[Install]
WantedBy=multi-user.target
EOF
[root@client ~]# systemctl daemon-reload
When ``systemd`` service is prepared, Keycloak needs to be initialized::
[root@client ~]# su - keycloak -c '''
export KEYCLOAK_ADMIN=admin
export KEYCLOAK_ADMIN_PASSWORD=Secret123
export KC_HOSTNAME=$(hostname):8443
export KC_HTTPS_CERTIFICATE_FILE=/etc/pki/tls/certs/keycloak.crt
export KC_HTTPS_CERTIFICATE_KEY_FILE=/etc/pki/tls/private/keycloak.key
export KC_HTTPS_TRUST_STORE_FILE=/etc/pki/tls/private/keycloak.store
export KC_HTTPS_TRUST_STORE_PASSWORD=Secret123
export KC_HTTP_RELATIVE_PATH=/auth
/opt/keycloak-${KEYCLOAK_VERSION}/bin/kc.sh --verbose build
'''
and can be started with the standard ``systemctl`` tool::
[root@client ~]# systemctl start keycloak
[root@client ~]# systemctl status --lines 3 --no-pager keycloak
● keycloak.service - Keycloak Server
Loaded: loaded (/etc/systemd/system/keycloak.service; disabled; vendor preset: disabled)
Active: active (running) since Fri 2022-05-06 10:43:06 UTC; 9min ago
Main PID: 27170 (java)
Tasks: 37 (limit: 2318)
Memory: 297.1M
CPU: 25.560s
CGroup: /system.slice/keycloak.service
└─27170 java -Xms64m -Xmx512m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m -Djava.net.preferIPv4Stack=true -D…
May 06 10:43:28 client.ipademo.local kc.sh[27170]: 2022-05-06 10:43:28,411 INFO [io.quarkus] (main) Keycloak 18.0.0 on …0.0:8443
May 06 10:43:28 client.ipademo.local kc.sh[27170]: 2022-05-06 10:43:28,412 INFO [io.quarkus] (main) Profile prod activated.
May 06 10:43:28 client.ipademo.local kc.sh[27170]: 2022-05-06 10:43:28,412 INFO [io.quarkus] (main) Installed features: [agroal…
Hint: Some lines were ellipsized, use -l to show in full.
Now we can use it for setting up users and OAuth 2.0 clients. There are two
handy scripts, ``kcadm.sh`` and ``kcreg.sh`` that allow to perform all
operations without visiting the Keycloak Web UI.
With ``kcadm.sh`` we login as admin and create user ``testuser1`` and set a password::
[root@client ~]# /opt/keycloak-18.0.0/bin/kcadm.sh config truststore \
--trustpass Secret123 \
/etc/pki/tls/private/keycloak.store
[root@client ~]# /opt/keycloak-18.0.0/bin/kcadm.sh config credentials \
--server https://$(hostname):8443/auth/ \
--realm master --user admin --password Secret123
Logging into https://client.ipademo.local:8443/auth/ as user admin of realm master
[root@client ~]# /opt/keycloak-18.0.0/bin/kcadm.sh create users \
-r master \
-s username=testuser1 -s enabled=true -s email=testuser1@ipademo.local
Created new user with id 'd319b32a-4cea-43c5-8ef8-19b2b8418d0a'
[root@client ~]# /opt/keycloak-18.0.0/bin/kcadm.sh set-password \
-r master \
--username testuser1 --new-password Secret123
With ``kcreg.sh`` we can create OAuth 2.0 client using a pre-defined template
that will include all parameters we need to allow OAuth 2.0 Device Authorization
Grant flow::
[root@client ~]# /opt/keycloak-18.0.0/bin/kcreg.sh config credentials \
--server https://$(hostname):8443/auth \
--realm master --user admin --password Secret123
[root@client ~]# cat >ipa_client.json <<EOF
{
"enabled" : true,
"redirectUris" : [ "https://ipa-ca.$(hostname -d)/ipa/idp/*" ],
"webOrigins" : [ "https://ipa-ca.$(hostname -d)" ],
"protocol" : "openid-connect",
"publicClient" : true,
"attributes" : {
"oauth2.device.authorization.grant.enabled" : "true",
"oauth2.device.polling.interval": "5"
}
}
EOF
[root@client ~]# /opt/keycloak-18.0.0/bin/kcreg.sh create \
-f ipa_client.json \
-s clientId=ipa_oidc_client
At this point, we have a Keycloak instance with a default ``master`` realm
(organization) and base URL ``https://$(hostname):8443/auth/``. In this realm we
have created ``testuser1`` user with a simple password. We also created OAuth
2.0 client ``ipa_oidc_client`` that is allowed to utilize OAuth 2.0 device
authorization grant flow. This client has no client secret ("public OAuth 2.0
client") associated. Confidential clients can also support device authorization
grant flows.
The client details include information about the redirect URIs. These are required
to specify for public OAuth 2.0 clients, but they aren't used for OAuth 2.0
device authorization grant flow.
Two attributes specified in the OAuth 2.0 client definition for Keycloak:
- ``oauth2.device.authorization.grant.enabled``, set to ``true``, allows OAuth 2.0
device authorization grant processing,
- ``oauth2.device.polling.interval``, set to 5, defines the polling interval for
the client to 5 seconds.
Keycloak 17.0.0 and 18.0.0 releases have a bug that sets default polling
interval to 600 seconds. This makes impossible actual polling process as the
lifespan of the device code is also set to 600 seconds. Keycloak's
[pull request 11893](https://github.com/keycloak/keycloak/pull/11893) needs
to be merged to fix the default settings.
Add IdP reference to IPA
------------------------
The following command adds IdP reference named ``keycloak`` as IPA administrator::
[root@client ~]# kinit admin
..
[root@client ~]# echo -e "Secret123\nSecret123" | \
[root@client ~]# ipa idp-add keycloak --provider keycloak \
--org master \
--base-url https://client.ipademo.local:8443/auth \
--client-id ipa_oidc_client \
--secret
-----------------------------------------
Added Identity Provider server "keycloak"
-----------------------------------------
Identity Provider server name: keycloak
Authorization URI: https://client.ipademo.local:8443/auth/realms/master/protocol/openid-connect/auth
Device authorization URI: https://client.ipademo.local:8443/auth/realms/master/protocol/openid-connect/auth/device
Token URI: https://client.ipademo.local:8443/auth/realms/master/protocol/openid-connect/token
User info URI: https://client.ipademo.local:8443/auth/realms/master/protocol/openid-connect/userinfo
Client identifier: ipa_oidc_client
Secret: U2VjcmV0MTIz
Scope: openid email
External IdP user identifier attribute: email
The name for the IdP reference is only used to associate an IdP with users in
IPA. Option ``--provider keycloak`` allows us to fill-in pre-defined template
for Keycloak or Red Hat SSO IdPs. The template expects both Keycloak's realm
(``--org`` option) and a base URL (``--base-url`` option) because Keycloak is
typically deployed as a part of a larger solution. These options may not be
needed for other pre-defined templates like Google or Github.
Associate IdP reference with IPA user
-------------------------------------
While we have added ``testuser1`` to Keycloak instance, this user needs to exist
in IPA to be visible to all enrolled systems. Currently there is no good
solution to integrate between IPA and Keycloak to allow automatically propagate
changes between the two. For the purpose of this workshop we would create users
manually -- we already did that for Keycloak.
Create a user ``testuser1`` in IPA::
[root@client ~]# ipa user-add testuser1 --first Test --last User1
----------------------
Added user "testuser1"
----------------------
User login: testuser1
First name: Test
Last name: User1
Full name: Test User1
Display name: Test User1
Initials: TU
Home directory: /home/testuser1
GECOS: Test User1
Login shell: /bin/sh
Principal name: testuser1@ipademo.local
Principal alias: testuser1@ipademo.local
Email address: testuser1@ipademo.local
UID: 35000003
GID: 35000003
Password: False
Member of groups: ipausers
Kerberos keys available: False
Once user is added, associate it with ``keycloak`` IdP reference we just
created. In order to allow user to login via IdP we need few conditions to be
satisfied:
* IdP reference defined for this IdP in IPA
* IdP reference associated with the user (``--idp`` option to ``ipa user-add``
or ``ipa user-mod``)
* IdP identity for the user is set in the user entry (``--idp-user-id`` option
to ``ipa user-add`` or ``ipa user-mod``)
* finally, user should be allowed to use ``idp`` user authentication method
(``--user-auth-type=idp`` option to ``ipa user-add`` or ``ipa user-mod`` or
``idp`` method set globally)
We can set these options to ``testuser1`` with ``ipa user-mod`` command::
[root@client ~]# ipa user-mod testuser1 --idp keycloak \
--idp-user-id testuser1@ipademo.local \
--user-auth-type=idp
-------------------------
Modified user "testuser1"
-------------------------
User login: testuser1
First name: Test
Last name: User1
Home directory: /home/testuser1
Login shell: /bin/sh
Principal name: testuser1@ipademo.local
Principal alias: testuser1@ipademo.local
Email address: testuser1@ipademo.local
UID: 35000003
GID: 35000003
User authentication types: idp
External IdP configuration: keycloak
External IdP user identifier: testuser1@ipademo.local
Account disabled: False
Password: False
Member of groups: ipausers
Kerberos keys available: False
As can be seen in the output, the account for ``testuser1`` has no password and
no Kerberos keys. It will not be able to authenticate to IPA services without
IdP's help.
Access IPA resources as an IdP user
-----------------------------------
There are two ways to trigger authentication and authorization of ``testuser1``
via our Keycloak IdP instance:
* obtain Kerberos ticket with ``kinit`` tool
* login to the target system via SSH or on the console
In order to obtain initial Kerberos ticket, we need to use ``kinit`` tool. SSSD
2.7.0 provides a special package ``sssd-idp`` which implements Kerberos
pre-authentication method ``idp``. When this package is installed, MIT Kerberos
configuration on the host is updated to automatically allow use of ``idp``
method. However, ``idp`` method requires use of FAST channel in order to provide
a secure connection between the Kerberos client and KDC. This is similar to
``otp`` pre-authentication method FreeIPA already provided for several years.
When IPA is deployed with integrated CA, IPA also provides a way to obtain a
special ticket, called Anonymous PKINIT, to use as a FAST channel factor.
Let's use Anonymous PKINIT to obtain a ticket and store it in the file
``./fast.ccache``. Then we can enable FAST channel with the use of ``-T`` option
for ``kinit`` tool::
[root@client ~]# kinit -n -c ./fast.ccache
[root@client ~]# kinit -T ./fast.ccache testuser1
Authenticate at https://client.ipademo.local:8443/auth/realms/master/device?user_code=YHMQ-XKTL and press ENTER.:
The prompt indicates that ``idp`` method was chosen between the KDC and the
Kerberos client. When KDC received the initial ticket granting ticket request,
IPA database driver (KDB) performed an LDAP lookup of the Kerberos principal and
found out that ``testuser1@IPADEMO.LOCAL`` Kerberos principal has ``idp`` user
authentication type. This, in turn, activated KDC side of the ``idp``
pre-authentication method and led to a request to ``ipa-otpd`` daemon. Finally,
``ipa-otpd`` daemon asked ``oidc_child`` to request a device code authorization
grant from the IdP associated with the ``testuser1@IPADEMO.LOCAL`` principal.
The grant flow resulted in IdP returning a code and a message which was
propagated back to the Kerberos client and displayed by the client side of the
``idp`` pre-authentication method.
At this point we need to visit the page and authorize access to the information.
Once it is done, we complete the process by pressing ``<ENTER>`` key. If
authorization was granted, KDC will issue a Kerberos ticket to and it will be
stored in the credentials cache::
[root@client ~]# klist
Ticket cache: KCM:0:58420
Default principal: testuser1@IPADEMO.LOCAL
Valid starting Expires Service principal
05/09/22 07:48:23 05/10/22 07:03:07 krbtgt/IPADEMO.LOCAL@IPADEMO.LOCAL
Similar process happens when ``pam_sss`` PAM module is used, for example, to
authenticate and authorize access to PAM services. Applications which use PAM to
authenticate and authorize remote access can also benefit from the flow. For
example, SSH daemon can be configured with ``keyboard-interactive`` method which
will allow PAM authentication and authorization. As part of it, PAM messages
will be relayed to the SSH client and SSH client's user input will be sent back
to PAM::
$ ssh testuser1@client.ipademo.local
(testuser1@client.ipademo.local) Authenticate at https://client.ipademo.local:8443/auth/realms/master/device?user_code=XYFL-ROYR and press ENTER.
Last login: Mon May 9 07:48:25 2022 from 10.0.190.227
-sh-5.1$ klist
Ticket cache: KCM:7800003:58420
Default principal: testuser1@IPADEMO.LOCAL
Valid starting Expires Service principal
05/09/22 07:49:38 05/10/22 07:49:24 krbtgt/IPADEMO.LOCAL@IPADEMO.LOCAL
-sh-5.1$
Once initial Kerberos ticket is available, it can be used to perform normal IPA
operations:
- access IPA API with command line tool ``ipa`` or through a Web UI in a browser
- login to other systems with GSSAPI authentication
- access PAM services which use ``pam_sss_gss`` module in their PAM stack definitions
Direct authentication to Web UI with the help of OAuth 2.0 client is not implemented yet.
Troubleshooting IdP integration
-------------------------------
Communication with an IdP server happens on IPA server when KDC calls out to
``ipa-otpd`` daemon and ``ipa-otpd`` daemon launches ``oidc_child`` helper.
Journal logs for ``ipa-otpd`` can be checked with the ``journalctl`` tool.
``ipa-otpd`` processes start on demand and content from all sessions can be
captured with the following command::
[root@master #] journalctl -u 'ipa-otpd@*'
The output would look similar to the following real world example::
May 02 18:51:28 dc.ipa.test systemd[1]: Started ipa-otpd service (PID 1473660/UID 0).
May 02 18:51:28 dc.ipa.test ipa-otpd[1636136]: LDAP: ldapi://%2Frun%2Fslapd-IPA-TEST.socket
May 02 18:51:28 dc.ipa.test ipa-otpd[1636136]: ab@IPA.TEST: request received
May 02 18:51:28 dc.ipa.test ipa-otpd[1636136]: ab@IPA.TEST: user query start
May 02 18:51:28 dc.ipa.test ipa-otpd[1636136]: ab@IPA.TEST: user query end: uid=ab,cn=users,cn=accounts,dc=ipa,dc=test
May 02 18:51:28 dc.ipa.test ipa-otpd[1636136]: ab@IPA.TEST: idp query start: cn=github,cn=idp,dc=ipa,dc=test
May 02 18:51:28 dc.ipa.test ipa-otpd[1636136]: ab@IPA.TEST: idp query end: github
May 02 18:51:28 dc.ipa.test ipa-otpd[1636136]: ab@IPA.TEST: oauth2 start: Get device code
May 02 18:51:29 dc.ipa.test ipa-otpd[1636136]: ab@IPA.TEST: Received: [{"device_code":"f071833afe966eaf596d83646f55250cfdb57418","expires_in":899,"interval":5}
May 02 18:51:29 dc.ipa.test ipa-otpd[1636136]: oauth2 {"verification_uri": "https://github.com/login/device", "user_code": "ECD3-4310"}
May 02 18:51:29 dc.ipa.test ipa-otpd[1636136]: ]
May 02 18:51:29 dc.ipa.test ipa-otpd[1636136]: ab@IPA.TEST: sent: 0 data: 200
May 02 18:51:29 dc.ipa.test ipa-otpd[1636136]: ab@IPA.TEST: ..sent: 200 data: 200
May 02 18:51:29 dc.ipa.test ipa-otpd[1636136]: ab@IPA.TEST: response sent: Access-Challenge
May 02 18:51:29 dc.ipa.test ipa-otpd[1636136]: Socket closed, shutting down...
First part of the output until ``idp query start`` is similar to RADIUS proxy
operation. Unlike RADIUS proxy, in the case of IdP communication, ``ipa-otpd``
first receives an initial state from the ``oidc_child`` process and sends it
back to the KDC within a RADIUS packet with ``Access-Challenge`` message.
The state is then transferred to the Kerberos client and results in a message
that instructs to visit the verification URI and enter the code. Some IdPs also
return a complete message to show, like in the case of Keycloak in our examples
above.
Once the Kerberos client returns, another ``ipa-otpd`` call is performed,
this time to request an access token::
May 02 18:51:50 dc.ipa.test systemd[1]: Started ipa-otpd service (PID 1473661/UID 0).
May 02 18:51:50 dc.ipa.test ipa-otpd[1636149]: LDAP: ldapi://%2Frun%2Fslapd-IPA-TEST.socket
May 02 18:51:50 dc.ipa.test ipa-otpd[1636149]: ab@IPA.TEST: request received
May 02 18:51:50 dc.ipa.test ipa-otpd[1636149]: ab@IPA.TEST: user query start
May 02 18:51:50 dc.ipa.test ipa-otpd[1636149]: ab@IPA.TEST: user query end: uid=ab,cn=users,cn=accounts,dc=ipa,dc=test
May 02 18:51:50 dc.ipa.test ipa-otpd[1636149]: ab@IPA.TEST: idp query start: cn=github,cn=idp,dc=ipa,dc=test
May 02 18:51:50 dc.ipa.test ipa-otpd[1636149]: ab@IPA.TEST: idp query end: github
May 02 18:51:50 dc.ipa.test ipa-otpd[1636149]: ab@IPA.TEST: oauth2 start: Get access token
May 02 18:51:50 dc.ipa.test ipa-otpd[1636149]: ab@IPA.TEST: Received: [abbra]
May 02 18:51:50 dc.ipa.test ipa-otpd[1636149]: ab@IPA.TEST: sent: 0 data: 20
May 02 18:51:50 dc.ipa.test ipa-otpd[1636149]: ab@IPA.TEST: ..sent: 20 data: 20
May 02 18:51:50 dc.ipa.test ipa-otpd[1636149]: ab@IPA.TEST: response sent: Access-Accept
May 02 18:51:50 dc.ipa.test ipa-otpd[1636149]: Socket closed, shutting down...
An access token request followed by the request to obtain a user information.
The resource owner's subject then compared with the value set in the LDAP entry
for this Kerberos principal with the help of ``--idp-user-id`` option. Subject's
field name is chosen through the same option to the IdP reference. If the check
is successful, ``ipa-otpd`` sends a RADIUS packet with ``Access-Accept``
response code.
Communication performed by ``oidc_child`` is not included into the journal logs
by default. If there are issues in accessing IdPs, a special option can be added
to ``/etc/ipa/default.conf`` to increase log level of ``oidc_child`` output. By
default, it is 0 and could be any number between 0 and 10::
[global]
oidc_child_debug_level=10
A value greater than 6 would include debug output from the ``libcurl`` utility::
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: oidc_child started.
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: Running with effective IDs: [0][0].
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: Running with real IDs [0][0].
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: JSON device code: [{"device_code":"f071833afe966eaf596d83646f55250cfdb57418","expires_in":899,"interval":5}].
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: Result does not contain the 'user_code' string.
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: Result does not contain the 'verification_uri' string.
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: Result does not contain the 'verification_url' string.
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: Result does not contain the 'verification_uri_complete' string.
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: Result does not contain the 'message' string.
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: device_code: [f071833afe966eaf596d83646f55250cfdb57418].
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: expires_in: [899].
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: interval: [5].
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: POST data: [grant_type=urn:ietf:params:oauth:grant-type:device_code&client_id=some-client-id&device_code=f071833afe966eaf596d83646f55250cfdb57418].
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * Trying 140.82.121.3:443...
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * Connected to github.com (140.82.121.3) port 443 (#0)
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * ALPN, offering h2
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * ALPN, offering http/1.1
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * successfully set certificate verify locations:
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * CAfile: /etc/pki/tls/certs/ca-bundle.crt
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * CApath: none
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * TLSv1.3 (OUT), TLS handshake, Client hello (1):
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * TLSv1.3 (IN), TLS handshake, Server hello (2):
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * TLSv1.3 (IN), TLS handshake, Certificate (11):
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * TLSv1.3 (IN), TLS handshake, CERT verify (15):
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * TLSv1.3 (IN), TLS handshake, Finished (20):
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * TLSv1.3 (OUT), TLS handshake, Finished (20):
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * ALPN, server accepted to use h2
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * Server certificate:
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * subject: C=US; ST=California; L=San Francisco; O=GitHub, Inc.; CN=github.com
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * start date: Mar 15 00:00:00 2022 GMT
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * expire date: Mar 15 23:59:59 2023 GMT
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * subjectAltName: host "github.com" matched cert's "github.com"
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * issuer: C=US; O=DigiCert Inc; CN=DigiCert TLS Hybrid ECC SHA384 2020 CA1
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * SSL certificate verify ok.
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * Using HTTP2, server supports multiplexing
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * Connection state changed (HTTP/2 confirmed)
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * Using Stream ID: 1 (easy handle 0x562cd1ee96e0)
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: > POST /login/oauth/access_token HTTP/2
Host: github.com
user-agent: SSSD oidc_child/0.0
accept: application/json
content-length: 139
content-type: application/x-www-form-urlencoded
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * We are completely uploaded and fine
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * old SSL session ID is stale, removing
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < HTTP/2 200
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < server: GitHub.com
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < date: Mon, 02 May 2022 18:51:50 GMT
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < content-type: application/json; charset=utf-8
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < vary: X-PJAX, X-PJAX-Container
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < permissions-policy: interest-cohort=()
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < etag: W/"some-e-tag-value"
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < cache-control: max-age=0, private, must-revalidate
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < strict-transport-security: max-age=31536000; includeSubdomains; preload
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < x-frame-options: deny
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < x-content-type-options: nosniff
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < x-xss-protection: 0
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < referrer-policy: origin-when-cross-origin, strict-origin-when-cross-origin
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < expect-ct: max-age=2592000, report-uri="https://api.github.com/_private/browser/errors"
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < content-security-policy: default-src 'none'; base-uri 'self'; block-all-mixed-content; child-src github.com/assets-cdn/worker/ gist.github.com/assets-cdn/worker/; connect-src 'self' uploads.git>
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < vary: Accept-Encoding, Accept, X-Requested-With
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < x-github-request-id: D1EA:541D:48A585:4BF8E5:62702846
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: <
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: {"access_token":"some-access-token","token_type":"bearer","scope":"user"}
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * Connection #0 to host github.com left intact
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: Result does not contain the 'id_token' string.
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: access_token: [some-access-token].
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: id_token: [(null)].
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * Trying 140.82.121.6:443...
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * Connected to api.github.com (140.82.121.6) port 443 (#0)
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * ALPN, offering h2
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * ALPN, offering http/1.1
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * successfully set certificate verify locations:
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * CAfile: /etc/pki/tls/certs/ca-bundle.crt
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * CApath: none
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * TLSv1.3 (OUT), TLS handshake, Client hello (1):
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * TLSv1.3 (IN), TLS handshake, Server hello (2):
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * TLSv1.3 (IN), TLS handshake, Certificate (11):
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * TLSv1.3 (IN), TLS handshake, CERT verify (15):
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * TLSv1.3 (IN), TLS handshake, Finished (20):
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * TLSv1.3 (OUT), TLS handshake, Finished (20):
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * ALPN, server accepted to use h2
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * Server certificate:
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * subject: C=US; ST=California; L=San Francisco; O=GitHub, Inc.; CN=*.github.com
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * start date: Mar 16 00:00:00 2022 GMT
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * expire date: Mar 16 23:59:59 2023 GMT
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * subjectAltName: host "api.github.com" matched cert's "*.github.com"
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * issuer: C=US; O=DigiCert Inc; CN=DigiCert TLS Hybrid ECC SHA384 2020 CA1
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * SSL certificate verify ok.
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * Using HTTP2, server supports multiplexing
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * Connection state changed (HTTP/2 confirmed)
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * Server auth using Bearer with user ''
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * Using Stream ID: 1 (easy handle 0x562cd1f92ae0)
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: > GET /user HTTP/2
Host: api.github.com
authorization: Bearer some-token-value
user-agent: SSSD oidc_child/0.0
accept: application/json
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * old SSL session ID is stale, removing
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < HTTP/2 200
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < server: GitHub.com
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < date: Mon, 02 May 2022 18:51:50 GMT
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < content-type: application/json; charset=utf-8
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < content-length: 1357
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < cache-control: private, max-age=60, s-maxage=60
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < vary: Accept, Authorization, Cookie, X-GitHub-OTP
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < etag: "some-e-tag-value"
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < last-modified: Mon, 14 Mar 2022 14:05:20 GMT
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < x-oauth-scopes: user
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < x-accepted-oauth-scopes:
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < x-oauth-client-id: some-client-id
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < x-github-media-type: github.v3
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < x-ratelimit-limit: 5000
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < x-ratelimit-remaining: 4996
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < x-ratelimit-reset: 1651520567
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < x-ratelimit-used: 4
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < x-ratelimit-resource: core
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < access-control-expose-headers: ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scop>
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < access-control-allow-origin: *
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < strict-transport-security: max-age=31536000; includeSubdomains; preload
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < x-frame-options: deny
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < x-content-type-options: nosniff
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < x-xss-protection: 0
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < referrer-policy: origin-when-cross-origin, strict-origin-when-cross-origin
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < content-security-policy: default-src 'none'
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < vary: Accept-Encoding, Accept, X-Requested-With
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < x-github-request-id: C5B8:5B48:4C0EB7:4D8AF2:62702846
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: <
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: {"login":"abbra","id":some-id,"node_id":"some-node","avatar_url":"some-avatar-url","gravatar_id":"","url":"some-user-url","html_ur
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: l":"some-url","followers_url":"some-api-url","following_url":"some-following-url","gists_url":"some-gists-url>
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * Connection #0 to host api.github.com left intact
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: userinfo: [{"login": "abbra", "id": some-id, "node_id": "some-node", "avatar_url": "some-avatar-rul", "gravatar_id": "", "url": "some-user-url", ">
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: User identifier: [abbra].
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: User identifier: [abbra].
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: oidc_child finished successful!
Don't forget to remove ``oidc_child_debug_level`` from the
``/etc/ipa/default.conf`` once troubleshooting is done. Information like above
often contains personal details of the user and should probably not stored in
the system journal.
+34 -15
View File
@@ -3,7 +3,11 @@
Vagrant.configure(2) do |config|
config.vm.box = "netoarmando/freeipa-workshop"
# Replace this with "fedora/34-cloud-base" (or latest) for a fresh box without
# pre-installed freeipa packages, you must also uncomment shell provisioning step
# at the bottom of this file.
# config.vm.box = "fedora/34-cloud-base"
config.vm.box = "freeipa/freeipa-workshop"
config.vm.synced_folder ".", "/vagrant", disabled: true
@@ -12,22 +16,21 @@ Vagrant.configure(2) do |config|
libvirt.memory = 1024
end
# Vagrant's "change host name" sets the short host name. Before
# we repair /etc/hosts (see below) let's reset /etc/hostname to
# the *full* host name
#
config.vm.provision "shell",
inline: "hostname --fqdn > /etc/hostname && hostname -F /etc/hostname"
# Vagrant's "change host name" capability for Fedora maps hostname
# to loopback. We must repair /etc/hosts
#
config.vm.provision "shell",
inline: "sed -ri 's/127\.0\.0\.1\s.*/127.0.0.1 localhost localhost.localdomain/' /etc/hosts"
config.vm.provider :virtualbox do |virtualbox|
virtualbox.memory = 1536
end
config.vm.define "server" do |server|
server.vm.network "private_network", ip: "192.168.33.10"
server.vm.hostname = "server.ipademo.local"
config.vm.provider "virtualbox" do |v|
v.memory = 1536
end
config.vm.provider "libvirt" do |v|
v.memory = 1536
end
end
config.vm.define "replica" do |replica|
@@ -39,7 +42,17 @@ Vagrant.configure(2) do |config|
replica.vm.provision "shell",
inline: 'echo "DNS1=192.168.33.10" >> /etc/sysconfig/network-scripts/ifcfg-eth1'
replica.vm.provision "shell",
inline: 'echo "nameserver 192.168.33.10" > /etc/resolv.conf'
inline: 'printf "DNS=192.168.33.10\nDomains=~." >> /etc/systemd/resolved.conf'
replica.vm.provision "shell",
inline: 'systemctl restart systemd-resolved'
config.vm.provider "virtualbox" do |v|
v.memory = 1536
end
config.vm.provider "libvirt" do |v|
v.memory = 1536
end
end
config.vm.define "client" do |client|
@@ -51,7 +64,9 @@ Vagrant.configure(2) do |config|
client.vm.provision "shell",
inline: 'echo "DNS1=192.168.33.10" >> /etc/sysconfig/network-scripts/ifcfg-eth1'
client.vm.provision "shell",
inline: 'echo "nameserver 192.168.33.10" > /etc/resolv.conf'
inline: 'printf "DNS=192.168.33.10\nDomains=~." >> /etc/systemd/resolved.conf'
client.vm.provision "shell",
inline: 'systemctl restart systemd-resolved'
client.vm.provision "shell",
inline: 'sudo sed -i "s/^/#/g" /etc/httpd/conf.d/ssl.conf'
client.vm.provision "shell",
@@ -60,4 +75,8 @@ Vagrant.configure(2) do |config|
inline: 'systemctl -q enable oddjobd && systemctl start oddjobd'
end
# Uncomment line below when using Fedora's cloud base box.
# config.vm.provision "shell", path: "workshop-install-packages.sh"
config.vm.provision "shell", path: "workshop-ipa-customizations.sh"
end
-14
View File
@@ -1,14 +0,0 @@
def application(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/plain')])
remote_user = environ.get('REMOTE_USER')
if remote_user is not None:
yield "LOGGED IN AS: {}\n".format(remote_user).encode('utf8')
else:
yield b"NOT LOGGED IN\n"
yield b"\nREMOTE_* REQUEST VARIABLES:\n\n"
for k, v in environ.items():
if k.startswith('REMOTE_'):
yield " {}: {}\n".format(k, v).encode('utf8')
+23 -33
View File
@@ -8,55 +8,45 @@ Requirements
------------
- Install packer (http://packer.io/)
- Clone the packer-templates repository
(https://github.com/kaorimatz/packer-templates)
- Install Vagrant, libvirt and VirtualBox
- Clone the Fedora kickstarts repo (https://pagure.io/fedora-kickstarts)
Packer template
---------------
Apply the following changes to the ``fedora-28-x86_64.json`` packer
template:
Packer template ``packer-template-fedora.json`` requires Fedora 34 kickstart file
used by Fedora to build vagrant images:
- Add the ``scripts/fedora/ipa.sh`` provisioner and copy (or
symlink) ``ipa.sh`` from *this* repository to ``scripts/fedora``.
This script installs the FreeIPA packages and creates other files
required for the workshop.
- Clone the repo and checkout latest Fedora release branch::
$ git clone https://pagure.io/fedora-kickstarts.git
$ cd fedora-kickstarts
$ git checkout f34
- Install ``pykickstart`` package which provides ``ksflatten`` tool::
$ sudo dnf install pykickstart
- Generate the ``anaconda-ks.cfg`` file needed by flattening vagrant kickstart files
and putting it onto the same folder as the packer template file::
$ ksflatten -c $FEDORA_KICKSTARTS_REPO/fedora-cloud-base-vagrant.ks > $FREEIPA_REPO/doc/workshop/anaconda-ks.cfg
Building the virtualbox image
Building the vagrant images
-----------------------------
Build the images::
$BIN_PACKER build -only=virtualbox-iso -var disk_size=4000 -var memory=1024 fedora-28-x86_64.json
Packer stores images and other data in ``/tmp`` during processing.
If you have limited space in ``/tmp`` set ``TMPDIR`` to point
somewhere else with more space.
$ cd $FREEIPA_REPO/doc/workshop
$ BIN_PACKER build packer-template-fedora.json
Building the QEMU/libvirt image
-------------------------------
Build the image::
$BIN_PACKER build -only=qemu -var disk_size=4000 -var memory=1024 fedora-28-x86_64.json
The output box is a gzip-compressed tarball. Unfortunately, the VM
image it contains is not sparse and will waste a lot of space (and
time) when Vagrant unpacks and imports the image. Therefore we
unpack, sparsify and repack the box::
mkdir box && cd box && tar -xf ../fedora-28-x86_64-libvirt.box
virt-sparsify --in-place box.img
tar -czf ../fedora-28-x86_64-libvirt.box * && cd .. && rm -rf box
Uploading boxes to HashiCorp Atlas
Uploading boxes to Vagrant Cloud
----------------------------------
Vagrant by default looks for boxes in a directory called *Atlas*.
Vagrant by default looks for boxes in a directory called *Vagrant Cloud*.
Therefore is is good to make images available there, so that people
can easily download them as part of workshop preparation.
@@ -31,5 +31,5 @@ Vagrant boxes
-------------
See ``building.rst`` for instructions on building Vagrant boxes.
At time of writing, the ``netoarmando/freeipa-workshop`` box is
FreeIPA 4.6.90 / Fedora 28, for the VirtualBox and libvirt providers.
At time of writing, the ``freeipa/freeipa-workshop`` box is
FreeIPA 4.9.3 / Fedora 34, for the VirtualBox and libvirt providers.
+77
View File
@@ -0,0 +1,77 @@
{
"builders": [{
"type": "qemu",
"iso_url": "{{user `iso_url`}}",
"iso_checksum": "{{user `iso_checksum`}}",
"output_directory": "output-{{user `box_name`}}-x86_64-{{build_type}}",
"vm_name": "packer-{{user `box_name`}}-x86_64",
"disk_size": "{{user `disk_size`}}",
"headless": "{{user `headless`}}",
"http_directory": ".",
"boot_wait": "5s",
"boot_command": [
"<tab> ",
"inst.ks=http://{{.HTTPIP}}:{{.HTTPPort}}/anaconda-ks.cfg ",
"biosdevname=0 ",
"net.ifnames=0 ",
"<enter>"
],
"ssh_timeout": "{{user `ssh_timeout`}}",
"ssh_username": "vagrant",
"ssh_password": "vagrant",
"shutdown_command": "sudo systemctl poweroff",
"qemuargs": [
["-m", "{{user `memory`}}"],
["-smp", "{{user `cpus`}}"]
]
}, {
"type": "virtualbox-iso",
"guest_os_type": "Fedora_64",
"iso_url": "{{user `iso_url`}}",
"iso_checksum": "{{user `iso_checksum`}}",
"output_directory": "output-{{user `box_name`}}-x86_64-{{build_type}}",
"vm_name": "packer-{{user `box_name`}}-x86_64",
"disk_size": "{{user `disk_size`}}",
"headless": "{{user `headless`}}",
"http_directory": ".",
"boot_wait": "5s",
"boot_command": [
"<tab> ",
"inst.ks=http://{{.HTTPIP}}:{{.HTTPPort}}/anaconda-ks.cfg ",
"biosdevname=0 ",
"net.ifnames=0 ",
"<enter>"
],
"ssh_timeout": "{{user `ssh_timeout`}}",
"ssh_username": "vagrant",
"ssh_password": "vagrant",
"shutdown_command": "sudo systemctl poweroff",
"vboxmanage": [
["modifyvm", "{{.Name}}", "--memory", "{{user `memory`}}"],
["modifyvm", "{{.Name}}", "--cpus", "{{user `cpus`}}"]
]
}],
"provisioners": [{
"type": "shell",
"scripts": [
"workshop-install-packages.sh"
]
}],
"post-processors": [{
"type": "vagrant",
"compression_level": "{{user `compression_level`}}",
"output": "{{user `box_name`}}-x86_64-{{.Provider}}.box"
}],
"variables": {
"box_name": "fedora-34",
"iso_url": "{{user `mirror`}}/releases/34/Server/x86_64/iso/Fedora-Server-netinst-x86_64-34-1.2.iso",
"iso_checksum": "file:{{user `mirror`}}/releases/34/Server/x86_64/iso/Fedora-Server-34-1.2-x86_64-CHECKSUM",
"compression_level": "9",
"cpus": "1",
"disk_size": "40000",
"headless": "false",
"memory": "1024",
"mirror": "http://download.fedoraproject.org/pub/fedora/linux",
"ssh_timeout": "60m"
}
}
+9 -6
View File
@@ -1,16 +1,19 @@
Local webserver
Troubleshooting
===============
Local webserver
---------------
Drop firewall::
sudo firewall-cmd --add-service=http
DNS / hosts file issues
=======================
-----------------------
Flush cache
-----------
^^^^^^^^^^^
Note: some resolvers cache NX.
@@ -24,7 +27,7 @@ Windows::
Virtual network
===============
---------------
If ``Vagrant::Errors::NetworkCollision`` occurs, try deleting host
network device, e.g.::
@@ -39,7 +42,7 @@ up::
Vagrant
=======
-------
If ``vagrant up`` fails to SSH into VM, delete
``~/.vagrant.d/insecure_private_key``. See
@@ -47,7 +50,7 @@ https://stackoverflow.com/questions/28284112/.
mod_lookup_identity
===================
-------------------
To flush cache::
@@ -0,0 +1,3 @@
#!/bin/bash
sudo dnf install -y freeipa-server freeipa-server-dns sssd-dbus mod_lookup_identity mod_authnz_pam haveged nmap-ncat nano pamtester bash-completion
sudo dnf clean all
@@ -1,5 +1,4 @@
#!/bin/bash
sudo dnf install -y freeipa-server freeipa-server-dns sssd-dbus mod_lookup_identity mod_authnz_pam haveged nmap-ncat nano pamtester bash-completion
sudo systemctl enable haveged
sudo sh -c "echo 'PS1=\"[\u@\h]\\\\$ \"' >> /etc/profile"
sudo sh -c "echo 'PS1=\"[\h]\\\\$ \"' >> /etc/bashrc"
@@ -11,10 +10,10 @@ sudo rm -f /etc/httpd/conf.d/welcome.conf
sudo sh -c "cat >/usr/share/httpd/app.py" <<EOF
def application(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/plain')])
logged_in = 'REMOTE_USER' in environ
remote_user = environ.get('REMOTE_USER')
if logged_in:
yield "LOGGED IN AS: {}\n".format(environ['REMOTE_USER']).encode('utf8')
if remote_user is not None:
yield "LOGGED IN AS: {}\n".format(remote_user).encode('utf8')
else:
yield b"NOT LOGGED IN\n"
@@ -37,3 +36,12 @@ sudo sh -c "cat >/etc/httpd/conf.d/app.conf" <<EOF
</Directory>
</VirtualHost>
EOF
# Vagrant's "change host name" sets the short host name. Before
# we repair /etc/hosts (see below) let's reset /etc/hostname to
# the *full* host name
hostname --fqdn > /etc/hostname && hostname -F /etc/hostname
# Vagrant's "change host name" capability for Fedora maps hostname
# to loopback. We must repair /etc/hosts
sed -ri 's/127\.0\.0\.1\s.*/127.0.0.1 localhost localhost.localdomain/' /etc/hosts
+13 -26
View File
@@ -38,7 +38,7 @@ Optional units—choose the topics that are relevant to you:
- `Unit 9: SELinux User Maps <9-selinux-user-map.rst>`_
- `Unit 10: SSH user and host key management <10-ssh-key-management.rst>`_
- `Unit 11: Kerberos ticket policy <11-kerberos-ticket-policy.rst>`_
- `Unit 12: External IdP support <12-external-idp-support.rst>`_
Editing files on VMs
--------------------
@@ -119,14 +119,11 @@ password everytime::
$ sudo gpasswd -a ${USER} libvirt
$ newgrp libvirt
On **Fedoda 28** you need to enable ``virtlogd``::
$ systemctl enable --now virtlogd.socket
Finally restart the services::
$ systemctl restart libvirtd
$ systemctl restart polkit
More information: https://docs.fedoraproject.org/en-US/quick-docs/getting-started-with-virtualization/
Otherwise, you will use VirtualBox and the ``virtualbox`` provider.
VirtualBox needs to build kernel modules, and that means that you must
@@ -150,7 +147,7 @@ in the transcript below (to make sure it wasn't tampered with)::
repo_gpgcheck=1
gpgkey=https://www.virtualbox.org/download/oracle_vbox.asc
$ sudo dnf install -y VirtualBox-5.2
$ sudo dnf install -y VirtualBox-6.1
Finally, load the kernel modules (you may need to restart your system for this to work)::
@@ -163,7 +160,7 @@ Mac OS X
Install Vagrant for Mac OS X from
https://www.vagrantup.com/downloads.html.
Install VirtualBox 5.2 for **OS X hosts** from
Install VirtualBox 6.1 for **OS X hosts** from
https://www.virtualbox.org/wiki/Downloads.
Install Git from https://git-scm.com/download/mac or via your
@@ -173,23 +170,12 @@ preferred package manager.
Debian / Ubuntu
^^^^^^^^^^^^^^^
Install Vagrant and Git::
Install Vagrant, Git and VirtualBox::
$ sudo apt-get install -y vagrant git
$ sudo apt-get install -y virtualbox-6.1
**Virtualbox 5.2** may be available from the system package manager,
depending your your release. Find out which version of VirtualBox is
available::
$ apt list virtualbox
Listing... done
virtualbox/bionic 5.2.10-dfsg-6 amd64
If version 5.2 is available, install it via ``apt-get``::
$ sudo apt-get install -y virtualbox
If VirtualBox 5.2 was not available in the official packages for
If VirtualBox 6.1 was not available in the official packages for
your release, follow the instructions at
https://www.virtualbox.org/wiki/Linux_Downloads to install it.
@@ -200,7 +186,7 @@ Windows
Install Vagrant via the ``.msi`` available from
https://www.vagrantup.com/downloads.html.
Install VirtualBox 5.2 for **Windows hosts** from
Install VirtualBox for **Windows hosts** from
https://www.virtualbox.org/wiki/Downloads.
You will also need to install an SSH client, and Git. Git for
@@ -216,18 +202,19 @@ workshop, which you will need locally.
::
$ git clone https://github.com/freeipa/freeipa-workshop.git
$ git clone https://github.com/freeipa/freeipa.git
$ cd freeipa/doc/workshop
Fetch Vagrant box
-----------------
Please fetch the Vagrant box prior to the workshop. It is > 600MB
Please fetch the Vagrant box prior to the workshop. It is > 700MB
so it may not be feasible to download it during the workshop.
::
$ vagrant box add netoarmando/freeipa-workshop
$ vagrant box add freeipa/freeipa-workshop
Add hosts file entries
+21 -4
View File
@@ -149,8 +149,8 @@
# RHEL 8.2+, F32+ has 3.58
%global nss_version 3.44.0-4
# RHEL 8.3+, F32+
%global sssd_version 2.4.0
# RHEL 8.7+, F35+, adds IdP integration
%global sssd_version 2.7.0
%define krb5_base_version %(LC_ALL=C /usr/bin/pkgconf --modversion krb5 | grep -Eo '^[^.]+\.[^.]+' || echo %krb5_version)
%global kdcproxy_version 0.4-3
@@ -323,7 +323,9 @@ BuildRequires: python3-wheel
%if %{with doc}
BuildRequires: python3-sphinx
BuildRequires: python3-m2r
BuildRequires: plantuml
BuildRequires: fontconfig
BuildRequires: google-noto-sans-vf-fonts
%endif
#
@@ -651,7 +653,12 @@ Requires: python3-sssdconfig >= %{sssd_version}
Requires: cyrus-sasl-gssapi%{?_isa}
Requires: chrony
Requires: krb5-workstation >= %{krb5_version}
Requires: authselect >= 0.4-2
# authselect: sssd profile with-subid
%if 0%{?fedora} >= 36
Requires: authselect >= 1.4.0
%else
Requires: authselect >= 1.2.5
%endif
Requires: curl
# NIS domain name config: /usr/lib/systemd/system/*-domainname.service
# All Fedora 28+ and RHEL8+ contain the service in hostname package
@@ -663,6 +670,7 @@ Requires: xmlrpc-c >= 1.27.4
Requires: jansson
%endif
Requires: sssd-ipa >= %{sssd_version}
Requires: sssd-idp >= %{sssd_version}
Requires: certmonger >= %{certmonger_version}
Requires: nss-tools >= %{nss_version}
Requires: bind-utils
@@ -695,6 +703,12 @@ Provides: %{name}-admintools = %{version}-%{release}
Conflicts: crypto-policies < 20200629-1
%endif
%if 0%{?rhel} == 9
# Conflict with crypto-policies < 20220223-1 to get upgraded AD-SUPPORT and
# AD-SUPPORT-LEGACY policy modules
Conflicts: crypto-policies < 20220223-1
%endif
%description client
IPA is an integrated solution to provide centrally managed Identity (users,
hosts, services), Authentication (SSO, 2FA), and Authorization
@@ -1053,6 +1067,7 @@ rm %{buildroot}/%{plugin_dir}/libipa_extdom_extop.la
rm %{buildroot}/%{plugin_dir}/libipa_range_check.la
rm %{buildroot}/%{plugin_dir}/libipa_otp_counter.la
rm %{buildroot}/%{plugin_dir}/libipa_otp_lasttoken.la
rm %{buildroot}/%{plugin_dir}/libipa_graceperiod.la
rm %{buildroot}/%{plugin_dir}/libtopology.la
rm %{buildroot}/%{_libdir}/krb5/plugins/kdb/ipadb.la
rm %{buildroot}/%{_libdir}/samba/pdb/ipasam.la
@@ -1236,6 +1251,7 @@ if [ $1 -gt 1 ] ; then
%{__python3} -c 'from ipaclient.install.client import configure_krb5_snippet; configure_krb5_snippet()' >>/var/log/ipaupgrade.log 2>&1
%{__python3} -c 'from ipaclient.install.client import update_ipa_nssdb; update_ipa_nssdb()' >>/var/log/ipaupgrade.log 2>&1
chmod 0600 /var/log/ipaupgrade.log
SSH_CLIENT_SYSTEM_CONF="/etc/ssh/ssh_config"
if [ -f "$SSH_CLIENT_SYSTEM_CONF" ]; then
sed -E --in-place=.orig 's/^(HostKeyAlgorithms ssh-rsa,ssh-dss)$/# disabled by ipa-client update\n# \1/' "$SSH_CLIENT_SYSTEM_CONF"
@@ -1411,6 +1427,7 @@ fi
%attr(755,root,root) %{plugin_dir}/libipa_sidgen.so
%attr(755,root,root) %{plugin_dir}/libipa_sidgen_task.so
%attr(755,root,root) %{plugin_dir}/libipa_extdom_extop.so
%attr(755,root,root) %{plugin_dir}/libipa_graceperiod.so
%attr(755,root,root) %{_libdir}/krb5/plugins/kdb/ipadb.so
%{_mandir}/man1/ipa-replica-conncheck.1*
%{_mandir}/man1/ipa-replica-install.1*
+3 -1
View File
@@ -7,4 +7,6 @@ systemdtmpfiles_DATA = \
CLEANFILES = $(systemdtmpfiles_DATA)
%: %.in Makefile
cp '$(srcdir)/$@.in' $@
sed \
-e 's|@HTTPD_GROUP[@]|$(HTTPD_GROUP)|g' \
'$(srcdir)/$@.in' >$@
+1 -1
View File
@@ -1,3 +1,3 @@
d /run/ipa 0711 root root
d /run/ipa/ccaches 6770 ipaapi ipaapi
a+ /run/ipa/ccaches - - - - g:apache:rwx
a+ /run/ipa/ccaches - - - - g:@HTTPD_GROUP@:rwx
@@ -220,7 +220,7 @@ def request_cert(reuse_existing, **kwargs):
sys.stderr.write(result.raw_error_output)
else:
# Write bytes directly
sys.stderr.buffer.write(result.raw_error_output) #pylint: disable=no-member
sys.stderr.buffer.write(result.raw_error_output)
sys.stderr.flush()
syslog.syslog(syslog.LOG_NOTICE,
+2 -2
View File
@@ -36,8 +36,8 @@ def run_operation(cmd):
result = ipautil.run(cmd, raiseonerr=False, env=os.environ)
# Write bytes directly
sys.stdout.buffer.write(result.raw_output) #pylint: disable=no-member
sys.stderr.buffer.write(result.raw_error_output) #pylint: disable=no-member
sys.stdout.buffer.write(result.raw_output)
sys.stderr.buffer.write(result.raw_error_output)
sys.stdout.flush()
sys.stderr.flush()
+1 -1
View File
@@ -58,4 +58,4 @@ attributeTypes: (2.16.840.1.113730.3.8.23.2 NAME 'ipaPwdMaxRepeat' EQUALITY inte
attributeTypes: (2.16.840.1.113730.3.8.23.3 NAME 'ipaPwdMaxSequence' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'IPA v4')
attributeTypes: (2.16.840.1.113730.3.8.23.4 NAME 'ipaPwdDictCheck' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE X-ORIGIN 'IPA v4')
attributeTypes: (2.16.840.1.113730.3.8.23.5 NAME 'ipaPwdUserCheck' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE X-ORIGIN 'IPA v4')
objectClasses: (2.16.840.1.113730.3.8.24.1 NAME 'ipaPwdPolicy' DESC 'IPA Password policy object class' SUP top MAY (ipaPwdMaxRepeat $ ipaPwdMaxSequence $ ipaPwdDictCheck $ ipaPwdUserCheck) X-ORIGIN 'IPA v4')
objectClasses: (2.16.840.1.113730.3.8.24.1 NAME 'ipaPwdPolicy' DESC 'IPA Password policy object class' SUP top MAY (ipaPwdMaxRepeat $ ipaPwdMaxSequence $ ipaPwdDictCheck $ ipaPwdUserCheck $ passwordGraceLimit) X-ORIGIN 'IPA v4')
+14
View File
@@ -18,3 +18,17 @@ objectClasses: (2.16.840.1.113730.3.8.24.2 NAME 'ipaSubordinateUid' DESC 'Subord
objectClasses: (2.16.840.1.113730.3.8.24.3 NAME 'ipaSubordinateGid' DESC 'Subordinate gids for users, see subgid(5)' SUP top AUXILIARY MUST ( ipaOwner $ ipaSubGidNumber $ ipaSubGidCount ) X-ORIGIN 'IPA v4.9')
objectClasses: (2.16.840.1.113730.3.8.24.4 NAME 'ipaSubordinateId' DESC 'Subordinate uid and gid for users' SUP top AUXILIARY MUST ( ipaOwner $ ipaSubUidNumber $ ipaSubUidCount $ ipaSubGidNumber $ ipaSubGidCount ) X-ORIGIN 'IPA v4.9')
objectClasses: (2.16.840.1.113730.3.8.24.5 NAME 'ipaSubordinateIdEntry' DESC 'Subordinate uid and gid entry' SUP top STRUCTURAL MUST ( ipaUniqueId ) MAY ( description ) X-ORIGIN 'IPA v4.9')
# External IdP support
attributeTypes: (2.16.840.1.113730.3.8.23.15 NAME 'ipaIdpDevAuthEndpoint' DESC 'Identity Provider Device Authorization Endpoint' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v4.9' )
attributeTypes: (2.16.840.1.113730.3.8.23.16 NAME 'ipaIdpAuthEndpoint' DESC 'Identity Provider Authorization Endpoint' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v4.9' )
attributeTypes: (2.16.840.1.113730.3.8.23.17 NAME 'ipaIdpTokenEndpoint' DESC 'Identity Provider Token Endpoint' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v4.9' )
attributeTypes: (2.16.840.1.113730.3.8.23.18 NAME 'ipaIdpClientId' DESC 'Identity Provider Client Identifier' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v4.9' )
attributeTypes: (2.16.840.1.113730.3.8.23.19 NAME 'ipaIdpClientSecret' DESC 'Identity Provider Client Secret' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 X-ORIGIN 'IPA v4.9' )
attributeTypes: (2.16.840.1.113730.3.8.23.20 NAME 'ipaIdpScope' DESC 'Identity Provider Scope' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v4.9' )
attributeTypes: (2.16.840.1.113730.3.8.23.21 NAME 'ipaIdpConfigLink' DESC 'Corresponding Identity Provider Configuration link' SUP distinguishedName EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE X-ORIGIN 'IPA v4.9')
attributeTypes: (2.16.840.1.113730.3.8.23.22 NAME 'ipaIdpSub' DESC 'Identity Provider User Subject' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v4.9' )
attributeTypes: (2.16.840.1.113730.3.8.23.23 NAME 'ipaIdpIssuerURL' DESC 'Identity Provider OIDC URL' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v4.9' )
attributeTypes: (2.16.840.1.113730.3.8.23.24 NAME 'ipaIdpUserInfoEndpoint' DESC 'Identity Provider UserInfo Endpoint' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v4.9' )
attributeTypes: (2.16.840.1.113730.3.8.23.25 NAME 'ipaIdpKeysEndpoint' DESC 'Identity Provider JWKS Endpoint' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v4.9' )
objectClasses: (2.16.840.1.113730.3.8.24.6 NAME 'ipaIdP' SUP top STRUCTURAL DESC 'Identity Provider Configuration' MUST ( cn ) MAY ( ipaIdpDevAuthEndpoint $ ipaIdpAuthEndpoint $ ipaIdpTokenEndpoint $ ipaIdpUserInfoEndpoint $ ipaIdpKeysEndpoint $ ipaIdpClientId $ description $ ipaIdpClientSecret $ ipaIdpScope $ ipaIdpIssuerURL $ ipaIdpSub ) X-ORIGIN 'IPA v4.9' )
objectClasses: (2.16.840.1.113730.3.8.24.7 NAME 'ipaIdpUser' SUP top AUXILIARY DESC 'User from an external Identity Provider ' MAY ( ipaIdpConfigLink $ ipaIdpSub ) X-ORIGIN 'IPA v4.9' )
+1
View File
@@ -98,6 +98,7 @@ dist_app_DATA = \
kdcproxy.wsgi \
ipakrb5.aug \
ipa.conf.template \
ipa-wsgi.conf.template \
ipa-kdc-proxy.conf.template \
ipa-pki-proxy.conf.template \
ipa-rewrite.conf.template \
+8
View File
@@ -307,3 +307,11 @@ dn: $SUFFIX
changetype: modify
add: aci
aci: (targetattr = "objectclass")(target = "ldap:///cn=certificate remove hold,cn=virtual operations,cn=etc,$SUFFIX" )(version 3.0 ; acl "permission:Certificate Remove Hold"; allow (write) groupdn = "ldap:///cn=Certificate Remove Hold,cn=permissions,cn=pbac,$SUFFIX";)
dn: cn=External IdP server Administrators,cn=privileges,cn=pbac,$SUFFIX
changetype: add
objectClass: top
objectClass: groupofnames
objectClass: nestedgroup
cn: External IdP server Administrators
description: External IdP server Administrators
-4
View File
@@ -32,10 +32,6 @@ dnaThreshold: eval($SUBID_DNA_THRESHOLD)
dnaSharedCfgDN: cn=subordinate-ids,cn=dna,cn=ipa,cn=etc,$SUFFIX
dnaExcludeScope: cn=provisioning,$SUFFIX
dnaInterval: eval($SUBID_COUNT)
# TODO: enable when 389-DS' DNA plugin supports dnaStepAttr
# dnaIntervalAttr: ipasubuidcount
# dnaIntervalAttr: ipasubgidcount
# dnaMaxInterval: eval($SUBID_COUNT)
# Enable the DNA plugin
dn: cn=Distributed Numeric Assignment Plugin,cn=plugins,cn=config
+1 -1
View File
@@ -8,7 +8,7 @@ objectClass: top
cn: dns
ipaConfigString: DNSVersion 1
ipaDNSVersion: 2
aci: (targetattr = "*")(version 3.0; acl "Allow read access"; allow (read,search,compare) groupdn = "ldap:///cn=Read DNS Entries,cn=permissions,cn=pbac,$SUFFIX" or userattr = "parent[0,1].managedby#GROUPDN";)
aci: (targetattr = "*")(version 3.0; acl "Read DNS entries from a zone"; allow (read,search,compare) userattr = "parent[0,1].managedby#GROUPDN";)
aci: (target = "ldap:///idnsname=*,cn=dns,$SUFFIX")(version 3.0;acl "Add DNS entries in a zone";allow (add) userattr = "parent[1].managedby#GROUPDN";)
aci: (target = "ldap:///idnsname=*,cn=dns,$SUFFIX")(version 3.0;acl "Remove DNS entries from a zone";allow (delete) userattr = "parent[1].managedby#GROUPDN";)
aci: (targetattr = "a6record || aaaarecord || afsdbrecord || aplrecord || arecord || certrecord || cn || cnamerecord || dhcidrecord || dlvrecord || dnamerecord || dnsclass || dnsttl || dsrecord || hinforecord || hiprecord || idnsallowdynupdate || idnsallowquery || idnsallowsyncptr || idnsallowtransfer || idnsforwarders || idnsforwardpolicy || idnsname || idnssecinlinesigning || idnssoaexpire || idnssoaminimum || idnssoamname || idnssoarefresh || idnssoaretry || idnssoarname || idnssoaserial || idnsupdatepolicy || idnszoneactive || ipseckeyrecord || keyrecord || kxrecord || locrecord || mdrecord || minforecord || mxrecord || naptrrecord || nsecrecord || nsec3paramrecord || nsrecord || nxtrecord || ptrrecord || rprecord || rrsigrecord || sigrecord || spfrecord || srvrecord || sshfprecord || tlsarecord || txtrecord || urirecord || unknownrecord ")(target = "ldap:///idnsname=*,cn=dns,$SUFFIX")(version 3.0;acl "Update DNS entries in a zone";allow (write) userattr = "parent[0,1].managedby#GROUPDN";)
+2 -2
View File
@@ -1,4 +1,4 @@
# VERSION 16 - DO NOT REMOVE THIS LINE
# VERSION 17 - DO NOT REMOVE THIS LINE
ProxyRequests Off
@@ -11,7 +11,7 @@ ProxyRequests Off
</LocationMatch>
# matches for admin port and installer
<LocationMatch "^/ca/admin/ca/getCertChain|^/ca/admin/ca/getConfigEntries|^/ca/admin/ca/getCookie|^/ca/admin/ca/getStatus|^/ca/admin/ca/securityDomainLogin|^/ca/admin/ca/getDomainXML|^/ca/admin/ca/updateNumberRange|^/ca/admin/ca/tokenAuthenticate|^/ca/admin/ca/updateNumberRange|^/ca/admin/ca/updateDomainXML|^/ca/admin/ca/updateConnector|^/ca/admin/ca/getSubsystemCert|^/kra/admin/kra/updateNumberRange|^/kra/admin/kra/getConfigEntries">
<LocationMatch "^/ca/admin/ca/getCertChain|^/ca/admin/ca/getConfigEntries|^/ca/admin/ca/getCookie|^/ca/admin/ca/getStatus|^/ca/admin/ca/securityDomainLogin|^/ca/admin/ca/getDomainXML|^/ca/admin/ca/updateNumberRange|^/ca/admin/ca/tokenAuthenticate|^/ca/admin/ca/updateNumberRange|^/ca/admin/ca/updateDomainXML|^/ca/admin/ca/updateConnector|^/ca/admin/ca/getSubsystemCert|^/kra/admin/kra/updateNumberRange|^/kra/admin/kra/getConfigEntries|^/kra/admin/kra/getStatus">
SSLOptions +StdEnvVars +ExportCertData +StrictRequire +OptRenegotiate
SSLVerifyClient none
ProxyPassMatch ajp://localhost:$DOGTAG_PORT $DOGTAG_AJP_SECRET
+53
View File
@@ -0,0 +1,53 @@
#
# VERSION 32 - DO NOT REMOVE THIS LINE
#
# This file may be overwritten on upgrades.
#
# FIXME: WSGISocketPrefix is a server-scope directive. The mod_wsgi package
# should really be fixed by adding this its /etc/httpd/conf.d/wsgi.conf:
WSGISocketPrefix $WSGI_PREFIX_DIR
# Configure mod_wsgi handler for /ipa
WSGIDaemonProcess ipa processes=$WSGI_PROCESSES threads=1 maximum-requests=500 \
user=ipaapi group=ipaapi display-name=%{GROUP} socket-timeout=2147483647 \
lang=C.UTF-8 locale=C.UTF-8
WSGIImportScript /usr/share/ipa/wsgi.py process-group=ipa application-group=ipa
<VirtualHost *:80>
ServerName $FQDN
ServerAlias ipa-ca.$DOMAIN
# Logging
CustomLog /var/log/httpd/ipa-access.log combined
ErrorLog /var/log/httpd/ipa-error.log
IncludeOptional $HTTPD_IPA_PKI_PROXY_CONF
Include $HTTPD_IPA_REWRITE_CONF
Include $HTTPD_IPA_CONF
</VirtualHost>
# the below section is only need if you have above 3 lines and want SSL
<VirtualHost *:443>
ServerName $FQDN
ServerAlias ipa-ca.$DOMAIN
# Logging
CustomLog /var/log/httpd/ipa-access.log combined
ErrorLog /var/log/httpd/ipa-error.log
# SSL
SSLEngine on
SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
SSLCACertificateFile /etc/ipa/ca.crt
SSLCertificateKeyFile /var/lib/ipa/private/httpd.key
SSLCertificateFile /var/lib/ipa/certs/httpd.crt
SSLCipherSuite PROFILE=SYSTEM
SSLProxyCipherSuite PROFILE=SYSTEM
#
IncludeOptional $HTTPD_IPA_KDCPROXY_CONF_SYMLINK
IncludeOptional $HTTPD_IPA_PKI_PROXY_CONF
Include $HTTPD_IPA_REWRITE_CONF
Include $HTTPD_IPA_CONF
</VirtualHost>
+15
View File
@@ -0,0 +1,15 @@
#
# VERSION 32 - DO NOT REMOVE THIS LINE
#
# This file may be overwritten on upgrades.
#
# FIXME: WSGISocketPrefix is a server-scope directive. The mod_wsgi package
# should really be fixed by adding this its /etc/httpd/conf.d/wsgi.conf:
WSGISocketPrefix $WSGI_PREFIX_DIR
# Configure mod_wsgi handler for /ipa
WSGIDaemonProcess ipa processes=$WSGI_PROCESSES threads=1 maximum-requests=500 \
user=ipaapi group=ipaapi display-name=%{GROUP} socket-timeout=2147483647 \
lang=C.UTF-8 locale=C.UTF-8
-7
View File
@@ -35,14 +35,7 @@ AddOutputFilterByType DEFLATE text/html text/plain text/xml \
application/javascript application/json text/css \
application/x-font-ttf
# FIXME: WSGISocketPrefix is a server-scope directive. The mod_wsgi package
# should really be fixed by adding this its /etc/httpd/conf.d/wsgi.conf:
WSGISocketPrefix $WSGI_PREFIX_DIR
# Configure mod_wsgi handler for /ipa
WSGIDaemonProcess ipa processes=$WSGI_PROCESSES threads=1 maximum-requests=500 \
user=ipaapi group=ipaapi display-name=%{GROUP} socket-timeout=2147483647 \
lang=C.UTF-8 locale=C.UTF-8
WSGIScriptAlias /ipa /usr/share/ipa/wsgi.py process-group=ipa \
application-group=%{GLOBAL}
WSGIScriptReloading Off
-1
View File
@@ -81,7 +81,6 @@ pki_skip_installation=False
pki_skip_sd_verify=False
pki_sslserver_token=internal
pki_ssl_server_token=%(pki_sslserver_token)s
pki_sslserver_nickname=Server-Cert cert-pki-ca
pki_sslserver_subject_dn=cn=%(ipa_fqdn)s,%(ipa_subject_base)s
+2 -1
View File
@@ -6,7 +6,8 @@
[realms]
$REALM = {
master_key_type = aes256-cts
master_key_type = $MASTER_KEY_TYPE
supported_enctypes = $SUPPORTED_ENCTYPES
max_life = 7d
max_renewable_life = 14d
acl_file = $KRB5KDC_KADM5_ACL
+4 -1
View File
@@ -28,6 +28,8 @@ ${FIPS}krbSupportedEncSaltTypes: camellia256-cts-cmac:normal
${FIPS}krbSupportedEncSaltTypes: camellia256-cts-cmac:special
krbMaxTicketLife: 86400
krbMaxRenewableAge: 604800
krbDefaultEncSaltTypes: aes256-sha2:special
krbDefaultEncSaltTypes: aes128-sha2:special
krbDefaultEncSaltTypes: aes256-cts:special
krbDefaultEncSaltTypes: aes128-cts:special
@@ -37,6 +39,7 @@ changetype: add
objectClass: top
objectClass: nsContainer
objectClass: krbPwdPolicy
objectClass: ipaPwdPolicy
krbMinPwdLife: 3600
krbPwdMinDiffChars: 0
krbPwdMinLength: 8
@@ -45,4 +48,4 @@ krbMaxPwdLife: 7776000
krbPwdMaxFailure: 6
krbPwdFailureCountInterval: 60
krbPwdLockoutDuration: 600
passwordGraceLimit: -1
+1 -1
View File
@@ -202,7 +202,7 @@ def main():
if not (user['uid'][0] in group['member_user'] and
group['cn'][0] in user['memberof_group']):
raise errors.RequirementError(name='admins group membership')
except errors.RequirementError as e:
except errors.RequirementError:
raise ScriptError(
"Must have administrative privileges to setup AD trusts on server"
)
+5
View File
@@ -131,6 +131,8 @@ def main():
else:
print("Enabling plugin")
# https://github.com/PyCQA/pylint/issues/872
# pylint: disable=unsupported-assignment-operation
if entry is None:
ld = LDAPUpdate()
if not ld.update(files):
@@ -139,6 +141,7 @@ def main():
else:
entry['nsslapd-pluginenabled'] = ['on']
api.Backend.ldap2.update_entry(entry)
# pylint: enable=unsupported-assignment-operation
except errors.ExecutionError as lde:
print("An error occurred while talking to the server.")
print(lde)
@@ -168,7 +171,9 @@ def main():
else:
print("Disabling plugin")
# pylint: disable=unsupported-assignment-operation
entry['nsslapd-pluginenabled'] = ['off']
# pylint: enable=unsupported-assignment-operation
api.Backend.ldap2.update_entry(entry)
except errors.DatabaseError as dbe:
print("An error occurred while talking to the server.")
+9 -6
View File
@@ -71,18 +71,21 @@ def parse_options():
if len(args):
n = len(args) - 1
for cmd in commands:
for cmd, args_info in commands.items():
if cmd == args[0]:
v = commands[cmd]
err = None
if n < v[0]:
err = v[3]
elif n > v[1]:
if n < args_info[0]:
err = args_info[3]
elif n > args_info[1]:
err = "too many arguments"
else:
valid_syntax = True
if err:
parser.error("Invalid syntax: %s\nUsage: %s [options] %s" % (err, cmd, v[2]))
parser.error(
"Invalid syntax: %s\nUsage: %s [options] %s" % (
err, cmd, args_info[2]
)
)
if not valid_syntax:
cmdstr = " | ".join(commands.keys())
+5 -5
View File
@@ -184,7 +184,7 @@ class IPACustodiaTester:
pkey = JWK(**dictkeys[usage_id])
local_pubkey = json_decode(pkey.export_public())
except Exception:
raise self.error(
raise self.error( # pylint: disable=raising-bad-type, #4772
"Failed to load and parse local JWK.", fatal=True
)
else:
@@ -193,7 +193,7 @@ class IPACustodiaTester:
))
if pkey.key_id != self.host_spn:
raise self.error(
raise self.error( # pylint: disable=raising-bad-type, #4772
"KID '{}' != host service principal name '{}' "
"(usage: {})".format(pkey.key_id, self.host_spn, usage),
fatal=True
@@ -210,7 +210,7 @@ class IPACustodiaTester:
try:
host_pubkey = json_decode(find_key(self.host_spn, usage_id))
except Exception:
raise self.error(
raise self.error( # pylint: disable=raising-bad-type, #4772
"Fetching host keys {} (usage: {}) failed.".format(
self.host_spn, usage),
fatal=True
@@ -223,7 +223,7 @@ class IPACustodiaTester:
if host_pubkey != local_pubkey:
self.debug("LDAP: '{}'".format(host_pubkey))
self.debug("Local: '{}'".format(local_pubkey))
raise self.error(
raise self.error( # pylint: disable=raising-bad-type, #4772
"Host key in LDAP does not match local key.",
fatal=True
)
@@ -235,7 +235,7 @@ class IPACustodiaTester:
try:
server_pubkey = json_decode(find_key(self.server_spn, usage_id))
except Exception:
raise self.error(
raise self.error( # pylint: disable=raising-bad-type, #4772
"Fetching server keys {} (usage: {}) failed.".format(
self.server_spn, usage),
fatal=True
+2
View File
@@ -155,7 +155,9 @@ def main():
elif entry.get('nsslapd-pluginenabled', [''])[0].lower() == 'off':
print("Enabling plugin")
# Already configured, just enable the plugin
# pylint: disable=unsupported-assignment-operation
entry['nsslapd-pluginenabled'] = ['on']
# pylint: enable=unsupported-assignment-operation
api.Backend.ldap2.update_entry(entry)
else:
print("Plugin already Enabled")
-1
View File
@@ -34,7 +34,6 @@ def main():
"File '{}' missing or not readable.\n".format(filename)
)
# pylint: disable=no-member
client = CustodiaClient(
client_service="{}@{}".format(service, env.host),
server=args.servername,
+2 -2
View File
@@ -319,7 +319,7 @@ class PortResponder(threading.Thread):
logger.debug('%d %s: Stopped listening', port, proto)
def _is_closing(self):
with self._close_lock: # pylint: disable=not-context-manager
with self._close_lock:
return self._close
def _bind_to_port(self, port, socket_type):
@@ -370,7 +370,7 @@ class PortResponder(threading.Thread):
def stop(self):
logger.debug('Stopping listening thread.')
with self._close_lock: # pylint: disable=not-context-manager
with self._close_lock:
self._close = True
+9 -6
View File
@@ -116,18 +116,21 @@ def parse_options():
if len(args):
n = len(args) - 1
for cmd in commands:
for cmd, args_info in commands.items():
if cmd == args[0]:
v = commands[cmd]
err = None
if n < v[0]:
err = v[3]
elif n > v[1]:
if n < args_info[0]:
err = args_info[3]
elif n > args_info[1]:
err = "too many arguments"
else:
valid_syntax = True
if err:
parser.error("Invalid syntax: %s\nUsage: %s [options] %s" % (err, cmd, v[2]))
parser.error(
"Invalid syntax: %s\nUsage: %s [options] %s" % (
err, cmd, args_info[2]
)
)
if not valid_syntax:
cmdstr = " | ".join(commands.keys())
+6
View File
@@ -92,9 +92,15 @@ Do not configure OpenSSH client.
\fB\-\-no\-sshd\fR
Do not configure OpenSSH server.
.TP
\fB\-\-subid\fR
Configure SSSD as data source for subid.
.TP
\fB\-\-skip\-conncheck\fR
Skip connection check to remote master
.TP
\fB\-\-skip\-mem\-check\fR
Skip checking for minimum required memory
.TP
\fB\-d\fR, \fB\-\-debug
Enable debug logging when more verbose output is needed
.TP
+6
View File
@@ -80,6 +80,12 @@ Do not configure OpenSSH client.
\fB\-\-no\-sshd\fR
Do not configure OpenSSH server.
.TP
\fB\-\-subid\fR
Configure SSSD as data source for subid.
.TP
\fB\-\-skip\-mem\-check\fR
Skip checking for minimum required memory
.TP
\fB\-d\fR, \fB\-\-debug\fR
Enable debug logging when more verbose output is needed.
.TP
@@ -318,6 +318,7 @@ define([
$type: 'text',
name: 'pagination_size',
label: '@i18n:customization.table_pagination',
required: true,
validators: ['positive_integer']
}
]
+1
View File
@@ -58,6 +58,7 @@ define([
'./topology',
'./user',
'./vault',
'./idp',
'dojo/domReady!'
],function(app_container) {
return app_container;
+1 -5
View File
@@ -184,12 +184,8 @@ return {
measurement_unit: 'seconds'
},
{
$type: 'radio',
$type: 'checkbox',
name: 'idnsallowdynupdate',
options: [
{ value: 'TRUE', label: '@i18n:true' },
{ value: 'FALSE', label: '@i18n:false' }
]
},
{
$type: 'textarea',
Loaded 100 of 361 files, more files were not shown because too many files have changed in this diff. Show more