Skip to content

Commit ef0630f

Browse files
authored
Merge pull request #2145 from maxberger/master
web ui: New setting for browser-based login
2 parents 10983fc + 19f9d0a commit ef0630f

7 files changed

Lines changed: 51 additions & 6 deletions

File tree

DOCUMENTATION.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1699,6 +1699,15 @@ Available backends are:
16991699
17001700
Default: `internal`
17011701
1702+
##### prefer_browser_login _(>= 3.7.4)_
1703+
1704+
Try to use browser based login rather than the built in login in the web UI. This
1705+
can be helpful if the login system you are using uses redirects, such as in
1706+
an OIDC setup. For this to work properly, you will also have to make sure CORS
1707+
headers are configured correctly.s
1708+
1709+
Default: `False`
1710+
17021711
#### [logging]
17031712
17041713
##### level

config

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,9 @@
363363
# Value: none | internal
364364
#type = internal
365365

366+
# Prefer browser login
367+
#prefer_browser_login = False
368+
366369

367370
[logging]
368371

radicale/config.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -691,7 +691,11 @@ def json_str_condition(value: Any) -> dict:
691691
"value": "internal",
692692
"help": "web interface backend",
693693
"type": str_or_callable,
694-
"internal": web.INTERNAL_TYPES})])),
694+
"internal": web.INTERNAL_TYPES}),
695+
("prefer_browser_login", {
696+
"value": "False",
697+
"help": "prefer browser login",
698+
"type": bool})])),
695699
("logging", OrderedDict([
696700
("level", {
697701
"value": "info",

radicale/tests/test_web.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ def test_internal(self) -> None:
3131
_, answer = self.get("/.web/")
3232
assert answer
3333
self.post("/.web", check=405)
34+
_, answer = self.get("/.web/js/config.js")
35+
assert "export const PREFER_BROWSER_LOGIN = false;" in answer
36+
self.configure({"web": {"prefer_browser_login": "True"}})
37+
_, answer = self.get("/.web/js/config.js")
38+
assert "export const PREFER_BROWSER_LOGIN = true;" in answer
3439

3540
def test_none(self) -> None:
3641
self.configure({"web": {"type": "none"}})

radicale/web/internal.py

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,27 @@
3434

3535
class Web(web.BaseWeb):
3636

37-
def get(self, environ: types.WSGIEnviron, base_prefix: str, path: str,
38-
user: str, request_info: dict) -> types.WSGIResponse:
39-
return httputils.serve_resource("radicale.web", "internal_data",
40-
base_prefix, path)
37+
def get(
38+
self,
39+
environ: types.WSGIEnviron,
40+
base_prefix: str,
41+
path: str,
42+
user: str,
43+
request_info: dict,
44+
) -> types.WSGIResponse:
45+
if path == "/.web/js/config.js":
46+
prefer_browser_login = (
47+
"true"
48+
if self.configuration.get("web", "prefer_browser_login")
49+
else "false"
50+
)
51+
content = (
52+
f"export const PREFER_BROWSER_LOGIN = {prefer_browser_login};\n".encode(
53+
"utf-8"
54+
)
55+
)
56+
headers = {"Content-Type": "application/javascript"}
57+
return 200, headers, content, None
58+
return httputils.serve_resource(
59+
"radicale.web", "internal_data", base_prefix, path
60+
)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// This file is dynamically overwritten during serving. The contents here are just to enable development an testing.
2+
3+
export const PREFER_BROWSER_LOGIN = false;

radicale/web/internal_data/js/scenes/LoginScene.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
*/
2121

2222
import { get_principal } from "../api/api.js";
23+
import { PREFER_BROWSER_LOGIN } from "../config.js";
2324
import { ROOT_PATH, SERVER } from "../constants.js";
2425
import { Collection } from "../models/collection.js";
2526
import { extract_title, extractUsernameFromPrincipalCollection } from "../utils/collection_utils.js";
@@ -167,7 +168,7 @@ export class LoginScene {
167168
fetch(SERVER + ROOT_PATH, {
168169
method: 'PROPFIND',
169170
headers: { 'Depth': '0' },
170-
credentials: 'omit'
171+
credentials: PREFER_BROWSER_LOGIN ? 'include' : 'omit'
171172
}).then((response) => {
172173
if (response.ok) {
173174
// Authenticated! Now it's safe to call get_principal

0 commit comments

Comments
 (0)