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

Increase the claims information for the external proxy JWT #1414

Open
jluterek opened this issue Mar 23, 2020 · 8 comments
Open

Increase the claims information for the external proxy JWT #1414

jluterek opened this issue Mar 23, 2020 · 8 comments

Comments

@jluterek
Copy link

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

I am building an external service that will be leveraged by a Custom Application. The service will be called following the procedure outlined in https://docs.commercetools.com/custom-applications/main-concepts/proxy-to-external-api

There is no way to secure the external API and limit access to the correct users. The only option is to validate that the user has a Merchant Center login. Since you can sign-up for a free trial at any time (providing a Merchant Center login), the API is open to the public.

There should be a process to lock an API down to a set of specific users. This could be through project, organization, permissions, or group.

Describe the solution you'd like

I'd like to see the organization, team, project, and user-name passed through the JWT claims. The service could then check this data when validating the bearer token.

Describe alternatives you've considered

I have considered passing this data in each call, but saw multiple problems:

  1. This creates extra work for the calling application.
  2. If you pass it as plain text then it can be easily spoofed.
  3. If you encrypt the data, then the custom application must have the encryption key. Being an SPA, that key could be retrieved from the browser.

I also wondered if the bearer token could be used to call another MC API that would retrieve this data, but there is already a lot of traffic validating the token and another call would add complexity and latency.

Additional context

@tdeekens
Copy link
Contributor

Thanks for the issue. This sounds reasonable. It will have to be prioritised and planned. While we reach out to product could you state what fields on the JWT you would recommend that information to be passed on if you have preferred ones already?

@jluterek
Copy link
Author

My initial thoughts were organization, team, project, and user. Giving this more thought, I don't believe the organization is needed. Since users are often in multiple teams I'm not sure how difficult it will be to identify their current team for accessing the project.

In order of usefulness:

  1. Project Key
  2. UserID
  3. TeamID

@tdeekens
Copy link
Contributor

Okay thanks. Furthermore, do you already have an idea how (of which claim) of the JWT you would see those fields to be defined?

@emmenko
Copy link
Member

emmenko commented Mar 24, 2020

I feel like we are focusing too much on the implementation details here.

I would like first to understand how the external service is supposed to work, meaning for example:

  • does it need to call the CTP API?
  • does it need "higher" level information like, projects and orgs of the user? If so, why?
  • does it not call any of the CTP APIs?
  • does it use any sort of authorization? Is it based on "custom permissions" or does it rely on the CTP permissions?

Based on those information, we can have a better understanding of what is actually needed from the external service, and how we can make that happen.

Thanks

@jluterek
Copy link
Author

I can't discuss client specifics in this open forum, so I would be happy to discuss in a call, slack, or confluence. I will try to answer the questions in a generic way here.

does it need to call the CTP API?

Yes - For one implementation the external service is calling CTP. The service has it's own key/secret. This is to get around a lack of permissions in the Merchant Center regarding shopping lists. The requirements are that any user from their organization in the team Administrators or Technology can have access.

No - Another project will be concerned with calling external services allowing a business user to make very basic configuration changes. Going through a custom application allows for a single place for a business user to login and manage content. In this case, there is a dev and prod project within CT and a dev/prod configuration in the external services. Users with access to the dev project in CT will have access to the dev external API. Users with access to the prod project in CT will have access to the prod external API.

does it need "higher" level information like, projects and orgs of the user? If so, why?

Many companies have multiple projects, often a development and production project. Passing the project key allows the external service to verify this information before making production level changes.

The project key can also be used to determine if the user has access to call this service. For example, the external API may allow anyone who has access to the production project to read from the service. It also prevents a user from creating their own MC account and calling that external service as it will be called from a different project. While this can be done at the user level that creates an additional burden as users are added and removed in the Merchant Center the External API would need to be maintained.

The current organization is not needed, but an indication of that user's permissions within the organization. Since the Merchant Center groups users into Teams in order to allocate permission levels this is often how companies manage access. Providing Team information would allow for proper access restrictions on the external API.

does it not call any of the CTP APIs?

See above.

