node-solid-server icon indicating copy to clipboard operation
node-solid-server copied to clipboard

Able to access private files when logged in with a different account/provider, which has not been granted access

Open andydavison opened this issue 5 years ago • 9 comments

I appear to be able to read, and overwrite files with a PUT, files in a private folder when logged in to a different account.

The example I found is editing https://andydavison.inrupt.net/private/test.jpg when logged in with https://ldp.demo-ess.inrupt.com/andydavison/. According to the ‘Your storage’ tab at https://andydavison.inrupt.net/, that private folder is not shared with anyone else, and indeed is inaccessible when logged out from both providers.

andydavison avatar Aug 03 '20 13:08 andydavison

Thanks for reporting this! Can you open your browser's developer console, right-click the PUT or GET which was successful but shouldn't have been, select 'Copy > as Curl' and either paste the curl command here or email it to me, michiel at unhosted dot org. My suspicion is the server may be mixing up the Cookie header and the Authorization header.

Which client are you using to do the editing? The web interface that's visible when you point your browser at https://andydavison.inrupt.net/private/test.jpg or some other Solid app or command-line script?

michielbdejong avatar Aug 04 '20 07:08 michielbdejong

@michielbdejong Here's an example of a PUT which I don't think should be working (there's nothing else in the pod, so you're welcome to the token 😅 ). The request is being sent using a React component I'm building, within the Storybook demo tool.

