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

When tokenType = jwt, scope restriction doesn't work. #684

Open
quicktribute opened this issue Apr 4, 2018 · 10 comments
Open

When tokenType = jwt, scope restriction doesn't work. #684

quicktribute opened this issue Apr 4, 2018 · 10 comments
Assignees

Comments

@quicktribute
Copy link

quicktribute commented Apr 4, 2018

EDIT:(For anyone who fac[ed|ing] this issue.)
(after talking to Vincenzo)

Here’s the problem: with so many ways to represent the scopes and not a standardized way to expose these, Express Gateway would be in trouble in doing so.

The problem we have is that Express Gateway can’t locate scopes in a JWT — because it’s location is unpredictable.

You have two ways to fix this:


Tried to restrict an apiEndpoint with scopes, and any logged user , with any role, could pass through to the proxy level.
After few tries, I figured this case happens only when the tokenType is "jwt".
When commenting the tokenType with it's props (issuer, audience,subject), the scopes restriction works perfectly.

Config references (bugged reference as reproduce steps):

apiEndpoint :

apiEndpoints:
  exampleApi:
    port: *gatewaySecurePort
    host: *gatewayHost
    paths:
      - "/example/*"
    scopes:
      - 'exampleAdmin'

pipeline :

example-api:
    apiEndpoints:
      - exampleApi
    policies:
      - oauth2:
        - action:
            jwt:
              <<: *jwtStrategy
      - rewrite:
        - condition:
            name: allOf
            conditions:
              - name: authenticated
              - name: pathmatch
                match: "/example/:route*"
          action:
            rewrite: "/:route"
      - proxy:
        - condition:
            name: authenticated
          action:
            serviceEndpoint: exampleServiceApi
            changeOrigin: true

systemConfig.accessTokens :

accessTokens:
  timeToExpiry: 7200000
  tokenType: "jwt"
  issuer: "example issuer"
  audience: "example audience"
  subject: "example subject"
  secretOrPrivateKey: "very_secret_thing_example"
@XVincentX XVincentX self-assigned this Apr 9, 2018
@XVincentX
Copy link
Member

As a self reminder, we have two issues here:

  1. The JWT specification does not have anything regards the scopes property. Some uses scope, some scopes. Moreover, some uses it as an array ["read","write"], some uses it as a string "read,write". It's a little bit difficult to handle all the use cases.

  2. Our oAuth2 policy is global, and this is starting to be a problem. oAuth2 policy should become local and spin up an internal server per policy instance or — anyway — do something to make it local. Express Gateway should be able to issue different JWTs with different signature parameters and so on and so forth. @altsang @kevinswiber

@kevinswiber
Copy link
Member

Because talking about possibilities with JWT is always confusing, I'm just going to take a moment to provide a refresher on different ways JWTs manifest in authentication/authorization.

There are actually 3 ways we could potentially use JWT in a gateway.

  1. JWT as a fancy API key
  2. JWT as an OAuth2 Access Token
  3. JWT for tokens in the OpenID Connect flows.

I think in use cases 1 and 3, we could potentially take JWTs issued by an Identity Provider, and in those cases, we'd need some indication of assigned scopes, likely via a custom claim.

For use case 2, I think we'd have to manage all of that internally. And if we're managing it internally, we should be able to take advantage of our scope management.

I think this issue is referring to use case 2, which should not require a custom scopes claim in the JWT. Scope management should work for JWT access tokens the same exact way it works for opaque access tokens.

@naorbe Feel free to comment if I'm missing something.

@kevinswiber
Copy link
Member

So it looks like we don't run a scope authorization check when the OAuth2 access token is a JWT.

We can do something like this in the OAuth2 use case for JWTs. This is what we're doing for opaque tokens: https://github.com/ExpressGateway/express-gateway/blob/master/lib/policies/oauth2/oauth2.js#L44-L66

Currently, we're just re-utilizing the JWT policy for the OAuth2 use case. @XVincentX, would it be as simple as running that above logic for JWTs in OAuth2 or am I missing an important aspect that would prevent it?

@alamgirqazi
Copy link
Contributor

I think I have a similar use case to this

http:
  port: 8080
admin:
  port: 9876
  hostname: localhost
apiEndpoints:
  customers:
    host: localhost
    paths: '/customers/*'
  orders:
    host: localhost
    paths: '/orders/*'
    scopes:
      - 'admin'
  users:
    host: localhost
    paths: '/users/*'
serviceEndpoints:
  customers:
    url: 'http://localhost:3000/'
  orders:
    url: 'http://localhost:3001/'
  users:
    url: 'http://localhost:3002/'
