Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support fully both Oauth & JWT authenticator in access rule #257

Closed
piotrmsc opened this issue Sep 19, 2019 · 9 comments
Closed

Support fully both Oauth & JWT authenticator in access rule #257

piotrmsc opened this issue Sep 19, 2019 · 9 comments

Comments

@piotrmsc
Copy link

piotrmsc commented Sep 19, 2019

Is your feature request related to a problem? Please describe.

Currently, you can define Oauth2 & JWT authenticator together, however, Authorization: Bearer is common header scheme for those two authenticators.
If you define an access rule with 2 authenticators where Oauth2 is first and a request is made with JWT, such request will be rejected as token introspection rejects presented JWT - and vice versa.

Describe the solution you'd like
Would be really nice to allow developers create an access rule which defines where to look for token header in case of authenticator JWT & Oauth or different alternative allow to specify authorization header scheme.

Example with header selection :

[{
  "id": "some-id",
  "upstream": {
    "url": "http://my-backend-service"
  },
  "match": {
    "url": "http://my-app/some-route",
    "methods": [
      "GET"
    ]
  },
  "authenticators": [{
    "handler": "jwt",
    "config": {
      "required_scope": ["scope-a", "scope-b"],
      "target_audience": ["aud-1"],
      "trusted_issuers": ["iss-1"],
      "tokenHeader" : "x-jwt-authorization"
    }
  },
 {
    "handler": "oauth2_introspection",
    "config": {
      "required_scope": ["scope-a", "scope-b"]
    }
  }
],
  "authorizer": { "handler": "allow" },
  "mutator": { "handler": "noop" }
}]

Example with authorization header scheme selection

[{
  "id": "some-id",
  "upstream": {
    "url": "http://my-backend-service"
  },
  "match": {
    "url": "http://my-app/some-route",
    "methods": [
      "GET"
    ]
  },
  "authenticators": [{
    "handler": "jwt",
    "config": {
      "required_scope": ["scope-a", "scope-b"],
      "target_audience": ["aud-1"],
      "trusted_issuers": ["iss-1"],
      "authorizationScheme" : "jwt"
    }
  },
 {
    "handler": "oauth2_introspection",
    "config": {
      "required_scope": ["scope-a", "scope-b"]
    }
  }
],
  "authorizer": { "handler": "allow" },
  "mutator": { "handler": "noop" }
}]

Additional context

Additional considerations :

  • if access rules is defined with JWT/oauth authenticator with custom header but such header is not present in the request (even not in Authorization header) oathkeeper should reject such call

  • if access rules is defined with JWT/oauth authenticator with custom header but in the request Authorization header is present, oathkeeper should validate it as it's done now with value in the Authorization header.

  • if access rules is defined with JWT/oauth authenticator with custom authorization scheme but in the request default Bearer scheme is used, oathkeeper should validate request

  • If access rules is defined with JWT/oauth authenticator with custom authorization scheme but in the request either defined scheme nor Bearer scheme is used, oathkeeper should reject such call

If scheme override option would be accepted it should have fallback to Bearer scheme.
If header override option would be accepted it should have fallback to Authorization header

/cc @aeneasr

Edited sample schema after discussion

[{
  "id": "some-id",
  "upstream": {
    "url": "http://my-backend-service"
  },
  "match": {
    "url": "http://my-app/some-route",
    "methods": [
      "GET"
    ]
  },
  "authenticators": [{
    "handler": "jwt",
    "config": {
      "required_scope": ["scope-a", "scope-b"],
      "target_audience": ["aud-1"],
      "trusted_issuers": ["iss-1"],
      "token_from": {
       // "header": "x-foo-bar",
       // or
       // "query_parameter": "token"
       }      
    }
  },
 {
    "handler": "oauth2_introspection",
    "config": {
      "required_scope": ["scope-a", "scope-b"]
    }
  }
],
  "authorizer": { "handler": "allow" },
  "mutator": { "handler": "noop" }
}]
  

@piotrmsc piotrmsc changed the title Support both Oauth & JWT authenticator in access rule Support fully both Oauth & JWT authenticator in access rule Sep 19, 2019
@aeneasr
Copy link
Member

aeneasr commented Sep 25, 2019

I think that's quite sensible. How about extending this a bit?

{
  "config": {
    "token_from": {
       // "header_value": "x-foo-bar",
       // or
       // "authorization_header": "bearer/jwt/.." (bearer would be the default)
       // or
       // "query_parameter": "token"
    }
  }
}

I'm not happy with the naming yet but I think it would decrease the verbosity of configuration.

@piotrmsc
Copy link
Author

piotrmsc commented Sep 26, 2019

@aeneasr so basically you want to support :

  • Specifying header
  • Specifying authorization scheme
  • Specifying query param

Personally I would pick only header and query. I would drop scheme override after reading again: https://tools.ietf.org/html/rfc6750#section-2.1.

So config could look like :

{
  "config": {
    "token": {
       // "header": "x-foo-bar",
       // or
       // "query_parameter": "token"
    }
  }
}

what do you think?

@aeneasr
Copy link
Member

aeneasr commented Sep 26, 2019

Ok, makes sense. I was not super comfortable with the scheme override either. I have seen instances where Authorization: jwt <> were used but these were kind of bespoke systems without any peer reviewed document or standard to support them.

I think that config looks fine! I would probably token to from. We should also decide if the operator is a or (exclusive) or and (inclusive). I think however it should be or.

@piotrmsc
Copy link
Author

Maybe token -> token_from? because config object already has different fields and token_from would indicate settings where to look for a token in the request.

Yeah, I agree we should have OR. So users can define header OR query param. Not combined.

Additional question would be about fallback.
If user configure header override I think it's good to have fallback to (default) Authorization header. But what should happen in case of query param? Should we fallback to default header or some default query param for example token?

@aeneasr
Copy link
Member

aeneasr commented Sep 26, 2019

I think both from and token_from are fine :)

If user configure header override I think it's good to have fallback to (default) Authorization header. But what should happen in case of query param? Should we fallback to default header or some default query param for example token?

Wouldn't that break your initial use case?

@piotrmsc
Copy link
Author

well, if user will not follow his own config there is a chance it will end up with the current issue. So let's keep in first iteration no fallback mechanism for header/query ;-)

@aeneasr
Copy link
Member

aeneasr commented Sep 27, 2019

Ok, sounds good :)

@piotrmsc
Copy link
Author

piotrmsc commented Sep 30, 2019

@aeneasr after second thought I would like to propose a small change.

  • Config token_from is optional
  • There is no fallback to query parameter.
  • If header as an override is not provided, proxy will look for token in Authorization header. It's up to the user to define JWT & Oatuh2 authenticator with header "separation" but we should note that in the docs

Why this change? To avoid breaking change in the AccessRule API, token_from config will be optional so no migration is required for existing AccessRules. Plus Authorization is a default header in RFC

@aeneasr
Copy link
Member

aeneasr commented Sep 30, 2019

Agreed, SGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants