Repository: ckan/ckan

Issue:
There is no way to determine the user ID when connecting through the API 
**CKAN version**
2.8

**Describe the bug**
It is not possible to determine a users ID when connecting through the API. In my opinion, this should be the default behavior of `user_show`, but the documentation states that *either the `id` or the `user_obj` parameter must be given*. I think it would be user-convenient to change this default behavior.

**Steps to reproduce**
Connect via API using an API key and call `user_show` without arguments.

**Expected behavior**
The information about the currently logged-in user is shown.

**Actual behavior**
```json
{"help": "https://dmoain.tld/api/3/action/help_show?name=user_show", "success": false, "error": {"message": "Not found", "__type": "Not Found Error"}}
```


Discussion:
Note: A workaround is to iterate over `user_list` and check whether the API key matches the `apikey` value (which is only set if authorized).
Instead of changing `user_show` let's add a new action `id_for_current_user_show` or similar that returns just the user id when someone is logged in. IIUC this should be harder to abuse with XSS attacks because it requires another round-trip to get actual user details (security experts please weigh in if you know better)
@shubham-mahajan @wardi just pinging to see if PR #5504 is still WIP.
@jqnatividad From my end PR is done, let's wait @wardi to review.
Any updates on this one? The workaround I mentioned before does not anymore work with API tokens. A new workaround is to check whether "email" is set for a user in the user list.
@paulmueller It is agreed in (https://github.com/ckan/ckan/pull/5504#issuecomment-760974628) that we will not be using a separate method but will create a flag in the request for that.

I will create a PR soon for that 

Resolving patch:
diff --git a/ckan/logic/action/get.py b/ckan/logic/action/get.py
--- a/ckan/logic/action/get.py
+++ b/ckan/logic/action/get.py
@@ -1354,12 +1354,10 @@ def tag_show(context, data_dict):
 def user_show(context, data_dict):
     '''Return a user account.
 
-    Either the ``id`` or the ``user_obj`` parameter must be given.
+    Either the ``id`` should be passed or the user should be logged in.
 
     :param id: the id or name of the user (optional)
     :type id: string
-    :param user_obj: the user dictionary of the user (optional)
-    :type user_obj: user dictionary
     :param include_datasets: Include a list of datasets the user has created.
         If it is the same user or a sysadmin requesting, it includes datasets
         that are draft or private.
@@ -1386,13 +1384,13 @@ def user_show(context, data_dict):
     '''
     model = context['model']
 
+    if 'user' in context and 'id' not in data_dict:
+        data_dict['id'] = context.get('user')
+
     id = data_dict.get('id', None)
-    provided_user = data_dict.get('user_obj', None)
     if id:
         user_obj = model.User.get(id)
         context['user_obj'] = user_obj
-    elif provided_user:
-        context['user_obj'] = user_obj = provided_user
     else:
         raise NotFound
 


Test patch:
diff --git a/ckan/tests/logic/action/test_get.py b/ckan/tests/logic/action/test_get.py
--- a/ckan/tests/logic/action/test_get.py
+++ b/ckan/tests/logic/action/test_get.py
@@ -1207,6 +1207,20 @@ def test_user_show_include_datasets_includes_draft_sysadmin(self):
         assert dataset_deleted["name"] not in datasets_got
         assert got_user["number_created_packages"] == 3
 
+    def test_user_show_for_myself_without_passing_id(self):
+
+        user = factories.User()
+
+        got_user = helpers.call_action(
+            "user_show", context={"user": user["name"]}
+        )
+
+        assert got_user["name"] == user["name"]
+        assert got_user["email"] == user["email"]
+        assert got_user["apikey"] == user["apikey"]
+        assert "password" not in got_user
+        assert "reset_key" not in got_user
+
 
 @pytest.mark.usefixtures("clean_db", "clean_index", "with_request_context")
 class TestCurrentPackageList(object):