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

Permissions pane causes 401 with PUT on CSS #113

Closed
RubenVerborgh opened this issue Jan 26, 2022 · 22 comments
Closed

Permissions pane causes 401 with PUT on CSS #113

RubenVerborgh opened this issue Jan 26, 2022 · 22 comments
Assignees
Labels
bug Something isn't working

Comments

@RubenVerborgh
Copy link
Contributor

When using the permissions pane to change an ACL file hosted on CSS, SolidOS will send a PUT request without an Authorization header, causing CSS to reply with 401.

In constrast, opening that same ACL file in the source pane, will generate the correct PUT request with the Authorization header, resulting in a 2xx.

This can be replicated with the Mashlib recipe.

@RubenVerborgh RubenVerborgh added the bug Something isn't working label Jan 26, 2022
@timbl
Copy link
Contributor

timbl commented Jan 27, 2022

Looks like the wrong fetch being called

@timbl
Copy link
Contributor

timbl commented Jan 27, 2022

But strange that NSS doesn't have the problem

@timbl
Copy link
Contributor

timbl commented Jan 27, 2022

It uses UpdateManager.put which uses webOperation which uses Fetcher._fetch which should be good if you are logged in .. nothing obvious

@bourgeoa
Copy link
Contributor

I can reproduce the 401 error with SolidOS web app on https://solidweb.me (CSS)

image

@bourgeoa
Copy link
Contributor

The PUT do not use Session.fetch() but browser-ponyfill fetch.

@RubenVerborgh
Copy link
Contributor Author

The PUT do not use Session.fetch() but browser-ponyfill fetch.

What line is that?

This is a bug in the code; the reason it works with NSS is (non-standard) cookies.

@jeff-zucker
Copy link
Collaborator

AFAIK, the only place in the SolidOS stack where browser-ponyfill.fetch is used is in @inrupt/solid-client-authn-core/dist/login/oidc/redirectHandler/redirectHandler.js in this line :

    const jwksResponse = await (0, cross_fetch_1.fetch)(jwksIri);  

In other words, it is part of Inrupt's login redirect process and only peripherally related to PUT and, unless I'm mistaken, is an Inrupt issue. I'm not sure the browser-ponyfill fetch is even related to this permissions pane issue.

@bourgeoa
Copy link
Contributor

bourgeoa commented Jan 31, 2022

@timbl @SharonStrats
The code https://github.com/solid/solid-ui/blob/eb82ec38b28b2e2feb872492149f48b6507ebf42/src/acl/access-controller.ts#L217
is not using the solidLogic store but is creating a new graph : newAClGraph = graph() with I suppose a non authenticated fetch.
The code organization seems to need 2 stores to be able to duplicate the graph in certain situations.

I do not succeed to create a duplicate of the authenticate store. Could you look at it.
With this code I still have a 401

