Check if email address can be used, and display perms in the test client

This commit is contained in:
Melon 2023-10-10 18:06:06 +01:00
parent c839fb1746
commit 340f1f9439
Signed by: melon
GPG Key ID: 6C9D970C50D26A25
2 changed files with 101 additions and 49 deletions

View File

@ -14,6 +14,7 @@ import (
"github.com/julienschmidt/httprouter" "github.com/julienschmidt/httprouter"
"golang.org/x/oauth2" "golang.org/x/oauth2"
"net/http" "net/http"
"net/mail"
"strings" "strings"
"time" "time"
) )
@ -45,6 +46,9 @@ func (h *HttpServer) flowPopupPost(rw http.ResponseWriter, req *http.Request, _
http.Error(rw, "No login service defined for this username", http.StatusBadRequest) http.Error(rw, "No login service defined for this username", http.StatusBadRequest)
return return
} }
// the @ must exist if the service is defined
n := strings.IndexByte(loginName, '@')
loginUn := loginName[:n]
targetOrigin := req.PostFormValue("origin") targetOrigin := req.PostFormValue("origin")
if _, found := h.services[targetOrigin]; !found { if _, found := h.services[targetOrigin]; !found {
@ -62,7 +66,7 @@ func (h *HttpServer) flowPopupPost(rw http.ResponseWriter, req *http.Request, _
// generate oauth2 config and redirect to authorize URL // generate oauth2 config and redirect to authorize URL
oa2conf := login.OAuth2Config oa2conf := login.OAuth2Config
oa2conf.RedirectURL = h.conf.BaseUrl + "/callback" oa2conf.RedirectURL = h.conf.BaseUrl + "/callback"
nextUrl := oa2conf.AuthCodeURL(state, oauth2.SetAuthURLParam("login_name", loginName)) nextUrl := oa2conf.AuthCodeURL(state, oauth2.SetAuthURLParam("login_name", loginUn))
http.Redirect(rw, req, nextUrl, http.StatusFound) http.Redirect(rw, req, nextUrl, http.StatusFound)
} }
@ -125,6 +129,26 @@ func (h *HttpServer) flowCallback(rw http.ResponseWriter, req *http.Request, _ h
} }
ps := claims.NewPermStorage() ps := claims.NewPermStorage()
if verified, ok := v3["email_verified"].(bool); ok && verified {
if mailAddress, ok := v3["email"].(string); ok {
address, err := mail.ParseAddress(mailAddress)
if err != nil {
http.Error(rw, "Invalid email in userinfo", http.StatusInternalServerError)
return
}
n := strings.IndexByte(address.Address, '@')
if n == -1 {
goto noEmailSupport
}
if address.Address[n+1:] != v.sso.Config.Namespace {
goto noEmailSupport
}
ps.Set("mail-client")
}
}
noEmailSupport:
nsSub := sub + "@" + v.sso.Config.Namespace nsSub := sub + "@" + v.sso.Config.Namespace
ati := uuidNewStringAti() ati := uuidNewStringAti()
accessToken, err := h.signer.GenerateJwt(nsSub, ati, jwt.ClaimStrings{aud}, 15*time.Minute, auth.AccessTokenClaims{ accessToken, err := h.signer.GenerateJwt(nsSub, ati, jwt.ClaimStrings{aud}, 15*time.Minute, auth.AccessTokenClaims{

View File

@ -3,60 +3,82 @@
<head> <head>
<title>Test Client</title> <title>Test Client</title>
<script> <script>
var currentLoginPopup = null; let currentLoginPopup = null;
window.addEventListener("message", function (event) { window.addEventListener("message", function (event) {
if (event.origin !== "http:\/\/localhost:9090") return; if (event.origin !== "http:\/\/localhost:9090") return;
if (isObject(event.data)) { if (isObject(event.data)) {
document.getElementById("someTextArea").textContent = JSON.stringify(event.data, null, 2); document.getElementById("someTextArea").textContent = JSON.stringify(event.data, null, 2);
if(currentLoginPopup) currentLoginPopup.close(); let perms = document.getElementById("somePerms");
return; perms.childNodes.forEach(function (x) {
} x.clear();
alert("Failed to log user in: the login data was probably corrupted"); });
}); let jwt = parseJwt(event.data.tokens.access);
if (jwt.per != null) {
jwt.per.forEach(function (x) {
let a = document.createElement("li");
a.textContent = x;
perms.appendChild(a);
});
}
function isObject(obj) { if (currentLoginPopup) currentLoginPopup.close();
return obj != null && obj.constructor.name === "Object" return;
} }
alert("Failed to log user in: the login data was probably corrupted");
});
function popupCenterScreen(url, title, w, h, focus) { function parseJwt(token) {
const top = (screen.availHeight - h) / 4, left = (screen.availWidth - w) / 2; const base64Url = token.split('.')[1];
const popup = openWindow(url, title, `scrollbars=yes,width=${w},height=${h},top=${top},left=${left}`); const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
if (focus === true && window.focus) popup.focus(); const jsonPayload = decodeURIComponent(window.atob(base64).split('').map(function (c) {
return popup; return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
} }).join(''));
return JSON.parse(jsonPayload);
}
function openWindow(url, winnm, options) { function isObject(obj) {
var wTop = firstAvailableValue([window.screen.availTop, window.screenY, window.screenTop, 0]); return obj != null && obj.constructor.name === "Object"
var wLeft = firstAvailableValue([window.screen.availLeft, window.screenX, window.screenLeft, 0]); }
var top = 0, left = 0;
var result;
if ((result = /top=(\d+)/g.exec(options))) top = parseInt(result[1]);
if ((result = /left=(\d+)/g.exec(options))) left = parseInt(result[1]);
if (options) {
options = options.replace("top=" + top, "top=" + (parseInt(top) + wTop));
options = options.replace("left=" + left, "left=" + (parseInt(left) + wLeft));
w = window.open(url, winnm, options);
} else w = window.open(url, winnm);
return w;
}
function firstAvailableValue(arr) { function popupCenterScreen(url, title, w, h, focus) {
for (var i = 0; i < arr.length; i++) const top = (screen.availHeight - h) / 4, left = (screen.availWidth - w) / 2;
if (typeof arr[i] != 'undefined') const popup = openWindow(url, title, `scrollbars=yes,width=${w},height=${h},top=${top},left=${left}`);
return arr[i]; if (focus === true && window.focus) popup.focus();
} return popup;
}
function doThisThing() { function openWindow(url, winnm, options) {
if(currentLoginPopup) currentLoginPopup.close(); var wTop = firstAvailableValue([window.screen.availTop, window.screenY, window.screenTop, 0]);
currentLoginPopup = popupCenterScreen('http://localhost:9090/popup?origin='+encodeURIComponent("http://localhost:2020"), 'Login with Lavender', 500, 500, false); var wLeft = firstAvailableValue([window.screen.availLeft, window.screenX, window.screenLeft, 0]);
} var top = 0, left = 0;
var result;
if ((result = /top=(\d+)/g.exec(options))) top = parseInt(result[1]);
if ((result = /left=(\d+)/g.exec(options))) left = parseInt(result[1]);
if (options) {
options = options.replace("top=" + top, "top=" + (parseInt(top) + wTop));
options = options.replace("left=" + left, "left=" + (parseInt(left) + wLeft));
w = window.open(url, winnm, options);
} else w = window.open(url, winnm);
return w;
}
function firstAvailableValue(arr) {
for (var i = 0; i < arr.length; i++)
if (typeof arr[i] != 'undefined')
return arr[i];
}
function doThisThing() {
if (currentLoginPopup) currentLoginPopup.close();
currentLoginPopup = popupCenterScreen('http://localhost:9090/popup?origin=' + encodeURIComponent("http://localhost:2020"), 'Login with Lavender', 500, 500, false);
}
</script> </script>
<style> <style>
#someTextArea { #someTextArea {
width: 400px; width: 400px;
height: 400px; height: 400px;
} }
</style> </style>
</head> </head>
<body> <body>
@ -67,8 +89,14 @@ function doThisThing() {
<div> <div>
<button onclick="doThisThing();">Login</button> <button onclick="doThisThing();">Login</button>
</div> </div>
<div> <div style="display:flex; gap: 2em;">
<textarea id="someTextArea"></textarea> <div>
<label for="someTextArea"></label><textarea id="someTextArea"></textarea>
</div>
<div>
<p>Permissions:</p>
<ul id="somePerms"></ul>
</div>
</div> </div>
</main> </main>
</body> </body>