policies:
  - jwt
  - oauth2
  - proxy
  # - cors
  # - logs
  # - key-auth
  - rate-limit  
pipelines:
  orders:
      apiEndpoints:   # process all request matching "api" apiEndpoint
        - orders
      policies:
        - rate-limit:
          - action:
              max: 10 # max 10 request
              windowMs: 120000   # per 120 seconds
              rateLimitBy: "${req.hostname}"
        
        - jwt: # secure API with key auth
          - action:
              secretOrPublicKey: thisisasecretkey
              checkCredentialExistence: false
              # secretOrPublicKeyFile: ./key/pubKey.pem
        
        - proxy: # name of the policy
          - action:
              serviceEndpoint: orders # reference to serviceEndpoints Section
  customers:    
      apiEndpoints:   # process all request matching "api" apiEndpoint
        - customers
      policies:   
        - proxy: # name of the policy
          - action:
              serviceEndpoint: customers # reference to serviceEndpoints Section
  
  users:    
      apiEndpoints:   # process all request matching "api" apiEndpoint
        - users
      policies:
        - rate-limit:
          - action:
              max: 3 # request allowed in given time.
              windowMs: 6000 # given time in seconds
              rateLimitBy: "${req.hostname}"
        - proxy: # name of the policy
          - action:
              serviceEndpoint: users # reference to serviceEndpoints Section

I have set up scope, created a JWT token and added the scope in the payload but EG doesnot restricts it.

@XVincentX
Copy link
Member

Yes — you're experiencing exactly the same issue. I wrote you a workaround in the Gitter channel (that is — use this)

@naprime
Copy link

naprime commented Aug 18, 2018

@XVincentX: Thanks! As your guide, I can fix this issue by add jwtScopes policy. Please add an "actionParam" to choose JWT scope field in your jwt policy. So we will not need jwtScopes anymore.

@naprime
Copy link

naprime commented Aug 18, 2018

@kevinswiber: You said "I think this issue is referring to use case 2, which should not require a custom scopes claim in the JWT. Scope management should work for JWT access tokens the same exact way it works for opaque access tokens.". I think so but "scope" in OAuth2 token is standard and many node package is doing the same way. So maybe we have to do as @XVincentX noted :)

@XVincentX
Copy link
Member

@naprime What policy are you referring to?

@naprime
Copy link

naprime commented Aug 22, 2018

@XVincentX : I means you should add one more param to select which "scope" user defined in your JWT plugin (https://www.express-gateway.io/docs/policies/jwt/)

@KrishnaPayyavula
Copy link

KrishnaPayyavula commented Oct 17, 2019

created a JWT to

I think I have a similar use case to this

http:
  port: 8080
admin:
  port: 9876
  hostname: localhost
apiEndpoints:
  customers:
    host: localhost
    paths: '/customers/*'
  orders:
    host: localhost
    paths: '/orders/*'
    scopes:
      - 'admin'
  users:
    host: localhost
    paths: '/users/*'
serviceEndpoints:
  customers:
    url: 'http://localhost:3000/'
  orders:
    url: 'http://localhost:3001/'
  users:
    url: 'http://localhost:3002/'
policies:
  - jwt
  - oauth2
  - proxy
  # - cors
  # - logs
  # - key-auth
  - rate-limit  
pipelines:
  orders:
      apiEndpoints:   # process all request matching "api" apiEndpoint
        - orders
      policies:
        - rate-limit:
          - action:
              max: 10 # max 10 request
              windowMs: 120000   # per 120 seconds
              rateLimitBy: "${req.hostname}"
        
        - jwt: # secure API with key auth
          - action:
              secretOrPublicKey: thisisasecretkey
              checkCredentialExistence: false
              # secretOrPublicKeyFile: ./key/pubKey.pem
        
        - proxy: # name of the policy
          - action:
              serviceEndpoint: orders # reference to serviceEndpoints Section
  customers:    
      apiEndpoints:   # process all request matching "api" apiEndpoint
        - customers
      policies:   
        - proxy: # name of the policy
          - action:
              serviceEndpoint: customers # reference to serviceEndpoints Section
  
  users:    
      apiEndpoints:   # process all request matching "api" apiEndpoint
        - users
      policies:
        - rate-limit:
          - action:
              max: 3 # request allowed in given time.
              windowMs: 6000 # given time in seconds
              rateLimitBy: "${req.hostname}"
        - proxy: # name of the policy
          - action:
              serviceEndpoint: users # reference to serviceEndpoints Section

I have set up scope, created a JWT token and added the scope in the payload but EG doesnot restricts it.

Have you solved this Issue ? @alamgirqazi
I have the same problem while using jwt with scopes.
Any help would be greatly helps me .

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

6 participants