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 Certificate Pinning #228

Closed
tsorencraig opened this issue Mar 16, 2018 · 11 comments
Closed

Support Certificate Pinning #228

tsorencraig opened this issue Mar 16, 2018 · 11 comments
Labels
enhancement Issues outlining new things we want to do or things that will make our lives as devs easier
Milestone

Comments

@tsorencraig
Copy link

Public key pinning is a great step for apps to reduce MITM vulnerabilities. The current instantiation of the Apollo Client allows a parameter for the URLSession configuration. In order to implement SSL pinning, however, an entire URLSession object should be able to be passed in. This would allows the URLSession object to register a delegate that handles the pinning by implementing

optional public func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Swift.Void)

This can be done simply by adding another constructor to the HttpNetworkTransport object that accepts the URLSession object instead of just it's configuration.

After that, injecting the session object with the appropriate delegate is simple.

let configuration = URLSessionConfiguration.default
        
let networkTransport = HTTPNetworkTransport(url: "https://some-gql-endpoint/graphql",
                                            session: URLSession(configuration: configuration,
                                                                                delegate: NSURLSessionPinningDelegate(),
                                                                                delegateQueue: nil))

let client = ApolloClient(networkTransport: networkTransport)
@martijnwalraven
Copy link
Contributor

I don't think we should give out control of URLSession completely, because HTTPNetworkTransport should have the ability to implement URLSessionDataDelegate methods. But maybe we could add a HTTPNetworkTransportDelegate protocol that would pass through the authentication challenge.

This is also one of the possible solutions to handling token authentication. See this issue for a long discussion about this :) We should really make some decisions here and solve these issues. @MrAlek, what do you think?

@MrAlek
Copy link
Contributor

MrAlek commented Mar 16, 2018

Though adding a HTTPNetworkTransportDelegate would be one way to open up the API, I think people will find more and more cases for customization. Maybe HTTPNetworkTransport should be opened up for subclassing instead, so you can override delegate methods, inspect the HTTPURLResponse & modify outgoing URLRequests? That could be a good intermediary solution before links are in place.

@johntmcintosh
Copy link

I'd second the idea of opening HTTPNetworkTransport for subclassing.

In our app, we've needed to re-implement HTTPNetworkTransport to have some hooks into both outgoing requests and incoming responses. Our use cases are:

  • Injecting logging of the request and response objects
  • Automatically triggering de-authentication if a 403 response is received
  • Hook for SSL Pinning

I think that a subclass of HTTPNetworkTransport would enable us to accomplish the same things without needing to re-implement that class ourselves, which would be a nice simplification.

@martijnwalraven , I'm happy to make a pass at a PR for that if you think that could be a viable option.

Regarding the token authentication piece, I'll take some time to digest the #37 thread and add some thoughts there as well, as that's a pretty urgent topic for us right now. Related to this thread, my concern with solving token auth via the subclass approach is that for us we have token refresh logic in a separate layer, and retrieving the user's current tokens is an asynchronous operation. As a result, this makes appending them in the network transport's send function problematic, since send is looking for a synchronous return value. I'll think about that some separately, but for now, I'd be thinking about this PR in terms of just opening up the existing structure to provide a little more flexibility for consumers of the library. Thoughts?

@crafterm
Copy link

crafterm commented Aug 6, 2018

I agree with @johntmcintosh - had the same requirement here and ended up reimplementing a new NetworkTransport class, where most of the code was largely HTTPNetworkTransport including pinning support. Being able to subclass, or access the URLSession property to become the delegate would be really useful.

@ericmarkmartin
Copy link

Same here. I can'e help but notice that this issue was opened almost 5 months ago. Is the reason there hasn't been any progress because the maintainers aren't sure if opening for subclassing is the right move or something else?

@wtrocki
Copy link

wtrocki commented Aug 23, 2018

This feature will be possible to be written by users if library will allow to provide custom NetworkTransport.
It is really easy fix and it could be game changer for apollo on ios. More about it in comment: #297 (comment)

@designatednerd
Copy link
Contributor

Apologies for the long radio silence on this issue. I'm going to be chatting with @martijnwalraven next week about the implications of giving up the ability to use the session delegate internally.

@designatednerd designatednerd added the enhancement Issues outlining new things we want to do or things that will make our lives as devs easier label Jul 15, 2019
@designatednerd designatednerd modified the milestones: 0.14.0, 0.15.0 Jul 24, 2019
@designatednerd
Copy link
Contributor

As of 0.15.0, we now support passing in a URLSession rather than just a URLSessionConfiguration, so you are able to take advantage of the URLSessionDelegate methods in order to facilitate this.

If you are still having problems with this after upgrading, please open a new issue. Thank you!

@ts95
Copy link

ts95 commented Dec 1, 2020

I recently updated Apollo to v0.37.0 and had to refactor the auth layer because of breaking changes. In the process of refactoring I noticed that there's seemingly no way to supply a custom URLSession instance anymore to the network transport class. Previously it could be supplied to HTTPNetworkTransport, but since that class has been replaced by RequestChainNetworkTransport whose initializer doesn't take a URLSession parameter, I can no longer specify a URLSessionDelegate for certificate pinning.

Am I missing something?

@ts95
Copy link

ts95 commented Dec 1, 2020

I found out that Apollo's URLSessionClient class implements URLSessionDelegate, so I can simply subclass it and override this method:

override func urlSession(
    _ session: URLSession,
    didReceive challenge: URLAuthenticationChallenge,
    completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void
)

The URLSessionClient instance can be passed to the LegacyInterceptorProvider initializer 👍

@designatednerd
Copy link
Contributor

You beat me to it! Yep, subclassing URLSessionClient is the answer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Issues outlining new things we want to do or things that will make our lives as devs easier
Projects
None yet
Development

No branches or pull requests

9 participants