feat: support third-party application to login with SAML rather than only Casdoor itself (#350)

Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>
This commit is contained in:
Yixiang Zhao
2021-12-10 00:23:04 +08:00
committed by GitHub
parent 70a550d8bc
commit b73b9a65b6
5 changed files with 63 additions and 16 deletions

View File

@ -15,5 +15,4 @@ verificationCodeTimeout = 10
initScore = 2000
logPostOnly = true
oidcOrigin = "https://door.casbin.com"
samlOrigin = "http://localhost:8000"
samlRequestOrigin = "http://localhost:7001"
samlOrigin = "http://localhost:8000"

View File

@ -15,6 +15,7 @@
package controllers
import (
"encoding/base64"
"encoding/json"
"fmt"
"net/url"
@ -369,8 +370,14 @@ func (c *ApiController) GetSamlLogin() {
func (c *ApiController) HandleSamlLogin() {
relayState := c.Input().Get("RelayState")
samlResponse := c.Input().Get("SAMLResponse")
decode, err := base64.StdEncoding.DecodeString(relayState)
if err != nil {
c.ResponseError(err.Error())
}
slice := strings.Split(string(decode), "&")
relayState = url.QueryEscape(relayState)
samlResponse = url.QueryEscape(samlResponse)
targetUrl := fmt.Sprintf("%s/callback/saml?replayState=%s&samlResponse=%s",
beego.AppConfig.String("samlRequestOrigin"), relayState, samlResponse)
targetUrl := fmt.Sprintf("%s?relayState=%s&samlResponse=%s",
slice[4], relayState, samlResponse)
c.Redirect(targetUrl, 303)
}

View File

@ -84,8 +84,8 @@ export function getSamlLogin(providerId) {
}).then(res => res.json());
}
export function loginWithSaml(values) {
return fetch(`${authConfig.serverUrl}/api/login`, {
export function loginWithSaml(values, param) {
return fetch(`${authConfig.serverUrl}/api/login${param}`, {
method: 'POST',
credentials: "include",
body: JSON.stringify(values),

View File

@ -186,8 +186,15 @@ class LoginPage extends React.Component {
}
getSamlUrl(providerId) {
const params = new URLSearchParams(this.props.location.search);
let clientId = params.get("client_id")
let application = params.get("state");
let realRedirectUri = params.get("redirect_uri");
let redirectUri = `${window.location.origin}/callback/saml`
let providerName = providerId.split('/')[1];
AuthBackend.getSamlLogin(providerId).then((res) => {
window.location.href = res.data
const replyState = `${clientId}&${application}&${providerName}&${realRedirectUri}&${redirectUri}`;
window.location.href = `${res.data}&RelayState=${btoa(replyState)}`;
});
}

View File

@ -19,6 +19,7 @@ import * as AuthBackend from "./AuthBackend";
import * as Util from "./Util";
import * as Setting from "../Setting";
import i18next from "i18next";
import {authConfig} from "./Auth";
class SamlCallback extends React.Component {
constructor(props) {
@ -29,28 +30,61 @@ class SamlCallback extends React.Component {
};
}
getResponseType(redirectUri) {
const authServerUrl = authConfig.serverUrl;
// Casdoor's own login page, so "code" is not necessary
if (redirectUri === "null") {
return "login";
}
const realRedirectUrl = new URL(redirectUri).origin;
// For Casdoor itself, we use "login" directly
if (authServerUrl === realRedirectUrl) {
return "login";
} else {
return "code";
}
}
UNSAFE_componentWillMount() {
const params = new URLSearchParams(this.props.location.search);
let relayState = params.get('relayState')
let samlResponse = params.get('samlResponse')
let redirectUri = `${window.location.origin}/callback`;
const applicationName = "app-built-in"
const messages = atob(relayState).split('&');
const clientId = messages[0];
const applicationName = messages[1] === "null" ? "app-built-in" : messages[1];
const providerName = messages[2];
const redirectUri = messages[3];
const responseType = this.getResponseType(redirectUri);
const body = {
type: "login",
type: responseType,
application: applicationName,
provider: "aliyun-idaas",
provider: providerName,
state: applicationName,
redirectUri: redirectUri,
redirectUri: `${window.location.origin}/callback`,
method: "signup",
relayState: relayState,
samlResponse: encodeURIComponent(samlResponse),
};
AuthBackend.loginWithSaml(body)
let param;
if (clientId === null || clientId === "") {
param = ""
} else {
param = `?clientId=${clientId}&responseType=${responseType}&redirectUri=${redirectUri}&scope=read&state=${applicationName}`
}
AuthBackend.loginWithSaml(body, param)
.then((res) => {
if (res.status === 'ok') {
Util.showMessage("success", `Logged in successfully`);
// Setting.goToLinkSoft(this, "/");
Setting.goToLink("/");
const responseType = this.getResponseType(redirectUri);
if (responseType === "login") {
Util.showMessage("success", `Logged in successfully`);
Setting.goToLink("/");
} else if (responseType === "code") {
const code = res.data;
Setting.goToLink(`${redirectUri}?code=${code}&state=${applicationName}`);
}
} else {
this.setState({
msg: res.msg,