curl 'https://andydavison.inrupt.net/private/test.jpg' \
  -X 'PUT' \
  -H 'Connection: keep-alive' \
  -H 'Content-Length: 48691' \
  -H 'authorization: Bearer eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiItemJsdDNvMHBsTzZ6Z3Z0TmQ5cEQiLCJhdWQiOiJodHRwczovL2FuZHlkYXZpc29uLmlucnVwdC5uZXQiLCJleHAiOjE1OTY1MzYxMjEsImlhdCI6MTU5NjUzMjUyMSwiaWRfdG9rZW4iOiJleUpoYkdjaU9pSlNVekkxTmlJc0luUjVjQ0k2SWtwWFZDSXNJbXRwWkNJNkluaGxUMnBsY3psMU0wRmpWVFJNUW5wallXNUZUVGR3V2t4M1UyeDRZVTQzVlRZeVducFBRa1JSZFhjaWZRLmV5SnpkV0lpT2lKb2RIUndjem92TDJ4a2NDNWtaVzF2TFdWemN5NXBibkoxY0hRdVkyOXRMMkZ1Wkhsa1lYWnBjMjl1TDNCeWIyWnBiR1V2WTJGeVpDTnRaU0lzSW01dmJtTmxJam9pVGxWc2VsOVVlVVJYTWpkeWRtUjZSVUZYYzJwamFHVTNha2wxVjBadVRISlRPVVIxWkcxWVdITnVRU0lzSW1GMFgyaGhjMmdpT2lKVGJGTXhORlowVUY5S0xWVkpOa0Z5YjNCVFJXRm5JaXdpYzE5b1lYTm9Jam9pYVhKcVZXOXFTM1pRTlU5c2RXeG5UVTV2UVVZMFFTSXNJbU51WmlJNmV5SmhiR2NpT2lKU1V6STFOaUlzSW1VaU9pSkJVVUZDSWl3aVpYaDBJanAwY25WbExDSnJaWGxmYjNCeklqcGJJblpsY21sbWVTSmRMQ0pyZEhraU9pSlNVMEVpTENKdUlqb2liR05FZGpkQ2VGVkVSbU4wV0ZsdWVFNUhkamgzY2tWd1RUazFaME5CWVZwdGVXSkdkR1JpUlMxR05ESlhWR2RLWlhCSlgzWnRkV1UyVFRSalZsWm1NRVl6UW10TFdUVjBWRE5TVGpKRk9ESmlXbU5QYW10cVRGa3RZakZwVDBJNWVESk9iRXRIVVZCa1drdFZiRWROWVZjMldHbG5lVkJqTUdoMFlYWXhWRTVEV1ROU1gyNXdkbUYwZGpoTFFscHZZMUJQUm5oSFdGWkxObWhYVkVGMWFXZHhURkJDVGxrMVJYTTJjM2QzWTI1M2FEVXhWMHBPY3paU2JrVlpkVEZDYW5scFRuWjJaemR0T1hKSWRpMUthR0ZNWjJ4RmRtVjVNbVpoZFcwelIyVlZkV2hDWDE4eFoyOW1hMkZPZWt4RUxVY3RXRVZ5T0RkaFgwMXhXVlpVWlVwbGMybHZRMTk1U0ZSWmJEVnJabFJxVGxGQ2RVRjFkMjAwVG10RlFWcEZZV1ZCTTNadmIzSTVlVXhZUzBGQ00yUXRlVXhWVkhwclJWVnZPVGx0UTA1WWNXcGxkRFZRWHpsTlREQkhjMGhxT1hodlpVTlJJbjBzSW1GMVpDSTZJaTE2WW14ME0yOHdjR3hQTm5wbmRuUk9aRGx3UkNJc0ltVjRjQ0k2TVRVNU5qVXpOVGczTXl3aWFXRjBJam94TlRrMk5UTXlNamN6TENKcGMzTWlPaUpvZEhSd2N6b3ZMMmxrWlc1MGFYUjVMbVJsYlc4dFpYTnpMbWx1Y25Wd2RDNWpiMjBpZlEuT1Etcm5aTnF1SjlWd3VSaWN0dDc2RFcyQVVaY0xSS3JUZjVPaFhUVTR6cTFseEFzREp0SEg0U2J2MHNnMEZwWXdwLU5fRy0wOUV1c2dvV2Ffb2VjU1hKTGxudDFLRzdYU3FIU3NKVmhvc2hocmZhUmVET3hIcjhWMlE3aGVXTVpGN1VPVk9qYWNIcXAtNTZMWlVsWUI0ZmptLVVydW5jYVBWdExvVEdtbnE2ZDJrVnBaMFVoLWh3bGRFY1JDWklfVlBHeDVCblNDcTdfcVV3YWhZa2RlSFdjeFY5TDc2ODNIX0lGbjA0UENaLXp2Umpwd1BnYkxNc3pzeFUwOVZDVlJsd0ZCRmdRck1mUElVX0k4LXpnR0NlQ2d4S0ZpamtzckprSktsampRSEt0dENXZG9QOV9VbUpGUXRocTdwQXFQQXJhZ0g4ckFyQm80aHBTUm9yZ3ZRIiwidG9rZW5fdHlwZSI6InBvcCJ9.k0VTE7sR0NoFCgMcZhmp1TzGKJ_7wMi7J4UoghCseWgn2ukgSSpzGzMO8-xJacfM8M3sPSKSTvcfaENUAFzciktkmORYVcBkoMNjzIY5KCS4jxRCbdwXxltyco5OuoCNkS11PDVf-XnoT5KfzOBiwYw5Guh5wTUKIzN4GmySfYH1BgGET6nRL9q3UhK5ePUY47fN6LRs83cdHsSVTn3mVN5655kImdZrjlQ04W7fqk9_c88NCN3bzKIibtsZdfJP9rV7daUciP0svwixf11lS6sat40OjZmL6mTXBLgKz_3D6dPZxcN6U-j_4bWJWsPel1EIj3cCw4WoGwgNH0sLSw' \
  -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36' \
  -H 'content-type: image/jpeg' \
  -H 'Accept: */*' \
  -H 'Origin: https://localhost:3000' \
  -H 'Sec-Fetch-Site: cross-site' \
  -H 'Sec-Fetch-Mode: cors' \
  -H 'Sec-Fetch-Dest: empty' \
  -H 'Referer: https://localhost:3000/iframe.html?id=image--without-children&viewMode=story' \
  -H 'Accept-Language: en-GB,en-US;q=0.9,en;q=0.8' \
  -H 'Cookie: nssidp.sid=s%3AfuIM_1u9gAVOIFVP6c8o88_cz0aeNfyA.e0A5GMR%2F%2BbnimnqzvK7DkBkc2Ijg367lnX3NWpKNr2c' \
  --compressed

andydavison avatar Aug 04 '20 09:08 andydavison

Thanks! I'm running the command against inrupt.net but the request takes a long time to complete.

When I try the same request against a local NSS instance (changing andydavison.inrupt.net to localhost:8443) I correctly see this in the server logs:

  solid:ACL    Checking auth <https://localhost:8443/private/.acl#owner> with agent null +0ms
  solid:ACL     Agent or group: Fail: not public and not logged on. +0ms
  solid:ACL      The agent/group check fails +0ms
  solid:ACL       Check failed: User Unauthorized +0ms
  solid:ACL accessDenied: modeURIorReasons: ["User Unauthorized"] +0ms

and also:

  error_description: 'Missing cnf key in access token',

from node_modules/@solid/oidc-rs/src/AuthenticatedRequest.js line 316

So it looks like the token you obtained from your IDP https://ldp.demo-ess.inrupt.com is not recognized by the inrupt.net server. I'll see if I can get to the JWT contents of your bearer token to debug that further.

michielbdejong avatar Aug 04 '20 10:08 michielbdejong

This is the PoPToken payload:

payload: {
      iss: '-zblt3o0plO6zgvtNd9pD',
      aud: 'https://andydavison.inrupt.net',
      exp: 1596536121,
      iat: 1596532521,
      id_token: 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6InhlT2plczl1M0FjVTRMQnpjYW5FTTdwWkx3U2x4YU43VTYyWnpPQkRRdXcifQ.eyJzdWIiOiJodHRwczovL2xkcC5kZW1vLWVzcy5pbnJ1cHQuY29tL2FuZHlkYXZpc29uL3Byb2ZpbGUvY2FyZCNtZSIsIm5vbmNlIjoiTlVsel9UeURXMjdydmR6RUFXc2pjaGU3akl1V0ZuTHJTOUR1ZG1YWHNuQSIsImF0X2hhc2giOiJTbFMxNFZ0UF9KLVVJNkFyb3BTRWFnIiwic19oYXNoIjoiaXJqVW9qS3ZQNU9sdWxnTU5vQUY0QSIsImNuZiI6eyJhbGciOiJSUzI1NiIsImUiOiJBUUFCIiwiZXh0Ijp0cnVlLCJrZXlfb3BzIjpbInZlcmlmeSJdLCJrdHkiOiJSU0EiLCJuIjoibGNEdjdCeFVERmN0WFlueE5Hdjh3ckVwTTk1Z0NBYVpteWJGdGRiRS1GNDJXVGdKZXBJX3ZtdWU2TTRjVlZmMEYzQmtLWTV0VDNSTjJFODJiWmNPamtqTFktYjFpT0I5eDJObEtHUVBkWktVbEdNYVc2WGlneVBjMGh0YXYxVE5DWTNSX25wdmF0djhLQlpvY1BPRnhHWFZLNmhXVEF1aWdxTFBCTlk1RXM2c3d3Y253aDUxV0pOczZSbkVZdTFCanlpTnZ2ZzdtOXJIdi1KaGFMZ2xFdmV5MmZhdW0zR2VVdWhCX18xZ29ma2FOekxELUctWEVyODdhX01xWVZUZUplc2lvQ195SFRZbDVrZlRqTlFCdUF1d200TmtFQVpFYWVBM3Zvb3I5eUxYS0FCM2QteUxVVHprRVVvOTltQ05YcWpldDVQXzlNTDBHc0hqOXhvZUNRIn0sImF1ZCI6Ii16Ymx0M28wcGxPNnpndnROZDlwRCIsImV4cCI6MTU5NjUzNTg3MywiaWF0IjoxNTk2NTMyMjczLCJpc3MiOiJodHRwczovL2lkZW50aXR5LmRlbW8tZXNzLmlucnVwdC5jb20ifQ.OQ-rnZNquJ9VwuRictt76DW2AUZcLRKrTf5OhXTU4zq1lxAsDJtHH4Sbv0sg0FpYwp-N_G-09EusgoWa_oecSXJLlnt1KG7XSqHSsJVhoshhrfaReDOxHr8V2Q7heWMZF7UOVOjacHqp-56LZUlYB4fjm-UruncaPVtLoTGmnq6d2kVpZ0Uh-hwldEcRCZI_VPGx5BnSCq7_qUwahYkdeHWcxV9L7683H_IFn04PCZ-zvRjpwPgbLMszsxU09VCVRlwFBFgQrMfPIU_I8-zgGCeCgxKFijksrJkJKljjQHKttCWdoP9_UmJFQthq7pAqPAragH8rArBo4hpSRorgvQ',
      token_type: 'pop'
    },
    signatures: undefined,
    signature: 'k0VTE7sR0NoFCgMcZhmp1TzGKJ_7wMi7J4UoghCseWgn2ukgSSpzGzMO8-xJacfM8M3sPSKSTvcfaENUAFzciktkmORYVcBkoMNjzIY5KCS4jxRCbdwXxltyco5OuoCNkS11PDVf-XnoT5KfzOBiwYw5Guh5wTUKIzN4GmySfYH1BgGET6nRL9q3UhK5ePUY47fN6LRs83cdHsSVTn3mVN5655kImdZrjlQ04W7fqk9_c88NCN3bzKIibtsZdfJP9rV7daUciP0svwixf11lS6sat40OjZmL6mTXBLgKz_3D6dPZxcN6U-j_4bWJWsPel1EIj3cCw4WoGwgNH0sLSw',
    key: undefined,
    serialization: 'compact'

michielbdejong avatar Aug 04 '20 10:08 michielbdejong

And JWT.decode(credential.popToken.payload.id_token) at node_modules/@solid/oidc-rs/src/AuthenticatedRequest.js line 316 gives:

payload: {
    sub: 'https://ldp.demo-ess.inrupt.com/andydavison/profile/card#me',
    nonce: 'NUlz_TyDW27rvdzEAWsjche7jIuWFnLrS9DudmXXsnA',
    at_hash: 'SlS14VtP_J-UI6AropSEag',
    s_hash: 'irjUojKvP5OlulgMNoAF4A',
    cnf: {
      alg: 'RS256',
      e: 'AQAB',
      ext: true,
      key_ops: [Array],
      kty: 'RSA',
      n: 'lcDv7BxUDFctXYnxNGv8wrEpM95gCAaZmybFtdbE-F42WTgJepI_vmue6M4cVVf0F3BkKY5tT3RN2E82bZcOjkjLY-b1iOB9x2NlKGQPdZKUlGMaW6XigyPc0htav1TNCY3R_npvatv8KBZocPOFxGXVK6hWTAuigqLPBNY5Es6swwcnwh51WJNs6RnEYu1BjyiNvvg7m9rHv-JhaLglEvey2faum3GeUuhB__1gofkaNzLD-G-XEr87a_MqYVTeJesioC_yHTYl5kfTjNQBuAuwm4NkEAZEaeA3voor9yLXKAB3d-yLUTzkEUo99mCNXqjet5P_9ML0GsHj9xoeCQ'
    },
    aud: '-zblt3o0plO6zgvtNd9pD',
    exp: 1596535873,
    iat: 1596532273,
    iss: 'https://identity.demo-ess.inrupt.com'
  },
  signatures: undefined,
  signature: 'OQ-rnZNquJ9VwuRictt76DW2AUZcLRKrTf5OhXTU4zq1lxAsDJtHH4Sbv0sg0FpYwp-N_G-09EusgoWa_oecSXJLlnt1KG7XSqHSsJVhoshhrfaReDOxHr8V2Q7heWMZF7UOVOjacHqp-56LZUlYB4fjm-UruncaPVtLoTGmnq6d2kVpZ0Uh-hwldEcRCZI_VPGx5BnSCq7_qUwahYkdeHWcxV9L7683H_IFn04PCZ-zvRjpwPgbLMszsxU09VCVRlwFBFgQrMfPIU_I8-zgGCeCgxKFijksrJkJKljjQHKttCWdoP9_UmJFQthq7pAqPAragH8rArBo4hpSRorgvQ',
  key: undefined,
  serialization: 'compact'

michielbdejong avatar Aug 04 '20 10:08 michielbdejong

It's true that payload.cnf exists in the id token but not in the access token. So I think the client-side may be doing something wrong there. Can you point me to the "Storybook demo tool" you mentioned? Is that different from https://solidproject.org/for-developers/apps/first-app?

michielbdejong avatar Aug 04 '20 10:08 michielbdejong

Also, can you try your curl command without the -H 'Cookie: nssidp.sid=s%3AfuIM_1u9gAVOIFVP6c8o88_cz0aeNfyA.e0A5GMR%2F%2BbnimnqzvK7DkBkc2Ijg367lnX3NWpKNr2c' \ line and see if that changes the result?

When I try it, I get "empty reply from the server" and I have no way to check whether the resource changed on your pod.

michielbdejong avatar Aug 04 '20 10:08 michielbdejong

Ah sorry, Storybook is a tool for developing React (and other) components in isolation — I'm running it locally.

Making a similar request without the cookie gives the following response:

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Log in</title>
  <link rel="stylesheet" href="/common/css/bootstrap.min.css">
  <link rel="stylesheet" href="/common/css/solid.css">
</head>
<body>
<div class="container">
  <div class="page-header">
    <div class="pull-right">
      <button id="register" type="button" class="btn btn-primary">Register</button>
      <button id="login"    type="button" class="btn btn-success">Log in</button>
      <button id="logout"   type="button" class="hidden btn btn-danger">Log out</button>
    </div>
    <h1>Log in to access this resource</h1>
  </div>

  <div class="alert alert-danger">
    <p>
      The resource you are trying to access
      (<code>https://andydavison.inrupt.net/private/test1.jpg</code>)
      requires you to log in.
    </p>
  </div>

</div>
</div>
<script src="/common/js/solid-auth-client.bundle.js"></script>
<script src="/common/js/auth-buttons.js"></script>
</body>

andydavison avatar Aug 04 '20 11:08 andydavison

The full PUT calls seem to be failing now (ERR_EMPTY_RESPONSE), and I can see on the file explorer on inrupt.net that a test.jpg.lock file has been created…

andydavison avatar Aug 04 '20 11:08 andydavison