dasch-swiss / dsp-api

DaSCH Service Platform API
http://admin.dasch.swiss
Apache License 2.0
74 stars 18 forks source link

Have webapi send JWT to Sipi for auth #520

Closed benjamingeer closed 5 years ago

benjamingeer commented 7 years ago

The Knora API server can use JWT to authorise a user to upload files to Sipi, as well as to view files stored in Sipi.

Parts:

benjamingeer commented 5 years ago

we could implement it by not allowing direct access to Sipi, but only through Knora which will then talk to Sipi. Basically, create an authorization proxy route.

But that would still require an extra HTTP request (and triplestore query) per image, which is what we have already. The only difference would be the order of the requests: client -> Knora -> Sipi instead of the current client -> Sipi -> Knora.

subotic commented 5 years ago

After the token expires (10 minutes or so), the tokens would need to be refreshed somehow. We need a per image authorization route anyway. The question is who is going to do the refreshing.

  1. If we use the IIIF Authorization API then the client (IIIF viewer) needs to implement this feature, which if they have implemented the Authorization API they should have already done so.

  2. Let's assume viewers work with appended JWT tokens to the image URL, then the viewer will work for 10 minutes (or whatever the lifetime of the token is). After that, the whole page needs to be refreshed so that all image URLs with fresh tokens can be requested.

In case 1 only those tokens will be refreshed (and also initially requested), for images that are actually viewed. In case 2 all image tokens need to be refreshed every single time.

I think that case 1 is going to generating less traffic.

benjamingeer commented 5 years ago

This is not clear to me yet. In the case of (1), how does the viewer get the token representing the user's permissions on the image? And how does it send that token to Sipi? Or do you mean that in (1), no token is involved, and we use cookies instead?

subotic commented 5 years ago

in case (1) the viewer would go to the authentication endpoint specified in the manifest file to get the token and then use this token to access Sipi. Since we apparently can set a different authentication endpoint for each image, we can generate a token with permissions specific to each image.

Now the most important thing is that the viewer handles token expiration, i.e. re-authenticates itself for every image when the token expires.

subotic commented 5 years ago

maybe a quick Skype call?

benjamingeer commented 5 years ago

Yes, I’ll call you in 20 minutes or so.

subotic commented 5 years ago

So it looks like that using the IIIF Authentication API is not going to be trivial. After talking to @benjamingeer, we decided that the fastest way would be to use session cookies like in Salsah1.5, and let Sipi ask Knora for the user's permissions for each requested image. Knora will cache this information so that the load on the triplestore should not be too high.

The implementation would involve changing V2 authentication to also create a session cookie. Then all HTML img tag requests should automatically include this information when talking to Sipi.

@gfoo would this be alright with you for your February release?

subotic commented 5 years ago

I‘ve read the IIIF Authentication API spec and @benjamingeer you where right. Both cookies and tokens are used. Cookies for Content Resources (image) and tokens for Description Resources (info,json).

So our proposed first step of adding session creation to V2 authentication alongside token is completely in line with the IIIF spec.

gfoo commented 5 years ago

So it means that I can use a Sipi image URL directly in the html img src attribute if I use the v2 auth endpoint (what I do actually) ?

gfoo commented 5 years ago

Sipi and Knora being not the same server you are taking about Third-party cookies?

subotic commented 5 years ago

So it means that I can use a Sipi image URL directly in the html img src attribute if I use the v2 auth endpoint (what I do actually) ?

Yes, that would be the goal.

Sipi and Knora being not the same server you are taking about Third-party cookies?

The Sipi and Knora API endpoint need to be under the same domain, e.g., api.example.com and iiif.example.com. This is how we already deploy.

benjamingeer commented 5 years ago

The Sipi and Knora API endpoint need to be under the same domain

I thought the client had to log into Knora first, then log into Sipi, so Sipi could set a cookie containing the same session ID. Isn't this what the Sipi script Knora_login.lua is for?

subotic commented 5 years ago

thought the client had to log into Knora first, then log into Sipi, so Sipi could set a cookie containing the same session ID. Isn't this what the Sipi script Knora_login.lua is for?

Not anymore. I changed it in November or so for V1. The client only needs to login into Knora and the same cookie will then be used by Sipi.

The Knora_login.lua and Knora_logout.lua are not used anymore. The calls to those routes are commented out in Salsah1.

benjamingeer commented 5 years ago

OK great. In that case, could you please delete those scripts?

subotic commented 5 years ago

If somebody, for whatever reason, want's to have API on one domain and SIpi on another, then he would/could theoretically use those. But I don't think that we need to support this use case.

subotic commented 5 years ago

