File: test_subids.py

package info (click to toggle)
freeipa 4.13.1-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 367,240 kB
  • sloc: javascript: 562,763; python: 310,289; ansic: 49,809; sh: 7,176; makefile: 2,589; xml: 343; sed: 16
file content (308 lines) | stat: -rw-r--r-- 11,046 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
#
# Copyright (C) 2021  FreeIPA Contributors see COPYING for license
#

"""Tests for subordinate ids
"""
import os

from ipalib.constants import (
    SUBID_COUNT, SUBID_RANGE_START, SUBID_RANGE_MAX, SUBID_DNA_THRESHOLD
)
from ipaplatform.paths import paths
from ipapython.dn import DN
from ipatests.pytest_ipa.integration import tasks
from ipatests.test_integration.base import IntegrationTest


class TestSubordinateId(IntegrationTest):
    num_replicas = 0
    num_clients = 1
    topology = "star"

    def _parse_result(self, result):
        # ipa CLI should get an --outform json option
        info = {}
        for line in result.stdout_text.split("\n"):
            line = line.strip()
            if line:
                if ":" not in line:
                    continue
                k, v = line.split(":", 1)
                k = k.strip()
                v = v.strip()
                try:
                    v = int(v, 10)
                except ValueError:
                    if v == "FALSE":
                        v = False
                    elif v == "TRUE":
                        v = True
                info.setdefault(k.lower(), []).append(v)

        for k, v in info.items():
            if len(v) == 1:
                info[k] = v[0]
            else:
                info[k] = set(v)
        return info

    def assert_subid_info(self, uid, info):
        assert info["ipauniqueid"]
        basedn = self.master.domain.basedn
        assert info["ipaowner"] == f"uid={uid},cn=users,cn=accounts,{basedn}"
        assert info["ipasubuidnumber"] == info["ipasubuidnumber"]
        assert info["ipasubuidnumber"] >= SUBID_RANGE_START
        assert info["ipasubuidnumber"] <= SUBID_RANGE_MAX
        assert info["ipasubuidcount"] == SUBID_COUNT
        assert info["ipasubgidnumber"] == info["ipasubgidnumber"]
        assert info["ipasubgidnumber"] == info["ipasubuidnumber"]
        assert info["ipasubgidcount"] == SUBID_COUNT

    def assert_subid(self, uid, *, match):
        cmd = ["ipa", "subid-find", "--raw", "--owner", uid]
        result = self.master.run_command(cmd, raiseonerr=False)
        if not match:
            assert result.returncode >= 1
            if result.returncode == 1:
                assert "0 subordinate ids matched" in result.stdout_text
            elif result.returncode == 2:
                assert "user not found" in result.stderr_text
            return None
        else:
            assert result.returncode == 0
            assert "1 subordinate id matched" in result.stdout_text
            info = self._parse_result(result)
            self.assert_subid_info(uid, info)
            self.master.run_command(
                ["ipa", "subid-show", info["ipauniqueid"]]
            )
            return info

    def subid_generate(self, uid, **kwargs):
        cmd = ["ipa", "subid-generate"]
        if uid is not None:
            cmd.extend(("--owner", uid))
        return self.master.run_command(cmd, **kwargs)

    def test_dna_config(self):
        conn = self.master.ldap_connect()
        dna_cfg = DN(
            "cn=Subordinate IDs,cn=Distributed Numeric Assignment Plugin,"
            "cn=plugins,cn=config"
        )
        entry = conn.get_entry(dna_cfg)

        def single_int(key):
            return int(entry.single_value[key])

        assert single_int("dnaInterval") == SUBID_COUNT
        assert single_int("dnaThreshold") == SUBID_DNA_THRESHOLD
        assert single_int("dnaMagicRegen") == -1
        assert single_int("dnaMaxValue") == SUBID_RANGE_MAX
        assert set(entry["dnaType"]) == {"ipasubgidnumber", "ipasubuidnumber"}

    def test_auto_generate_subid(self):
        uid = "testuser_auto1"
        passwd = "Secret123"
        tasks.create_active_user(self.master, uid, password=passwd)

        tasks.kinit_admin(self.master)
        self.assert_subid(uid, match=False)

        # add subid by name
        self.subid_generate(uid)
        info = self.assert_subid(uid, match=True)

        # second generate fails due to unique index on ipaowner
        result = self.subid_generate(uid, raiseonerr=False)
        assert result.returncode > 0
        assert f'for user "{uid}" already exists' in result.stderr_text

        # check matching
        subuid = info["ipasubuidnumber"]
        for offset in (0, 1, 65535):
            result = self.master.run_command(
                ["ipa", "subid-match", f"--subuid={subuid + offset}", "--raw"]
            )
            match = self._parse_result(result)
            self.assert_subid_info(uid, match)

    def test_ipa_subid_script(self):
        tasks.kinit_admin(self.master)

        tool = os.path.join(paths.LIBEXEC_IPA_DIR, "ipa-subids")
        users = []
        for i in range(1, 11):
            uid = f"testuser_script{i}"
            users.append(uid)
            tasks.user_add(self.master, uid)
            self.assert_subid(uid, match=False)

        cmd = [tool, "--verbose", "--group", "ipausers"]
        self.master.run_command(cmd)

        for uid in users:
            self.assert_subid(uid, match=True)

    def test_subid_selfservice(self):
        uid1 = "testuser_selfservice1"
        uid2 = "testuser_selfservice2"
        password = "Secret123"
        role = "Subordinate ID Selfservice User"

        tasks.create_active_user(self.master, uid1, password=password)
        tasks.create_active_user(self.master, uid2, password=password)

        tasks.kinit_user(self.master, uid1, password=password)
        self.assert_subid(uid1, match=False)
        result = self.subid_generate(uid1, raiseonerr=False)
        assert result.returncode > 0
        result = self.subid_generate(None, raiseonerr=False)
        assert result.returncode > 0

        tasks.kinit_admin(self.master)
        self.master.run_command(
            ["ipa", "role-add-member", role, "--groups=ipausers"]
        )

        try:
            tasks.kinit_user(self.master, uid1, password)
            self.subid_generate(uid1)
            self.assert_subid(uid1, match=True)

            # add subid from whoami
            tasks.kinit_as_user(self.master, uid2, password=password)
            self.subid_generate(None)
            self.assert_subid(uid2, match=True)
        finally:
            tasks.kinit_admin(self.master)
            self.master.run_command(
                ["ipa", "role-remove-member", role, "--groups=ipausers"]
            )

    def test_subid_useradmin(self):
        tasks.kinit_admin(self.master)

        uid_useradmin = "testuser_usermgr_mgr1"
        role = "User Administrator"
        uid = "testuser_usermgr_user1"
        password = "Secret123"

        # create user administrator
        tasks.create_active_user(
            self.master, uid_useradmin, password=password
        )
        # add user to user admin group
        tasks.kinit_admin(self.master)
        self.master.run_command(
            ["ipa", "role-add-member", role, f"--users={uid_useradmin}"],
        )
        # kinit as user admin
        tasks.kinit_user(self.master, uid_useradmin, password)

        # create new user as user admin
        tasks.user_add(self.master, uid)
        # assign new subid to user (with useradmin credentials)
        self.subid_generate(uid)

        # test that user admin can preserve and delete users with subids
        self.master.run_command(["ipa", "user-del", "--preserve", uid])
        # XXX does not work, see subordinate-ids.md
        # subid should still exist
        # self.assert_subid(uid, match=True)
        # final delete should remove the user and subid
        self.master.run_command(["ipa", "user-del", uid])
        self.assert_subid(uid, match=False)

    def tset_subid_auto_assign(self):
        tasks.kinit_admin(self.master)
        uid = "testuser_autoassign_user1"

        self.master.run_command(
            ["ipa", "config-mod", "--user-default-subid=true"]
        )

        try:
            tasks.user_add(self.master, uid)
            self.assert_subid(uid, match=True)
        finally:
            self.master.run_command(
                ["ipa", "config-mod", "--user-default-subid=false"]
            )

    def test_idrange_subid(self):
        tasks.kinit_admin(self.master)

        range_name = f"{self.master.domain.realm}_subid_range"

        result = self.master.run_command(
            ["ipa", "idrange-show", range_name, "--raw"]
        )
        info = self._parse_result(result)

        # see https://github.com/SSSD/sssd/issues/5571
        assert info["iparangetype"] == "ipa-ad-trust"
        assert info["ipabaseid"] == SUBID_RANGE_START
        assert info["ipaidrangesize"] == SUBID_RANGE_MAX - SUBID_RANGE_START
        assert info["ipabaserid"] < SUBID_RANGE_START
        assert "ipasecondarybaserid" not in info
        assert info["ipanttrusteddomainsid"].startswith(
            "S-1-5-21-738065-838566-"
        )

    def test_subid_stats(self):
        tasks.kinit_admin(self.master)
        self.master.run_command(["ipa", "subid-stats"])

    def test_sudid_match_shows_uid(self):
        """
        Test if subid-match command shows UID of the owner instead of DN

        https://pagure.io/freeipa/issue/8977
        """
        uid = "admin"
        self.subid_generate(uid)
        info = self.assert_subid(uid, match=True)
        subuid = info["ipasubuidnumber"]
        result = self.master.run_command(["ipa", "subid-match",
                                          f"--subuid={subuid}"])
        owner = self._parse_result(result)["owner"]
        assert owner == uid

    def test_nsswitch_doesnot_contain_subid_entry(self):
        """
        This testcase checks that when ipa-client-install
        is installed without subid option, the nsswitch.conf
        does not contain subid entry or does not use sss as
        source for subid
        """
        cmd = self.clients[0].run_command(
            ["grep", "^subid", "/etc/nsswitch.conf"],
            raiseonerr=False
        )
        # a source is defined for the subid database.
        # Ensure it is not "sss"
        if cmd.returncode == 0:
            assert 'sss' not in cmd.stdout_text
        else:
            # grep command returncode 1 means no matching line
            # was found = no source is defined for the subid database,
            # which is valid other return codes would
            # mean an error occurred
            assert cmd.returncode == 1

    def test_nsswitch_is_updated_with_subid_entry(self):
        """
        This test case checks that when ipa-client-install
        is installed with --subid option, the nsswitch.conf
        file is modified with the entry 'subid: sss'
        """
        tasks.uninstall_client(self.clients[0])
        tasks.install_client(self.master, self.clients[0],
                             extra_args=['--subid'])
        cmd = self.clients[0].run_command(
            ["grep", "^subid", "/etc/nsswitch.conf"]
        )
        subid = cmd.stdout_text.split()
        assert ['subid:', 'sss'] == subid