Repository: sebadob/rauthy (language: rust)

Issue:
GET /users/{id} with apikey returns 401 when other requests work
Hey,

thanks for `rauthy`, loving it so far! However, I'm running into an issue when trying to `GET` user by `id` through the API. Tried as default config as possible.

## Setup

Docker `compose.yml`:
```docker
services:
  postgres:
    image: postgres:16
    ports:
      - "5432:5432"
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: rauthy

  rauthy:
    image: ghcr.io/sebadob/rauthy:0.26.2
    ports:
      - "8080:8080"
      - "9090:9090"
    environment:
      COOKIE_MODE: danger-insecure
      RUST_BACKTRACE: 1
    depends_on:
      - postgres
    volumes:
      - ./reference.cfg:/app/rauthy.cfg
```

From the [reference config](https://sebadob.github.io/rauthy/config/config.html) I changed only the following lines:
```
DATABASE_URL=postgresql://postgres:postgres@postgres:5432/rauthy
ENC_KEYS="
q6u26onRvXVG4427/M0NFQzhSSldCY01rckJNa1JYZ3g2NUFtSnNOVGdoU0E=
bVCyTsGaggVy5yqQ/UzluN29DZW41M3hTSkx6Y3NtZmRuQkR2TnJxUTYzcjQ=
"
```

Then I log in as the default admin, generate API key with all the access rights and use it in the header of requests:
`Authorization: API-Key test-key$dIYPNlgxnx3VAnGybzHZd5eQUk4vwjlzQOITucyuEDLs6HjC65YsjaUArSp3nSM1`

_______

## Request results

Running 
`GET http://localhost:8080/auth/v1/users` 
returns all users without a problem:
`[{"id":"za9UxpH7XVxqrtpEbThoqvn2","email":"admin@localhost.de","created_at":1680971457,"last_login":1731073621}]`

Running 
`GET http://localhost:8080/auth/v1/users/za9UxpH7XVxqrtpEbThoqvn2`
returns 401 Unauthorized:
```
HTTP/1.1 401 Unauthorized
content-length: 76
connection: close
strict-transport-security: max-age=31536000;includeSubDomains
content-type: application/json
content-security-policy: frame-ancestors 'none'; object-src 'none';
cache-control: no-store
www-authenticate: OAuth
x-robots-tag: noindex, nofollow
x-frame-options: SAMEORIGIN
referrer-policy: no-referrer
x-content-type-options: nosniff
date: Fri, 08 Nov 2024 14:22:18 GMT

{"timestamp":1731075738,"error":"Unauthorized","message":"No valid session"}
```

Interestingly, `GET http://localhost:8080/auth/v1/users/email/admin@localhost.de` also works.

_______

## Thoughts

I traced the issue to [this session validation call](https://github.com/sebadob/rauthy/blob/fb86b9db683c8a6be8a8b6fad2b66b00e441e129/src/api/src/users.rs#L365) that calls [`validate_session_auth`](https://github.com/sebadob/rauthy/blob/fb86b9db683c8a6be8a8b6fad2b66b00e441e129/src/models/src/entity/principal.rs#L179). This session validation is not present in other API methods like `get_user_by_email`. 

I presume the session validation is present to allow given user to call this endpoint with his own `id` as the parameter. However, I believe it should be possible to call this endpoint with an apikey without having any session? If this is not the case, I think it should be mentioned in the docs (preferably in Swagger IMO).


Discussion / hints:
Hey, thanks for your issue.

Yes this is a bug, obviously. The `validate_session_auth()` you linked should not be called at this point, only when the current session is `!api_key_or_admin` and it should be pushed down into the if clause to not throw an error in this situation.

Edit:

This additional session validation at the top is a left-over from an earlier migration.
Btw I hope the `ENC_KEYS` you posted are only used in a DEV / testing setup. ;)

Fix patch:
diff --git a/src/api/src/users.rs b/src/api/src/users.rs
index cc30d0e68..31ffe6fc1 100644
--- a/src/api/src/users.rs
+++ b/src/api/src/users.rs
@@ -362,14 +362,14 @@ pub async fn get_user_by_id(
     path: web::Path<String>,
     principal: ReqPrincipal,
 ) -> Result<HttpResponse, ErrorResponse> {
-    principal.validate_session_auth()?;
-
     let id = path.into_inner();
+
     // principal must either be an admin or have the same user id
     let api_key_or_admin = principal
         .validate_api_key_or_admin_session(AccessGroup::Users, AccessRights::Read)
         .is_ok();
     if !api_key_or_admin {
+        principal.validate_session_auth()?;
         principal.is_user(&id)?;
     }
 


Test patch: