mirror of
https://github.com/casdoor/casdoor.git
synced 2025-07-31 17:10:32 +08:00
Compare commits
7 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
558bcf95d6 | ||
![]() |
bb937c30c1 | ||
![]() |
8dfdf7f767 | ||
![]() |
62b2082e82 | ||
![]() |
a1806439f8 | ||
![]() |
01e58158b7 | ||
![]() |
15427ad9d6 |
18
go.mod
18
go.mod
@@ -14,7 +14,7 @@ require (
|
||||
github.com/casbin/casbin/v2 v2.30.1
|
||||
github.com/casdoor/go-sms-sender v0.12.0
|
||||
github.com/casdoor/gomail/v2 v2.0.1
|
||||
github.com/casdoor/oss v1.2.1
|
||||
github.com/casdoor/oss v1.3.0
|
||||
github.com/casdoor/xorm-adapter/v3 v3.0.4
|
||||
github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f
|
||||
github.com/denisenkom/go-mssqldb v0.9.0
|
||||
@@ -28,9 +28,6 @@ require (
|
||||
github.com/go-sql-driver/mysql v1.6.0
|
||||
github.com/go-webauthn/webauthn v0.6.0
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/gorilla/mux v1.7.3 // indirect
|
||||
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect
|
||||
@@ -43,7 +40,7 @@ require (
|
||||
github.com/nyaruka/phonenumbers v1.1.5
|
||||
github.com/pquerna/otp v1.4.0
|
||||
github.com/prometheus/client_golang v1.11.1
|
||||
github.com/prometheus/client_model v0.2.0
|
||||
github.com/prometheus/client_model v0.3.0
|
||||
github.com/qiangmzsx/string-adapter/v2 v2.1.0
|
||||
github.com/robfig/cron/v3 v3.0.1
|
||||
github.com/russellhaering/gosaml2 v0.9.0
|
||||
@@ -53,7 +50,7 @@ require (
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible
|
||||
github.com/siddontang/go-log v0.0.0-20190221022429-1e957dd83bed
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
|
||||
github.com/stretchr/testify v1.8.2
|
||||
github.com/stretchr/testify v1.8.3
|
||||
github.com/tealeg/xlsx v1.0.5
|
||||
github.com/thanhpk/randstr v1.0.4
|
||||
github.com/tklauser/go-sysconf v0.3.10 // indirect
|
||||
@@ -61,12 +58,11 @@ require (
|
||||
github.com/xorm-io/core v0.7.4
|
||||
github.com/xorm-io/xorm v1.1.6
|
||||
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
||||
golang.org/x/crypto v0.6.0
|
||||
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect
|
||||
golang.org/x/net v0.7.0
|
||||
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914
|
||||
golang.org/x/crypto v0.11.0
|
||||
golang.org/x/net v0.13.0
|
||||
golang.org/x/oauth2 v0.10.0
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/square/go-jose.v2 v2.6.0
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
modernc.org/sqlite v1.10.1-0.20210314190707-798bbeb9bb84
|
||||
modernc.org/sqlite v1.18.2
|
||||
)
|
||||
|
@@ -269,6 +269,11 @@ func UpdatePolicy(oldPolicy, newPolicy []string, adapter *Adapter) (bool, error)
|
||||
if err != nil {
|
||||
return affected, err
|
||||
}
|
||||
err = adapter.SavePolicy(casbinModel)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return affected, nil
|
||||
}
|
||||
|
||||
@@ -285,6 +290,10 @@ func AddPolicy(policy []string, adapter *Adapter) (bool, error) {
|
||||
}
|
||||
|
||||
casbinModel.AddPolicy("p", "p", policy)
|
||||
err = adapter.SavePolicy(casbinModel)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
@@ -305,6 +314,11 @@ func RemovePolicy(policy []string, adapter *Adapter) (bool, error) {
|
||||
if err != nil {
|
||||
return affected, err
|
||||
}
|
||||
err = adapter.SavePolicy(casbinModel)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return affected, nil
|
||||
}
|
||||
|
||||
|
@@ -41,6 +41,7 @@ type LdapUser struct {
|
||||
GidNumber string `json:"gidNumber"`
|
||||
// Gcn string
|
||||
Uuid string `json:"uuid"`
|
||||
UserPrincipalName string `json:"userPrincipalName"`
|
||||
DisplayName string `json:"displayName"`
|
||||
Mail string
|
||||
Email string `json:"email"`
|
||||
@@ -51,9 +52,10 @@ type LdapUser struct {
|
||||
RegisteredAddress string
|
||||
PostalAddress string
|
||||
|
||||
GroupId string `json:"groupId"`
|
||||
Phone string `json:"phone"`
|
||||
Address string `json:"address"`
|
||||
GroupId string `json:"groupId"`
|
||||
Phone string `json:"phone"`
|
||||
Address string `json:"address"`
|
||||
MemberOf string `json:"memberOf"`
|
||||
}
|
||||
|
||||
func (ldap *Ldap) GetLdapConn() (c *LdapConn, err error) {
|
||||
@@ -168,6 +170,8 @@ func (l *LdapConn) GetLdapUsers(ldapServer *Ldap) ([]LdapUser, error) {
|
||||
user.Uuid = attribute.Values[0]
|
||||
case "objectGUID":
|
||||
user.Uuid = attribute.Values[0]
|
||||
case "userPrincipalName":
|
||||
user.UserPrincipalName = attribute.Values[0]
|
||||
case "displayName":
|
||||
user.DisplayName = attribute.Values[0]
|
||||
case "mail":
|
||||
@@ -186,6 +190,8 @@ func (l *LdapConn) GetLdapUsers(ldapServer *Ldap) ([]LdapUser, error) {
|
||||
user.RegisteredAddress = attribute.Values[0]
|
||||
case "postalAddress":
|
||||
user.PostalAddress = attribute.Values[0]
|
||||
case "memberOf":
|
||||
user.MemberOf = attribute.Values[0]
|
||||
}
|
||||
}
|
||||
ldapUsers = append(ldapUsers, user)
|
||||
|
@@ -254,7 +254,8 @@ func DeleteProvider(provider *Provider) (bool, error) {
|
||||
func (p *Provider) getPaymentProvider() (pp.PaymentProvider, *Cert, error) {
|
||||
cert := &Cert{}
|
||||
if p.Cert != "" {
|
||||
cert, err := getCert(p.Owner, p.Cert)
|
||||
var err error
|
||||
cert, err = getCert(p.Owner, p.Cert)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
@@ -55,12 +55,6 @@ func StaticFilter(ctx *context.Context) {
|
||||
path += urlPath
|
||||
}
|
||||
|
||||
path2 := strings.TrimPrefix(path, "web/build/images/")
|
||||
if util.FileExist(path2) {
|
||||
makeGzipResponse(ctx.ResponseWriter, ctx.Request, path2)
|
||||
return
|
||||
}
|
||||
|
||||
if !util.FileExist(path) {
|
||||
path = "web/build/index.html"
|
||||
}
|
||||
|
31
storage/google_cloud.go
Normal file
31
storage/google_cloud.go
Normal file
@@ -0,0 +1,31 @@
|
||||
// Copyright 2023 The Casdoor Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package storage
|
||||
|
||||
import (
|
||||
"github.com/casdoor/oss"
|
||||
"github.com/casdoor/oss/googlecloud"
|
||||
)
|
||||
|
||||
func NewGoogleCloudStorageProvider(clientId string, clientSecret string, bucket string, endpoint string) oss.StorageInterface {
|
||||
sp, _ := googlecloud.New(&googlecloud.Config{
|
||||
AccessID: clientId,
|
||||
AccessKey: clientSecret,
|
||||
Bucket: bucket,
|
||||
Endpoint: endpoint,
|
||||
})
|
||||
|
||||
return sp
|
||||
}
|
32
storage/qiniu_cloud.go
Normal file
32
storage/qiniu_cloud.go
Normal file
@@ -0,0 +1,32 @@
|
||||
// Copyright 2023 The Casdoor Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package storage
|
||||
|
||||
import (
|
||||
"github.com/casdoor/oss"
|
||||
"github.com/casdoor/oss/qiniu"
|
||||
)
|
||||
|
||||
func NewQiniuCloudKodoStorageProvider(clientId string, clientSecret string, region string, bucket string, endpoint string) oss.StorageInterface {
|
||||
sp := qiniu.New(&qiniu.Config{
|
||||
AccessID: clientId,
|
||||
AccessKey: clientSecret,
|
||||
Region: region,
|
||||
Bucket: bucket,
|
||||
Endpoint: endpoint,
|
||||
})
|
||||
|
||||
return sp
|
||||
}
|
@@ -30,6 +30,10 @@ func GetStorageProvider(providerType string, clientId string, clientSecret strin
|
||||
return NewTencentCloudCosStorageProvider(clientId, clientSecret, region, bucket, endpoint)
|
||||
case "Azure Blob":
|
||||
return NewAzureBlobStorageProvider(clientId, clientSecret, region, bucket, endpoint)
|
||||
case "Qiniu Cloud Kodo":
|
||||
return NewQiniuCloudKodoStorageProvider(clientId, clientSecret, region, bucket, endpoint)
|
||||
case "Google Cloud Storage":
|
||||
return NewGoogleCloudStorageProvider(clientId, clientSecret, bucket, endpoint)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@@ -25,5 +25,12 @@ func CasbinToSlice(casbinRule xormadapter.CasbinRule) []string {
|
||||
casbinRule.V4,
|
||||
casbinRule.V5,
|
||||
}
|
||||
// remove empty strings from end, for update model policy map
|
||||
for i := len(s) - 1; i >= 0; i-- {
|
||||
if s[i] != "" {
|
||||
s = s[:i+1]
|
||||
break
|
||||
}
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
@@ -644,7 +644,7 @@ class ProviderEditPage extends React.Component {
|
||||
</Col>
|
||||
</Row>
|
||||
)}
|
||||
{["Local File System", "MinIO", "Tencent Cloud COS"].includes(this.state.provider.type) ? null : (
|
||||
{["Local File System", "MinIO", "Tencent Cloud COS", "Google Cloud Storage", "Qiniu Cloud Kodo"].includes(this.state.provider.type) ? null : (
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={2}>
|
||||
{Setting.getLabel(i18next.t("provider:Endpoint (Intranet)"), i18next.t("provider:Region endpoint for Intranet"))} :
|
||||
@@ -678,7 +678,7 @@ class ProviderEditPage extends React.Component {
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
{["MinIO"].includes(this.state.provider.type) ? null : (
|
||||
{["MinIO", "Google Cloud Storage", "Qiniu Cloud Kodo"].includes(this.state.provider.type) ? null : (
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={2}>
|
||||
{Setting.getLabel(i18next.t("provider:Domain"), i18next.t("provider:Domain - Tooltip"))} :
|
||||
@@ -690,7 +690,7 @@ class ProviderEditPage extends React.Component {
|
||||
</Col>
|
||||
</Row>
|
||||
)}
|
||||
{["AWS S3", "Tencent Cloud COS"].includes(this.state.provider.type) ? (
|
||||
{["AWS S3", "Tencent Cloud COS", "Qiniu Cloud Kodo"].includes(this.state.provider.type) ? (
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={2}>
|
||||
{Setting.getLabel(i18next.t("provider:Region ID"), i18next.t("provider:Region ID - Tooltip"))} :
|
||||
|
@@ -37,7 +37,7 @@ class ProviderListPage extends BaseListPage {
|
||||
|
||||
newProvider() {
|
||||
const randomName = Setting.getRandomName();
|
||||
const owner = Setting.isDefaultOrganizationSelected(this.props.account) ? this.state.owner : Setting.getRequestOrganization();
|
||||
const owner = Setting.isDefaultOrganizationSelected(this.props.account) ? this.state.owner : Setting.getRequestOrganization(this.props.account);
|
||||
return {
|
||||
owner: owner,
|
||||
name: `provider_${randomName}`,
|
||||
|
@@ -177,6 +177,14 @@ export const OtherProviderInfo = {
|
||||
logo: `${StaticBaseUrl}/img/social_azure.png`,
|
||||
url: "https://azure.microsoft.com/en-us/services/storage/blobs/",
|
||||
},
|
||||
"Qiniu Cloud Kodo": {
|
||||
logo: `${StaticBaseUrl}/img/social_qiniu_cloud.png`,
|
||||
url: "https://www.qiniu.com/solutions/storage",
|
||||
},
|
||||
"Google Cloud Storage": {
|
||||
logo: `${StaticBaseUrl}/img/social_google_cloud.png`,
|
||||
url: "https://cloud.google.com/storage",
|
||||
},
|
||||
},
|
||||
SAML: {
|
||||
"Aliyun IDaaS": {
|
||||
@@ -901,6 +909,8 @@ export function getProviderTypeOptions(category) {
|
||||
{id: "Aliyun OSS", name: "Aliyun OSS"},
|
||||
{id: "Tencent Cloud COS", name: "Tencent Cloud COS"},
|
||||
{id: "Azure Blob", name: "Azure Blob"},
|
||||
{id: "Qiniu Cloud Kodo", name: "Qiniu Cloud Kodo"},
|
||||
{id: "Google Cloud Storage", name: "Google Cloud Storage"},
|
||||
]
|
||||
);
|
||||
} else if (category === "SAML") {
|
||||
|
@@ -133,13 +133,25 @@ class UserEditPage extends React.Component {
|
||||
|
||||
this.setState({
|
||||
application: res.data,
|
||||
isGroupsVisible: res.data?.organizationObj.accountItems?.some((item) => item.name === "Groups" && item.visible),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
getUserOrganization() {
|
||||
return this.state.organizations.filter(organization => organization.name === this.state.user.owner)[0];
|
||||
}
|
||||
|
||||
isGroupsVisible() {
|
||||
const organization = this.getUserOrganization();
|
||||
if (!organization) {
|
||||
return false;
|
||||
} else {
|
||||
return organization.accountItems?.some((item) => item.name === "Groups" && item.visible);
|
||||
}
|
||||
}
|
||||
|
||||
getGroups(organizationName) {
|
||||
if (this.state.isGroupsVisible) {
|
||||
if (this.isGroupsVisible()) {
|
||||
GroupBackend.getGroups(organizationName)
|
||||
.then((res) => {
|
||||
if (res.status === "ok") {
|
||||
@@ -401,7 +413,7 @@ class UserEditPage extends React.Component {
|
||||
{Setting.getLabel(i18next.t("general:Password"), i18next.t("general:Password - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<PasswordModal user={this.state.user} organization={this.state.application?.organizationObj} account={this.props.account} disabled={disabled} />
|
||||
<PasswordModal user={this.state.user} organization={this.getUserOrganization()} account={this.props.account} disabled={disabled} />
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
@@ -442,7 +454,7 @@ class UserEditPage extends React.Component {
|
||||
onChange={(value) => {
|
||||
this.updateUserField("countryCode", value);
|
||||
}}
|
||||
countryCodes={this.state.application?.organizationObj.countryCodes}
|
||||
countryCodes={this.getUserOrganization()?.countryCodes}
|
||||
/>
|
||||
<Input value={this.state.user.phone}
|
||||
style={{width: "70%"}}
|
||||
@@ -599,10 +611,10 @@ class UserEditPage extends React.Component {
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
{
|
||||
this.state.application?.organizationObj.tags?.length > 0 ? (
|
||||
this.getUserOrganization()?.tags?.length > 0 ? (
|
||||
<Select virtual={false} style={{width: "100%"}} value={this.state.user.tag}
|
||||
onChange={(value => {this.updateUserField("tag", value);})}
|
||||
options={this.state.application.organizationObj.tags?.map((tag) => {
|
||||
options={this.getUserOrganization()?.tags?.map((tag) => {
|
||||
const tokens = tag.split("|");
|
||||
const value = tokens[0];
|
||||
const displayValue = Setting.getLanguage() !== "zh" ? tokens[0] : tokens[1];
|
||||
@@ -888,7 +900,7 @@ class UserEditPage extends React.Component {
|
||||
{Setting.getLabel(i18next.t("mfa:Multi-factor authentication"), i18next.t("mfa:Multi-factor authentication - Tooltip "))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Card title={i18next.t("mfa:Multi-factor methods")}
|
||||
<Card size="small" title={i18next.t("mfa:Multi-factor methods")}
|
||||
extra={this.state.multiFactorAuths?.some(mfaProps => mfaProps.enabled) ?
|
||||
<PopconfirmModal
|
||||
text={i18next.t("general:Disable")}
|
||||
@@ -1008,7 +1020,7 @@ class UserEditPage extends React.Component {
|
||||
</div>
|
||||
} style={(Setting.isMobile()) ? {margin: "5px"} : {}} type="inner">
|
||||
{
|
||||
this.state.application?.organizationObj.accountItems?.map(accountItem => {
|
||||
this.getUserOrganization()?.accountItems?.map(accountItem => {
|
||||
return (
|
||||
<React.Fragment key={accountItem.name}>
|
||||
{
|
||||
|
@@ -287,10 +287,10 @@ class PolicyTable extends React.Component {
|
||||
) : (
|
||||
<div>
|
||||
<Tooltip placement="topLeft" title="Edit">
|
||||
<Button disabled={this.state.editingIndex !== ""} style={{marginRight: "5px"}} icon={<EditOutlined />} size="small" onClick={() => this.edit(record, index)} />
|
||||
<Button disabled={this.state.editingIndex !== "" || Setting.builtInObject({owner: this.props.owner, name: this.props.name})} style={{marginRight: "5px"}} icon={<EditOutlined />} size="small" onClick={() => this.edit(record, index)} />
|
||||
</Tooltip>
|
||||
<Tooltip placement="topLeft" title="Delete">
|
||||
<Button disabled={this.state.editingIndex !== ""} style={{marginRight: "5px"}} icon={<DeleteOutlined />} size="small" onClick={() => this.deletePolicy(table, index)} />
|
||||
<Button disabled={this.state.editingIndex !== "" || Setting.builtInObject({owner: this.props.owner, name: this.props.name})} style={{marginRight: "5px"}} icon={<DeleteOutlined />} size="small" onClick={() => this.deletePolicy(table, index)} />
|
||||
</Tooltip>
|
||||
</div>
|
||||
);
|
||||
@@ -304,14 +304,14 @@ class PolicyTable extends React.Component {
|
||||
onChange: (page) => this.setState({
|
||||
page: page,
|
||||
}),
|
||||
disabled: this.state.editingIndex !== "",
|
||||
disabled: this.state.editingIndex !== "" || Setting.builtInObject({owner: this.props.owner, name: this.props.name}),
|
||||
current: this.state.page,
|
||||
}}
|
||||
columns={columns} dataSource={table} rowKey="key" size="middle" bordered
|
||||
loading={this.state.loading}
|
||||
title={() => (
|
||||
<div>
|
||||
<Button disabled={this.state.editingIndex !== ""} style={{marginRight: "5px"}} type="primary" size="small" onClick={() => this.addRow(table)}>{i18next.t("general:Add")}</Button>
|
||||
<Button disabled={this.state.editingIndex !== "" || Setting.builtInObject({owner: this.props.owner, name: this.props.name})} style={{marginRight: "5px"}} type="primary" size="small" onClick={() => this.addRow(table)}>{i18next.t("general:Add")}</Button>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
|
Reference in New Issue
Block a user