fcrepo4-labs / fcrepo-api-x

Fedora API Extension Framework
Apache License 2.0
10 stars 11 forks source link

OPTIONS request against service to load extension can require credentials #121

Closed dannylamb closed 7 years ago

dannylamb commented 7 years ago

Stems from https://github.com/Islandora-CLAW/CLAW/issues/612#issuecomment-306817641

When the Loader Service is making an OPTIONS request against a service to load an extension, it does not provide credentials. This causes the loader service to fail when the attempting to load a service that requires authentication for OPTIONS requests.

ajs6f commented 7 years ago

Yes, I think we are talking about a different set of credentials from those used against a registry inside a repo. It happens that for CLAW, for now, they are the same, but that might not be the case.

birkland commented 7 years ago

OK, let's think through the security considerations here.

The loader itself is an extension, so it can be considered to be an actor distinct from API-X whose role is to provide a convenient mechanism for updating API-X's registries (i.e. you tell it where your extension lives, and it populates the API-X registries). The workflow is:

So the relevant security questions are:

  1. Is the agent who issued the POST authorized to add/update extensions?
    • Right now, the loader extension has no built-in security and trusts all requests. The only way to secure the loader service right now is via the network, e.g route and trust requests based on network origin (trusted subnet, etc).
  2. Is the Loader extension authorized to receive an OPTIONS response from the provided service URI?
    • Right now, the service instance would have to trust OPTIONS requests from API-X. This is the motivation for this particular issue,
  3. Is the Loader extension authorized to update the registries?
    • It is presently given the credentials (via configuration or provided HttpClient) to update the various registries via API-X's config.

Does that sound about right so far?

ajs6f commented 7 years ago

Sounds pretty on-target to me. Of the three points, 1 seems to me to be a separate ticket. 2 is indeed the one we are talking about right now. And 3 was, as you implied, the purpose of the recent work to break out an injectable client.

Possible problem: every given service just might require different authN!

dannylamb commented 7 years ago

@ajs6f We don't have that use case right now, but it's frightening possibility. Let's not go there unless we absolutely have to :pray:

ajs6f commented 7 years ago

Good point, @dannylamb . Let's only make our lives a little bit harder than necessary, not a lot. :)

dannylamb commented 7 years ago

For this ticket, it looks like the jetty component can be configured with a custom http client. The documentation makes it sound like a bad idea, though. It might still be worth trying.

birkland commented 7 years ago

OK. I'm thinking that we may be OK just injecting the same HttpClient as we did for solving (3). Here's why:

dannylamb commented 7 years ago

@birkland That would work for CLAW because the services and Fedora use the same authentication methods.

birkland commented 7 years ago

@dannylamb We may want to refactor to use http4 instead of adding httpclient to Jetty. We've found that the way Camel jetty component wraps and invokes the jetty httpclient library really sucks.

ajs6f commented 7 years ago

http4 is my go-to for that kind of action in Camel.

dannylamb commented 7 years ago

@birkland That's cool. The http4 component looks like it has an httpClientConfigurator option that should be useful.

dannylamb commented 7 years ago

Also... there's a fourth component to this issue. The routing/execution engine is going to have to authenticate against the services as well.

ajs6f commented 7 years ago

Is it safe to assume that the authN against the services for execution will be the same as for getting the extension definition?

birkland commented 7 years ago

@dannylamb The way it's set up now for (4) is much like a reverse proxy: API-X will pass along any auth headers present in the original request to the service. So as far as auth* is concerned, it's a negotiation between the client and the service. If Danny authenticates as Danny, then the service sees Danny's auth header, rather than FedoraAdmin's (for example), and makes its own decisions about its trust in Danny.

That being said, there may be value in using the injected HttpClient there as well, if you want to control which credentials are being used.

dannylamb commented 7 years ago

@birkland Ah, I forgot about that. That will work fine for us as is, since we share authentication schemes across sevices and Fedora. I was just being overly paranoid.

birkland commented 7 years ago

@dannylamb No worries! CLAW is pushing the envelope with security, and that's a good thing.

ajs6f commented 7 years ago

"CLAW is pushing the envelope with security". Let's not make that the motto. :)

dannylamb commented 7 years ago

So in looking through this issue, the plan of attack would be:

  1. Use the http4 component instead of jetty here
  2. Configure the http4 component to use a custom HttpClientConfigurer
  3. Provide a default HttpClientConfigurer that provides an HttpClient identical to the default provided by Api-X
  4. CLAW will need to provide an analagous HttpClientConfigurer which adds the same StaticTokenRequestInterceptor as is added to its custom HttpClient.
ajs6f commented 7 years ago

Sounds right. I will be happy to tackle the 4th part when the time comes!

One question-- do we want to use HttpClientConfigurer, or would we rather do what (we now know is fully-supported and) we did previously-- inject an actual HttpClient?

birkland commented 7 years ago

I'm working on a PR right now (now just adding an IT). The approach it takes is to inject an HttpClient as before

dannylamb commented 7 years ago

@ajs6f @birkland awesome. that seems simpler than duplicating the technique with a configurer.