Seafile API and webdav through SSO

Note this thread: Authenticate to seafile APIs using Shibboleth, where daniel.pan sketched a way to access the API with Shibboleth. The same is possible with OIDC. However, OIDC does not have a specific success page in Seafile. Seafile’s OIDC callback (the page called by Keycloak upon successful login) is at /oauth/callback, and it displays your list of libraries (the usual Seafile home page).

One option is to include the below patch (based on 6.3.4) in seahub/seahub/templates/libraries.html. However, this is dangerous if you do not understand it! Make sure to set a very specific allowed origin in postMessage, because otherwise any site you open in your browser can steal your access token – simply by opening a new window with your Seafile instance while you are logged in.

--- libraries.html	2019-04-16 17:33:50.652115255 +0200
+++ libraries.html.modified	2019-04-16 17:33:00.622745013 +0200
@@ -313,6 +313,36 @@
     freezeItemHightlight: false
 };
 </script>
+
+<script>
+(function() {
+function getCookie(name) {
+    var cookieValue = null;
+    if (document.cookie && document.cookie != '') {
+        var cookies = document.cookie.split(';');
+        for (var i = 0; i < cookies.length; i++) {
+            var cookie = cookies[i].trim();
+            // Does this cookie string begin with the name we want?
+            if (cookie.substring(0, name.length + 1) == (name + '=')) {
+                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
+                break;
+            }
+        }
+    }
+    return cookieValue;
+}
+
+let seahub_auth_info = getCookie("seahub_auth");
+
+if (seahub_auth_info) {
+    window.parent.postMessage(seahub_auth_info, "https://www.example.com");
+    if (window.opener) {
+        window.opener.postMessage(seahub_auth_info, "https://www.example.com");
+    }
+}
+})();
+</script>
+
 {% if debug %}
 <script data-main="{% static "scripts/main.js" %}" src="{% static "scripts/lib/require.js" %}"></script>
 {% else %}

A “portal page” could then do something like this:

window.addEventListener("message", async (message) => {
	const data = JSON.parse(message.data).split("@");
	const token = data[data.length - 1];
	popup.close();

	let rawResponse = await fetch ("https://cloud.seafile.com/api2/account/info/", {
		headers: {authorization: "Token " + token}
	});
	let responseData = await rawResponse.json();
	console.log(responseData);
});
const popup = window.open("https://cloud.seafile.com/oauth/login/");