mirror of
https://github.com/casdoor/casdoor.git
synced 2025-07-02 11:20:18 +08:00
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:
@ -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"
|
@ -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)
|
||||
}
|
||||
|
@ -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),
|
||||
|
@ -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)}`;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
Reference in New Issue
Block a user