I will delete them.

loicjaouen commented 5 years ago

@subotic : so the browser is supposed to automatically send the session cookie received from knora to both knora and sipi? (if they are in the same domain)

subotic commented 5 years ago

Yes, exactly.

gfoo commented 5 years ago

Just tested #1165 and it works fine (don't know if Sipi correctly use the cookies sent by the browser to check the permissions but I can now see correctly the Sipi images from my Angular app)

subotic commented 5 years ago

Sipi should already use it. It is the way the Salsah1.5 GUI is working.

gfoo commented 5 years ago

Ok, it works from Salsah (dev stack) after having manually removed the cookie because logout seems to not do that, is something that I have to do (remove cookie) from my app when I logout from Knora using DELETE /v2/authentication or is it the Knora's responsibility?

loicjaouen commented 5 years ago

@gfoo , removing cookies is tricky as the http protocol defines only set-cookie and no remove-cookie. That leaves us with the only choice of override an existing cookie and changing the expiry date, but there is no guaranty that the browser will react as expected.

@subotic : I don't get the same result, using stock docker images dhlabbasel/webapi:4.0.0 and dhlabbasel/salsah1:4.0.0, login into knora doesn't add the domain directive, I see:

set-cookie: KnoraAuthentication=[cookie]; Path=/

where I expected and additional ; Domain=.example.com

should I use another tag?

subotic commented 5 years ago

or is it the Knora's responsibility?

Yes, Knora should send the same cookie with the changed expire date. What I have found, is that with Safari I need to refresh the browser to see that the cookie was removed.

subotic commented 5 years ago

where I expected and additional ; Domain=.example.com

Good catch. This needs to be set. The current implementation wouldn't work in production.

subotic commented 5 years ago

where I expected and additional ; Domain=.example.com

Good catch. This needs to be set. The current implementation wouldn't work in production.

should be fixed in #1170

gfoo commented 5 years ago

finally, not so sure that it works very well with Angular through their HttpClient, it worked a first time but not anymore :(

subotic commented 5 years ago

Cookies are a browser functionality. I don't think that it matters if Angular is used or not. Which browser are you using for testing? I find Safari better for the cookie stuff, as you can see the whole HTTP response header including the set-cookie header.

gfoo commented 5 years ago

If you want to quickly test login/logout with Angular without dev env: https://stackblitz.com/edit/angular-ea4gsz

subotic commented 5 years ago

This seems to work. I had to download and run it locally, because of the blocked mixed content (stackblitz is https and localhost is http).

You could make another button to check with Knora: GET /v2/authentication tries to authenticate the user and tells you the result.

gfoo commented 5 years ago

I updated the project, I can see the Set-Cookie: KnoraAuthentication=eyJ... in the response header by my browser definitely does not store the cookie.

capture d ecran 2019-01-17 a 18 15 07 capture d ecran 2019-01-17 a 18 13 47
subotic commented 5 years ago

I think that the cookie is there. Just to see it, you need to refresh the page.

gfoo commented 5 years ago

It works now because I added withCredentials=true :| (updated stackblitz) Maybe it is related to #1170 ?

gfoo commented 5 years ago

This is not related directly to Angular HttpClient but to XMLHttpRequest, see this test: https://gist.github.com/gfoo/6d9f449b55d4ae19fe8ecfcbfa1f70d8 For me, with or without withCredentials=true makes a difference.

subotic commented 5 years ago

withCredentials=true

Ah, yes. Now that you mention it. I have fallen for this one in the past. We have this set in Salsah1 (https://github.com/dhlab-basel/Knora/blob/ac2c9bafc4d211f126660cbf10e9f8330b1cb614/salsah1/src/public/js/01_salsah_api.js#L60-L62)

benjamingeer commented 5 years ago

Would it help to document that somewhere?

subotic commented 5 years ago

@kilchenmann For a future reference, don't forget to set withCredentials=true, when dealing with cookies.

subotic commented 5 years ago

Would it help to document that somewhere?

It is, kinda: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials ;-)

subotic commented 5 years ago

If someone writes it's own services, then this would be a thing that they should know. If they use our library, then this will be already set correctly.

gfoo commented 5 years ago

Don't know if it is clear but I use http://0.0.0.0:3333 as Knora base url to get cookie working from my Angular app, but as related in #1174 and #1130 my Sipi container for an unknown reason cannot access to 0.0.0.0, so (no more true) I use container name in docker compose file.

subotic commented 5 years ago

Yes, this is how it should work locally.

benjamingeer commented 5 years ago

Is this issue resolved? Can we close it?

gfoo commented 5 years ago

yes, thanks.