Subject: [Captive-portals] API access and .well-known

From: Martin Thomson <[email-masked]>
Date: Mon, 15 Jan 2018 16:39:59 +1100

(see also https://github.com/capport-wg/api/issues/2)

Currently the API draft proposes use of .well-known for finding the
API.  Generally speaking, there's a trend toward avoiding use of
.well-known except when either:

* it is difficult to configure or provide a full URL, or
* the .well-known provides information about the origin as a whole.

In this case, the latter definitely doesn't apply, but I think we
should probably discuss the former a little.

The problem we have is that there are really two URLs we care about
and 7710 only provides one.  (PvD might provide two URLs, so we don't
need to worry about this problem for PvD.)

The old API draft used HTTP method to distinguish the two uses: GET
for HTML that you might show to a person; POST for an API.  But the
new, leaner API uses GET too, so that's not an option we can use.

HTTP content negotiation is another option here.  It's pretty
well-supported on the whole aside from a few wrinkles around caching.
I suspect we will find that caching will be infeasible for other
reasons (see the other issues on GitHub for a taste of that).  Content
negotiation works [1] by having the client send an Accept header field
with a new media type (straw man: application/capport+json) and the
server would detect this and send back an API response or redirect to
the API endpoint.  If this content-type wasn't present, it could send
back HTML (or a redirect to a server that does).

Here's the options I see:

a. use .well-known and just provide better justification for it
b. use content negotiation
c. find some way to get two URIs, like revising 7710 or finding an
alternative mechanism (such as the one in RFC 5986)

Tommy notes that this has a drawback in that it forces the web UI and
API to be co-located.  I don't think that is necessarily true if you
accept that HTTP-level redirects are possible.  Indeed, that is how
many enforcement points work today: they terminate a connection
locally but then redirect to more capable servers.  Also, using
.well-known doesn't really make the resources any less co-located
because the origin - and the server - are still the same.

What do folks prefer here?

[1] Content negotiation can use other properties of the request as
well, but Accept is common and pretty widely supported.

---

From: Evert Pot <[email-masked]>
Date: Tue, 16 Jan 2018 10:16:10 -0800

> well, but Accept is common and pretty widely supported.
We would definitely prefer to see 2 distinct urls here. It makes the 
least amount of assumptions, and gives the most amount of flexibility.

Evert

---

From: Tommy Pauly <[email-masked]>
Date: Tue, 16 Jan 2018 14:18:39 -0800

Hi Evert,

I think that all three options that Martin provided implicitly support two different URLs ([API-URL] and [HTML-URL] for lack of a better term) that a client device could use. I agree that making things very explicit and clear is important.

>> a. use .well-known and just provide better justification for it

The reason I suggested a well-known URL was to ensure that we didn’t collide with some other URL (like the captive portal landing page) or some other JSON that’s not really doing this API. It would be easier to validate that the configuration did indeed intend to point to this JSON API. 

Note that in this setup, you would learn about the URL of the Captive Portal JSON API as the main entry point for the UE (the discovery coming from either 7710 or PvD or the like). This is specifically the first URL, [API-URL]. The JSON content itself would contain [HTML-URL].

Instead of using a well-known URL here, we could imagine just enforcing that the discovered URL MUST be a JSON endpoint that serves up this API.

The benefit of this approach (get [API-URL] first, and follow it to [HTML-URL]) is that we pave the way towards more flexibility when we don’t necessarily need the [HTML-URL] to do traditional captive portals, but instead can do interaction models designed for watch-like devices, or multiple devices that don’t ever need a follow-on URL.

>> b. use content negotiation

In this approach, [API-URL] and [HTML-URL] are essentially the same, just with different content. I agree with the concern that this is ambiguous. It also has the potentially negative effect of tying together the JSON API and traditional HTML URL. Yes, you can do redirects, etc, to not be co-located, but this seems more prone to configuration error and complexity. 

>> alternative mechanism (such as the one in RFC 5986)

I think that this approach is effectively saying that [API-URL] and [HTML-URL] are both signaled explicitly in the discovery mechanism. While this avoids the problem of ambiguity, it bakes in the notion of a legacy captive portal URL, and takes up more space in the discovery mechanism.

I’d vote for some variation on (a), but we can just explain the meaning of the URL we discover more clearly, instead of using a well known URL.

Thanks,
Tommy

> On Jan 16, 2018, at 10:16 AM, Evert Pot <[email-masked]> wrote:
> 
> We would definitely prefer to see 2 distinct urls here. It makes the least amount of assumptions, and gives the most amount of flexibility.
> 
> Evert
> 
> _______________________________________________
> Captive-portals mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/captive-portals

---

From: Adam Roach <[email-masked]>
Date: Tue, 16 Jan 2018 16:44:15 -0600

[as an individual]

I agree that we should strictly avoid synthesizing URLs in general, and 
should try to avoid .well-known URLs in particular. Sometimes you're 
forced to use .well-known (e.g., when there's literally no way to get a 
full URL to the client), but that doesn't seem to be the case here.

> alternative mechanism (such as the one in RFC 5986)

For what it's worth, I don't think (a) is possible -- I don't believe 
any plausible justification text can be put together that explains why 
other approaches are infeasible.

Something else to consider is serving up the HTML portal on the endpoint 
you get from RFC7710, and including a link-relation [RFC5988] header 
field that points to the API; e.g.:

HTTP/1.1 200 OK
Link: <https://portal-api.example.com/json/>;rel="capport-api"
Content-Type: text/html

<!DOCTYPE html PUBLIC ... <html>... [legacy portal page goes here]... 
</html>

Importantly: clients interested only in the API can simply perform a 
HEAD rather than a GET to retrieve the Link information. I'll note that 
this provides a clear extension point if you decide you need yet a third 
thing to be discoverable and/or need different HTTP endpoints for 
versioning in the future. I do note that it requires an additional round 
trip, similar to the redirection approach that has been discussed in 
conjunction with content negotiation. Notably, taking this approach 
eliminates the need for redirects, since the link header can point to 
any arbitrary URL.

/a

---

From: Martin Thomson <[email-masked]>
Date: Wed, 17 Jan 2018 13:16:51 +1100

Right, I neglected to mention that option.  Call it (d) link relations.

You might also do the reverse in the API-first arrangement that Tommy
suggests (API at the URL, HTML at the other end of a link relation).
It seems likely that 7710 deployment is scant enough that we would be
free to make this decision without being constrained to deal with
backwards compatibility.

One likely deployment involves the thing that is configured being
different to the thing that ultimately serves the content (for reasons
of sorting out the UE identification, if nothing else), so it's
possible that Adam's suggestion here doesn't add round trips that
weren't already needed.

On Wed, Jan 17, 2018 at 9:44 AM, Adam Roach <[email-masked]> wrote:
> should try to avoid .well-known URLs in particular. Sometimes you're forced
> to use .well-known (e.g., when there's literally no way to get a full URL to
> the client), but that doesn't seem to be the case here.
>
>
> For what it's worth, I don't think (a) is possible -- I don't believe any
> plausible justification text can be put together that explains why other
> approaches are infeasible.
>
> Something else to consider is serving up the HTML portal on the endpoint you
> get from RFC7710, and including a link-relation [RFC5988] header field that
> points to the API; e.g.:
>
>
> HTTP/1.1 200 OK
> <!DOCTYPE html PUBLIC ...
> <html>...
> [legacy portal page goes here]...
> </html>
>
>
> Importantly: clients interested only in the API can simply perform a HEAD
> rather than a GET to retrieve the Link information. I'll note that this
> provides a clear extension point if you decide you need yet a third thing to
> be discoverable and/or need different HTTP endpoints for versioning in the
> future. I do note that it requires an additional round trip, similar to the
> redirection approach that has been discussed in conjunction with content
> negotiation. Notably, taking this approach eliminates the need for
> redirects, since the link header can point to any arbitrary URL.
>
> /a

---

From: Evert Pot <[email-masked]>
Date: Wed, 17 Jan 2018 11:19:21 -0800

Hi Tommy,

> I think that all three options that Martin provided implicitly support two different URLs ([API-URL] and [HTML-URL] for lack of a better term) that a client device could use. I agree that making th…
Yea, I guess this is a misunderstanding of terms. I think using a 
well-known uri, to me, is not necessarily providing a URI ;) All you do 
is provide an origin, and have the client of the API reconstruct the 
URI. I should have been more clear.

