diff --git a/README-user.md b/README-user.md
index 064a192f..528f0998 100644
--- a/README-user.md
+++ b/README-user.md
@@ -41,7 +41,7 @@ ipaserver.test.local
```
-Example playbook to add users:
+Example playbook to ensure a user is present:
```yaml
---
@@ -50,7 +50,7 @@ Example playbook to add users:
become: true
tasks:
- # Create user pinky
+ # Ensure user pinky is present
- ipauser:
ipaadmin_password: MyPassword123
name: pinky
@@ -64,7 +64,7 @@ Example playbook to add users:
password: "no-brain"
update_password: on_create
- # Create user brain
+ # Ensure user brain is present
- ipauser:
ipaadmin_password: MyPassword123
name: brain
@@ -74,6 +74,75 @@ Example playbook to add users:
`update_password` controls if a password for a user will be set in present state only on creation or every time (always).
+These two `ipauser` module calls can be combined into one with the `users` variable:
+
+```yaml
+---
+- name: Playbook to handle users
+ hosts: ipaserver
+ become: true
+
+ tasks:
+ # Ensure users pinky and brain are present
+ - ipauser:
+ ipaadmin_password: MyPassword123
+ users:
+ - name: pinky
+ first: pinky
+ last: Acme
+ uid: 10001
+ gid: 100
+ phone: "+555123457"
+ email: pinky@acme.com
+ passwordexpiration: "2023-01-19 23:59:59"
+ password: "no-brain"
+ - name: brain
+ first: brain
+ last: Acme
+ update_password: on_create
+```
+
+You can also alternatively use a json file containing the users, here `users_present.json`:
+
+```json
+{
+ "users": [
+ {
+ "name": "user1",
+ "first": "First 1",
+ "last": "Last 1"
+ },
+ {
+ "name": "user2",
+ "first": "First 2",
+ "last": "Last 2"
+ },
+ ...
+ ]
+}
+```
+
+And ensure the presence of the users with this example playbook:
+
+```yaml
+---
+- name: Tests
+ hosts: ipaserver
+ become: true
+ gather_facts: false
+
+ tasks:
+ - name: Include users_present.json
+ include_vars:
+ file: users_present.json
+
+ - name: Users present
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ users: "{{ users }}"
+```
+
+
Example playbook to delete a user, but preserve it:
```yaml
@@ -91,6 +160,28 @@ Example playbook to delete a user, but preserve it:
state: absent
```
+This can also be done with the `users` variable containing only names, this can be combined into one module call:
+
+Example playbook to delete a user is absent, but preserved:
+
+```yaml
+---
+- name: Playbook to handle users
+ hosts: ipaserver
+ become: true
+
+ tasks:
+ # Remove but preserve user pinky
+ - ipauser:
+ ipaadmin_password: MyPassword123
+ users:
+ - name: pinky
+ preserve: yes
+ state: absent
+```
+
+This can also be done as an alternative with the `users` variable containing only names.
+
Example playbook to undelete a preserved user.
@@ -108,6 +199,8 @@ Example playbook to undelete a preserved user.
state: undeleted
```
+This can also be done as an alternative with the `users` variable containing only names.
+
Example playbook to disable a user:
@@ -125,6 +218,8 @@ Example playbook to disable a user:
state: disabled
```
+This can also be done as an alternative with the `users` variable containing only names.
+
Example playbook to enable users:
@@ -142,6 +237,8 @@ Example playbook to enable users:
state: enabled
```
+This can also be done as an alternative with the `users` variable containing only names.
+
Example playbook to unlock users:
@@ -160,7 +257,7 @@ Example playbook to unlock users:
```
-Example playbook to delete users:
+Example playbook to ensure users are absent:
```yaml
---
@@ -169,13 +266,34 @@ Example playbook to delete users:
become: true
tasks:
- # Remove user pinky and brain
+ # Ensure users pinky and brain are absent
- ipauser:
ipaadmin_password: MyPassword123
name: pinky,brain
state: absent
```
+This can also be done as an alternative with the `users` variable containing only names.
+
+
+Example playbook to ensure users are absent:
+
+```yaml
+---
+- name: Playbook to handle users
+ hosts: ipaserver
+ become: true
+
+ tasks:
+ # Ensure users pinky and brain are absent
+ - ipauser:
+ ipaadmin_password: MyPassword123
+ users:
+ - name: pinky
+ - name: brain
+ state: absent
+```
+
Variables
=========
@@ -183,11 +301,28 @@ Variables
ipauser
-------
+**General Variables:**
+
Variable | Description | Required
-------- | ----------- | --------
`ipaadmin_principal` | The admin principal is a string and defaults to `admin` | no
`ipaadmin_password` | The admin password is a string and is required if there is no admin ticket available on the node | no
-`name` | The list of user name strings. | no
+`name` | The list of user name strings. `name` with *user variables* or `users` containing *user variables* need to be used. | no
+**User variables** | Only used with `name` variable in the first level. | no
+`users` | The list of user dicts. Each `users` dict entry can contain **user variables**.
There is one required option in the `users` dict:| no
+ | `name` - The user name string of the entry. | yes
+ | **User variables** | no
+`preserve` | Delete a user, keeping the entry available for future use. (bool) | no
+`update_password` | Set password for a user in present state only on creation or always. It can be one of `always` or `on_create` and defaults to `always`. | no
+`preserve` | Delete a user, keeping the entry available for future use. (bool) | no
+`state` | The state to ensure. It can be one of `present`, `absent`, `enabled`, `disabled`, `unlocked` or `undeleted`, default: `present`. Only `names` or `users` with only `name` set are allowed if state is not `present`. | yes
+
+
+
+**User Variables:**
+
+Variable | Description | Required
+-------- | ----------- | --------
`first` \| `givenname` | The first name string. | no
`last` | The last name | no
`fullname` \| `cn` | The full name string. | no
@@ -195,17 +330,40 @@ Variable | Description | Required
`homedir` | The home directory string. | no
`shell` \| `loginshell` | The login shell string. | no
`email` | List of email address strings. | no
-`principalname` \| `krbprincipalname` | The kerberos principal sptring. | no
+`principal` \| `principalnam` \| `krbprincipalname` | The kerberos principal sptring. | no
+`principalexpiration` \| `krbprincipalexpiration` | The kerberos principal expiration date. Possible formats: `YYYYMMddHHmmssZ`, `YYYY-MM-ddTHH:mm:ssZ`, `YYYY-MM-ddTHH:mmZ`, `YYYY-MM-ddZ`, `YYYY-MM-dd HH:mm:ssZ` or `YYYY-MM-dd HH:mmZ`. The trailing 'Z' can be skipped. | no
`passwordexpiration` \| `krbpasswordexpiration` | The kerberos password expiration date. Possible formats: `YYYYMMddHHmmssZ`, `YYYY-MM-ddTHH:mm:ssZ`, `YYYY-MM-ddTHH:mmZ`, `YYYY-MM-ddZ`, `YYYY-MM-dd HH:mm:ssZ` or `YYYY-MM-dd HH:mmZ`. The trailing 'Z' can be skipped. | no
`password` | The user password string. | no
+`random` | Generate a random user password | no
`uid` \| `uidnumber` | The UID integer. | no
`gid` \| `gidnumber` | The GID integer. | no
+`city` | City | no
+`userstate` \| `st` | State/Province | no
+`postalcode` \| `zip` | Postalcode/ZIP | no
`phone` \| `telephonenumber` | List of telephone number strings, | no
+`mobile` | List of mobile telephone number strings. | no
+`pager` | List of pager number strings. | no
+`fax` \| `facsimiletelephonenumber` | List of fax number strings. | no
+`orgunit` | The Organisation unit. | no
`title` | The job title string. | no
-~~`sshpubkey` \| `ipasshpubkey`~~ | ~~List of SSH public keys.~~ | ~~no~~
-`update_password` | Set password for a user in present state only on creation or always. It can be one of `always` or `on_create` and defaults to `always`. | no
-`preserve` | Delete a user, keeping the entry available for future use. (bool) | no
-`state` | The state to ensure. It can be one of `present`, `absent`, `enabled`, `disabled`, `unlocked` or `undeleted`, default: `present`. | yes
+`manager` | List of manager user names. | no
+`carlicense` | List of car licenses. | no
+`sshpubkey` \| `ipasshpubkey` | List of SSH public keys. | no
+`userauthtype` | List of supported user authentication types. Choices: `password`, `radius` and `otp` | no
+`userclass` | User category. (semantics placed on this attribute are for local interpretation). | no
+`radius` | RADIUS proxy configuration | no
+`radiususer` | RADIUS proxy username | no
+`departmentnumber` | Department Number | no
+`employeenumber` | Employee Number | no
+`employeetype` | Employee Type | no
+`preferredlanguage` | Preferred Language | no
+`certificate` | List of base-64 encoded user certificates. | no
+`certmapdata` | List of certificate mappings. Either `certificate` or `issuer` together with `subject` need to be specified.
Options: | no
+ | `certificate` - Base-64 encoded user certificate | no
+ | `issuer` - Issuer of the certificate | no
+ | `subject` - Subject of the certificate | no
+`noprivate` | Do not create user private group. (bool) | no
+`nomembers` | Suppress processing of membership attributes. (bool) | no
Authors
diff --git a/playbooks/user/user_certificate_absent.yml b/playbooks/user/user_certificate_absent.yml
new file mode 100644
index 00000000..d50b40f4
--- /dev/null
+++ b/playbooks/user/user_certificate_absent.yml
@@ -0,0 +1,16 @@
+---
+- name: Test user certificates
+ hosts: ipaserver
+ become: true
+ gather_facts: false
+
+ tasks:
+ - name: User test cert absent
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: test
+ certificate:
+ - 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
+ state: absent
diff --git a/playbooks/user/user_certificate_present.yml b/playbooks/user/user_certificate_present.yml
new file mode 100644
index 00000000..b3220846
--- /dev/null
+++ b/playbooks/user/user_certificate_present.yml
@@ -0,0 +1,15 @@
+---
+- name: Test user certificates
+ hosts: ipaserver
+ become: true
+ gather_facts: false
+
+ tasks:
+ - name: User test cert present
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: test
+ certificate:
+ - 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
diff --git a/playbooks/user/user_present.yml b/playbooks/user/user_present.yml
new file mode 100644
index 00000000..9abf26a9
--- /dev/null
+++ b/playbooks/user/user_present.yml
@@ -0,0 +1,40 @@
+---
+- name: Tests
+ hosts: ipaserver
+ become: true
+ gather_facts: false
+
+ tasks:
+ - name: User pinky present
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: pinky
+ uid: 10001
+ gid: 100
+ phone: "+555123457"
+ email: pinky@acme.com
+ principalexpiration: "20220119235959"
+ passwordexpiration: "2022-01-19 23:59:59"
+ first: pinky
+ last: Acme
+ initials: pa
+ principal: pa
+ random: yes
+ city: PinkyCity
+ userstate: PinkyState
+ postalcode: 321
+ mobile: "+555123458,+555123459"
+ pager: "+555123450,+555123451"
+ fax: "+555123452,+555123453"
+ orgunit: PinkyOrgUnit
+ manager: manager1,manager2
+ update_password: on_create
+ carlicense: PinkyCarLicense1,PinkyCarLicense2
+ userauthtype: password,radius,otp
+ userclass: PinkyUserClass
+ departmentnumber: "1234"
+ employeenumber: "0815"
+ employeetype: "PinkyExmployeeType"
+ preferredlanguage: "en"
+ noprivate: yes
+ nomembers: false
diff --git a/playbooks/user/users_absent.yml b/playbooks/user/users_absent.yml
new file mode 100644
index 00000000..a592a062
--- /dev/null
+++ b/playbooks/user/users_absent.yml
@@ -0,0 +1,42 @@
+---
+- name: Tests
+ hosts: ipaserver
+ become: true
+ gather_facts: false
+
+ tasks:
+ - name: Users user1..10 absent
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ users:
+ - name: user1
+ givenname: user1
+ last: Last
+ - name: user2
+ first: user2
+ last: Last
+ - name: user3
+ first: user3
+ last: Last
+ - name: user4
+ first: user4
+ last: Last
+ - name: user5
+ first: user5
+ last: Last
+ - name: user6
+ first: user6
+ last: Last
+ - name: user7
+ first: user7
+ last: Last
+ - name: user8
+ first: user8
+ last: Last
+ - name: user9
+ first: user9
+ last: Last
+ - name: user10
+ first: user10
+ last: Last
+ state: absent
diff --git a/playbooks/user/users_certificate_absent.yml b/playbooks/user/users_certificate_absent.yml
new file mode 100644
index 00000000..0963e4fe
--- /dev/null
+++ b/playbooks/user/users_certificate_absent.yml
@@ -0,0 +1,17 @@
+---
+- name: Test user certificates
+ hosts: ipaserver
+ become: true
+ gather_facts: false
+
+ tasks:
+ - name: User test cert absent
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ users:
+ - name: test
+ certificate:
+ - MIIC/zCCAeegAwIBAgIUZGHLaSYg1myp6EI4VGWSC27vOrswDQYJKoZIhvcNAQELBQAwDzENMAsGA1UEAwwEdGVzdDAeFw0xOTEwMTQxNjI4MzVaFw0yMDEwMTMxNjI4MzVaMA8xDTALBgNVBAMMBHRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDER/lB8wUAmPTSwSc/NOXNlzdpPOQDSwrhKH6XsqZF4KpQoSY/nmCjAhJmOVpOUo4K2fGRZ0yAH9fkGv6yJP6c7IAFjLeec7GPHVwN4bZrP1DXfTAmfmXhcRQbCYkV+wmq8Puzw/+xA9EJrrodnJPPsE6E8HnSVLF6Ys9+cJMJ7HuwOI+wYt3gkmspsir1tccmf4x1PP+yHJWdcXyetlFRcmZ8gspjqOR2jb89xSQsh8gcyDW6rPNlSTzYZ2FmNtjES6ZhCsYL31fQbF2QglidlLGpAlvHUUS+xCigW73cvhFPMWXcfO51Mr15RcgYTckY+7QZ2nYqplRBoDlQl6DnAgMBAAGjUzBRMB0GA1UdDgQWBBTPG99XVRdxpOXMZo3Nhy+ldnf13TAfBgNVHSMEGDAWgBTPG99XVRdxpOXMZo3Nhy+ldnf13TAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAjWTcnIl2mpNbfHAN8DB4Kk+RNRmhsH0y+r/47MXVTMMMToCfofeNY3Jeohu+2lIXMPQfTvXUbDTkNAGsGLv6LtQEUfSREqgk1eY7bT9BFfpH1uV2ZFhCO9jBA+E4bf55Kx7bgUNG31ykBshOsOblOJM1lS/0q4TWHAxrsU2PNwPi8X0ten+eGeB8aRshxS17Ij2cH0fdAMmSA+jMAvTIZl853Bxe0HuozauKwOFWL4qHm61c4O/j1mQCLqJKYfJ9mBDWFQLszd/tF+ePKiNhZCQly60F8Lumn2CDZj5UIkl8wk9Wls5n1BIQs+M8AN65NAdv7+js8jKUKCuyji8r3
+ - MIIC/zCCAeegAwIBAgIUAWE1vaA+mZd3nwZqwWH64EbHvR0wDQYJKoZIhvcNAQELBQAwDzENMAsGA1UEAwwEdGVzdDAeFw0xOTEwMTQxNjI4NDVaFw0yMDEwMTMxNjI4NDVaMA8xDTALBgNVBAMMBHRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCWzJibKtN8Zf7LgandINhFonx99AKi44iaZkrlMKEObE6Faf8NTUbUgK3VfJNYmCbA1baLVJ0YZJijJ7S/4o7h7eeqcJVXJkEhWNTimWXNW/YCzTHe3SSapnSYOKmdHHRClplysL8OyyEG7pbX/aB9iAfFb/+vUFCX5sMwFFrYxOimKJ9Pc/NRFtdv1wNw1rqWKF1ZzagWRlG4QgzRGwQ4quc7yO98TKikj2OPiIt7Zd46hbqQxmgGBtCkVOZIhxu77OmNrFsXmM4rZZpmqh0UdqcpwkRojVnGXmNqeMCd6dNTnLhr9wukUYw0KgE57zCDVr9Ix+p/dA5R1mG4RJ2XAgMBAAGjUzBRMB0GA1UdDgQWBBSbuiH2lNVrID3yt1SsFwtOFKOnpTAfBgNVHSMEGDAWgBSbuiH2lNVrID3yt1SsFwtOFKOnpTAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBCVWd293wWyohFqMFMHRBBg97T2Uc1yeT0dMH4BpuOaCqQp4q5ep+uLcXEI6+3mEwm8pa/ULQCD8yLLdotIWlG3+h/4boFpdiPFcBDgT8kGe+0KOzB8Nt7E13QYOu12MNi10qwGrjKhdhu1xBe4fpY5VCetVU1OLyuTsUyucQsFrtZI0SR83h+blbyoMZ7IhMngCfGUe1bnYeWnLbpFbigKfPuVDWsMH2kgj05EAd5EgHkWbX8QA8hmcmDKfNT3YZM8kiGQwmFrnQdq8bN0uHR8Nz+24cbmdbHcD65wlDW6GmYxi8mW+V6bAqn9pir/J14r4YFnqMGgjmdt81tscJV
+ - MIIC/zCCAeegAwIBAgIUTC33WUoYGFoIVGMwgjbc5J6xCyowDQYJKoZIhvcNAQELBQAwDzENMAsGA1UEAwwEdGVzdDAeFw0xOTEwMTQxNjI4NTJaFw0yMDEwMTMxNjI4NTJaMA8xDTALBgNVBAMMBHRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDCA+6P2eieXHaVJivtWif7SntjjkJm0juRKRRGsT3wt+zCZqoDe8zylTBN0mse/POWXdC+zXRMC2X/c4V10kgrvWbnNdFdUFfBUphiXSoqnUYHZ6Ta+b4UTzC2tECSUEnSCz9n1ofHnyqDyT9FELzVkRkQqexD+BFgZTF39R4q8BA4bWKQy94Kgvb+IP77+ou4fhkBLI1MX5nkWa3Oyu4TMzT/tqgPE70hk8wQzUU2aiwJ7IsmnWE6Ysk7c4DYMJQF/51bi2ByZWERNjyBY6L+ZV90aL4UFR9O+Pw9HatfHVBRdmzSkKJOr9iu4summWgH0QYDmbkdhGwYvup0EmEfAgMBAAGjUzBRMB0GA1UdDgQWBBSJCQ8ho0Ppe0khVhgiMqsvlgxIjzAfBgNVHSMEGDAWgBSJCQ8ho0Ppe0khVhgiMqsvlgxIjzAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAILLPnau32r/YoOVCVWQotGtySy36aFlHa3T8IkSpatNCPIf3U0FWS6TVYBwY0PBfdqWBkvCuJTupLh0OEP4TCsDa5pJGOK7blyfiAfcHajqyouACSVNlG63EPvB63h4H4F4HJnhDd4z7pVC/WPB8w5GTBJNjELmeWfH7nj7lu8UkOdLhzTKL40RPs0k4l09yYBmZqqExxGsSfvRBQcrwlAsvQ0E/cTNGbyzOKs3SbOM2WEHye6xNEsey01icYcjfjqvEd6mw3+WOUeJAuDH9/EOloFM2iz5Xp31Ig3WT0RVy+lMriG9GesPpFBs2xp9wQCXLNIkpbHKyYs3voMyBH
+ state: absent
diff --git a/playbooks/user/users_certificate_present.yml b/playbooks/user/users_certificate_present.yml
new file mode 100644
index 00000000..8d82a877
--- /dev/null
+++ b/playbooks/user/users_certificate_present.yml
@@ -0,0 +1,16 @@
+---
+- name: Test user certificates
+ hosts: ipaserver
+ become: true
+ gather_facts: false
+
+ tasks:
+ - name: User test cert present
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ users:
+ - name: test
+ certificate:
+ - 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
diff --git a/playbooks/user/users_present.yml b/playbooks/user/users_present.yml
new file mode 100644
index 00000000..3b9303b0
--- /dev/null
+++ b/playbooks/user/users_present.yml
@@ -0,0 +1,41 @@
+---
+- name: Tests
+ hosts: ipaserver
+ become: true
+ gather_facts: false
+
+ tasks:
+ - name: Users user1..10 present
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ users:
+ - name: user1
+ first: user1
+ last: Last
+ - name: user2
+ first: user2
+ last: Last
+ - name: user3
+ first: user3
+ last: Last
+ - name: user4
+ first: user4
+ last: Last
+ - name: user5
+ first: user5
+ last: Last
+ - name: user6
+ first: user6
+ last: Last
+ - name: user7
+ first: user7
+ last: Last
+ - name: user8
+ first: user8
+ last: Last
+ - name: user9
+ first: user9
+ last: Last
+ - name: user10
+ first: user10
+ last: Last
diff --git a/plugins/modules/ipauser.py b/plugins/modules/ipauser.py
index 748eb841..4a25ed7b 100644
--- a/plugins/modules/ipauser.py
+++ b/plugins/modules/ipauser.py
@@ -41,6 +41,167 @@ options:
name:
description: The list of users (internally uid).
required: false
+ users:
+ description: The list of user dicts (internally uid).
+ options:
+ name:
+ description: The ser (internally uid).
+ required: true
+ first:
+ description: The first name
+ required: false
+ aliases: ["givenname"]
+ last:
+ description: The last name
+ required: false
+ fullname:
+ description: The full name
+ required: false
+ aliases: ["cn"]
+ displayname:
+ description: The display name
+ required: false
+ initials:
+ description: Initials
+ required: false
+ homedir:
+ description: The home directory
+ required: false
+ shell:
+ description: The login shell
+ required: false
+ aliases: ["loginshell"]
+ email:
+ description: List of email addresses
+ required: false
+ principal:
+ description: The kerberos principal
+ required: false
+ aliases: ["principalname", "krbprincipalname"]
+ principalexpiration:
+ description:
+ - The kerberos principal expiration date
+ - (possible formats: YYYYMMddHHmmssZ, YYYY-MM-ddTHH:mm:ssZ,
+ - YYYY-MM-ddTHH:mmZ, YYYY-MM-ddZ, YYYY-MM-dd HH:mm:ssZ,
+ - YYYY-MM-dd HH:mmZ) The trailing 'Z' can be skipped.
+ required: false
+ aliases: ["krbprincipalexpiration"]
+ passwordexpiration:
+ description:
+ - The kerberos password expiration date (FreeIPA-4.7+)
+ - (possible formats: YYYYMMddHHmmssZ, YYYY-MM-ddTHH:mm:ssZ,
+ - YYYY-MM-ddTHH:mmZ, YYYY-MM-ddZ, YYYY-MM-dd HH:mm:ssZ,
+ - YYYY-MM-dd HH:mmZ) The trailing 'Z' can be skipped.
+ required: false
+ aliases: ["krbpasswordexpiration"]
+ password:
+ description: The user password
+ required: false
+ random:
+ description: Generate a random user password
+ required: false
+ type: bool
+ uid:
+ description: The UID
+ required: false
+ aliases: ["uidnumber"]
+ gid:
+ description: The GID
+ required: false
+ aliases: ["gidnumber"]
+ city:
+ description: City
+ required: false
+ userstate:
+ description: State/Province
+ required: false
+ aliases: ["st"]
+ postalcode:
+ description: Postalcode/ZIP
+ required: false
+ aliases: ["zip"]
+ phone:
+ description: List of telephone numbers
+ required: false
+ aliases: ["telephonenumber"]
+ mobile:
+ description: List of mobile telephone numbers
+ required: false
+ pager:
+ description: List of pager numbers
+ required: false
+ fax:
+ description: List of fax numbers
+ required: false
+ aliases: ["facsimiletelephonenumber"]
+ orgunit:
+ description: Org. Unit
+ required: false
+ title:
+ description: The job title
+ required: false
+ manager:
+ description: List of managers
+ required: false
+ carlicense:
+ description: List of car licenses
+ required: false
+ sshpubkey:
+ description: List of SSH public keys
+ required: false
+ aliases: ["ipasshpubkey"]
+ userauthtype:
+ description: List of supported user authentication types
+ choices=['password', 'radius', 'otp']
+ required: false
+ userclass:
+ description:
+ - User category
+ - (semantics placed on this attribute are for local interpretation)
+ required: false
+ radius:
+ description: RADIUS proxy configuration
+ required: false
+ radiususer:
+ description: RADIUS proxy username
+ required: false
+ departmentnumber:
+ description: Department Number
+ required: false
+ employeenumber:
+ description: Employee Number
+ required: false
+ employeetype:
+ description: Employee Type
+ required: false
+ preferredlanguage:
+ description: Preferred Language
+ required: false
+ certificate:
+ description: List of base-64 encoded user certificates
+ required: false
+ certmapdata:
+ description: List of certificate mappings
+ options:
+ certificate:
+ description: Base-64 encoded user certificate
+ required: false
+ issuer:
+ description: Issuer of the certificate
+ required: false
+ subject:
+ description: Subject of the certificate
+ required: false
+ required: false
+ noprivate:
+ description: Don't create user private group
+ required: false
+ type: bool
+ nomembers:
+ description: Suppress processing of membership attributes
+ required: false
+ type: bool
+ required: false
first:
description: The first name
required: false
@@ -55,6 +216,9 @@ options:
displayname:
description: The display name
required: false
+ initials:
+ description: Initials
+ required: false
homedir:
description: The home directory
required: false
@@ -65,13 +229,21 @@ options:
email:
description: List of email addresses
required: false
- principalname:
+ principal:
description: The kerberos principal
required: false
- aliases: ["krbprincipalname"]
+ aliases: ["principalname", "krbprincipalname"]
+ principalexpiration:
+ description:
+ - The kerberos principal expiration date
+ - (possible formats: YYYYMMddHHmmssZ, YYYY-MM-ddTHH:mm:ssZ,
+ - YYYY-MM-ddTHH:mmZ, YYYY-MM-ddZ, YYYY-MM-dd HH:mm:ssZ,
+ - YYYY-MM-dd HH:mmZ) The trailing 'Z' can be skipped.
+ required: false
+ aliases: ["krbprincipalexpiration"]
passwordexpiration:
description:
- - The kerberos password expiration date
+ - The kerberos password expiration date (FreeIPA-4.7+)
- (possible formats: YYYYMMddHHmmssZ, YYYY-MM-ddTHH:mm:ssZ,
- YYYY-MM-ddTHH:mmZ, YYYY-MM-ddZ, YYYY-MM-dd HH:mm:ssZ,
- YYYY-MM-dd HH:mmZ) The trailing 'Z' can be skipped.
@@ -80,6 +252,10 @@ options:
password:
description: The user password
required: false
+ random:
+ description: Generate a random user password
+ required: false
+ type: bool
uid:
description: The UID
required: false
@@ -88,26 +264,111 @@ options:
description: The GID
required: false
aliases: ["gidnumber"]
+ city:
+ description: City
+ required: false
+ userstate:
+ description: State/Province
+ required: false
+ aliases: ["st"]
+ postalcode:
+ description: ZIP
+ required: false
+ aliases: ["zip"]
phone:
description: List of telephone numbers
required: false
aliases: ["telephonenumber"]
+ mobile:
+ description: List of mobile telephone numbers
+ required: false
+ pager:
+ description: List of pager numbers
+ required: false
+ fax:
+ description: List of fax numbers
+ required: false
+ aliases: ["facsimiletelephonenumber"]
+ orgunit:
+ description: Org. Unit
+ required: false
title:
description: The job title
required: false
- #sshpubkey:
- # description: List of SSH public keys
- # required: false
- # aliases: ["ipasshpubkey"]
- # ..
- update_password:
+ manager:
+ description: List of managers
+ required: false
+ carlicense:
+ description: List of car licenses
+ required: false
+ sshpubkey:
+ description: List of SSH public keys
+ required: false
+ aliases: ["ipasshpubkey"]
+ userauthtype:
+ description: List of supported user authentication types
+ choices=['password', 'radius', 'otp']
+ required: false
+ userclass:
description:
- Set password for a user in present state only on creation or always
- default: 'always'
- choices: ["always", "on_create"]
+ - User category
+ - (semantics placed on this attribute are for local interpretation)
+ required: false
+ radius:
+ description: RADIUS proxy configuration
+ required: false
+ radiususer:
+ description: RADIUS proxy username
+ required: false
+ departmentnumber:
+ description: Department Number
+ required: false
+ employeenumber:
+ description: Employee Number
+ required: false
+ employeetype:
+ description: Employee Type
+ required: false
+ preferredlanguage:
+ description: Preferred Language
+ required: false
+ certificate:
+ description: List of base-64 encoded user certificates
+ required: false
+ certmapdata:
+ description: List of certificate mappings
+ options:
+ certificate:
+ description: Base-64 encoded user certificate
+ required: false
+ issuer:
+ description: Issuer of the certificate
+ required: false
+ subject:
+ description: Subject of the certificate
+ required: false
+ required: false
+ noprivate:
+ description: Don't create user private group
+ required: false
+ type: bool
+ nomembers:
+ description: Suppress processing of membership attributes
+ required: false
+ type: bool
preserve:
description: Delete a user, keeping the entry available for future use
required: false
+ update_password:
+ description:
+ Set password for a user in present state only on creation or always
+ default: "always"
+ choices: ["always", "on_create"]
+ required: false
+ action:
+ description: Work on user or member level
+ default: "user"
+ choices: ["member", "user"]
state:
description: State to ensure
default: present
@@ -179,31 +440,48 @@ from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_text
from ansible.module_utils.ansible_freeipa_module import temp_kinit, \
temp_kdestroy, valid_creds, api_connect, api_command, date_format, \
- compare_args_ipa
+ compare_args_ipa, module_params_get, api_check_param, api_get_realm
+import six
+
+
+if six.PY3:
+ unicode = str
def find_user(module, name, preserved=False):
_args = {
"all": True,
- "uid": to_text(name),
+ "uid": name,
}
if preserved:
_args["preserved"] = preserved
- _result = api_command(module, "user_find", to_text(name), _args)
+ _result = api_command(module, "user_find", name, _args)
if len(_result["result"]) > 1:
module.fail_json(
msg="There is more than one user '%s'" % (name))
elif len(_result["result"]) == 1:
- return _result["result"][0]
+ # Transform each principal to a string
+ _result = _result["result"][0]
+ if "krbprincipalname" in _result \
+ and _result["krbprincipalname"] is not None:
+ _list = []
+ for x in _result["krbprincipalname"]:
+ _list.append(str(x))
+ _result["krbprincipalname"] = _list
+ return _result
else:
return None
-def gen_args(first, last, fullname, displayname, homedir, shell, emails,
- principalname, passwordexpiration, password, uid, gid,
- phones, title, sshpubkey):
+def gen_args(first, last, fullname, displayname, initials, homedir, shell,
+ email, principalexpiration, passwordexpiration, password,
+ random, uid, gid, city, userstate, postalcode, phone, mobile,
+ pager, fax, orgunit, title, carlicense, sshpubkey, userauthtype,
+ userclass, radius, radiususer, departmentnumber, employeenumber,
+ employeetype, preferredlanguage, noprivate, nomembers):
+ # principal, manager, certificate and certmapdata are handled not in here
_args = {}
if first is not None:
_args["givenname"] = first
@@ -213,33 +491,222 @@ def gen_args(first, last, fullname, displayname, homedir, shell, emails,
_args["cn"] = fullname
if displayname is not None:
_args["displayname"] = displayname
+ if initials is not None:
+ _args["initials"] = initials
if homedir is not None:
_args["homedirectory"] = homedir
if shell is not None:
_args["loginshell"] = shell
- if emails is not None and len(emails) > 0:
- _args["mail"] = emails
- if principalname is not None:
- _args["krbprincipalname"] = principalname
+ if email is not None and len(email) > 0:
+ _args["mail"] = email
+ if principalexpiration is not None:
+ _args["krbprincipalexpiration"] = principalexpiration
if passwordexpiration is not None:
_args["krbpasswordexpiration"] = passwordexpiration
if password is not None:
_args["userpassword"] = password
+ if random is not None:
+ _args["random"] = random
if uid is not None:
- _args["uidnumber"] = str(uid)
+ _args["uidnumber"] = to_text(str(uid))
if gid is not None:
- _args["gidnumber"] = str(gid)
- if phones is not None and len(phones) > 0:
- _args["telephonenumber"] = phones
+ _args["gidnumber"] = to_text(str(gid))
+ if city is not None:
+ _args["l"] = city
+ if userstate is not None:
+ _args["st"] = userstate
+ if postalcode is not None:
+ _args["postalcode"] = postalcode
+ if phone is not None and len(phone) > 0:
+ _args["telephonenumber"] = phone
+ if mobile is not None and len(mobile) > 0:
+ _args["mobile"] = mobile
+ if pager is not None and len(pager) > 0:
+ _args["pager"] = pager
+ if fax is not None and len(fax) > 0:
+ _args["facsimiletelephonenumber"] = fax
+ if orgunit is not None:
+ _args["ou"] = orgunit
if title is not None:
_args["title"] = title
- if sshpubkey is not None:
+ if carlicense is not None and len(carlicense) > 0:
+ _args["carlicense"] = carlicense
+ if sshpubkey is not None and len(sshpubkey) > 0:
_args["ipasshpubkey"] = sshpubkey
+ if userauthtype is not None and len(userauthtype) > 0:
+ _args["ipauserauthtype"] = userauthtype
+ if userclass is not None:
+ _args["userclass"] = userclass
+ if radius is not None:
+ _args["ipatokenradiusconfiglink"] = radius
+ if radiususer is not None:
+ _args["ipatokenradiususername"] = radiususer
+ if departmentnumber is not None:
+ _args["departmentnumber"] = departmentnumber
+ if employeenumber is not None:
+ _args["employeenumber"] = employeenumber
+ if employeetype is not None:
+ _args["employeetype"] = employeetype
+ if preferredlanguage is not None:
+ _args["preferredlanguage"] = preferredlanguage
+ if noprivate is not None:
+ _args["noprivate"] = noprivate
+ if nomembers is not None:
+ _args["no_members"] = nomembers
+ return _args
+
+def check_parameters(module, state, action,
+ first, last, fullname, displayname, initials, homedir,
+ shell, email, principal, principalexpiration,
+ passwordexpiration, password, random, uid, gid, city,
+ phone, mobile, pager, fax, orgunit, title, manager,
+ carlicense, sshpubkey, userauthtype, userclass, radius,
+ radiususer, departmentnumber, employeenumber,
+ employeetype, preferredlanguage, certificate,
+ certmapdata, noprivate, nomembers, preserve,
+ update_password):
+
+ if state == "present":
+ if action == "member":
+ invalid = ["first", "last", "fullname", "displayname", "initials",
+ "homedir", "shell", "email", "principalexpiration",
+ "passwordexpiration", "password", "random", "uid",
+ "gid", "city", "phone", "mobile", "pager", "fax",
+ "orgunit", "title", "carlicense", "sshpubkey",
+ "userauthtype", "userclass", "radius", "radiususer",
+ "departmentnumber", "employeenumber", "employeetype",
+ "preferredlanguage", "noprivate", "nomembers",
+ "preserve", "update_password"]
+ for x in invalid:
+ if vars()[x] is not None:
+ module.fail_json(
+ msg="Argument '%s' can not be used with action "
+ "'%s'" % (x, action))
+
+ else:
+ invalid = ["first", "last", "fullname", "displayname", "initials",
+ "homedir", "shell", "email", "principalexpiration",
+ "passwordexpiration", "password", "random", "uid",
+ "gid", "city", "phone", "mobile", "pager", "fax",
+ "orgunit", "title", "carlicense", "sshpubkey",
+ "userauthtype", "userclass", "radius", "radiususer",
+ "departmentnumber", "employeenumber", "employeetype",
+ "preferredlanguage", "noprivate", "nomembers",
+ "update_password"]
+ if action == "user":
+ invalid.extend(["principal", "manager",
+ "certificate", "certmapdata",
+ ])
+ for x in invalid:
+ if vars()[x] is not None:
+ module.fail_json(
+ msg="Argument '%s' can not be used with state '%s'" %
+ (x, state))
+
+ if state != "absent" and preserve is not None:
+ module.fail_json(
+ msg="Preserve is only possible for state=absent")
+
+ if certmapdata is not None:
+ for x in certmapdata:
+ certificate = x.get("certificate")
+ issuer = x.get("issuer")
+ subject = x.get("subject")
+
+ if certificate is not None \
+ and (issuer is not None or subject is not None):
+ module.fail_json(
+ msg="certmapdata: certificate can not be used with "
+ "issuer or subject")
+ if certificate is None:
+ if issuer is None:
+ module.fail_json(msg="certmapdata: issuer is missing")
+ if subject is None:
+ module.fail_json(msg="certmapdata: subject is missing")
+
+
+def gen_certmapdata_args(certmapdata):
+ certificate = certmapdata.get("certificate")
+ issuer = certmapdata.get("issuer")
+ subject = certmapdata.get("subject")
+
+ _args = {}
+ if certificate is not None:
+ _args["certificate"] = certificate
+ if issuer is not None:
+ _args["issuer"] = issuer
+ if subject is not None:
+ _args["subject"] = subject
return _args
def main():
+ user_spec = dict(
+ # present
+ first=dict(type="str", aliases=["givenname"], default=None),
+ last=dict(type="str", default=None),
+ fullname=dict(type="str", aliases=["cn"], default=None),
+ displayname=dict(type="str", default=None),
+ initials=dict(type="str", default=None),
+ homedir=dict(type="str", default=None),
+ shell=dict(type="str", aliases=["loginshell"], default=None),
+ email=dict(type="list", default=None),
+ principal=dict(type="list", aliases=["principalname",
+ "krbprincipalname"],
+ default=None),
+ principalexpiration=dict(type="str",
+ aliases=["krbprincipalexpiration"],
+ default=None),
+ passwordexpiration=dict(type="str",
+ aliases=["krbpasswordexpiration"],
+ default=None),
+ password=dict(type="str", default=None, no_log=True),
+ random=dict(type='bool', default=None),
+ uid=dict(type="int", aliases=["uidnumber"], default=None),
+ gid=dict(type="int", aliases=["gidnumber"], default=None),
+ city=dict(type="str", default=None),
+ userstate=dict(type="str", aliases=["st"], default=None),
+ postalcode=dict(type="str", aliases=["zip"], default=None),
+ phone=dict(type="list", aliases=["telephonenumber"], default=None),
+ mobile=dict(type="list", default=None),
+ pager=dict(type="list", default=None),
+ fax=dict(type="list", aliases=["facsimiletelephonenumber"],
+ default=None),
+ orgunit=dict(type="str", aliases=["ou"], default=None),
+ title=dict(type="str", default=None),
+ manager=dict(type="list", default=None),
+ carlicense=dict(type="list", default=None),
+ sshpubkey=dict(type="list", aliases=["ipasshpubkey"],
+ default=None),
+ userauthtype=dict(type='list', aliases=["ipauserauthtype"],
+ default=None,
+ choices=['password', 'radius', 'otp']),
+ userclass=dict(type="list", aliases=["class"],
+ default=None),
+ radius=dict(type="str", aliases=["ipatokenradiusconfiglink"],
+ default=None),
+ radiususer=dict(type="str", aliases=["radiususername",
+ "ipatokenradiususername"],
+ default=None),
+ departmentnumber=dict(type="list", default=None),
+ employeenumber=dict(type="str", default=None),
+ employeetype=dict(type="str", default=None),
+ preferredlanguage=dict(type="str", default=None),
+ certificate=dict(type="list", aliases=["usercertificate"],
+ default=None),
+ certmapdata=dict(type="list", default=None,
+ options=dict(
+ # Here certificate is a simple string
+ certificate=dict(type="str", default=None),
+ issuer=dict(type="str", default=None),
+ subject=dict(type="str", default=None)
+ ),
+ elements='dict', required=False),
+ noprivate=dict(type='bool', default=None),
+ nomembers=dict(type='bool', default=None),
+ )
+
ansible_module = AnsibleModule(
argument_spec=dict(
# general
@@ -247,36 +714,35 @@ def main():
ipaadmin_password=dict(type="str", required=False, no_log=True),
name=dict(type="list", aliases=["login"], default=None,
- required=True),
- # present
- first=dict(type="str", aliases=["givenname"], default=None),
- last=dict(type="str", default=None),
- fullname=dict(type="str", aliases=["cn"], default=None),
- displayname=dict(type="str", default=None),
- homedir=dict(type="str", default=None),
- shell=dict(type="str", aliases=["loginshell"], default=None),
- email=dict(type="list", default=None),
- principalname=dict(type="str", aliases=["krbprincipalname"],
- default=None),
- passwordexpiration=dict(type="str",
- aliases=["krbpasswordexpiration"],
- default=None),
- password=dict(type="str", default=None, no_log=True),
- uid=dict(type="int", aliases=["uidnumber"], default=None),
- gid=dict(type="int", aliases=["gidnumber"], default=None),
- phone=dict(type="list", aliases=["telephonenumber"], default=None),
- title=dict(type="str", default=None),
- # sshpubkey=dict(type="list", aliases=["ipasshpubkey"],
- # default=None),
- update_password=dict(type='str', default=None,
- choices=['always', 'on_create']),
+ required=False),
+ users=dict(type="list", aliases=["login"], default=None,
+ options=dict(
+ # Here name is a simple string
+ name=dict(type="str", required=True),
+ # Add user specific parameters
+ **user_spec
+ ),
+ elements='dict', required=False),
+
# deleted
preserve=dict(required=False, type='bool', default=None),
- # state
+
+ # mod
+ update_password=dict(type='str', default=None,
+ choices=['always', 'on_create']),
+
+ # general
+ action=dict(type="str", default="user",
+ choices=["member", "user"]),
state=dict(type="str", default="present",
choices=["present", "absent", "enabled", "disabled",
"unlocked", "undeleted"]),
+
+ # Add user specific parameters for simple use case
+ **user_spec
),
+ mutually_exclusive=[["name", "users"]],
+ required_one_of=[["name", "users"]],
supports_check_mode=True,
)
@@ -285,66 +751,101 @@ def main():
# Get parameters
# general
- ipaadmin_principal = ansible_module.params.get("ipaadmin_principal")
- ipaadmin_password = ansible_module.params.get("ipaadmin_password")
- names = ansible_module.params.get("name")
+ ipaadmin_principal = module_params_get(ansible_module,
+ "ipaadmin_principal")
+ ipaadmin_password = module_params_get(ansible_module, "ipaadmin_password")
+ names = module_params_get(ansible_module, "name")
+ users = module_params_get(ansible_module, "users")
# present
- first = ansible_module.params.get("first")
- last = ansible_module.params.get("last")
- fullname = ansible_module.params.get("fullname")
- displayname = ansible_module.params.get("displayname")
- homedir = ansible_module.params.get("homedir")
- shell = ansible_module.params.get("shell")
- emails = ansible_module.params.get("email")
- principalname = ansible_module.params.get("principalname")
- passwordexpiration = ansible_module.params.get("passwordexpiration")
+ first = module_params_get(ansible_module, "first")
+ last = module_params_get(ansible_module, "last")
+ fullname = module_params_get(ansible_module, "fullname")
+ displayname = module_params_get(ansible_module, "displayname")
+ initials = module_params_get(ansible_module, "initials")
+ homedir = module_params_get(ansible_module, "homedir")
+ shell = module_params_get(ansible_module, "shell")
+ email = module_params_get(ansible_module, "email")
+ principal = module_params_get(ansible_module, "principal")
+ principalexpiration = module_params_get(ansible_module,
+ "principalexpiration")
+ if principalexpiration is not None:
+ if principalexpiration[:-1] != "Z":
+ principalexpiration = principalexpiration + "Z"
+ principalexpiration = date_format(principalexpiration)
+ passwordexpiration = module_params_get(ansible_module,
+ "passwordexpiration")
if passwordexpiration is not None:
if passwordexpiration[:-1] != "Z":
- passwordexpiration = "%sZ" % passwordexpiration
+ passwordexpiration = passwordexpiration + "Z"
passwordexpiration = date_format(passwordexpiration)
- password = ansible_module.params.get("password")
- uid = ansible_module.params.get("uid")
- gid = ansible_module.params.get("gid")
- phones = ansible_module.params.get("phone")
- title = ansible_module.params.get("title")
- sshpubkey = ansible_module.params.get("sshpubkey")
- update_password = ansible_module.params.get("update_password")
+ password = module_params_get(ansible_module, "password")
+ random = module_params_get(ansible_module, "random")
+ uid = module_params_get(ansible_module, "uid")
+ gid = module_params_get(ansible_module, "gid")
+ city = module_params_get(ansible_module, "city")
+ userstate = module_params_get(ansible_module, "userstate")
+ postalcode = module_params_get(ansible_module, "postalcode")
+ phone = module_params_get(ansible_module, "phone")
+ mobile = module_params_get(ansible_module, "mobile")
+ pager = module_params_get(ansible_module, "pager")
+ fax = module_params_get(ansible_module, "fax")
+ orgunit = module_params_get(ansible_module, "orgunit")
+ title = module_params_get(ansible_module, "title")
+ manager = module_params_get(ansible_module, "manager")
+ carlicense = module_params_get(ansible_module, "carlicense")
+ sshpubkey = module_params_get(ansible_module, "sshpubkey")
+ userauthtype = module_params_get(ansible_module, "userauthtype")
+ userclass = module_params_get(ansible_module, "userclass")
+ radius = module_params_get(ansible_module, "radius")
+ radiususer = module_params_get(ansible_module, "radiususer")
+ departmentnumber = module_params_get(ansible_module, "departmentnumber")
+ employeenumber = module_params_get(ansible_module, "employeenumber")
+ employeetype = module_params_get(ansible_module, "employeetype")
+ preferredlanguage = module_params_get(ansible_module, "preferredlanguage")
+ certificate = module_params_get(ansible_module, "certificate")
+ certmapdata = module_params_get(ansible_module, "certmapdata")
+ noprivate = module_params_get(ansible_module, "noprivate")
+ nomembers = module_params_get(ansible_module, "nomembers")
# deleted
- preserve = ansible_module.params.get("preserve")
- # state
- state = ansible_module.params.get("state")
+ preserve = module_params_get(ansible_module, "preserve")
+ # mod
+ update_password = module_params_get(ansible_module, "update_password")
+ # general
+ action = module_params_get(ansible_module, "action")
+ state = module_params_get(ansible_module, "state")
# Check parameters
+ if (names is None or len(names) < 1) and \
+ (users is None or len(users) < 1):
+ ansible_module.fail_json(msg="One of name and users is required")
+
if state == "present":
- if len(names) != 1:
+ if names is not None and len(names) != 1:
ansible_module.fail_json(
- msg="Only one user can be added at a time.")
- if first is None:
- ansible_module.fail_json(msg="First name is needed")
- if last is None:
- ansible_module.fail_json(msg="Last name is needed")
+ msg="Only one user can be added at a time using name.")
+ if action != "member":
+ # Only check first and last here if names is set
+ if names is not None:
+ if first is None:
+ ansible_module.fail_json(msg="First name is needed")
+ if last is None:
+ ansible_module.fail_json(msg="Last name is needed")
- if state == "absent":
- if len(names) < 1:
- ansible_module.fail_json(
- msg="No name given.")
- for x in ["first", "last", "fullname", "displayname", "homedir",
- "shell", "emails", "principalname", "passwordexpiration",
- "password", "uid", "gid", "phones", "title", "sshpubkey",
- "update_password"]:
- if vars()[x] is not None:
- ansible_module.fail_json(
- msg="Argument '%s' can not be used with state '%s'" %
- (x, state))
- else:
- if preserve is not None:
- ansible_module.fail_json(
- msg="Preserve is only possible for state=absent")
+ check_parameters(
+ ansible_module, state, action,
+ first, last, fullname, displayname, initials, homedir, shell, email,
+ principal, principalexpiration, passwordexpiration, password, random,
+ uid, gid, city, phone, mobile, pager, fax, orgunit, title, manager,
+ carlicense, sshpubkey, userauthtype, userclass, radius, radiususer,
+ departmentnumber, employeenumber, employeetype, preferredlanguage,
+ certificate, certmapdata, noprivate, nomembers, preserve,
+ update_password)
- if update_password is None:
- update_password = "always"
+ # Use users if names is None
+ if users is not None:
+ names = users
# Init
@@ -358,53 +859,380 @@ def main():
ipaadmin_password)
api_connect()
+ # Check version specific settings
+
+ server_realm = api_get_realm()
+
commands = []
- for name in names:
+ for user in names:
+ if isinstance(user, dict):
+ name = user.get("name")
+ # present
+ first = user.get("first")
+ last = user.get("last")
+ fullname = user.get("fullname")
+ displayname = user.get("displayname")
+ initials = user.get("initials")
+ homedir = user.get("homedir")
+ shell = user.get("shell")
+ email = user.get("email")
+ principal = user.get("principal")
+ principalexpiration = user.get("principalexpiration")
+ if principalexpiration is not None:
+ if principalexpiration[:-1] != "Z":
+ principalexpiration = principalexpiration + "Z"
+ principalexpiration = date_format(principalexpiration)
+ passwordexpiration = user.get("passwordexpiration")
+ if passwordexpiration is not None:
+ if passwordexpiration[:-1] != "Z":
+ passwordexpiration = passwordexpiration + "Z"
+ passwordexpiration = date_format(passwordexpiration)
+ password = user.get("password")
+ random = user.get("random")
+ uid = user.get("uid")
+ gid = user.get("gid")
+ city = user.get("city")
+ userstate = user.get("userstate")
+ postalcode = user.get("postalcode")
+ phone = user.get("phone")
+ mobile = user.get("mobile")
+ pager = user.get("pager")
+ fax = user.get("fax")
+ orgunit = user.get("orgunit")
+ title = user.get("title")
+ manager = user.get("manager")
+ carlicense = user.get("carlicense")
+ sshpubkey = user.get("sshpubkey")
+ userauthtype = user.get("userauthtype")
+ userclass = user.get("userclass")
+ radius = user.get("radius")
+ radiususer = user.get("radiususer")
+ departmentnumber = user.get("departmentnumber")
+ employeenumber = user.get("employeenumber")
+ employeetype = user.get("employeetype")
+ preferredlanguage = user.get("preferredlanguage")
+ certificate = user.get("certificate")
+ certmapdata = user.get("certmapdata")
+ noprivate = user.get("noprivate")
+ nomembers = user.get("nomembers")
+
+ check_parameters(
+ ansible_module, state, action,
+ first, last, fullname, displayname, initials, homedir,
+ shell, email, principal, principalexpiration,
+ passwordexpiration, password, random, uid, gid, city,
+ phone, mobile, pager, fax, orgunit, title, manager,
+ carlicense, sshpubkey, userauthtype, userclass, radius,
+ radiususer, departmentnumber, employeenumber,
+ employeetype, preferredlanguage, certificate,
+ certmapdata, noprivate, nomembers, preserve,
+ update_password)
+
+ elif isinstance(user, str) or isinstance(user, unicode):
+ name = user
+ else:
+ ansible_module.fail_json(msg="User '%s' is not valid" %
+ repr(user))
+
+ # Fix principals: add realm if missing
+ # We need the connected API for the realm, therefore it can not
+ # be part of check_parameters as this is used also before the
+ # connection to the API has been established.
+ if principal is not None:
+ principal = [x if "@" in x else x + "@" + server_realm
+ for x in principal]
+
+ # Check passwordexpiration availability.
+ # We need the connected API for this test, therefore it can not
+ # be part of check_parameters as this is used also before the
+ # connection to the API has been established.
+ if passwordexpiration is not None and \
+ not api_check_param("user_add", "krbpasswordexpiration"):
+ ansible_module.fail_json(
+ msg="The use of passwordexpiration is not supported by "
+ "your IPA version")
+
# Make sure user exists
res_find = find_user(ansible_module, name)
- # Also search for preserved user
- res_find_preserved = find_user(ansible_module, name,
- preserved=True)
+ # Also search for preserved user if the user could not be found
+ if res_find is None:
+ res_find_preserved = find_user(ansible_module, name,
+ preserved=True)
+ else:
+ res_find_preserved = None
# Create command
if state == "present":
# Generate args
args = gen_args(
- first, last, fullname, displayname, homedir, shell, emails,
- principalname, passwordexpiration, password, uid, gid,
- phones, title, sshpubkey)
+ first, last, fullname, displayname, initials, homedir,
+ shell, email, principalexpiration, passwordexpiration,
+ password, random, uid, gid, city, userstate, postalcode,
+ phone, mobile, pager, fax, orgunit, title, carlicense,
+ sshpubkey, userauthtype, userclass, radius, radiususer,
+ departmentnumber, employeenumber, employeetype,
+ preferredlanguage, noprivate, nomembers)
# Also check preserved users
if res_find is None and res_find_preserved is not None:
res_find = res_find_preserved
- # Found the user
- if res_find is not None:
- # Ignore password with update_password == on_create
- if update_password == "on_create" and \
- "userpassword" in args:
- del args["userpassword"]
+ if action == "user":
+ # Found the user
+ if res_find is not None:
+ # Ignore password and random with
+ # update_password == on_create
+ if update_password == "on_create":
+ if "userpassword" in args:
+ del args["userpassword"]
+ if "random" in args:
+ del args["random"]
+ if "noprivate" in args:
+ del args["noprivate"]
- # For all settings is args, check if there are
- # different settings in the find result.
- # If yes: modify
- if not compare_args_ipa(ansible_module, args, res_find):
- commands.append([name, "user_mod", args])
- else:
- commands.append([name, "user_add", args])
+ # For all settings is args, check if there are
+ # different settings in the find result.
+ # If yes: modify
+ if not compare_args_ipa(ansible_module, args,
+ res_find):
+ commands.append([name, "user_mod", args])
+
+ else:
+ commands.append([name, "user_add", args])
+
+ # Handle members: principal, manager
+ if res_find is not None:
+ # Generate addition and removal lists
+ manager_add = list(
+ set(manager or []) -
+ set(res_find.get("manager", [])))
+ manager_del = list(
+ set(res_find.get("manager", [])) -
+ set(manager or []))
+ principal_add = list(
+ set(principal or []) -
+ set(res_find.get("krbprincipalname", [])))
+ principal_del = list(
+ set(res_find.get("krbprincipalname", [])) -
+ set(principal or []))
+
+ # Principals are not returned as utf8 for IPA using
+ # python2 using user_find, therefore we need to
+ # convert the principals that we should remove.
+ principal_del = [to_text(x) for x in principal_del]
+
+ certificate_add = list(
+ set(certificate or []) -
+ set(res_find.get("certificate", [])))
+ certificate_del = list(
+ set(res_find.get("certificate", [])) -
+ set(certificate or []))
+ certmapdata_add = list(
+ set(certmapdata or []) -
+ set(res_find.get("ipaCertMapData", [])))
+ certmapdata_del = list(
+ set(res_find.get("ipaCertMapData", [])) -
+ set(certmapdata or []))
+
+ else:
+ # Use given managers and principals
+ manager_add = manager or []
+ manager_del = []
+ principal_add = principal or []
+ principal_del = []
+ certificate_add = certificate or []
+ certificate_del = []
+ certmapdata_add = certmapdata or []
+ certmapdata_del = []
+
+ # Remove canonical principal from principal_del
+ canonical_principal = name + "@" + server_realm
+ if canonical_principal in principal_del:
+ principal_del.remove(canonical_principal)
+
+ # Add managers
+ if len(manager_add) > 0:
+ commands.append([name, "user_add_manager",
+ {
+ "user": manager_add,
+ }])
+ # Remove managers
+ if len(manager_del) > 0:
+ commands.append([name, "user_remove_manager",
+ {
+ "user": manager_del,
+ }])
+
+ # Principals need to be added and removed one by one,
+ # because if entry already exists, the processing of
+ # the remaining enries is stopped. The same applies to
+ # the removal of non-existing entries.
+
+ # Add principals
+ if len(principal_add) > 0:
+ for _principal in principal_add:
+ commands.append([name, "user_add_principal",
+ {
+ "krbprincipalname":
+ _principal,
+ }])
+ # Remove principals
+ if len(principal_del) > 0:
+ for _principal in principal_del:
+ commands.append([name, "user_remove_principal",
+ {
+ "krbprincipalname":
+ _principal,
+ }])
+
+ # Certificates need to be added and removed one by one,
+ # because if entry already exists, the processing of
+ # the remaining enries is stopped. The same applies to
+ # the removal of non-existing entries.
+
+ # Add certificates
+ if len(certificate_add) > 0:
+ for _certificate in certificate_add:
+ commands.append([name, "user_add_cert",
+ {
+ "usercertificate":
+ _certificate,
+ }])
+ # Remove certificates
+ if len(certificate_del) > 0:
+ for _certificate in certificate_del:
+ commands.append([name, "user_remove_cert",
+ {
+ "usercertificate":
+ _certificate,
+ }])
+
+ # certmapdata need to be added and removed one by one,
+ # because issuer and subject can only be done one by
+ # one reliably (https://pagure.io/freeipa/issue/8097)
+
+ # Add certmapdata
+ if len(certmapdata_add) > 0:
+ for _data in certmapdata_add:
+ commands.append([name, "user_add_certmapdata",
+ gen_certmapdata_args(_data)])
+ # Remove certmapdata
+ if len(certmapdata_del) > 0:
+ for _data in certmapdata_del:
+ commands.append([name, "user_add_certmapdata",
+ gen_certmapdata_args(_data)])
+
+ elif action == "member":
+ if res_find is None:
+ ansible_module.fail_json(
+ msg="No user '%s'" % name)
+
+ # Ensure managers are present
+ if manager is not None and len(manager) > 0:
+ commands.append([name, "user_add_manager",
+ {
+ "user": manager,
+ }])
+
+ # Principals need to be added and removed one by one,
+ # because if entry already exists, the processing of
+ # the remaining enries is stopped. The same applies to
+ # the removal of non-existing entries.
+
+ # Ensure principals are present
+ if principal is not None and len(principal) > 0:
+ for _principal in principal:
+ commands.append([name, "user_add_principal",
+ {
+ "krbprincipalname":
+ _principal,
+ }])
+
+ # Certificates need to be added and removed one by one,
+ # because if entry already exists, the processing of
+ # the remaining enries is stopped. The same applies to
+ # the removal of non-existing entries.
+
+ # Ensure certificates are present
+ if certificate is not None and len(certificate) > 0:
+ for _certificate in certificate:
+ commands.append([name, "user_add_cert",
+ {
+ "usercertificate":
+ _certificate,
+ }])
+
+ # certmapdata need to be added and removed one by one,
+ # because issuer and subject can only be done one by
+ # one reliably (https://pagure.io/freeipa/issue/8097)
+
+ # Ensure certmapdata are present
+ if certmapdata is not None and len(certmapdata) > 0:
+ for _data in certmapdata:
+ commands.append([name, "user_add_certmapdata",
+ gen_certmapdata_args(_data)])
elif state == "absent":
# Also check preserved users
if res_find is None and res_find_preserved is not None:
res_find = res_find_preserved
- if res_find is not None:
- args = {}
- if preserve is not None:
- args["preserve"] = preserve
- commands.append([name, "user_del", args])
+ if action == "user":
+ if res_find is not None:
+ args = {}
+ if preserve is not None:
+ args["preserve"] = preserve
+ commands.append([name, "user_del", args])
+ elif action == "member":
+ if res_find is None:
+ ansible_module.fail_json(
+ msg="No user '%s'" % name)
+ # Ensure managers are absent
+ if manager is not None and len(manager) > 0:
+ commands.append([name, "user_remove_manager",
+ {
+ "user": manager,
+ }])
+
+ # Principals need to be added and removed one by one,
+ # because if entry already exists, the processing of
+ # the remaining enries is stopped. The same applies to
+ # the removal of non-existing entries.
+
+ # Ensure principals are absent
+ if principal is not None and len(principal) > 0:
+ commands.append([name, "user_remove_principal",
+ {
+ "krbprincipalname": principal,
+ }])
+
+ # Certificates need to be added and removed one by one,
+ # because if entry already exists, the processing of
+ # the remaining enries is stopped. The same applies to
+ # the removal of non-existing entries.
+
+ # Ensure certificates are absent
+ if certificate is not None and len(certificate) > 0:
+ for _certificate in certificate:
+ commands.append([name, "user_remove_cert",
+ {
+ "usercertificate":
+ _certificate,
+ }])
+
+ # certmapdata need to be added and removed one by one,
+ # because issuer and subject can only be done one by
+ # one reliably (https://pagure.io/freeipa/issue/8097)
+
+ # Ensure certmapdata are absent
+ if certmapdata is not None and len(certmapdata) > 0:
+ # Using issuer and subject can only be done one by
+ # one reliably (https://pagure.io/freeipa/issue/8097)
+ for _data in certmapdata:
+ commands.append([name, "user_remove_certmapdata",
+ gen_certmapdata_args(_data)])
elif state == "undeleted":
if res_find_preserved is not None:
commands.append([name, "user_undel", {}])
@@ -434,13 +1262,43 @@ def main():
# Execute commands
+ errors = []
for name, command, args in commands:
try:
- api_command(ansible_module, command, to_text(name), args)
- changed = True
+ result = api_command(ansible_module, command, name,
+ args)
+ if "completed" in result:
+ if result["completed"] > 0:
+ changed = True
+ else:
+ changed = True
except Exception as e:
+ msg = str(e)
+ if "already contains" in msg \
+ or "does not contain" in msg:
+ continue
+ # The canonical principal name may not be removed
+ if "equal to the canonical principal name must" in msg:
+ continue
ansible_module.fail_json(msg="%s: %s: %s" % (command, name,
- str(e)))
+ msg))
+
+ # Get all errors
+ # All "already a member" and "not a member" failures in the
+ # result are ignored. All others are reported.
+ if "failed" in result and len(result["failed"]) > 0:
+ for item in result["failed"]:
+ failed_item = result["failed"][item]
+ for member_type in failed_item:
+ for member, failure in failed_item[member_type]:
+ if "already a member" in failure \
+ or "not a member" in failure:
+ continue
+ errors.append("%s: %s %s: %s" % (
+ command, member_type, member, failure))
+
+ if len(errors) > 0:
+ ansible_module.fail_json(msg=", ".join(errors))
except Exception as e:
ansible_module.fail_json(msg=str(e))
diff --git a/tests/user/certificate/cert1.der b/tests/user/certificate/cert1.der
new file mode 100644
index 00000000..334511ff
Binary files /dev/null and b/tests/user/certificate/cert1.der differ
diff --git a/tests/user/certificate/cert1.pem b/tests/user/certificate/cert1.pem
new file mode 100644
index 00000000..6fb9d2e9
--- /dev/null
+++ b/tests/user/certificate/cert1.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIC/zCCAeegAwIBAgIUZGHLaSYg1myp6EI4VGWSC27vOrswDQYJKoZIhvcNAQEL
+BQAwDzENMAsGA1UEAwwEdGVzdDAeFw0xOTEwMTQxNjI4MzVaFw0yMDEwMTMxNjI4
+MzVaMA8xDTALBgNVBAMMBHRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
+AoIBAQDER/lB8wUAmPTSwSc/NOXNlzdpPOQDSwrhKH6XsqZF4KpQoSY/nmCjAhJm
+OVpOUo4K2fGRZ0yAH9fkGv6yJP6c7IAFjLeec7GPHVwN4bZrP1DXfTAmfmXhcRQb
+CYkV+wmq8Puzw/+xA9EJrrodnJPPsE6E8HnSVLF6Ys9+cJMJ7HuwOI+wYt3gkmsp
+sir1tccmf4x1PP+yHJWdcXyetlFRcmZ8gspjqOR2jb89xSQsh8gcyDW6rPNlSTzY
+Z2FmNtjES6ZhCsYL31fQbF2QglidlLGpAlvHUUS+xCigW73cvhFPMWXcfO51Mr15
+RcgYTckY+7QZ2nYqplRBoDlQl6DnAgMBAAGjUzBRMB0GA1UdDgQWBBTPG99XVRdx
+pOXMZo3Nhy+ldnf13TAfBgNVHSMEGDAWgBTPG99XVRdxpOXMZo3Nhy+ldnf13TAP
+BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAjWTcnIl2mpNbfHAN8
+DB4Kk+RNRmhsH0y+r/47MXVTMMMToCfofeNY3Jeohu+2lIXMPQfTvXUbDTkNAGsG
+Lv6LtQEUfSREqgk1eY7bT9BFfpH1uV2ZFhCO9jBA+E4bf55Kx7bgUNG31ykBshOs
+OblOJM1lS/0q4TWHAxrsU2PNwPi8X0ten+eGeB8aRshxS17Ij2cH0fdAMmSA+jMA
+vTIZl853Bxe0HuozauKwOFWL4qHm61c4O/j1mQCLqJKYfJ9mBDWFQLszd/tF+ePK
+iNhZCQly60F8Lumn2CDZj5UIkl8wk9Wls5n1BIQs+M8AN65NAdv7+js8jKUKCuyj
+i8r3
+-----END CERTIFICATE-----
diff --git a/tests/user/certificate/cert2.der b/tests/user/certificate/cert2.der
new file mode 100644
index 00000000..a3ba5a57
Binary files /dev/null and b/tests/user/certificate/cert2.der differ
diff --git a/tests/user/certificate/cert2.pem b/tests/user/certificate/cert2.pem
new file mode 100644
index 00000000..4a243b25
--- /dev/null
+++ b/tests/user/certificate/cert2.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIC/zCCAeegAwIBAgIUAWE1vaA+mZd3nwZqwWH64EbHvR0wDQYJKoZIhvcNAQEL
+BQAwDzENMAsGA1UEAwwEdGVzdDAeFw0xOTEwMTQxNjI4NDVaFw0yMDEwMTMxNjI4
+NDVaMA8xDTALBgNVBAMMBHRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
+AoIBAQCWzJibKtN8Zf7LgandINhFonx99AKi44iaZkrlMKEObE6Faf8NTUbUgK3V
+fJNYmCbA1baLVJ0YZJijJ7S/4o7h7eeqcJVXJkEhWNTimWXNW/YCzTHe3SSapnSY
+OKmdHHRClplysL8OyyEG7pbX/aB9iAfFb/+vUFCX5sMwFFrYxOimKJ9Pc/NRFtdv
+1wNw1rqWKF1ZzagWRlG4QgzRGwQ4quc7yO98TKikj2OPiIt7Zd46hbqQxmgGBtCk
+VOZIhxu77OmNrFsXmM4rZZpmqh0UdqcpwkRojVnGXmNqeMCd6dNTnLhr9wukUYw0
+KgE57zCDVr9Ix+p/dA5R1mG4RJ2XAgMBAAGjUzBRMB0GA1UdDgQWBBSbuiH2lNVr
+ID3yt1SsFwtOFKOnpTAfBgNVHSMEGDAWgBSbuiH2lNVrID3yt1SsFwtOFKOnpTAP
+BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBCVWd293wWyohFqMFM
+HRBBg97T2Uc1yeT0dMH4BpuOaCqQp4q5ep+uLcXEI6+3mEwm8pa/ULQCD8yLLdot
+IWlG3+h/4boFpdiPFcBDgT8kGe+0KOzB8Nt7E13QYOu12MNi10qwGrjKhdhu1xBe
+4fpY5VCetVU1OLyuTsUyucQsFrtZI0SR83h+blbyoMZ7IhMngCfGUe1bnYeWnLbp
+FbigKfPuVDWsMH2kgj05EAd5EgHkWbX8QA8hmcmDKfNT3YZM8kiGQwmFrnQdq8bN
+0uHR8Nz+24cbmdbHcD65wlDW6GmYxi8mW+V6bAqn9pir/J14r4YFnqMGgjmdt81t
+scJV
+-----END CERTIFICATE-----
diff --git a/tests/user/certificate/cert3.der b/tests/user/certificate/cert3.der
new file mode 100644
index 00000000..783830ee
Binary files /dev/null and b/tests/user/certificate/cert3.der differ
diff --git a/tests/user/certificate/cert3.pem b/tests/user/certificate/cert3.pem
new file mode 100644
index 00000000..b2a6a99c
--- /dev/null
+++ b/tests/user/certificate/cert3.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIC/zCCAeegAwIBAgIUTC33WUoYGFoIVGMwgjbc5J6xCyowDQYJKoZIhvcNAQEL
+BQAwDzENMAsGA1UEAwwEdGVzdDAeFw0xOTEwMTQxNjI4NTJaFw0yMDEwMTMxNjI4
+NTJaMA8xDTALBgNVBAMMBHRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
+AoIBAQDCA+6P2eieXHaVJivtWif7SntjjkJm0juRKRRGsT3wt+zCZqoDe8zylTBN
+0mse/POWXdC+zXRMC2X/c4V10kgrvWbnNdFdUFfBUphiXSoqnUYHZ6Ta+b4UTzC2
+tECSUEnSCz9n1ofHnyqDyT9FELzVkRkQqexD+BFgZTF39R4q8BA4bWKQy94Kgvb+
+IP77+ou4fhkBLI1MX5nkWa3Oyu4TMzT/tqgPE70hk8wQzUU2aiwJ7IsmnWE6Ysk7
+c4DYMJQF/51bi2ByZWERNjyBY6L+ZV90aL4UFR9O+Pw9HatfHVBRdmzSkKJOr9iu
+4summWgH0QYDmbkdhGwYvup0EmEfAgMBAAGjUzBRMB0GA1UdDgQWBBSJCQ8ho0Pp
+e0khVhgiMqsvlgxIjzAfBgNVHSMEGDAWgBSJCQ8ho0Ppe0khVhgiMqsvlgxIjzAP
+BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAILLPnau32r/YoOVCV
+WQotGtySy36aFlHa3T8IkSpatNCPIf3U0FWS6TVYBwY0PBfdqWBkvCuJTupLh0OE
+P4TCsDa5pJGOK7blyfiAfcHajqyouACSVNlG63EPvB63h4H4F4HJnhDd4z7pVC/W
+PB8w5GTBJNjELmeWfH7nj7lu8UkOdLhzTKL40RPs0k4l09yYBmZqqExxGsSfvRBQ
+crwlAsvQ0E/cTNGbyzOKs3SbOM2WEHye6xNEsey01icYcjfjqvEd6mw3+WOUeJAu
+DH9/EOloFM2iz5Xp31Ig3WT0RVy+lMriG9GesPpFBs2xp9wQCXLNIkpbHKyYs3vo
+MyBH
+-----END CERTIFICATE-----
diff --git a/tests/user/certificate/private1.key b/tests/user/certificate/private1.key
new file mode 100644
index 00000000..cb76298b
--- /dev/null
+++ b/tests/user/certificate/private1.key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDER/lB8wUAmPTS
+wSc/NOXNlzdpPOQDSwrhKH6XsqZF4KpQoSY/nmCjAhJmOVpOUo4K2fGRZ0yAH9fk
+Gv6yJP6c7IAFjLeec7GPHVwN4bZrP1DXfTAmfmXhcRQbCYkV+wmq8Puzw/+xA9EJ
+rrodnJPPsE6E8HnSVLF6Ys9+cJMJ7HuwOI+wYt3gkmspsir1tccmf4x1PP+yHJWd
+cXyetlFRcmZ8gspjqOR2jb89xSQsh8gcyDW6rPNlSTzYZ2FmNtjES6ZhCsYL31fQ
+bF2QglidlLGpAlvHUUS+xCigW73cvhFPMWXcfO51Mr15RcgYTckY+7QZ2nYqplRB
+oDlQl6DnAgMBAAECggEBALtKTj6urHxId3xPEKsQR6Noglgp4Qx/Y687W6hWsLAG
+051CV+PmtSF2DaZ7XX9U6PLTydzL68RqHjArzhKgmE+WoAYrot5QWQJNqpQYZ19o
+uDQW4YYpn/+BTgUKkUNnGm+BqTt8b5QyJxoNHsy4ppZMDnBtomCfrgYxGPr2YmfZ
+Ee7oEEf1xIU2maE5Nxv97lNR2Xvm2R4F8lzRcHmvejLYNiqZ2Ag4ijnKVTpoEMUy
+afl5LNSzGJETXsv+LtaJGEr6x8/IesVSCdyX2LZeAyQPLKwb3YQDkQree54vwS7p
+cVmQdx6fLTYV1tOSXUEC2ibInO188kGA198HSqSgHJkCgYEA7zhL+6tYZdXoMzTH
+hXHLYGHmQsQXxleH5uciz4q+en7do6BFB2DqIgLTpcD/H8XMDlg9WO7756H1zqvb
+6IOkqwsrro/fsgb6FrmjXl8zlkwT3pTNJfmBydRf7Qk2woCRPUoLZBRAumNL8RSx
+Xm1/DbPbTR3jjVNH9dPb3Efd0qUCgYEA0gyesMgwDzjsXpPUsuWTMBMziy0KRFNT
+lCMCI5DVpy/XnptyLdkY93jvmq+VWbily4KlOYbfYJ/16xeNZ7aNOMnC6z4z9p9+
+w3E9q5xKJcAJP5kN/WnjBwErveDK9r1YSj8RJpvapJFqjxA5WVTwADtyBhgNS4Og
+mXPPBleMC5sCgYEA0Yw/AvXVOV9nR3O0UvCbdpJLYbDkIpoKMfnGRIcE08jN3cdG
+sG/0qFZRj6C/2tUpKmehVYYCo6T77U4eFE88r5fZa9Ab45a4+68hrEk4py99ODyg
+d+NYDbQ7Uyf/D+IPV+DEmaYkDSFuJIA73ruL0DT8pVDJQ8LwBibPMObDKQECgYBa
+aUYxD6noE3diaj1GV5zYN5ubD2L47+jsvXjhOClOkkA8K+qko2qksrBno6YkfV8X
+zv8xWMVzgMbIT1X1S1VUGTxGJ3sUb6iPlYGXCWm9AAC7GDU2W8p1rGJYk5apR+zl
+4GmQdctRxKnaNICK3A2F/BBjYRzv4RNSmc+Fik9kewKBgHsCF3uEP7ONvmEjYLQ4
+7+6fZ+m4BXKeU/kKQoEXSjSFn0dBIHo+2yuafSUz04VJCVXUic3c47kHwVtgX5lu
+jEUL1jgK4aBbl9cvywupHBf3spAP89aocgFiC9uUJzp3u39U0LpgXY7Z+1lUsCL+
+VG2oGh0KVgazjUzmbTf9ZcLp
+-----END PRIVATE KEY-----
diff --git a/tests/user/certificate/private2.key b/tests/user/certificate/private2.key
new file mode 100644
index 00000000..59d83b9f
--- /dev/null
+++ b/tests/user/certificate/private2.key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCWzJibKtN8Zf7L
+gandINhFonx99AKi44iaZkrlMKEObE6Faf8NTUbUgK3VfJNYmCbA1baLVJ0YZJij
+J7S/4o7h7eeqcJVXJkEhWNTimWXNW/YCzTHe3SSapnSYOKmdHHRClplysL8OyyEG
+7pbX/aB9iAfFb/+vUFCX5sMwFFrYxOimKJ9Pc/NRFtdv1wNw1rqWKF1ZzagWRlG4
+QgzRGwQ4quc7yO98TKikj2OPiIt7Zd46hbqQxmgGBtCkVOZIhxu77OmNrFsXmM4r
+ZZpmqh0UdqcpwkRojVnGXmNqeMCd6dNTnLhr9wukUYw0KgE57zCDVr9Ix+p/dA5R
+1mG4RJ2XAgMBAAECggEAS5nXCDO4Qy1/R9eBqXLF+mMztpGWoMMhwQZ3ld+DXw+9
+bfVuAOU1FWRNwjHqTQg6pYJ/Oer5tzj3rRRC8dBLgckb078Nn9t125oFYHU3LHVm
+KJFm5yxHJaE94vLFVhbl0lxeIbmqj2gW7rq+tRpaU5TXEIzNyr6hKQZv5LLPuMx6
+MiBrSpkCwfPf9psv6k2GIGqE1JuY99dNqdEUi8UQryNMzV4pthUmVybO8NPxUY8M
+s/VAbG1Hy9tgInR3wRgTjEc2ejUJrTziiqiZarZtCp+JSZufYakDU9yZbu9v4Oz9
+ityPdApkW8CuZnJcUDAtdgtKMhWyBPnWcrUgkbV0AQKBgQDGY1saiI9M7VlleyDc
+QNVXpPCmOpDLso5X3hZrrHDgDIGkvXa026Q5ufkdxkybRYJeOCdYzIM/iXSJlgNe
+R2a+aoAsePfEVFAe96ZgzrLrBq7lGvcPXGpT6GTVl0d0CwN/vG1Tzk89Hq3xIBbh
+NTlM+j2ot66xgekIsE0v5Pi41wKBgQDCl14mgaui4DqYFYlI/ckI00r/X0/0HIhf
+kf/Ck/pkF89IeOAK+O4GOfVoMk3vi1gDYgiz6G7h+sUsFTOYKuP9io/vX0pIFNOA
+NPgaVtRKitiepNo4vwc+/PRmxvf2XXFXFRSiYf0jDzruvE3yDzWwX9P1nQFBQoPj
+r8g/6+7pQQKBgDXHnVzWBDLQbNmLxV6v3KXDutD1M2dk4h2DwQQzXO3/te1YxyNE
+H4LenV+q7/1vnGW6R0BVQIcq1gKuPf+Cz6Fy8Ygcyt3YFVgvvlSj8/CugR7ubmcl
+oFVavGsCdYZJrgsko2aCmQxykqi5EDrA2OW7OJfSI3NPSkLmuCXxplNFAoGBALHD
+D5pDqOTAzCY0vlY0qNrsEr4ZdvO8wQP1XtyEzB919MDy01CSuPZtKfeGxNWIyN1G
+SEb5lZnQuSCdOaXPwLjURMralQQmKlQbj26YVZTHJD5AwK1ILTloYWgmaUzhbfGs
+a04wD8xgVGjVEquHI3e9AueEBypztgJgiaGDSZxBAoGADpxUn3L6lJrPyOd3IJrj
+ypU/EfvY7Qd5pRTrJd9tObbi8zF1sWi/FcQNgoZP7oz/aklFfq8WWwJbe0fL1Wk/
+MeVHj8JEc/dh1ISgbHYdBgegvS6L30RcNRUJWANYcifEQPlSHTzYXviQ8tEOCq+S
+/TPqxnd2CkT6w3bSCJbxKVM=
+-----END PRIVATE KEY-----
diff --git a/tests/user/certificate/private3.key b/tests/user/certificate/private3.key
new file mode 100644
index 00000000..f4261623
--- /dev/null
+++ b/tests/user/certificate/private3.key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDCA+6P2eieXHaV
+JivtWif7SntjjkJm0juRKRRGsT3wt+zCZqoDe8zylTBN0mse/POWXdC+zXRMC2X/
+c4V10kgrvWbnNdFdUFfBUphiXSoqnUYHZ6Ta+b4UTzC2tECSUEnSCz9n1ofHnyqD
+yT9FELzVkRkQqexD+BFgZTF39R4q8BA4bWKQy94Kgvb+IP77+ou4fhkBLI1MX5nk
+Wa3Oyu4TMzT/tqgPE70hk8wQzUU2aiwJ7IsmnWE6Ysk7c4DYMJQF/51bi2ByZWER
+NjyBY6L+ZV90aL4UFR9O+Pw9HatfHVBRdmzSkKJOr9iu4summWgH0QYDmbkdhGwY
+vup0EmEfAgMBAAECggEAdEgFAGSbHebPD79sDnq9gcf3QgjuVU/lcbAMPf5W4GJr
+3WvItAPMJwwxgkL9/vmeSN37kY/0BuvB+yPStnYM2WJQPX0s+V+A6RZGzJWIAzh1
+01RUIwYR3XxE9wv7s3W5eNFS9DpI8OS9h3TjndJVSy8Gtc0SFP6l839S8dGQfiyN
+eMqV16M+TM0LwyEogvGa79l4HjMIcorypCXg8NVcDaxNJYnAcegoRwdhGsb4jKG6
+kB+Z4dfAKLu7OFT6/20Q0QUdA/PrdBRAFt8KPhrrweKaAApVtrU0OHNs9ULFHXnu
+kSVKZ+UTCUGWxMd4lJw5XZQ4FqUdb8Sxt8TUuvRioQKBgQDy6zY1EiqsDZE+sJbd
+/jnUWn+I4/xR5y4KmbEx76dWL39TooyiHYKABJQ9BgvBIXi95AXaRodwn12DhaW7
+VW0m4RgJH/FNZoxc9xOE2+EPr2pQGn6bvJK9IjsITDoAmDbguzMZ+TCDGZqIYiIE
+GTcgeW7NOBYM2Qy8Ufqe9zfV0QKBgQDMdo426TPxdU6Gb8AVOFFuXlL6Py0Sxk0q
+pEAhyEzCKV9HM1eX8aDrJ5++lFiMwlhkYRrWVBENPyhPgWo9sMATJM0AIsBKTSyg
+rVuqlaU8e+Pqyl8ZMOZ6uMq3zLts/Vp1sX5yU8vw5FqMddMas6SMpIoPEIAiJlse
+CujyJ29T7wKBgQCiQnry+C+IvYdHWK1tm2MFdW27Ao6IJuOaMQ8rS+l6qD9kni9S
+GmQRHv3lxSQU3UbJkIZYRsQxdkIAmEUb3PQMBE8JyUxlZxpa/q8LD9RFpeZdm1T2
+sf9SVosX/9K+ku4VLvXzY4AEEhYnA2W1VyJ7jqF0cwJHkrPvFtNRW9DwAQKBgCRi
+6NYu1DahSLM2Cfn8xskccinkulHABpWTG3KnoblgAXu7UFhTAO84Yv5YihWqtG5Q
+taT02v//gF39yvlljhkaEH14sb3HVCzYDRsjfH9yENKE5z2lbS7j2fexsJ0pzUJq
+rvULopyhFtguU75Jv/vjgEpEBnmNV+PVzzTg/bfzAoGAGz11E33qpZjVw6becf9w
+U8qnPfncIqSCg0fWNnsYwD56vI9L2ExCZG//SOUZ54b8GW+RaTFDHOlIE8dRAhrF
+M5QnEjm2S+wVPJz7gKQ3cVART8EPi/Q6BT7YIgNIhemq+AwW5xMhZcBiA3vRI/Eu
+vi807exD569efFLa9uspI8o=
+-----END PRIVATE KEY-----
diff --git a/tests/user/certificate/test_user_certificate.yml b/tests/user/certificate/test_user_certificate.yml
new file mode 100644
index 00000000..527c0f31
--- /dev/null
+++ b/tests/user/certificate/test_user_certificate.yml
@@ -0,0 +1,92 @@
+#
+# Generate self-signed certificates using openssl:
+#
+# openssl req -x509 -newkey rsa:2048 -days 365 -nodes -keyout private1.key -out cert1.pem -subj '/CN=test'
+# openssl req -x509 -newkey rsa:2048 -days 365 -nodes -keyout private2.key -out cert2.pem -subj '/CN=test'
+# openssl req -x509 -newkey rsa:2048 -days 365 -nodes -keyout private3.key -out cert3.pem -subj '/CN=test'
+#
+# Convert the certificate do DER for easier handling through CLI
+#
+# openssl x509 -outform der -in cert1.pem -out cert1.der
+# openssl x509 -outform der -in cert2.pem -out cert2.der
+# openssl x509 -outform der -in cert3.pem -out cert3.der
+#
+# Use base64:
+#
+# base64 cert1.der -w5000
+# base64 cert2.der -w5000
+# base64 cert3.der -w5000
+#
+---
+- name: Test user certificates
+ hosts: ipaserver
+ become: true
+ gather_facts: false
+
+ tasks:
+ - name: User test present
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: test
+ first: test
+ last: test
+
+ - name: User test cert members present
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: test
+ certificate:
+ - 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
+ action: member
+ register: result
+ failed_when: not result.changed
+
+ - name: User test cert members present again
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: test
+ first: test
+ last: test
+ certificate:
+ - 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
+ action: member
+ register: result
+ failed_when: result.changed
+
+ - name: User test cert members absent
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: test
+ certificate:
+ - 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
+ state: absent
+ action: member
+ register: result
+ failed_when: not result.changed
+
+ - name: User test cert members absent again
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: test
+ certificate:
+ - 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
+ state: absent
+ action: member
+ register: result
+ failed_when: result.changed
+
+ - name: User test absent
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: test
+ state: absent
+ register: result
+ failed_when: not result.changed
diff --git a/tests/user/certificate/test_users_certificate.yml b/tests/user/certificate/test_users_certificate.yml
new file mode 100644
index 00000000..b5abbde2
--- /dev/null
+++ b/tests/user/certificate/test_users_certificate.yml
@@ -0,0 +1,103 @@
+#
+# Generate self-signed certificates using openssl:
+#
+# openssl req -x509 -newkey rsa:2048 -days 365 -nodes -keyout private1.key -out cert1.pem -subj '/CN=test'
+# openssl req -x509 -newkey rsa:2048 -days 365 -nodes -keyout private2.key -out cert2.pem -subj '/CN=test'
+# openssl req -x509 -newkey rsa:2048 -days 365 -nodes -keyout private3.key -out cert3.pem -subj '/CN=test'
+#
+# Convert the certificate do DER for easier handling through CLI
+#
+# openssl x509 -outform der -in cert1.pem -out cert1.der
+# openssl x509 -outform der -in cert2.pem -out cert2.der
+# openssl x509 -outform der -in cert3.pem -out cert3.der
+#
+# Use base64:
+#
+# base64 cert1.der -w5000
+# base64 cert2.der -w5000
+# base64 cert3.der -w5000
+#
+---
+- name: Test user certificates
+ hosts: ipaserver
+ become: true
+ gather_facts: false
+
+ tasks:
+ - name: User test absent
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ users:
+ - name: test
+ state: absent
+
+ - name: User test present
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ users:
+ - name: test
+ first: test
+ last: test
+
+ - name: User test cert members present
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ users:
+ - name: test
+ certificate:
+ - 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
+ action: member
+ register: result
+ failed_when: not result.changed
+
+ - name: User test cert members present again
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ users:
+ - name: test
+ certificate:
+ - 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
+ action: member
+ register: result
+ failed_when: result.changed
+
+ - name: User test cert members absent
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ users:
+ - name: test
+ certificate:
+ - MIIC/zCCAeegAwIBAgIUZGHLaSYg1myp6EI4VGWSC27vOrswDQYJKoZIhvcNAQELBQAwDzENMAsGA1UEAwwEdGVzdDAeFw0xOTEwMTQxNjI4MzVaFw0yMDEwMTMxNjI4MzVaMA8xDTALBgNVBAMMBHRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDER/lB8wUAmPTSwSc/NOXNlzdpPOQDSwrhKH6XsqZF4KpQoSY/nmCjAhJmOVpOUo4K2fGRZ0yAH9fkGv6yJP6c7IAFjLeec7GPHVwN4bZrP1DXfTAmfmXhcRQbCYkV+wmq8Puzw/+xA9EJrrodnJPPsE6E8HnSVLF6Ys9+cJMJ7HuwOI+wYt3gkmspsir1tccmf4x1PP+yHJWdcXyetlFRcmZ8gspjqOR2jb89xSQsh8gcyDW6rPNlSTzYZ2FmNtjES6ZhCsYL31fQbF2QglidlLGpAlvHUUS+xCigW73cvhFPMWXcfO51Mr15RcgYTckY+7QZ2nYqplRBoDlQl6DnAgMBAAGjUzBRMB0GA1UdDgQWBBTPG99XVRdxpOXMZo3Nhy+ldnf13TAfBgNVHSMEGDAWgBTPG99XVRdxpOXMZo3Nhy+ldnf13TAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAjWTcnIl2mpNbfHAN8DB4Kk+RNRmhsH0y+r/47MXVTMMMToCfofeNY3Jeohu+2lIXMPQfTvXUbDTkNAGsGLv6LtQEUfSREqgk1eY7bT9BFfpH1uV2ZFhCO9jBA+E4bf55Kx7bgUNG31ykBshOsOblOJM1lS/0q4TWHAxrsU2PNwPi8X0ten+eGeB8aRshxS17Ij2cH0fdAMmSA+jMAvTIZl853Bxe0HuozauKwOFWL4qHm61c4O/j1mQCLqJKYfJ9mBDWFQLszd/tF+ePKiNhZCQly60F8Lumn2CDZj5UIkl8wk9Wls5n1BIQs+M8AN65NAdv7+js8jKUKCuyji8r3
+ - MIIC/zCCAeegAwIBAgIUAWE1vaA+mZd3nwZqwWH64EbHvR0wDQYJKoZIhvcNAQELBQAwDzENMAsGA1UEAwwEdGVzdDAeFw0xOTEwMTQxNjI4NDVaFw0yMDEwMTMxNjI4NDVaMA8xDTALBgNVBAMMBHRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCWzJibKtN8Zf7LgandINhFonx99AKi44iaZkrlMKEObE6Faf8NTUbUgK3VfJNYmCbA1baLVJ0YZJijJ7S/4o7h7eeqcJVXJkEhWNTimWXNW/YCzTHe3SSapnSYOKmdHHRClplysL8OyyEG7pbX/aB9iAfFb/+vUFCX5sMwFFrYxOimKJ9Pc/NRFtdv1wNw1rqWKF1ZzagWRlG4QgzRGwQ4quc7yO98TKikj2OPiIt7Zd46hbqQxmgGBtCkVOZIhxu77OmNrFsXmM4rZZpmqh0UdqcpwkRojVnGXmNqeMCd6dNTnLhr9wukUYw0KgE57zCDVr9Ix+p/dA5R1mG4RJ2XAgMBAAGjUzBRMB0GA1UdDgQWBBSbuiH2lNVrID3yt1SsFwtOFKOnpTAfBgNVHSMEGDAWgBSbuiH2lNVrID3yt1SsFwtOFKOnpTAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBCVWd293wWyohFqMFMHRBBg97T2Uc1yeT0dMH4BpuOaCqQp4q5ep+uLcXEI6+3mEwm8pa/ULQCD8yLLdotIWlG3+h/4boFpdiPFcBDgT8kGe+0KOzB8Nt7E13QYOu12MNi10qwGrjKhdhu1xBe4fpY5VCetVU1OLyuTsUyucQsFrtZI0SR83h+blbyoMZ7IhMngCfGUe1bnYeWnLbpFbigKfPuVDWsMH2kgj05EAd5EgHkWbX8QA8hmcmDKfNT3YZM8kiGQwmFrnQdq8bN0uHR8Nz+24cbmdbHcD65wlDW6GmYxi8mW+V6bAqn9pir/J14r4YFnqMGgjmdt81tscJV
+ - MIIC/zCCAeegAwIBAgIUTC33WUoYGFoIVGMwgjbc5J6xCyowDQYJKoZIhvcNAQELBQAwDzENMAsGA1UEAwwEdGVzdDAeFw0xOTEwMTQxNjI4NTJaFw0yMDEwMTMxNjI4NTJaMA8xDTALBgNVBAMMBHRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDCA+6P2eieXHaVJivtWif7SntjjkJm0juRKRRGsT3wt+zCZqoDe8zylTBN0mse/POWXdC+zXRMC2X/c4V10kgrvWbnNdFdUFfBUphiXSoqnUYHZ6Ta+b4UTzC2tECSUEnSCz9n1ofHnyqDyT9FELzVkRkQqexD+BFgZTF39R4q8BA4bWKQy94Kgvb+IP77+ou4fhkBLI1MX5nkWa3Oyu4TMzT/tqgPE70hk8wQzUU2aiwJ7IsmnWE6Ysk7c4DYMJQF/51bi2ByZWERNjyBY6L+ZV90aL4UFR9O+Pw9HatfHVBRdmzSkKJOr9iu4summWgH0QYDmbkdhGwYvup0EmEfAgMBAAGjUzBRMB0GA1UdDgQWBBSJCQ8ho0Ppe0khVhgiMqsvlgxIjzAfBgNVHSMEGDAWgBSJCQ8ho0Ppe0khVhgiMqsvlgxIjzAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAILLPnau32r/YoOVCVWQotGtySy36aFlHa3T8IkSpatNCPIf3U0FWS6TVYBwY0PBfdqWBkvCuJTupLh0OEP4TCsDa5pJGOK7blyfiAfcHajqyouACSVNlG63EPvB63h4H4F4HJnhDd4z7pVC/WPB8w5GTBJNjELmeWfH7nj7lu8UkOdLhzTKL40RPs0k4l09yYBmZqqExxGsSfvRBQcrwlAsvQ0E/cTNGbyzOKs3SbOM2WEHye6xNEsey01icYcjfjqvEd6mw3+WOUeJAuDH9/EOloFM2iz5Xp31Ig3WT0RVy+lMriG9GesPpFBs2xp9wQCXLNIkpbHKyYs3voMyBH
+ state: absent
+ action: member
+ #register: result
+ #failed_when: not result.changed
+
+ - name: User test cert members absent again
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ users:
+ - name: test
+ certificate:
+ - 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
+ state: absent
+ action: member
+ register: result
+ failed_when: result.changed
+
+ - name: User test absent
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ users:
+ - name: test
+ state: absent
+ register: result
+ failed_when: not result.changed
diff --git a/tests/user/certmapdata/test_user_certmapdata.yml b/tests/user/certmapdata/test_user_certmapdata.yml
new file mode 100644
index 00000000..cf5576ec
--- /dev/null
+++ b/tests/user/certmapdata/test_user_certmapdata.yml
@@ -0,0 +1,160 @@
+#
+# Generate self-signed certificates using openssl:
+#
+# openssl req -x509 -newkey rsa:2048 -days 365 -nodes -keyout private1.key -out cert1.pem -subj '/CN=test1'
+# openssl req -x509 -newkey rsa:2048 -days 365 -nodes -keyout private2.key -out cert2.pem -subj '/CN=test2'
+# openssl req -x509 -newkey rsa:2048 -days 365 -nodes -keyout private3.key -out cert3.pem -subj '/CN=test2'
+#
+# Convert the certificate do DER for easier handling through CLI
+#
+# openssl x509 -outform der -in cert1.pem -out cert1.der
+# openssl x509 -outform der -in cert2.pem -out cert2.der
+# openssl x509 -outform der -in cert3.pem -out cert3.der
+#
+# Use base64:
+#
+# base64 cert1.der -w5000
+# base64 cert2.der -w5000
+# base64 cert3.der -w5000
+#
+---
+- name: Test user certmapdata
+ hosts: ipaserver
+ become: true
+ gather_facts: false
+
+ tasks:
+ - name: User test absent
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: test
+ state: absent
+
+ - name: User test present
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: test
+ first: test
+ last: test
+ register: result
+ failed_when: not result.changed
+
+ - name: User test certmapdata members present
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: test
+ certmapdata:
+ - certificate: MIIDATCCAemgAwIBAgIUFDZuUg9kBvN+ubTBaS6d62KafvQwDQYJKoZIhvcNAQELBQAwEDEOMAwGA1UEAwwFdGVzdDEwHhcNMTkxMDE0MTk0ODM4WhcNMjAxMDEzMTk0ODM4WjAQMQ4wDAYDVQQDDAV0ZXN0MTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALrwv6KuOIZMxjp9aueRgJWKns7P7Oo8lo4ojBVhyB3K11+1OifLqfo2SL9HPx9XynvouMj+XnqbY+NRLOX9wPYAvA7rXUgN1zQYK5stCCTjW0V4QloHnMUPM0shIuErcTP1UMatzTaFxd+UkvZCMNbE9jXHeCd3uDYoqA8Y4yRuqQ4HcnbB7DyMNZHaSCHxQCvZzllJA9m1b+c2sO3l7008PibG5RSpPnrjMUeH4yzjaB8R7A/WApAA1g5bn+IXD2dDsbdHAVFdzqwkxxLlacD8pbM7jWtCI+qJwE6dXpPb5WRkUz3tZLkEW7EQJAi3TMy//hF/SobEul3WVjiO/HUCAwEAAaNTMFEwHQYDVR0OBBYEFCkUPLMp0M5rgxHNAYuunGM0if/vMB8GA1UdIwQYMBaAFCkUPLMp0M5rgxHNAYuunGM0if/vMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAI7gj1VllrF0eRqPP9xtSqWla+qGMpHUWur1yIoy3R8I7LV3muQpbgxsfOyH2PHj69v+8yvI5einvOXJVgJxcn/ERxm/prIdo+QlK4O/SDdswJWfjCaDlk03PzjDzHXeEWRwDFV9zpRx/hjLUn8knwBOSbUE8ImUGt37ZBMBsz++y+oCZJVxzwZgcXZ3L4yuhJ0l48Cz+2EEoYN08gJqNk1EzmpBcAYJJ0Ai1psFqu12b32fNIhWSSf5THldqNefdpBlMo5ZtC9wE//NTml+nebA1FJDSppTMfHP/rTb/wfNx5vc5KLYYR9wZUUUDeJhdNPlBZZuuVbn29X6a4teoBk=
+ - certificate: MIIDATCCAemgAwIBAgIUK2Sa8/xr/4H9BOB0K0SswbVmmMcwDQYJKoZIhvcNAQELBQAwEDEOMAwGA1UEAwwFdGVzdDIwHhcNMTkxMDE0MTk0ODM1WhcNMjAxMDEzMTk0ODM1WjAQMQ4wDAYDVQQDDAV0ZXN0MjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANQdGqRUTNCptUsZxVe03YTYyhg6+ovidYP9bPPsCS1FzOTCKV9maFv4GHGEI455lkGowW3okT2DPC5pgtH43vZkDtjXNy1JDyg1y4OmxfiAg4Uc0W9DnakvEokVyt44WRzXjlv2CBO+A7Zon8z3aJwKKCV4EfpuvRw/npqhrnGF/w/n7NXyeRXI6lom9hqIQzJoRjXrMIEbtzM8m2GWlFq8af1KJ+Cmm25c87aeyu7I0+BRCq21pwcyQ6Cx0Lo3szQVlD9ZN6wUfz3IDacLjoMOZkVrclIKO0DU595AVo86TD0C1TC/vCjmDGOfgoQsfS5OFfP+FmN6we9IVIAUcL8CAwEAAaNTMFEwHQYDVR0OBBYEFHTGQuoyDwtbHVLU0SseGvarrJKOMB8GA1UdIwQYMBaAFHTGQuoyDwtbHVLU0SseGvarrJKOMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAEGcA6GzCv67GYWoFK9zAjN01M79BDSuac2QV+9PYjQ7tLXQPGdoXJjJzrkJLgzTwqH2iIUqGoAZp30dW89yrJuA8s0gk3SbPOowYmst6pN6SeENxXL/1kn/IBm3+oHf5IWf7vaW4j8tYt7Q3x2K3V9GWRrozGEPIXk8yMeJq72wpfWynDxxYOepGG2+pSkm8soi9Fpt29pb+DtKB2U9GpMBS8vHU+1H4trIvEOMsd4v+X1+Vxlnt8tgy8/PrlKk1wLB9r1XA+W/vXPBe0tRcuntsXiniSKGC5oiR9AFS134HFEWuhxXWihNFzsLmNimvvxQBlXMRPZC1waCSoTKTAI=
+ - certificate: MIIDATCCAemgAwIBAgIUIa8TtXJ4Nq8VYrlgbSKcVt0FdckwDQYJKoZIhvcNAQELBQAwEDEOMAwGA1UEAwwFdGVzdDMwHhcNMTkxMDE0MTk0ODQ1WhcNMjAxMDEzMTk0ODQ1WjAQMQ4wDAYDVQQDDAV0ZXN0MzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMyttsxCiNH8qx83FTkQaUKxQXer6aMa5DpyfnGMh1K3icfEHyiKLkrjiuFbnfYC1s/iYkz9UyBQrneglYROGgr8TSFC5LXiVppI3/LONKuBh0GfmBM8dhYkOg6WmEB15EL7Hj3V6Xi/Sx3WFnvY/wAzds06linDp/I46jRXqMrWFuhXbf4A09OXpQs6KOMWkkitw3lKuKLgiNzXEiAHaS2YqW7UwSy9RLCrIDMwEmVzZ/gh3vGwM2jyfhOZ75U/xOt9U6jMQsp7hFQAoSeVBTuGpjI40g3IbNBRNi2SnERFzQFkJr0tzAX250XGDaRwRuLhilYoQoJl59B2cTzYsLECAwEAAaNTMFEwHQYDVR0OBBYEFD8iZgdSshdfyAMNfQNzS74Dl9UVMB8GA1UdIwQYMBaAFD8iZgdSshdfyAMNfQNzS74Dl9UVMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFrip5Hl7dHz3oqXLcoza9rQCiMsXV7Q2gVHJ6W2YZZlQpVOBmNPf0n42OVZrnIkDnuGD+pGuw65Aq/TnfMI2KrW8o//aOXLitR60moMEbj61IlBx3aUGvdhyevrz4tM8SHX05p4K86ZJ9jZuS/sNyDwBKBaBAqjW1Rjuqb2o+C9zvDgPWFX++8OgXljDPHR6XYAKpRBmbBZHxYXazjhj1gGhb9/txqDn4EniPXE4rZ/X5MwXzAPs7ROgvr7fkIQypO+O++FGn8rWQL+5zZY0GavOK6FMBJj8M6RDHwEEsXQqSHicsrL8iMx4jun82wgu+gO5lBPTMd0hjsOYR3eT0A=
+ action: member
+ register: result
+ failed_when: not result.changed
+
+ - name: User test certmapdata members present again
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: test
+ certmapdata:
+ - certificate: MIIDATCCAemgAwIBAgIUFDZuUg9kBvN+ubTBaS6d62KafvQwDQYJKoZIhvcNAQELBQAwEDEOMAwGA1UEAwwFdGVzdDEwHhcNMTkxMDE0MTk0ODM4WhcNMjAxMDEzMTk0ODM4WjAQMQ4wDAYDVQQDDAV0ZXN0MTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALrwv6KuOIZMxjp9aueRgJWKns7P7Oo8lo4ojBVhyB3K11+1OifLqfo2SL9HPx9XynvouMj+XnqbY+NRLOX9wPYAvA7rXUgN1zQYK5stCCTjW0V4QloHnMUPM0shIuErcTP1UMatzTaFxd+UkvZCMNbE9jXHeCd3uDYoqA8Y4yRuqQ4HcnbB7DyMNZHaSCHxQCvZzllJA9m1b+c2sO3l7008PibG5RSpPnrjMUeH4yzjaB8R7A/WApAA1g5bn+IXD2dDsbdHAVFdzqwkxxLlacD8pbM7jWtCI+qJwE6dXpPb5WRkUz3tZLkEW7EQJAi3TMy//hF/SobEul3WVjiO/HUCAwEAAaNTMFEwHQYDVR0OBBYEFCkUPLMp0M5rgxHNAYuunGM0if/vMB8GA1UdIwQYMBaAFCkUPLMp0M5rgxHNAYuunGM0if/vMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAI7gj1VllrF0eRqPP9xtSqWla+qGMpHUWur1yIoy3R8I7LV3muQpbgxsfOyH2PHj69v+8yvI5einvOXJVgJxcn/ERxm/prIdo+QlK4O/SDdswJWfjCaDlk03PzjDzHXeEWRwDFV9zpRx/hjLUn8knwBOSbUE8ImUGt37ZBMBsz++y+oCZJVxzwZgcXZ3L4yuhJ0l48Cz+2EEoYN08gJqNk1EzmpBcAYJJ0Ai1psFqu12b32fNIhWSSf5THldqNefdpBlMo5ZtC9wE//NTml+nebA1FJDSppTMfHP/rTb/wfNx5vc5KLYYR9wZUUUDeJhdNPlBZZuuVbn29X6a4teoBk=
+ - certificate: MIIDATCCAemgAwIBAgIUK2Sa8/xr/4H9BOB0K0SswbVmmMcwDQYJKoZIhvcNAQELBQAwEDEOMAwGA1UEAwwFdGVzdDIwHhcNMTkxMDE0MTk0ODM1WhcNMjAxMDEzMTk0ODM1WjAQMQ4wDAYDVQQDDAV0ZXN0MjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANQdGqRUTNCptUsZxVe03YTYyhg6+ovidYP9bPPsCS1FzOTCKV9maFv4GHGEI455lkGowW3okT2DPC5pgtH43vZkDtjXNy1JDyg1y4OmxfiAg4Uc0W9DnakvEokVyt44WRzXjlv2CBO+A7Zon8z3aJwKKCV4EfpuvRw/npqhrnGF/w/n7NXyeRXI6lom9hqIQzJoRjXrMIEbtzM8m2GWlFq8af1KJ+Cmm25c87aeyu7I0+BRCq21pwcyQ6Cx0Lo3szQVlD9ZN6wUfz3IDacLjoMOZkVrclIKO0DU595AVo86TD0C1TC/vCjmDGOfgoQsfS5OFfP+FmN6we9IVIAUcL8CAwEAAaNTMFEwHQYDVR0OBBYEFHTGQuoyDwtbHVLU0SseGvarrJKOMB8GA1UdIwQYMBaAFHTGQuoyDwtbHVLU0SseGvarrJKOMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAEGcA6GzCv67GYWoFK9zAjN01M79BDSuac2QV+9PYjQ7tLXQPGdoXJjJzrkJLgzTwqH2iIUqGoAZp30dW89yrJuA8s0gk3SbPOowYmst6pN6SeENxXL/1kn/IBm3+oHf5IWf7vaW4j8tYt7Q3x2K3V9GWRrozGEPIXk8yMeJq72wpfWynDxxYOepGG2+pSkm8soi9Fpt29pb+DtKB2U9GpMBS8vHU+1H4trIvEOMsd4v+X1+Vxlnt8tgy8/PrlKk1wLB9r1XA+W/vXPBe0tRcuntsXiniSKGC5oiR9AFS134HFEWuhxXWihNFzsLmNimvvxQBlXMRPZC1waCSoTKTAI=
+ - certificate: MIIDATCCAemgAwIBAgIUIa8TtXJ4Nq8VYrlgbSKcVt0FdckwDQYJKoZIhvcNAQELBQAwEDEOMAwGA1UEAwwFdGVzdDMwHhcNMTkxMDE0MTk0ODQ1WhcNMjAxMDEzMTk0ODQ1WjAQMQ4wDAYDVQQDDAV0ZXN0MzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMyttsxCiNH8qx83FTkQaUKxQXer6aMa5DpyfnGMh1K3icfEHyiKLkrjiuFbnfYC1s/iYkz9UyBQrneglYROGgr8TSFC5LXiVppI3/LONKuBh0GfmBM8dhYkOg6WmEB15EL7Hj3V6Xi/Sx3WFnvY/wAzds06linDp/I46jRXqMrWFuhXbf4A09OXpQs6KOMWkkitw3lKuKLgiNzXEiAHaS2YqW7UwSy9RLCrIDMwEmVzZ/gh3vGwM2jyfhOZ75U/xOt9U6jMQsp7hFQAoSeVBTuGpjI40g3IbNBRNi2SnERFzQFkJr0tzAX250XGDaRwRuLhilYoQoJl59B2cTzYsLECAwEAAaNTMFEwHQYDVR0OBBYEFD8iZgdSshdfyAMNfQNzS74Dl9UVMB8GA1UdIwQYMBaAFD8iZgdSshdfyAMNfQNzS74Dl9UVMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFrip5Hl7dHz3oqXLcoza9rQCiMsXV7Q2gVHJ6W2YZZlQpVOBmNPf0n42OVZrnIkDnuGD+pGuw65Aq/TnfMI2KrW8o//aOXLitR60moMEbj61IlBx3aUGvdhyevrz4tM8SHX05p4K86ZJ9jZuS/sNyDwBKBaBAqjW1Rjuqb2o+C9zvDgPWFX++8OgXljDPHR6XYAKpRBmbBZHxYXazjhj1gGhb9/txqDn4EniPXE4rZ/X5MwXzAPs7ROgvr7fkIQypO+O++FGn8rWQL+5zZY0GavOK6FMBJj8M6RDHwEEsXQqSHicsrL8iMx4jun82wgu+gO5lBPTMd0hjsOYR3eT0A=
+ action: member
+ register: result
+ failed_when: result.changed
+
+ - name: User test certmapdata members absent
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: test
+ certmapdata:
+ - certificate: MIIDATCCAemgAwIBAgIUFDZuUg9kBvN+ubTBaS6d62KafvQwDQYJKoZIhvcNAQELBQAwEDEOMAwGA1UEAwwFdGVzdDEwHhcNMTkxMDE0MTk0ODM4WhcNMjAxMDEzMTk0ODM4WjAQMQ4wDAYDVQQDDAV0ZXN0MTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALrwv6KuOIZMxjp9aueRgJWKns7P7Oo8lo4ojBVhyB3K11+1OifLqfo2SL9HPx9XynvouMj+XnqbY+NRLOX9wPYAvA7rXUgN1zQYK5stCCTjW0V4QloHnMUPM0shIuErcTP1UMatzTaFxd+UkvZCMNbE9jXHeCd3uDYoqA8Y4yRuqQ4HcnbB7DyMNZHaSCHxQCvZzllJA9m1b+c2sO3l7008PibG5RSpPnrjMUeH4yzjaB8R7A/WApAA1g5bn+IXD2dDsbdHAVFdzqwkxxLlacD8pbM7jWtCI+qJwE6dXpPb5WRkUz3tZLkEW7EQJAi3TMy//hF/SobEul3WVjiO/HUCAwEAAaNTMFEwHQYDVR0OBBYEFCkUPLMp0M5rgxHNAYuunGM0if/vMB8GA1UdIwQYMBaAFCkUPLMp0M5rgxHNAYuunGM0if/vMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAI7gj1VllrF0eRqPP9xtSqWla+qGMpHUWur1yIoy3R8I7LV3muQpbgxsfOyH2PHj69v+8yvI5einvOXJVgJxcn/ERxm/prIdo+QlK4O/SDdswJWfjCaDlk03PzjDzHXeEWRwDFV9zpRx/hjLUn8knwBOSbUE8ImUGt37ZBMBsz++y+oCZJVxzwZgcXZ3L4yuhJ0l48Cz+2EEoYN08gJqNk1EzmpBcAYJJ0Ai1psFqu12b32fNIhWSSf5THldqNefdpBlMo5ZtC9wE//NTml+nebA1FJDSppTMfHP/rTb/wfNx5vc5KLYYR9wZUUUDeJhdNPlBZZuuVbn29X6a4teoBk=
+ - certificate: MIIDATCCAemgAwIBAgIUK2Sa8/xr/4H9BOB0K0SswbVmmMcwDQYJKoZIhvcNAQELBQAwEDEOMAwGA1UEAwwFdGVzdDIwHhcNMTkxMDE0MTk0ODM1WhcNMjAxMDEzMTk0ODM1WjAQMQ4wDAYDVQQDDAV0ZXN0MjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANQdGqRUTNCptUsZxVe03YTYyhg6+ovidYP9bPPsCS1FzOTCKV9maFv4GHGEI455lkGowW3okT2DPC5pgtH43vZkDtjXNy1JDyg1y4OmxfiAg4Uc0W9DnakvEokVyt44WRzXjlv2CBO+A7Zon8z3aJwKKCV4EfpuvRw/npqhrnGF/w/n7NXyeRXI6lom9hqIQzJoRjXrMIEbtzM8m2GWlFq8af1KJ+Cmm25c87aeyu7I0+BRCq21pwcyQ6Cx0Lo3szQVlD9ZN6wUfz3IDacLjoMOZkVrclIKO0DU595AVo86TD0C1TC/vCjmDGOfgoQsfS5OFfP+FmN6we9IVIAUcL8CAwEAAaNTMFEwHQYDVR0OBBYEFHTGQuoyDwtbHVLU0SseGvarrJKOMB8GA1UdIwQYMBaAFHTGQuoyDwtbHVLU0SseGvarrJKOMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAEGcA6GzCv67GYWoFK9zAjN01M79BDSuac2QV+9PYjQ7tLXQPGdoXJjJzrkJLgzTwqH2iIUqGoAZp30dW89yrJuA8s0gk3SbPOowYmst6pN6SeENxXL/1kn/IBm3+oHf5IWf7vaW4j8tYt7Q3x2K3V9GWRrozGEPIXk8yMeJq72wpfWynDxxYOepGG2+pSkm8soi9Fpt29pb+DtKB2U9GpMBS8vHU+1H4trIvEOMsd4v+X1+Vxlnt8tgy8/PrlKk1wLB9r1XA+W/vXPBe0tRcuntsXiniSKGC5oiR9AFS134HFEWuhxXWihNFzsLmNimvvxQBlXMRPZC1waCSoTKTAI=
+ - certificate: MIIDATCCAemgAwIBAgIUIa8TtXJ4Nq8VYrlgbSKcVt0FdckwDQYJKoZIhvcNAQELBQAwEDEOMAwGA1UEAwwFdGVzdDMwHhcNMTkxMDE0MTk0ODQ1WhcNMjAxMDEzMTk0ODQ1WjAQMQ4wDAYDVQQDDAV0ZXN0MzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMyttsxCiNH8qx83FTkQaUKxQXer6aMa5DpyfnGMh1K3icfEHyiKLkrjiuFbnfYC1s/iYkz9UyBQrneglYROGgr8TSFC5LXiVppI3/LONKuBh0GfmBM8dhYkOg6WmEB15EL7Hj3V6Xi/Sx3WFnvY/wAzds06linDp/I46jRXqMrWFuhXbf4A09OXpQs6KOMWkkitw3lKuKLgiNzXEiAHaS2YqW7UwSy9RLCrIDMwEmVzZ/gh3vGwM2jyfhOZ75U/xOt9U6jMQsp7hFQAoSeVBTuGpjI40g3IbNBRNi2SnERFzQFkJr0tzAX250XGDaRwRuLhilYoQoJl59B2cTzYsLECAwEAAaNTMFEwHQYDVR0OBBYEFD8iZgdSshdfyAMNfQNzS74Dl9UVMB8GA1UdIwQYMBaAFD8iZgdSshdfyAMNfQNzS74Dl9UVMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFrip5Hl7dHz3oqXLcoza9rQCiMsXV7Q2gVHJ6W2YZZlQpVOBmNPf0n42OVZrnIkDnuGD+pGuw65Aq/TnfMI2KrW8o//aOXLitR60moMEbj61IlBx3aUGvdhyevrz4tM8SHX05p4K86ZJ9jZuS/sNyDwBKBaBAqjW1Rjuqb2o+C9zvDgPWFX++8OgXljDPHR6XYAKpRBmbBZHxYXazjhj1gGhb9/txqDn4EniPXE4rZ/X5MwXzAPs7ROgvr7fkIQypO+O++FGn8rWQL+5zZY0GavOK6FMBJj8M6RDHwEEsXQqSHicsrL8iMx4jun82wgu+gO5lBPTMd0hjsOYR3eT0A=
+ action: member
+ state: absent
+ register: result
+ failed_when: not result.changed
+
+ - name: User test certmapdata members absent again
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: test
+ certmapdata:
+ - certificate: MIIDATCCAemgAwIBAgIUFDZuUg9kBvN+ubTBaS6d62KafvQwDQYJKoZIhvcNAQELBQAwEDEOMAwGA1UEAwwFdGVzdDEwHhcNMTkxMDE0MTk0ODM4WhcNMjAxMDEzMTk0ODM4WjAQMQ4wDAYDVQQDDAV0ZXN0MTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALrwv6KuOIZMxjp9aueRgJWKns7P7Oo8lo4ojBVhyB3K11+1OifLqfo2SL9HPx9XynvouMj+XnqbY+NRLOX9wPYAvA7rXUgN1zQYK5stCCTjW0V4QloHnMUPM0shIuErcTP1UMatzTaFxd+UkvZCMNbE9jXHeCd3uDYoqA8Y4yRuqQ4HcnbB7DyMNZHaSCHxQCvZzllJA9m1b+c2sO3l7008PibG5RSpPnrjMUeH4yzjaB8R7A/WApAA1g5bn+IXD2dDsbdHAVFdzqwkxxLlacD8pbM7jWtCI+qJwE6dXpPb5WRkUz3tZLkEW7EQJAi3TMy//hF/SobEul3WVjiO/HUCAwEAAaNTMFEwHQYDVR0OBBYEFCkUPLMp0M5rgxHNAYuunGM0if/vMB8GA1UdIwQYMBaAFCkUPLMp0M5rgxHNAYuunGM0if/vMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAI7gj1VllrF0eRqPP9xtSqWla+qGMpHUWur1yIoy3R8I7LV3muQpbgxsfOyH2PHj69v+8yvI5einvOXJVgJxcn/ERxm/prIdo+QlK4O/SDdswJWfjCaDlk03PzjDzHXeEWRwDFV9zpRx/hjLUn8knwBOSbUE8ImUGt37ZBMBsz++y+oCZJVxzwZgcXZ3L4yuhJ0l48Cz+2EEoYN08gJqNk1EzmpBcAYJJ0Ai1psFqu12b32fNIhWSSf5THldqNefdpBlMo5ZtC9wE//NTml+nebA1FJDSppTMfHP/rTb/wfNx5vc5KLYYR9wZUUUDeJhdNPlBZZuuVbn29X6a4teoBk=
+ - certificate: MIIDATCCAemgAwIBAgIUK2Sa8/xr/4H9BOB0K0SswbVmmMcwDQYJKoZIhvcNAQELBQAwEDEOMAwGA1UEAwwFdGVzdDIwHhcNMTkxMDE0MTk0ODM1WhcNMjAxMDEzMTk0ODM1WjAQMQ4wDAYDVQQDDAV0ZXN0MjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANQdGqRUTNCptUsZxVe03YTYyhg6+ovidYP9bPPsCS1FzOTCKV9maFv4GHGEI455lkGowW3okT2DPC5pgtH43vZkDtjXNy1JDyg1y4OmxfiAg4Uc0W9DnakvEokVyt44WRzXjlv2CBO+A7Zon8z3aJwKKCV4EfpuvRw/npqhrnGF/w/n7NXyeRXI6lom9hqIQzJoRjXrMIEbtzM8m2GWlFq8af1KJ+Cmm25c87aeyu7I0+BRCq21pwcyQ6Cx0Lo3szQVlD9ZN6wUfz3IDacLjoMOZkVrclIKO0DU595AVo86TD0C1TC/vCjmDGOfgoQsfS5OFfP+FmN6we9IVIAUcL8CAwEAAaNTMFEwHQYDVR0OBBYEFHTGQuoyDwtbHVLU0SseGvarrJKOMB8GA1UdIwQYMBaAFHTGQuoyDwtbHVLU0SseGvarrJKOMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAEGcA6GzCv67GYWoFK9zAjN01M79BDSuac2QV+9PYjQ7tLXQPGdoXJjJzrkJLgzTwqH2iIUqGoAZp30dW89yrJuA8s0gk3SbPOowYmst6pN6SeENxXL/1kn/IBm3+oHf5IWf7vaW4j8tYt7Q3x2K3V9GWRrozGEPIXk8yMeJq72wpfWynDxxYOepGG2+pSkm8soi9Fpt29pb+DtKB2U9GpMBS8vHU+1H4trIvEOMsd4v+X1+Vxlnt8tgy8/PrlKk1wLB9r1XA+W/vXPBe0tRcuntsXiniSKGC5oiR9AFS134HFEWuhxXWihNFzsLmNimvvxQBlXMRPZC1waCSoTKTAI=
+ - certificate: MIIDATCCAemgAwIBAgIUIa8TtXJ4Nq8VYrlgbSKcVt0FdckwDQYJKoZIhvcNAQELBQAwEDEOMAwGA1UEAwwFdGVzdDMwHhcNMTkxMDE0MTk0ODQ1WhcNMjAxMDEzMTk0ODQ1WjAQMQ4wDAYDVQQDDAV0ZXN0MzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMyttsxCiNH8qx83FTkQaUKxQXer6aMa5DpyfnGMh1K3icfEHyiKLkrjiuFbnfYC1s/iYkz9UyBQrneglYROGgr8TSFC5LXiVppI3/LONKuBh0GfmBM8dhYkOg6WmEB15EL7Hj3V6Xi/Sx3WFnvY/wAzds06linDp/I46jRXqMrWFuhXbf4A09OXpQs6KOMWkkitw3lKuKLgiNzXEiAHaS2YqW7UwSy9RLCrIDMwEmVzZ/gh3vGwM2jyfhOZ75U/xOt9U6jMQsp7hFQAoSeVBTuGpjI40g3IbNBRNi2SnERFzQFkJr0tzAX250XGDaRwRuLhilYoQoJl59B2cTzYsLECAwEAAaNTMFEwHQYDVR0OBBYEFD8iZgdSshdfyAMNfQNzS74Dl9UVMB8GA1UdIwQYMBaAFD8iZgdSshdfyAMNfQNzS74Dl9UVMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFrip5Hl7dHz3oqXLcoza9rQCiMsXV7Q2gVHJ6W2YZZlQpVOBmNPf0n42OVZrnIkDnuGD+pGuw65Aq/TnfMI2KrW8o//aOXLitR60moMEbj61IlBx3aUGvdhyevrz4tM8SHX05p4K86ZJ9jZuS/sNyDwBKBaBAqjW1Rjuqb2o+C9zvDgPWFX++8OgXljDPHR6XYAKpRBmbBZHxYXazjhj1gGhb9/txqDn4EniPXE4rZ/X5MwXzAPs7ROgvr7fkIQypO+O++FGn8rWQL+5zZY0GavOK6FMBJj8M6RDHwEEsXQqSHicsrL8iMx4jun82wgu+gO5lBPTMd0hjsOYR3eT0A=
+ action: member
+ state: absent
+ register: result
+ failed_when: result.changed
+
+ - name: User test certmapdata members present
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: test
+ certmapdata:
+ - issuer: CN=issuer1
+ subject: CN=subject1
+ - issuer: CN=issuer2
+ subject: CN=subject2
+ - issuer: CN=issuer3
+ subject: CN=subject3
+ action: member
+ register: result
+ failed_when: not result.changed
+
+ - name: User test certmapdata members present again
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: test
+ certmapdata:
+ - issuer: CN=issuer1
+ subject: CN=subject1
+ - issuer: CN=issuer2
+ subject: CN=subject2
+ - issuer: CN=issuer3
+ subject: CN=subject3
+ action: member
+ register: result
+ failed_when: result.changed
+
+ - name: User test certmapdata members absent
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: test
+ certmapdata:
+ - issuer: CN=issuer1
+ subject: CN=subject1
+ - issuer: CN=issuer2
+ subject: CN=subject2
+ - issuer: CN=issuer3
+ subject: CN=subject3
+ action: member
+ state: absent
+ register: result
+ failed_when: not result.changed
+
+ - name: User test certmapdata members absent again
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: test
+ certmapdata:
+ - issuer: CN=issuer1
+ subject: CN=subject1
+ - issuer: CN=issuer2
+ subject: CN=subject2
+ - issuer: CN=issuer3
+ subject: CN=subject3
+ action: member
+ state: absent
+ register: result
+ failed_when: result.changed
+
+ - name: User test absent
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: test
+ state: absent
+ register: result
+ failed_when: not result.changed
diff --git a/tests/user/certmapdata/test_user_certmapdata_issuer_subject.yml b/tests/user/certmapdata/test_user_certmapdata_issuer_subject.yml
new file mode 100644
index 00000000..0309c6af
--- /dev/null
+++ b/tests/user/certmapdata/test_user_certmapdata_issuer_subject.yml
@@ -0,0 +1,91 @@
+---
+- name: Test user certmapdata
+ hosts: ipaserver
+ become: true
+ gather_facts: false
+
+ tasks:
+ - name: User test absent
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: test
+ state: absent
+
+ - name: User test present
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: test
+ first: test
+ last: test
+ register: result
+ failed_when: not result.changed
+
+ - name: User test certmapdata members present
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: test
+ certmapdata:
+ - issuer: CN=issuer1
+ subject: CN=subject1
+ - issuer: CN=issuer2
+ subject: CN=subject2
+ - issuer: CN=issuer3
+ subject: CN=subject3
+ action: member
+ register: result
+ failed_when: not result.changed
+
+ - name: User test certmapdata members present again
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: test
+ certmapdata:
+ - issuer: CN=issuer1
+ subject: CN=subject1
+ - issuer: CN=issuer2
+ subject: CN=subject2
+ - issuer: CN=issuer3
+ subject: CN=subject3
+ action: member
+ register: result
+ failed_when: result.changed
+
+ - name: User test certmapdata members absent
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: test
+ certmapdata:
+ - issuer: CN=issuer1
+ subject: CN=subject1
+ - issuer: CN=issuer2
+ subject: CN=subject2
+ - issuer: CN=issuer3
+ subject: CN=subject3
+ action: member
+ state: absent
+ register: result
+ failed_when: not result.changed
+
+ - name: User test certmapdata members absent again
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: test
+ certmapdata:
+ - issuer: CN=issuer1
+ subject: CN=subject1
+ - issuer: CN=issuer2
+ subject: CN=subject2
+ - issuer: CN=issuer3
+ subject: CN=subject3
+ action: member
+ state: absent
+ register: result
+ failed_when: result.changed
+
+ - name: User test absent
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: test
+ state: absent
+ register: result
+ failed_when: not result.changed
diff --git a/tests/user/certmapdata/test_users_certmapdata.yml b/tests/user/certmapdata/test_users_certmapdata.yml
new file mode 100644
index 00000000..5509fa4c
--- /dev/null
+++ b/tests/user/certmapdata/test_users_certmapdata.yml
@@ -0,0 +1,171 @@
+#
+# Generate self-signed certificates using openssl:
+#
+# openssl req -x509 -newkey rsa:2048 -days 365 -nodes -keyout private1.key -out cert1.pem -subj '/CN=test1'
+# openssl req -x509 -newkey rsa:2048 -days 365 -nodes -keyout private2.key -out cert2.pem -subj '/CN=test2'
+# openssl req -x509 -newkey rsa:2048 -days 365 -nodes -keyout private3.key -out cert3.pem -subj '/CN=test2'
+#
+# Convert the certificate do DER for easier handling through CLI
+#
+# openssl x509 -outform der -in cert1.pem -out cert1.der
+# openssl x509 -outform der -in cert2.pem -out cert2.der
+# openssl x509 -outform der -in cert3.pem -out cert3.der
+#
+# Use base64:
+#
+# base64 cert1.der -w5000
+# base64 cert2.der -w5000
+# base64 cert3.der -w5000
+#
+---
+- name: Test user certmapdata
+ hosts: ipaserver
+ become: true
+ gather_facts: false
+
+ tasks:
+ - name: User test absent
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ users:
+ - name: test
+ state: absent
+
+ - name: User test present
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ users:
+ - name: test
+ first: test
+ last: test
+ register: result
+ failed_when: not result.changed
+
+ - name: User test certmapdata members present
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ users:
+ - name: test
+ certmapdata:
+ - certificate: MIIDATCCAemgAwIBAgIUFDZuUg9kBvN+ubTBaS6d62KafvQwDQYJKoZIhvcNAQELBQAwEDEOMAwGA1UEAwwFdGVzdDEwHhcNMTkxMDE0MTk0ODM4WhcNMjAxMDEzMTk0ODM4WjAQMQ4wDAYDVQQDDAV0ZXN0MTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALrwv6KuOIZMxjp9aueRgJWKns7P7Oo8lo4ojBVhyB3K11+1OifLqfo2SL9HPx9XynvouMj+XnqbY+NRLOX9wPYAvA7rXUgN1zQYK5stCCTjW0V4QloHnMUPM0shIuErcTP1UMatzTaFxd+UkvZCMNbE9jXHeCd3uDYoqA8Y4yRuqQ4HcnbB7DyMNZHaSCHxQCvZzllJA9m1b+c2sO3l7008PibG5RSpPnrjMUeH4yzjaB8R7A/WApAA1g5bn+IXD2dDsbdHAVFdzqwkxxLlacD8pbM7jWtCI+qJwE6dXpPb5WRkUz3tZLkEW7EQJAi3TMy//hF/SobEul3WVjiO/HUCAwEAAaNTMFEwHQYDVR0OBBYEFCkUPLMp0M5rgxHNAYuunGM0if/vMB8GA1UdIwQYMBaAFCkUPLMp0M5rgxHNAYuunGM0if/vMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAI7gj1VllrF0eRqPP9xtSqWla+qGMpHUWur1yIoy3R8I7LV3muQpbgxsfOyH2PHj69v+8yvI5einvOXJVgJxcn/ERxm/prIdo+QlK4O/SDdswJWfjCaDlk03PzjDzHXeEWRwDFV9zpRx/hjLUn8knwBOSbUE8ImUGt37ZBMBsz++y+oCZJVxzwZgcXZ3L4yuhJ0l48Cz+2EEoYN08gJqNk1EzmpBcAYJJ0Ai1psFqu12b32fNIhWSSf5THldqNefdpBlMo5ZtC9wE//NTml+nebA1FJDSppTMfHP/rTb/wfNx5vc5KLYYR9wZUUUDeJhdNPlBZZuuVbn29X6a4teoBk=
+ - certificate: MIIDATCCAemgAwIBAgIUK2Sa8/xr/4H9BOB0K0SswbVmmMcwDQYJKoZIhvcNAQELBQAwEDEOMAwGA1UEAwwFdGVzdDIwHhcNMTkxMDE0MTk0ODM1WhcNMjAxMDEzMTk0ODM1WjAQMQ4wDAYDVQQDDAV0ZXN0MjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANQdGqRUTNCptUsZxVe03YTYyhg6+ovidYP9bPPsCS1FzOTCKV9maFv4GHGEI455lkGowW3okT2DPC5pgtH43vZkDtjXNy1JDyg1y4OmxfiAg4Uc0W9DnakvEokVyt44WRzXjlv2CBO+A7Zon8z3aJwKKCV4EfpuvRw/npqhrnGF/w/n7NXyeRXI6lom9hqIQzJoRjXrMIEbtzM8m2GWlFq8af1KJ+Cmm25c87aeyu7I0+BRCq21pwcyQ6Cx0Lo3szQVlD9ZN6wUfz3IDacLjoMOZkVrclIKO0DU595AVo86TD0C1TC/vCjmDGOfgoQsfS5OFfP+FmN6we9IVIAUcL8CAwEAAaNTMFEwHQYDVR0OBBYEFHTGQuoyDwtbHVLU0SseGvarrJKOMB8GA1UdIwQYMBaAFHTGQuoyDwtbHVLU0SseGvarrJKOMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAEGcA6GzCv67GYWoFK9zAjN01M79BDSuac2QV+9PYjQ7tLXQPGdoXJjJzrkJLgzTwqH2iIUqGoAZp30dW89yrJuA8s0gk3SbPOowYmst6pN6SeENxXL/1kn/IBm3+oHf5IWf7vaW4j8tYt7Q3x2K3V9GWRrozGEPIXk8yMeJq72wpfWynDxxYOepGG2+pSkm8soi9Fpt29pb+DtKB2U9GpMBS8vHU+1H4trIvEOMsd4v+X1+Vxlnt8tgy8/PrlKk1wLB9r1XA+W/vXPBe0tRcuntsXiniSKGC5oiR9AFS134HFEWuhxXWihNFzsLmNimvvxQBlXMRPZC1waCSoTKTAI=
+ - certificate: MIIDATCCAemgAwIBAgIUIa8TtXJ4Nq8VYrlgbSKcVt0FdckwDQYJKoZIhvcNAQELBQAwEDEOMAwGA1UEAwwFdGVzdDMwHhcNMTkxMDE0MTk0ODQ1WhcNMjAxMDEzMTk0ODQ1WjAQMQ4wDAYDVQQDDAV0ZXN0MzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMyttsxCiNH8qx83FTkQaUKxQXer6aMa5DpyfnGMh1K3icfEHyiKLkrjiuFbnfYC1s/iYkz9UyBQrneglYROGgr8TSFC5LXiVppI3/LONKuBh0GfmBM8dhYkOg6WmEB15EL7Hj3V6Xi/Sx3WFnvY/wAzds06linDp/I46jRXqMrWFuhXbf4A09OXpQs6KOMWkkitw3lKuKLgiNzXEiAHaS2YqW7UwSy9RLCrIDMwEmVzZ/gh3vGwM2jyfhOZ75U/xOt9U6jMQsp7hFQAoSeVBTuGpjI40g3IbNBRNi2SnERFzQFkJr0tzAX250XGDaRwRuLhilYoQoJl59B2cTzYsLECAwEAAaNTMFEwHQYDVR0OBBYEFD8iZgdSshdfyAMNfQNzS74Dl9UVMB8GA1UdIwQYMBaAFD8iZgdSshdfyAMNfQNzS74Dl9UVMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFrip5Hl7dHz3oqXLcoza9rQCiMsXV7Q2gVHJ6W2YZZlQpVOBmNPf0n42OVZrnIkDnuGD+pGuw65Aq/TnfMI2KrW8o//aOXLitR60moMEbj61IlBx3aUGvdhyevrz4tM8SHX05p4K86ZJ9jZuS/sNyDwBKBaBAqjW1Rjuqb2o+C9zvDgPWFX++8OgXljDPHR6XYAKpRBmbBZHxYXazjhj1gGhb9/txqDn4EniPXE4rZ/X5MwXzAPs7ROgvr7fkIQypO+O++FGn8rWQL+5zZY0GavOK6FMBJj8M6RDHwEEsXQqSHicsrL8iMx4jun82wgu+gO5lBPTMd0hjsOYR3eT0A=
+ action: member
+ register: result
+ failed_when: not result.changed
+
+ - name: User test certmapdata members present again
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ users:
+ - name: test
+ certmapdata:
+ - certificate: MIIDATCCAemgAwIBAgIUFDZuUg9kBvN+ubTBaS6d62KafvQwDQYJKoZIhvcNAQELBQAwEDEOMAwGA1UEAwwFdGVzdDEwHhcNMTkxMDE0MTk0ODM4WhcNMjAxMDEzMTk0ODM4WjAQMQ4wDAYDVQQDDAV0ZXN0MTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALrwv6KuOIZMxjp9aueRgJWKns7P7Oo8lo4ojBVhyB3K11+1OifLqfo2SL9HPx9XynvouMj+XnqbY+NRLOX9wPYAvA7rXUgN1zQYK5stCCTjW0V4QloHnMUPM0shIuErcTP1UMatzTaFxd+UkvZCMNbE9jXHeCd3uDYoqA8Y4yRuqQ4HcnbB7DyMNZHaSCHxQCvZzllJA9m1b+c2sO3l7008PibG5RSpPnrjMUeH4yzjaB8R7A/WApAA1g5bn+IXD2dDsbdHAVFdzqwkxxLlacD8pbM7jWtCI+qJwE6dXpPb5WRkUz3tZLkEW7EQJAi3TMy//hF/SobEul3WVjiO/HUCAwEAAaNTMFEwHQYDVR0OBBYEFCkUPLMp0M5rgxHNAYuunGM0if/vMB8GA1UdIwQYMBaAFCkUPLMp0M5rgxHNAYuunGM0if/vMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAI7gj1VllrF0eRqPP9xtSqWla+qGMpHUWur1yIoy3R8I7LV3muQpbgxsfOyH2PHj69v+8yvI5einvOXJVgJxcn/ERxm/prIdo+QlK4O/SDdswJWfjCaDlk03PzjDzHXeEWRwDFV9zpRx/hjLUn8knwBOSbUE8ImUGt37ZBMBsz++y+oCZJVxzwZgcXZ3L4yuhJ0l48Cz+2EEoYN08gJqNk1EzmpBcAYJJ0Ai1psFqu12b32fNIhWSSf5THldqNefdpBlMo5ZtC9wE//NTml+nebA1FJDSppTMfHP/rTb/wfNx5vc5KLYYR9wZUUUDeJhdNPlBZZuuVbn29X6a4teoBk=
+ - certificate: MIIDATCCAemgAwIBAgIUK2Sa8/xr/4H9BOB0K0SswbVmmMcwDQYJKoZIhvcNAQELBQAwEDEOMAwGA1UEAwwFdGVzdDIwHhcNMTkxMDE0MTk0ODM1WhcNMjAxMDEzMTk0ODM1WjAQMQ4wDAYDVQQDDAV0ZXN0MjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANQdGqRUTNCptUsZxVe03YTYyhg6+ovidYP9bPPsCS1FzOTCKV9maFv4GHGEI455lkGowW3okT2DPC5pgtH43vZkDtjXNy1JDyg1y4OmxfiAg4Uc0W9DnakvEokVyt44WRzXjlv2CBO+A7Zon8z3aJwKKCV4EfpuvRw/npqhrnGF/w/n7NXyeRXI6lom9hqIQzJoRjXrMIEbtzM8m2GWlFq8af1KJ+Cmm25c87aeyu7I0+BRCq21pwcyQ6Cx0Lo3szQVlD9ZN6wUfz3IDacLjoMOZkVrclIKO0DU595AVo86TD0C1TC/vCjmDGOfgoQsfS5OFfP+FmN6we9IVIAUcL8CAwEAAaNTMFEwHQYDVR0OBBYEFHTGQuoyDwtbHVLU0SseGvarrJKOMB8GA1UdIwQYMBaAFHTGQuoyDwtbHVLU0SseGvarrJKOMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAEGcA6GzCv67GYWoFK9zAjN01M79BDSuac2QV+9PYjQ7tLXQPGdoXJjJzrkJLgzTwqH2iIUqGoAZp30dW89yrJuA8s0gk3SbPOowYmst6pN6SeENxXL/1kn/IBm3+oHf5IWf7vaW4j8tYt7Q3x2K3V9GWRrozGEPIXk8yMeJq72wpfWynDxxYOepGG2+pSkm8soi9Fpt29pb+DtKB2U9GpMBS8vHU+1H4trIvEOMsd4v+X1+Vxlnt8tgy8/PrlKk1wLB9r1XA+W/vXPBe0tRcuntsXiniSKGC5oiR9AFS134HFEWuhxXWihNFzsLmNimvvxQBlXMRPZC1waCSoTKTAI=
+ - certificate: MIIDATCCAemgAwIBAgIUIa8TtXJ4Nq8VYrlgbSKcVt0FdckwDQYJKoZIhvcNAQELBQAwEDEOMAwGA1UEAwwFdGVzdDMwHhcNMTkxMDE0MTk0ODQ1WhcNMjAxMDEzMTk0ODQ1WjAQMQ4wDAYDVQQDDAV0ZXN0MzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMyttsxCiNH8qx83FTkQaUKxQXer6aMa5DpyfnGMh1K3icfEHyiKLkrjiuFbnfYC1s/iYkz9UyBQrneglYROGgr8TSFC5LXiVppI3/LONKuBh0GfmBM8dhYkOg6WmEB15EL7Hj3V6Xi/Sx3WFnvY/wAzds06linDp/I46jRXqMrWFuhXbf4A09OXpQs6KOMWkkitw3lKuKLgiNzXEiAHaS2YqW7UwSy9RLCrIDMwEmVzZ/gh3vGwM2jyfhOZ75U/xOt9U6jMQsp7hFQAoSeVBTuGpjI40g3IbNBRNi2SnERFzQFkJr0tzAX250XGDaRwRuLhilYoQoJl59B2cTzYsLECAwEAAaNTMFEwHQYDVR0OBBYEFD8iZgdSshdfyAMNfQNzS74Dl9UVMB8GA1UdIwQYMBaAFD8iZgdSshdfyAMNfQNzS74Dl9UVMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFrip5Hl7dHz3oqXLcoza9rQCiMsXV7Q2gVHJ6W2YZZlQpVOBmNPf0n42OVZrnIkDnuGD+pGuw65Aq/TnfMI2KrW8o//aOXLitR60moMEbj61IlBx3aUGvdhyevrz4tM8SHX05p4K86ZJ9jZuS/sNyDwBKBaBAqjW1Rjuqb2o+C9zvDgPWFX++8OgXljDPHR6XYAKpRBmbBZHxYXazjhj1gGhb9/txqDn4EniPXE4rZ/X5MwXzAPs7ROgvr7fkIQypO+O++FGn8rWQL+5zZY0GavOK6FMBJj8M6RDHwEEsXQqSHicsrL8iMx4jun82wgu+gO5lBPTMd0hjsOYR3eT0A=
+ action: member
+ register: result
+ failed_when: result.changed
+
+ - name: User test certmapdata members absent
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ users:
+ - name: test
+ certmapdata:
+ - certificate: MIIDATCCAemgAwIBAgIUFDZuUg9kBvN+ubTBaS6d62KafvQwDQYJKoZIhvcNAQELBQAwEDEOMAwGA1UEAwwFdGVzdDEwHhcNMTkxMDE0MTk0ODM4WhcNMjAxMDEzMTk0ODM4WjAQMQ4wDAYDVQQDDAV0ZXN0MTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALrwv6KuOIZMxjp9aueRgJWKns7P7Oo8lo4ojBVhyB3K11+1OifLqfo2SL9HPx9XynvouMj+XnqbY+NRLOX9wPYAvA7rXUgN1zQYK5stCCTjW0V4QloHnMUPM0shIuErcTP1UMatzTaFxd+UkvZCMNbE9jXHeCd3uDYoqA8Y4yRuqQ4HcnbB7DyMNZHaSCHxQCvZzllJA9m1b+c2sO3l7008PibG5RSpPnrjMUeH4yzjaB8R7A/WApAA1g5bn+IXD2dDsbdHAVFdzqwkxxLlacD8pbM7jWtCI+qJwE6dXpPb5WRkUz3tZLkEW7EQJAi3TMy//hF/SobEul3WVjiO/HUCAwEAAaNTMFEwHQYDVR0OBBYEFCkUPLMp0M5rgxHNAYuunGM0if/vMB8GA1UdIwQYMBaAFCkUPLMp0M5rgxHNAYuunGM0if/vMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAI7gj1VllrF0eRqPP9xtSqWla+qGMpHUWur1yIoy3R8I7LV3muQpbgxsfOyH2PHj69v+8yvI5einvOXJVgJxcn/ERxm/prIdo+QlK4O/SDdswJWfjCaDlk03PzjDzHXeEWRwDFV9zpRx/hjLUn8knwBOSbUE8ImUGt37ZBMBsz++y+oCZJVxzwZgcXZ3L4yuhJ0l48Cz+2EEoYN08gJqNk1EzmpBcAYJJ0Ai1psFqu12b32fNIhWSSf5THldqNefdpBlMo5ZtC9wE//NTml+nebA1FJDSppTMfHP/rTb/wfNx5vc5KLYYR9wZUUUDeJhdNPlBZZuuVbn29X6a4teoBk=
+ - certificate: MIIDATCCAemgAwIBAgIUK2Sa8/xr/4H9BOB0K0SswbVmmMcwDQYJKoZIhvcNAQELBQAwEDEOMAwGA1UEAwwFdGVzdDIwHhcNMTkxMDE0MTk0ODM1WhcNMjAxMDEzMTk0ODM1WjAQMQ4wDAYDVQQDDAV0ZXN0MjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANQdGqRUTNCptUsZxVe03YTYyhg6+ovidYP9bPPsCS1FzOTCKV9maFv4GHGEI455lkGowW3okT2DPC5pgtH43vZkDtjXNy1JDyg1y4OmxfiAg4Uc0W9DnakvEokVyt44WRzXjlv2CBO+A7Zon8z3aJwKKCV4EfpuvRw/npqhrnGF/w/n7NXyeRXI6lom9hqIQzJoRjXrMIEbtzM8m2GWlFq8af1KJ+Cmm25c87aeyu7I0+BRCq21pwcyQ6Cx0Lo3szQVlD9ZN6wUfz3IDacLjoMOZkVrclIKO0DU595AVo86TD0C1TC/vCjmDGOfgoQsfS5OFfP+FmN6we9IVIAUcL8CAwEAAaNTMFEwHQYDVR0OBBYEFHTGQuoyDwtbHVLU0SseGvarrJKOMB8GA1UdIwQYMBaAFHTGQuoyDwtbHVLU0SseGvarrJKOMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAEGcA6GzCv67GYWoFK9zAjN01M79BDSuac2QV+9PYjQ7tLXQPGdoXJjJzrkJLgzTwqH2iIUqGoAZp30dW89yrJuA8s0gk3SbPOowYmst6pN6SeENxXL/1kn/IBm3+oHf5IWf7vaW4j8tYt7Q3x2K3V9GWRrozGEPIXk8yMeJq72wpfWynDxxYOepGG2+pSkm8soi9Fpt29pb+DtKB2U9GpMBS8vHU+1H4trIvEOMsd4v+X1+Vxlnt8tgy8/PrlKk1wLB9r1XA+W/vXPBe0tRcuntsXiniSKGC5oiR9AFS134HFEWuhxXWihNFzsLmNimvvxQBlXMRPZC1waCSoTKTAI=
+ - certificate: MIIDATCCAemgAwIBAgIUIa8TtXJ4Nq8VYrlgbSKcVt0FdckwDQYJKoZIhvcNAQELBQAwEDEOMAwGA1UEAwwFdGVzdDMwHhcNMTkxMDE0MTk0ODQ1WhcNMjAxMDEzMTk0ODQ1WjAQMQ4wDAYDVQQDDAV0ZXN0MzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMyttsxCiNH8qx83FTkQaUKxQXer6aMa5DpyfnGMh1K3icfEHyiKLkrjiuFbnfYC1s/iYkz9UyBQrneglYROGgr8TSFC5LXiVppI3/LONKuBh0GfmBM8dhYkOg6WmEB15EL7Hj3V6Xi/Sx3WFnvY/wAzds06linDp/I46jRXqMrWFuhXbf4A09OXpQs6KOMWkkitw3lKuKLgiNzXEiAHaS2YqW7UwSy9RLCrIDMwEmVzZ/gh3vGwM2jyfhOZ75U/xOt9U6jMQsp7hFQAoSeVBTuGpjI40g3IbNBRNi2SnERFzQFkJr0tzAX250XGDaRwRuLhilYoQoJl59B2cTzYsLECAwEAAaNTMFEwHQYDVR0OBBYEFD8iZgdSshdfyAMNfQNzS74Dl9UVMB8GA1UdIwQYMBaAFD8iZgdSshdfyAMNfQNzS74Dl9UVMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFrip5Hl7dHz3oqXLcoza9rQCiMsXV7Q2gVHJ6W2YZZlQpVOBmNPf0n42OVZrnIkDnuGD+pGuw65Aq/TnfMI2KrW8o//aOXLitR60moMEbj61IlBx3aUGvdhyevrz4tM8SHX05p4K86ZJ9jZuS/sNyDwBKBaBAqjW1Rjuqb2o+C9zvDgPWFX++8OgXljDPHR6XYAKpRBmbBZHxYXazjhj1gGhb9/txqDn4EniPXE4rZ/X5MwXzAPs7ROgvr7fkIQypO+O++FGn8rWQL+5zZY0GavOK6FMBJj8M6RDHwEEsXQqSHicsrL8iMx4jun82wgu+gO5lBPTMd0hjsOYR3eT0A=
+ action: member
+ state: absent
+ register: result
+ failed_when: not result.changed
+
+ - name: User test certmapdata members absent again
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ users:
+ - name: test
+ certmapdata:
+ - certificate: MIIDATCCAemgAwIBAgIUFDZuUg9kBvN+ubTBaS6d62KafvQwDQYJKoZIhvcNAQELBQAwEDEOMAwGA1UEAwwFdGVzdDEwHhcNMTkxMDE0MTk0ODM4WhcNMjAxMDEzMTk0ODM4WjAQMQ4wDAYDVQQDDAV0ZXN0MTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALrwv6KuOIZMxjp9aueRgJWKns7P7Oo8lo4ojBVhyB3K11+1OifLqfo2SL9HPx9XynvouMj+XnqbY+NRLOX9wPYAvA7rXUgN1zQYK5stCCTjW0V4QloHnMUPM0shIuErcTP1UMatzTaFxd+UkvZCMNbE9jXHeCd3uDYoqA8Y4yRuqQ4HcnbB7DyMNZHaSCHxQCvZzllJA9m1b+c2sO3l7008PibG5RSpPnrjMUeH4yzjaB8R7A/WApAA1g5bn+IXD2dDsbdHAVFdzqwkxxLlacD8pbM7jWtCI+qJwE6dXpPb5WRkUz3tZLkEW7EQJAi3TMy//hF/SobEul3WVjiO/HUCAwEAAaNTMFEwHQYDVR0OBBYEFCkUPLMp0M5rgxHNAYuunGM0if/vMB8GA1UdIwQYMBaAFCkUPLMp0M5rgxHNAYuunGM0if/vMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAI7gj1VllrF0eRqPP9xtSqWla+qGMpHUWur1yIoy3R8I7LV3muQpbgxsfOyH2PHj69v+8yvI5einvOXJVgJxcn/ERxm/prIdo+QlK4O/SDdswJWfjCaDlk03PzjDzHXeEWRwDFV9zpRx/hjLUn8knwBOSbUE8ImUGt37ZBMBsz++y+oCZJVxzwZgcXZ3L4yuhJ0l48Cz+2EEoYN08gJqNk1EzmpBcAYJJ0Ai1psFqu12b32fNIhWSSf5THldqNefdpBlMo5ZtC9wE//NTml+nebA1FJDSppTMfHP/rTb/wfNx5vc5KLYYR9wZUUUDeJhdNPlBZZuuVbn29X6a4teoBk=
+ - certificate: MIIDATCCAemgAwIBAgIUK2Sa8/xr/4H9BOB0K0SswbVmmMcwDQYJKoZIhvcNAQELBQAwEDEOMAwGA1UEAwwFdGVzdDIwHhcNMTkxMDE0MTk0ODM1WhcNMjAxMDEzMTk0ODM1WjAQMQ4wDAYDVQQDDAV0ZXN0MjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANQdGqRUTNCptUsZxVe03YTYyhg6+ovidYP9bPPsCS1FzOTCKV9maFv4GHGEI455lkGowW3okT2DPC5pgtH43vZkDtjXNy1JDyg1y4OmxfiAg4Uc0W9DnakvEokVyt44WRzXjlv2CBO+A7Zon8z3aJwKKCV4EfpuvRw/npqhrnGF/w/n7NXyeRXI6lom9hqIQzJoRjXrMIEbtzM8m2GWlFq8af1KJ+Cmm25c87aeyu7I0+BRCq21pwcyQ6Cx0Lo3szQVlD9ZN6wUfz3IDacLjoMOZkVrclIKO0DU595AVo86TD0C1TC/vCjmDGOfgoQsfS5OFfP+FmN6we9IVIAUcL8CAwEAAaNTMFEwHQYDVR0OBBYEFHTGQuoyDwtbHVLU0SseGvarrJKOMB8GA1UdIwQYMBaAFHTGQuoyDwtbHVLU0SseGvarrJKOMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAEGcA6GzCv67GYWoFK9zAjN01M79BDSuac2QV+9PYjQ7tLXQPGdoXJjJzrkJLgzTwqH2iIUqGoAZp30dW89yrJuA8s0gk3SbPOowYmst6pN6SeENxXL/1kn/IBm3+oHf5IWf7vaW4j8tYt7Q3x2K3V9GWRrozGEPIXk8yMeJq72wpfWynDxxYOepGG2+pSkm8soi9Fpt29pb+DtKB2U9GpMBS8vHU+1H4trIvEOMsd4v+X1+Vxlnt8tgy8/PrlKk1wLB9r1XA+W/vXPBe0tRcuntsXiniSKGC5oiR9AFS134HFEWuhxXWihNFzsLmNimvvxQBlXMRPZC1waCSoTKTAI=
+ - certificate: MIIDATCCAemgAwIBAgIUIa8TtXJ4Nq8VYrlgbSKcVt0FdckwDQYJKoZIhvcNAQELBQAwEDEOMAwGA1UEAwwFdGVzdDMwHhcNMTkxMDE0MTk0ODQ1WhcNMjAxMDEzMTk0ODQ1WjAQMQ4wDAYDVQQDDAV0ZXN0MzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMyttsxCiNH8qx83FTkQaUKxQXer6aMa5DpyfnGMh1K3icfEHyiKLkrjiuFbnfYC1s/iYkz9UyBQrneglYROGgr8TSFC5LXiVppI3/LONKuBh0GfmBM8dhYkOg6WmEB15EL7Hj3V6Xi/Sx3WFnvY/wAzds06linDp/I46jRXqMrWFuhXbf4A09OXpQs6KOMWkkitw3lKuKLgiNzXEiAHaS2YqW7UwSy9RLCrIDMwEmVzZ/gh3vGwM2jyfhOZ75U/xOt9U6jMQsp7hFQAoSeVBTuGpjI40g3IbNBRNi2SnERFzQFkJr0tzAX250XGDaRwRuLhilYoQoJl59B2cTzYsLECAwEAAaNTMFEwHQYDVR0OBBYEFD8iZgdSshdfyAMNfQNzS74Dl9UVMB8GA1UdIwQYMBaAFD8iZgdSshdfyAMNfQNzS74Dl9UVMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFrip5Hl7dHz3oqXLcoza9rQCiMsXV7Q2gVHJ6W2YZZlQpVOBmNPf0n42OVZrnIkDnuGD+pGuw65Aq/TnfMI2KrW8o//aOXLitR60moMEbj61IlBx3aUGvdhyevrz4tM8SHX05p4K86ZJ9jZuS/sNyDwBKBaBAqjW1Rjuqb2o+C9zvDgPWFX++8OgXljDPHR6XYAKpRBmbBZHxYXazjhj1gGhb9/txqDn4EniPXE4rZ/X5MwXzAPs7ROgvr7fkIQypO+O++FGn8rWQL+5zZY0GavOK6FMBJj8M6RDHwEEsXQqSHicsrL8iMx4jun82wgu+gO5lBPTMd0hjsOYR3eT0A=
+ action: member
+ state: absent
+ register: result
+ failed_when: result.changed
+
+ - name: User test certmapdata members present
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ users:
+ - name: test
+ certmapdata:
+ - issuer: CN=issuer1
+ subject: CN=subject1
+ - issuer: CN=issuer2
+ subject: CN=subject2
+ - issuer: CN=issuer3
+ subject: CN=subject3
+ action: member
+ register: result
+ failed_when: not result.changed
+
+ - name: User test certmapdata members present again
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ users:
+ - name: test
+ certmapdata:
+ - issuer: CN=issuer1
+ subject: CN=subject1
+ - issuer: CN=issuer2
+ subject: CN=subject2
+ - issuer: CN=issuer3
+ subject: CN=subject3
+ action: member
+ register: result
+ failed_when: result.changed
+
+ - name: User test certmapdata members absent
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ users:
+ - name: test
+ certmapdata:
+ - issuer: CN=issuer1
+ subject: CN=subject1
+ - issuer: CN=issuer2
+ subject: CN=subject2
+ - issuer: CN=issuer3
+ subject: CN=subject3
+ action: member
+ state: absent
+ register: result
+ failed_when: not result.changed
+
+ - name: User test certmapdata members absent again
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ users:
+ - name: test
+ certmapdata:
+ - issuer: CN=issuer1
+ subject: CN=subject1
+ - issuer: CN=issuer2
+ subject: CN=subject2
+ - issuer: CN=issuer3
+ subject: CN=subject3
+ action: member
+ state: absent
+ register: result
+ failed_when: result.changed
+
+ - name: User test absent
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ users:
+ - name: test
+ state: absent
+ register: result
+ failed_when: not result.changed
diff --git a/tests/user/test_user.yml b/tests/user/test_user.yml
new file mode 100644
index 00000000..c172049f
--- /dev/null
+++ b/tests/user/test_user.yml
@@ -0,0 +1,258 @@
+---
+- name: Tests
+ hosts: ipaserver
+ become: true
+ gather_facts: false
+
+ tasks:
+ - name: Remove test users
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: manager1,manager2,manager3,pinky,pinky2
+ state: absent
+
+ - name: User manager1 present
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: manager1
+ first: Manager
+ last: One
+ register: result
+ failed_when: not result.changed
+
+ - name: User manager2 present
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: manager2
+ first: Manager
+ last: One
+ register: result
+ failed_when: not result.changed
+
+ - name: User manager3 present
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: manager3
+ first: Manager
+ last: One
+ register: result
+ failed_when: not result.changed
+
+ - name: User pinky present
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: pinky
+ uid: 10001
+ gid: 100
+ phone: "+555123457"
+ email: pinky@acme.com
+ principalexpiration: "20220119235959"
+ #passwordexpiration: "2022-01-19 23:59:59"
+ first: pinky
+ last: Acme
+ initials: pa
+ #password: foo2
+ principal: pa
+ random: yes
+ city: PinkyCity
+ userstate: PinkyState
+ postalcode: PinkyZip
+ mobile: "+555123458,+555123459"
+ pager: "+555123450,+555123451"
+ fax: "+555123452,+555123453"
+ orgunit: PinkyOrgUnit
+ manager: manager1,manager2
+ update_password: on_create
+ carlicense: PinkyCarLicense1,PinkyCarLicense2
+ # sshpubkey
+ userauthtype: password,radius,otp
+ userclass: PinkyUserClass
+ #radius: "http://some.link/"
+ #radiususer: PinkyRadiusUser
+ departmentnumber: "1234"
+ employeenumber: "0815"
+ employeetype: "PinkyExmployeeType"
+ preferredlanguage: "en"
+ # certificate
+ noprivate: yes
+ nomembers: false
+ #issuer: PinkyIssuer
+ #subject: PinkySubject
+ register: result
+ failed_when: not result.changed
+
+ - name: User pinky present with changed settings
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: pinky
+ first: pinky
+ last: Acme
+ #manager: manager1,manager2,manager3
+ #principal: pa,pa1,pa3
+ sshpubkey:
+ - ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCqmVDpEX5gnSjKuv97AyzOhaUMMKz8ahOA3GY77tVC4o68KNgMCmDSEG1/kOIaElngNLaCha3p/2iAcU9Bi1tLKUlm2bbO5NHNwHfRxY/3cJtq+/7D1vxJzqThYwI4F9vr1WxyY2+mMTv3pXbfAJoR8Mu06XaEY5PDetlDKjHLuNWF+/O7ZU8PsULTa1dJZFrtXeFpmUoLoGxQBvlrlcPI1zDciCSU24t27Zan5Py2l5QchyI7yhCyMM77KDtj5+AFVpmkb9+zq50rYJAyFVeyUvwjzErvQrKJzYpA0NyBp7vskWbt36M16/M/LxEK7HA6mkcakO3ESWx5MT1LAjvdlnxbWG3787MxweHXuB8CZU+9bZPFBaJ+VQtOfJ7I8eH0S16moPC4ak8FlcFvOH8ERDPWLFDqfy09yaZ7bVIF0//5ZI7Nf3YDe3S7GrBX5ieYuECyP6UNkTx9BRsAQeVvXEc6otzB7iCSnYBMGUGzCqeigoAWaVQUONsSR3Uatks= pinky@ipaserver.el81.local
+ - ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDc8MIjaSrxLYHvu+hduoF4m6NUFSlXZWzYbd3BK4L47/U4eiXoOS6dcfuZJDjmLfOipc7XVp7NADwAgA1yBOAjbeVpXr2tC8w8saZibl75WBOEjDfNroiOh/f/ojrwwHg05QTVSZHs27sU1HBPyCQM/FHVM6EnRfmyiBkEBA/3ca0PJ9UJhWb2XisCaz6y6QcTh4gQnvHzgmEmK31GwiKnmBSEQuj8P5NGCO8RlN3cq3zpRpMDEoBRCjQYicllf/5P43r5OGvS1LhTiAMfyqE37URezNQa7aozBpH1GhIwAmjAtm84jXQjxUgZPYC0aSLuADYErScOP4792r6koH9t/DM5/M+jG2c4PNWynDczUw6Eaxl5E3hU0Ee9UN0Oee7iBnVenS/QMeZNyo5lMA/HXT5lrYiJGTYM0shRjGXXYBbJZhWerguSWDAdUd1gvuGP1nb7/+/Cvb46+HX7zYouS5Ojo0yPzMZ07X142jnKAfx9LnKdMUCwBJzbtoJ91Zc= pinky@ipaserver.el81.local
+ register: result
+ failed_when: not result.changed
+
+ - name: User pinky add manager manager1
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: pinky
+ manager: manager1
+ action: member
+ register: result
+ failed_when: not result.changed
+
+ - name: User pinky add manager manager1 again
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: pinky
+ manager: manager1
+ action: member
+ register: result
+ failed_when: result.changed
+
+ - name: User pinky add manager manager2, manager3
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: pinky
+ manager: manager2,manager3
+ action: member
+ register: result
+ failed_when: not result.changed
+
+ - name: User pinky add manager manager2, manager3 again
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: pinky
+ manager: manager2,manager3
+ action: member
+ register: result
+ failed_when: result.changed
+
+ - name: User pinky remove manager manager1
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: pinky
+ manager: manager1
+ action: member
+ state: absent
+ register: result
+ failed_when: not result.changed
+
+ - name: User pinky remove manager manager1 again
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: pinky
+ manager: manager1
+ action: member
+ state: absent
+ register: result
+ failed_when: result.changed
+
+ - name: User pinky add principal pa
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: pinky
+ principal: pa
+ action: member
+ register: result
+ failed_when: not result.changed
+
+ - name: User pinky add principal pa again
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: pinky
+ principal: pa
+ action: member
+ register: result
+ failed_when: result.changed
+
+ - name: User pinky add principal pa1
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: pinky
+ principal: pa1
+ action: member
+ register: result
+ failed_when: not result.changed
+
+ - name: User pinky remove principal pa1
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: pinky
+ principal: pa1
+ action: member
+ state: absent
+ register: result
+ failed_when: not result.changed
+
+ - name: User pinky remove principal pa1 again
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: pinky
+ principal: pa1
+ action: member
+ state: absent
+ register: result
+ failed_when: result.changed
+
+ - name: User pinky remove principal pa
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: pinky
+ principal: pa
+ action: member
+ state: absent
+ register: result
+ failed_when: not result.changed
+
+ - name: User pinky remove principal non-existing pa2
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: pinky
+ principal: pa2
+ action: member
+ state: absent
+ register: result
+ failed_when: result.changed
+
+ - name: User pinky absent and preserved
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: pinky
+ preserve: yes
+ state: absent
+ register: result
+ failed_when: not result.changed
+
+ - name: User pinky undeleted (preserved before)
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: pinky
+ state: undeleted
+ register: result
+ failed_when: not result.changed
+
+ - name: Users pinky disabled
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: pinky
+ state: disabled
+ register: result
+ failed_when: not result.changed
+
+ - name: User pinky enabled
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: pinky
+ state: enabled
+ register: result
+ failed_when: not result.changed
+
+ - name: Remove test users
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: manager1,manager2,manager3,pinky,pinky2
+ state: absent
diff --git a/tests/user/test_users.yml b/tests/user/test_users.yml
new file mode 100644
index 00000000..729bb68c
--- /dev/null
+++ b/tests/user/test_users.yml
@@ -0,0 +1,376 @@
+---
+- name: Tests
+ hosts: ipaserver
+ become: true
+ gather_facts: false
+
+ tasks:
+ - name: Remove test users
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: user1,user2,user3,user4,user5,user6,user7,user8,user9,user10
+ state: absent
+
+ - name: Users user1..10 present
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ users:
+ - name: user1
+ givenname: user1
+ last: Last
+ - name: user2
+ first: user2
+ last: Last
+ - name: user3
+ first: user3
+ last: Last
+ - name: user4
+ first: user4
+ last: Last
+ - name: user5
+ first: user5
+ last: Last
+ - name: user6
+ first: user6
+ last: Last
+ - name: user7
+ first: user7
+ last: Last
+ - name: user8
+ first: user8
+ last: Last
+ - name: user9
+ first: user9
+ last: Last
+ - name: user10
+ first: user10
+ last: Last
+ register: result
+ failed_when: not result.changed
+
+ - name: Users user1..10 present
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ users:
+ - name: user1
+ givenname: user1
+ last: Last
+ - name: user2
+ first: user2
+ last: Last
+ - name: user3
+ first: user3
+ last: Last
+ - name: user4
+ first: user4
+ last: Last
+ - name: user5
+ first: user5
+ last: Last
+ - name: user6
+ first: user6
+ last: Last
+ - name: user7
+ first: user7
+ last: Last
+ - name: user8
+ first: user8
+ last: Last
+ - name: user9
+ first: user9
+ last: Last
+ - name: user10
+ first: user10
+ last: Last
+ register: result
+ failed_when: result.changed
+
+ - name: Remove test users
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: user1,user2,user3,user4,user5,user6,user7,user8,user9,user10
+ state: absent
+
+ - name: Remove test users
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: manager1,manager2,manager3,pinky,pinky2
+ state: absent
+
+ - name: User manager1 present
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ users:
+ - name: manager1
+ first: Manager1
+ last: One1
+ - name: manager2
+ first: Manager2
+ last: One2
+ - name: manager3
+ first: Manager3
+ last: One3
+ register: result
+ failed_when: not result.changed
+
+ - name: User pinky present
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: pinky
+ uid: 10001
+ gid: 100
+ phone: "+555123457"
+ email: pinky@acme.com
+ principalexpiration: "20220119235959"
+ #passwordexpiration: "2022-01-19 23:59:59"
+ first: pinky
+ last: Acme
+ initials: pa
+ #password: foo2
+ principal: pa
+ random: yes
+ city: PinkyCity
+ userstate: PinkyState
+ postalcode: PinkyZip
+ mobile: "+555123458,+555123459"
+ pager: "+555123450,+555123451"
+ fax: "+555123452,+555123453"
+ orgunit: PinkyOrgUnit
+ manager: manager1,manager2
+ update_password: on_create
+ carlicense: PinkyCarLicense1,PinkyCarLicense2
+ # sshpubkey
+ userauthtype: password,radius,otp
+ userclass: PinkyUserClass
+ #radius: "http://some.link/"
+ #radiususer: PinkyRadiusUser
+ departmentnumber: "1234"
+ employeenumber: "0815"
+ employeetype: "PinkyExmployeeType"
+ preferredlanguage: "en"
+ # certificate
+ noprivate: yes
+ nomembers: false
+ #issuer: PinkyIssuer
+ #subject: PinkySubject
+ register: result
+ failed_when: not result.changed
+
+ - name: Same user pinky present again
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: pinky
+ uid: 10001
+ gid: 100
+ phone: "+555123457"
+ email: pinky@acme.com
+ principalexpiration: "20220119235959"
+ #passwordexpiration: "2022-01-19 23:59:59"
+ first: pinky
+ last: Acme
+ initials: pa
+ #password: foo2
+ principal: pa
+ random: yes
+ city: PinkyCity
+ userstate: PinkyState
+ postalcode: PinkyZip
+ mobile: "+555123458,+555123459"
+ pager: "+555123450,+555123451"
+ fax: "+555123452,+555123453"
+ orgunit: PinkyOrgUnit
+ manager: manager1,manager2
+ update_password: on_create
+ carlicense: PinkyCarLicense1,PinkyCarLicense2
+ # sshpubkey
+ userauthtype: password,radius,otp
+ userclass: PinkyUserClass
+ #radius: "http://some.link/"
+ #radiususer: PinkyRadiusUser
+ departmentnumber: "1234"
+ employeenumber: "0815"
+ employeetype: "PinkyExmployeeType"
+ preferredlanguage: "en"
+ # certificate
+ noprivate: yes
+ nomembers: false
+ #issuer: PinkyIssuer
+ #subject: PinkySubject
+ register: result
+ failed_when: result.changed
+
+ - name: User pinky present with changed settings
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: pinky
+ first: pinky
+ last: Acme
+ #manager: manager1,manager2,manager3
+ #principal: pa,pa1,pa3
+ sshpubkey:
+ - ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCqmVDpEX5gnSjKuv97AyzOhaUMMKz8ahOA3GY77tVC4o68KNgMCmDSEG1/kOIaElngNLaCha3p/2iAcU9Bi1tLKUlm2bbO5NHNwHfRxY/3cJtq+/7D1vxJzqThYwI4F9vr1WxyY2+mMTv3pXbfAJoR8Mu06XaEY5PDetlDKjHLuNWF+/O7ZU8PsULTa1dJZFrtXeFpmUoLoGxQBvlrlcPI1zDciCSU24t27Zan5Py2l5QchyI7yhCyMM77KDtj5+AFVpmkb9+zq50rYJAyFVeyUvwjzErvQrKJzYpA0NyBp7vskWbt36M16/M/LxEK7HA6mkcakO3ESWx5MT1LAjvdlnxbWG3787MxweHXuB8CZU+9bZPFBaJ+VQtOfJ7I8eH0S16moPC4ak8FlcFvOH8ERDPWLFDqfy09yaZ7bVIF0//5ZI7Nf3YDe3S7GrBX5ieYuECyP6UNkTx9BRsAQeVvXEc6otzB7iCSnYBMGUGzCqeigoAWaVQUONsSR3Uatks= pinky@ipaserver.el81.local
+ - ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDc8MIjaSrxLYHvu+hduoF4m6NUFSlXZWzYbd3BK4L47/U4eiXoOS6dcfuZJDjmLfOipc7XVp7NADwAgA1yBOAjbeVpXr2tC8w8saZibl75WBOEjDfNroiOh/f/ojrwwHg05QTVSZHs27sU1HBPyCQM/FHVM6EnRfmyiBkEBA/3ca0PJ9UJhWb2XisCaz6y6QcTh4gQnvHzgmEmK31GwiKnmBSEQuj8P5NGCO8RlN3cq3zpRpMDEoBRCjQYicllf/5P43r5OGvS1LhTiAMfyqE37URezNQa7aozBpH1GhIwAmjAtm84jXQjxUgZPYC0aSLuADYErScOP4792r6koH9t/DM5/M+jG2c4PNWynDczUw6Eaxl5E3hU0Ee9UN0Oee7iBnVenS/QMeZNyo5lMA/HXT5lrYiJGTYM0shRjGXXYBbJZhWerguSWDAdUd1gvuGP1nb7/+/Cvb46+HX7zYouS5Ojo0yPzMZ07X142jnKAfx9LnKdMUCwBJzbtoJ91Zc= pinky@ipaserver.el81.local
+ register: result
+ failed_when: not result.changed
+
+ - name: User pinky add manager manager1
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: pinky
+ manager: manager1
+ action: member
+ register: result
+ failed_when: not result.changed
+
+ - name: User pinky add manager manager1 again
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: pinky
+ manager: manager1
+ action: member
+ register: result
+ failed_when: result.changed
+
+ - name: User pinky add manager manager2, manager3
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: pinky
+ manager: manager2,manager3
+ action: member
+ register: result
+ failed_when: not result.changed
+
+ - name: User pinky add manager manager2, manager3 again
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: pinky
+ manager: manager2,manager3
+ action: member
+ register: result
+ failed_when: result.changed
+
+ - name: User pinky remove manager manager1
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: pinky
+ manager: manager1
+ action: member
+ state: absent
+ register: result
+ failed_when: not result.changed
+
+ - name: User pinky remove manager manager1 again
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: pinky
+ manager: manager1
+ action: member
+ state: absent
+ register: result
+ failed_when: result.changed
+
+ - name: User pinky add principal pa
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: pinky
+ principal: pa
+ action: member
+ register: result
+ failed_when: not result.changed
+
+ - name: User pinky add principal pa again
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: pinky
+ principal: pa
+ action: member
+ register: result
+ failed_when: result.changed
+
+ - name: User pinky add principal pa1
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: pinky
+ principal: pa1
+ action: member
+ register: result
+ failed_when: not result.changed
+
+ - name: User pinky remove principal pa1
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: pinky
+ principal: pa1
+ action: member
+ state: absent
+ register: result
+ failed_when: not result.changed
+
+ - name: User pinky remove principal pa1 again
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: pinky
+ principal: pa1
+ action: member
+ state: absent
+ register: result
+ failed_when: result.changed
+
+ - name: User pinky remove principal pa
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: pinky
+ principal: pa
+ action: member
+ state: absent
+ register: result
+ failed_when: not result.changed
+
+ - name: User pinky remove principal non-existing pa2
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: pinky
+ principal: pa2
+ action: member
+ state: absent
+ register: result
+ failed_when: result.changed
+
+ - name: User pinky absent and preserved
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: pinky
+ preserve: yes
+ state: absent
+ register: result
+ failed_when: not result.changed
+
+ - name: User pinky undeleted (preserved before)
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: pinky
+ state: undeleted
+ register: result
+ failed_when: not result.changed
+
+ - name: Users pinky disabled
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: pinky
+ state: disabled
+ register: result
+ failed_when: not result.changed
+
+ - name: User pinky enabled
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: pinky
+ state: enabled
+ register: result
+ failed_when: not result.changed
+
+ - name: Remove test users
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ name: manager1,manager2,manager3,pinky,pinky2
+ state: absent
diff --git a/tests/user/test_users_absent.yml b/tests/user/test_users_absent.yml
new file mode 100644
index 00000000..eaab27f7
--- /dev/null
+++ b/tests/user/test_users_absent.yml
@@ -0,0 +1,16 @@
+---
+- name: Tests
+ hosts: ipaserver
+ become: true
+ gather_facts: false
+
+ tasks:
+ - name: Include users_absent.json
+ include_vars:
+ file: users_absent.json
+
+ - name: Users absent
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ users: "{{ users }}"
+ state: absent
diff --git a/tests/user/test_users_invalid_cert.yml b/tests/user/test_users_invalid_cert.yml
new file mode 100644
index 00000000..62a8d9e5
--- /dev/null
+++ b/tests/user/test_users_invalid_cert.yml
@@ -0,0 +1,64 @@
+#
+# Generate self-signed certificates using openssl:
+#
+# openssl req -x509 -newkey rsa:2048 -days 365 -nodes -keyout private1.key -out cert1.pem -subj '/CN=test'
+# openssl req -x509 -newkey rsa:2048 -days 365 -nodes -keyout private2.key -out cert2.pem -subj '/CN=test'
+# openssl req -x509 -newkey rsa:2048 -days 365 -nodes -keyout private3.key -out cert3.pem -subj '/CN=test'
+#
+# Convert the certificate do DER for easier handling through CLI
+#
+# openssl x509 -outform der -in cert1.pem -out cert1.der
+# openssl x509 -outform der -in cert2.pem -out cert2.der
+# openssl x509 -outform der -in cert3.pem -out cert3.der
+#
+# Use base64:
+#
+# base64 cert1.der -w5000
+# base64 cert2.der -w5000
+# base64 cert3.der -w5000
+#
+---
+- name: Test user certificates
+ hosts: ipaserver
+ become: true
+ gather_facts: false
+
+ tasks:
+ - name: User test absent
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ users:
+ - name: test
+ state: absent
+
+ - name: User test present
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ users:
+ - name: test
+ first: test
+ last: test
+
+ - name: User test cert members present
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ users:
+ - name: test
+ certificate:
+ - MIIC/zCCAeegAwIBAgIUAWE1vaA+mZd3nwZqwWH64EbHvR0wDQYJKoZIhvcNAQELBQAwDzENMAsGA1UEAwwEdGVzdDAeFw0xOTEwMTQxNjI4NDVaFw0yMDEwMTMxNjI4NDVaMA8xDTALBgNVBAMMBHRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCWzJibKtN8Zf7LgandINhFonx99AKi44iaZkrlMKEObE6Faf8NTUbUgK3VfJNYmCbA1baLVJ0YZJijJ7S/4o7h7eeqcJVXJkEhWNTimWXNW/YCzTHe3SSapnSYOKmdHHRClplysL8OyyEG7pbX/aB9iAfFb/+vUFCX5sMwFFrYxOimKJ9Pc/NRFtdv1wNw1rqWKF1ZzagWRlG4QgzRGwQ4quc7yO98TKikj2OPiIt7Zd46hbqQxmgGBtCkVOZIhxu77OmNrFsXmM4rZZpmqh0UdqcpwkRojVnGXmNqeMCd6dNTnLhr9wukUYw0KgE57zCDVr9Ix+p/dA5R1mG4RJ2XAgMBAAGjUzBRMB0GA1UdDgQWBBSbuiH2lNVrID3yt1SsFwtOFKOnpTAfBgNVHSMEGDAWgBSbuiH2lNVrID3yt1SsFwtOFKOnpTAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBCVWd293wWyohFqMFMHRBBg97T2Uc1yeT0dMH4BpuOaCqQp4q5ep+uLcXEI6+3mEwm8pa/ULQCD8yLLdotIWlG3+h/4boFpdiPFcBDgT8kGe+0KOzB8Nt7E13QYOu12MNi10qwGrjKhdhu1xBe4fpY5VCetVU1OLyuTsUyucQsFrtZI0SR83h+blbyoMZ7IhMngCfGUe1bnYeWnLbpFbigKfPuVDWsMH2kgj05EAd5EgHkWbX8QA8hmcmDKfNT3YZM8kiGQwmFrnQdq8bN0uHR8Nz+24cbmdbHcD65wlDW6GmYxi8mW+V6bAqn9pir/J14r4YFnqMGgjmdt81tscJV
+ action: member
+ register: result
+ failed_when: not result.changed
+
+ - name: User test cert members absent
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ users:
+ - name: test
+ certificate:
+ - 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
+ state: absent
+ action: member
+ #register: result
+ #failed_when: not result.changed
diff --git a/tests/user/test_users_present.yml b/tests/user/test_users_present.yml
new file mode 100644
index 00000000..370b1372
--- /dev/null
+++ b/tests/user/test_users_present.yml
@@ -0,0 +1,15 @@
+---
+- name: Tests
+ hosts: ipaserver
+ become: true
+ gather_facts: false
+
+ tasks:
+ - name: Include users_present.json
+ include_vars:
+ file: users_present.json
+
+ - name: Users present
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ users: "{{ users }}"
diff --git a/tests/user/test_users_present_slice.yml b/tests/user/test_users_present_slice.yml
new file mode 100644
index 00000000..8c6524d8
--- /dev/null
+++ b/tests/user/test_users_present_slice.yml
@@ -0,0 +1,19 @@
+---
+- name: Tests
+ hosts: ipaserver
+ become: true
+ gather_facts: false
+
+ vars:
+ slice_size: 500
+ tasks:
+ - name: Include users_present.json
+ include_vars:
+ file: users_present.json
+ - debug:
+ msg: "{{ users | length }}"
+ - name: Users present
+ ipauser:
+ ipaadmin_password: SomeADMINpassword
+ users: "{{ users[item:item+slice_size] }}"
+ loop: "{{ range(0,users | length, slice_size) | list }}"
diff --git a/tests/user/users_absent.json b/tests/user/users_absent.json
new file mode 100644
index 00000000..6d29807a
--- /dev/null
+++ b/tests/user/users_absent.json
@@ -0,0 +1,3004 @@
+{
+ "users": [
+ {
+ "name": "user1",
+ },
+ {
+ "name": "user2",
+ },
+ {
+ "name": "user3",
+ },
+ {
+ "name": "user4",
+ },
+ {
+ "name": "user5",
+ },
+ {
+ "name": "user6",
+ },
+ {
+ "name": "user7",
+ },
+ {
+ "name": "user8",
+ },
+ {
+ "name": "user9",
+ },
+ {
+ "name": "user10",
+ },
+ {
+ "name": "user11",
+ },
+ {
+ "name": "user12",
+ },
+ {
+ "name": "user13",
+ },
+ {
+ "name": "user14",
+ },
+ {
+ "name": "user15",
+ },
+ {
+ "name": "user16",
+ },
+ {
+ "name": "user17",
+ },
+ {
+ "name": "user18",
+ },
+ {
+ "name": "user19",
+ },
+ {
+ "name": "user20",
+ },
+ {
+ "name": "user21",
+ },
+ {
+ "name": "user22",
+ },
+ {
+ "name": "user23",
+ },
+ {
+ "name": "user24",
+ },
+ {
+ "name": "user25",
+ },
+ {
+ "name": "user26",
+ },
+ {
+ "name": "user27",
+ },
+ {
+ "name": "user28",
+ },
+ {
+ "name": "user29",
+ },
+ {
+ "name": "user30",
+ },
+ {
+ "name": "user31",
+ },
+ {
+ "name": "user32",
+ },
+ {
+ "name": "user33",
+ },
+ {
+ "name": "user34",
+ },
+ {
+ "name": "user35",
+ },
+ {
+ "name": "user36",
+ },
+ {
+ "name": "user37",
+ },
+ {
+ "name": "user38",
+ },
+ {
+ "name": "user39",
+ },
+ {
+ "name": "user40",
+ },
+ {
+ "name": "user41",
+ },
+ {
+ "name": "user42",
+ },
+ {
+ "name": "user43",
+ },
+ {
+ "name": "user44",
+ },
+ {
+ "name": "user45",
+ },
+ {
+ "name": "user46",
+ },
+ {
+ "name": "user47",
+ },
+ {
+ "name": "user48",
+ },
+ {
+ "name": "user49",
+ },
+ {
+ "name": "user50",
+ },
+ {
+ "name": "user51",
+ },
+ {
+ "name": "user52",
+ },
+ {
+ "name": "user53",
+ },
+ {
+ "name": "user54",
+ },
+ {
+ "name": "user55",
+ },
+ {
+ "name": "user56",
+ },
+ {
+ "name": "user57",
+ },
+ {
+ "name": "user58",
+ },
+ {
+ "name": "user59",
+ },
+ {
+ "name": "user60",
+ },
+ {
+ "name": "user61",
+ },
+ {
+ "name": "user62",
+ },
+ {
+ "name": "user63",
+ },
+ {
+ "name": "user64",
+ },
+ {
+ "name": "user65",
+ },
+ {
+ "name": "user66",
+ },
+ {
+ "name": "user67",
+ },
+ {
+ "name": "user68",
+ },
+ {
+ "name": "user69",
+ },
+ {
+ "name": "user70",
+ },
+ {
+ "name": "user71",
+ },
+ {
+ "name": "user72",
+ },
+ {
+ "name": "user73",
+ },
+ {
+ "name": "user74",
+ },
+ {
+ "name": "user75",
+ },
+ {
+ "name": "user76",
+ },
+ {
+ "name": "user77",
+ },
+ {
+ "name": "user78",
+ },
+ {
+ "name": "user79",
+ },
+ {
+ "name": "user80",
+ },
+ {
+ "name": "user81",
+ },
+ {
+ "name": "user82",
+ },
+ {
+ "name": "user83",
+ },
+ {
+ "name": "user84",
+ },
+ {
+ "name": "user85",
+ },
+ {
+ "name": "user86",
+ },
+ {
+ "name": "user87",
+ },
+ {
+ "name": "user88",
+ },
+ {
+ "name": "user89",
+ },
+ {
+ "name": "user90",
+ },
+ {
+ "name": "user91",
+ },
+ {
+ "name": "user92",
+ },
+ {
+ "name": "user93",
+ },
+ {
+ "name": "user94",
+ },
+ {
+ "name": "user95",
+ },
+ {
+ "name": "user96",
+ },
+ {
+ "name": "user97",
+ },
+ {
+ "name": "user98",
+ },
+ {
+ "name": "user99",
+ },
+ {
+ "name": "user100",
+ },
+ {
+ "name": "user101",
+ },
+ {
+ "name": "user102",
+ },
+ {
+ "name": "user103",
+ },
+ {
+ "name": "user104",
+ },
+ {
+ "name": "user105",
+ },
+ {
+ "name": "user106",
+ },
+ {
+ "name": "user107",
+ },
+ {
+ "name": "user108",
+ },
+ {
+ "name": "user109",
+ },
+ {
+ "name": "user110",
+ },
+ {
+ "name": "user111",
+ },
+ {
+ "name": "user112",
+ },
+ {
+ "name": "user113",
+ },
+ {
+ "name": "user114",
+ },
+ {
+ "name": "user115",
+ },
+ {
+ "name": "user116",
+ },
+ {
+ "name": "user117",
+ },
+ {
+ "name": "user118",
+ },
+ {
+ "name": "user119",
+ },
+ {
+ "name": "user120",
+ },
+ {
+ "name": "user121",
+ },
+ {
+ "name": "user122",
+ },
+ {
+ "name": "user123",
+ },
+ {
+ "name": "user124",
+ },
+ {
+ "name": "user125",
+ },
+ {
+ "name": "user126",
+ },
+ {
+ "name": "user127",
+ },
+ {
+ "name": "user128",
+ },
+ {
+ "name": "user129",
+ },
+ {
+ "name": "user130",
+ },
+ {
+ "name": "user131",
+ },
+ {
+ "name": "user132",
+ },
+ {
+ "name": "user133",
+ },
+ {
+ "name": "user134",
+ },
+ {
+ "name": "user135",
+ },
+ {
+ "name": "user136",
+ },
+ {
+ "name": "user137",
+ },
+ {
+ "name": "user138",
+ },
+ {
+ "name": "user139",
+ },
+ {
+ "name": "user140",
+ },
+ {
+ "name": "user141",
+ },
+ {
+ "name": "user142",
+ },
+ {
+ "name": "user143",
+ },
+ {
+ "name": "user144",
+ },
+ {
+ "name": "user145",
+ },
+ {
+ "name": "user146",
+ },
+ {
+ "name": "user147",
+ },
+ {
+ "name": "user148",
+ },
+ {
+ "name": "user149",
+ },
+ {
+ "name": "user150",
+ },
+ {
+ "name": "user151",
+ },
+ {
+ "name": "user152",
+ },
+ {
+ "name": "user153",
+ },
+ {
+ "name": "user154",
+ },
+ {
+ "name": "user155",
+ },
+ {
+ "name": "user156",
+ },
+ {
+ "name": "user157",
+ },
+ {
+ "name": "user158",
+ },
+ {
+ "name": "user159",
+ },
+ {
+ "name": "user160",
+ },
+ {
+ "name": "user161",
+ },
+ {
+ "name": "user162",
+ },
+ {
+ "name": "user163",
+ },
+ {
+ "name": "user164",
+ },
+ {
+ "name": "user165",
+ },
+ {
+ "name": "user166",
+ },
+ {
+ "name": "user167",
+ },
+ {
+ "name": "user168",
+ },
+ {
+ "name": "user169",
+ },
+ {
+ "name": "user170",
+ },
+ {
+ "name": "user171",
+ },
+ {
+ "name": "user172",
+ },
+ {
+ "name": "user173",
+ },
+ {
+ "name": "user174",
+ },
+ {
+ "name": "user175",
+ },
+ {
+ "name": "user176",
+ },
+ {
+ "name": "user177",
+ },
+ {
+ "name": "user178",
+ },
+ {
+ "name": "user179",
+ },
+ {
+ "name": "user180",
+ },
+ {
+ "name": "user181",
+ },
+ {
+ "name": "user182",
+ },
+ {
+ "name": "user183",
+ },
+ {
+ "name": "user184",
+ },
+ {
+ "name": "user185",
+ },
+ {
+ "name": "user186",
+ },
+ {
+ "name": "user187",
+ },
+ {
+ "name": "user188",
+ },
+ {
+ "name": "user189",
+ },
+ {
+ "name": "user190",
+ },
+ {
+ "name": "user191",
+ },
+ {
+ "name": "user192",
+ },
+ {
+ "name": "user193",
+ },
+ {
+ "name": "user194",
+ },
+ {
+ "name": "user195",
+ },
+ {
+ "name": "user196",
+ },
+ {
+ "name": "user197",
+ },
+ {
+ "name": "user198",
+ },
+ {
+ "name": "user199",
+ },
+ {
+ "name": "user200",
+ },
+ {
+ "name": "user201",
+ },
+ {
+ "name": "user202",
+ },
+ {
+ "name": "user203",
+ },
+ {
+ "name": "user204",
+ },
+ {
+ "name": "user205",
+ },
+ {
+ "name": "user206",
+ },
+ {
+ "name": "user207",
+ },
+ {
+ "name": "user208",
+ },
+ {
+ "name": "user209",
+ },
+ {
+ "name": "user210",
+ },
+ {
+ "name": "user211",
+ },
+ {
+ "name": "user212",
+ },
+ {
+ "name": "user213",
+ },
+ {
+ "name": "user214",
+ },
+ {
+ "name": "user215",
+ },
+ {
+ "name": "user216",
+ },
+ {
+ "name": "user217",
+ },
+ {
+ "name": "user218",
+ },
+ {
+ "name": "user219",
+ },
+ {
+ "name": "user220",
+ },
+ {
+ "name": "user221",
+ },
+ {
+ "name": "user222",
+ },
+ {
+ "name": "user223",
+ },
+ {
+ "name": "user224",
+ },
+ {
+ "name": "user225",
+ },
+ {
+ "name": "user226",
+ },
+ {
+ "name": "user227",
+ },
+ {
+ "name": "user228",
+ },
+ {
+ "name": "user229",
+ },
+ {
+ "name": "user230",
+ },
+ {
+ "name": "user231",
+ },
+ {
+ "name": "user232",
+ },
+ {
+ "name": "user233",
+ },
+ {
+ "name": "user234",
+ },
+ {
+ "name": "user235",
+ },
+ {
+ "name": "user236",
+ },
+ {
+ "name": "user237",
+ },
+ {
+ "name": "user238",
+ },
+ {
+ "name": "user239",
+ },
+ {
+ "name": "user240",
+ },
+ {
+ "name": "user241",
+ },
+ {
+ "name": "user242",
+ },
+ {
+ "name": "user243",
+ },
+ {
+ "name": "user244",
+ },
+ {
+ "name": "user245",
+ },
+ {
+ "name": "user246",
+ },
+ {
+ "name": "user247",
+ },
+ {
+ "name": "user248",
+ },
+ {
+ "name": "user249",
+ },
+ {
+ "name": "user250",
+ },
+ {
+ "name": "user251",
+ },
+ {
+ "name": "user252",
+ },
+ {
+ "name": "user253",
+ },
+ {
+ "name": "user254",
+ },
+ {
+ "name": "user255",
+ },
+ {
+ "name": "user256",
+ },
+ {
+ "name": "user257",
+ },
+ {
+ "name": "user258",
+ },
+ {
+ "name": "user259",
+ },
+ {
+ "name": "user260",
+ },
+ {
+ "name": "user261",
+ },
+ {
+ "name": "user262",
+ },
+ {
+ "name": "user263",
+ },
+ {
+ "name": "user264",
+ },
+ {
+ "name": "user265",
+ },
+ {
+ "name": "user266",
+ },
+ {
+ "name": "user267",
+ },
+ {
+ "name": "user268",
+ },
+ {
+ "name": "user269",
+ },
+ {
+ "name": "user270",
+ },
+ {
+ "name": "user271",
+ },
+ {
+ "name": "user272",
+ },
+ {
+ "name": "user273",
+ },
+ {
+ "name": "user274",
+ },
+ {
+ "name": "user275",
+ },
+ {
+ "name": "user276",
+ },
+ {
+ "name": "user277",
+ },
+ {
+ "name": "user278",
+ },
+ {
+ "name": "user279",
+ },
+ {
+ "name": "user280",
+ },
+ {
+ "name": "user281",
+ },
+ {
+ "name": "user282",
+ },
+ {
+ "name": "user283",
+ },
+ {
+ "name": "user284",
+ },
+ {
+ "name": "user285",
+ },
+ {
+ "name": "user286",
+ },
+ {
+ "name": "user287",
+ },
+ {
+ "name": "user288",
+ },
+ {
+ "name": "user289",
+ },
+ {
+ "name": "user290",
+ },
+ {
+ "name": "user291",
+ },
+ {
+ "name": "user292",
+ },
+ {
+ "name": "user293",
+ },
+ {
+ "name": "user294",
+ },
+ {
+ "name": "user295",
+ },
+ {
+ "name": "user296",
+ },
+ {
+ "name": "user297",
+ },
+ {
+ "name": "user298",
+ },
+ {
+ "name": "user299",
+ },
+ {
+ "name": "user300",
+ },
+ {
+ "name": "user301",
+ },
+ {
+ "name": "user302",
+ },
+ {
+ "name": "user303",
+ },
+ {
+ "name": "user304",
+ },
+ {
+ "name": "user305",
+ },
+ {
+ "name": "user306",
+ },
+ {
+ "name": "user307",
+ },
+ {
+ "name": "user308",
+ },
+ {
+ "name": "user309",
+ },
+ {
+ "name": "user310",
+ },
+ {
+ "name": "user311",
+ },
+ {
+ "name": "user312",
+ },
+ {
+ "name": "user313",
+ },
+ {
+ "name": "user314",
+ },
+ {
+ "name": "user315",
+ },
+ {
+ "name": "user316",
+ },
+ {
+ "name": "user317",
+ },
+ {
+ "name": "user318",
+ },
+ {
+ "name": "user319",
+ },
+ {
+ "name": "user320",
+ },
+ {
+ "name": "user321",
+ },
+ {
+ "name": "user322",
+ },
+ {
+ "name": "user323",
+ },
+ {
+ "name": "user324",
+ },
+ {
+ "name": "user325",
+ },
+ {
+ "name": "user326",
+ },
+ {
+ "name": "user327",
+ },
+ {
+ "name": "user328",
+ },
+ {
+ "name": "user329",
+ },
+ {
+ "name": "user330",
+ },
+ {
+ "name": "user331",
+ },
+ {
+ "name": "user332",
+ },
+ {
+ "name": "user333",
+ },
+ {
+ "name": "user334",
+ },
+ {
+ "name": "user335",
+ },
+ {
+ "name": "user336",
+ },
+ {
+ "name": "user337",
+ },
+ {
+ "name": "user338",
+ },
+ {
+ "name": "user339",
+ },
+ {
+ "name": "user340",
+ },
+ {
+ "name": "user341",
+ },
+ {
+ "name": "user342",
+ },
+ {
+ "name": "user343",
+ },
+ {
+ "name": "user344",
+ },
+ {
+ "name": "user345",
+ },
+ {
+ "name": "user346",
+ },
+ {
+ "name": "user347",
+ },
+ {
+ "name": "user348",
+ },
+ {
+ "name": "user349",
+ },
+ {
+ "name": "user350",
+ },
+ {
+ "name": "user351",
+ },
+ {
+ "name": "user352",
+ },
+ {
+ "name": "user353",
+ },
+ {
+ "name": "user354",
+ },
+ {
+ "name": "user355",
+ },
+ {
+ "name": "user356",
+ },
+ {
+ "name": "user357",
+ },
+ {
+ "name": "user358",
+ },
+ {
+ "name": "user359",
+ },
+ {
+ "name": "user360",
+ },
+ {
+ "name": "user361",
+ },
+ {
+ "name": "user362",
+ },
+ {
+ "name": "user363",
+ },
+ {
+ "name": "user364",
+ },
+ {
+ "name": "user365",
+ },
+ {
+ "name": "user366",
+ },
+ {
+ "name": "user367",
+ },
+ {
+ "name": "user368",
+ },
+ {
+ "name": "user369",
+ },
+ {
+ "name": "user370",
+ },
+ {
+ "name": "user371",
+ },
+ {
+ "name": "user372",
+ },
+ {
+ "name": "user373",
+ },
+ {
+ "name": "user374",
+ },
+ {
+ "name": "user375",
+ },
+ {
+ "name": "user376",
+ },
+ {
+ "name": "user377",
+ },
+ {
+ "name": "user378",
+ },
+ {
+ "name": "user379",
+ },
+ {
+ "name": "user380",
+ },
+ {
+ "name": "user381",
+ },
+ {
+ "name": "user382",
+ },
+ {
+ "name": "user383",
+ },
+ {
+ "name": "user384",
+ },
+ {
+ "name": "user385",
+ },
+ {
+ "name": "user386",
+ },
+ {
+ "name": "user387",
+ },
+ {
+ "name": "user388",
+ },
+ {
+ "name": "user389",
+ },
+ {
+ "name": "user390",
+ },
+ {
+ "name": "user391",
+ },
+ {
+ "name": "user392",
+ },
+ {
+ "name": "user393",
+ },
+ {
+ "name": "user394",
+ },
+ {
+ "name": "user395",
+ },
+ {
+ "name": "user396",
+ },
+ {
+ "name": "user397",
+ },
+ {
+ "name": "user398",
+ },
+ {
+ "name": "user399",
+ },
+ {
+ "name": "user400",
+ },
+ {
+ "name": "user401",
+ },
+ {
+ "name": "user402",
+ },
+ {
+ "name": "user403",
+ },
+ {
+ "name": "user404",
+ },
+ {
+ "name": "user405",
+ },
+ {
+ "name": "user406",
+ },
+ {
+ "name": "user407",
+ },
+ {
+ "name": "user408",
+ },
+ {
+ "name": "user409",
+ },
+ {
+ "name": "user410",
+ },
+ {
+ "name": "user411",
+ },
+ {
+ "name": "user412",
+ },
+ {
+ "name": "user413",
+ },
+ {
+ "name": "user414",
+ },
+ {
+ "name": "user415",
+ },
+ {
+ "name": "user416",
+ },
+ {
+ "name": "user417",
+ },
+ {
+ "name": "user418",
+ },
+ {
+ "name": "user419",
+ },
+ {
+ "name": "user420",
+ },
+ {
+ "name": "user421",
+ },
+ {
+ "name": "user422",
+ },
+ {
+ "name": "user423",
+ },
+ {
+ "name": "user424",
+ },
+ {
+ "name": "user425",
+ },
+ {
+ "name": "user426",
+ },
+ {
+ "name": "user427",
+ },
+ {
+ "name": "user428",
+ },
+ {
+ "name": "user429",
+ },
+ {
+ "name": "user430",
+ },
+ {
+ "name": "user431",
+ },
+ {
+ "name": "user432",
+ },
+ {
+ "name": "user433",
+ },
+ {
+ "name": "user434",
+ },
+ {
+ "name": "user435",
+ },
+ {
+ "name": "user436",
+ },
+ {
+ "name": "user437",
+ },
+ {
+ "name": "user438",
+ },
+ {
+ "name": "user439",
+ },
+ {
+ "name": "user440",
+ },
+ {
+ "name": "user441",
+ },
+ {
+ "name": "user442",
+ },
+ {
+ "name": "user443",
+ },
+ {
+ "name": "user444",
+ },
+ {
+ "name": "user445",
+ },
+ {
+ "name": "user446",
+ },
+ {
+ "name": "user447",
+ },
+ {
+ "name": "user448",
+ },
+ {
+ "name": "user449",
+ },
+ {
+ "name": "user450",
+ },
+ {
+ "name": "user451",
+ },
+ {
+ "name": "user452",
+ },
+ {
+ "name": "user453",
+ },
+ {
+ "name": "user454",
+ },
+ {
+ "name": "user455",
+ },
+ {
+ "name": "user456",
+ },
+ {
+ "name": "user457",
+ },
+ {
+ "name": "user458",
+ },
+ {
+ "name": "user459",
+ },
+ {
+ "name": "user460",
+ },
+ {
+ "name": "user461",
+ },
+ {
+ "name": "user462",
+ },
+ {
+ "name": "user463",
+ },
+ {
+ "name": "user464",
+ },
+ {
+ "name": "user465",
+ },
+ {
+ "name": "user466",
+ },
+ {
+ "name": "user467",
+ },
+ {
+ "name": "user468",
+ },
+ {
+ "name": "user469",
+ },
+ {
+ "name": "user470",
+ },
+ {
+ "name": "user471",
+ },
+ {
+ "name": "user472",
+ },
+ {
+ "name": "user473",
+ },
+ {
+ "name": "user474",
+ },
+ {
+ "name": "user475",
+ },
+ {
+ "name": "user476",
+ },
+ {
+ "name": "user477",
+ },
+ {
+ "name": "user478",
+ },
+ {
+ "name": "user479",
+ },
+ {
+ "name": "user480",
+ },
+ {
+ "name": "user481",
+ },
+ {
+ "name": "user482",
+ },
+ {
+ "name": "user483",
+ },
+ {
+ "name": "user484",
+ },
+ {
+ "name": "user485",
+ },
+ {
+ "name": "user486",
+ },
+ {
+ "name": "user487",
+ },
+ {
+ "name": "user488",
+ },
+ {
+ "name": "user489",
+ },
+ {
+ "name": "user490",
+ },
+ {
+ "name": "user491",
+ },
+ {
+ "name": "user492",
+ },
+ {
+ "name": "user493",
+ },
+ {
+ "name": "user494",
+ },
+ {
+ "name": "user495",
+ },
+ {
+ "name": "user496",
+ },
+ {
+ "name": "user497",
+ },
+ {
+ "name": "user498",
+ },
+ {
+ "name": "user499",
+ },
+ {
+ "name": "user500",
+ },
+ {
+ "name": "user501",
+ },
+ {
+ "name": "user502",
+ },
+ {
+ "name": "user503",
+ },
+ {
+ "name": "user504",
+ },
+ {
+ "name": "user505",
+ },
+ {
+ "name": "user506",
+ },
+ {
+ "name": "user507",
+ },
+ {
+ "name": "user508",
+ },
+ {
+ "name": "user509",
+ },
+ {
+ "name": "user510",
+ },
+ {
+ "name": "user511",
+ },
+ {
+ "name": "user512",
+ },
+ {
+ "name": "user513",
+ },
+ {
+ "name": "user514",
+ },
+ {
+ "name": "user515",
+ },
+ {
+ "name": "user516",
+ },
+ {
+ "name": "user517",
+ },
+ {
+ "name": "user518",
+ },
+ {
+ "name": "user519",
+ },
+ {
+ "name": "user520",
+ },
+ {
+ "name": "user521",
+ },
+ {
+ "name": "user522",
+ },
+ {
+ "name": "user523",
+ },
+ {
+ "name": "user524",
+ },
+ {
+ "name": "user525",
+ },
+ {
+ "name": "user526",
+ },
+ {
+ "name": "user527",
+ },
+ {
+ "name": "user528",
+ },
+ {
+ "name": "user529",
+ },
+ {
+ "name": "user530",
+ },
+ {
+ "name": "user531",
+ },
+ {
+ "name": "user532",
+ },
+ {
+ "name": "user533",
+ },
+ {
+ "name": "user534",
+ },
+ {
+ "name": "user535",
+ },
+ {
+ "name": "user536",
+ },
+ {
+ "name": "user537",
+ },
+ {
+ "name": "user538",
+ },
+ {
+ "name": "user539",
+ },
+ {
+ "name": "user540",
+ },
+ {
+ "name": "user541",
+ },
+ {
+ "name": "user542",
+ },
+ {
+ "name": "user543",
+ },
+ {
+ "name": "user544",
+ },
+ {
+ "name": "user545",
+ },
+ {
+ "name": "user546",
+ },
+ {
+ "name": "user547",
+ },
+ {
+ "name": "user548",
+ },
+ {
+ "name": "user549",
+ },
+ {
+ "name": "user550",
+ },
+ {
+ "name": "user551",
+ },
+ {
+ "name": "user552",
+ },
+ {
+ "name": "user553",
+ },
+ {
+ "name": "user554",
+ },
+ {
+ "name": "user555",
+ },
+ {
+ "name": "user556",
+ },
+ {
+ "name": "user557",
+ },
+ {
+ "name": "user558",
+ },
+ {
+ "name": "user559",
+ },
+ {
+ "name": "user560",
+ },
+ {
+ "name": "user561",
+ },
+ {
+ "name": "user562",
+ },
+ {
+ "name": "user563",
+ },
+ {
+ "name": "user564",
+ },
+ {
+ "name": "user565",
+ },
+ {
+ "name": "user566",
+ },
+ {
+ "name": "user567",
+ },
+ {
+ "name": "user568",
+ },
+ {
+ "name": "user569",
+ },
+ {
+ "name": "user570",
+ },
+ {
+ "name": "user571",
+ },
+ {
+ "name": "user572",
+ },
+ {
+ "name": "user573",
+ },
+ {
+ "name": "user574",
+ },
+ {
+ "name": "user575",
+ },
+ {
+ "name": "user576",
+ },
+ {
+ "name": "user577",
+ },
+ {
+ "name": "user578",
+ },
+ {
+ "name": "user579",
+ },
+ {
+ "name": "user580",
+ },
+ {
+ "name": "user581",
+ },
+ {
+ "name": "user582",
+ },
+ {
+ "name": "user583",
+ },
+ {
+ "name": "user584",
+ },
+ {
+ "name": "user585",
+ },
+ {
+ "name": "user586",
+ },
+ {
+ "name": "user587",
+ },
+ {
+ "name": "user588",
+ },
+ {
+ "name": "user589",
+ },
+ {
+ "name": "user590",
+ },
+ {
+ "name": "user591",
+ },
+ {
+ "name": "user592",
+ },
+ {
+ "name": "user593",
+ },
+ {
+ "name": "user594",
+ },
+ {
+ "name": "user595",
+ },
+ {
+ "name": "user596",
+ },
+ {
+ "name": "user597",
+ },
+ {
+ "name": "user598",
+ },
+ {
+ "name": "user599",
+ },
+ {
+ "name": "user600",
+ },
+ {
+ "name": "user601",
+ },
+ {
+ "name": "user602",
+ },
+ {
+ "name": "user603",
+ },
+ {
+ "name": "user604",
+ },
+ {
+ "name": "user605",
+ },
+ {
+ "name": "user606",
+ },
+ {
+ "name": "user607",
+ },
+ {
+ "name": "user608",
+ },
+ {
+ "name": "user609",
+ },
+ {
+ "name": "user610",
+ },
+ {
+ "name": "user611",
+ },
+ {
+ "name": "user612",
+ },
+ {
+ "name": "user613",
+ },
+ {
+ "name": "user614",
+ },
+ {
+ "name": "user615",
+ },
+ {
+ "name": "user616",
+ },
+ {
+ "name": "user617",
+ },
+ {
+ "name": "user618",
+ },
+ {
+ "name": "user619",
+ },
+ {
+ "name": "user620",
+ },
+ {
+ "name": "user621",
+ },
+ {
+ "name": "user622",
+ },
+ {
+ "name": "user623",
+ },
+ {
+ "name": "user624",
+ },
+ {
+ "name": "user625",
+ },
+ {
+ "name": "user626",
+ },
+ {
+ "name": "user627",
+ },
+ {
+ "name": "user628",
+ },
+ {
+ "name": "user629",
+ },
+ {
+ "name": "user630",
+ },
+ {
+ "name": "user631",
+ },
+ {
+ "name": "user632",
+ },
+ {
+ "name": "user633",
+ },
+ {
+ "name": "user634",
+ },
+ {
+ "name": "user635",
+ },
+ {
+ "name": "user636",
+ },
+ {
+ "name": "user637",
+ },
+ {
+ "name": "user638",
+ },
+ {
+ "name": "user639",
+ },
+ {
+ "name": "user640",
+ },
+ {
+ "name": "user641",
+ },
+ {
+ "name": "user642",
+ },
+ {
+ "name": "user643",
+ },
+ {
+ "name": "user644",
+ },
+ {
+ "name": "user645",
+ },
+ {
+ "name": "user646",
+ },
+ {
+ "name": "user647",
+ },
+ {
+ "name": "user648",
+ },
+ {
+ "name": "user649",
+ },
+ {
+ "name": "user650",
+ },
+ {
+ "name": "user651",
+ },
+ {
+ "name": "user652",
+ },
+ {
+ "name": "user653",
+ },
+ {
+ "name": "user654",
+ },
+ {
+ "name": "user655",
+ },
+ {
+ "name": "user656",
+ },
+ {
+ "name": "user657",
+ },
+ {
+ "name": "user658",
+ },
+ {
+ "name": "user659",
+ },
+ {
+ "name": "user660",
+ },
+ {
+ "name": "user661",
+ },
+ {
+ "name": "user662",
+ },
+ {
+ "name": "user663",
+ },
+ {
+ "name": "user664",
+ },
+ {
+ "name": "user665",
+ },
+ {
+ "name": "user666",
+ },
+ {
+ "name": "user667",
+ },
+ {
+ "name": "user668",
+ },
+ {
+ "name": "user669",
+ },
+ {
+ "name": "user670",
+ },
+ {
+ "name": "user671",
+ },
+ {
+ "name": "user672",
+ },
+ {
+ "name": "user673",
+ },
+ {
+ "name": "user674",
+ },
+ {
+ "name": "user675",
+ },
+ {
+ "name": "user676",
+ },
+ {
+ "name": "user677",
+ },
+ {
+ "name": "user678",
+ },
+ {
+ "name": "user679",
+ },
+ {
+ "name": "user680",
+ },
+ {
+ "name": "user681",
+ },
+ {
+ "name": "user682",
+ },
+ {
+ "name": "user683",
+ },
+ {
+ "name": "user684",
+ },
+ {
+ "name": "user685",
+ },
+ {
+ "name": "user686",
+ },
+ {
+ "name": "user687",
+ },
+ {
+ "name": "user688",
+ },
+ {
+ "name": "user689",
+ },
+ {
+ "name": "user690",
+ },
+ {
+ "name": "user691",
+ },
+ {
+ "name": "user692",
+ },
+ {
+ "name": "user693",
+ },
+ {
+ "name": "user694",
+ },
+ {
+ "name": "user695",
+ },
+ {
+ "name": "user696",
+ },
+ {
+ "name": "user697",
+ },
+ {
+ "name": "user698",
+ },
+ {
+ "name": "user699",
+ },
+ {
+ "name": "user700",
+ },
+ {
+ "name": "user701",
+ },
+ {
+ "name": "user702",
+ },
+ {
+ "name": "user703",
+ },
+ {
+ "name": "user704",
+ },
+ {
+ "name": "user705",
+ },
+ {
+ "name": "user706",
+ },
+ {
+ "name": "user707",
+ },
+ {
+ "name": "user708",
+ },
+ {
+ "name": "user709",
+ },
+ {
+ "name": "user710",
+ },
+ {
+ "name": "user711",
+ },
+ {
+ "name": "user712",
+ },
+ {
+ "name": "user713",
+ },
+ {
+ "name": "user714",
+ },
+ {
+ "name": "user715",
+ },
+ {
+ "name": "user716",
+ },
+ {
+ "name": "user717",
+ },
+ {
+ "name": "user718",
+ },
+ {
+ "name": "user719",
+ },
+ {
+ "name": "user720",
+ },
+ {
+ "name": "user721",
+ },
+ {
+ "name": "user722",
+ },
+ {
+ "name": "user723",
+ },
+ {
+ "name": "user724",
+ },
+ {
+ "name": "user725",
+ },
+ {
+ "name": "user726",
+ },
+ {
+ "name": "user727",
+ },
+ {
+ "name": "user728",
+ },
+ {
+ "name": "user729",
+ },
+ {
+ "name": "user730",
+ },
+ {
+ "name": "user731",
+ },
+ {
+ "name": "user732",
+ },
+ {
+ "name": "user733",
+ },
+ {
+ "name": "user734",
+ },
+ {
+ "name": "user735",
+ },
+ {
+ "name": "user736",
+ },
+ {
+ "name": "user737",
+ },
+ {
+ "name": "user738",
+ },
+ {
+ "name": "user739",
+ },
+ {
+ "name": "user740",
+ },
+ {
+ "name": "user741",
+ },
+ {
+ "name": "user742",
+ },
+ {
+ "name": "user743",
+ },
+ {
+ "name": "user744",
+ },
+ {
+ "name": "user745",
+ },
+ {
+ "name": "user746",
+ },
+ {
+ "name": "user747",
+ },
+ {
+ "name": "user748",
+ },
+ {
+ "name": "user749",
+ },
+ {
+ "name": "user750",
+ },
+ {
+ "name": "user751",
+ },
+ {
+ "name": "user752",
+ },
+ {
+ "name": "user753",
+ },
+ {
+ "name": "user754",
+ },
+ {
+ "name": "user755",
+ },
+ {
+ "name": "user756",
+ },
+ {
+ "name": "user757",
+ },
+ {
+ "name": "user758",
+ },
+ {
+ "name": "user759",
+ },
+ {
+ "name": "user760",
+ },
+ {
+ "name": "user761",
+ },
+ {
+ "name": "user762",
+ },
+ {
+ "name": "user763",
+ },
+ {
+ "name": "user764",
+ },
+ {
+ "name": "user765",
+ },
+ {
+ "name": "user766",
+ },
+ {
+ "name": "user767",
+ },
+ {
+ "name": "user768",
+ },
+ {
+ "name": "user769",
+ },
+ {
+ "name": "user770",
+ },
+ {
+ "name": "user771",
+ },
+ {
+ "name": "user772",
+ },
+ {
+ "name": "user773",
+ },
+ {
+ "name": "user774",
+ },
+ {
+ "name": "user775",
+ },
+ {
+ "name": "user776",
+ },
+ {
+ "name": "user777",
+ },
+ {
+ "name": "user778",
+ },
+ {
+ "name": "user779",
+ },
+ {
+ "name": "user780",
+ },
+ {
+ "name": "user781",
+ },
+ {
+ "name": "user782",
+ },
+ {
+ "name": "user783",
+ },
+ {
+ "name": "user784",
+ },
+ {
+ "name": "user785",
+ },
+ {
+ "name": "user786",
+ },
+ {
+ "name": "user787",
+ },
+ {
+ "name": "user788",
+ },
+ {
+ "name": "user789",
+ },
+ {
+ "name": "user790",
+ },
+ {
+ "name": "user791",
+ },
+ {
+ "name": "user792",
+ },
+ {
+ "name": "user793",
+ },
+ {
+ "name": "user794",
+ },
+ {
+ "name": "user795",
+ },
+ {
+ "name": "user796",
+ },
+ {
+ "name": "user797",
+ },
+ {
+ "name": "user798",
+ },
+ {
+ "name": "user799",
+ },
+ {
+ "name": "user800",
+ },
+ {
+ "name": "user801",
+ },
+ {
+ "name": "user802",
+ },
+ {
+ "name": "user803",
+ },
+ {
+ "name": "user804",
+ },
+ {
+ "name": "user805",
+ },
+ {
+ "name": "user806",
+ },
+ {
+ "name": "user807",
+ },
+ {
+ "name": "user808",
+ },
+ {
+ "name": "user809",
+ },
+ {
+ "name": "user810",
+ },
+ {
+ "name": "user811",
+ },
+ {
+ "name": "user812",
+ },
+ {
+ "name": "user813",
+ },
+ {
+ "name": "user814",
+ },
+ {
+ "name": "user815",
+ },
+ {
+ "name": "user816",
+ },
+ {
+ "name": "user817",
+ },
+ {
+ "name": "user818",
+ },
+ {
+ "name": "user819",
+ },
+ {
+ "name": "user820",
+ },
+ {
+ "name": "user821",
+ },
+ {
+ "name": "user822",
+ },
+ {
+ "name": "user823",
+ },
+ {
+ "name": "user824",
+ },
+ {
+ "name": "user825",
+ },
+ {
+ "name": "user826",
+ },
+ {
+ "name": "user827",
+ },
+ {
+ "name": "user828",
+ },
+ {
+ "name": "user829",
+ },
+ {
+ "name": "user830",
+ },
+ {
+ "name": "user831",
+ },
+ {
+ "name": "user832",
+ },
+ {
+ "name": "user833",
+ },
+ {
+ "name": "user834",
+ },
+ {
+ "name": "user835",
+ },
+ {
+ "name": "user836",
+ },
+ {
+ "name": "user837",
+ },
+ {
+ "name": "user838",
+ },
+ {
+ "name": "user839",
+ },
+ {
+ "name": "user840",
+ },
+ {
+ "name": "user841",
+ },
+ {
+ "name": "user842",
+ },
+ {
+ "name": "user843",
+ },
+ {
+ "name": "user844",
+ },
+ {
+ "name": "user845",
+ },
+ {
+ "name": "user846",
+ },
+ {
+ "name": "user847",
+ },
+ {
+ "name": "user848",
+ },
+ {
+ "name": "user849",
+ },
+ {
+ "name": "user850",
+ },
+ {
+ "name": "user851",
+ },
+ {
+ "name": "user852",
+ },
+ {
+ "name": "user853",
+ },
+ {
+ "name": "user854",
+ },
+ {
+ "name": "user855",
+ },
+ {
+ "name": "user856",
+ },
+ {
+ "name": "user857",
+ },
+ {
+ "name": "user858",
+ },
+ {
+ "name": "user859",
+ },
+ {
+ "name": "user860",
+ },
+ {
+ "name": "user861",
+ },
+ {
+ "name": "user862",
+ },
+ {
+ "name": "user863",
+ },
+ {
+ "name": "user864",
+ },
+ {
+ "name": "user865",
+ },
+ {
+ "name": "user866",
+ },
+ {
+ "name": "user867",
+ },
+ {
+ "name": "user868",
+ },
+ {
+ "name": "user869",
+ },
+ {
+ "name": "user870",
+ },
+ {
+ "name": "user871",
+ },
+ {
+ "name": "user872",
+ },
+ {
+ "name": "user873",
+ },
+ {
+ "name": "user874",
+ },
+ {
+ "name": "user875",
+ },
+ {
+ "name": "user876",
+ },
+ {
+ "name": "user877",
+ },
+ {
+ "name": "user878",
+ },
+ {
+ "name": "user879",
+ },
+ {
+ "name": "user880",
+ },
+ {
+ "name": "user881",
+ },
+ {
+ "name": "user882",
+ },
+ {
+ "name": "user883",
+ },
+ {
+ "name": "user884",
+ },
+ {
+ "name": "user885",
+ },
+ {
+ "name": "user886",
+ },
+ {
+ "name": "user887",
+ },
+ {
+ "name": "user888",
+ },
+ {
+ "name": "user889",
+ },
+ {
+ "name": "user890",
+ },
+ {
+ "name": "user891",
+ },
+ {
+ "name": "user892",
+ },
+ {
+ "name": "user893",
+ },
+ {
+ "name": "user894",
+ },
+ {
+ "name": "user895",
+ },
+ {
+ "name": "user896",
+ },
+ {
+ "name": "user897",
+ },
+ {
+ "name": "user898",
+ },
+ {
+ "name": "user899",
+ },
+ {
+ "name": "user900",
+ },
+ {
+ "name": "user901",
+ },
+ {
+ "name": "user902",
+ },
+ {
+ "name": "user903",
+ },
+ {
+ "name": "user904",
+ },
+ {
+ "name": "user905",
+ },
+ {
+ "name": "user906",
+ },
+ {
+ "name": "user907",
+ },
+ {
+ "name": "user908",
+ },
+ {
+ "name": "user909",
+ },
+ {
+ "name": "user910",
+ },
+ {
+ "name": "user911",
+ },
+ {
+ "name": "user912",
+ },
+ {
+ "name": "user913",
+ },
+ {
+ "name": "user914",
+ },
+ {
+ "name": "user915",
+ },
+ {
+ "name": "user916",
+ },
+ {
+ "name": "user917",
+ },
+ {
+ "name": "user918",
+ },
+ {
+ "name": "user919",
+ },
+ {
+ "name": "user920",
+ },
+ {
+ "name": "user921",
+ },
+ {
+ "name": "user922",
+ },
+ {
+ "name": "user923",
+ },
+ {
+ "name": "user924",
+ },
+ {
+ "name": "user925",
+ },
+ {
+ "name": "user926",
+ },
+ {
+ "name": "user927",
+ },
+ {
+ "name": "user928",
+ },
+ {
+ "name": "user929",
+ },
+ {
+ "name": "user930",
+ },
+ {
+ "name": "user931",
+ },
+ {
+ "name": "user932",
+ },
+ {
+ "name": "user933",
+ },
+ {
+ "name": "user934",
+ },
+ {
+ "name": "user935",
+ },
+ {
+ "name": "user936",
+ },
+ {
+ "name": "user937",
+ },
+ {
+ "name": "user938",
+ },
+ {
+ "name": "user939",
+ },
+ {
+ "name": "user940",
+ },
+ {
+ "name": "user941",
+ },
+ {
+ "name": "user942",
+ },
+ {
+ "name": "user943",
+ },
+ {
+ "name": "user944",
+ },
+ {
+ "name": "user945",
+ },
+ {
+ "name": "user946",
+ },
+ {
+ "name": "user947",
+ },
+ {
+ "name": "user948",
+ },
+ {
+ "name": "user949",
+ },
+ {
+ "name": "user950",
+ },
+ {
+ "name": "user951",
+ },
+ {
+ "name": "user952",
+ },
+ {
+ "name": "user953",
+ },
+ {
+ "name": "user954",
+ },
+ {
+ "name": "user955",
+ },
+ {
+ "name": "user956",
+ },
+ {
+ "name": "user957",
+ },
+ {
+ "name": "user958",
+ },
+ {
+ "name": "user959",
+ },
+ {
+ "name": "user960",
+ },
+ {
+ "name": "user961",
+ },
+ {
+ "name": "user962",
+ },
+ {
+ "name": "user963",
+ },
+ {
+ "name": "user964",
+ },
+ {
+ "name": "user965",
+ },
+ {
+ "name": "user966",
+ },
+ {
+ "name": "user967",
+ },
+ {
+ "name": "user968",
+ },
+ {
+ "name": "user969",
+ },
+ {
+ "name": "user970",
+ },
+ {
+ "name": "user971",
+ },
+ {
+ "name": "user972",
+ },
+ {
+ "name": "user973",
+ },
+ {
+ "name": "user974",
+ },
+ {
+ "name": "user975",
+ },
+ {
+ "name": "user976",
+ },
+ {
+ "name": "user977",
+ },
+ {
+ "name": "user978",
+ },
+ {
+ "name": "user979",
+ },
+ {
+ "name": "user980",
+ },
+ {
+ "name": "user981",
+ },
+ {
+ "name": "user982",
+ },
+ {
+ "name": "user983",
+ },
+ {
+ "name": "user984",
+ },
+ {
+ "name": "user985",
+ },
+ {
+ "name": "user986",
+ },
+ {
+ "name": "user987",
+ },
+ {
+ "name": "user988",
+ },
+ {
+ "name": "user989",
+ },
+ {
+ "name": "user990",
+ },
+ {
+ "name": "user991",
+ },
+ {
+ "name": "user992",
+ },
+ {
+ "name": "user993",
+ },
+ {
+ "name": "user994",
+ },
+ {
+ "name": "user995",
+ },
+ {
+ "name": "user996",
+ },
+ {
+ "name": "user997",
+ },
+ {
+ "name": "user998",
+ },
+ {
+ "name": "user999",
+ },
+ {
+ "name": "user1000",
+ }
+ ]
+}
diff --git a/tests/user/users_absent.sh b/tests/user/users_absent.sh
new file mode 100644
index 00000000..1ee89ada
--- /dev/null
+++ b/tests/user/users_absent.sh
@@ -0,0 +1,22 @@
+#!/bin/bash
+
+NUM=1000
+FILE="users_absent.json"
+
+echo "{" > $FILE
+
+echo " \"users\": [" >> $FILE
+
+for i in $(seq 1 $NUM); do
+ echo " {" >> $FILE
+ echo " \"name\": \"user$i\"," >> $FILE
+ if [ $i -lt $NUM ]; then
+ echo " }," >> $FILE
+ else
+ echo " }" >> $FILE
+ fi
+done
+
+echo " ]" >> $FILE
+
+echo "}" >> $FILE
diff --git a/tests/user/users_present.json b/tests/user/users_present.json
new file mode 100644
index 00000000..514edc88
--- /dev/null
+++ b/tests/user/users_present.json
@@ -0,0 +1,5004 @@
+{
+ "users": [
+ {
+ "name": "user1",
+ "first": "First 1",
+ "last": "Last 1"
+ },
+ {
+ "name": "user2",
+ "first": "First 2",
+ "last": "Last 2"
+ },
+ {
+ "name": "user3",
+ "first": "First 3",
+ "last": "Last 3"
+ },
+ {
+ "name": "user4",
+ "first": "First 4",
+ "last": "Last 4"
+ },
+ {
+ "name": "user5",
+ "first": "First 5",
+ "last": "Last 5"
+ },
+ {
+ "name": "user6",
+ "first": "First 6",
+ "last": "Last 6"
+ },
+ {
+ "name": "user7",
+ "first": "First 7",
+ "last": "Last 7"
+ },
+ {
+ "name": "user8",
+ "first": "First 8",
+ "last": "Last 8"
+ },
+ {
+ "name": "user9",
+ "first": "First 9",
+ "last": "Last 9"
+ },
+ {
+ "name": "user10",
+ "first": "First 10",
+ "last": "Last 10"
+ },
+ {
+ "name": "user11",
+ "first": "First 11",
+ "last": "Last 11"
+ },
+ {
+ "name": "user12",
+ "first": "First 12",
+ "last": "Last 12"
+ },
+ {
+ "name": "user13",
+ "first": "First 13",
+ "last": "Last 13"
+ },
+ {
+ "name": "user14",
+ "first": "First 14",
+ "last": "Last 14"
+ },
+ {
+ "name": "user15",
+ "first": "First 15",
+ "last": "Last 15"
+ },
+ {
+ "name": "user16",
+ "first": "First 16",
+ "last": "Last 16"
+ },
+ {
+ "name": "user17",
+ "first": "First 17",
+ "last": "Last 17"
+ },
+ {
+ "name": "user18",
+ "first": "First 18",
+ "last": "Last 18"
+ },
+ {
+ "name": "user19",
+ "first": "First 19",
+ "last": "Last 19"
+ },
+ {
+ "name": "user20",
+ "first": "First 20",
+ "last": "Last 20"
+ },
+ {
+ "name": "user21",
+ "first": "First 21",
+ "last": "Last 21"
+ },
+ {
+ "name": "user22",
+ "first": "First 22",
+ "last": "Last 22"
+ },
+ {
+ "name": "user23",
+ "first": "First 23",
+ "last": "Last 23"
+ },
+ {
+ "name": "user24",
+ "first": "First 24",
+ "last": "Last 24"
+ },
+ {
+ "name": "user25",
+ "first": "First 25",
+ "last": "Last 25"
+ },
+ {
+ "name": "user26",
+ "first": "First 26",
+ "last": "Last 26"
+ },
+ {
+ "name": "user27",
+ "first": "First 27",
+ "last": "Last 27"
+ },
+ {
+ "name": "user28",
+ "first": "First 28",
+ "last": "Last 28"
+ },
+ {
+ "name": "user29",
+ "first": "First 29",
+ "last": "Last 29"
+ },
+ {
+ "name": "user30",
+ "first": "First 30",
+ "last": "Last 30"
+ },
+ {
+ "name": "user31",
+ "first": "First 31",
+ "last": "Last 31"
+ },
+ {
+ "name": "user32",
+ "first": "First 32",
+ "last": "Last 32"
+ },
+ {
+ "name": "user33",
+ "first": "First 33",
+ "last": "Last 33"
+ },
+ {
+ "name": "user34",
+ "first": "First 34",
+ "last": "Last 34"
+ },
+ {
+ "name": "user35",
+ "first": "First 35",
+ "last": "Last 35"
+ },
+ {
+ "name": "user36",
+ "first": "First 36",
+ "last": "Last 36"
+ },
+ {
+ "name": "user37",
+ "first": "First 37",
+ "last": "Last 37"
+ },
+ {
+ "name": "user38",
+ "first": "First 38",
+ "last": "Last 38"
+ },
+ {
+ "name": "user39",
+ "first": "First 39",
+ "last": "Last 39"
+ },
+ {
+ "name": "user40",
+ "first": "First 40",
+ "last": "Last 40"
+ },
+ {
+ "name": "user41",
+ "first": "First 41",
+ "last": "Last 41"
+ },
+ {
+ "name": "user42",
+ "first": "First 42",
+ "last": "Last 42"
+ },
+ {
+ "name": "user43",
+ "first": "First 43",
+ "last": "Last 43"
+ },
+ {
+ "name": "user44",
+ "first": "First 44",
+ "last": "Last 44"
+ },
+ {
+ "name": "user45",
+ "first": "First 45",
+ "last": "Last 45"
+ },
+ {
+ "name": "user46",
+ "first": "First 46",
+ "last": "Last 46"
+ },
+ {
+ "name": "user47",
+ "first": "First 47",
+ "last": "Last 47"
+ },
+ {
+ "name": "user48",
+ "first": "First 48",
+ "last": "Last 48"
+ },
+ {
+ "name": "user49",
+ "first": "First 49",
+ "last": "Last 49"
+ },
+ {
+ "name": "user50",
+ "first": "First 50",
+ "last": "Last 50"
+ },
+ {
+ "name": "user51",
+ "first": "First 51",
+ "last": "Last 51"
+ },
+ {
+ "name": "user52",
+ "first": "First 52",
+ "last": "Last 52"
+ },
+ {
+ "name": "user53",
+ "first": "First 53",
+ "last": "Last 53"
+ },
+ {
+ "name": "user54",
+ "first": "First 54",
+ "last": "Last 54"
+ },
+ {
+ "name": "user55",
+ "first": "First 55",
+ "last": "Last 55"
+ },
+ {
+ "name": "user56",
+ "first": "First 56",
+ "last": "Last 56"
+ },
+ {
+ "name": "user57",
+ "first": "First 57",
+ "last": "Last 57"
+ },
+ {
+ "name": "user58",
+ "first": "First 58",
+ "last": "Last 58"
+ },
+ {
+ "name": "user59",
+ "first": "First 59",
+ "last": "Last 59"
+ },
+ {
+ "name": "user60",
+ "first": "First 60",
+ "last": "Last 60"
+ },
+ {
+ "name": "user61",
+ "first": "First 61",
+ "last": "Last 61"
+ },
+ {
+ "name": "user62",
+ "first": "First 62",
+ "last": "Last 62"
+ },
+ {
+ "name": "user63",
+ "first": "First 63",
+ "last": "Last 63"
+ },
+ {
+ "name": "user64",
+ "first": "First 64",
+ "last": "Last 64"
+ },
+ {
+ "name": "user65",
+ "first": "First 65",
+ "last": "Last 65"
+ },
+ {
+ "name": "user66",
+ "first": "First 66",
+ "last": "Last 66"
+ },
+ {
+ "name": "user67",
+ "first": "First 67",
+ "last": "Last 67"
+ },
+ {
+ "name": "user68",
+ "first": "First 68",
+ "last": "Last 68"
+ },
+ {
+ "name": "user69",
+ "first": "First 69",
+ "last": "Last 69"
+ },
+ {
+ "name": "user70",
+ "first": "First 70",
+ "last": "Last 70"
+ },
+ {
+ "name": "user71",
+ "first": "First 71",
+ "last": "Last 71"
+ },
+ {
+ "name": "user72",
+ "first": "First 72",
+ "last": "Last 72"
+ },
+ {
+ "name": "user73",
+ "first": "First 73",
+ "last": "Last 73"
+ },
+ {
+ "name": "user74",
+ "first": "First 74",
+ "last": "Last 74"
+ },
+ {
+ "name": "user75",
+ "first": "First 75",
+ "last": "Last 75"
+ },
+ {
+ "name": "user76",
+ "first": "First 76",
+ "last": "Last 76"
+ },
+ {
+ "name": "user77",
+ "first": "First 77",
+ "last": "Last 77"
+ },
+ {
+ "name": "user78",
+ "first": "First 78",
+ "last": "Last 78"
+ },
+ {
+ "name": "user79",
+ "first": "First 79",
+ "last": "Last 79"
+ },
+ {
+ "name": "user80",
+ "first": "First 80",
+ "last": "Last 80"
+ },
+ {
+ "name": "user81",
+ "first": "First 81",
+ "last": "Last 81"
+ },
+ {
+ "name": "user82",
+ "first": "First 82",
+ "last": "Last 82"
+ },
+ {
+ "name": "user83",
+ "first": "First 83",
+ "last": "Last 83"
+ },
+ {
+ "name": "user84",
+ "first": "First 84",
+ "last": "Last 84"
+ },
+ {
+ "name": "user85",
+ "first": "First 85",
+ "last": "Last 85"
+ },
+ {
+ "name": "user86",
+ "first": "First 86",
+ "last": "Last 86"
+ },
+ {
+ "name": "user87",
+ "first": "First 87",
+ "last": "Last 87"
+ },
+ {
+ "name": "user88",
+ "first": "First 88",
+ "last": "Last 88"
+ },
+ {
+ "name": "user89",
+ "first": "First 89",
+ "last": "Last 89"
+ },
+ {
+ "name": "user90",
+ "first": "First 90",
+ "last": "Last 90"
+ },
+ {
+ "name": "user91",
+ "first": "First 91",
+ "last": "Last 91"
+ },
+ {
+ "name": "user92",
+ "first": "First 92",
+ "last": "Last 92"
+ },
+ {
+ "name": "user93",
+ "first": "First 93",
+ "last": "Last 93"
+ },
+ {
+ "name": "user94",
+ "first": "First 94",
+ "last": "Last 94"
+ },
+ {
+ "name": "user95",
+ "first": "First 95",
+ "last": "Last 95"
+ },
+ {
+ "name": "user96",
+ "first": "First 96",
+ "last": "Last 96"
+ },
+ {
+ "name": "user97",
+ "first": "First 97",
+ "last": "Last 97"
+ },
+ {
+ "name": "user98",
+ "first": "First 98",
+ "last": "Last 98"
+ },
+ {
+ "name": "user99",
+ "first": "First 99",
+ "last": "Last 99"
+ },
+ {
+ "name": "user100",
+ "first": "First 100",
+ "last": "Last 100"
+ },
+ {
+ "name": "user101",
+ "first": "First 101",
+ "last": "Last 101"
+ },
+ {
+ "name": "user102",
+ "first": "First 102",
+ "last": "Last 102"
+ },
+ {
+ "name": "user103",
+ "first": "First 103",
+ "last": "Last 103"
+ },
+ {
+ "name": "user104",
+ "first": "First 104",
+ "last": "Last 104"
+ },
+ {
+ "name": "user105",
+ "first": "First 105",
+ "last": "Last 105"
+ },
+ {
+ "name": "user106",
+ "first": "First 106",
+ "last": "Last 106"
+ },
+ {
+ "name": "user107",
+ "first": "First 107",
+ "last": "Last 107"
+ },
+ {
+ "name": "user108",
+ "first": "First 108",
+ "last": "Last 108"
+ },
+ {
+ "name": "user109",
+ "first": "First 109",
+ "last": "Last 109"
+ },
+ {
+ "name": "user110",
+ "first": "First 110",
+ "last": "Last 110"
+ },
+ {
+ "name": "user111",
+ "first": "First 111",
+ "last": "Last 111"
+ },
+ {
+ "name": "user112",
+ "first": "First 112",
+ "last": "Last 112"
+ },
+ {
+ "name": "user113",
+ "first": "First 113",
+ "last": "Last 113"
+ },
+ {
+ "name": "user114",
+ "first": "First 114",
+ "last": "Last 114"
+ },
+ {
+ "name": "user115",
+ "first": "First 115",
+ "last": "Last 115"
+ },
+ {
+ "name": "user116",
+ "first": "First 116",
+ "last": "Last 116"
+ },
+ {
+ "name": "user117",
+ "first": "First 117",
+ "last": "Last 117"
+ },
+ {
+ "name": "user118",
+ "first": "First 118",
+ "last": "Last 118"
+ },
+ {
+ "name": "user119",
+ "first": "First 119",
+ "last": "Last 119"
+ },
+ {
+ "name": "user120",
+ "first": "First 120",
+ "last": "Last 120"
+ },
+ {
+ "name": "user121",
+ "first": "First 121",
+ "last": "Last 121"
+ },
+ {
+ "name": "user122",
+ "first": "First 122",
+ "last": "Last 122"
+ },
+ {
+ "name": "user123",
+ "first": "First 123",
+ "last": "Last 123"
+ },
+ {
+ "name": "user124",
+ "first": "First 124",
+ "last": "Last 124"
+ },
+ {
+ "name": "user125",
+ "first": "First 125",
+ "last": "Last 125"
+ },
+ {
+ "name": "user126",
+ "first": "First 126",
+ "last": "Last 126"
+ },
+ {
+ "name": "user127",
+ "first": "First 127",
+ "last": "Last 127"
+ },
+ {
+ "name": "user128",
+ "first": "First 128",
+ "last": "Last 128"
+ },
+ {
+ "name": "user129",
+ "first": "First 129",
+ "last": "Last 129"
+ },
+ {
+ "name": "user130",
+ "first": "First 130",
+ "last": "Last 130"
+ },
+ {
+ "name": "user131",
+ "first": "First 131",
+ "last": "Last 131"
+ },
+ {
+ "name": "user132",
+ "first": "First 132",
+ "last": "Last 132"
+ },
+ {
+ "name": "user133",
+ "first": "First 133",
+ "last": "Last 133"
+ },
+ {
+ "name": "user134",
+ "first": "First 134",
+ "last": "Last 134"
+ },
+ {
+ "name": "user135",
+ "first": "First 135",
+ "last": "Last 135"
+ },
+ {
+ "name": "user136",
+ "first": "First 136",
+ "last": "Last 136"
+ },
+ {
+ "name": "user137",
+ "first": "First 137",
+ "last": "Last 137"
+ },
+ {
+ "name": "user138",
+ "first": "First 138",
+ "last": "Last 138"
+ },
+ {
+ "name": "user139",
+ "first": "First 139",
+ "last": "Last 139"
+ },
+ {
+ "name": "user140",
+ "first": "First 140",
+ "last": "Last 140"
+ },
+ {
+ "name": "user141",
+ "first": "First 141",
+ "last": "Last 141"
+ },
+ {
+ "name": "user142",
+ "first": "First 142",
+ "last": "Last 142"
+ },
+ {
+ "name": "user143",
+ "first": "First 143",
+ "last": "Last 143"
+ },
+ {
+ "name": "user144",
+ "first": "First 144",
+ "last": "Last 144"
+ },
+ {
+ "name": "user145",
+ "first": "First 145",
+ "last": "Last 145"
+ },
+ {
+ "name": "user146",
+ "first": "First 146",
+ "last": "Last 146"
+ },
+ {
+ "name": "user147",
+ "first": "First 147",
+ "last": "Last 147"
+ },
+ {
+ "name": "user148",
+ "first": "First 148",
+ "last": "Last 148"
+ },
+ {
+ "name": "user149",
+ "first": "First 149",
+ "last": "Last 149"
+ },
+ {
+ "name": "user150",
+ "first": "First 150",
+ "last": "Last 150"
+ },
+ {
+ "name": "user151",
+ "first": "First 151",
+ "last": "Last 151"
+ },
+ {
+ "name": "user152",
+ "first": "First 152",
+ "last": "Last 152"
+ },
+ {
+ "name": "user153",
+ "first": "First 153",
+ "last": "Last 153"
+ },
+ {
+ "name": "user154",
+ "first": "First 154",
+ "last": "Last 154"
+ },
+ {
+ "name": "user155",
+ "first": "First 155",
+ "last": "Last 155"
+ },
+ {
+ "name": "user156",
+ "first": "First 156",
+ "last": "Last 156"
+ },
+ {
+ "name": "user157",
+ "first": "First 157",
+ "last": "Last 157"
+ },
+ {
+ "name": "user158",
+ "first": "First 158",
+ "last": "Last 158"
+ },
+ {
+ "name": "user159",
+ "first": "First 159",
+ "last": "Last 159"
+ },
+ {
+ "name": "user160",
+ "first": "First 160",
+ "last": "Last 160"
+ },
+ {
+ "name": "user161",
+ "first": "First 161",
+ "last": "Last 161"
+ },
+ {
+ "name": "user162",
+ "first": "First 162",
+ "last": "Last 162"
+ },
+ {
+ "name": "user163",
+ "first": "First 163",
+ "last": "Last 163"
+ },
+ {
+ "name": "user164",
+ "first": "First 164",
+ "last": "Last 164"
+ },
+ {
+ "name": "user165",
+ "first": "First 165",
+ "last": "Last 165"
+ },
+ {
+ "name": "user166",
+ "first": "First 166",
+ "last": "Last 166"
+ },
+ {
+ "name": "user167",
+ "first": "First 167",
+ "last": "Last 167"
+ },
+ {
+ "name": "user168",
+ "first": "First 168",
+ "last": "Last 168"
+ },
+ {
+ "name": "user169",
+ "first": "First 169",
+ "last": "Last 169"
+ },
+ {
+ "name": "user170",
+ "first": "First 170",
+ "last": "Last 170"
+ },
+ {
+ "name": "user171",
+ "first": "First 171",
+ "last": "Last 171"
+ },
+ {
+ "name": "user172",
+ "first": "First 172",
+ "last": "Last 172"
+ },
+ {
+ "name": "user173",
+ "first": "First 173",
+ "last": "Last 173"
+ },
+ {
+ "name": "user174",
+ "first": "First 174",
+ "last": "Last 174"
+ },
+ {
+ "name": "user175",
+ "first": "First 175",
+ "last": "Last 175"
+ },
+ {
+ "name": "user176",
+ "first": "First 176",
+ "last": "Last 176"
+ },
+ {
+ "name": "user177",
+ "first": "First 177",
+ "last": "Last 177"
+ },
+ {
+ "name": "user178",
+ "first": "First 178",
+ "last": "Last 178"
+ },
+ {
+ "name": "user179",
+ "first": "First 179",
+ "last": "Last 179"
+ },
+ {
+ "name": "user180",
+ "first": "First 180",
+ "last": "Last 180"
+ },
+ {
+ "name": "user181",
+ "first": "First 181",
+ "last": "Last 181"
+ },
+ {
+ "name": "user182",
+ "first": "First 182",
+ "last": "Last 182"
+ },
+ {
+ "name": "user183",
+ "first": "First 183",
+ "last": "Last 183"
+ },
+ {
+ "name": "user184",
+ "first": "First 184",
+ "last": "Last 184"
+ },
+ {
+ "name": "user185",
+ "first": "First 185",
+ "last": "Last 185"
+ },
+ {
+ "name": "user186",
+ "first": "First 186",
+ "last": "Last 186"
+ },
+ {
+ "name": "user187",
+ "first": "First 187",
+ "last": "Last 187"
+ },
+ {
+ "name": "user188",
+ "first": "First 188",
+ "last": "Last 188"
+ },
+ {
+ "name": "user189",
+ "first": "First 189",
+ "last": "Last 189"
+ },
+ {
+ "name": "user190",
+ "first": "First 190",
+ "last": "Last 190"
+ },
+ {
+ "name": "user191",
+ "first": "First 191",
+ "last": "Last 191"
+ },
+ {
+ "name": "user192",
+ "first": "First 192",
+ "last": "Last 192"
+ },
+ {
+ "name": "user193",
+ "first": "First 193",
+ "last": "Last 193"
+ },
+ {
+ "name": "user194",
+ "first": "First 194",
+ "last": "Last 194"
+ },
+ {
+ "name": "user195",
+ "first": "First 195",
+ "last": "Last 195"
+ },
+ {
+ "name": "user196",
+ "first": "First 196",
+ "last": "Last 196"
+ },
+ {
+ "name": "user197",
+ "first": "First 197",
+ "last": "Last 197"
+ },
+ {
+ "name": "user198",
+ "first": "First 198",
+ "last": "Last 198"
+ },
+ {
+ "name": "user199",
+ "first": "First 199",
+ "last": "Last 199"
+ },
+ {
+ "name": "user200",
+ "first": "First 200",
+ "last": "Last 200"
+ },
+ {
+ "name": "user201",
+ "first": "First 201",
+ "last": "Last 201"
+ },
+ {
+ "name": "user202",
+ "first": "First 202",
+ "last": "Last 202"
+ },
+ {
+ "name": "user203",
+ "first": "First 203",
+ "last": "Last 203"
+ },
+ {
+ "name": "user204",
+ "first": "First 204",
+ "last": "Last 204"
+ },
+ {
+ "name": "user205",
+ "first": "First 205",
+ "last": "Last 205"
+ },
+ {
+ "name": "user206",
+ "first": "First 206",
+ "last": "Last 206"
+ },
+ {
+ "name": "user207",
+ "first": "First 207",
+ "last": "Last 207"
+ },
+ {
+ "name": "user208",
+ "first": "First 208",
+ "last": "Last 208"
+ },
+ {
+ "name": "user209",
+ "first": "First 209",
+ "last": "Last 209"
+ },
+ {
+ "name": "user210",
+ "first": "First 210",
+ "last": "Last 210"
+ },
+ {
+ "name": "user211",
+ "first": "First 211",
+ "last": "Last 211"
+ },
+ {
+ "name": "user212",
+ "first": "First 212",
+ "last": "Last 212"
+ },
+ {
+ "name": "user213",
+ "first": "First 213",
+ "last": "Last 213"
+ },
+ {
+ "name": "user214",
+ "first": "First 214",
+ "last": "Last 214"
+ },
+ {
+ "name": "user215",
+ "first": "First 215",
+ "last": "Last 215"
+ },
+ {
+ "name": "user216",
+ "first": "First 216",
+ "last": "Last 216"
+ },
+ {
+ "name": "user217",
+ "first": "First 217",
+ "last": "Last 217"
+ },
+ {
+ "name": "user218",
+ "first": "First 218",
+ "last": "Last 218"
+ },
+ {
+ "name": "user219",
+ "first": "First 219",
+ "last": "Last 219"
+ },
+ {
+ "name": "user220",
+ "first": "First 220",
+ "last": "Last 220"
+ },
+ {
+ "name": "user221",
+ "first": "First 221",
+ "last": "Last 221"
+ },
+ {
+ "name": "user222",
+ "first": "First 222",
+ "last": "Last 222"
+ },
+ {
+ "name": "user223",
+ "first": "First 223",
+ "last": "Last 223"
+ },
+ {
+ "name": "user224",
+ "first": "First 224",
+ "last": "Last 224"
+ },
+ {
+ "name": "user225",
+ "first": "First 225",
+ "last": "Last 225"
+ },
+ {
+ "name": "user226",
+ "first": "First 226",
+ "last": "Last 226"
+ },
+ {
+ "name": "user227",
+ "first": "First 227",
+ "last": "Last 227"
+ },
+ {
+ "name": "user228",
+ "first": "First 228",
+ "last": "Last 228"
+ },
+ {
+ "name": "user229",
+ "first": "First 229",
+ "last": "Last 229"
+ },
+ {
+ "name": "user230",
+ "first": "First 230",
+ "last": "Last 230"
+ },
+ {
+ "name": "user231",
+ "first": "First 231",
+ "last": "Last 231"
+ },
+ {
+ "name": "user232",
+ "first": "First 232",
+ "last": "Last 232"
+ },
+ {
+ "name": "user233",
+ "first": "First 233",
+ "last": "Last 233"
+ },
+ {
+ "name": "user234",
+ "first": "First 234",
+ "last": "Last 234"
+ },
+ {
+ "name": "user235",
+ "first": "First 235",
+ "last": "Last 235"
+ },
+ {
+ "name": "user236",
+ "first": "First 236",
+ "last": "Last 236"
+ },
+ {
+ "name": "user237",
+ "first": "First 237",
+ "last": "Last 237"
+ },
+ {
+ "name": "user238",
+ "first": "First 238",
+ "last": "Last 238"
+ },
+ {
+ "name": "user239",
+ "first": "First 239",
+ "last": "Last 239"
+ },
+ {
+ "name": "user240",
+ "first": "First 240",
+ "last": "Last 240"
+ },
+ {
+ "name": "user241",
+ "first": "First 241",
+ "last": "Last 241"
+ },
+ {
+ "name": "user242",
+ "first": "First 242",
+ "last": "Last 242"
+ },
+ {
+ "name": "user243",
+ "first": "First 243",
+ "last": "Last 243"
+ },
+ {
+ "name": "user244",
+ "first": "First 244",
+ "last": "Last 244"
+ },
+ {
+ "name": "user245",
+ "first": "First 245",
+ "last": "Last 245"
+ },
+ {
+ "name": "user246",
+ "first": "First 246",
+ "last": "Last 246"
+ },
+ {
+ "name": "user247",
+ "first": "First 247",
+ "last": "Last 247"
+ },
+ {
+ "name": "user248",
+ "first": "First 248",
+ "last": "Last 248"
+ },
+ {
+ "name": "user249",
+ "first": "First 249",
+ "last": "Last 249"
+ },
+ {
+ "name": "user250",
+ "first": "First 250",
+ "last": "Last 250"
+ },
+ {
+ "name": "user251",
+ "first": "First 251",
+ "last": "Last 251"
+ },
+ {
+ "name": "user252",
+ "first": "First 252",
+ "last": "Last 252"
+ },
+ {
+ "name": "user253",
+ "first": "First 253",
+ "last": "Last 253"
+ },
+ {
+ "name": "user254",
+ "first": "First 254",
+ "last": "Last 254"
+ },
+ {
+ "name": "user255",
+ "first": "First 255",
+ "last": "Last 255"
+ },
+ {
+ "name": "user256",
+ "first": "First 256",
+ "last": "Last 256"
+ },
+ {
+ "name": "user257",
+ "first": "First 257",
+ "last": "Last 257"
+ },
+ {
+ "name": "user258",
+ "first": "First 258",
+ "last": "Last 258"
+ },
+ {
+ "name": "user259",
+ "first": "First 259",
+ "last": "Last 259"
+ },
+ {
+ "name": "user260",
+ "first": "First 260",
+ "last": "Last 260"
+ },
+ {
+ "name": "user261",
+ "first": "First 261",
+ "last": "Last 261"
+ },
+ {
+ "name": "user262",
+ "first": "First 262",
+ "last": "Last 262"
+ },
+ {
+ "name": "user263",
+ "first": "First 263",
+ "last": "Last 263"
+ },
+ {
+ "name": "user264",
+ "first": "First 264",
+ "last": "Last 264"
+ },
+ {
+ "name": "user265",
+ "first": "First 265",
+ "last": "Last 265"
+ },
+ {
+ "name": "user266",
+ "first": "First 266",
+ "last": "Last 266"
+ },
+ {
+ "name": "user267",
+ "first": "First 267",
+ "last": "Last 267"
+ },
+ {
+ "name": "user268",
+ "first": "First 268",
+ "last": "Last 268"
+ },
+ {
+ "name": "user269",
+ "first": "First 269",
+ "last": "Last 269"
+ },
+ {
+ "name": "user270",
+ "first": "First 270",
+ "last": "Last 270"
+ },
+ {
+ "name": "user271",
+ "first": "First 271",
+ "last": "Last 271"
+ },
+ {
+ "name": "user272",
+ "first": "First 272",
+ "last": "Last 272"
+ },
+ {
+ "name": "user273",
+ "first": "First 273",
+ "last": "Last 273"
+ },
+ {
+ "name": "user274",
+ "first": "First 274",
+ "last": "Last 274"
+ },
+ {
+ "name": "user275",
+ "first": "First 275",
+ "last": "Last 275"
+ },
+ {
+ "name": "user276",
+ "first": "First 276",
+ "last": "Last 276"
+ },
+ {
+ "name": "user277",
+ "first": "First 277",
+ "last": "Last 277"
+ },
+ {
+ "name": "user278",
+ "first": "First 278",
+ "last": "Last 278"
+ },
+ {
+ "name": "user279",
+ "first": "First 279",
+ "last": "Last 279"
+ },
+ {
+ "name": "user280",
+ "first": "First 280",
+ "last": "Last 280"
+ },
+ {
+ "name": "user281",
+ "first": "First 281",
+ "last": "Last 281"
+ },
+ {
+ "name": "user282",
+ "first": "First 282",
+ "last": "Last 282"
+ },
+ {
+ "name": "user283",
+ "first": "First 283",
+ "last": "Last 283"
+ },
+ {
+ "name": "user284",
+ "first": "First 284",
+ "last": "Last 284"
+ },
+ {
+ "name": "user285",
+ "first": "First 285",
+ "last": "Last 285"
+ },
+ {
+ "name": "user286",
+ "first": "First 286",
+ "last": "Last 286"
+ },
+ {
+ "name": "user287",
+ "first": "First 287",
+ "last": "Last 287"
+ },
+ {
+ "name": "user288",
+ "first": "First 288",
+ "last": "Last 288"
+ },
+ {
+ "name": "user289",
+ "first": "First 289",
+ "last": "Last 289"
+ },
+ {
+ "name": "user290",
+ "first": "First 290",
+ "last": "Last 290"
+ },
+ {
+ "name": "user291",
+ "first": "First 291",
+ "last": "Last 291"
+ },
+ {
+ "name": "user292",
+ "first": "First 292",
+ "last": "Last 292"
+ },
+ {
+ "name": "user293",
+ "first": "First 293",
+ "last": "Last 293"
+ },
+ {
+ "name": "user294",
+ "first": "First 294",
+ "last": "Last 294"
+ },
+ {
+ "name": "user295",
+ "first": "First 295",
+ "last": "Last 295"
+ },
+ {
+ "name": "user296",
+ "first": "First 296",
+ "last": "Last 296"
+ },
+ {
+ "name": "user297",
+ "first": "First 297",
+ "last": "Last 297"
+ },
+ {
+ "name": "user298",
+ "first": "First 298",
+ "last": "Last 298"
+ },
+ {
+ "name": "user299",
+ "first": "First 299",
+ "last": "Last 299"
+ },
+ {
+ "name": "user300",
+ "first": "First 300",
+ "last": "Last 300"
+ },
+ {
+ "name": "user301",
+ "first": "First 301",
+ "last": "Last 301"
+ },
+ {
+ "name": "user302",
+ "first": "First 302",
+ "last": "Last 302"
+ },
+ {
+ "name": "user303",
+ "first": "First 303",
+ "last": "Last 303"
+ },
+ {
+ "name": "user304",
+ "first": "First 304",
+ "last": "Last 304"
+ },
+ {
+ "name": "user305",
+ "first": "First 305",
+ "last": "Last 305"
+ },
+ {
+ "name": "user306",
+ "first": "First 306",
+ "last": "Last 306"
+ },
+ {
+ "name": "user307",
+ "first": "First 307",
+ "last": "Last 307"
+ },
+ {
+ "name": "user308",
+ "first": "First 308",
+ "last": "Last 308"
+ },
+ {
+ "name": "user309",
+ "first": "First 309",
+ "last": "Last 309"
+ },
+ {
+ "name": "user310",
+ "first": "First 310",
+ "last": "Last 310"
+ },
+ {
+ "name": "user311",
+ "first": "First 311",
+ "last": "Last 311"
+ },
+ {
+ "name": "user312",
+ "first": "First 312",
+ "last": "Last 312"
+ },
+ {
+ "name": "user313",
+ "first": "First 313",
+ "last": "Last 313"
+ },
+ {
+ "name": "user314",
+ "first": "First 314",
+ "last": "Last 314"
+ },
+ {
+ "name": "user315",
+ "first": "First 315",
+ "last": "Last 315"
+ },
+ {
+ "name": "user316",
+ "first": "First 316",
+ "last": "Last 316"
+ },
+ {
+ "name": "user317",
+ "first": "First 317",
+ "last": "Last 317"
+ },
+ {
+ "name": "user318",
+ "first": "First 318",
+ "last": "Last 318"
+ },
+ {
+ "name": "user319",
+ "first": "First 319",
+ "last": "Last 319"
+ },
+ {
+ "name": "user320",
+ "first": "First 320",
+ "last": "Last 320"
+ },
+ {
+ "name": "user321",
+ "first": "First 321",
+ "last": "Last 321"
+ },
+ {
+ "name": "user322",
+ "first": "First 322",
+ "last": "Last 322"
+ },
+ {
+ "name": "user323",
+ "first": "First 323",
+ "last": "Last 323"
+ },
+ {
+ "name": "user324",
+ "first": "First 324",
+ "last": "Last 324"
+ },
+ {
+ "name": "user325",
+ "first": "First 325",
+ "last": "Last 325"
+ },
+ {
+ "name": "user326",
+ "first": "First 326",
+ "last": "Last 326"
+ },
+ {
+ "name": "user327",
+ "first": "First 327",
+ "last": "Last 327"
+ },
+ {
+ "name": "user328",
+ "first": "First 328",
+ "last": "Last 328"
+ },
+ {
+ "name": "user329",
+ "first": "First 329",
+ "last": "Last 329"
+ },
+ {
+ "name": "user330",
+ "first": "First 330",
+ "last": "Last 330"
+ },
+ {
+ "name": "user331",
+ "first": "First 331",
+ "last": "Last 331"
+ },
+ {
+ "name": "user332",
+ "first": "First 332",
+ "last": "Last 332"
+ },
+ {
+ "name": "user333",
+ "first": "First 333",
+ "last": "Last 333"
+ },
+ {
+ "name": "user334",
+ "first": "First 334",
+ "last": "Last 334"
+ },
+ {
+ "name": "user335",
+ "first": "First 335",
+ "last": "Last 335"
+ },
+ {
+ "name": "user336",
+ "first": "First 336",
+ "last": "Last 336"
+ },
+ {
+ "name": "user337",
+ "first": "First 337",
+ "last": "Last 337"
+ },
+ {
+ "name": "user338",
+ "first": "First 338",
+ "last": "Last 338"
+ },
+ {
+ "name": "user339",
+ "first": "First 339",
+ "last": "Last 339"
+ },
+ {
+ "name": "user340",
+ "first": "First 340",
+ "last": "Last 340"
+ },
+ {
+ "name": "user341",
+ "first": "First 341",
+ "last": "Last 341"
+ },
+ {
+ "name": "user342",
+ "first": "First 342",
+ "last": "Last 342"
+ },
+ {
+ "name": "user343",
+ "first": "First 343",
+ "last": "Last 343"
+ },
+ {
+ "name": "user344",
+ "first": "First 344",
+ "last": "Last 344"
+ },
+ {
+ "name": "user345",
+ "first": "First 345",
+ "last": "Last 345"
+ },
+ {
+ "name": "user346",
+ "first": "First 346",
+ "last": "Last 346"
+ },
+ {
+ "name": "user347",
+ "first": "First 347",
+ "last": "Last 347"
+ },
+ {
+ "name": "user348",
+ "first": "First 348",
+ "last": "Last 348"
+ },
+ {
+ "name": "user349",
+ "first": "First 349",
+ "last": "Last 349"
+ },
+ {
+ "name": "user350",
+ "first": "First 350",
+ "last": "Last 350"
+ },
+ {
+ "name": "user351",
+ "first": "First 351",
+ "last": "Last 351"
+ },
+ {
+ "name": "user352",
+ "first": "First 352",
+ "last": "Last 352"
+ },
+ {
+ "name": "user353",
+ "first": "First 353",
+ "last": "Last 353"
+ },
+ {
+ "name": "user354",
+ "first": "First 354",
+ "last": "Last 354"
+ },
+ {
+ "name": "user355",
+ "first": "First 355",
+ "last": "Last 355"
+ },
+ {
+ "name": "user356",
+ "first": "First 356",
+ "last": "Last 356"
+ },
+ {
+ "name": "user357",
+ "first": "First 357",
+ "last": "Last 357"
+ },
+ {
+ "name": "user358",
+ "first": "First 358",
+ "last": "Last 358"
+ },
+ {
+ "name": "user359",
+ "first": "First 359",
+ "last": "Last 359"
+ },
+ {
+ "name": "user360",
+ "first": "First 360",
+ "last": "Last 360"
+ },
+ {
+ "name": "user361",
+ "first": "First 361",
+ "last": "Last 361"
+ },
+ {
+ "name": "user362",
+ "first": "First 362",
+ "last": "Last 362"
+ },
+ {
+ "name": "user363",
+ "first": "First 363",
+ "last": "Last 363"
+ },
+ {
+ "name": "user364",
+ "first": "First 364",
+ "last": "Last 364"
+ },
+ {
+ "name": "user365",
+ "first": "First 365",
+ "last": "Last 365"
+ },
+ {
+ "name": "user366",
+ "first": "First 366",
+ "last": "Last 366"
+ },
+ {
+ "name": "user367",
+ "first": "First 367",
+ "last": "Last 367"
+ },
+ {
+ "name": "user368",
+ "first": "First 368",
+ "last": "Last 368"
+ },
+ {
+ "name": "user369",
+ "first": "First 369",
+ "last": "Last 369"
+ },
+ {
+ "name": "user370",
+ "first": "First 370",
+ "last": "Last 370"
+ },
+ {
+ "name": "user371",
+ "first": "First 371",
+ "last": "Last 371"
+ },
+ {
+ "name": "user372",
+ "first": "First 372",
+ "last": "Last 372"
+ },
+ {
+ "name": "user373",
+ "first": "First 373",
+ "last": "Last 373"
+ },
+ {
+ "name": "user374",
+ "first": "First 374",
+ "last": "Last 374"
+ },
+ {
+ "name": "user375",
+ "first": "First 375",
+ "last": "Last 375"
+ },
+ {
+ "name": "user376",
+ "first": "First 376",
+ "last": "Last 376"
+ },
+ {
+ "name": "user377",
+ "first": "First 377",
+ "last": "Last 377"
+ },
+ {
+ "name": "user378",
+ "first": "First 378",
+ "last": "Last 378"
+ },
+ {
+ "name": "user379",
+ "first": "First 379",
+ "last": "Last 379"
+ },
+ {
+ "name": "user380",
+ "first": "First 380",
+ "last": "Last 380"
+ },
+ {
+ "name": "user381",
+ "first": "First 381",
+ "last": "Last 381"
+ },
+ {
+ "name": "user382",
+ "first": "First 382",
+ "last": "Last 382"
+ },
+ {
+ "name": "user383",
+ "first": "First 383",
+ "last": "Last 383"
+ },
+ {
+ "name": "user384",
+ "first": "First 384",
+ "last": "Last 384"
+ },
+ {
+ "name": "user385",
+ "first": "First 385",
+ "last": "Last 385"
+ },
+ {
+ "name": "user386",
+ "first": "First 386",
+ "last": "Last 386"
+ },
+ {
+ "name": "user387",
+ "first": "First 387",
+ "last": "Last 387"
+ },
+ {
+ "name": "user388",
+ "first": "First 388",
+ "last": "Last 388"
+ },
+ {
+ "name": "user389",
+ "first": "First 389",
+ "last": "Last 389"
+ },
+ {
+ "name": "user390",
+ "first": "First 390",
+ "last": "Last 390"
+ },
+ {
+ "name": "user391",
+ "first": "First 391",
+ "last": "Last 391"
+ },
+ {
+ "name": "user392",
+ "first": "First 392",
+ "last": "Last 392"
+ },
+ {
+ "name": "user393",
+ "first": "First 393",
+ "last": "Last 393"
+ },
+ {
+ "name": "user394",
+ "first": "First 394",
+ "last": "Last 394"
+ },
+ {
+ "name": "user395",
+ "first": "First 395",
+ "last": "Last 395"
+ },
+ {
+ "name": "user396",
+ "first": "First 396",
+ "last": "Last 396"
+ },
+ {
+ "name": "user397",
+ "first": "First 397",
+ "last": "Last 397"
+ },
+ {
+ "name": "user398",
+ "first": "First 398",
+ "last": "Last 398"
+ },
+ {
+ "name": "user399",
+ "first": "First 399",
+ "last": "Last 399"
+ },
+ {
+ "name": "user400",
+ "first": "First 400",
+ "last": "Last 400"
+ },
+ {
+ "name": "user401",
+ "first": "First 401",
+ "last": "Last 401"
+ },
+ {
+ "name": "user402",
+ "first": "First 402",
+ "last": "Last 402"
+ },
+ {
+ "name": "user403",
+ "first": "First 403",
+ "last": "Last 403"
+ },
+ {
+ "name": "user404",
+ "first": "First 404",
+ "last": "Last 404"
+ },
+ {
+ "name": "user405",
+ "first": "First 405",
+ "last": "Last 405"
+ },
+ {
+ "name": "user406",
+ "first": "First 406",
+ "last": "Last 406"
+ },
+ {
+ "name": "user407",
+ "first": "First 407",
+ "last": "Last 407"
+ },
+ {
+ "name": "user408",
+ "first": "First 408",
+ "last": "Last 408"
+ },
+ {
+ "name": "user409",
+ "first": "First 409",
+ "last": "Last 409"
+ },
+ {
+ "name": "user410",
+ "first": "First 410",
+ "last": "Last 410"
+ },
+ {
+ "name": "user411",
+ "first": "First 411",
+ "last": "Last 411"
+ },
+ {
+ "name": "user412",
+ "first": "First 412",
+ "last": "Last 412"
+ },
+ {
+ "name": "user413",
+ "first": "First 413",
+ "last": "Last 413"
+ },
+ {
+ "name": "user414",
+ "first": "First 414",
+ "last": "Last 414"
+ },
+ {
+ "name": "user415",
+ "first": "First 415",
+ "last": "Last 415"
+ },
+ {
+ "name": "user416",
+ "first": "First 416",
+ "last": "Last 416"
+ },
+ {
+ "name": "user417",
+ "first": "First 417",
+ "last": "Last 417"
+ },
+ {
+ "name": "user418",
+ "first": "First 418",
+ "last": "Last 418"
+ },
+ {
+ "name": "user419",
+ "first": "First 419",
+ "last": "Last 419"
+ },
+ {
+ "name": "user420",
+ "first": "First 420",
+ "last": "Last 420"
+ },
+ {
+ "name": "user421",
+ "first": "First 421",
+ "last": "Last 421"
+ },
+ {
+ "name": "user422",
+ "first": "First 422",
+ "last": "Last 422"
+ },
+ {
+ "name": "user423",
+ "first": "First 423",
+ "last": "Last 423"
+ },
+ {
+ "name": "user424",
+ "first": "First 424",
+ "last": "Last 424"
+ },
+ {
+ "name": "user425",
+ "first": "First 425",
+ "last": "Last 425"
+ },
+ {
+ "name": "user426",
+ "first": "First 426",
+ "last": "Last 426"
+ },
+ {
+ "name": "user427",
+ "first": "First 427",
+ "last": "Last 427"
+ },
+ {
+ "name": "user428",
+ "first": "First 428",
+ "last": "Last 428"
+ },
+ {
+ "name": "user429",
+ "first": "First 429",
+ "last": "Last 429"
+ },
+ {
+ "name": "user430",
+ "first": "First 430",
+ "last": "Last 430"
+ },
+ {
+ "name": "user431",
+ "first": "First 431",
+ "last": "Last 431"
+ },
+ {
+ "name": "user432",
+ "first": "First 432",
+ "last": "Last 432"
+ },
+ {
+ "name": "user433",
+ "first": "First 433",
+ "last": "Last 433"
+ },
+ {
+ "name": "user434",
+ "first": "First 434",
+ "last": "Last 434"
+ },
+ {
+ "name": "user435",
+ "first": "First 435",
+ "last": "Last 435"
+ },
+ {
+ "name": "user436",
+ "first": "First 436",
+ "last": "Last 436"
+ },
+ {
+ "name": "user437",
+ "first": "First 437",
+ "last": "Last 437"
+ },
+ {
+ "name": "user438",
+ "first": "First 438",
+ "last": "Last 438"
+ },
+ {
+ "name": "user439",
+ "first": "First 439",
+ "last": "Last 439"
+ },
+ {
+ "name": "user440",
+ "first": "First 440",
+ "last": "Last 440"
+ },
+ {
+ "name": "user441",
+ "first": "First 441",
+ "last": "Last 441"
+ },
+ {
+ "name": "user442",
+ "first": "First 442",
+ "last": "Last 442"
+ },
+ {
+ "name": "user443",
+ "first": "First 443",
+ "last": "Last 443"
+ },
+ {
+ "name": "user444",
+ "first": "First 444",
+ "last": "Last 444"
+ },
+ {
+ "name": "user445",
+ "first": "First 445",
+ "last": "Last 445"
+ },
+ {
+ "name": "user446",
+ "first": "First 446",
+ "last": "Last 446"
+ },
+ {
+ "name": "user447",
+ "first": "First 447",
+ "last": "Last 447"
+ },
+ {
+ "name": "user448",
+ "first": "First 448",
+ "last": "Last 448"
+ },
+ {
+ "name": "user449",
+ "first": "First 449",
+ "last": "Last 449"
+ },
+ {
+ "name": "user450",
+ "first": "First 450",
+ "last": "Last 450"
+ },
+ {
+ "name": "user451",
+ "first": "First 451",
+ "last": "Last 451"
+ },
+ {
+ "name": "user452",
+ "first": "First 452",
+ "last": "Last 452"
+ },
+ {
+ "name": "user453",
+ "first": "First 453",
+ "last": "Last 453"
+ },
+ {
+ "name": "user454",
+ "first": "First 454",
+ "last": "Last 454"
+ },
+ {
+ "name": "user455",
+ "first": "First 455",
+ "last": "Last 455"
+ },
+ {
+ "name": "user456",
+ "first": "First 456",
+ "last": "Last 456"
+ },
+ {
+ "name": "user457",
+ "first": "First 457",
+ "last": "Last 457"
+ },
+ {
+ "name": "user458",
+ "first": "First 458",
+ "last": "Last 458"
+ },
+ {
+ "name": "user459",
+ "first": "First 459",
+ "last": "Last 459"
+ },
+ {
+ "name": "user460",
+ "first": "First 460",
+ "last": "Last 460"
+ },
+ {
+ "name": "user461",
+ "first": "First 461",
+ "last": "Last 461"
+ },
+ {
+ "name": "user462",
+ "first": "First 462",
+ "last": "Last 462"
+ },
+ {
+ "name": "user463",
+ "first": "First 463",
+ "last": "Last 463"
+ },
+ {
+ "name": "user464",
+ "first": "First 464",
+ "last": "Last 464"
+ },
+ {
+ "name": "user465",
+ "first": "First 465",
+ "last": "Last 465"
+ },
+ {
+ "name": "user466",
+ "first": "First 466",
+ "last": "Last 466"
+ },
+ {
+ "name": "user467",
+ "first": "First 467",
+ "last": "Last 467"
+ },
+ {
+ "name": "user468",
+ "first": "First 468",
+ "last": "Last 468"
+ },
+ {
+ "name": "user469",
+ "first": "First 469",
+ "last": "Last 469"
+ },
+ {
+ "name": "user470",
+ "first": "First 470",
+ "last": "Last 470"
+ },
+ {
+ "name": "user471",
+ "first": "First 471",
+ "last": "Last 471"
+ },
+ {
+ "name": "user472",
+ "first": "First 472",
+ "last": "Last 472"
+ },
+ {
+ "name": "user473",
+ "first": "First 473",
+ "last": "Last 473"
+ },
+ {
+ "name": "user474",
+ "first": "First 474",
+ "last": "Last 474"
+ },
+ {
+ "name": "user475",
+ "first": "First 475",
+ "last": "Last 475"
+ },
+ {
+ "name": "user476",
+ "first": "First 476",
+ "last": "Last 476"
+ },
+ {
+ "name": "user477",
+ "first": "First 477",
+ "last": "Last 477"
+ },
+ {
+ "name": "user478",
+ "first": "First 478",
+ "last": "Last 478"
+ },
+ {
+ "name": "user479",
+ "first": "First 479",
+ "last": "Last 479"
+ },
+ {
+ "name": "user480",
+ "first": "First 480",
+ "last": "Last 480"
+ },
+ {
+ "name": "user481",
+ "first": "First 481",
+ "last": "Last 481"
+ },
+ {
+ "name": "user482",
+ "first": "First 482",
+ "last": "Last 482"
+ },
+ {
+ "name": "user483",
+ "first": "First 483",
+ "last": "Last 483"
+ },
+ {
+ "name": "user484",
+ "first": "First 484",
+ "last": "Last 484"
+ },
+ {
+ "name": "user485",
+ "first": "First 485",
+ "last": "Last 485"
+ },
+ {
+ "name": "user486",
+ "first": "First 486",
+ "last": "Last 486"
+ },
+ {
+ "name": "user487",
+ "first": "First 487",
+ "last": "Last 487"
+ },
+ {
+ "name": "user488",
+ "first": "First 488",
+ "last": "Last 488"
+ },
+ {
+ "name": "user489",
+ "first": "First 489",
+ "last": "Last 489"
+ },
+ {
+ "name": "user490",
+ "first": "First 490",
+ "last": "Last 490"
+ },
+ {
+ "name": "user491",
+ "first": "First 491",
+ "last": "Last 491"
+ },
+ {
+ "name": "user492",
+ "first": "First 492",
+ "last": "Last 492"
+ },
+ {
+ "name": "user493",
+ "first": "First 493",
+ "last": "Last 493"
+ },
+ {
+ "name": "user494",
+ "first": "First 494",
+ "last": "Last 494"
+ },
+ {
+ "name": "user495",
+ "first": "First 495",
+ "last": "Last 495"
+ },
+ {
+ "name": "user496",
+ "first": "First 496",
+ "last": "Last 496"
+ },
+ {
+ "name": "user497",
+ "first": "First 497",
+ "last": "Last 497"
+ },
+ {
+ "name": "user498",
+ "first": "First 498",
+ "last": "Last 498"
+ },
+ {
+ "name": "user499",
+ "first": "First 499",
+ "last": "Last 499"
+ },
+ {
+ "name": "user500",
+ "first": "First 500",
+ "last": "Last 500"
+ },
+ {
+ "name": "user501",
+ "first": "First 501",
+ "last": "Last 501"
+ },
+ {
+ "name": "user502",
+ "first": "First 502",
+ "last": "Last 502"
+ },
+ {
+ "name": "user503",
+ "first": "First 503",
+ "last": "Last 503"
+ },
+ {
+ "name": "user504",
+ "first": "First 504",
+ "last": "Last 504"
+ },
+ {
+ "name": "user505",
+ "first": "First 505",
+ "last": "Last 505"
+ },
+ {
+ "name": "user506",
+ "first": "First 506",
+ "last": "Last 506"
+ },
+ {
+ "name": "user507",
+ "first": "First 507",
+ "last": "Last 507"
+ },
+ {
+ "name": "user508",
+ "first": "First 508",
+ "last": "Last 508"
+ },
+ {
+ "name": "user509",
+ "first": "First 509",
+ "last": "Last 509"
+ },
+ {
+ "name": "user510",
+ "first": "First 510",
+ "last": "Last 510"
+ },
+ {
+ "name": "user511",
+ "first": "First 511",
+ "last": "Last 511"
+ },
+ {
+ "name": "user512",
+ "first": "First 512",
+ "last": "Last 512"
+ },
+ {
+ "name": "user513",
+ "first": "First 513",
+ "last": "Last 513"
+ },
+ {
+ "name": "user514",
+ "first": "First 514",
+ "last": "Last 514"
+ },
+ {
+ "name": "user515",
+ "first": "First 515",
+ "last": "Last 515"
+ },
+ {
+ "name": "user516",
+ "first": "First 516",
+ "last": "Last 516"
+ },
+ {
+ "name": "user517",
+ "first": "First 517",
+ "last": "Last 517"
+ },
+ {
+ "name": "user518",
+ "first": "First 518",
+ "last": "Last 518"
+ },
+ {
+ "name": "user519",
+ "first": "First 519",
+ "last": "Last 519"
+ },
+ {
+ "name": "user520",
+ "first": "First 520",
+ "last": "Last 520"
+ },
+ {
+ "name": "user521",
+ "first": "First 521",
+ "last": "Last 521"
+ },
+ {
+ "name": "user522",
+ "first": "First 522",
+ "last": "Last 522"
+ },
+ {
+ "name": "user523",
+ "first": "First 523",
+ "last": "Last 523"
+ },
+ {
+ "name": "user524",
+ "first": "First 524",
+ "last": "Last 524"
+ },
+ {
+ "name": "user525",
+ "first": "First 525",
+ "last": "Last 525"
+ },
+ {
+ "name": "user526",
+ "first": "First 526",
+ "last": "Last 526"
+ },
+ {
+ "name": "user527",
+ "first": "First 527",
+ "last": "Last 527"
+ },
+ {
+ "name": "user528",
+ "first": "First 528",
+ "last": "Last 528"
+ },
+ {
+ "name": "user529",
+ "first": "First 529",
+ "last": "Last 529"
+ },
+ {
+ "name": "user530",
+ "first": "First 530",
+ "last": "Last 530"
+ },
+ {
+ "name": "user531",
+ "first": "First 531",
+ "last": "Last 531"
+ },
+ {
+ "name": "user532",
+ "first": "First 532",
+ "last": "Last 532"
+ },
+ {
+ "name": "user533",
+ "first": "First 533",
+ "last": "Last 533"
+ },
+ {
+ "name": "user534",
+ "first": "First 534",
+ "last": "Last 534"
+ },
+ {
+ "name": "user535",
+ "first": "First 535",
+ "last": "Last 535"
+ },
+ {
+ "name": "user536",
+ "first": "First 536",
+ "last": "Last 536"
+ },
+ {
+ "name": "user537",
+ "first": "First 537",
+ "last": "Last 537"
+ },
+ {
+ "name": "user538",
+ "first": "First 538",
+ "last": "Last 538"
+ },
+ {
+ "name": "user539",
+ "first": "First 539",
+ "last": "Last 539"
+ },
+ {
+ "name": "user540",
+ "first": "First 540",
+ "last": "Last 540"
+ },
+ {
+ "name": "user541",
+ "first": "First 541",
+ "last": "Last 541"
+ },
+ {
+ "name": "user542",
+ "first": "First 542",
+ "last": "Last 542"
+ },
+ {
+ "name": "user543",
+ "first": "First 543",
+ "last": "Last 543"
+ },
+ {
+ "name": "user544",
+ "first": "First 544",
+ "last": "Last 544"
+ },
+ {
+ "name": "user545",
+ "first": "First 545",
+ "last": "Last 545"
+ },
+ {
+ "name": "user546",
+ "first": "First 546",
+ "last": "Last 546"
+ },
+ {
+ "name": "user547",
+ "first": "First 547",
+ "last": "Last 547"
+ },
+ {
+ "name": "user548",
+ "first": "First 548",
+ "last": "Last 548"
+ },
+ {
+ "name": "user549",
+ "first": "First 549",
+ "last": "Last 549"
+ },
+ {
+ "name": "user550",
+ "first": "First 550",
+ "last": "Last 550"
+ },
+ {
+ "name": "user551",
+ "first": "First 551",
+ "last": "Last 551"
+ },
+ {
+ "name": "user552",
+ "first": "First 552",
+ "last": "Last 552"
+ },
+ {
+ "name": "user553",
+ "first": "First 553",
+ "last": "Last 553"
+ },
+ {
+ "name": "user554",
+ "first": "First 554",
+ "last": "Last 554"
+ },
+ {
+ "name": "user555",
+ "first": "First 555",
+ "last": "Last 555"
+ },
+ {
+ "name": "user556",
+ "first": "First 556",
+ "last": "Last 556"
+ },
+ {
+ "name": "user557",
+ "first": "First 557",
+ "last": "Last 557"
+ },
+ {
+ "name": "user558",
+ "first": "First 558",
+ "last": "Last 558"
+ },
+ {
+ "name": "user559",
+ "first": "First 559",
+ "last": "Last 559"
+ },
+ {
+ "name": "user560",
+ "first": "First 560",
+ "last": "Last 560"
+ },
+ {
+ "name": "user561",
+ "first": "First 561",
+ "last": "Last 561"
+ },
+ {
+ "name": "user562",
+ "first": "First 562",
+ "last": "Last 562"
+ },
+ {
+ "name": "user563",
+ "first": "First 563",
+ "last": "Last 563"
+ },
+ {
+ "name": "user564",
+ "first": "First 564",
+ "last": "Last 564"
+ },
+ {
+ "name": "user565",
+ "first": "First 565",
+ "last": "Last 565"
+ },
+ {
+ "name": "user566",
+ "first": "First 566",
+ "last": "Last 566"
+ },
+ {
+ "name": "user567",
+ "first": "First 567",
+ "last": "Last 567"
+ },
+ {
+ "name": "user568",
+ "first": "First 568",
+ "last": "Last 568"
+ },
+ {
+ "name": "user569",
+ "first": "First 569",
+ "last": "Last 569"
+ },
+ {
+ "name": "user570",
+ "first": "First 570",
+ "last": "Last 570"
+ },
+ {
+ "name": "user571",
+ "first": "First 571",
+ "last": "Last 571"
+ },
+ {
+ "name": "user572",
+ "first": "First 572",
+ "last": "Last 572"
+ },
+ {
+ "name": "user573",
+ "first": "First 573",
+ "last": "Last 573"
+ },
+ {
+ "name": "user574",
+ "first": "First 574",
+ "last": "Last 574"
+ },
+ {
+ "name": "user575",
+ "first": "First 575",
+ "last": "Last 575"
+ },
+ {
+ "name": "user576",
+ "first": "First 576",
+ "last": "Last 576"
+ },
+ {
+ "name": "user577",
+ "first": "First 577",
+ "last": "Last 577"
+ },
+ {
+ "name": "user578",
+ "first": "First 578",
+ "last": "Last 578"
+ },
+ {
+ "name": "user579",
+ "first": "First 579",
+ "last": "Last 579"
+ },
+ {
+ "name": "user580",
+ "first": "First 580",
+ "last": "Last 580"
+ },
+ {
+ "name": "user581",
+ "first": "First 581",
+ "last": "Last 581"
+ },
+ {
+ "name": "user582",
+ "first": "First 582",
+ "last": "Last 582"
+ },
+ {
+ "name": "user583",
+ "first": "First 583",
+ "last": "Last 583"
+ },
+ {
+ "name": "user584",
+ "first": "First 584",
+ "last": "Last 584"
+ },
+ {
+ "name": "user585",
+ "first": "First 585",
+ "last": "Last 585"
+ },
+ {
+ "name": "user586",
+ "first": "First 586",
+ "last": "Last 586"
+ },
+ {
+ "name": "user587",
+ "first": "First 587",
+ "last": "Last 587"
+ },
+ {
+ "name": "user588",
+ "first": "First 588",
+ "last": "Last 588"
+ },
+ {
+ "name": "user589",
+ "first": "First 589",
+ "last": "Last 589"
+ },
+ {
+ "name": "user590",
+ "first": "First 590",
+ "last": "Last 590"
+ },
+ {
+ "name": "user591",
+ "first": "First 591",
+ "last": "Last 591"
+ },
+ {
+ "name": "user592",
+ "first": "First 592",
+ "last": "Last 592"
+ },
+ {
+ "name": "user593",
+ "first": "First 593",
+ "last": "Last 593"
+ },
+ {
+ "name": "user594",
+ "first": "First 594",
+ "last": "Last 594"
+ },
+ {
+ "name": "user595",
+ "first": "First 595",
+ "last": "Last 595"
+ },
+ {
+ "name": "user596",
+ "first": "First 596",
+ "last": "Last 596"
+ },
+ {
+ "name": "user597",
+ "first": "First 597",
+ "last": "Last 597"
+ },
+ {
+ "name": "user598",
+ "first": "First 598",
+ "last": "Last 598"
+ },
+ {
+ "name": "user599",
+ "first": "First 599",
+ "last": "Last 599"
+ },
+ {
+ "name": "user600",
+ "first": "First 600",
+ "last": "Last 600"
+ },
+ {
+ "name": "user601",
+ "first": "First 601",
+ "last": "Last 601"
+ },
+ {
+ "name": "user602",
+ "first": "First 602",
+ "last": "Last 602"
+ },
+ {
+ "name": "user603",
+ "first": "First 603",
+ "last": "Last 603"
+ },
+ {
+ "name": "user604",
+ "first": "First 604",
+ "last": "Last 604"
+ },
+ {
+ "name": "user605",
+ "first": "First 605",
+ "last": "Last 605"
+ },
+ {
+ "name": "user606",
+ "first": "First 606",
+ "last": "Last 606"
+ },
+ {
+ "name": "user607",
+ "first": "First 607",
+ "last": "Last 607"
+ },
+ {
+ "name": "user608",
+ "first": "First 608",
+ "last": "Last 608"
+ },
+ {
+ "name": "user609",
+ "first": "First 609",
+ "last": "Last 609"
+ },
+ {
+ "name": "user610",
+ "first": "First 610",
+ "last": "Last 610"
+ },
+ {
+ "name": "user611",
+ "first": "First 611",
+ "last": "Last 611"
+ },
+ {
+ "name": "user612",
+ "first": "First 612",
+ "last": "Last 612"
+ },
+ {
+ "name": "user613",
+ "first": "First 613",
+ "last": "Last 613"
+ },
+ {
+ "name": "user614",
+ "first": "First 614",
+ "last": "Last 614"
+ },
+ {
+ "name": "user615",
+ "first": "First 615",
+ "last": "Last 615"
+ },
+ {
+ "name": "user616",
+ "first": "First 616",
+ "last": "Last 616"
+ },
+ {
+ "name": "user617",
+ "first": "First 617",
+ "last": "Last 617"
+ },
+ {
+ "name": "user618",
+ "first": "First 618",
+ "last": "Last 618"
+ },
+ {
+ "name": "user619",
+ "first": "First 619",
+ "last": "Last 619"
+ },
+ {
+ "name": "user620",
+ "first": "First 620",
+ "last": "Last 620"
+ },
+ {
+ "name": "user621",
+ "first": "First 621",
+ "last": "Last 621"
+ },
+ {
+ "name": "user622",
+ "first": "First 622",
+ "last": "Last 622"
+ },
+ {
+ "name": "user623",
+ "first": "First 623",
+ "last": "Last 623"
+ },
+ {
+ "name": "user624",
+ "first": "First 624",
+ "last": "Last 624"
+ },
+ {
+ "name": "user625",
+ "first": "First 625",
+ "last": "Last 625"
+ },
+ {
+ "name": "user626",
+ "first": "First 626",
+ "last": "Last 626"
+ },
+ {
+ "name": "user627",
+ "first": "First 627",
+ "last": "Last 627"
+ },
+ {
+ "name": "user628",
+ "first": "First 628",
+ "last": "Last 628"
+ },
+ {
+ "name": "user629",
+ "first": "First 629",
+ "last": "Last 629"
+ },
+ {
+ "name": "user630",
+ "first": "First 630",
+ "last": "Last 630"
+ },
+ {
+ "name": "user631",
+ "first": "First 631",
+ "last": "Last 631"
+ },
+ {
+ "name": "user632",
+ "first": "First 632",
+ "last": "Last 632"
+ },
+ {
+ "name": "user633",
+ "first": "First 633",
+ "last": "Last 633"
+ },
+ {
+ "name": "user634",
+ "first": "First 634",
+ "last": "Last 634"
+ },
+ {
+ "name": "user635",
+ "first": "First 635",
+ "last": "Last 635"
+ },
+ {
+ "name": "user636",
+ "first": "First 636",
+ "last": "Last 636"
+ },
+ {
+ "name": "user637",
+ "first": "First 637",
+ "last": "Last 637"
+ },
+ {
+ "name": "user638",
+ "first": "First 638",
+ "last": "Last 638"
+ },
+ {
+ "name": "user639",
+ "first": "First 639",
+ "last": "Last 639"
+ },
+ {
+ "name": "user640",
+ "first": "First 640",
+ "last": "Last 640"
+ },
+ {
+ "name": "user641",
+ "first": "First 641",
+ "last": "Last 641"
+ },
+ {
+ "name": "user642",
+ "first": "First 642",
+ "last": "Last 642"
+ },
+ {
+ "name": "user643",
+ "first": "First 643",
+ "last": "Last 643"
+ },
+ {
+ "name": "user644",
+ "first": "First 644",
+ "last": "Last 644"
+ },
+ {
+ "name": "user645",
+ "first": "First 645",
+ "last": "Last 645"
+ },
+ {
+ "name": "user646",
+ "first": "First 646",
+ "last": "Last 646"
+ },
+ {
+ "name": "user647",
+ "first": "First 647",
+ "last": "Last 647"
+ },
+ {
+ "name": "user648",
+ "first": "First 648",
+ "last": "Last 648"
+ },
+ {
+ "name": "user649",
+ "first": "First 649",
+ "last": "Last 649"
+ },
+ {
+ "name": "user650",
+ "first": "First 650",
+ "last": "Last 650"
+ },
+ {
+ "name": "user651",
+ "first": "First 651",
+ "last": "Last 651"
+ },
+ {
+ "name": "user652",
+ "first": "First 652",
+ "last": "Last 652"
+ },
+ {
+ "name": "user653",
+ "first": "First 653",
+ "last": "Last 653"
+ },
+ {
+ "name": "user654",
+ "first": "First 654",
+ "last": "Last 654"
+ },
+ {
+ "name": "user655",
+ "first": "First 655",
+ "last": "Last 655"
+ },
+ {
+ "name": "user656",
+ "first": "First 656",
+ "last": "Last 656"
+ },
+ {
+ "name": "user657",
+ "first": "First 657",
+ "last": "Last 657"
+ },
+ {
+ "name": "user658",
+ "first": "First 658",
+ "last": "Last 658"
+ },
+ {
+ "name": "user659",
+ "first": "First 659",
+ "last": "Last 659"
+ },
+ {
+ "name": "user660",
+ "first": "First 660",
+ "last": "Last 660"
+ },
+ {
+ "name": "user661",
+ "first": "First 661",
+ "last": "Last 661"
+ },
+ {
+ "name": "user662",
+ "first": "First 662",
+ "last": "Last 662"
+ },
+ {
+ "name": "user663",
+ "first": "First 663",
+ "last": "Last 663"
+ },
+ {
+ "name": "user664",
+ "first": "First 664",
+ "last": "Last 664"
+ },
+ {
+ "name": "user665",
+ "first": "First 665",
+ "last": "Last 665"
+ },
+ {
+ "name": "user666",
+ "first": "First 666",
+ "last": "Last 666"
+ },
+ {
+ "name": "user667",
+ "first": "First 667",
+ "last": "Last 667"
+ },
+ {
+ "name": "user668",
+ "first": "First 668",
+ "last": "Last 668"
+ },
+ {
+ "name": "user669",
+ "first": "First 669",
+ "last": "Last 669"
+ },
+ {
+ "name": "user670",
+ "first": "First 670",
+ "last": "Last 670"
+ },
+ {
+ "name": "user671",
+ "first": "First 671",
+ "last": "Last 671"
+ },
+ {
+ "name": "user672",
+ "first": "First 672",
+ "last": "Last 672"
+ },
+ {
+ "name": "user673",
+ "first": "First 673",
+ "last": "Last 673"
+ },
+ {
+ "name": "user674",
+ "first": "First 674",
+ "last": "Last 674"
+ },
+ {
+ "name": "user675",
+ "first": "First 675",
+ "last": "Last 675"
+ },
+ {
+ "name": "user676",
+ "first": "First 676",
+ "last": "Last 676"
+ },
+ {
+ "name": "user677",
+ "first": "First 677",
+ "last": "Last 677"
+ },
+ {
+ "name": "user678",
+ "first": "First 678",
+ "last": "Last 678"
+ },
+ {
+ "name": "user679",
+ "first": "First 679",
+ "last": "Last 679"
+ },
+ {
+ "name": "user680",
+ "first": "First 680",
+ "last": "Last 680"
+ },
+ {
+ "name": "user681",
+ "first": "First 681",
+ "last": "Last 681"
+ },
+ {
+ "name": "user682",
+ "first": "First 682",
+ "last": "Last 682"
+ },
+ {
+ "name": "user683",
+ "first": "First 683",
+ "last": "Last 683"
+ },
+ {
+ "name": "user684",
+ "first": "First 684",
+ "last": "Last 684"
+ },
+ {
+ "name": "user685",
+ "first": "First 685",
+ "last": "Last 685"
+ },
+ {
+ "name": "user686",
+ "first": "First 686",
+ "last": "Last 686"
+ },
+ {
+ "name": "user687",
+ "first": "First 687",
+ "last": "Last 687"
+ },
+ {
+ "name": "user688",
+ "first": "First 688",
+ "last": "Last 688"
+ },
+ {
+ "name": "user689",
+ "first": "First 689",
+ "last": "Last 689"
+ },
+ {
+ "name": "user690",
+ "first": "First 690",
+ "last": "Last 690"
+ },
+ {
+ "name": "user691",
+ "first": "First 691",
+ "last": "Last 691"
+ },
+ {
+ "name": "user692",
+ "first": "First 692",
+ "last": "Last 692"
+ },
+ {
+ "name": "user693",
+ "first": "First 693",
+ "last": "Last 693"
+ },
+ {
+ "name": "user694",
+ "first": "First 694",
+ "last": "Last 694"
+ },
+ {
+ "name": "user695",
+ "first": "First 695",
+ "last": "Last 695"
+ },
+ {
+ "name": "user696",
+ "first": "First 696",
+ "last": "Last 696"
+ },
+ {
+ "name": "user697",
+ "first": "First 697",
+ "last": "Last 697"
+ },
+ {
+ "name": "user698",
+ "first": "First 698",
+ "last": "Last 698"
+ },
+ {
+ "name": "user699",
+ "first": "First 699",
+ "last": "Last 699"
+ },
+ {
+ "name": "user700",
+ "first": "First 700",
+ "last": "Last 700"
+ },
+ {
+ "name": "user701",
+ "first": "First 701",
+ "last": "Last 701"
+ },
+ {
+ "name": "user702",
+ "first": "First 702",
+ "last": "Last 702"
+ },
+ {
+ "name": "user703",
+ "first": "First 703",
+ "last": "Last 703"
+ },
+ {
+ "name": "user704",
+ "first": "First 704",
+ "last": "Last 704"
+ },
+ {
+ "name": "user705",
+ "first": "First 705",
+ "last": "Last 705"
+ },
+ {
+ "name": "user706",
+ "first": "First 706",
+ "last": "Last 706"
+ },
+ {
+ "name": "user707",
+ "first": "First 707",
+ "last": "Last 707"
+ },
+ {
+ "name": "user708",
+ "first": "First 708",
+ "last": "Last 708"
+ },
+ {
+ "name": "user709",
+ "first": "First 709",
+ "last": "Last 709"
+ },
+ {
+ "name": "user710",
+ "first": "First 710",
+ "last": "Last 710"
+ },
+ {
+ "name": "user711",
+ "first": "First 711",
+ "last": "Last 711"
+ },
+ {
+ "name": "user712",
+ "first": "First 712",
+ "last": "Last 712"
+ },
+ {
+ "name": "user713",
+ "first": "First 713",
+ "last": "Last 713"
+ },
+ {
+ "name": "user714",
+ "first": "First 714",
+ "last": "Last 714"
+ },
+ {
+ "name": "user715",
+ "first": "First 715",
+ "last": "Last 715"
+ },
+ {
+ "name": "user716",
+ "first": "First 716",
+ "last": "Last 716"
+ },
+ {
+ "name": "user717",
+ "first": "First 717",
+ "last": "Last 717"
+ },
+ {
+ "name": "user718",
+ "first": "First 718",
+ "last": "Last 718"
+ },
+ {
+ "name": "user719",
+ "first": "First 719",
+ "last": "Last 719"
+ },
+ {
+ "name": "user720",
+ "first": "First 720",
+ "last": "Last 720"
+ },
+ {
+ "name": "user721",
+ "first": "First 721",
+ "last": "Last 721"
+ },
+ {
+ "name": "user722",
+ "first": "First 722",
+ "last": "Last 722"
+ },
+ {
+ "name": "user723",
+ "first": "First 723",
+ "last": "Last 723"
+ },
+ {
+ "name": "user724",
+ "first": "First 724",
+ "last": "Last 724"
+ },
+ {
+ "name": "user725",
+ "first": "First 725",
+ "last": "Last 725"
+ },
+ {
+ "name": "user726",
+ "first": "First 726",
+ "last": "Last 726"
+ },
+ {
+ "name": "user727",
+ "first": "First 727",
+ "last": "Last 727"
+ },
+ {
+ "name": "user728",
+ "first": "First 728",
+ "last": "Last 728"
+ },
+ {
+ "name": "user729",
+ "first": "First 729",
+ "last": "Last 729"
+ },
+ {
+ "name": "user730",
+ "first": "First 730",
+ "last": "Last 730"
+ },
+ {
+ "name": "user731",
+ "first": "First 731",
+ "last": "Last 731"
+ },
+ {
+ "name": "user732",
+ "first": "First 732",
+ "last": "Last 732"
+ },
+ {
+ "name": "user733",
+ "first": "First 733",
+ "last": "Last 733"
+ },
+ {
+ "name": "user734",
+ "first": "First 734",
+ "last": "Last 734"
+ },
+ {
+ "name": "user735",
+ "first": "First 735",
+ "last": "Last 735"
+ },
+ {
+ "name": "user736",
+ "first": "First 736",
+ "last": "Last 736"
+ },
+ {
+ "name": "user737",
+ "first": "First 737",
+ "last": "Last 737"
+ },
+ {
+ "name": "user738",
+ "first": "First 738",
+ "last": "Last 738"
+ },
+ {
+ "name": "user739",
+ "first": "First 739",
+ "last": "Last 739"
+ },
+ {
+ "name": "user740",
+ "first": "First 740",
+ "last": "Last 740"
+ },
+ {
+ "name": "user741",
+ "first": "First 741",
+ "last": "Last 741"
+ },
+ {
+ "name": "user742",
+ "first": "First 742",
+ "last": "Last 742"
+ },
+ {
+ "name": "user743",
+ "first": "First 743",
+ "last": "Last 743"
+ },
+ {
+ "name": "user744",
+ "first": "First 744",
+ "last": "Last 744"
+ },
+ {
+ "name": "user745",
+ "first": "First 745",
+ "last": "Last 745"
+ },
+ {
+ "name": "user746",
+ "first": "First 746",
+ "last": "Last 746"
+ },
+ {
+ "name": "user747",
+ "first": "First 747",
+ "last": "Last 747"
+ },
+ {
+ "name": "user748",
+ "first": "First 748",
+ "last": "Last 748"
+ },
+ {
+ "name": "user749",
+ "first": "First 749",
+ "last": "Last 749"
+ },
+ {
+ "name": "user750",
+ "first": "First 750",
+ "last": "Last 750"
+ },
+ {
+ "name": "user751",
+ "first": "First 751",
+ "last": "Last 751"
+ },
+ {
+ "name": "user752",
+ "first": "First 752",
+ "last": "Last 752"
+ },
+ {
+ "name": "user753",
+ "first": "First 753",
+ "last": "Last 753"
+ },
+ {
+ "name": "user754",
+ "first": "First 754",
+ "last": "Last 754"
+ },
+ {
+ "name": "user755",
+ "first": "First 755",
+ "last": "Last 755"
+ },
+ {
+ "name": "user756",
+ "first": "First 756",
+ "last": "Last 756"
+ },
+ {
+ "name": "user757",
+ "first": "First 757",
+ "last": "Last 757"
+ },
+ {
+ "name": "user758",
+ "first": "First 758",
+ "last": "Last 758"
+ },
+ {
+ "name": "user759",
+ "first": "First 759",
+ "last": "Last 759"
+ },
+ {
+ "name": "user760",
+ "first": "First 760",
+ "last": "Last 760"
+ },
+ {
+ "name": "user761",
+ "first": "First 761",
+ "last": "Last 761"
+ },
+ {
+ "name": "user762",
+ "first": "First 762",
+ "last": "Last 762"
+ },
+ {
+ "name": "user763",
+ "first": "First 763",
+ "last": "Last 763"
+ },
+ {
+ "name": "user764",
+ "first": "First 764",
+ "last": "Last 764"
+ },
+ {
+ "name": "user765",
+ "first": "First 765",
+ "last": "Last 765"
+ },
+ {
+ "name": "user766",
+ "first": "First 766",
+ "last": "Last 766"
+ },
+ {
+ "name": "user767",
+ "first": "First 767",
+ "last": "Last 767"
+ },
+ {
+ "name": "user768",
+ "first": "First 768",
+ "last": "Last 768"
+ },
+ {
+ "name": "user769",
+ "first": "First 769",
+ "last": "Last 769"
+ },
+ {
+ "name": "user770",
+ "first": "First 770",
+ "last": "Last 770"
+ },
+ {
+ "name": "user771",
+ "first": "First 771",
+ "last": "Last 771"
+ },
+ {
+ "name": "user772",
+ "first": "First 772",
+ "last": "Last 772"
+ },
+ {
+ "name": "user773",
+ "first": "First 773",
+ "last": "Last 773"
+ },
+ {
+ "name": "user774",
+ "first": "First 774",
+ "last": "Last 774"
+ },
+ {
+ "name": "user775",
+ "first": "First 775",
+ "last": "Last 775"
+ },
+ {
+ "name": "user776",
+ "first": "First 776",
+ "last": "Last 776"
+ },
+ {
+ "name": "user777",
+ "first": "First 777",
+ "last": "Last 777"
+ },
+ {
+ "name": "user778",
+ "first": "First 778",
+ "last": "Last 778"
+ },
+ {
+ "name": "user779",
+ "first": "First 779",
+ "last": "Last 779"
+ },
+ {
+ "name": "user780",
+ "first": "First 780",
+ "last": "Last 780"
+ },
+ {
+ "name": "user781",
+ "first": "First 781",
+ "last": "Last 781"
+ },
+ {
+ "name": "user782",
+ "first": "First 782",
+ "last": "Last 782"
+ },
+ {
+ "name": "user783",
+ "first": "First 783",
+ "last": "Last 783"
+ },
+ {
+ "name": "user784",
+ "first": "First 784",
+ "last": "Last 784"
+ },
+ {
+ "name": "user785",
+ "first": "First 785",
+ "last": "Last 785"
+ },
+ {
+ "name": "user786",
+ "first": "First 786",
+ "last": "Last 786"
+ },
+ {
+ "name": "user787",
+ "first": "First 787",
+ "last": "Last 787"
+ },
+ {
+ "name": "user788",
+ "first": "First 788",
+ "last": "Last 788"
+ },
+ {
+ "name": "user789",
+ "first": "First 789",
+ "last": "Last 789"
+ },
+ {
+ "name": "user790",
+ "first": "First 790",
+ "last": "Last 790"
+ },
+ {
+ "name": "user791",
+ "first": "First 791",
+ "last": "Last 791"
+ },
+ {
+ "name": "user792",
+ "first": "First 792",
+ "last": "Last 792"
+ },
+ {
+ "name": "user793",
+ "first": "First 793",
+ "last": "Last 793"
+ },
+ {
+ "name": "user794",
+ "first": "First 794",
+ "last": "Last 794"
+ },
+ {
+ "name": "user795",
+ "first": "First 795",
+ "last": "Last 795"
+ },
+ {
+ "name": "user796",
+ "first": "First 796",
+ "last": "Last 796"
+ },
+ {
+ "name": "user797",
+ "first": "First 797",
+ "last": "Last 797"
+ },
+ {
+ "name": "user798",
+ "first": "First 798",
+ "last": "Last 798"
+ },
+ {
+ "name": "user799",
+ "first": "First 799",
+ "last": "Last 799"
+ },
+ {
+ "name": "user800",
+ "first": "First 800",
+ "last": "Last 800"
+ },
+ {
+ "name": "user801",
+ "first": "First 801",
+ "last": "Last 801"
+ },
+ {
+ "name": "user802",
+ "first": "First 802",
+ "last": "Last 802"
+ },
+ {
+ "name": "user803",
+ "first": "First 803",
+ "last": "Last 803"
+ },
+ {
+ "name": "user804",
+ "first": "First 804",
+ "last": "Last 804"
+ },
+ {
+ "name": "user805",
+ "first": "First 805",
+ "last": "Last 805"
+ },
+ {
+ "name": "user806",
+ "first": "First 806",
+ "last": "Last 806"
+ },
+ {
+ "name": "user807",
+ "first": "First 807",
+ "last": "Last 807"
+ },
+ {
+ "name": "user808",
+ "first": "First 808",
+ "last": "Last 808"
+ },
+ {
+ "name": "user809",
+ "first": "First 809",
+ "last": "Last 809"
+ },
+ {
+ "name": "user810",
+ "first": "First 810",
+ "last": "Last 810"
+ },
+ {
+ "name": "user811",
+ "first": "First 811",
+ "last": "Last 811"
+ },
+ {
+ "name": "user812",
+ "first": "First 812",
+ "last": "Last 812"
+ },
+ {
+ "name": "user813",
+ "first": "First 813",
+ "last": "Last 813"
+ },
+ {
+ "name": "user814",
+ "first": "First 814",
+ "last": "Last 814"
+ },
+ {
+ "name": "user815",
+ "first": "First 815",
+ "last": "Last 815"
+ },
+ {
+ "name": "user816",
+ "first": "First 816",
+ "last": "Last 816"
+ },
+ {
+ "name": "user817",
+ "first": "First 817",
+ "last": "Last 817"
+ },
+ {
+ "name": "user818",
+ "first": "First 818",
+ "last": "Last 818"
+ },
+ {
+ "name": "user819",
+ "first": "First 819",
+ "last": "Last 819"
+ },
+ {
+ "name": "user820",
+ "first": "First 820",
+ "last": "Last 820"
+ },
+ {
+ "name": "user821",
+ "first": "First 821",
+ "last": "Last 821"
+ },
+ {
+ "name": "user822",
+ "first": "First 822",
+ "last": "Last 822"
+ },
+ {
+ "name": "user823",
+ "first": "First 823",
+ "last": "Last 823"
+ },
+ {
+ "name": "user824",
+ "first": "First 824",
+ "last": "Last 824"
+ },
+ {
+ "name": "user825",
+ "first": "First 825",
+ "last": "Last 825"
+ },
+ {
+ "name": "user826",
+ "first": "First 826",
+ "last": "Last 826"
+ },
+ {
+ "name": "user827",
+ "first": "First 827",
+ "last": "Last 827"
+ },
+ {
+ "name": "user828",
+ "first": "First 828",
+ "last": "Last 828"
+ },
+ {
+ "name": "user829",
+ "first": "First 829",
+ "last": "Last 829"
+ },
+ {
+ "name": "user830",
+ "first": "First 830",
+ "last": "Last 830"
+ },
+ {
+ "name": "user831",
+ "first": "First 831",
+ "last": "Last 831"
+ },
+ {
+ "name": "user832",
+ "first": "First 832",
+ "last": "Last 832"
+ },
+ {
+ "name": "user833",
+ "first": "First 833",
+ "last": "Last 833"
+ },
+ {
+ "name": "user834",
+ "first": "First 834",
+ "last": "Last 834"
+ },
+ {
+ "name": "user835",
+ "first": "First 835",
+ "last": "Last 835"
+ },
+ {
+ "name": "user836",
+ "first": "First 836",
+ "last": "Last 836"
+ },
+ {
+ "name": "user837",
+ "first": "First 837",
+ "last": "Last 837"
+ },
+ {
+ "name": "user838",
+ "first": "First 838",
+ "last": "Last 838"
+ },
+ {
+ "name": "user839",
+ "first": "First 839",
+ "last": "Last 839"
+ },
+ {
+ "name": "user840",
+ "first": "First 840",
+ "last": "Last 840"
+ },
+ {
+ "name": "user841",
+ "first": "First 841",
+ "last": "Last 841"
+ },
+ {
+ "name": "user842",
+ "first": "First 842",
+ "last": "Last 842"
+ },
+ {
+ "name": "user843",
+ "first": "First 843",
+ "last": "Last 843"
+ },
+ {
+ "name": "user844",
+ "first": "First 844",
+ "last": "Last 844"
+ },
+ {
+ "name": "user845",
+ "first": "First 845",
+ "last": "Last 845"
+ },
+ {
+ "name": "user846",
+ "first": "First 846",
+ "last": "Last 846"
+ },
+ {
+ "name": "user847",
+ "first": "First 847",
+ "last": "Last 847"
+ },
+ {
+ "name": "user848",
+ "first": "First 848",
+ "last": "Last 848"
+ },
+ {
+ "name": "user849",
+ "first": "First 849",
+ "last": "Last 849"
+ },
+ {
+ "name": "user850",
+ "first": "First 850",
+ "last": "Last 850"
+ },
+ {
+ "name": "user851",
+ "first": "First 851",
+ "last": "Last 851"
+ },
+ {
+ "name": "user852",
+ "first": "First 852",
+ "last": "Last 852"
+ },
+ {
+ "name": "user853",
+ "first": "First 853",
+ "last": "Last 853"
+ },
+ {
+ "name": "user854",
+ "first": "First 854",
+ "last": "Last 854"
+ },
+ {
+ "name": "user855",
+ "first": "First 855",
+ "last": "Last 855"
+ },
+ {
+ "name": "user856",
+ "first": "First 856",
+ "last": "Last 856"
+ },
+ {
+ "name": "user857",
+ "first": "First 857",
+ "last": "Last 857"
+ },
+ {
+ "name": "user858",
+ "first": "First 858",
+ "last": "Last 858"
+ },
+ {
+ "name": "user859",
+ "first": "First 859",
+ "last": "Last 859"
+ },
+ {
+ "name": "user860",
+ "first": "First 860",
+ "last": "Last 860"
+ },
+ {
+ "name": "user861",
+ "first": "First 861",
+ "last": "Last 861"
+ },
+ {
+ "name": "user862",
+ "first": "First 862",
+ "last": "Last 862"
+ },
+ {
+ "name": "user863",
+ "first": "First 863",
+ "last": "Last 863"
+ },
+ {
+ "name": "user864",
+ "first": "First 864",
+ "last": "Last 864"
+ },
+ {
+ "name": "user865",
+ "first": "First 865",
+ "last": "Last 865"
+ },
+ {
+ "name": "user866",
+ "first": "First 866",
+ "last": "Last 866"
+ },
+ {
+ "name": "user867",
+ "first": "First 867",
+ "last": "Last 867"
+ },
+ {
+ "name": "user868",
+ "first": "First 868",
+ "last": "Last 868"
+ },
+ {
+ "name": "user869",
+ "first": "First 869",
+ "last": "Last 869"
+ },
+ {
+ "name": "user870",
+ "first": "First 870",
+ "last": "Last 870"
+ },
+ {
+ "name": "user871",
+ "first": "First 871",
+ "last": "Last 871"
+ },
+ {
+ "name": "user872",
+ "first": "First 872",
+ "last": "Last 872"
+ },
+ {
+ "name": "user873",
+ "first": "First 873",
+ "last": "Last 873"
+ },
+ {
+ "name": "user874",
+ "first": "First 874",
+ "last": "Last 874"
+ },
+ {
+ "name": "user875",
+ "first": "First 875",
+ "last": "Last 875"
+ },
+ {
+ "name": "user876",
+ "first": "First 876",
+ "last": "Last 876"
+ },
+ {
+ "name": "user877",
+ "first": "First 877",
+ "last": "Last 877"
+ },
+ {
+ "name": "user878",
+ "first": "First 878",
+ "last": "Last 878"
+ },
+ {
+ "name": "user879",
+ "first": "First 879",
+ "last": "Last 879"
+ },
+ {
+ "name": "user880",
+ "first": "First 880",
+ "last": "Last 880"
+ },
+ {
+ "name": "user881",
+ "first": "First 881",
+ "last": "Last 881"
+ },
+ {
+ "name": "user882",
+ "first": "First 882",
+ "last": "Last 882"
+ },
+ {
+ "name": "user883",
+ "first": "First 883",
+ "last": "Last 883"
+ },
+ {
+ "name": "user884",
+ "first": "First 884",
+ "last": "Last 884"
+ },
+ {
+ "name": "user885",
+ "first": "First 885",
+ "last": "Last 885"
+ },
+ {
+ "name": "user886",
+ "first": "First 886",
+ "last": "Last 886"
+ },
+ {
+ "name": "user887",
+ "first": "First 887",
+ "last": "Last 887"
+ },
+ {
+ "name": "user888",
+ "first": "First 888",
+ "last": "Last 888"
+ },
+ {
+ "name": "user889",
+ "first": "First 889",
+ "last": "Last 889"
+ },
+ {
+ "name": "user890",
+ "first": "First 890",
+ "last": "Last 890"
+ },
+ {
+ "name": "user891",
+ "first": "First 891",
+ "last": "Last 891"
+ },
+ {
+ "name": "user892",
+ "first": "First 892",
+ "last": "Last 892"
+ },
+ {
+ "name": "user893",
+ "first": "First 893",
+ "last": "Last 893"
+ },
+ {
+ "name": "user894",
+ "first": "First 894",
+ "last": "Last 894"
+ },
+ {
+ "name": "user895",
+ "first": "First 895",
+ "last": "Last 895"
+ },
+ {
+ "name": "user896",
+ "first": "First 896",
+ "last": "Last 896"
+ },
+ {
+ "name": "user897",
+ "first": "First 897",
+ "last": "Last 897"
+ },
+ {
+ "name": "user898",
+ "first": "First 898",
+ "last": "Last 898"
+ },
+ {
+ "name": "user899",
+ "first": "First 899",
+ "last": "Last 899"
+ },
+ {
+ "name": "user900",
+ "first": "First 900",
+ "last": "Last 900"
+ },
+ {
+ "name": "user901",
+ "first": "First 901",
+ "last": "Last 901"
+ },
+ {
+ "name": "user902",
+ "first": "First 902",
+ "last": "Last 902"
+ },
+ {
+ "name": "user903",
+ "first": "First 903",
+ "last": "Last 903"
+ },
+ {
+ "name": "user904",
+ "first": "First 904",
+ "last": "Last 904"
+ },
+ {
+ "name": "user905",
+ "first": "First 905",
+ "last": "Last 905"
+ },
+ {
+ "name": "user906",
+ "first": "First 906",
+ "last": "Last 906"
+ },
+ {
+ "name": "user907",
+ "first": "First 907",
+ "last": "Last 907"
+ },
+ {
+ "name": "user908",
+ "first": "First 908",
+ "last": "Last 908"
+ },
+ {
+ "name": "user909",
+ "first": "First 909",
+ "last": "Last 909"
+ },
+ {
+ "name": "user910",
+ "first": "First 910",
+ "last": "Last 910"
+ },
+ {
+ "name": "user911",
+ "first": "First 911",
+ "last": "Last 911"
+ },
+ {
+ "name": "user912",
+ "first": "First 912",
+ "last": "Last 912"
+ },
+ {
+ "name": "user913",
+ "first": "First 913",
+ "last": "Last 913"
+ },
+ {
+ "name": "user914",
+ "first": "First 914",
+ "last": "Last 914"
+ },
+ {
+ "name": "user915",
+ "first": "First 915",
+ "last": "Last 915"
+ },
+ {
+ "name": "user916",
+ "first": "First 916",
+ "last": "Last 916"
+ },
+ {
+ "name": "user917",
+ "first": "First 917",
+ "last": "Last 917"
+ },
+ {
+ "name": "user918",
+ "first": "First 918",
+ "last": "Last 918"
+ },
+ {
+ "name": "user919",
+ "first": "First 919",
+ "last": "Last 919"
+ },
+ {
+ "name": "user920",
+ "first": "First 920",
+ "last": "Last 920"
+ },
+ {
+ "name": "user921",
+ "first": "First 921",
+ "last": "Last 921"
+ },
+ {
+ "name": "user922",
+ "first": "First 922",
+ "last": "Last 922"
+ },
+ {
+ "name": "user923",
+ "first": "First 923",
+ "last": "Last 923"
+ },
+ {
+ "name": "user924",
+ "first": "First 924",
+ "last": "Last 924"
+ },
+ {
+ "name": "user925",
+ "first": "First 925",
+ "last": "Last 925"
+ },
+ {
+ "name": "user926",
+ "first": "First 926",
+ "last": "Last 926"
+ },
+ {
+ "name": "user927",
+ "first": "First 927",
+ "last": "Last 927"
+ },
+ {
+ "name": "user928",
+ "first": "First 928",
+ "last": "Last 928"
+ },
+ {
+ "name": "user929",
+ "first": "First 929",
+ "last": "Last 929"
+ },
+ {
+ "name": "user930",
+ "first": "First 930",
+ "last": "Last 930"
+ },
+ {
+ "name": "user931",
+ "first": "First 931",
+ "last": "Last 931"
+ },
+ {
+ "name": "user932",
+ "first": "First 932",
+ "last": "Last 932"
+ },
+ {
+ "name": "user933",
+ "first": "First 933",
+ "last": "Last 933"
+ },
+ {
+ "name": "user934",
+ "first": "First 934",
+ "last": "Last 934"
+ },
+ {
+ "name": "user935",
+ "first": "First 935",
+ "last": "Last 935"
+ },
+ {
+ "name": "user936",
+ "first": "First 936",
+ "last": "Last 936"
+ },
+ {
+ "name": "user937",
+ "first": "First 937",
+ "last": "Last 937"
+ },
+ {
+ "name": "user938",
+ "first": "First 938",
+ "last": "Last 938"
+ },
+ {
+ "name": "user939",
+ "first": "First 939",
+ "last": "Last 939"
+ },
+ {
+ "name": "user940",
+ "first": "First 940",
+ "last": "Last 940"
+ },
+ {
+ "name": "user941",
+ "first": "First 941",
+ "last": "Last 941"
+ },
+ {
+ "name": "user942",
+ "first": "First 942",
+ "last": "Last 942"
+ },
+ {
+ "name": "user943",
+ "first": "First 943",
+ "last": "Last 943"
+ },
+ {
+ "name": "user944",
+ "first": "First 944",
+ "last": "Last 944"
+ },
+ {
+ "name": "user945",
+ "first": "First 945",
+ "last": "Last 945"
+ },
+ {
+ "name": "user946",
+ "first": "First 946",
+ "last": "Last 946"
+ },
+ {
+ "name": "user947",
+ "first": "First 947",
+ "last": "Last 947"
+ },
+ {
+ "name": "user948",
+ "first": "First 948",
+ "last": "Last 948"
+ },
+ {
+ "name": "user949",
+ "first": "First 949",
+ "last": "Last 949"
+ },
+ {
+ "name": "user950",
+ "first": "First 950",
+ "last": "Last 950"
+ },
+ {
+ "name": "user951",
+ "first": "First 951",
+ "last": "Last 951"
+ },
+ {
+ "name": "user952",
+ "first": "First 952",
+ "last": "Last 952"
+ },
+ {
+ "name": "user953",
+ "first": "First 953",
+ "last": "Last 953"
+ },
+ {
+ "name": "user954",
+ "first": "First 954",
+ "last": "Last 954"
+ },
+ {
+ "name": "user955",
+ "first": "First 955",
+ "last": "Last 955"
+ },
+ {
+ "name": "user956",
+ "first": "First 956",
+ "last": "Last 956"
+ },
+ {
+ "name": "user957",
+ "first": "First 957",
+ "last": "Last 957"
+ },
+ {
+ "name": "user958",
+ "first": "First 958",
+ "last": "Last 958"
+ },
+ {
+ "name": "user959",
+ "first": "First 959",
+ "last": "Last 959"
+ },
+ {
+ "name": "user960",
+ "first": "First 960",
+ "last": "Last 960"
+ },
+ {
+ "name": "user961",
+ "first": "First 961",
+ "last": "Last 961"
+ },
+ {
+ "name": "user962",
+ "first": "First 962",
+ "last": "Last 962"
+ },
+ {
+ "name": "user963",
+ "first": "First 963",
+ "last": "Last 963"
+ },
+ {
+ "name": "user964",
+ "first": "First 964",
+ "last": "Last 964"
+ },
+ {
+ "name": "user965",
+ "first": "First 965",
+ "last": "Last 965"
+ },
+ {
+ "name": "user966",
+ "first": "First 966",
+ "last": "Last 966"
+ },
+ {
+ "name": "user967",
+ "first": "First 967",
+ "last": "Last 967"
+ },
+ {
+ "name": "user968",
+ "first": "First 968",
+ "last": "Last 968"
+ },
+ {
+ "name": "user969",
+ "first": "First 969",
+ "last": "Last 969"
+ },
+ {
+ "name": "user970",
+ "first": "First 970",
+ "last": "Last 970"
+ },
+ {
+ "name": "user971",
+ "first": "First 971",
+ "last": "Last 971"
+ },
+ {
+ "name": "user972",
+ "first": "First 972",
+ "last": "Last 972"
+ },
+ {
+ "name": "user973",
+ "first": "First 973",
+ "last": "Last 973"
+ },
+ {
+ "name": "user974",
+ "first": "First 974",
+ "last": "Last 974"
+ },
+ {
+ "name": "user975",
+ "first": "First 975",
+ "last": "Last 975"
+ },
+ {
+ "name": "user976",
+ "first": "First 976",
+ "last": "Last 976"
+ },
+ {
+ "name": "user977",
+ "first": "First 977",
+ "last": "Last 977"
+ },
+ {
+ "name": "user978",
+ "first": "First 978",
+ "last": "Last 978"
+ },
+ {
+ "name": "user979",
+ "first": "First 979",
+ "last": "Last 979"
+ },
+ {
+ "name": "user980",
+ "first": "First 980",
+ "last": "Last 980"
+ },
+ {
+ "name": "user981",
+ "first": "First 981",
+ "last": "Last 981"
+ },
+ {
+ "name": "user982",
+ "first": "First 982",
+ "last": "Last 982"
+ },
+ {
+ "name": "user983",
+ "first": "First 983",
+ "last": "Last 983"
+ },
+ {
+ "name": "user984",
+ "first": "First 984",
+ "last": "Last 984"
+ },
+ {
+ "name": "user985",
+ "first": "First 985",
+ "last": "Last 985"
+ },
+ {
+ "name": "user986",
+ "first": "First 986",
+ "last": "Last 986"
+ },
+ {
+ "name": "user987",
+ "first": "First 987",
+ "last": "Last 987"
+ },
+ {
+ "name": "user988",
+ "first": "First 988",
+ "last": "Last 988"
+ },
+ {
+ "name": "user989",
+ "first": "First 989",
+ "last": "Last 989"
+ },
+ {
+ "name": "user990",
+ "first": "First 990",
+ "last": "Last 990"
+ },
+ {
+ "name": "user991",
+ "first": "First 991",
+ "last": "Last 991"
+ },
+ {
+ "name": "user992",
+ "first": "First 992",
+ "last": "Last 992"
+ },
+ {
+ "name": "user993",
+ "first": "First 993",
+ "last": "Last 993"
+ },
+ {
+ "name": "user994",
+ "first": "First 994",
+ "last": "Last 994"
+ },
+ {
+ "name": "user995",
+ "first": "First 995",
+ "last": "Last 995"
+ },
+ {
+ "name": "user996",
+ "first": "First 996",
+ "last": "Last 996"
+ },
+ {
+ "name": "user997",
+ "first": "First 997",
+ "last": "Last 997"
+ },
+ {
+ "name": "user998",
+ "first": "First 998",
+ "last": "Last 998"
+ },
+ {
+ "name": "user999",
+ "first": "First 999",
+ "last": "Last 999"
+ },
+ {
+ "name": "user1000",
+ "first": "First 1000",
+ "last": "Last 1000"
+ }
+ ]
+}
diff --git a/tests/user/users_present.sh b/tests/user/users_present.sh
new file mode 100644
index 00000000..c23f8d1f
--- /dev/null
+++ b/tests/user/users_present.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+NUM=1000
+FILE="users_present.json"
+
+echo "{" > $FILE
+
+echo " \"users\": [" >> $FILE
+
+for i in $(seq 1 $NUM); do
+ echo " {" >> $FILE
+ echo " \"name\": \"user$i\"," >> $FILE
+ echo " \"first\": \"First $i\"," >> $FILE
+ echo " \"last\": \"Last $i\"" >> $FILE
+ if [ $i -lt $NUM ]; then
+ echo " }," >> $FILE
+ else
+ echo " }" >> $FILE
+ fi
+done
+
+echo " ]" >> $FILE
+
+echo "}" >> $FILE