import { store } from '../logic'
......
public save (): Promise<void> {
       const newAClGraph = store
......
       const updater = newAClGraph?.updater // || new UpdateManager(newAClGraph)

@jeff-zucker
Copy link
Collaborator

@bourgeoa the code there creates a new store (newACLGraph) and an upadater for it without specifying a fetch, Which means you are correct that it uses the default cross-fetch. So we don't need to do anything with the store, just with the fetcher for the updater. This can be done by this sequence :

  import {fetcher} from 'rdflib';
  const newACLGraph = graph() 
  const fetcher = fetcher(newACLGraph,{fetch:this.store.fetcher._fetch})
const updater ...

That will create a new store and an updater for it that uses the fetch from the existing store. I believe that is the desired effect.

@bourgeoa
Copy link
Contributor

Adding the authorized fetch enable creation and edit on creation.
when trying to edit an existing ACL the 401 error comes again. Weird.
When the error is there there is no way to remove the 401 error except by reloading the page.

@bourgeoa
Copy link
Contributor

bourgeoa commented Feb 17, 2022

@angelo-v

Adding the authorized fetch enable creation and edit on creation.
when trying to edit an existing ACL the 401 error comes again. Weird.
When the error is there there is no way to remove the 401 error except by reloading the page.

I haven't created a branch in solid-ui for that.
The only think I did is add here
https://github.com/solid/solid-ui/blob/48f3ebed3572bc099bfcd5b770fd5a3f4d738795/src/acl/access-controller.ts#L230

    newAClGraph.fetcher = fetcher(newAClGraph, { fetch: this.store.fetcher._fetch })

This add an authenticated fetch to the newAClGraph.
I use the tryMoveAuth branch, but the problem should not be branch depending. It existed before.

My analyse is that for any reason loading an existing resource ACL to the store does load in a store with no-authenticated.fetch

@bourgeoa
Copy link
Contributor

bourgeoa commented Feb 17, 2022

@aveltens found the problem
https://github.com/solid/solid-ui/blob/48f3ebed3572bc099bfcd5b770fd5a3f4d738795/src/acl/access-groups.ts#L71

This is creating a node-fetch fetcher
Just commenting out solves the issue.

@bourgeoa
Copy link
Contributor

@RubenVerborgh a test-version of mashlib@1.7.20-401 includes the PATCH resolving this issue.

@RubenVerborgh
Copy link
Contributor Author

Super, thanks!

@timbl
Copy link
Contributor

timbl commented Feb 19, 2022

When those bits were written, we used to think about making a Fetcher. In fact we had the shortcut fetcher() to do it easily. Now we just make a LiveStore which has automatically has a Fetcher and an UpdateManager attached to it.
Should we change the default _fetch for any new Fetcher?

@jeff-zucker
Copy link
Collaborator

I believe so, yes. It should check the window.solidFetch to see if the user set a global fetch method and then check the existing _fetch and use that. I can't see any advantage to ignoring the user's definition of a fetch method and lots of reasons to honor it.

@timbl
Copy link
Contributor

timbl commented Feb 21, 2022

I wonder why the problem did not show up on NSS.

@RubenVerborgh
Copy link
Contributor Author

I wonder why the problem did not show up on NSS.

Cookie-based auth is also active (which CSS and ESS don't use because of security concerns).

@jeff-zucker
Copy link
Collaborator

@RubenVerborgh and @timbl - I don't believe it has to do with cookies. If you try the script below, you see that I login to NSS and then do an unauthenticated fetch and get back a 401 even though the cookie is active.

<!DOCTYPE html><html><head>
  <meta charset="UTF-8" />
</head><body>
  <span id="webId"></span>
  <input id="oidc" value="https://solidcommunity.net" style="width:24em" />
  <button id="loginButton">Login</button>
  <button id="logoutButton">Logout</button>

<script src="https://cdn.jsdelivr.net/npm/@inrupt/solid-client-authn-browser@1.11.2/dist/solid-client-authn.bundle.js">
</script>
<script>

const iscan = solidClientAuthentication;
var session = iscan.getDefaultSession();

const loginButton = document.querySelector("#loginButton");
const logoutButton = document.querySelector("#logoutButton");
const webIdArea = document.querySelector("#webId");
loginButton.onclick = ()=> { 
  return iscan.login({
    oidcIssuer: document.getElementById("oidc").value,
    redirectUrl: window.location.href,
    clientName: "Minimal login/logout"
  });
};
logoutButton.onclick = async ()=> { 
  await session.logout();
  showLoginStatus();
};
async function handleRedirectAfterLogin() {
  await iscan.handleIncomingRedirect();
  showLoginStatus();
}
async function showLoginStatus() {
  session = iscan.getDefaultSession();
  if (session.info.isLoggedIn) {
    loginButton.style.display = "none";
    logoutButton.style.display = "inline-block";
    webId.innerHTML = `Logged in as ${session.info.webId}`;
    const privateThing='https://jeff-zucker.solidcommunity.net/private/testput.txt';
    let response = await window.fetch(privateThing,{
      method:"PUT",
      headers: {"content-type":"text/plain"},
      body: "some words",
    })
    webId.innerHTML+="Response to un-authenticated PUT : "+response.status;
  }
  else {
    loginButton.style.display =  "inline-block";
    logoutButton.style.display = "none";
    webId.innerHTML = `Not logged in.`;
  }
}
handleRedirectAfterLogin();
</script></body></html>

@RubenVerborgh
Copy link
Contributor Author

    let response = await window.fetch(privateThing,{
      method:"PUT",
      headers: {"content-type":"text/plain"},
      body: "some words",
    })

is missing credentials: "include" which rdflib used to set at some point

@jeff-zucker
Copy link
Collaborator

jeff-zucker commented Feb 21, 2022 via email

@bourgeoa bourgeoa self-assigned this Feb 22, 2022
@bourgeoa
Copy link
Contributor

bourgeoa commented Mar 3, 2022

@bourgeoa bourgeoa closed this as completed Mar 3, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

4 participants