Compare commits

..

7 Commits

Author SHA1 Message Date
e158b58ffa fix: add hidden signal to support chrome extension to auto-signin (#1109)
* feat: add hiden applicationName(support chrome extension to auto recognize applicationName)

* feat: add hiden applicationName for all page

* fix typo

* delete unuseful code

* remove hidden applicationName from login page

* prevent crash if signupApplication is null

* Update App.js

Co-authored-by: Gucheng <85475922+nomeguy@users.noreply.github.com>
2022-09-07 17:02:28 +08:00
a399184cfc fix: correct edit URL in model list (#1108)
Co-authored-by: Mario Fischer <mario.fischer@inmanet.de>
2022-09-07 00:54:27 +08:00
2f9f946c87 feat: fix GOPROXY bug by exporting environment variable (#1106) 2022-09-05 23:17:39 +08:00
d8b60f838e fix: fix bugs about 3rd-party login in cas flow (#1096) 2022-09-05 23:02:25 +08:00
7599e2715a feat: add demo mode (#1097)
* feat: add demo mode

* feat: add demo mode

* Update app.conf

* Update authz.go

* Update authz.go

Co-authored-by: Yang Luo <hsluoyz@qq.com>
2022-09-04 21:20:19 +08:00
35676455bc chore(style): add keyword spacing rule (#1098) 2022-09-04 19:40:30 +08:00
8128671c8c Improve email code 2022-09-04 12:15:07 +08:00
12 changed files with 75 additions and 13 deletions

View File

@ -128,6 +128,12 @@ p, *, *, GET, /api/get-release, *, *
} }
func IsAllowed(subOwner string, subName string, method string, urlPath string, objOwner string, objName string) bool { func IsAllowed(subOwner string, subName string, method string, urlPath string, objOwner string, objName string) bool {
if conf.IsDemoMode() {
if !isAllowedInDemoMode(subOwner, subName, method, urlPath, objOwner, objName) {
return false
}
}
res, err := Enforcer.Enforce(subOwner, subName, method, urlPath, objOwner, objName) res, err := Enforcer.Enforce(subOwner, subName, method, urlPath, objOwner, objName)
if err != nil { if err != nil {
panic(err) panic(err)
@ -135,3 +141,22 @@ func IsAllowed(subOwner string, subName string, method string, urlPath string, o
return res return res
} }
func isAllowedInDemoMode(subOwner string, subName string, method string, urlPath string, objOwner string, objName string) bool {
if method == "POST" {
if urlPath == "/api/login" || urlPath == "/api/logout" || urlPath == "/api/signup" || urlPath == "/api/send-verification-code" {
return true
} else if urlPath == "/api/update-user" {
// Allow ordinary users to update their own information
if subOwner == objOwner && subName == objName && !(subOwner == "built-in" && subName == "admin") {
return true
}
return false
} else {
return false
}
}
// If method equals GET
return true
}

View File

@ -6,6 +6,6 @@ then
echo "Successfully connected to Google, no need to use Go proxy" echo "Successfully connected to Google, no need to use Go proxy"
else else
echo "Google is blocked, Go proxy is enabled: GOPROXY=https://goproxy.cn,direct" echo "Google is blocked, Go proxy is enabled: GOPROXY=https://goproxy.cn,direct"
GO_PROXY_SETTING=$(GOPROXY=https://goproxy.cn,direct) export GOPROXY="https://goproxy.cn,direct"
fi fi
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 $GO_PROXY_SETTING go build -ldflags="-w -s" -o server . CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" -o server .

View File

@ -17,3 +17,4 @@ initScore = 2000
logPostOnly = true logPostOnly = true
origin = origin =
staticBaseUrl = "https://cdn.casbin.org" staticBaseUrl = "https://cdn.casbin.org"
isDemoMode = false

View File

@ -80,3 +80,7 @@ func GetBeegoConfDataSourceName() string {
return dataSourceName return dataSourceName
} }
func IsDemoMode() bool {
return strings.ToLower(GetConfigString("isDemoMode")) == "true"
}

View File

@ -47,7 +47,7 @@ func SendVerificationCodeToEmail(organization *Organization, user *User, provide
sender := organization.DisplayName sender := organization.DisplayName
title := provider.Title title := provider.Title
code := getRandomCode(5) code := getRandomCode(6)
// "You have requested a verification code at Casdoor. Here is your code: %s, please enter in 5 minutes." // "You have requested a verification code at Casdoor. Here is your code: %s, please enter in 5 minutes."
content := fmt.Sprintf(provider.Content, code) content := fmt.Sprintf(provider.Content, code)
@ -63,7 +63,7 @@ func SendVerificationCodeToPhone(organization *Organization, user *User, provide
return errors.New("please set a SMS provider first") return errors.New("please set a SMS provider first")
} }
code := getRandomCode(5) code := getRandomCode(6)
if err := SendSms(provider, code, dest); err != nil { if err := SendSms(provider, code, dest); err != nil {
return err return err
} }

View File

@ -97,6 +97,7 @@
"react/jsx-key": "error", "react/jsx-key": "error",
"no-console": "error", "no-console": "error",
"eqeqeq": "error", "eqeqeq": "error",
"keyword-spacing": "error",
"react/prop-types": "off", "react/prop-types": "off",
"react/display-name": "off", "react/display-name": "off",

View File

@ -527,7 +527,7 @@ class App extends Component {
} }
renderRouter() { renderRouter() {
return( return (
<div> <div>
<Switch> <Switch>
<Route exact path="/result" render={(props) => this.renderHomeIfLoggedIn(<ResultPage {...props} />)} /> <Route exact path="/result" render={(props) => this.renderHomeIfLoggedIn(<ResultPage {...props} />)} />
@ -618,7 +618,7 @@ class App extends Component {
</div> </div>
); );
} else { } else {
return( return (
<div> <div>
<Header style={{padding: "0", marginBottom: "3px"}}> <Header style={{padding: "0", marginBottom: "3px"}}>
{ {
@ -746,6 +746,7 @@ class App extends Component {
const organization = this.state.account.organization; const organization = this.state.account.organization;
return ( return (
<React.Fragment> <React.Fragment>
<div style={{display: "none"}} id="CasdoorApplicationName" value={this.state.account.signupApplication} />
<Helmet> <Helmet>
<title>{organization.displayName}</title> <title>{organization.displayName}</title>
<link rel="icon" href={organization.favicon} /> <link rel="icon" href={organization.favicon} />

View File

@ -88,7 +88,7 @@ class ModelListPage extends BaseListPage {
...this.getColumnSearchProps("name"), ...this.getColumnSearchProps("name"),
render: (text, record, index) => { render: (text, record, index) => {
return ( return (
<Link to={`/models/${text}`}> <Link to={`/models/${record.owner}/${text}`}>
{text} {text}
</Link> </Link>
); );

View File

@ -541,7 +541,7 @@ class ProviderEditPage extends React.Component {
{Setting.getLabel(i18next.t("provider:Email Content"), i18next.t("provider:Email Content - Tooltip"))} : {Setting.getLabel(i18next.t("provider:Email Content"), i18next.t("provider:Email Content - Tooltip"))} :
</Col> </Col>
<Col span={22} > <Col span={22} >
<TextArea autoSize={{minRows: 1, maxRows: 100}} value={this.state.provider.content} onChange={e => { <TextArea autoSize={{minRows: 3, maxRows: 100}} value={this.state.provider.content} onChange={e => {
this.updateProviderField("content", e.target.value); this.updateProviderField("content", e.target.value);
}} /> }} />
</Col> </Col>

View File

@ -450,9 +450,9 @@ export function trim(str, ch) {
let start = 0; let start = 0;
let end = str.length; let end = str.length;
while(start < end && str[start] === ch) {++start;} while (start < end && str[start] === ch) {++start;}
while(end > start && str[end - 1] === ch) {--end;} while (end > start && str[end - 1] === ch) {--end;}
return (start > 0 || end < str.length) ? str.substring(start, end) : str; return (start > 0 || end < str.length) ? str.substring(start, end) : str;
} }

View File

@ -50,8 +50,12 @@ class AuthCallback extends React.Component {
// Casdoor's own login page, so "code" is not necessary // Casdoor's own login page, so "code" is not necessary
if (realRedirectUri === null) { if (realRedirectUri === null) {
const samlRequest = innerParams.get("SAMLRequest"); const samlRequest = innerParams.get("SAMLRequest");
// cas don't use 'redirect_url', it is called 'service'
const casService = innerParams.get("service");
if (samlRequest !== null && samlRequest !== undefined && samlRequest !== "") { if (samlRequest !== null && samlRequest !== undefined && samlRequest !== "") {
return "saml"; return "saml";
} else if (casService !== null && casService !== undefined && casService !== "") {
return "cas";
} }
return "login"; return "login";
} }
@ -97,6 +101,7 @@ class AuthCallback extends React.Component {
const providerName = innerParams.get("provider"); const providerName = innerParams.get("provider");
const method = innerParams.get("method"); const method = innerParams.get("method");
const samlRequest = innerParams.get("SAMLRequest"); const samlRequest = innerParams.get("SAMLRequest");
const casService = innerParams.get("service");
const redirectUri = `${window.location.origin}/callback`; const redirectUri = `${window.location.origin}/callback`;
@ -111,6 +116,31 @@ class AuthCallback extends React.Component {
redirectUri: redirectUri, redirectUri: redirectUri,
method: method, method: method,
}; };
if (this.getResponseType() === "cas") {
// user is using casdoor as cas sso server, and wants the ticket to be acquired
AuthBackend.loginCas(body, {"service": casService}).then((res) => {
if (res.status === "ok") {
let msg = "Logged in successfully.";
if (casService === "") {
// If service was not specified, Casdoor must display a message notifying the client that it has successfully initiated a single sign-on session.
msg += "Now you can visit apps protected by Casdoor.";
}
Util.showMessage("success", msg);
if (casService !== "") {
const st = res.data;
const newUrl = new URL(casService);
newUrl.searchParams.append("ticket", st);
window.location.href = newUrl.toString();
}
} else {
Util.showMessage("error", `Failed to log in: ${res.msg}`);
}
});
return;
}
// OAuth
const oAuthParams = Util.getOAuthGetParameters(innerParams); const oAuthParams = Util.getOAuthGetParameters(innerParams);
const concatChar = oAuthParams?.redirectUri?.includes("?") ? "&" : "?"; const concatChar = oAuthParams?.redirectUri?.includes("?") ? "&" : "?";
AuthBackend.login(body, oAuthParams) AuthBackend.login(body, oAuthParams)

View File

@ -584,9 +584,9 @@ class SignupPage extends React.Component {
&nbsp;&nbsp;{i18next.t("signup:Have account?")}&nbsp; &nbsp;&nbsp;{i18next.t("signup:Have account?")}&nbsp;
<a onClick={() => { <a onClick={() => {
const linkInStorage = sessionStorage.getItem("signinUrl"); const linkInStorage = sessionStorage.getItem("signinUrl");
if(linkInStorage !== null && linkInStorage !== "") { if (linkInStorage !== null && linkInStorage !== "") {
Setting.goToLink(linkInStorage); Setting.goToLink(linkInStorage);
}else{ } else {
Setting.goToLogin(this, application); Setting.goToLogin(this, application);
} }
}}> }}>