In our ideal world the AP provides fully qualified URIs.

Linking to the html page from the JSON endpoint sounds like a great 
idea. Have you considered using a format such as HAL, and specify a Link 
Relation[1] instead of using a plain property?

http://www.iana.org/assignments/link-relations/link-relations.xhtml

[snip]

---

From: Michael Richardson <[email-masked]>
Date: Thu, 18 Jan 2018 17:15:14 -0500

Tommy Pauly <[email-masked]> wrote:
    > The benefit of this approach (get [API-URL] first, and follow it to
    > [HTML-URL]) is that we pave the way towards more flexibility when we
    > don’t necessarily need the [HTML-URL] to do traditional captive
    > portals, but instead can do interaction models designed for watch-like
    > devices, or multiple devices that don’t ever need a follow-on URL.

+1

    > I think that this approach is effectively saying that [API-URL] and
    > [HTML-URL] are both signaled explicitly in the discovery
    > mechanism. While this avoids the problem of ambiguity, it bakes in the
    > notion of a legacy captive portal URL, and takes up more space in the
    > discovery mechanism.

    > I’d vote for some variation on (a), but we can just explain the meaning
    > of the URL we discover more clearly, instead of using a well known
    > URL.

I think that we need the 7710 mechanism to get the HOST part, and that the
URL part SHOULD be .well-known/blah, but MAY be something else.

