community.general icon indicating copy to clipboard operation
community.general copied to clipboard

keycloak_user: fails with `TypeError: 'NoneType' object is not subscriptable` when plus addressed email is used

Open liamjones opened this issue 5 months ago • 3 comments

Summary

I have a keycloak_user task trying to create a master realm admin account to replace the bootstrap temp admin when it first starts up.

If the username/email is a plain email address - [email protected] - it works fine.

If the username/email is a plus addressed email - [email protected] - it falls over with a stack trace and the error TypeError: 'NoneType' object is not subscriptable.

Issue Type

Bug Report

Component Name

keycloak_user

Ansible Version

$ ansible --version
ansible [core 2.18.2]
  config file = None
  configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/local/lib/python3.13/site-packages/ansible
  ansible collection location = /root/.ansible/collections:/usr/share/ansible/collections
  executable location = /usr/local/bin/ansible
  python version = 3.13.3 (main, Apr 22 2025, 00:00:00) [GCC 14.2.1 20250110 (Red Hat 14.2.1-7)] (/usr/bin/python3)
  jinja version = 3.1.5
  libyaml = True

Community.general Version

$ ansible-galaxy collection list community.general

# /root/.ansible/collections/ansible_collections
Collection        Version
----------------- -------
community.general 10.7.1

Configuration

$ ansible-config dump --only-changed
CONFIG_FILE() = None
DEFAULT_FILTER_PLUGIN_PATH(env: ANSIBLE_FILTER_PLUGINS) = ['/workdir/ansible/filter_plugins']
DIFF_ALWAYS(env: ANSIBLE_DIFF_ALWAYS) = True

GALAXY_SERVERS:

OS / Environment

macOS Sequoia 15.5 & ghcr.io/ansible/community-ansible-dev-tools:25.4.2 container

Steps to Reproduce

- name: Permanent admin user is created
  community.general.keycloak_user:
    auth_realm: master
    auth_keycloak_url: http://localhost:8080
    auth_username: bootstrap-admin
    auth_password: bootstrap-admin-password
    username: [email protected]
    email: [email protected]
    email_verified: yes
    credentials:
      - type: password
        value: admin-user-password
    enabled: yes

Expected Results

Task to complete successfully.

Actual Results

An exception occurred during task execution. To see the full traceback, use -vvv. The error was: TypeError: 'NoneType' object is not subscriptable
fatal: [app-server]: FAILED! => {"changed": false, "module_stderr": "Traceback (most recent call last):\n  File \"/home/ansible/.ansible/tmp/ansible-tmp-1750956586.270055-29625-270436618283342/AnsiballZ_keycloak_user.py\", line 107, in <module>\n    _ansiballz_main()\n  File \"/home/ansible/.ansible/tmp/ansible-tmp-1750956586.270055-29625-270436618283342/AnsiballZ_keycloak_user.py\", line 99, in _ansiballz_main\n    invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)\n  File \"/home/ansible/.ansible/tmp/ansible-tmp-1750956586.270055-29625-270436618283342/AnsiballZ_keycloak_user.py\", line 47, in invoke_module\n    runpy.run_module(mod_name='ansible_collections.community.general.plugins.modules.keycloak_user', init_globals=dict(_module_fqn='ansible_collections.community.general.plugins.modules.keycloak_user', _modlib_path=modlib_path),\n  File \"/usr/lib/python3.8/runpy.py\", line 207, in run_module\n    return _run_module_code(code, init_globals, run_name, mod_spec)\n  File \"/usr/lib/python3.8/runpy.py\", line 97, in _run_module_code\n    _run_code(code, mod_globals, init_globals,\n  File \"/usr/lib/python3.8/runpy.py\", line 87, in _run_code\n    exec(code, run_globals)\n  File \"/tmp/ansible_community.general.keycloak_user_payload_xjp3szu1/ansible_community.general.keycloak_user_payload.zip/ansible_collections/community/general/plugins/modules/keycloak_user.py\", line 550, in <module>\n  File \"/tmp/ansible_community.general.keycloak_user_payload_xjp3szu1/ansible_community.general.keycloak_user_payload.zip/ansible_collections/community/general/plugins/modules/keycloak_user.py\", line 512, in main\nTypeError: 'NoneType' object is not subscriptable\n", "module_stdout": "", "msg": "MODULE FAILURE: No start of json char found\nSee stdout/stderr for the exact error", "rc": 1}

