-
Notifications
You must be signed in to change notification settings - Fork 166
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
OPDS: Issues with acquisition across domains #2512
Comments
In my head to access other sub-domain/domain with authentication you have to generate a signed URL . These URLs don't rely on |
I feel there are shortcomings with each of these approaches:
This does not scale well. For large OPDS feeds this will require the generation of a large number of pre-signed links each In our case, there may be over 2000 titles and each of these will have an LCP encrypted Epub and PDF available meaning we must generate over 4000 pre-signed links every time the OPDS feed is accessed, for each user. Pagination would offset this somewhat but it is still unnecessary effort when most acquisition links will not be accessed.
This requires OPDS feed providers to set up an additional service, and acts as a potential point of failure.
That makes sense and I agree with this approach. However Authentication for OPDS 1.0 states (bold emphasis added by me):
Thorium currently does not respect OPDS Authentication Documents returned when accessing Acquisition Links and receiving a 401 Unauthorized response, instead raising an error and not downloading the content. I think the correct solution is for Thorium to add support for this scenario. |
cross-posting from another issue, but just in case somebody in the future comes across this thread, here is a separate discussion about OPDS Auth: |
I can confirm that OPDS clients should store Access Tokens and Refresh Tokens in a way where they're tied to the As mentioned above, upon encountering a 401 with an Authentication Document in its response, Thorium should use the To avoid this situation where the client always needs to do an initial GET request without a Bearer Token, I plan on adding a new This approach has been implemented in Aldiko a while back and is much more efficient when interacting with an OPDS catalog. |
Apologies if that has already been discussed elsewhere - I was not able to find mention of this in the draft and wanted to raise a potential issue with using the Tying authentication tokens to the An attacker wanting to gain access to a user's account could craft an OPDS Feed that contains an OPDS Authentication Document that uses the same Id as a legitimate OPDS Feed provider. If the user has previously authenticated using that document, and the client looks up the auth token by the document's id, that token will be sent to the attacker.
OPDS Clients must not provide the token in this scenario. In the case of Basic Auth, this could result in usernames and passwords being entered by users and shared with the attacker. For OAuth, the Some validation on the Authentication Document's |
@mpdunlop would you mind posting this message on https://github.com/opds-community/drafts as an issue? I think that this is a legitimate concern that could be addressed by adding a new property in the Authentication Document that would list all the domains where the |
Done 👍 At this stage I'm not sure how this is going to affect our discussion here. I would still like to see Thorium re-auth the user when accessing an acquisition link that returns an OPDS Authentication Document as it would resolve our immediate issues. The token obtained during this re-authentication could be stored against the acquisition link's host without compromising security, although it isn't strictly in-line with the OPDS specification. |
Thank you for your contribution, it's a very useful discussion under the current context where we're evaluating how Authentication for OPDS could better align with OAuth 2.1. In order to get a bit more context, is it correct to assume that ebooks.com is working on:
|
We're not planning on forking Thorium or utilizing Readium Mobile at this stage. Currently we're hoping to implement two feature requests for partners we work with: The first would like us to support Thorium Reader. We don't plan to fork it at this stage, and in terms of the user-experience it should be better in most scenarios, or at least similar to, our users who currently read on desktop with Adobe Digital Editions. As an aside, the main reason they've requested Thorium is for it's focus on accessibility (we agree - it's great!). The second is planning use our OPDS feeds to load content purchased by our users into their own app. We won't have any direct control over this reader, so we've been using Thorium as a sort of testing ground for our implementation. The thinking is that if ebooks.com adheres to the OPDS 1.2/2.0 specification, utilizes LCP for DRM, and it works in Thorium, then we should be able to refer this partner to all the relevant standards and documentation for them use in their own implementation. There are some other projects we're working on that will benefit from this work, but it's not my place to talk about those yet :) |
Understood, that's very helpful.
Since you can use auto-discovery for the LCP passphrase in OPDS, the overall UX can be much better than ADE and LCP becomes completely seamless for the end-user.
Good to know. At this point I would say that you can skip OPDS 1.2 entirely and just support 2.0, that's what a lot of organizations have been doing for the last few years. |
Hello, @panaC what is the current status of the OPDS improvements merged to the develop branch, in relation to this particular issue? This remains unsolved, right? I will re-read this thread to make sure I am not missing anything, and let's discuss Monday afternoon during our triage concall? |
What about implementing a cookie Thorium currently delegates the cookie logic to
|
ideally the auth server sets first-party cookies for particular same-site (potentially different origin, strictly speaking) API endpoint, even restricting specific URL paths for additional security, and limiting to HTTP (no JS script access) and secure HTTPS only. Absent of cookies, how do you suggest the client should implement same-site=strict/lax policy? The same-site=none approach is only suitable for not-security / not-access-control related data flows, so Thorium currently implements same-site=strict (same origin only). We could switch over to same-site=lax (subdomains allowed) with a few trivial changes, I believe, but I just want to make sure we also cover the cross-origin case if needed (third party cookies equivalent). |
I don't think that cookies are needed at all in this case. An OPDS client can send an Access Token either when:
|
Sure, so absent of a cookie jar from which to automatically transmit access credentials or session data, what secure heuristics do you recommend the client implements in order to determine when to include a specific auth bearer header (for example in a publication download HTTP(S) GET request, when the access token was obtained from a different site, or maybe even a different origin)? |
@HadrienGardeur to be clear I am asking about cases when there is no 'authenticate' on the 'download' link. |
@mpdunlop could you please share an OPDS feed that demonstrates the problem Thorium needs to solve? This would help with testing and validating the implementation, thank you :) |
@danielweck I can't make it available publicly, but I can provide access to our testing environment. If you email me at [email protected], I'll send you the necessary details. In the meantime, here's the authentication flow where the issue occurs:
{
"id": "opds-auth.example.com",
"title": "Authentication Required",
"authentication": [
{
"type": "http://opds-spec.org/auth/oauth/implicit",
"links": [
{
"href": "https://opds-auth.example.com/connect/authorize?scope=bookshelf%20download",
"rel": "authenticate",
"type": "text/html"
}
]
}
],
"description": "You must be signed in to view your bookshelf.",
"links": [
{
"href": "https://www.example.com/logo.png",
"rel": "logo",
"type": "image/png",
"title": "Logo",
"height": 46,
"width": 240
},
{
"href": "mailto:[email protected]",
"rel": "help"
},
{
"href": "https://support.example.com/",
"rel": "help",
"type": "text/html"
}
]
}
{
"metadata": {
"title": "User's Bookshelf",
"numberOfItems": 1
},
"links": [
{
"href": "https://bookshelf.example.com/v1/bookshelf",
"type": "application/opds+json",
"rel": "self"
}
],
"publications": [
{
"metadata": {
"identifier": "https://www.example.com/book/123456/",
"title": "Example Book",
"published": "2020-01-01T00:00:00",
"language": "en",
"author": {
"name": "John Doe",
"identifier": "https://www.example.com/en-au/author/jon-doe/123456",
"sortAs": "Doe, John",
"role": "author"
},
"publisher": [
{
"name": "Example Publisher",
"role": "Publisher"
}
],
"subject": [
{
"name": "MATHEMATICS > General",
"sortAs": "MATHEMATICS > General",
"scheme": "https://www.bisg.org/#bisac",
"code": "MAT000000"
}
],
"description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam in tellus ac mauris convallis mattis. Sed sit amet eleifend turpis. Cras ac magna feugiat, placerat massa a, pulvinar tortor."
},
"links": [
{
"properties": {
"lcp_hashed_passphrase": "MV9b23bQeMQ7isAGTkoBZGErH853yGk0W/yUx1iU7dM=",
"indirectAcquisition": [
{
"type": "application/pdf"
}
]
},
"href": "https://download.example.com/v1/download/123456/Pdf/lcpl/",
"type": "application/vnd.readium.lcp.license.v1.0+json",
"title": "Download PDF",
"rel": "http://opds-spec.org/acquisition",
"fileInfo": {
"hashValue": "315f5bdb76d078c43b8ac0064e4a0164612b1fce77c869345bfc94c75894edd3",
"hashAlgorithm": "http://www.w3.org/2001/04/xmlenc#sha256"
}
}
],
"images": [
{
"href": "https://image.example.com/cover/123456.jpg",
"type": "image/jpeg",
"height": 250,
"width": 166
}
]
}
]
}
Note: Rather than hosting a static OPDS Authentication document at a specific URI, we return it as part of a 401 Unauthorized response whenever a resource is accessed without proper authorization. This follows the requirements specified in the draft Authentication for OPDS 1.0. If we were to host one, we could utilize Link-Level Hints for Authentication, but this appears to be an optional approach (usage of may vs must in the specification) so we didn't think it would be necessary. |
Couldn't an attacker replay / reuse an existing auth access token against a known ID? That being said, a subdomain is essentially the same site (albeit not the same origin), so Thorium could adopt a same-site:lax approach instead of it's current same-site:strict policy, which would solve the security problem of relying on a mapping with document IDs.
That's clearly a bug, we must fix this auth flow. @panaC I guess the download phase is not wired like the OPDS "browse" phase. @mpdunlop we would love to be able to access your auth'ed OPDS feed. My email is [email protected] |
Yes, this is correct. The suggestions in the discussion thread would effectively mitigate this risk - and would be our preferred approach. However, since these are only suggestions at this stage, we can't rely on them being implemented by OPDS clients.
While this approach would solve our immediate problem, it could potentially interfere with OPDS providers who use multiple authentication systems across different subdomains (e.g., I believe @HadrienGardeur's suggestion in Given that the trusted domains feature isn't yet specified, would adopting |
Indeed the download part is entrusted to thorium-reader/src/renderer/library/components/dialog/publicationInfos/opdsControls/OpdsControls.tsx Lines 106 to 109 in 59e5a71
thorium-reader/src/renderer/library/components/dialog/publicationInfos/opdsControls/OpdsControls.tsx Lines 298 to 301 in 59e5a71
thorium-reader/src/renderer/library/redux/sagas/sameFileImport.ts Lines 48 to 52 in d25a395
thorium-reader/src/main/redux/sagas/api/publication/import/importFromLink.ts Lines 74 to 151 in d25a395
|
I plan on opening up a PR next week focusing on improvements to the OPDS Authentication draft:
While we can't influence all OPDS clients, we can have an impact on a number of them through Readium projects. It's already in our plans to re-work our OPDS support on iOS in 2025 with full support for Authentication for OPDS. |
Thorium now updated with the auth flow fix implemented by @panaC (download from a different origin now triggers re-auth, credentials stored as usual for this domain so only asks once) |
https://bookshelf.contoso.org/purchased.json
)https://auth.contoso.org/connect/authorize
); andhttps://download.contoso.org/epub/1d5235d7-044d-46b1-bc8e-913868f20003.epub
)Thorium does not pass the
access_token
obtained from the OAuth response atauth.contoso.org
todownload.contoso.org
and the request will fail to authenticate.It appears that the authorization response's
bearer
token is cached against the OPDS Feed's domain (bookshelf.contoso.org
) which can not later be retrieved by Thorium when usingdownload.contoso.org
as a lookup.To see if it would work, I attempted to return an OPDS Authentication Document when accessing an acquisition link and the request was missing a
bearer
token. I hoped that the id of the OPDS Authentication Document would be used to look up the existingbearer
token, but this also failed to work.What is the correct way to represent this data and give the user a seamless experience?
The text was updated successfully, but these errors were encountered: