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

initial implemention of cors #11

Closed
wants to merge 17 commits into from
Closed

initial implemention of cors #11

wants to merge 17 commits into from

Conversation

bloodbare
Copy link
Member

Work in progress cors

@landscape-bot
Copy link

Code Health
Repository health decreased by 0.51% when pulling 6a76f60 on cors into 7ba0817 on master.

@landscape-bot
Copy link

Code Health
Repository health increased by 0.09% when pulling d30258a on cors into 7ba0817 on master.

@tisto tisto added this to the 1.0a2 milestone Oct 15, 2015
@tisto
Copy link
Member

tisto commented Nov 8, 2015

@bloodbare any news on that? we need tests and docs before we can merge...

@bloodbare
Copy link
Member Author

Its been rebased, I merged our code on this branch so we have cors and permission overwriting.

@tisto @lukasgraf can you review + merge ?

@tisto
Copy link
Member

tisto commented Jan 26, 2016

Crap. After I merged #38, we need to rebase this pr.

@bloodbare would you mind rebasing again?

@buchi you had some architectural doubts regarding CORS support in plone.rest, right? Could you repeat those or point me our discussion.

@bloodbare
Copy link
Member Author

Uff I've been trying to merge but the change its really big, sorry to miss #38 but I have doubts about it.

@buchi
Copy link
Member

buchi commented Jan 26, 2016

@tisto @bloodbare regarding my architectural doubts, my point is that configuring CORS in ZCML is not flexible enough. In general you need to configure CORS headers per website and not per Python package. E.g. plone.restapi cannot configure any CORS headers because it doesn't know which origins it should allow. Somebody using plone.restapi and in need of CORS support would have to override the ZCML service definitions of plone.restapi.
Therefore I would propose to remove CORS configuration from the service directive in ZCML and instead configure it in the registry. Also an additional ZCML directive would be an option.
It should be possible to define CORS headers per website without redefining services.

@bloodbare
Copy link
Member Author

Hey @buchi, I see your points, in defense of my implementation I would say:

  • I changed the default cors configuration for each service with '*' so by default cors is enabled and open without adding any cors configuration, you need to define when you want to be restrictive about headers, origin, ...
  • The design is based on github.com/mozilla/cornice as its beeing used really abroad for pyramid developers and makes transition and documentation easy from the point of view of a rest service
  • In my opinion the problem is that plone.restapi should have a way to define a cors configuration for all the services that it defines, maybe splitted by HTTP verb. I would define on plone.restapi a registry entry where you have this information and use a custom ZCML meta directive that gets that registry configuration for specific verb/all the site.

I have the use case of needing different cors for different services, so I would not touch plone.rest. In my opinion plone.rest should be all code that is no plone related, agnostic about plone.restapi and sites.

@@ -13,6 +13,14 @@ def mark_as_api_request(event):
"""Mark a request with Accept 'application/json' with the IAPIRequest
interface.
"""
# In cors calls there is accept header so we need to force

if event.request.get('REQUEST_METHOD') == 'OPTIONS':
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Handling all OPTIONS requests as IAPIRequest is a bad idea. It will break WebDAV support. Also HAProxy is doing backend healthchecks with OPTIONS requests. I would propose checking for the "Origin" HTTP header.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, both together is great. Pushed.

@buchi
Copy link
Member

buchi commented Jan 27, 2016

After our discussion and after thinking again about CORS support I would propose an additional directive for configuring CORS instead of having it in the service directive. Without thinking about implementation but from a user's point of view the directive could look like this:

<plone:serviceCORS
  accept="application/json"
  methods="GET POST OPTIONS"
  origin="http://www.foo.bar http://spam.and.eggs"
  headers="X-Custom-Header"
  max_age="3600"
  />

The association between a service and a CORS configuration would be made through the accept and methods attributes. This would also mean that a single CORS configuration can be associated with multiple services, which makes sense.

@bloodbare Does this fit your use-case?

@tisto @lukasgraf @jone any thoughts?

@lukasgraf
Copy link
Member

@buchi I like the idea of a separate directive for configuring CORS a lot.

I agree with your earlier that more flexibility is needed - I think it's unlikely that plone.rest can anticipate what sort of CORS configuration the user is going to require, more often than not this will need to be configured on per-deployment basis I think.

A dedicated ZCML directive is nice because it avoids persisting configuration in the database.

I'm not certain yet what exactly the CORS spec says regarding combinations of methods and origins - would it in theory be possible to allow a different set of origins for POST than for PUT? I'm assuming yes. If so, is this something we even want to support in a first implementation?

As for the headers attribute: I'm assuming this could be used to e.g. return something like Access-Control-Allow-Credentials in the response to the preflight request? Or does this refer to the Access-Control-Allow-Headers response header?

@buchi
Copy link
Member

buchi commented Jan 28, 2016

After thinking again I came to the following conclusions:

  • It doesn't make sense to associate CORS policies with services because we can not control the Accept header of a CORS preflight request. It's set by the browser and it's Accept: */* in general. This also means if we have e.g. two different GET services, one for application/json and one for text/xml, it's not possible to have different CORS policies for these.
  • In theory simple CORS requests could have a CORS policy specific to an Accept header, but that would be inconsistent to CORS preflight requests, we don't want to do that.
  • It's possible to define different CORS policies per content type and browser layer. I'm not sure if that's needed, but it shouldn't be hard to implement, so let's do it.

The directive for a CORS policy could then look like this:

<plone:corsPolicy
  for="plone.dexterity.interfaces.IDexterityContent"
  layer="IMyBrowserlayer"
  methods="GET POST OPTIONS"
  origin="http://www.foo.bar http://spam.and.eggs"
  headers="X-Custom-Header"
  max_age="3600"
  />

@bloodbare
Copy link
Member Author

I'll not try to merge the master onto cors, I've been trying for some time and its so different aproach. I've implemented content negotiation and I'll push with the working cors.

…n and this implementation has the problem of defining content negotiation for each method only, we will need to improve to link the content negotiation to a specific service
@tisto
Copy link
Member

tisto commented Feb 7, 2016

As discussed with @bloodbare we will close this branch.

@tisto tisto closed this Feb 7, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants