Repository: ckan/ckan

Issue:
Overwriting package_show auth function raises dataset not found
**CKAN version**
2.9.3

**Describe the bug**
Overwriting the package_show auth function in an extension produces dataset not found error for anonymous users when they attempt to access a package's webpage. This occurs both with code to limit access to remove access restrictions. Other auth overwrites seem to work as expected.

If the user is logged in, access is granted.

**Steps to reproduce**

1. Create an extension with a function that overwrites the package_show function with a custom one (such as the one included in the code below).
2. in the extension, overwrite the `get_auth_functions()` as below

```
# outside plugin class
def package_show(context, data_dict):

    return {'success': True}

# Inside the plugin class
def get_auth_functions(self):

   return {
		   "package_show": package_show
		   }
```

3. install extension
4. make sure you are logged out 
5. attempt to open a dataset's webpage

**Expected behavior**
Users should be able to access package pages regardless of permissions. Alternatively, if access is restricted, the package_show function should return custom error message or redirect.

**Additional details**

ERROR [ckan.config.middleware.flask_app] 404 Not Found: Dataset not found
Traceback (most recent call last):
  File "/usr/lib/ckan/venv/local/lib/python2.7/site-packages/flask/app.py", line 1949, in full_dispatch_request
    rv = self.dispatch_request()
  File "/usr/lib/ckan/venv/local/lib/python2.7/site-packages/flask/app.py", line 1935, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/usr/lib/ckan/venv/src/ckan/ckan/views/dataset.py", line 438, in read
    return base.abort(404, _(u'Dataset not found'))
  File "/usr/lib/ckan/venv/src/ckan/ckan/lib/base.py", line 66, in abort
    flask_abort(status_code, detail)
  File "/usr/lib/ckan/venv/local/lib/python2.7/site-packages/werkzeug/exceptions.py", line 774, in abort
    return _aborter(status, *args, **kwargs)
  File "/usr/lib/ckan/venv/local/lib/python2.7/site-packages/werkzeug/exceptions.py", line 755, in __call__
    raise self.mapping[code](*args, **kwargs)



Discussion:
This happens because, by default all auth function in `ckan/logic/auth/get` has an attribute `auth_allow_anonymous_access`. 
https://github.com/ckan/ckan/blob/2e63e7fbaf7208f122e8c90a419f7c71485423b9/ckan/authz.py#L84-L95

If you track down your `auth_function` you will see it will fail here: 
https://github.com/ckan/ckan/blob/2e63e7fbaf7208f122e8c90a419f7c71485423b9/ckan/authz.py#L233
to avoid this you can use decorator on your auth_func: 

```
import ckan.plugins as p 

@p.toolkit.auth_allow_anonymous_access
def package_show()
```
If you would call the api directly, it would so the reason for failure which in this case is that it requires authenticated user. The UI shows 404 Not found for both non-existing datasets and those where user does not have permission due to security reasons.
Thank you for clarifying about the decorator and for the explanation about why it occurs. Using the decorator prevents the error when overwriting the function to allow access to packages.

Is there anyway to customize the error message thrown when access is not allowed for security reasons? There are some cases where I would like to have custom code to restrict access to packages; however, "dataset not found" might lead some end users to think that there's an error with the site's ability to serve the package instead of realizing that they need to log in (or have elevated permissions) to view it.

Take this as an example (in my actual implementation there would be more if statements but for replication purposes I'm keeping it simple)

```
# I tried putting the p.toolkit.auth_disallow_anonymous_access decorator here, to no effect. Would I need to allow anonymous
# access with a decorator first and then later restrict it?
def package_show(context, data_dict):
    if context.get("auth_user_obj") is not None:
        return {"success": True}
    return {"success": False, "message": "You must be signed in to view this page"}
```
> s there anyway to customize the error message thrown when access is not allowed for security reasons?

You can change the core code in your project.

Instead of this: 
https://github.com/ckan/ckan/blob/2e63e7fbaf7208f122e8c90a419f7c71485423b9/ckan/views/dataset.py#L447-L451

you can change to this:
![image](https://user-images.githubusercontent.com/72216462/162228518-8f0134a7-c73e-48b6-b3d6-50b93da50574.png)


and you would get the proper message
<img width="493" alt="image" src="https://user-images.githubusercontent.com/72216462/162228643-2bd87787-53e4-4b01-8bc5-b4d224291707.png">

Currently it's not possible to customize the error messages except by changing the localizations. One improvement for this could be that instead of "Dataset not found" the error message would "Dataset not found or you've no permission to view it"
Thank you for the help, the provided code addresses my immediate need. Additionally, something like the error message @Zharktas wrote might have preempted the user feedback that preceded my attempt to change the error message.
@jannettim @Zharktas , I am interested to work on this issue.

Resolving patch:
diff --git a/ckan/views/dataset.py b/ckan/views/dataset.py
--- a/ckan/views/dataset.py
+++ b/ckan/views/dataset.py
@@ -446,7 +446,10 @@ def read(package_type: str, id: str) -> Union[Response, str]:
         pkg_dict = get_action(u'package_show')(context, data_dict)
         pkg = context[u'package']
     except (NotFound, NotAuthorized):
-        return base.abort(404, _(u'Dataset not found'))
+        return base.abort(
+            404,
+            _(u'Dataset not found or you have no permission to view it')
+        )
 
     g.pkg_dict = pkg_dict
     g.pkg = pkg


Test patch: