ory / oathkeeper

A cloud native Identity & Access Proxy / API (IAP) and Access Control Decision API that authenticates, authorizes, and mutates incoming HTTP(s) requests. Inspired by the BeyondCorp / Zero Trust white paper. Written in Go.

Home Page:https://www.ory.sh/?utm_source=github&utm_medium=banner&utm_campaign=hydra

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Unauthenticated requests with any cookie (but no session cookie) receive a 401 even with anonymous authenticator

joaojramia opened this issue · comments

Preflight checklist

Describe the bug

We have set our Oauthkeeper rules for our endpoint to have the following authenticators:

authenticators:
  - handler: cookie_session
  - handler: bearer_token
  - handler: anonymous
authorizer:
    handler: allow

Whenever we make an unauthenticated request (without a session cookie), however containing ANY other cookie (such as a simple test=helloWorld) it returns a 401 and ignores our anonymous rule. If we remove all cookies and perform the same request, it works as intended and is handled as an anonymous request.

Reproducing the bug

Steps to reproduce this behavior:

  1. Add both the cookie_session and the anonymous authenticators in the rules configuration (as seen on the "Describe the bug" session above).
  2. Run the application
  3. Make a request without any cookies to the endpoint configured in step number 1. I should work as intended and fallback to the anonymous authenticator.
  4. Make the same request, however add a cookie to it beforehand (if from the browser, simply input document.cookie = "myCookie=myTestCookie";). It will lead to a 401, as if it ignores the anonymous authenticator.

Relevant log output

Error logs from Oathkeeper when making a request with **any cookie**:


time=2022-09-19T12:49:02Z level=info msg=started handling request http_request=map[headers:map[accept:*/* accept-encoding:gzip, deflate, br accept-language:de cookie:myCookie=myTestC
ookie origin:http://localhost:3000 referer:http://localhost:3000/ user-agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 S
afari/537.36] host:localhost:4455 method:POST path:/graphql query:<nil> remote:172.17.0.1:55952 scheme:http]

time=2022-09-19T12:49:03Z level=info msg=Access credentials are invalid audience=application service_name=ORY Oathkeeper service_version=v0.39.4

time=2022-09-19T12:49:03Z level=warning msg=Access request denied audience=application error=map[debug: message:Access credentials are invalid reason: status:Unauthorized status_code
:401] granted=false http_host=localhost:4455 http_method=POST http_url=http://localhost:4455/graphql http_user_agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.3
6 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36 service_name=ORY Oathkeeper service_version=v0.39.4

time=2022-09-19T12:49:03Z level=error msg=An error occurred while handling a request code=401 debug= details=map[] error=Access credentials are invalid reason= request-id= status=401
 writer=JSON

time=2022-09-19T12:49:03Z level=info msg=completed handling request http_request=map[headers:map[accept:*/* accept-encoding:gzip, deflate, br accept-language:de cookie:myCookie=myTes
tCookie origin:http://localhost:3000 referer:http://localhost:3000/ user-agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0
 Safari/537.36] host:localhost:4455 method:POST path:/graphql query:<nil> remote:172.17.0.1:55952 scheme:http] http_response=map[status:401 text_status:Unauthorized took:1.093923709s
]


### Relevant configuration

```yml
- id: our-id
  version: v0.39.4
  upstream:
    url: http://localhost:4000 # always true, as this GraphQL mesh is run within this Docker container
  match:
    url: https://<.*>.our-url.com/<.*>
    methods:
      - GET
      - HEAD
      - POST
      - PUT
      - DELETE
      - OPTIONS
      - CONNECT
      - TRACE
      - PATCH
  authenticators:
    - handler: cookie_session
    - handler: bearer_token
    - handler: anonymous
  authorizer:
    handler: allow
  mutators:
    - handler: header

Version

0.39.4

On which operating system are you observing this issue?

Ory Cloud

In which environment are you deploying?

Ory Cloud

Additional Context

We have a single endpoint, as we are using GraphQL, and our goal using multiple authenticators is to get user information whenever they are authenticated, but still allow anonymous requests when the user is not authenticated.

commented

I have a similar issue, maybe it's just a lack of documentation, but I was assuming that if one authenticator is successful, the request is let through, but the opposite seems the case.

Unfortunately we need to combine the authenticators, because we have a single GraphQL endpoint and we need to get the user from the cookie_session and still allow anonymous requests as well.

From the documentation, this should be possible:
"You can define more than one authenticator in the Access Rule. The first authenticator that's able to handle the credentials will be consulted and other authenticators will be ignored".

Without this, we can't get any unathenticated requests to our endpoint, which blocks us.

What's interesting is that it works just fine if there are no cookies present, however it fails when we have any cookie, like mentioned in the bug report.

Hi everyone, any updates here? This is a blocker for us, happy to join a call if necessary!

iirc you can set the cookie name in the config, which ahould then ignore all other cookies!

commented

@aeneasr I think it's not that... I think it's about multiple authenticators on a route, expecting the least needy to succeed. As an example, if I have cookie_session and anonymous my backend will never receive an anonymous request if an expired cookie is in the request.

So right now now cookie_session (or bearer_token) supersedes anonymous always, even though my app can handle the "anonymous" part.


As an example, our client always includes a token in a request if there's a token stored locally. The client doesn't know if the token expired/timed out.

When the token timed out, I can't log the user back in as the token is part of the requests and will be validated by Ory Cloud, and it'll say 401. So it seems we have to add logic to the code to "omit" the token in some cases. E.g. to keep it simple, we always allow login and never include the token in these requests.

Or we have to respond based on "error" (e.g. 401 -> drop token, re-do request).

I expected that adding bearer_token and anonymous as authenticators to a route would allow us to handle this more gracefully. As in, token is still invalid, but the request would be forwarded to my backend.

Setting the cookie name in the only array in config solved it for us. Thank you for the info @aeneasr.

Just FYI our confusion here came from making requests without any cookies and it working as expected (passed to the next authenticator).

commented

Setting the cookie name in the only array in config solved it for us. Thank you for the info @aeneasr.

Just FYI our confusion here came from making requests without any cookies and it working as expected (passed to the next authenticator).

Mind sharing what exactly you did?

We have in our config the following authenticators:

authenticators:
  anonymous:
    enabled: true
    config:
      subject: anonymous # =default
  cookie_session:
    enabled: true
    config:
      check_session_url: https://auth.{our-domain}.com/sessions/whoami
      preserve_path: true
      extra_from: '@this'
      subject_from: 'identity.id'
      additional_headers:
        accept-encoding: identity
      only:
        - ory_session_mystifying{our-ory-session-cookie}

Basically if we don't use the only configuration with the name of the cookie we use in authenticated requests, it would fail with any other unrelated cookie. Once we added the only configuration, it now ignores all other cookies we pass in the requests, and if there is no ory_session... cookie, it just goes to the next authenticator we configured (in our case it is anonymous).

Are you having the same problem, that with a random cookie your cookie_session authenticator fails, but with no cookies it ignores that authenticator and goes to the next?