mirror of
https://github.com/casdoor/casdoor.git
synced 2025-07-23 22:53:31 +08:00
Compare commits
24 Commits
Author | SHA1 | Date | |
---|---|---|---|
5ec0c7a890 | |||
051752340d | |||
c87c001da3 | |||
12bc419659 | |||
d5f18f2d64 | |||
02c06bc93c | |||
40aa9a4693 | |||
630b84f534 | |||
339a85e4b0 | |||
c22ab44894 | |||
c3fb48f473 | |||
a111fd672c | |||
9fd175eefd | |||
d9bcce9485 | |||
d183b9eca9 | |||
f24d9ae251 | |||
030c1caa50 | |||
cee2c608a2 | |||
82d0e895e0 | |||
dee9bac110 | |||
e7a6986b62 | |||
b91b4aec91 | |||
fe48c38bc6 | |||
1be777c08f |
@ -32,5 +32,5 @@ COPY --from=BACK /go/src/casdoor/ ./
|
||||
COPY --from=BACK /usr/bin/wait-for-it ./
|
||||
RUN mkdir -p web/build && apk add --no-cache bash coreutils
|
||||
COPY --from=FRONT /web/build /web/build
|
||||
CMD ./wait-for-it db:3306 -- ./server
|
||||
CMD ./server
|
||||
|
||||
|
20
README.md
20
README.md
@ -7,10 +7,10 @@
|
||||
<a href="https://hub.docker.com/r/casbin/casdoor">
|
||||
<img alt="docker pull casbin/casdoor" src="https://img.shields.io/docker/pulls/casbin/casdoor.svg">
|
||||
</a>
|
||||
<a href="https://github.com/casbin/casdoor/actions/workflows/build.yml">
|
||||
<a href="https://github.com/casdoor/casdoor/actions/workflows/build.yml">
|
||||
<img alt="GitHub Workflow Status (branch)" src="https://github.com/casbin/jcasbin/workflows/build/badge.svg?style=flat-square">
|
||||
</a>
|
||||
<a href="https://github.com/casbin/casdoor/releases/latest">
|
||||
<a href="https://github.com/casdoor/casdoor/releases/latest">
|
||||
<img alt="GitHub Release" src="https://img.shields.io/github/v/release/casbin/casdoor.svg">
|
||||
</a>
|
||||
<a href="https://hub.docker.com/repository/docker/casbin/casdoor">
|
||||
@ -19,19 +19,19 @@
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://goreportcard.com/report/github.com/casbin/casdoor">
|
||||
<img alt="Go Report Card" src="https://goreportcard.com/badge/github.com/casbin/casdoor?style=flat-square">
|
||||
<a href="https://goreportcard.com/report/github.com/casdoor/casdoor">
|
||||
<img alt="Go Report Card" src="https://goreportcard.com/badge/github.com/casdoor/casdoor?style=flat-square">
|
||||
</a>
|
||||
<a href="https://github.com/casbin/casdoor/blob/master/LICENSE">
|
||||
<a href="https://github.com/casdoor/casdoor/blob/master/LICENSE">
|
||||
<img src="https://img.shields.io/github/license/casbin/casdoor?style=flat-square" alt="license">
|
||||
</a>
|
||||
<a href="https://github.com/casbin/casdoor/issues">
|
||||
<a href="https://github.com/casdoor/casdoor/issues">
|
||||
<img alt="GitHub issues" src="https://img.shields.io/github/issues/casbin/casdoor?style=flat-square">
|
||||
</a>
|
||||
<a href="#">
|
||||
<img alt="GitHub stars" src="https://img.shields.io/github/stars/casbin/casdoor?style=flat-square">
|
||||
</a>
|
||||
<a href="https://github.com/casbin/casdoor/network">
|
||||
<a href="https://github.com/casdoor/casdoor/network">
|
||||
<img alt="GitHub forks" src="https://img.shields.io/github/forks/casbin/casdoor?style=flat-square">
|
||||
</a>
|
||||
<a href="https://crowdin.com/project/casdoor-site">
|
||||
@ -54,13 +54,13 @@ Run your own casdoor program in a few minutes.
|
||||
There are two methods, get code via go subcommand `get`:
|
||||
|
||||
```shell
|
||||
go get github.com/casbin/casdoor
|
||||
go get github.com/casdoor/casdoor
|
||||
```
|
||||
|
||||
or `git`:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/casbin/casdoor
|
||||
git clone https://github.com/casdoor/casdoor
|
||||
```
|
||||
|
||||
Finally, change directory:
|
||||
@ -182,5 +182,5 @@ If you are contributing to casdoor, please note that we use [Crowdin](https://cr
|
||||
|
||||
## License
|
||||
|
||||
[Apache-2.0](https://github.com/casbin/casdoor/blob/master/LICENSE)
|
||||
[Apache-2.0](https://github.com/casdoor/casdoor/blob/master/LICENSE)
|
||||
|
||||
|
@ -18,8 +18,8 @@ import (
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/casbin/casbin/v2"
|
||||
"github.com/casbin/casbin/v2/model"
|
||||
"github.com/casbin/casdoor/conf"
|
||||
xormadapter "github.com/casbin/xorm-adapter/v2"
|
||||
"github.com/casdoor/casdoor/conf"
|
||||
stringadapter "github.com/qiangmzsx/string-adapter/v2"
|
||||
)
|
||||
|
||||
@ -28,7 +28,8 @@ var Enforcer *casbin.Enforcer
|
||||
func InitAuthz() {
|
||||
var err error
|
||||
|
||||
a, err := xormadapter.NewAdapter(beego.AppConfig.String("driverName"), conf.GetBeegoConfDataSourceName()+beego.AppConfig.String("dbName"), true)
|
||||
tableNamePrefix := beego.AppConfig.String("tableNamePrefix")
|
||||
a, err := xormadapter.NewAdapterWithTableName(beego.AppConfig.String("driverName"), conf.GetBeegoConfDataSourceName()+beego.AppConfig.String("dbName"), "casbin_rule", tableNamePrefix, true)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@ -79,6 +80,7 @@ p, *, *, POST, /api/login, *, *
|
||||
p, *, *, GET, /api/get-app-login, *, *
|
||||
p, *, *, POST, /api/logout, *, *
|
||||
p, *, *, GET, /api/get-account, *, *
|
||||
p, *, *, GET, /api/userinfo, *, *
|
||||
p, *, *, POST, /api/login/oauth/access_token, *, *
|
||||
p, *, *, POST, /api/login/oauth/refresh_token, *, *
|
||||
p, *, *, GET, /api/get-application, *, *
|
||||
|
@ -6,6 +6,8 @@ copyrequestbody = true
|
||||
driverName = mysql
|
||||
dataSourceName = root:123456@tcp(localhost:3306)/
|
||||
dbName = casdoor
|
||||
tableNamePrefix =
|
||||
showSql = false
|
||||
redisEndpoint =
|
||||
defaultStorageProvider =
|
||||
isCloudIntranet = false
|
||||
|
@ -18,9 +18,11 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/casbin/casdoor/object"
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -67,6 +69,18 @@ type Response struct {
|
||||
Data2 interface{} `json:"data2"`
|
||||
}
|
||||
|
||||
type Userinfo struct {
|
||||
Sub string `json:"sub"`
|
||||
Iss string `json:"iss"`
|
||||
Aud string `json:"aud"`
|
||||
Name string `json:"name,omitempty"`
|
||||
DisplayName string `json:"preferred_username,omitempty"`
|
||||
Email string `json:"email,omitempty"`
|
||||
Avatar string `json:"picture,omitempty"`
|
||||
Address string `json:"address,omitempty"`
|
||||
Phone string `json:"phone,omitempty"`
|
||||
}
|
||||
|
||||
type HumanCheck struct {
|
||||
Type string `json:"type"`
|
||||
AppKey string `json:"appKey"`
|
||||
@ -231,6 +245,47 @@ func (c *ApiController) GetAccount() {
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
// UserInfo
|
||||
// @Title UserInfo
|
||||
// @Tag Account API
|
||||
// @Description return user information according to OIDC standards
|
||||
// @Success 200 {object} controllers.Userinfo The Response object
|
||||
// @router /userinfo [get]
|
||||
func (c *ApiController) GetUserinfo() {
|
||||
userId, ok := c.RequireSignedIn()
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
user := object.GetUser(userId)
|
||||
if user == nil {
|
||||
c.ResponseError(fmt.Sprintf("The user: %s doesn't exist", userId))
|
||||
return
|
||||
}
|
||||
scope, aud := c.GetSessionOidc()
|
||||
iss := beego.AppConfig.String("origin")
|
||||
resp := Userinfo{
|
||||
Sub: user.Id,
|
||||
Iss: iss,
|
||||
Aud: aud,
|
||||
}
|
||||
if strings.Contains(scope, "profile") {
|
||||
resp.Name = user.Name
|
||||
resp.DisplayName = user.DisplayName
|
||||
resp.Avatar = user.Avatar
|
||||
}
|
||||
if strings.Contains(scope, "email") {
|
||||
resp.Email = user.Email
|
||||
}
|
||||
if strings.Contains(scope, "address") {
|
||||
resp.Address = user.Location
|
||||
}
|
||||
if strings.Contains(scope, "phone") {
|
||||
resp.Phone = user.Phone
|
||||
}
|
||||
c.Data["json"] = resp
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
// GetHumanCheck ...
|
||||
// @Tag Login API
|
||||
// @Title GetHumancheck
|
||||
|
@ -18,8 +18,8 @@ import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/astaxie/beego/utils/pagination"
|
||||
"github.com/casbin/casdoor/object"
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
|
||||
// GetApplications
|
||||
@ -38,8 +38,17 @@ func (c *ApiController) GetApplications() {
|
||||
value := c.Input().Get("value")
|
||||
sortField := c.Input().Get("sortField")
|
||||
sortOrder := c.Input().Get("sortOrder")
|
||||
organization := c.Input().Get("organization")
|
||||
|
||||
if limit == "" || page == "" {
|
||||
c.Data["json"] = object.GetMaskedApplications(object.GetApplications(owner), userId)
|
||||
var applications []*object.Application
|
||||
if organization == "" {
|
||||
applications = object.GetApplications(owner)
|
||||
} else {
|
||||
applications = object.GetApplicationsByOrganizationName(owner, organization)
|
||||
}
|
||||
|
||||
c.Data["json"] = object.GetMaskedApplications(applications, userId)
|
||||
c.ServeJSON()
|
||||
} else {
|
||||
limit := util.ParseInt(limit)
|
||||
|
@ -24,10 +24,10 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/casbin/casdoor/idp"
|
||||
"github.com/casbin/casdoor/object"
|
||||
"github.com/casbin/casdoor/proxy"
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/casdoor/casdoor/idp"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/proxy"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
|
||||
func codeToResponse(code *object.Code) *Response {
|
||||
@ -52,7 +52,14 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
|
||||
scope := c.Input().Get("scope")
|
||||
state := c.Input().Get("state")
|
||||
nonce := c.Input().Get("nonce")
|
||||
code := object.GetOAuthCode(userId, clientId, responseType, redirectUri, scope, state, nonce)
|
||||
challengeMethod := c.Input().Get("code_challenge_method")
|
||||
codeChallenge := c.Input().Get("code_challenge")
|
||||
|
||||
if challengeMethod != "S256" && challengeMethod != "null" {
|
||||
c.ResponseError("Challenge method should be S256")
|
||||
return
|
||||
}
|
||||
code := object.GetOAuthCode(userId, clientId, responseType, redirectUri, scope, state, nonce, codeChallenge)
|
||||
resp = codeToResponse(code)
|
||||
|
||||
if application.EnableSigninSession || application.HasPromptPage() {
|
||||
|
@ -15,10 +15,12 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
|
||||
// controller for handlers under /api uri
|
||||
@ -35,6 +37,21 @@ type SessionData struct {
|
||||
ExpireTime int64
|
||||
}
|
||||
|
||||
func (c *ApiController) IsGlobalAdmin() bool {
|
||||
username := c.GetSessionUsername()
|
||||
if strings.HasPrefix(username, "app/") {
|
||||
// e.g., "app/app-casnode"
|
||||
return true
|
||||
}
|
||||
|
||||
user := object.GetUser(username)
|
||||
if user == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return user.Owner == "built-in" || user.IsGlobalAdmin
|
||||
}
|
||||
|
||||
// GetSessionUsername ...
|
||||
func (c *ApiController) GetSessionUsername() string {
|
||||
// check if user session expired
|
||||
@ -55,6 +72,28 @@ func (c *ApiController) GetSessionUsername() string {
|
||||
return user.(string)
|
||||
}
|
||||
|
||||
func (c *ApiController) GetSessionOidc() (string, string) {
|
||||
sessionData := c.GetSessionData()
|
||||
if sessionData != nil &&
|
||||
sessionData.ExpireTime != 0 &&
|
||||
sessionData.ExpireTime < time.Now().Unix() {
|
||||
c.SetSessionUsername("")
|
||||
c.SetSessionData(nil)
|
||||
return "", ""
|
||||
}
|
||||
scopeValue := c.GetSession("scope")
|
||||
audValue := c.GetSession("aud")
|
||||
var scope, aud string
|
||||
var ok bool
|
||||
if scope, ok = scopeValue.(string); !ok {
|
||||
scope = ""
|
||||
}
|
||||
if aud, ok = audValue.(string); !ok {
|
||||
aud = ""
|
||||
}
|
||||
return scope, aud
|
||||
}
|
||||
|
||||
// SetSessionUsername ...
|
||||
func (c *ApiController) SetSessionUsername(user string) {
|
||||
c.SetSession("username", user)
|
||||
|
@ -18,8 +18,8 @@ import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/astaxie/beego/utils/pagination"
|
||||
"github.com/casbin/casdoor/object"
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
|
||||
// GetCerts
|
||||
|
@ -17,8 +17,8 @@ package controllers
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/casbin/casdoor/object"
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
|
||||
type LdapServer struct {
|
||||
|
@ -17,7 +17,7 @@ package controllers
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/casbin/casdoor/object"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
)
|
||||
|
||||
type LinkForm struct {
|
||||
|
@ -14,7 +14,7 @@
|
||||
|
||||
package controllers
|
||||
|
||||
import "github.com/casbin/casdoor/object"
|
||||
import "github.com/casdoor/casdoor/object"
|
||||
|
||||
// @Title GetOidcDiscovery
|
||||
// @Tag OIDC API
|
||||
|
@ -18,8 +18,8 @@ import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/astaxie/beego/utils/pagination"
|
||||
"github.com/casbin/casdoor/object"
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
|
||||
// GetOrganizations ...
|
||||
|
@ -18,8 +18,8 @@ import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/astaxie/beego/utils/pagination"
|
||||
"github.com/casbin/casdoor/object"
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
|
||||
// GetPermissions
|
||||
|
@ -17,8 +17,8 @@ package controllers
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/astaxie/beego/utils/pagination"
|
||||
"github.com/casbin/casdoor/object"
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
|
||||
// GetProviders
|
||||
|
@ -16,8 +16,8 @@ package controllers
|
||||
|
||||
import (
|
||||
"github.com/astaxie/beego/utils/pagination"
|
||||
"github.com/casbin/casdoor/object"
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
|
||||
// GetRecords
|
||||
|
@ -23,8 +23,8 @@ import (
|
||||
"path/filepath"
|
||||
|
||||
"github.com/astaxie/beego/utils/pagination"
|
||||
"github.com/casbin/casdoor/object"
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
|
||||
// @router /get-resources [get]
|
||||
@ -202,7 +202,7 @@ func (c *ApiController) UploadResource() {
|
||||
}
|
||||
|
||||
user.Avatar = fileUrl
|
||||
object.UpdateUser(user.GetId(), user, []string{"avatar"})
|
||||
object.UpdateUser(user.GetId(), user, []string{"avatar"}, false)
|
||||
case "termsOfUse":
|
||||
applicationId := fmt.Sprintf("admin/%s", parent)
|
||||
app := object.GetApplication(applicationId)
|
||||
|
@ -18,8 +18,8 @@ import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/astaxie/beego/utils/pagination"
|
||||
"github.com/casbin/casdoor/object"
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
|
||||
// GetRoles
|
||||
|
@ -21,8 +21,8 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/casbin/casdoor/object"
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
|
||||
// SendEmail
|
||||
|
@ -18,8 +18,8 @@ import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/astaxie/beego/utils/pagination"
|
||||
"github.com/casbin/casdoor/object"
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
|
||||
// GetSyncers
|
||||
|
@ -18,8 +18,8 @@ import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/astaxie/beego/utils/pagination"
|
||||
"github.com/casbin/casdoor/object"
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
|
||||
// GetTokens
|
||||
@ -142,7 +142,15 @@ func (c *ApiController) GetOAuthCode() {
|
||||
state := c.Input().Get("state")
|
||||
nonce := c.Input().Get("nonce")
|
||||
|
||||
c.Data["json"] = object.GetOAuthCode(userId, clientId, responseType, redirectUri, scope, state, nonce)
|
||||
challengeMethod := c.Input().Get("code_challenge_method")
|
||||
codeChallenge := c.Input().Get("code_challenge")
|
||||
|
||||
if challengeMethod != "S256" && challengeMethod != "null" {
|
||||
c.ResponseError("Challenge method should be S256")
|
||||
return
|
||||
}
|
||||
|
||||
c.Data["json"] = object.GetOAuthCode(userId, clientId, responseType, redirectUri, scope, state, nonce, codeChallenge)
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
@ -161,12 +169,13 @@ func (c *ApiController) GetOAuthToken() {
|
||||
clientId := c.Input().Get("client_id")
|
||||
clientSecret := c.Input().Get("client_secret")
|
||||
code := c.Input().Get("code")
|
||||
verifier := c.Input().Get("code_verifier")
|
||||
|
||||
if clientId == "" && clientSecret == "" {
|
||||
clientId, clientSecret, _ = c.Ctx.Request.BasicAuth()
|
||||
}
|
||||
|
||||
c.Data["json"] = object.GetOAuthToken(grantType, clientId, clientSecret, code)
|
||||
c.Data["json"] = object.GetOAuthToken(grantType, clientId, clientSecret, code, verifier)
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
|
@ -20,8 +20,8 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/astaxie/beego/utils/pagination"
|
||||
"github.com/casbin/casdoor/object"
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
|
||||
// GetGlobalUsers
|
||||
@ -125,7 +125,8 @@ func (c *ApiController) UpdateUser() {
|
||||
columns = strings.Split(columnsStr, ",")
|
||||
}
|
||||
|
||||
affected := object.UpdateUser(id, &user, columns)
|
||||
isGlobalAdmin := c.IsGlobalAdmin()
|
||||
affected := object.UpdateUser(id, &user, columns, isGlobalAdmin)
|
||||
if affected {
|
||||
object.UpdateUserToOriginalDatabase(&user)
|
||||
}
|
||||
|
@ -20,8 +20,8 @@ import (
|
||||
"mime/multipart"
|
||||
"os"
|
||||
|
||||
"github.com/casbin/casdoor/object"
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
|
||||
func saveFile(path string, file *multipart.File) {
|
||||
|
@ -19,8 +19,8 @@ import (
|
||||
"strconv"
|
||||
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/casbin/casdoor/object"
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
|
||||
// ResponseOk ...
|
||||
|
@ -19,8 +19,8 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/casbin/casdoor/object"
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
|
||||
func (c *ApiController) getCurrentUser() *object.User {
|
||||
|
@ -18,8 +18,8 @@ import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/astaxie/beego/utils/pagination"
|
||||
"github.com/casbin/casdoor/object"
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
|
||||
// GetWebhooks
|
||||
|
@ -1,5 +1,6 @@
|
||||
version: '3.1'
|
||||
services:
|
||||
restart: always
|
||||
casdoor:
|
||||
build:
|
||||
context: ./
|
||||
|
6
go.mod
6
go.mod
@ -1,4 +1,4 @@
|
||||
module github.com/casbin/casdoor
|
||||
module github.com/casdoor/casdoor
|
||||
|
||||
go 1.16
|
||||
|
||||
@ -8,7 +8,7 @@ require (
|
||||
github.com/aws/aws-sdk-go v1.37.30
|
||||
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f // indirect
|
||||
github.com/casbin/casbin/v2 v2.30.1
|
||||
github.com/casbin/xorm-adapter/v2 v2.3.1
|
||||
github.com/casbin/xorm-adapter/v2 v2.5.1
|
||||
github.com/casdoor/go-sms-sender v0.0.5
|
||||
github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f
|
||||
github.com/go-gomail/gomail v0.0.0-20160411212932-81ebce5c23df
|
||||
@ -18,9 +18,9 @@ require (
|
||||
github.com/google/uuid v1.2.0
|
||||
github.com/jinzhu/configor v1.2.1 // indirect
|
||||
github.com/markbates/goth v1.68.1-0.20211006204042-9dc8905b41c8
|
||||
github.com/mileusna/crontab v1.0.1
|
||||
github.com/qiangmzsx/string-adapter/v2 v2.1.0
|
||||
github.com/qor/oss v0.0.0-20191031055114-aef9ba66bf76
|
||||
github.com/robfig/cron/v3 v3.0.1
|
||||
github.com/russellhaering/gosaml2 v0.6.0
|
||||
github.com/russellhaering/goxmldsig v1.1.1
|
||||
github.com/satori/go.uuid v1.2.0 // indirect
|
||||
|
10
go.sum
10
go.sum
@ -74,11 +74,11 @@ github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6
|
||||
github.com/casbin/casbin v1.7.0 h1:PuzlE8w0JBg/DhIqnkF1Dewf3z+qmUZMVN07PonvVUQ=
|
||||
github.com/casbin/casbin v1.7.0/go.mod h1:c67qKN6Oum3UF5Q1+BByfFxkwKvhwW57ITjqwtzR1KE=
|
||||
github.com/casbin/casbin/v2 v2.1.0/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
|
||||
github.com/casbin/casbin/v2 v2.25.5/go.mod h1:wUgota0cQbTXE6Vd+KWpg41726jFRi7upxio0sR+Xd0=
|
||||
github.com/casbin/casbin/v2 v2.28.3/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg=
|
||||
github.com/casbin/casbin/v2 v2.30.1 h1:P5HWadDL7olwUXNdcuKUBk+x75Y2eitFxYTcLNKeKF0=
|
||||
github.com/casbin/casbin/v2 v2.30.1/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg=
|
||||
github.com/casbin/xorm-adapter/v2 v2.3.1 h1:RVGsM6KYFP9s4OQJXrP/gv56Wmt5P40mzvcyXgv5xeg=
|
||||
github.com/casbin/xorm-adapter/v2 v2.3.1/go.mod h1:GZ+nlIdasVFunQ71SlvkL/HcQQBvFncphDf+2Yl167c=
|
||||
github.com/casbin/xorm-adapter/v2 v2.5.1 h1:BkpIxRHKa0s3bSMx173PpuU7oTs+Zw7XmD0BIta0HGM=
|
||||
github.com/casbin/xorm-adapter/v2 v2.5.1/go.mod h1:AeH4dBKHC9/zYxzdPVHhPDzF8LYLqjDdb767CWJoV54=
|
||||
github.com/casdoor/go-sms-sender v0.0.5 h1:9qhlMM+UoSOvvY7puUULqSHBBA7fbe02Px/tzchQboo=
|
||||
github.com/casdoor/go-sms-sender v0.0.5/go.mod h1:TMM/BsZQAa+7JVDXl2KqgxnzZgCjmHEX5MBN662mM5M=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
@ -264,8 +264,6 @@ github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJK
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/mileusna/crontab v1.0.1 h1:YrDLc7l3xOiznmXq2FtAgg+1YQ3yC6pfFVPe+ywXNtg=
|
||||
github.com/mileusna/crontab v1.0.1/go.mod h1:dbns64w/u3tUnGZGf8pAa76ZqOfeBX4olW4U1ZwExmc=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
@ -313,6 +311,8 @@ github.com/qiangmzsx/string-adapter/v2 v2.1.0 h1:q0y8TPa/sTwtriJPRe8gWL++PuZ+XbO
|
||||
github.com/qiangmzsx/string-adapter/v2 v2.1.0/go.mod h1:PElPB7b7HnGKTsuADAffFpOQXHqjEGJz1+U1a6yR5wA=
|
||||
github.com/qor/oss v0.0.0-20191031055114-aef9ba66bf76 h1:J2Xj92efYLxPl3BiibgEDEUiMsCBzwTurE/8JjD8CG4=
|
||||
github.com/qor/oss v0.0.0-20191031055114-aef9ba66bf76/go.mod h1:JhtPzUhP5KGtCB2yksmxuYAD4hEWw4qGQJpucjsm3U0=
|
||||
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
|
||||
|
@ -21,7 +21,7 @@ import (
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
|
||||
type I18nData map[string]map[string]string
|
||||
|
@ -18,7 +18,7 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
|
||||
func getI18nFilePath(language string) string {
|
||||
|
116
idp/baidu.go
Normal file
116
idp/baidu.go
Normal file
@ -0,0 +1,116 @@
|
||||
// Copyright 2021 The casbin 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 idp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
type BaiduIdProvider struct {
|
||||
Client *http.Client
|
||||
Config *oauth2.Config
|
||||
}
|
||||
|
||||
func NewBaiduIdProvider(clientId string, clientSecret string, redirectUrl string) *BaiduIdProvider {
|
||||
idp := &BaiduIdProvider{}
|
||||
|
||||
config := idp.getConfig()
|
||||
config.ClientID = clientId
|
||||
config.ClientSecret = clientSecret
|
||||
config.RedirectURL = redirectUrl
|
||||
idp.Config = config
|
||||
|
||||
return idp
|
||||
}
|
||||
|
||||
func (idp *BaiduIdProvider) SetHttpClient(client *http.Client) {
|
||||
idp.Client = client
|
||||
}
|
||||
|
||||
func (idp *BaiduIdProvider) getConfig() *oauth2.Config {
|
||||
var endpoint = oauth2.Endpoint{
|
||||
AuthURL: "https://openapi.baidu.com/oauth/2.0/authorize",
|
||||
TokenURL: "https://openapi.baidu.com/oauth/2.0/token",
|
||||
}
|
||||
|
||||
var config = &oauth2.Config{
|
||||
Scopes: []string{"email"},
|
||||
Endpoint: endpoint,
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
func (idp *BaiduIdProvider) GetToken(code string) (*oauth2.Token, error) {
|
||||
ctx := context.WithValue(context.Background(), oauth2.HTTPClient, idp.Client)
|
||||
return idp.Config.Exchange(ctx, code)
|
||||
}
|
||||
|
||||
/*
|
||||
{
|
||||
"userid":"2097322476",
|
||||
"username":"wl19871011",
|
||||
"realname":"阳光",
|
||||
"userdetail":"喜欢自由",
|
||||
"birthday":"1987-01-01",
|
||||
"marriage":"恋爱",
|
||||
"sex":"男",
|
||||
"blood":"O",
|
||||
"constellation":"射手",
|
||||
"figure":"小巧",
|
||||
"education":"大学/专科",
|
||||
"trade":"计算机/电子产品",
|
||||
"job":"未知",
|
||||
"birthday_year":"1987",
|
||||
"birthday_month":"01",
|
||||
"birthday_day":"01",
|
||||
}
|
||||
*/
|
||||
|
||||
type BaiduUserInfo struct {
|
||||
OpenId string `json:"openid"`
|
||||
Username string `json:"username"`
|
||||
Portrait string `json:"portrait"`
|
||||
}
|
||||
|
||||
func (idp *BaiduIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
|
||||
resp, err := idp.Client.Get(fmt.Sprintf("https://openapi.baidu.com/rest/2.0/passport/users/getInfo?access_token=%s", token.AccessToken))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
data, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
baiduUser := BaiduUserInfo{}
|
||||
if err = json.Unmarshal(data, &baiduUser); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
userInfo := UserInfo{
|
||||
Id: baiduUser.OpenId,
|
||||
Username: baiduUser.Username,
|
||||
DisplayName: baiduUser.Username,
|
||||
AvatarUrl: fmt.Sprintf("https://himg.bdimg.com/sys/portrait/item/%s", baiduUser.Portrait),
|
||||
}
|
||||
return &userInfo, nil
|
||||
}
|
@ -21,7 +21,7 @@ import (
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
"github.com/markbates/goth"
|
||||
"github.com/markbates/goth/providers/amazon"
|
||||
"github.com/markbates/goth/providers/apple"
|
||||
|
@ -60,6 +60,8 @@ func GetIdProvider(providerType string, clientId string, clientSecret string, re
|
||||
return NewLarkIdProvider(clientId, clientSecret, redirectUrl)
|
||||
} else if providerType == "GitLab" {
|
||||
return NewGitlabIdProvider(clientId, clientSecret, redirectUrl)
|
||||
} else if providerType == "Baidu" {
|
||||
return NewBaiduIdProvider(clientId, clientSecret, redirectUrl)
|
||||
} else if isGothSupport(providerType) {
|
||||
return NewGothIdProvider(providerType, clientId, clientSecret, redirectUrl)
|
||||
}
|
||||
|
10
main.go
10
main.go
@ -21,11 +21,11 @@ import (
|
||||
"github.com/astaxie/beego/logs"
|
||||
"github.com/astaxie/beego/plugins/cors"
|
||||
_ "github.com/astaxie/beego/session/redis"
|
||||
"github.com/casbin/casdoor/authz"
|
||||
"github.com/casbin/casdoor/object"
|
||||
"github.com/casbin/casdoor/proxy"
|
||||
"github.com/casbin/casdoor/routers"
|
||||
_ "github.com/casbin/casdoor/routers"
|
||||
"github.com/casdoor/casdoor/authz"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/proxy"
|
||||
"github.com/casdoor/casdoor/routers"
|
||||
_ "github.com/casdoor/casdoor/routers"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
@ -17,10 +17,11 @@ package object
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"xorm.io/core"
|
||||
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/casbin/casdoor/conf"
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/casdoor/casdoor/conf"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
//_ "github.com/denisenkom/go-mssqldb" // db = mssql
|
||||
_ "github.com/go-sql-driver/mysql" // db = mysql
|
||||
//_ "github.com/lib/pq" // db = postgres
|
||||
@ -110,6 +111,13 @@ func (a *Adapter) close() {
|
||||
}
|
||||
|
||||
func (a *Adapter) createTable() {
|
||||
showSql, _ := beego.AppConfig.Bool("showSql")
|
||||
a.Engine.ShowSQL(showSql)
|
||||
|
||||
tableNamePrefix := beego.AppConfig.String("tableNamePrefix")
|
||||
tbMapper := core.NewPrefixMapper(core.SnakeMapper{}, tableNamePrefix)
|
||||
a.Engine.SetTableMapper(tbMapper)
|
||||
|
||||
err := a.Engine.Sync2(new(Organization))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@ -182,12 +190,17 @@ func (a *Adapter) createTable() {
|
||||
}
|
||||
|
||||
func GetSession(owner string, offset, limit int, field, value, sortField, sortOrder string) *xorm.Session {
|
||||
session := adapter.Engine.Limit(limit, offset).Where("1=1")
|
||||
session := adapter.Engine.Prepare()
|
||||
if offset != -1 && limit != -1 {
|
||||
session.Limit(limit, offset)
|
||||
}
|
||||
if owner != "" {
|
||||
session = session.And("owner=?", owner)
|
||||
}
|
||||
if field != "" && value != "" {
|
||||
session = session.And(fmt.Sprintf("%s like ?", util.SnakeString(field)), fmt.Sprintf("%%%s%%", value))
|
||||
if filterField(field) {
|
||||
session = session.And(fmt.Sprintf("%s like ?", util.SnakeString(field)), fmt.Sprintf("%%%s%%", value))
|
||||
}
|
||||
}
|
||||
if sortField == "" || sortOrder == "" {
|
||||
sortField = "created_time"
|
||||
@ -198,4 +211,4 @@ func GetSession(owner string, offset, limit int, field, value, sortField, sortOr
|
||||
session = session.Desc(util.SnakeString(sortField))
|
||||
}
|
||||
return session
|
||||
}
|
||||
}
|
@ -17,7 +17,7 @@ package object
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
"xorm.io/core"
|
||||
)
|
||||
|
||||
@ -56,10 +56,7 @@ type Application struct {
|
||||
}
|
||||
|
||||
func GetApplicationCount(owner, field, value string) int {
|
||||
session := adapter.Engine.Where("owner=?", owner)
|
||||
if field != "" && value != "" {
|
||||
session = session.And(fmt.Sprintf("%s like ?", util.SnakeString(field)), fmt.Sprintf("%%%s%%", value))
|
||||
}
|
||||
session := GetSession(owner, -1, -1, field, value, "", "")
|
||||
count, err := session.Count(&Application{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@ -89,7 +86,7 @@ func GetPaginationApplications(owner string, offset, limit int, field, value, so
|
||||
return applications
|
||||
}
|
||||
|
||||
func getApplicationsByOrganizationName(owner string, organization string) []*Application {
|
||||
func GetApplicationsByOrganizationName(owner string, organization string) []*Application {
|
||||
applications := []*Application{}
|
||||
err := adapter.Engine.Desc("created_time").Find(&applications, &Application{Owner: owner, Organization: organization})
|
||||
if err != nil {
|
||||
|
@ -20,7 +20,7 @@ import (
|
||||
"io"
|
||||
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/casbin/casdoor/proxy"
|
||||
"github.com/casdoor/casdoor/proxy"
|
||||
)
|
||||
|
||||
var defaultStorageProvider *Provider = nil
|
||||
|
@ -18,7 +18,7 @@ import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/casbin/casdoor/proxy"
|
||||
"github.com/casdoor/casdoor/proxy"
|
||||
)
|
||||
|
||||
func TestSyncPermanentAvatars(t *testing.T) {
|
||||
|
@ -17,7 +17,7 @@ package object
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
"xorm.io/core"
|
||||
)
|
||||
|
||||
@ -53,10 +53,7 @@ func GetMaskedCerts(certs []*Cert) []*Cert {
|
||||
}
|
||||
|
||||
func GetCertCount(owner, field, value string) int {
|
||||
session := adapter.Engine.Where("owner=?", owner)
|
||||
if field != "" && value != "" {
|
||||
session = session.And(fmt.Sprintf("%s like ?", util.SnakeString(field)), fmt.Sprintf("%%%s%%", value))
|
||||
}
|
||||
session := GetSession(owner, -1, -1, field, value, "", "")
|
||||
count, err := session.Count(&Cert{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
@ -18,15 +18,19 @@ import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
|
||||
"github.com/casbin/casdoor/cred"
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/casdoor/casdoor/cred"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
goldap "github.com/go-ldap/ldap/v3"
|
||||
)
|
||||
|
||||
var reWhiteSpace *regexp.Regexp
|
||||
var (
|
||||
reWhiteSpace *regexp.Regexp
|
||||
reFieldWhiteList *regexp.Regexp
|
||||
)
|
||||
|
||||
func init() {
|
||||
reWhiteSpace, _ = regexp.Compile(`\s`)
|
||||
reFieldWhiteList, _ = regexp.Compile(`^[A-Za-z0-9]+$`)
|
||||
}
|
||||
|
||||
func CheckUserSignup(application *Application, organization *Organization, username string, password string, displayName string, email string, phone string, affiliation string) string {
|
||||
@ -179,3 +183,7 @@ func CheckUserPassword(organization string, username string, password string) (*
|
||||
|
||||
return user, ""
|
||||
}
|
||||
|
||||
func filterField(field string) bool {
|
||||
return reFieldWhiteList.MatchString(field)
|
||||
}
|
@ -17,7 +17,7 @@ package object
|
||||
import (
|
||||
_ "embed"
|
||||
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
|
||||
//go:embed token_jwt_key.pem
|
||||
|
@ -19,7 +19,7 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
goldap "github.com/go-ldap/ldap/v3"
|
||||
"github.com/thanhpk/randstr"
|
||||
)
|
||||
|
@ -54,7 +54,7 @@ func init() {
|
||||
Issuer: origin,
|
||||
AuthorizationEndpoint: fmt.Sprintf("%s/login/oauth/authorize", origin),
|
||||
TokenEndpoint: fmt.Sprintf("%s/api/login/oauth/access_token", origin),
|
||||
UserinfoEndpoint: fmt.Sprintf("%s/api/get-account", origin),
|
||||
UserinfoEndpoint: fmt.Sprintf("%s/api/userinfo", origin),
|
||||
JwksUri: fmt.Sprintf("%s/api/certs", origin),
|
||||
ResponseTypesSupported: []string{"id_token"},
|
||||
ResponseModesSupported: []string{"login", "code", "link"},
|
||||
@ -85,6 +85,7 @@ func GetJsonWebKeySet() (jose.JSONWebKeySet, error) {
|
||||
var jwk jose.JSONWebKey
|
||||
jwk.Key = x509Cert.PublicKey
|
||||
jwk.Certificates = []*x509.Certificate{x509Cert}
|
||||
jwk.KeyID = cert.Name
|
||||
|
||||
var jwks jose.JSONWebKeySet
|
||||
jwks.Keys = []jose.JSONWebKey{jwk}
|
||||
|
@ -15,10 +15,8 @@
|
||||
package object
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/casbin/casdoor/cred"
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/casdoor/casdoor/cred"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
"xorm.io/core"
|
||||
)
|
||||
|
||||
@ -39,10 +37,7 @@ type Organization struct {
|
||||
}
|
||||
|
||||
func GetOrganizationCount(owner, field, value string) int {
|
||||
session := adapter.Engine.Where("owner=?", owner)
|
||||
if field != "" && value != "" {
|
||||
session = session.And(fmt.Sprintf("%s like ?", util.SnakeString(field)), fmt.Sprintf("%%%s%%", value))
|
||||
}
|
||||
session := GetSession(owner, -1, -1, field, value, "", "")
|
||||
count, err := session.Count(&Organization{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@ -124,7 +119,7 @@ func UpdateOrganization(id string, organization *Organization) bool {
|
||||
}
|
||||
|
||||
if name != organization.Name {
|
||||
applications := getApplicationsByOrganizationName("admin", name)
|
||||
applications := GetApplicationsByOrganizationName("admin", name)
|
||||
for _, application := range applications {
|
||||
application.Organization = organization.Name
|
||||
UpdateApplication(application.GetId(), application)
|
||||
|
@ -17,7 +17,7 @@ package object
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
"xorm.io/core"
|
||||
)
|
||||
|
||||
@ -39,10 +39,7 @@ type Permission struct {
|
||||
}
|
||||
|
||||
func GetPermissionCount(owner, field, value string) int {
|
||||
session := adapter.Engine.Where("owner=?", owner)
|
||||
if field != "" && value != "" {
|
||||
session = session.And(fmt.Sprintf("%s like ?", util.SnakeString(field)), fmt.Sprintf("%%%s%%", value))
|
||||
}
|
||||
session := GetSession(owner, -1, -1, field, value, "", "")
|
||||
count, err := session.Count(&Permission{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
@ -17,7 +17,7 @@ package object
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
"xorm.io/core"
|
||||
)
|
||||
|
||||
@ -81,10 +81,7 @@ func GetMaskedProviders(providers []*Provider) []*Provider {
|
||||
}
|
||||
|
||||
func GetProviderCount(owner, field, value string) int {
|
||||
session := adapter.Engine.Where("owner=?", owner)
|
||||
if field != "" && value != "" {
|
||||
session = session.And(fmt.Sprintf("%s like ?", util.SnakeString(field)), fmt.Sprintf("%%%s%%", value))
|
||||
}
|
||||
session := GetSession(owner, -1, -1, field, value, "", "")
|
||||
count, err := session.Count(&Provider{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
@ -20,7 +20,7 @@ import (
|
||||
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/astaxie/beego/context"
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
|
||||
var logPostOnly bool
|
||||
@ -102,10 +102,7 @@ func AddRecord(record *Record) bool {
|
||||
}
|
||||
|
||||
func GetRecordCount(field, value string) int {
|
||||
session := adapter.Engine.Where("1=1")
|
||||
if field != "" && value != "" {
|
||||
session = session.And(fmt.Sprintf("%s like ?", util.SnakeString(field)), fmt.Sprintf("%%%s%%", value))
|
||||
}
|
||||
session := GetSession("", -1, -1, field, value, "", "")
|
||||
count, err := session.Count(&Record{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
@ -17,7 +17,7 @@ package object
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
"xorm.io/core"
|
||||
)
|
||||
|
||||
@ -40,11 +40,8 @@ type Resource struct {
|
||||
}
|
||||
|
||||
func GetResourceCount(owner, user, field, value string) int {
|
||||
session := adapter.Engine.Where("owner=? and user=?", owner, user)
|
||||
if field != "" && value != "" {
|
||||
session = session.And(fmt.Sprintf("%s like ?", util.SnakeString(field)), fmt.Sprintf("%%%s%%", value))
|
||||
}
|
||||
count, err := session.Count(&Resource{})
|
||||
session := GetSession(owner, -1, -1, field, value, "", "")
|
||||
count, err := session.Count(&Resource{User: user})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ package object
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
"xorm.io/core"
|
||||
)
|
||||
|
||||
@ -33,10 +33,7 @@ type Role struct {
|
||||
}
|
||||
|
||||
func GetRoleCount(owner, field, value string) int {
|
||||
session := adapter.Engine.Where("owner=?", owner)
|
||||
if field != "" && value != "" {
|
||||
session = session.And(fmt.Sprintf("%s like ?", util.SnakeString(field)), fmt.Sprintf("%%%s%%", value))
|
||||
}
|
||||
session := GetSession(owner, -1, -1, field, value, "", "")
|
||||
count, err := session.Count(&Role{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
@ -20,8 +20,8 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/casbin/casdoor/storage"
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/casdoor/casdoor/storage"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
|
||||
var isCloudIntranet bool
|
||||
|
@ -17,7 +17,7 @@ package object
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
"xorm.io/core"
|
||||
)
|
||||
|
||||
@ -48,6 +48,7 @@ type Syncer struct {
|
||||
TableColumns []*TableColumn `xorm:"mediumtext" json:"tableColumns"`
|
||||
AffiliationTable string `xorm:"varchar(100)" json:"affiliationTable"`
|
||||
AvatarBaseUrl string `xorm:"varchar(100)" json:"avatarBaseUrl"`
|
||||
ErrorText string `xorm:"mediumtext" json:"errorText"`
|
||||
SyncInterval int `json:"syncInterval"`
|
||||
IsEnabled bool `json:"isEnabled"`
|
||||
|
||||
@ -55,10 +56,7 @@ type Syncer struct {
|
||||
}
|
||||
|
||||
func GetSyncerCount(owner, field, value string) int {
|
||||
session := adapter.Engine.Where("owner=?", owner)
|
||||
if field != "" && value != "" {
|
||||
session = session.And(fmt.Sprintf("%s like ?", util.SnakeString(field)), fmt.Sprintf("%%%s%%", value))
|
||||
}
|
||||
session := GetSession(owner, -1, -1, field, value, "", "")
|
||||
count, err := session.Count(&Syncer{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@ -140,6 +138,26 @@ func UpdateSyncer(id string, syncer *Syncer) bool {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if affected == 1 {
|
||||
addSyncerJob(syncer)
|
||||
}
|
||||
|
||||
return affected != 0
|
||||
}
|
||||
|
||||
func updateSyncerErrorText(syncer *Syncer, line string) bool {
|
||||
s := getSyncer(syncer.Owner, syncer.Name)
|
||||
if s == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
s.ErrorText = s.ErrorText + line
|
||||
|
||||
affected, err := adapter.Engine.ID(core.PK{s.Owner, s.Name}).Cols("error_text").Update(s)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return affected != 0
|
||||
}
|
||||
|
||||
@ -149,6 +167,10 @@ func AddSyncer(syncer *Syncer) bool {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if affected == 1 {
|
||||
addSyncerJob(syncer)
|
||||
}
|
||||
|
||||
return affected != 0
|
||||
}
|
||||
|
||||
@ -158,6 +180,10 @@ func DeleteSyncer(syncer *Syncer) bool {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if affected == 1 {
|
||||
deleteSyncerJob(syncer)
|
||||
}
|
||||
|
||||
return affected != 0
|
||||
}
|
||||
|
||||
|
@ -14,27 +14,56 @@
|
||||
|
||||
package object
|
||||
|
||||
import "github.com/mileusna/crontab"
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
var cronMap map[string]*crontab.Crontab
|
||||
"github.com/robfig/cron/v3"
|
||||
)
|
||||
|
||||
var cronMap map[string]*cron.Cron
|
||||
|
||||
func init() {
|
||||
cronMap = map[string]*crontab.Crontab{}
|
||||
cronMap = map[string]*cron.Cron{}
|
||||
}
|
||||
|
||||
func getCrontab(name string) *crontab.Crontab {
|
||||
ctab, ok := cronMap[name]
|
||||
func getCronMap(name string) *cron.Cron {
|
||||
m, ok := cronMap[name]
|
||||
if !ok {
|
||||
ctab = crontab.New()
|
||||
cronMap[name] = ctab
|
||||
m = cron.New()
|
||||
cronMap[name] = m
|
||||
}
|
||||
return ctab
|
||||
return m
|
||||
}
|
||||
|
||||
func clearCrontab(name string) {
|
||||
ctab, ok := cronMap[name]
|
||||
func clearCron(name string) {
|
||||
cron, ok := cronMap[name]
|
||||
if ok {
|
||||
ctab.Clear()
|
||||
cron.Stop()
|
||||
delete(cronMap, name)
|
||||
}
|
||||
}
|
||||
|
||||
func addSyncerJob(syncer *Syncer) {
|
||||
deleteSyncerJob(syncer)
|
||||
|
||||
if !syncer.IsEnabled {
|
||||
return
|
||||
}
|
||||
|
||||
syncer.initAdapter()
|
||||
|
||||
syncer.syncUsers()
|
||||
|
||||
schedule := fmt.Sprintf("@every %ds", syncer.SyncInterval)
|
||||
cron := getCronMap(syncer.Name)
|
||||
_, err := cron.AddFunc(schedule, syncer.syncUsers)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
cron.Start()
|
||||
}
|
||||
|
||||
func deleteSyncerJob(syncer *Syncer) {
|
||||
clearCron(syncer.Name)
|
||||
}
|
||||
|
@ -14,13 +14,25 @@
|
||||
|
||||
package object
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (syncer *Syncer) syncUsers() {
|
||||
fmt.Printf("Running syncUsers()..\n")
|
||||
|
||||
users, userMap := syncer.getUserMap()
|
||||
oUsers, oUserMap := syncer.getOriginalUserMap()
|
||||
oUsers, oUserMap, err := syncer.getOriginalUserMap()
|
||||
if err != nil {
|
||||
fmt.Printf(err.Error())
|
||||
|
||||
timestamp := time.Now().Format("2006-01-02 15:04:05")
|
||||
line := fmt.Sprintf("[%s] %s\n", timestamp, err.Error())
|
||||
updateSyncerErrorText(syncer, line)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("Users: %d, oUsers: %d\n", len(users), len(oUsers))
|
||||
|
||||
var affiliationMap map[int]string
|
||||
|
@ -19,48 +19,51 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
"xorm.io/core"
|
||||
)
|
||||
|
||||
type OriginalUser = User
|
||||
|
||||
func (syncer *Syncer) getOriginalUsers() []*OriginalUser {
|
||||
func (syncer *Syncer) getOriginalUsers() ([]*OriginalUser, error) {
|
||||
sql := fmt.Sprintf("select * from %s", syncer.getTable())
|
||||
results, err := syncer.Adapter.Engine.QueryString(sql)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return syncer.getOriginalUsersFromMap(results)
|
||||
return syncer.getOriginalUsersFromMap(results), nil
|
||||
}
|
||||
|
||||
func (syncer *Syncer) getOriginalUserMap() ([]*OriginalUser, map[string]*OriginalUser) {
|
||||
users := syncer.getOriginalUsers()
|
||||
func (syncer *Syncer) getOriginalUserMap() ([]*OriginalUser, map[string]*OriginalUser, error) {
|
||||
users, err := syncer.getOriginalUsers()
|
||||
if err != nil {
|
||||
return users, nil, err
|
||||
}
|
||||
|
||||
m := map[string]*OriginalUser{}
|
||||
for _, user := range users {
|
||||
m[user.Id] = user
|
||||
}
|
||||
return users, m
|
||||
return users, m, nil
|
||||
}
|
||||
|
||||
func (syncer *Syncer) addUser(user *OriginalUser) bool {
|
||||
func (syncer *Syncer) addUser(user *OriginalUser) (bool, error) {
|
||||
m := syncer.getMapFromOriginalUser(user)
|
||||
keyString, valueString := syncer.getSqlKeyValueStringFromMap(m)
|
||||
|
||||
sql := fmt.Sprintf("insert into %s (%s) values (%s)", syncer.getTable(), keyString, valueString)
|
||||
res, err := syncer.Adapter.Engine.Exec(sql)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return false, err
|
||||
}
|
||||
|
||||
affected, err := res.RowsAffected()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return false, err
|
||||
}
|
||||
|
||||
return affected != 0
|
||||
return affected != 0, nil
|
||||
}
|
||||
|
||||
/*func (syncer *Syncer) getOriginalColumns() []string {
|
||||
@ -84,7 +87,7 @@ func (syncer *Syncer) getCasdoorColumns() []string {
|
||||
return res
|
||||
}
|
||||
|
||||
func (syncer *Syncer) updateUser(user *OriginalUser) bool {
|
||||
func (syncer *Syncer) updateUser(user *OriginalUser) (bool, error) {
|
||||
m := syncer.getMapFromOriginalUser(user)
|
||||
pkValue := m[syncer.TablePrimaryKey]
|
||||
delete(m, syncer.TablePrimaryKey)
|
||||
@ -93,22 +96,22 @@ func (syncer *Syncer) updateUser(user *OriginalUser) bool {
|
||||
sql := fmt.Sprintf("update %s set %s where %s = %s", syncer.getTable(), setString, syncer.TablePrimaryKey, pkValue)
|
||||
res, err := syncer.Adapter.Engine.Exec(sql)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return false, err
|
||||
}
|
||||
|
||||
affected, err := res.RowsAffected()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return false, err
|
||||
}
|
||||
|
||||
return affected != 0
|
||||
return affected != 0, nil
|
||||
}
|
||||
|
||||
func (syncer *Syncer) updateUserForOriginalFields(user *User) bool {
|
||||
func (syncer *Syncer) updateUserForOriginalFields(user *User) (bool, error) {
|
||||
owner, name := util.GetOwnerAndNameFromId(user.GetId())
|
||||
oldUser := getUserById(owner, name)
|
||||
if oldUser == nil {
|
||||
return false
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if user.Avatar != oldUser.Avatar && user.Avatar != "" {
|
||||
@ -119,10 +122,10 @@ func (syncer *Syncer) updateUserForOriginalFields(user *User) bool {
|
||||
columns = append(columns, "affiliation", "hash", "pre_hash")
|
||||
affected, err := adapter.Engine.ID(core.PK{oldUser.Owner, oldUser.Name}).Cols(columns...).Update(user)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return false, err
|
||||
}
|
||||
|
||||
return affected != 0
|
||||
return affected != 0, nil
|
||||
}
|
||||
|
||||
func (syncer *Syncer) calculateHash(user *OriginalUser) string {
|
||||
@ -158,22 +161,7 @@ func (syncer *Syncer) initAdapter() {
|
||||
func RunSyncUsersJob() {
|
||||
syncers := GetSyncers("admin")
|
||||
for _, syncer := range syncers {
|
||||
if !syncer.IsEnabled {
|
||||
continue
|
||||
}
|
||||
|
||||
syncer.initAdapter()
|
||||
|
||||
syncer.syncUsers()
|
||||
|
||||
// run at every minute
|
||||
//schedule := fmt.Sprintf("* * * * %d", syncer.SyncInterval)
|
||||
schedule := "* * * * *"
|
||||
ctab := getCrontab(syncer.Name)
|
||||
err := ctab.AddJob(schedule, syncer.syncUsers)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
addSyncerJob(syncer)
|
||||
}
|
||||
|
||||
time.Sleep(time.Duration(1<<63 - 1))
|
||||
|
@ -19,7 +19,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
|
||||
func (syncer *Syncer) getFullAvatarUrl(avatar string) string {
|
||||
|
@ -15,10 +15,12 @@
|
||||
package object
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
"xorm.io/core"
|
||||
)
|
||||
|
||||
@ -36,12 +38,13 @@ type Token struct {
|
||||
Organization string `xorm:"varchar(100)" json:"organization"`
|
||||
User string `xorm:"varchar(100)" json:"user"`
|
||||
|
||||
Code string `xorm:"varchar(100)" json:"code"`
|
||||
AccessToken string `xorm:"mediumtext" json:"accessToken"`
|
||||
RefreshToken string `xorm:"mediumtext" json:"refreshToken"`
|
||||
ExpiresIn int `json:"expiresIn"`
|
||||
Scope string `xorm:"varchar(100)" json:"scope"`
|
||||
TokenType string `xorm:"varchar(100)" json:"tokenType"`
|
||||
Code string `xorm:"varchar(100)" json:"code"`
|
||||
AccessToken string `xorm:"mediumtext" json:"accessToken"`
|
||||
RefreshToken string `xorm:"mediumtext" json:"refreshToken"`
|
||||
ExpiresIn int `json:"expiresIn"`
|
||||
Scope string `xorm:"varchar(100)" json:"scope"`
|
||||
TokenType string `xorm:"varchar(100)" json:"tokenType"`
|
||||
CodeChallenge string `xorm:"varchar(100)" json:"codeChallenge"`
|
||||
}
|
||||
|
||||
type TokenWrapper struct {
|
||||
@ -54,10 +57,7 @@ type TokenWrapper struct {
|
||||
}
|
||||
|
||||
func GetTokenCount(owner, field, value string) int {
|
||||
session := adapter.Engine.Where("owner=?", owner)
|
||||
if field != "" && value != "" {
|
||||
session = session.And(fmt.Sprintf("%s like ?", util.SnakeString(field)), fmt.Sprintf("%%%s%%", value))
|
||||
}
|
||||
session := GetSession(owner, -1, -1, field, value, "", "")
|
||||
count, err := session.Count(&Token{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@ -182,7 +182,7 @@ func CheckOAuthLogin(clientId string, responseType string, redirectUri string, s
|
||||
return "", application
|
||||
}
|
||||
|
||||
func GetOAuthCode(userId string, clientId string, responseType string, redirectUri string, scope string, state string, nonce string) *Code {
|
||||
func GetOAuthCode(userId string, clientId string, responseType string, redirectUri string, scope string, state string, nonce string, challenge string) *Code {
|
||||
user := GetUser(userId)
|
||||
if user == nil {
|
||||
return &Code{
|
||||
@ -205,24 +205,29 @@ func GetOAuthCode(userId string, clientId string, responseType string, redirectU
|
||||
}
|
||||
}
|
||||
|
||||
accessToken, refreshToken, err := generateJwtToken(application, user, nonce)
|
||||
accessToken, refreshToken, err := generateJwtToken(application, user, nonce, scope)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if challenge == "null" {
|
||||
challenge = ""
|
||||
}
|
||||
|
||||
token := &Token{
|
||||
Owner: application.Owner,
|
||||
Name: util.GenerateId(),
|
||||
CreatedTime: util.GetCurrentTime(),
|
||||
Application: application.Name,
|
||||
Organization: user.Owner,
|
||||
User: user.Name,
|
||||
Code: util.GenerateClientId(),
|
||||
AccessToken: accessToken,
|
||||
RefreshToken: refreshToken,
|
||||
ExpiresIn: application.ExpireInHours * 60,
|
||||
Scope: scope,
|
||||
TokenType: "Bearer",
|
||||
Owner: application.Owner,
|
||||
Name: util.GenerateId(),
|
||||
CreatedTime: util.GetCurrentTime(),
|
||||
Application: application.Name,
|
||||
Organization: user.Owner,
|
||||
User: user.Name,
|
||||
Code: util.GenerateClientId(),
|
||||
AccessToken: accessToken,
|
||||
RefreshToken: refreshToken,
|
||||
ExpiresIn: application.ExpireInHours * 60,
|
||||
Scope: scope,
|
||||
TokenType: "Bearer",
|
||||
CodeChallenge: challenge,
|
||||
}
|
||||
AddToken(token)
|
||||
|
||||
@ -232,7 +237,7 @@ func GetOAuthCode(userId string, clientId string, responseType string, redirectU
|
||||
}
|
||||
}
|
||||
|
||||
func GetOAuthToken(grantType string, clientId string, clientSecret string, code string) *TokenWrapper {
|
||||
func GetOAuthToken(grantType string, clientId string, clientSecret string, code string, verifier string) *TokenWrapper {
|
||||
application := GetApplicationByClientId(clientId)
|
||||
if application == nil {
|
||||
return &TokenWrapper{
|
||||
@ -288,6 +293,14 @@ func GetOAuthToken(grantType string, clientId string, clientSecret string, code
|
||||
Scope: "",
|
||||
}
|
||||
}
|
||||
if token.CodeChallenge != "" && pkceChallenge(verifier) != token.CodeChallenge {
|
||||
return &TokenWrapper{
|
||||
AccessToken: "error: incorrect code_verifier",
|
||||
TokenType: "",
|
||||
ExpiresIn: 0,
|
||||
Scope: "",
|
||||
}
|
||||
}
|
||||
|
||||
tokenWrapper := &TokenWrapper{
|
||||
AccessToken: token.AccessToken,
|
||||
@ -360,7 +373,7 @@ func RefreshToken(grantType string, refreshToken string, scope string, clientId
|
||||
Scope: "",
|
||||
}
|
||||
}
|
||||
newAccessToken, newRefreshToken, err := generateJwtToken(application, user, "")
|
||||
newAccessToken, newRefreshToken, err := generateJwtToken(application, user, "", scope)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@ -392,3 +405,10 @@ func RefreshToken(grantType string, refreshToken string, scope string, clientId
|
||||
|
||||
return tokenWrapper
|
||||
}
|
||||
|
||||
// PkceChallenge: base64-URL-encoded SHA256 hash of verifier, per rfc 7636
|
||||
func pkceChallenge(verifier string) string {
|
||||
sum := sha256.Sum256([]byte(verifier))
|
||||
challenge := base64.URLEncoding.WithPadding(base64.NoPadding).EncodeToString(sum[:])
|
||||
return challenge
|
||||
}
|
||||
|
@ -26,6 +26,8 @@ import (
|
||||
type Claims struct {
|
||||
*User
|
||||
Nonce string `json:"nonce,omitempty"`
|
||||
Tag string `json:"tag,omitempty"`
|
||||
Scope string `json:"scope,omitempty"`
|
||||
jwt.RegisteredClaims
|
||||
}
|
||||
|
||||
@ -37,6 +39,7 @@ type UserShort struct {
|
||||
type ClaimsShort struct {
|
||||
*UserShort
|
||||
Nonce string `json:"nonce,omitempty"`
|
||||
Scope string `json:"scope,omitempty"`
|
||||
jwt.RegisteredClaims
|
||||
}
|
||||
|
||||
@ -52,12 +55,13 @@ func getShortClaims(claims Claims) ClaimsShort {
|
||||
res := ClaimsShort{
|
||||
UserShort: getShortUser(claims.User),
|
||||
Nonce: claims.Nonce,
|
||||
Scope: claims.Scope,
|
||||
RegisteredClaims: claims.RegisteredClaims,
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func generateJwtToken(application *Application, user *User, nonce string) (string, string, error) {
|
||||
func generateJwtToken(application *Application, user *User, nonce string, scope string) (string, string, error) {
|
||||
nowTime := time.Now()
|
||||
expireTime := nowTime.Add(time.Duration(application.ExpireInHours) * time.Hour)
|
||||
refreshExpireTime := nowTime.Add(time.Duration(application.RefreshExpireInHours) * time.Hour)
|
||||
@ -67,6 +71,9 @@ func generateJwtToken(application *Application, user *User, nonce string) (strin
|
||||
claims := Claims{
|
||||
User: user,
|
||||
Nonce: nonce,
|
||||
// FIXME: A workaround for custom claim by reusing `tag` in user info
|
||||
Tag: user.Tag,
|
||||
Scope: scope,
|
||||
RegisteredClaims: jwt.RegisteredClaims{
|
||||
Issuer: beego.AppConfig.String("origin"),
|
||||
Subject: user.Id,
|
||||
@ -102,6 +109,7 @@ func generateJwtToken(application *Application, user *User, nonce string) (strin
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
token.Header["kid"] = cert.Name
|
||||
tokenString, err := token.SignedString(key)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
|
@ -18,7 +18,7 @@ import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
|
||||
func TestGenerateRsaKeys(t *testing.T) {
|
||||
|
@ -18,7 +18,7 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
"xorm.io/core"
|
||||
)
|
||||
|
||||
@ -28,7 +28,7 @@ type User struct {
|
||||
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
|
||||
UpdatedTime string `xorm:"varchar(100)" json:"updatedTime"`
|
||||
|
||||
Id string `xorm:"varchar(100)" json:"id"`
|
||||
Id string `xorm:"varchar(100) index" json:"id"`
|
||||
Type string `xorm:"varchar(100)" json:"type"`
|
||||
Password string `xorm:"varchar(100)" json:"password"`
|
||||
PasswordSalt string `xorm:"varchar(100)" json:"passwordSalt"`
|
||||
@ -79,6 +79,7 @@ type User struct {
|
||||
Wecom string `xorm:"wecom varchar(100)" json:"wecom"`
|
||||
Lark string `xorm:"lark varchar(100)" json:"lark"`
|
||||
Gitlab string `xorm:"gitlab varchar(100)" json:"gitlab"`
|
||||
Baidu string `xorm:"baidu varchar(100)" json:"baidu"`
|
||||
Apple string `xorm:"apple varchar(100)" json:"apple"`
|
||||
AzureAD string `xorm:"azuread varchar(100)" json:"azuread"`
|
||||
Slack string `xorm:"slack varchar(100)" json:"slack"`
|
||||
@ -88,10 +89,7 @@ type User struct {
|
||||
}
|
||||
|
||||
func GetGlobalUserCount(field, value string) int {
|
||||
session := adapter.Engine.Where("1=1")
|
||||
if field != "" && value != "" {
|
||||
session = session.And(fmt.Sprintf("%s like ?", util.SnakeString(field)), fmt.Sprintf("%%%s%%", value))
|
||||
}
|
||||
session := GetSession("", -1, -1, field, value, "", "")
|
||||
count, err := session.Count(&User{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@ -122,10 +120,7 @@ func GetPaginationGlobalUsers(offset, limit int, field, value, sortField, sortOr
|
||||
}
|
||||
|
||||
func GetUserCount(owner, field, value string) int {
|
||||
session := adapter.Engine.Where("owner=?", owner)
|
||||
if field != "" && value != "" {
|
||||
session = session.And(fmt.Sprintf("%s like ?", util.SnakeString(field)), fmt.Sprintf("%%%s%%", value))
|
||||
}
|
||||
session := GetSession(owner, -1, -1, field, value, "", "")
|
||||
count, err := session.Count(&User{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@ -270,7 +265,7 @@ func GetLastUser(owner string) *User {
|
||||
return nil
|
||||
}
|
||||
|
||||
func UpdateUser(id string, user *User, columns []string) bool {
|
||||
func UpdateUser(id string, user *User, columns []string, isGlobalAdmin bool) bool {
|
||||
owner, name := util.GetOwnerAndNameFromIdNoCheck(id)
|
||||
oldUser := getUser(owner, name)
|
||||
if oldUser == nil {
|
||||
@ -285,9 +280,12 @@ func UpdateUser(id string, user *User, columns []string) bool {
|
||||
|
||||
if len(columns) == 0 {
|
||||
columns = []string{"owner", "display_name", "avatar",
|
||||
"location", "address", "region", "language", "affiliation", "title", "homepage", "bio", "score", "tag",
|
||||
"location", "address", "region", "language", "affiliation", "title", "homepage", "bio", "score", "tag", "signup_application",
|
||||
"is_admin", "is_global_admin", "is_forbidden", "is_deleted", "hash", "is_default_avatar", "properties"}
|
||||
}
|
||||
if isGlobalAdmin {
|
||||
columns = append(columns, "name")
|
||||
}
|
||||
|
||||
affected, err := adapter.Engine.ID(core.PK{owner, name}).Cols(columns...).Update(user)
|
||||
if err != nil {
|
||||
@ -348,9 +346,10 @@ func AddUsers(users []*User) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
organization := GetOrganizationByUser(users[0])
|
||||
//organization := GetOrganizationByUser(users[0])
|
||||
for _, user := range users {
|
||||
user.UpdateUserPassword(organization)
|
||||
// this function is only used for syncer or batch upload, so no need to encrypt the password
|
||||
//user.UpdateUserPassword(organization)
|
||||
|
||||
user.UpdateUserHash()
|
||||
user.PreHash = user.Hash
|
||||
|
@ -14,7 +14,7 @@
|
||||
|
||||
package object
|
||||
|
||||
import "github.com/casbin/casdoor/cred"
|
||||
import "github.com/casdoor/casdoor/cred"
|
||||
|
||||
func calculateHash(user *User) string {
|
||||
syncer := getDbSyncerForUser(user)
|
||||
|
@ -19,7 +19,7 @@ import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
"xorm.io/core"
|
||||
)
|
||||
|
||||
|
@ -15,8 +15,8 @@
|
||||
package object
|
||||
|
||||
import (
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/casbin/casdoor/xlsx"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
"github.com/casdoor/casdoor/xlsx"
|
||||
)
|
||||
|
||||
func getUserMap(owner string) map[string]*User {
|
||||
|
@ -19,7 +19,7 @@ import (
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/casbin/casdoor/idp"
|
||||
"github.com/casdoor/casdoor/idp"
|
||||
"xorm.io/core"
|
||||
)
|
||||
|
||||
@ -65,7 +65,7 @@ func GetUserByFields(organization string, field string) *User {
|
||||
}
|
||||
|
||||
// check ID card
|
||||
user = GetUserByField(organization, "idCard", field)
|
||||
user = GetUserByField(organization, "id_card", field)
|
||||
if user != nil {
|
||||
return user
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
"xorm.io/core"
|
||||
)
|
||||
|
||||
|
@ -17,7 +17,7 @@ package object
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
"xorm.io/core"
|
||||
)
|
||||
|
||||
@ -43,10 +43,7 @@ type Webhook struct {
|
||||
}
|
||||
|
||||
func GetWebhookCount(owner, field, value string) int {
|
||||
session := adapter.Engine.Where("owner=?", owner)
|
||||
if field != "" && value != "" {
|
||||
session = session.And(fmt.Sprintf("%s like ?", util.SnakeString(field)), fmt.Sprintf("%%%s%%", value))
|
||||
}
|
||||
session := GetSession(owner, -1, -1, field, value, "", "")
|
||||
count, err := session.Count(&Webhook{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
@ -18,7 +18,7 @@ import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
|
||||
func sendWebhook(webhook *Webhook, record *Record) error {
|
||||
|
@ -20,8 +20,8 @@ import (
|
||||
"net/http"
|
||||
|
||||
"github.com/astaxie/beego/context"
|
||||
"github.com/casbin/casdoor/authz"
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/casdoor/casdoor/authz"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
|
||||
type Object struct {
|
||||
|
@ -19,8 +19,8 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/astaxie/beego/context"
|
||||
"github.com/casbin/casdoor/object"
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
|
||||
func AutoSigninFilter(ctx *context.Context) {
|
||||
@ -43,6 +43,7 @@ func AutoSigninFilter(ctx *context.Context) {
|
||||
|
||||
userId := fmt.Sprintf("%s/%s", claims.User.Owner, claims.User.Name)
|
||||
setSessionUser(ctx, userId)
|
||||
setSessionOidc(ctx, claims.Scope, claims.Audience[0])
|
||||
return
|
||||
}
|
||||
|
||||
@ -81,5 +82,6 @@ func AutoSigninFilter(ctx *context.Context) {
|
||||
|
||||
setSessionUser(ctx, fmt.Sprintf("%s/%s", claims.Owner, claims.Name))
|
||||
setSessionExpire(ctx, claims.ExpiresAt.Unix())
|
||||
setSessionOidc(ctx, claims.Scope, claims.Audience[0])
|
||||
}
|
||||
}
|
||||
|
@ -19,8 +19,8 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/astaxie/beego/context"
|
||||
"github.com/casbin/casdoor/object"
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
|
||||
type Response struct {
|
||||
@ -97,6 +97,18 @@ func setSessionExpire(ctx *context.Context, ExpireTime int64) {
|
||||
ctx.Input.CruSession.SessionRelease(ctx.ResponseWriter)
|
||||
}
|
||||
|
||||
func setSessionOidc(ctx *context.Context, scope string, aud string) {
|
||||
err := ctx.Input.CruSession.Set("scope", scope)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
err = ctx.Input.CruSession.Set("aud", aud)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ctx.Input.CruSession.SessionRelease(ctx.ResponseWriter)
|
||||
}
|
||||
|
||||
func parseBearerToken(ctx *context.Context) string {
|
||||
header := ctx.Request.Header.Get("Authorization")
|
||||
tokens := strings.Split(header, " ")
|
||||
|
@ -18,8 +18,8 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/astaxie/beego/context"
|
||||
"github.com/casbin/casdoor/object"
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
|
||||
func getUser(ctx *context.Context) (username string) {
|
||||
|
@ -22,7 +22,7 @@ package routers
|
||||
import (
|
||||
"github.com/astaxie/beego"
|
||||
|
||||
"github.com/casbin/casdoor/controllers"
|
||||
"github.com/casdoor/casdoor/controllers"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -50,6 +50,7 @@ func initAPI() {
|
||||
beego.Router("/api/get-app-login", &controllers.ApiController{}, "GET:GetApplicationLogin")
|
||||
beego.Router("/api/logout", &controllers.ApiController{}, "POST:Logout")
|
||||
beego.Router("/api/get-account", &controllers.ApiController{}, "GET:GetAccount")
|
||||
beego.Router("/api/userinfo", &controllers.ApiController{}, "GET:GetUserinfo")
|
||||
beego.Router("/api/unlink", &controllers.ApiController{}, "POST:Unlink")
|
||||
beego.Router("/api/get-saml-login", &controllers.ApiController{}, "GET:GetSamlLogin")
|
||||
beego.Router("/api/acs", &controllers.ApiController{}, "POST:HandleSamlLogin")
|
||||
|
@ -19,7 +19,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/astaxie/beego/context"
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
|
||||
func StaticFilter(ctx *context.Context) {
|
||||
|
@ -13,7 +13,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
export const ShowGithubCorner = false;
|
||||
export const GithubRepo = "https://github.com/casbin/casdoor";
|
||||
export const GithubRepo = "https://github.com/casdoor/casdoor";
|
||||
|
||||
export const ForceLanguage = "";
|
||||
export const DefaultLanguage = "en";
|
||||
|
@ -59,7 +59,7 @@ export const PasswordModal = (props) => {
|
||||
|
||||
return (
|
||||
<Row>
|
||||
<Button type="default" onClick={showModal}>
|
||||
<Button type="default" disabled={props.disabled} onClick={showModal}>
|
||||
{ hasOldPassword ? i18next.t("user:Modify password...") : i18next.t("user:Set password...")}
|
||||
</Button>
|
||||
<Modal
|
||||
|
@ -112,7 +112,12 @@ class PermissionEditPage extends React.Component {
|
||||
{Setting.getLabel(i18next.t("general:Organization"), i18next.t("general:Organization - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Select virtual={false} style={{width: '100%'}} value={this.state.permission.owner} onChange={(value => {this.updatePermissionField('owner', value);})}>
|
||||
<Select virtual={false} style={{width: '100%'}} value={this.state.permission.owner} onChange={(owner => {
|
||||
this.updatePermissionField('owner', owner);
|
||||
|
||||
this.getUsers(owner);
|
||||
this.getRoles(owner);
|
||||
})}>
|
||||
{
|
||||
this.state.organizations.map((organization, index) => <Option key={index} value={organization.name}>{organization.name}</Option>)
|
||||
}
|
||||
|
@ -398,6 +398,7 @@ export function getProviderTypeOptions(category) {
|
||||
{id: 'WeCom', name: 'WeCom'},
|
||||
{id: 'Lark', name: 'Lark'},
|
||||
{id: 'GitLab', name: 'GitLab'},
|
||||
{id: 'Baidu', name: 'Baidu'},
|
||||
{id: 'Apple', name: 'Apple'},
|
||||
{id: 'AzureAD', name: 'AzureAD'},
|
||||
{id: 'Slack', name: 'Slack'},
|
||||
@ -595,6 +596,7 @@ export function getTagColor(s) {
|
||||
|
||||
export function getTags(tags) {
|
||||
let res = [];
|
||||
if (!tags) return res;
|
||||
tags.forEach((tag, i) => {
|
||||
res.push(
|
||||
<Tag color={getTagColor(tag)}>
|
||||
|
@ -21,6 +21,11 @@ import * as Setting from "./Setting";
|
||||
import i18next from "i18next";
|
||||
import SyncerTableColumnTable from "./SyncerTableColumnTable";
|
||||
|
||||
import {Controlled as CodeMirror} from 'react-codemirror2';
|
||||
import "codemirror/lib/codemirror.css";
|
||||
require('codemirror/theme/material-darker.css');
|
||||
require("codemirror/mode/javascript/javascript");
|
||||
|
||||
const { Option } = Select;
|
||||
|
||||
class SyncerEditPage extends React.Component {
|
||||
@ -248,6 +253,22 @@ class SyncerEditPage extends React.Component {
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("syncer:Error text"), i18next.t("syncer:Error text - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<div style={{width: "100%", height: "300px"}} >
|
||||
<CodeMirror
|
||||
value={this.state.syncer.errorText}
|
||||
options={{mode: 'javascript', theme: "material-darker"}}
|
||||
onBeforeChange={(editor, data, value) => {
|
||||
this.updateSyncerField("errorText", value);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 19 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Is enabled"), i18next.t("general:Is enabled - Tooltip"))} :
|
||||
|
@ -41,7 +41,7 @@ class SyncerListPage extends BaseListPage {
|
||||
tableColumns: [],
|
||||
affiliationTable: "",
|
||||
avatarBaseUrl: "",
|
||||
syncInterval: 1,
|
||||
syncInterval: 10,
|
||||
isEnabled: true,
|
||||
}
|
||||
}
|
||||
|
@ -45,12 +45,14 @@ class UserEditPage extends React.Component {
|
||||
user: null,
|
||||
application: null,
|
||||
organizations: [],
|
||||
applications: [],
|
||||
};
|
||||
}
|
||||
|
||||
UNSAFE_componentWillMount() {
|
||||
this.getUser();
|
||||
this.getOrganizations();
|
||||
this.getApplicationsByOrganization(this.state.organizationName);
|
||||
this.getUserApplication();
|
||||
}
|
||||
|
||||
@ -72,6 +74,15 @@ class UserEditPage extends React.Component {
|
||||
});
|
||||
}
|
||||
|
||||
getApplicationsByOrganization(organizationName) {
|
||||
ApplicationBackend.getApplicationsByOrganization("admin", organizationName)
|
||||
.then((res) => {
|
||||
this.setState({
|
||||
applications: (res.msg === undefined) ? res : [],
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
getUserApplication() {
|
||||
ApplicationBackend.getUserApplication(this.state.organizationName, this.state.userName)
|
||||
.then((application) => {
|
||||
@ -140,7 +151,7 @@ class UserEditPage extends React.Component {
|
||||
{Setting.getLabel(i18next.t("general:Name"), i18next.t("general:Name - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={this.state.user.name} disabled={true} onChange={e => {
|
||||
<Input value={this.state.user.name} disabled={!Setting.isAdminUser(this.props.account)} onChange={e => {
|
||||
this.updateUserField('name', e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
@ -203,7 +214,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} account={this.props.account} />
|
||||
<PasswordModal user={this.state.user} account={this.props.account} disabled={this.state.userName !== this.state.user.name} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
@ -293,6 +304,18 @@ class UserEditPage extends React.Component {
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Signup application"), i18next.t("general:Signup application - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Select virtual={false} style={{width: '100%'}} disabled={!Setting.isAdminUser(this.props.account)} value={this.state.user.signupApplication} onChange={(value => {this.updateUserField('signupApplication', value);})}>
|
||||
{
|
||||
this.state.applications.map((application, index) => <Option key={index} value={application.name}>{application.name}</Option>)
|
||||
}
|
||||
</Select>
|
||||
</Col>
|
||||
</Row>
|
||||
{
|
||||
!this.isSelfOrAdmin() ? null : (
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
|
@ -44,7 +44,7 @@ function oAuthParamsToQuery(oAuthParams) {
|
||||
}
|
||||
|
||||
// code
|
||||
return `?clientId=${oAuthParams.clientId}&responseType=${oAuthParams.responseType}&redirectUri=${oAuthParams.redirectUri}&scope=${oAuthParams.scope}&state=${oAuthParams.state}&nonce=${oAuthParams.nonce}`;
|
||||
return `?clientId=${oAuthParams.clientId}&responseType=${oAuthParams.responseType}&redirectUri=${oAuthParams.redirectUri}&scope=${oAuthParams.scope}&state=${oAuthParams.state}&nonce=${oAuthParams.nonce}&code_challenge_method=${oAuthParams.challengeMethod}&code_challenge=${oAuthParams.codeChallenge}`;
|
||||
}
|
||||
|
||||
export function getApplicationLogin(oAuthParams) {
|
||||
|
32
web/src/auth/BaiduLoginButton.js
Normal file
32
web/src/auth/BaiduLoginButton.js
Normal file
@ -0,0 +1,32 @@
|
||||
// Copyright 2021 The casbin 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.
|
||||
|
||||
import {createButton} from "react-social-login-buttons";
|
||||
import {StaticBaseUrl} from "../Setting";
|
||||
|
||||
function Icon({ width = 24, height = 24, color }) {
|
||||
return <img src={`${StaticBaseUrl}/buttons/baidu.svg`} alt="Sign in with Baidu" style={{width: 24, height: 24}} />;
|
||||
}
|
||||
|
||||
const config = {
|
||||
text: "Sign in with Baidu",
|
||||
icon: Icon,
|
||||
iconFormat: name => `fa fa-${name}`,
|
||||
style: {background: "#ffffff", color: "#000000"},
|
||||
activeStyle: {background: "#ededee"},
|
||||
};
|
||||
|
||||
const BaiduLoginButton = createButton(config);
|
||||
|
||||
export default BaiduLoginButton;
|
@ -34,6 +34,7 @@ import LinkedInLoginButton from "./LinkedInLoginButton";
|
||||
import WeComLoginButton from "./WeComLoginButton";
|
||||
import LarkLoginButton from "./LarkLoginButton";
|
||||
import GitLabLoginButton from "./GitLabLoginButton";
|
||||
import BaiduLoginButton from "./BaiduLoginButton";
|
||||
import AppleLoginButton from "./AppleLoginButton"
|
||||
import AzureADLoginButton from "./AzureADLoginButton";
|
||||
import SlackLoginButton from "./SlackLoginButton";
|
||||
@ -183,6 +184,8 @@ class LoginPage extends React.Component {
|
||||
return <LarkLoginButton text={text} align={"center"} />
|
||||
} else if (type === "GitLab") {
|
||||
return <GitLabLoginButton text={text} align={"center"} />
|
||||
} else if (type === "Baidu") {
|
||||
return <BaiduLoginButton text={text} align={"center"} />
|
||||
} else if (type === "Apple") {
|
||||
return <AppleLoginButton text={text} align={"center"} />
|
||||
} else if (type === "AzureAD") {
|
||||
@ -482,6 +485,19 @@ class LoginPage extends React.Component {
|
||||
return null;
|
||||
}
|
||||
|
||||
const params = new URLSearchParams(this.props.location.search);
|
||||
let silentSignin = params.get("silentSignin");
|
||||
if (silentSignin !== null) {
|
||||
if (window !== window.parent) {
|
||||
const message = {tag: "Casdoor", type: "SilentSignin", data: "signing-in"};
|
||||
window.parent.postMessage(message, "*");
|
||||
}
|
||||
|
||||
let values = {};
|
||||
values["application"] = this.state.application.name;
|
||||
this.onFinish(values);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div style={{fontSize: 16, textAlign: "left"}}>
|
||||
|
@ -69,6 +69,10 @@ const authInfo = {
|
||||
scope: "read_user+profile",
|
||||
endpoint: "https://gitlab.com/oauth/authorize",
|
||||
},
|
||||
Baidu: {
|
||||
scope: "basic",
|
||||
endpoint: "http://openapi.baidu.com/oauth/2.0/authorize",
|
||||
},
|
||||
Apple: {
|
||||
scope: "name%20email",
|
||||
endpoint: "https://appleid.apple.com/auth/authorize",
|
||||
@ -227,6 +231,8 @@ export function getAuthUrl(application, provider, method) {
|
||||
return `${endpoint}?app_id=${provider.clientId}&redirect_uri=${redirectUri}&state=${state}`;
|
||||
} else if (provider.type === "GitLab") {
|
||||
return `${endpoint}?client_id=${provider.clientId}&redirect_uri=${redirectUri}&state=${state}&response_type=code&scope=${scope}`;
|
||||
} else if (provider.type === "Baidu") {
|
||||
return `${endpoint}?client_id=${provider.clientId}&redirect_uri=${redirectUri}&state=${state}&response_type=code&scope=${scope}&display=popup`;
|
||||
} else if (provider.type === "Apple") {
|
||||
return `${endpoint}?client_id=${provider.clientId}&redirect_uri=${redirectUri}&state=${state}&response_type=code&scope=${scope}&response_mode=form_post`;
|
||||
} else if (provider.type === "AzureAD") {
|
||||
|
@ -83,7 +83,9 @@ export function getOAuthGetParameters(params) {
|
||||
const scope = queries.get("scope");
|
||||
const state = queries.get("state");
|
||||
const nonce = queries.get("nonce")
|
||||
|
||||
const challengeMethod = queries.get("code_challenge_method")
|
||||
const codeChallenge = queries.get("code_challenge")
|
||||
|
||||
if (clientId === undefined || clientId === null) {
|
||||
// login
|
||||
return null;
|
||||
@ -96,6 +98,8 @@ export function getOAuthGetParameters(params) {
|
||||
scope: scope,
|
||||
state: state,
|
||||
nonce: nonce,
|
||||
challengeMethod: challengeMethod,
|
||||
codeChallenge: codeChallenge,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,13 @@ export function getApplications(owner, page = "", pageSize = "", field = "", val
|
||||
}).then(res => res.json());
|
||||
}
|
||||
|
||||
export function getApplicationsByOrganization(owner, organization) {
|
||||
return fetch(`${Setting.ServerUrl}/api/get-applications?owner=${owner}&organization=${organization}`, {
|
||||
method: "GET",
|
||||
credentials: "include"
|
||||
}).then(res => res.json());
|
||||
}
|
||||
|
||||
export function getApplication(owner, name) {
|
||||
return fetch(`${Setting.ServerUrl}/api/get-application?id=${owner}/${encodeURIComponent(name)}`, {
|
||||
method: "GET",
|
||||
|
@ -154,6 +154,8 @@
|
||||
"Signin URL - Tooltip": "sign in url",
|
||||
"Signup URL": "Registrierungs-URL",
|
||||
"Signup URL - Tooltip": "sign up url",
|
||||
"Signup application": "Signup application",
|
||||
"Signup application - Tooltip": "Signup application - Tooltip",
|
||||
"Sorry, the page you visited does not exist.": "Die von Ihnen besuchte Seite existiert leider nicht.",
|
||||
"Swagger": "Swagger",
|
||||
"Syncers": "Syncers",
|
||||
@ -384,6 +386,8 @@
|
||||
"Database type": "Datenbanktyp",
|
||||
"Database type - Tooltip": "Datenbanktyp - Tooltip",
|
||||
"Edit Syncer": "Syncer bearbeiten",
|
||||
"Error text": "Error text",
|
||||
"Error text - Tooltip": "Error text - Tooltip",
|
||||
"Is hashed": "Ist gehasht",
|
||||
"Sync interval": "Sync-Intervall",
|
||||
"Sync interval - Tooltip": "Sync-Intervall - Tooltip",
|
||||
|
@ -154,6 +154,8 @@
|
||||
"Signin URL - Tooltip": "Signin URL - Tooltip",
|
||||
"Signup URL": "Signup URL",
|
||||
"Signup URL - Tooltip": "Signup URL - Tooltip",
|
||||
"Signup application": "Signup application",
|
||||
"Signup application - Tooltip": "Signup application - Tooltip",
|
||||
"Sorry, the page you visited does not exist.": "Sorry, the page you visited does not exist.",
|
||||
"Swagger": "Swagger",
|
||||
"Syncers": "Syncers",
|
||||
@ -384,6 +386,8 @@
|
||||
"Database type": "Database type",
|
||||
"Database type - Tooltip": "Database type - Tooltip",
|
||||
"Edit Syncer": "Edit Syncer",
|
||||
"Error text": "Error text",
|
||||
"Error text - Tooltip": "Error text - Tooltip",
|
||||
"Is hashed": "Is hashed",
|
||||
"Sync interval": "Sync interval",
|
||||
"Sync interval - Tooltip": "Sync interval - Tooltip",
|
||||
|
@ -154,6 +154,8 @@
|
||||
"Signin URL - Tooltip": "sign in url",
|
||||
"Signup URL": "URL d'inscription",
|
||||
"Signup URL - Tooltip": "sign up url",
|
||||
"Signup application": "Signup application",
|
||||
"Signup application - Tooltip": "Signup application - Tooltip",
|
||||
"Sorry, the page you visited does not exist.": "Désolé, la page que vous avez visitée n'existe pas.",
|
||||
"Swagger": "Swagger",
|
||||
"Syncers": "Synchronisateurs",
|
||||
@ -384,6 +386,8 @@
|
||||
"Database type": "Type de base de données",
|
||||
"Database type - Tooltip": "Type de base de données - infobulle",
|
||||
"Edit Syncer": "Editer le synchro",
|
||||
"Error text": "Error text",
|
||||
"Error text - Tooltip": "Error text - Tooltip",
|
||||
"Is hashed": "Est haché",
|
||||
"Sync interval": "Intervalle de synchronisation",
|
||||
"Sync interval - Tooltip": "Intervalle de synchronisation - infobulle",
|
||||
|
@ -154,6 +154,8 @@
|
||||
"Signin URL - Tooltip": "sign in url",
|
||||
"Signup URL": "サインアップURL",
|
||||
"Signup URL - Tooltip": "sign up url",
|
||||
"Signup application": "Signup application",
|
||||
"Signup application - Tooltip": "Signup application - Tooltip",
|
||||
"Sorry, the page you visited does not exist.": "申し訳ありませんが、訪問したページは存在しません。",
|
||||
"Swagger": "Swagger",
|
||||
"Syncers": "Syncers",
|
||||
@ -384,6 +386,8 @@
|
||||
"Database type": "データベースの種類",
|
||||
"Database type - Tooltip": "データベース タイプ - ツールチップ",
|
||||
"Edit Syncer": "同期ツールを編集",
|
||||
"Error text": "Error text",
|
||||
"Error text - Tooltip": "Error text - Tooltip",
|
||||
"Is hashed": "ハッシュされました",
|
||||
"Sync interval": "同期間隔",
|
||||
"Sync interval - Tooltip": "同期間隔 - ツールチップ",
|
||||
|
@ -154,6 +154,8 @@
|
||||
"Signin URL - Tooltip": "sign in url",
|
||||
"Signup URL": "Signup URL",
|
||||
"Signup URL - Tooltip": "sign up url",
|
||||
"Signup application": "Signup application",
|
||||
"Signup application - Tooltip": "Signup application - Tooltip",
|
||||
"Sorry, the page you visited does not exist.": "Sorry, the page you visited does not exist.",
|
||||
"Swagger": "Swagger",
|
||||
"Syncers": "Syncers",
|
||||
@ -384,6 +386,8 @@
|
||||
"Database type": "Database type",
|
||||
"Database type - Tooltip": "Database type - Tooltip",
|
||||
"Edit Syncer": "Edit Syncer",
|
||||
"Error text": "Error text",
|
||||
"Error text - Tooltip": "Error text - Tooltip",
|
||||
"Is hashed": "Is hashed",
|
||||
"Sync interval": "Sync interval",
|
||||
"Sync interval - Tooltip": "Sync interval - Tooltip",
|
||||
|
@ -154,6 +154,8 @@
|
||||
"Signin URL - Tooltip": "sign in url",
|
||||
"Signup URL": "URL регистрации",
|
||||
"Signup URL - Tooltip": "sign up url",
|
||||
"Signup application": "Signup application",
|
||||
"Signup application - Tooltip": "Signup application - Tooltip",
|
||||
"Sorry, the page you visited does not exist.": "Извините, посещенная вами страница не существует.",
|
||||
"Swagger": "Swagger",
|
||||
"Syncers": "Синхронизаторы",
|
||||
@ -384,6 +386,8 @@
|
||||
"Database type": "Тип базы данных",
|
||||
"Database type - Tooltip": "Тип базы данных - Подсказка",
|
||||
"Edit Syncer": "Изменить синхронизатор",
|
||||
"Error text": "Error text",
|
||||
"Error text - Tooltip": "Error text - Tooltip",
|
||||
"Is hashed": "Хэшировано",
|
||||
"Sync interval": "Интервал синхронизации",
|
||||
"Sync interval - Tooltip": "Интервал синхронизации - Tooltip",
|
||||
|
@ -154,6 +154,8 @@
|
||||
"Signin URL - Tooltip": "用户的登录地址",
|
||||
"Signup URL": "注册URL",
|
||||
"Signup URL - Tooltip": "展示给用户的注册地址",
|
||||
"Signup application": "注册应用",
|
||||
"Signup application - Tooltip": "表示用户注册时通过哪个应用注册的",
|
||||
"Sorry, the page you visited does not exist.": "抱歉,您访问的页面不存在",
|
||||
"Swagger": "API文档",
|
||||
"Syncers": "同步器",
|
||||
@ -384,9 +386,11 @@
|
||||
"Database type": "数据库类型",
|
||||
"Database type - Tooltip": "数据库类型",
|
||||
"Edit Syncer": "编辑同步器",
|
||||
"Error text": "错误信息",
|
||||
"Error text - Tooltip": "同步器连接数据库时发生的错误",
|
||||
"Is hashed": "是否参与哈希计算",
|
||||
"Sync interval": "同步间隔",
|
||||
"Sync interval - Tooltip": "单位为分钟",
|
||||
"Sync interval - Tooltip": "单位为秒",
|
||||
"Table": "表名",
|
||||
"Table - Tooltip": "数据库表名",
|
||||
"Table columns": "表格列",
|
||||
|
@ -15,7 +15,7 @@
|
||||
package xlsx
|
||||
|
||||
import (
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
"github.com/tealeg/xlsx"
|
||||
)
|
||||
|
||||
|
Reference in New Issue
Block a user