does it use any sort of authorization? Is it based on "custom permissions" or does it rely on the CTP permissions?

Yes. The currently documented approach allows for locking down an external API to ANY Merchant Center user. The goal is to allow for a more granular approach to add additional security to the external API.

The most granular is user-specific. It is also important to pass userid for any logging needed.

The MC allows users to be grouped for permission purposes, it would be useful to leverage this same grouping when evaluating permissions. An example would be that Administrators and Shop Owners could access the API, but Customer Service can not. This would mean passing the current team (the one allowing them to access the MC Custom Application), not the full list of teams for the user.

While having the Team would be great (it fits how companies consider MC permissions), it may be more difficult on the technical side. A simpler approach may be to pass the CT scopes for that user in the current project. Then some type of mapping can be done (Admins and Shop Owners have edit order permissions so look for that scope). This is not how companies have defined their requirements to me, but I could see it as a workaround if others deem it a better approach.

It's important that the data passed would be specific to that call not for the user. For example if a user belongs to multiple organizations and teams:

UserID: 12345
Organizations: [abc, def, ghi]
Teams: [a1, d2, g3]
Projects: [abc1, abc2, def1, def2, ghi1]

This user calls an external API from a custom application registered in project abc1, the only data that external API would have access to is around that call:

UserID: 12345
Team: a1
Project: abc1

Providing the full list of teams would expose too much information.

@emmenko
Copy link
Member

emmenko commented Mar 24, 2020

Thanks a lot for the extended feedback. This is already a good start!

We will discuss this internally and get back to you if we have more questions.


A couple of follow up questions first:

The service has it's own key/secret.

I suppose what you might need from the MC is to give you the list of scopes that you would need to get an access token from CTP. The MC could perform some initial checks (about the user + project) and extract the necessary scopes from the user's permissions.

Alternatively, you can simply ask the MC to give you a valid access token for this user + project.

Those are just a couple of ideas first, just to understand if that would be enough for you.
For an external service to access orgs and teams information might not be what you really need we are also not sure we want to expose this information.

@tdeekens
Copy link
Contributor

suppose what you might need from the MC is to give you the list of scopes

I understood that differently. The permissions might be enough. The service could then use those. If the scopes would then be needed the service could talk to another GraphQL query returning a set of scopes given a set of permissions.

@jluterek
Copy link
Author

I suppose what you might need from the MC is to give you the list of scopes that you would need to get an access token from CTP. The MC could perform some initial checks (about the user + project) and extract the necessary scopes from the user's permissions.

Alternatively, you can simply ask the MC to give you a valid access token for this user + project.

Those are just a couple of ideas first, just to understand if that would be enough for you.
For an external service to access orgs and teams information might not be what you really need we are also not sure we want to expose this information.

Having the MC give a valid access token would not help at all. Unless it can be used to query additional information about the user, but then why not pass the info first instead of needing a follow-up call.

For the first scenario where this external API accesses CTP resources. We can not use an access token for the user+project. That access token is scoped only for resources managed in the Merchant Center. So there is no way to scope that token for endpoints like Shopping Lists or Reviews. I'm hoping that eventually, this scenario will go away as MC permissions evolve, but currently, an external API with its own key/secret is a workaround.

For the second scenario of accessing another service, there is no need for a CTP token. Here we need to build rules around WHO can access that service. That is where a UserID, or TeamID can be leveraged, in order to build rules. Permission rules I've received follow the format:

  1. Anyone with access to the CT Production Project can access this service.
  2. Only Administrators can access this service.
  3. Only Administrators and Shop Owners can access this service.

Extracting the user scopes and passing that along with the userid could work depending on Team structure.

  1. Anyone with access to the CT Production Project can access this service.
  2. Only Administrators can access this service. Only users with manage project can access this service.
  3. Only Administrators and Shop Owners can access this service. Only users with manage orders can access this service.

The UserID would be used for logging changes.

@emmenko emmenko added ❓ Type: Question Further information is requested 📞 Type: Customer request labels Mar 24, 2020
@emmenko emmenko added this to Needs triage in SHIELD Board - Support Oct 8, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
No open projects
Development

No branches or pull requests

3 participants