--
Michael Richardson <[email-masked]>, Sandelman Software Works
 -= IPv6 IoT consulting =-

---

From: Michael Richardson <[email-masked]>
Date: Thu, 18 Jan 2018 17:18:08 -0500

Adam Roach <[email-masked]> wrote:
    > I agree that we should strictly avoid synthesizing URLs in general,
    > and should try to avoid .well-known URLs in particular. Sometimes
    > you're forced to use .well-known (e.g., when there's literally no way
    > to get a full URL to the client), but that doesn't seem to be the case
    > here.

Is it reasonable for different enforcements points to return different URLs
to different clients?  If so, that solves much of the multi-tenancy problems,
and I guess I recant some of my previous message.

I'd still like to register a /.well-known value as a suggestion.

---

From: Adam Roach <[email-masked]>
Date: Thu, 18 Jan 2018 16:19:37 -0600

[as an individual]

> URL part SHOULD be .well-known/blah, but MAY be something else.

No, please don't. That's very much *not* what .well-known is meant for. 
See RFC 5785, section 1.1.

/a

---

From: Adam Roach <[email-masked]>
Date: Thu, 18 Jan 2018 16:33:02 -0600

> and I guess I recant some of my previous message.

Sure, either in a 3xx response; or, if we're using Link: relations, 
those URLs can vary based on the client. If you want to get fancy about 
it, you can even have your DHCP server hand out different URLs in the 
RFC7710 field. There are a lot of ways to deal with multi-tenancy.

> I'd still like to register a /.well-known value as a suggestion.

Why?

/a

---

From: Martin Thomson <[email-masked]>
Date: Fri, 19 Jan 2018 10:19:22 +1100

On Fri, Jan 19, 2018 at 9:33 AM, Adam Roach <[email-masked]> wrote:
> Sure, either in a 3xx response; or, if we're using Link: relations, those
> URLs can vary based on the client. If you want to get fancy about it, you
> can even have your DHCP server hand out different URLs in the RFC7710 field.
> There are a lot of ways to deal with multi-tenancy.

Adam is correct.  Note that DHCP offers the possibility of per-client
configuration, which is something not available with a RA.

Note also that if you believe it necessary to provide the client with
an identifier using any of these opportunities, you need to
authenticate it later, lest the client switch it out on you.  This
might not give the client the ability to piggy back on top of another
client's access, but it might lead to privacy violations.

---

From: Michael Richardson <[email-masked]>
Date: Fri, 19 Jan 2018 15:36:10 -0500

> URLs can vary based on the client. If you want to get fancy about it, you can
    > even have your DHCP server hand out different URLs in the RFC7710
    > field. There are a lot of ways to deal with multi-tenancy.

    >> I'd still like to register a /.well-known value as a suggestion.

Adams asks "Why?"

I anticipate some not-yet-well-defined situations where the RFC7710 field can
not automatically be passed to a browser that has a human there.
For diagnostics and support service interactions.

---

From: Adam Roach <[email-masked]>
Date: Fri, 19 Jan 2018 14:49:48 -0600

> not automatically be passed to a browser that has a human there.

We (the ART ADs) have already had conversations where we've talked 
people out of speculatively staking out space in the .well-known 
namespace. The guidance here is: come back when you have a clearly 
defined use-case.

> For diagnostics and support service interactions.

Can you expand on this? I mean, if a service provider wants to put 
things in a consistent place to make diagnostics easier, that's their 
prerogative. In fact, that's kind of the whole *point* of avoiding 
synthesized URLs: if we have normative requirements that put certain 
endpoints in places we spell out, then it takes that flexibility away 
from operators. The use of .well-known demonstrably makes this situation 
worse, not better, for running a network.

/a

---

From: Erik Kline <[email-masked]>
Date: Wed, 24 Jan 2018 10:44:07 +0900

<hat-free>

I quite like this option.  If we use this approach then it seems to me
host-side implementations can choose their level of support, right?

    [A] super basic HTML view interaction

Makes a GET for the RFC 7710 URL, ignores any Link relation, serves up
the HTML to the human.

    [B] HTML + Link support

Makes a GET for the RFC 7710 URL, notices the Link relate, and starts
a connection to the API endpoint for not really too much more cost
than following a 3xx redirect (especially if the HTML is structured
such that a webview would need to fetch lots of extra resources, which
the API-following code path could avoid loading).

    [C] some kind of clever HTML + Link support

Makes a HEAD for the RFC 7710 URL.  If there is no Link header try to
re-use the existing TCP connection to issue a GET and serve HTML to
the human.  If there is a Link relation, start a connection to the API
endpoint.

Do I understand things correctly, is this reasonable?