Code of Conduct

  • [x] I agree to follow the Ansible Code of Conduct

liamjones avatar Jun 26 '25 16:06 liamjones

Files identified in the description:

If these files are incorrect, please update the component name section of the description or use the !component bot command.

click here for bot help

ansibullbot avatar Jun 26 '25 16:06 ansibullbot

cc @eikef @elfelip @mattock @ndclt @thomasbach-dev click here for bot help

ansibullbot avatar Jun 26 '25 16:06 ansibullbot

Stack trace in readable:

Traceback (most recent call last):
  File "/home/ansible/.ansible/tmp/ansible-tmp-1750956586.270055-29625-270436618283342/AnsiballZ_keycloak_user.py", line 107, in <module>
    _ansiballz_main()
  File "/home/ansible/.ansible/tmp/ansible-tmp-1750956586.270055-29625-270436618283342/AnsiballZ_keycloak_user.py", line 99, in _ansiballz_main
    invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)
  File "/home/ansible/.ansible/tmp/ansible-tmp-1750956586.270055-29625-270436618283342/AnsiballZ_keycloak_user.py", line 47, in invoke_module
    runpy.run_module(mod_name='ansible_collections.community.general.plugins.modules.keycloak_user', init_globals=dict(_module_fqn='ansible_collections.community.general.plugins.modules.keycloak_user', _modlib_path=modlib_path),
  File "/usr/lib/python3.8/runpy.py", line 207, in run_module
    return _run_module_code(code, init_globals, run_name, mod_spec)
  File "/usr/lib/python3.8/runpy.py", line 97, in _run_module_code
    _run_code(code, mod_globals, init_globals,
  File "/usr/lib/python3.8/runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "/tmp/ansible_community.general.keycloak_user_payload_xjp3szu1/ansible_community.general.keycloak_user_payload.zip/ansible_collections/community/general/plugins/modules/keycloak_user.py", line 550, in <module>
  File "/tmp/ansible_community.general.keycloak_user_payload_xjp3szu1/ansible_community.general.keycloak_user_payload.zip/ansible_collections/community/general/plugins/modules/keycloak_user.py", line 512, in main
TypeError: 'NoneType' object is not subscriptable

It seems that kc.create_user(userrep=desired_user, realm=realm) returned None instead of the user object, which caused the error two lines after it.

Looking at the code, it seems that after creation, the user information is queried by composing an URL like users_url += '?username=%s&exact=true' % username. Since username is probably the email address with +, and + in URL encoding means space, this is asking for another user (admin [email protected] instead of [email protected]), which - unsurprisingly - does not exist.

This is one more case where proper URL encoding should be used... (I hope I remember this if I see yet another PR which tries to add the cheap version for something like that... :D )

The correct version would be something like:

from ansible.module_utils.six.moves.urllib.parse import urlencode

users_url += '?' + urlencode({"username": username, "exact": "true"}

felixfontein avatar Jun 26 '25 19:06 felixfontein

Hi @liamjones, has the temporary quick-fix done the trick for you? If so, could you please submit the fix as a PR here? TIA :-)

russoz avatar Jun 30 '25 06:06 russoz

@russoz it fixed the immediate issue but I had to abandon it for now since molecule doesn't work with a git branch referenced collection in requirements.yml https://github.com/ansible/molecule/issues/4461

It's a very rough fix atm (there are other bits of plugins/module_utils/identity/keycloak/keycloak.py with the same problem). I'll see if I can raise a PR at some point but it might take a week or two before I can find time.

liamjones avatar Jun 30 '25 07:06 liamjones

Thanks for getting back on this. Whenever you find time to pour on this, it will be much appreciated. 😁

russoz avatar Jun 30 '25 08:06 russoz