Compare commits

..

13 Commits

Author SHA1 Message Date
ade64693e4 fix: support lower go version(1.15) (#599)
* fix: support lower go version(1.15)

* fix: support lower go version(1.15)

* fix: support lower go version(1.15)
2022-03-21 21:55:16 +08:00
5f8924ed4e feat: support overriding configuration with env (#590) 2022-03-20 23:21:09 +08:00
1a6d98d029 refactor: New Crowdin translations by Github Action (#592)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2022-03-20 22:30:29 +08:00
447dd1c534 feat: update the uploaded user field and provide demo xlsx file (#596)
Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>
2022-03-20 22:28:22 +08:00
86b5d72e5d fix: concatChar assignment logic (#595)
Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>
2022-03-20 11:54:14 +08:00
6bc4e646e5 fix: oAuthParams may not exist (#594)
Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>
2022-03-20 10:33:50 +08:00
0841eb5c30 Fix !skipCi directive. 2022-03-19 23:15:19 +08:00
4015c221f7 refactor: New Crowdin translations by Github Action (#588)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2022-03-19 22:01:20 +08:00
dcd6328498 fix: callback url param missing (#583)
Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>
2022-03-19 20:01:44 +08:00
8080927890 fix: redirect for non-built-in app logout (#587)
Signed-off-by: Steve0x2a <stevesough@gmail.com>
2022-03-19 19:50:05 +08:00
a95c5b05a9 Remove GitHub provider hacking code. 2022-03-19 19:43:54 +08:00
865a65d399 fix: fix the params problem in code signin (#577)
Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>
2022-03-18 20:12:29 +08:00
e8b9c67671 feat: add casdoor as itself idp support (#578)
Signed-off-by: Steve0x2a <stevesough@gmail.com>
2022-03-18 18:28:46 +08:00
56 changed files with 930 additions and 179 deletions

View File

@ -15,7 +15,6 @@
package authz package authz
import ( import (
"github.com/astaxie/beego"
"github.com/casbin/casbin/v2" "github.com/casbin/casbin/v2"
"github.com/casbin/casbin/v2/model" "github.com/casbin/casbin/v2/model"
xormadapter "github.com/casbin/xorm-adapter/v2" xormadapter "github.com/casbin/xorm-adapter/v2"
@ -28,8 +27,8 @@ var Enforcer *casbin.Enforcer
func InitAuthz() { func InitAuthz() {
var err error var err error
tableNamePrefix := beego.AppConfig.String("tableNamePrefix") tableNamePrefix := conf.GetConfigString("tableNamePrefix")
a, err := xormadapter.NewAdapterWithTableName(beego.AppConfig.String("driverName"), conf.GetBeegoConfDataSourceName()+beego.AppConfig.String("dbName"), "casbin_rule", tableNamePrefix, true) a, err := xormadapter.NewAdapterWithTableName(conf.GetConfigString("driverName"), conf.GetBeegoConfDataSourceName()+conf.GetConfigString("dbName"), "casbin_rule", tableNamePrefix, true)
if err != nil { if err != nil {
panic(err) panic(err)
} }

View File

@ -15,14 +15,49 @@
package conf package conf
import ( import (
"fmt"
"os" "os"
"strconv"
"strings" "strings"
"github.com/astaxie/beego" "github.com/astaxie/beego"
) )
func GetConfigString(key string) string {
if value, ok := os.LookupEnv(key); ok {
return value
}
return beego.AppConfig.String(key)
}
func GetConfigBool(key string) (bool, error) {
value := GetConfigString(key)
if value == "true" {
return true, nil
} else if value == "false" {
return false, nil
}
return false, fmt.Errorf("value %s cannot be converted into bool", value)
}
func GetConfigInt64(key string) (int64, error) {
value := GetConfigString(key)
num, err := strconv.ParseInt(value, 10, 64)
return num, err
}
func init() {
//this array contains the beego configuration items that may be modified via env
var presetConfigItems = []string{"httpport", "appname"}
for _, key := range presetConfigItems {
if value, ok := os.LookupEnv(key); ok {
beego.AppConfig.Set(key, value)
}
}
}
func GetBeegoConfDataSourceName() string { func GetBeegoConfDataSourceName() string {
dataSourceName := beego.AppConfig.String("dataSourceName") dataSourceName := GetConfigString("dataSourceName")
runningInDocker := os.Getenv("RUNNING_IN_DOCKER") runningInDocker := os.Getenv("RUNNING_IN_DOCKER")
if runningInDocker == "true" { if runningInDocker == "true" {

98
conf/conf_test.go Normal file
View File

@ -0,0 +1,98 @@
// Copyright 2022 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 conf
import (
"os"
"testing"
"github.com/astaxie/beego"
"github.com/stretchr/testify/assert"
)
func TestGetConfString(t *testing.T) {
scenarios := []struct {
description string
input string
expected interface{}
}{
{"Should be return casbin", "appname", "casbin"},
{"Should be return 8000", "httpport", "8000"},
{"Should be return value", "key", "value"},
}
//do some set up job
os.Setenv("appname", "casbin")
os.Setenv("key", "value")
err := beego.LoadAppConfig("ini", "app.conf")
assert.Nil(t, err)
for _, scenery := range scenarios {
t.Run(scenery.description, func(t *testing.T) {
actual := GetConfigString(scenery.input)
assert.Equal(t, scenery.expected, actual)
})
}
}
func TestGetConfInt(t *testing.T) {
scenarios := []struct {
description string
input string
expected interface{}
}{
{"Should be return 8000", "httpport", 8001},
{"Should be return 8000", "verificationCodeTimeout", 10},
}
//do some set up job
os.Setenv("httpport", "8001")
err := beego.LoadAppConfig("ini", "app.conf")
assert.Nil(t, err)
for _, scenery := range scenarios {
t.Run(scenery.description, func(t *testing.T) {
actual, err := GetConfigInt64(scenery.input)
assert.Nil(t, err)
assert.Equal(t, scenery.expected, int(actual))
})
}
}
func TestGetConfBool(t *testing.T) {
scenarios := []struct {
description string
input string
expected interface{}
}{
{"Should be return false", "SessionOn", false},
{"Should be return false", "copyrequestbody", true},
}
//do some set up job
os.Setenv("SessionOn", "false")
err := beego.LoadAppConfig("ini", "app.conf")
assert.Nil(t, err)
for _, scenery := range scenarios {
t.Run(scenery.description, func(t *testing.T) {
actual, err := GetConfigBool(scenery.input)
assert.Nil(t, err)
assert.Equal(t, scenery.expected, actual)
})
}
}

View File

@ -225,10 +225,15 @@ func (c *ApiController) Logout() {
user := c.GetSessionUsername() user := c.GetSessionUsername()
util.LogInfo(c.Ctx, "API: [%s] logged out", user) util.LogInfo(c.Ctx, "API: [%s] logged out", user)
application := c.GetSessionApplication()
c.SetSessionUsername("") c.SetSessionUsername("")
c.SetSessionData(nil) c.SetSessionData(nil)
c.ResponseOk(user) if application == nil || application.Name == "app-built-in" || application.HomepageUrl == "" {
c.ResponseOk(user)
return
}
c.ResponseOk(user, application.HomepageUrl)
} }
// GetAccount // GetAccount

View File

@ -23,7 +23,7 @@ import (
"strings" "strings"
"time" "time"
"github.com/astaxie/beego" "github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/idp" "github.com/casdoor/casdoor/idp"
"github.com/casdoor/casdoor/object" "github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/proxy" "github.com/casdoor/casdoor/proxy"
@ -267,8 +267,8 @@ func (c *ApiController) Login() {
setHttpClient(idProvider, provider.Type) setHttpClient(idProvider, provider.Type)
if form.State != beego.AppConfig.String("authState") && form.State != application.Name { if form.State != conf.GetConfigString("authState") && form.State != application.Name {
c.ResponseError(fmt.Sprintf("state expected: \"%s\", but got: \"%s\"", beego.AppConfig.String("authState"), form.State)) c.ResponseError(fmt.Sprintf("state expected: \"%s\", but got: \"%s\"", conf.GetConfigString("authState"), form.State))
return return
} }

View File

@ -72,6 +72,15 @@ func (c *ApiController) GetSessionUsername() string {
return user.(string) return user.(string)
} }
func (c *ApiController) GetSessionApplication() *object.Application {
clientId := c.GetSession("aud")
if clientId == nil {
return nil
}
application := object.GetApplicationByClientId(clientId.(string))
return application
}
func (c *ApiController) GetSessionOidc() (string, string) { func (c *ApiController) GetSessionOidc() (string, string) {
sessionData := c.GetSessionData() sessionData := c.GetSessionData()
if sessionData != nil && if sessionData != nil &&

View File

@ -178,7 +178,7 @@ func (c *ApiController) UpdateLdap() {
} }
if ldap.AutoSync != 0 { if ldap.AutoSync != 0 {
object.GetLdapAutoSynchronizer().StartAutoSync(ldap.Id) object.GetLdapAutoSynchronizer().StartAutoSync(ldap.Id)
} else if ldap.AutoSync == 0 && prevLdap.AutoSync != 0{ } else if ldap.AutoSync == 0 && prevLdap.AutoSync != 0 {
object.GetLdapAutoSynchronizer().StopAutoSync(ldap.Id) object.GetLdapAutoSynchronizer().StopAutoSync(ldap.Id)
} }

View File

@ -18,7 +18,7 @@ import (
"fmt" "fmt"
"strconv" "strconv"
"github.com/astaxie/beego" "github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/object" "github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
) )
@ -62,7 +62,7 @@ func (c *ApiController) RequireSignedIn() (string, bool) {
} }
func getInitScore() int { func getInitScore() int {
score, err := strconv.Atoi(beego.AppConfig.String("initScore")) score, err := strconv.Atoi(conf.GetConfigString("initScore"))
if err != nil { if err != nil {
panic(err) panic(err)
} }

View File

@ -19,7 +19,7 @@ import (
"crypto/tls" "crypto/tls"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io/ioutil"
"net/http" "net/http"
"net/url" "net/url"
"time" "time"
@ -88,7 +88,7 @@ func (idp *AdfsIdProvider) GetToken(code string) (*oauth2.Token, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
data, err := io.ReadAll(resp.Body) data, err := ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -18,7 +18,7 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io/ioutil"
"net/http" "net/http"
"golang.org/x/oauth2" "golang.org/x/oauth2"
@ -97,7 +97,7 @@ func (idp *BaiduIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error)
return nil, err return nil, err
} }
data, err := io.ReadAll(resp.Body) data, err := ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
return nil, err return nil, err
} }

158
idp/casdoor.go Normal file
View File

@ -0,0 +1,158 @@
// Copyright 2022 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 idp
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"time"
"golang.org/x/oauth2"
)
type CasdoorIdProvider struct {
Client *http.Client
Config *oauth2.Config
Host string
}
func NewCasdoorIdProvider(clientId string, clientSecret string, redirectUrl string, hostUrl string) *CasdoorIdProvider {
idp := &CasdoorIdProvider{}
config := idp.getConfig(hostUrl)
config.ClientID = clientId
config.ClientSecret = clientSecret
config.RedirectURL = redirectUrl
idp.Config = config
idp.Host = hostUrl
return idp
}
func (idp *CasdoorIdProvider) SetHttpClient(client *http.Client) {
idp.Client = client
}
func (idp *CasdoorIdProvider) getConfig(hostUrl string) *oauth2.Config {
return &oauth2.Config{
Endpoint: oauth2.Endpoint{
TokenURL: hostUrl + "/api/login/oauth/access_token",
},
Scopes: []string{"openid email profile"},
}
}
type CasdoorToken struct {
AccessToken string `json:"access_token"`
ExpiresIn int `json:"expires_in"`
}
func (idp *CasdoorIdProvider) GetToken(code string) (*oauth2.Token, error) {
resp, err := http.PostForm(idp.Config.Endpoint.TokenURL, url.Values{
"client_id": {idp.Config.ClientID},
"client_secret": {idp.Config.ClientSecret},
"code": {code},
"grant_type": {"authorization_code"},
})
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
pToken := &CasdoorToken{}
err = json.Unmarshal(body, pToken)
if err != nil {
return nil, err
}
//check if token is expired
if pToken.ExpiresIn <= 0 {
return nil, fmt.Errorf("%s", pToken.AccessToken)
}
token := &oauth2.Token{
AccessToken: pToken.AccessToken,
Expiry: time.Unix(time.Now().Unix()+int64(pToken.ExpiresIn), 0),
}
return token, nil
}
/*
{
"sub": "2f80c349-4beb-407f-b1f0-528aac0f1acd",
"iss": "https://door.casbin.com",
"aud": "7a11****0fa2172",
"name": "admin",
"preferred_username": "Admin",
"email": "admin@example.com",
"picture": "https://casbin.org/img/casbin.svg",
"address": "Guangdong",
"phone": "12345678910"
}
*/
type CasdoorUserInfo struct {
Id string `json:"sub"`
Name string `json:"name"`
DisplayName string `json:"preferred_username"`
Email string `json:"email"`
AvatarUrl string `json:"picture"`
Status string `json:"status"`
Msg string `json:"msg"`
}
func (idp *CasdoorIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
cdUserinfo := &CasdoorUserInfo{}
accessToken := token.AccessToken
request, err := http.NewRequest("GET", fmt.Sprintf("%s/api/userinfo", idp.Host), nil)
if err != nil {
return nil, err
}
//add accesstoken to bearer token
request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", accessToken))
resp, err := idp.Client.Do(request)
if err != nil {
return nil, err
}
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
err = json.Unmarshal(data, cdUserinfo)
if err != nil {
return nil, err
}
if cdUserinfo.Status != "" {
return nil, fmt.Errorf("err: %s", cdUserinfo.Msg)
}
userInfo := &UserInfo{
Id: cdUserinfo.Id,
Username: cdUserinfo.Name,
DisplayName: cdUserinfo.DisplayName,
Email: cdUserinfo.Email,
AvatarUrl: cdUserinfo.AvatarUrl,
}
return userInfo, nil
}

View File

@ -18,6 +18,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
"io/ioutil"
"net/http" "net/http"
"strings" "strings"
"time" "time"
@ -143,7 +144,7 @@ func (idp *DingTalkIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, erro
return nil, err return nil, err
} }
data, err := io.ReadAll(resp.Body) data, err := ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -178,7 +179,7 @@ func (idp *DingTalkIdProvider) postWithBody(body interface{}, url string) ([]byt
if err != nil { if err != nil {
return nil, err return nil, err
} }
data, err := io.ReadAll(resp.Body) data, err := ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -19,6 +19,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
"io/ioutil"
"net/http" "net/http"
"net/url" "net/url"
"strconv" "strconv"
@ -92,7 +93,7 @@ func (idp *GiteeIdProvider) GetToken(code string) (*oauth2.Token, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
rbs, err := io.ReadAll(resp.Body) rbs, err := ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -17,7 +17,7 @@ package idp
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"io" "io/ioutil"
"net/http" "net/http"
"strconv" "strconv"
"time" "time"
@ -172,7 +172,7 @@ func (idp *GithubIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error)
defer resp.Body.Close() defer resp.Body.Close()
body, err := io.ReadAll(resp.Body) body, err := ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -17,7 +17,7 @@ package idp
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io/ioutil"
"net/http" "net/http"
"net/url" "net/url"
"strconv" "strconv"
@ -85,7 +85,7 @@ func (idp *GitlabIdProvider) GetToken(code string) (*oauth2.Token, error) {
return nil, err return nil, err
} }
data, err := io.ReadAll(resp.Body) data, err := ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -209,7 +209,7 @@ func (idp *GitlabIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error)
return nil, err return nil, err
} }
data, err := io.ReadAll(resp.Body) data, err := ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -19,7 +19,7 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"io" "io/ioutil"
"net/http" "net/http"
"golang.org/x/oauth2" "golang.org/x/oauth2"
@ -95,7 +95,7 @@ func (idp *GoogleIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error)
} }
defer resp.Body.Close() defer resp.Body.Close()
body, err := io.ReadAll(resp.Body) body, err := ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -17,7 +17,7 @@ package idp
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io/ioutil"
"net/http" "net/http"
"golang.org/x/oauth2" "golang.org/x/oauth2"
@ -69,7 +69,7 @@ func (idp *InfoflowInternalIdProvider) GetToken(code string) (*oauth2.Token, err
return nil, err return nil, err
} }
data, err := io.ReadAll(resp.Body) data, err := ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -147,7 +147,7 @@ func (idp *InfoflowInternalIdProvider) GetUserInfo(token *oauth2.Token) (*UserIn
return nil, err return nil, err
} }
data, err := io.ReadAll(resp.Body) data, err := ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -165,7 +165,7 @@ func (idp *InfoflowInternalIdProvider) GetUserInfo(token *oauth2.Token) (*UserIn
return nil, err return nil, err
} }
data, err = io.ReadAll(resp.Body) data, err = ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -18,6 +18,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
"io/ioutil"
"net/http" "net/http"
"strings" "strings"
"time" "time"
@ -143,7 +144,7 @@ func (idp *InfoflowIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, erro
return nil, err return nil, err
} }
data, err := io.ReadAll(resp.Body) data, err := ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -161,7 +162,7 @@ func (idp *InfoflowIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, erro
return nil, err return nil, err
} }
data, err = io.ReadAll(resp.Body) data, err = ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -196,7 +197,7 @@ func (idp *InfoflowIdProvider) postWithBody(body interface{}, url string) ([]byt
if err != nil { if err != nil {
return nil, err return nil, err
} }
data, err := io.ReadAll(resp.Body) data, err := ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -17,6 +17,7 @@ package idp
import ( import (
"encoding/json" "encoding/json"
"io" "io"
"io/ioutil"
"net/http" "net/http"
"strings" "strings"
"time" "time"
@ -168,7 +169,7 @@ func (idp *LarkIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
req.Header.Set("Authorization", "Bearer "+token.AccessToken) req.Header.Set("Authorization", "Bearer "+token.AccessToken)
resp, err := idp.Client.Do(req) resp, err := idp.Client.Do(req)
data, err = io.ReadAll(resp.Body) data, err = ioutil.ReadAll(resp.Body)
err = resp.Body.Close() err = resp.Body.Close()
if err != nil { if err != nil {
return nil, err return nil, err
@ -200,7 +201,7 @@ func (idp *LarkIdProvider) postWithBody(body interface{}, url string) ([]byte, e
if err != nil { if err != nil {
return nil, err return nil, err
} }
data, err := io.ReadAll(resp.Body) data, err := ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -18,6 +18,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
"io/ioutil"
"net/http" "net/http"
"net/url" "net/url"
"strings" "strings"
@ -84,7 +85,7 @@ func (idp *LinkedInIdProvider) GetToken(code string) (*oauth2.Token, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
rbs, err := io.ReadAll(resp.Body) rbs, err := ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -322,7 +323,7 @@ func (idp *LinkedInIdProvider) GetUrlRespWithAuthorization(url, token string) ([
} }
}(resp.Body) }(resp.Body)
bs, err := io.ReadAll(resp.Body) bs, err := ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -78,6 +78,8 @@ func GetIdProvider(typ string, subType string, clientId string, clientSecret str
} else { } else {
return nil return nil
} }
} else if typ == "Casdoor" {
return NewCasdoorIdProvider(clientId, clientSecret, redirectUrl, hostUrl)
} else if isGothSupport(typ) { } else if isGothSupport(typ) {
return NewGothIdProvider(typ, clientId, clientSecret, redirectUrl) return NewGothIdProvider(typ, clientId, clientSecret, redirectUrl)
} }

View File

@ -18,7 +18,7 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"io" "io/ioutil"
"net/http" "net/http"
"net/url" "net/url"
"regexp" "regexp"
@ -75,7 +75,7 @@ func (idp *QqIdProvider) GetToken(code string) (*oauth2.Token, error) {
} }
defer resp.Body.Close() defer resp.Body.Close()
tokenContent, err := io.ReadAll(resp.Body) tokenContent, err := ioutil.ReadAll(resp.Body)
re := regexp.MustCompile("token=(.*?)&") re := regexp.MustCompile("token=(.*?)&")
matched := re.FindAllStringSubmatch(string(tokenContent), -1) matched := re.FindAllStringSubmatch(string(tokenContent), -1)
@ -145,7 +145,7 @@ func (idp *QqIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
} }
defer resp.Body.Close() defer resp.Body.Close()
openIdBody, err := io.ReadAll(resp.Body) openIdBody, err := ioutil.ReadAll(resp.Body)
re := regexp.MustCompile("\"openid\":\"(.*?)\"}") re := regexp.MustCompile("\"openid\":\"(.*?)\"}")
matched := re.FindAllStringSubmatch(string(openIdBody), -1) matched := re.FindAllStringSubmatch(string(openIdBody), -1)
@ -161,7 +161,7 @@ func (idp *QqIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
} }
defer resp.Body.Close() defer resp.Body.Close()
userInfoBody, err := io.ReadAll(resp.Body) userInfoBody, err := ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -17,7 +17,7 @@ package idp
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io/ioutil"
"net/http" "net/http"
"time" "time"
@ -72,7 +72,7 @@ func (idp *WeComInternalIdProvider) GetToken(code string) (*oauth2.Token, error)
return nil, err return nil, err
} }
data, err := io.ReadAll(resp.Body) data, err := ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -122,7 +122,7 @@ func (idp *WeComInternalIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo,
return nil, err return nil, err
} }
data, err := io.ReadAll(resp.Body) data, err := ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -143,7 +143,7 @@ func (idp *WeComInternalIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo,
return nil, err return nil, err
} }
data, err = io.ReadAll(resp.Body) data, err = ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -18,6 +18,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
"io/ioutil"
"net/http" "net/http"
"strings" "strings"
"time" "time"
@ -194,7 +195,7 @@ func (idp *WeComIdProvider) postWithBody(body interface{}, url string) ([]byte,
if err != nil { if err != nil {
return nil, err return nil, err
} }
data, err := io.ReadAll(resp.Body) data, err := ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -19,6 +19,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
"io/ioutil"
"net/http" "net/http"
"net/url" "net/url"
"strconv" "strconv"
@ -91,7 +92,7 @@ func (idp *WeiBoIdProvider) GetToken(code string) (*oauth2.Token, error) {
return return
} }
}(resp.Body) }(resp.Body)
bs, err := io.ReadAll(resp.Body) bs, err := ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -22,6 +22,7 @@ import (
"github.com/astaxie/beego/logs" "github.com/astaxie/beego/logs"
_ "github.com/astaxie/beego/session/redis" _ "github.com/astaxie/beego/session/redis"
"github.com/casdoor/casdoor/authz" "github.com/casdoor/casdoor/authz"
"github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/object" "github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/proxy" "github.com/casdoor/casdoor/proxy"
"github.com/casdoor/casdoor/routers" "github.com/casdoor/casdoor/routers"
@ -31,6 +32,7 @@ import (
func main() { func main() {
createDatabase := flag.Bool("createDatabase", false, "true if you need casdoor to create database") createDatabase := flag.Bool("createDatabase", false, "true if you need casdoor to create database")
flag.Parse() flag.Parse()
object.InitAdapter(*createDatabase) object.InitAdapter(*createDatabase)
object.InitDb() object.InitDb()
object.InitDefaultStorageProvider() object.InitDefaultStorageProvider()
@ -52,12 +54,12 @@ func main() {
beego.InsertFilter("*", beego.BeforeRouter, routers.RecordMessage) beego.InsertFilter("*", beego.BeforeRouter, routers.RecordMessage)
beego.BConfig.WebConfig.Session.SessionName = "casdoor_session_id" beego.BConfig.WebConfig.Session.SessionName = "casdoor_session_id"
if beego.AppConfig.String("redisEndpoint") == "" { if conf.GetConfigString("redisEndpoint") == "" {
beego.BConfig.WebConfig.Session.SessionProvider = "file" beego.BConfig.WebConfig.Session.SessionProvider = "file"
beego.BConfig.WebConfig.Session.SessionProviderConfig = "./tmp" beego.BConfig.WebConfig.Session.SessionProviderConfig = "./tmp"
} else { } else {
beego.BConfig.WebConfig.Session.SessionProvider = "redis" beego.BConfig.WebConfig.Session.SessionProvider = "redis"
beego.BConfig.WebConfig.Session.SessionProviderConfig = beego.AppConfig.String("redisEndpoint") beego.BConfig.WebConfig.Session.SessionProviderConfig = conf.GetConfigString("redisEndpoint")
} }
beego.BConfig.WebConfig.Session.SessionCookieLifeTime = 3600 * 24 * 30 beego.BConfig.WebConfig.Session.SessionCookieLifeTime = 3600 * 24 * 30
//beego.BConfig.WebConfig.Session.SessionCookieSameSite = http.SameSiteNoneMode //beego.BConfig.WebConfig.Session.SessionCookieSameSite = http.SameSiteNoneMode

View File

@ -41,7 +41,7 @@ func InitConfig() {
func InitAdapter(createDatabase bool) { func InitAdapter(createDatabase bool) {
adapter = NewAdapter(beego.AppConfig.String("driverName"), conf.GetBeegoConfDataSourceName(), beego.AppConfig.String("dbName")) adapter = NewAdapter(conf.GetConfigString("driverName"), conf.GetBeegoConfDataSourceName(), conf.GetConfigString("dbName"))
if createDatabase { if createDatabase {
adapter.CreateDatabase() adapter.CreateDatabase()
} }
@ -111,10 +111,10 @@ func (a *Adapter) close() {
} }
func (a *Adapter) createTable() { func (a *Adapter) createTable() {
showSql, _ := beego.AppConfig.Bool("showSql") showSql, _ := conf.GetConfigBool("showSql")
a.Engine.ShowSQL(showSql) a.Engine.ShowSQL(showSql)
tableNamePrefix := beego.AppConfig.String("tableNamePrefix") tableNamePrefix := conf.GetConfigString("tableNamePrefix")
tbMapper := core.NewPrefixMapper(core.SnakeMapper{}, tableNamePrefix) tbMapper := core.NewPrefixMapper(core.SnakeMapper{}, tableNamePrefix)
a.Engine.SetTableMapper(tbMapper) a.Engine.SetTableMapper(tbMapper)

View File

@ -229,7 +229,7 @@ func GetMaskedApplication(application *Application, userId string) *Application
application.OrganizationObj.PasswordSalt = "***" application.OrganizationObj.PasswordSalt = "***"
} }
} }
return application return application
} }
func GetMaskedApplications(applications []*Application, userId string) []*Application { func GetMaskedApplications(applications []*Application, userId string) []*Application {

View File

@ -19,14 +19,14 @@ import (
"fmt" "fmt"
"io" "io"
"github.com/astaxie/beego" "github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/proxy" "github.com/casdoor/casdoor/proxy"
) )
var defaultStorageProvider *Provider = nil var defaultStorageProvider *Provider = nil
func InitDefaultStorageProvider() { func InitDefaultStorageProvider() {
defaultStorageProviderStr := beego.AppConfig.String("defaultStorageProvider") defaultStorageProviderStr := conf.GetConfigString("defaultStorageProvider")
if defaultStorageProviderStr != "" { if defaultStorageProviderStr != "" {
defaultStorageProvider = getProvider("admin", defaultStorageProviderStr) defaultStorageProvider = getProvider("admin", defaultStorageProviderStr)
} }

View File

@ -15,17 +15,11 @@
package object package object
import ( import (
_ "embed" "io/ioutil"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
) )
//go:embed token_jwt_key.pem
var tokenJwtPublicKey string
//go:embed token_jwt_key.key
var tokenJwtPrivateKey string
func InitDb() { func InitDb() {
initBuiltInOrganization() initBuiltInOrganization()
initBuiltInUser() initBuiltInUser()
@ -122,7 +116,22 @@ func initBuiltInApplication() {
AddApplication(application) AddApplication(application)
} }
func readTokenFromFile() (string, string) {
pemPath := "./object/token_jwt_key.pem"
keyPath := "./object/token_jwt_key.key"
pem, err := ioutil.ReadFile(pemPath)
if err != nil {
return "", ""
}
key, err := ioutil.ReadFile(keyPath)
if err != nil {
return "", ""
}
return string(pem), string(key)
}
func initBuiltInCert() { func initBuiltInCert() {
tokenJwtPublicKey, tokenJwtPrivateKey := readTokenFromFile()
cert := getCert("admin", "cert-built-in") cert := getCert("admin", "cert-built-in")
if cert != nil { if cert != nil {
return return

View File

@ -20,7 +20,7 @@ import (
"fmt" "fmt"
"strings" "strings"
"github.com/astaxie/beego" "github.com/casdoor/casdoor/conf"
"gopkg.in/square/go-jose.v2" "gopkg.in/square/go-jose.v2"
) )
@ -58,7 +58,7 @@ func getOriginFromHost(host string) (string, string) {
func GetOidcDiscovery(host string) OidcDiscovery { func GetOidcDiscovery(host string) OidcDiscovery {
originFrontend, originBackend := getOriginFromHost(host) originFrontend, originBackend := getOriginFromHost(host)
origin := beego.AppConfig.String("origin") origin := conf.GetConfigString("origin")
if origin != "" { if origin != "" {
originFrontend = origin originFrontend = origin
originBackend = origin originBackend = origin

View File

@ -13,6 +13,7 @@
// limitations under the License. // limitations under the License.
//go:build !skipCi //go:build !skipCi
// +build !skipCi
package object package object

View File

@ -18,8 +18,8 @@ import (
"fmt" "fmt"
"strings" "strings"
"github.com/astaxie/beego"
"github.com/astaxie/beego/context" "github.com/astaxie/beego/context"
"github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
) )
@ -27,7 +27,7 @@ var logPostOnly bool
func init() { func init() {
var err error var err error
logPostOnly, err = beego.AppConfig.Bool("logPostOnly") logPostOnly, err = conf.GetConfigBool("logPostOnly")
if err != nil { if err != nil {
//panic(err) //panic(err)
} }

View File

@ -23,7 +23,7 @@ import (
"regexp" "regexp"
"strings" "strings"
"github.com/astaxie/beego" "github.com/casdoor/casdoor/conf"
saml2 "github.com/russellhaering/gosaml2" saml2 "github.com/russellhaering/gosaml2"
dsig "github.com/russellhaering/goxmldsig" dsig "github.com/russellhaering/goxmldsig"
) )
@ -73,7 +73,7 @@ func buildSp(provider *Provider, samlResponse string) (*saml2.SAMLServiceProvide
certStore := dsig.MemoryX509CertificateStore{ certStore := dsig.MemoryX509CertificateStore{
Roots: []*x509.Certificate{}, Roots: []*x509.Certificate{},
} }
origin := beego.AppConfig.String("origin") origin := conf.GetConfigString("origin")
certEncodedData := "" certEncodedData := ""
if samlResponse != "" { if samlResponse != "" {
certEncodedData = parseSamlResponse(samlResponse, provider.Type) certEncodedData = parseSamlResponse(samlResponse, provider.Type)

View File

@ -19,7 +19,7 @@ import (
"fmt" "fmt"
"strings" "strings"
"github.com/astaxie/beego" "github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/storage" "github.com/casdoor/casdoor/storage"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
) )
@ -28,7 +28,7 @@ var isCloudIntranet bool
func init() { func init() {
var err error var err error
isCloudIntranet, err = beego.AppConfig.Bool("isCloudIntranet") isCloudIntranet, err = conf.GetConfigBool("isCloudIntranet")
if err != nil { if err != nil {
//panic(err) //panic(err)
} }

View File

@ -10,6 +10,7 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//go:build !skipCi //go:build !skipCi
// +build !skipCi // +build !skipCi

View File

@ -15,11 +15,10 @@
package object package object
import ( import (
_ "embed"
"fmt" "fmt"
"time" "time"
"github.com/astaxie/beego" "github.com/casdoor/casdoor/conf"
"github.com/golang-jwt/jwt/v4" "github.com/golang-jwt/jwt/v4"
) )
@ -67,7 +66,7 @@ func generateJwtToken(application *Application, user *User, nonce string, scope
refreshExpireTime := nowTime.Add(time.Duration(application.RefreshExpireInHours) * time.Hour) refreshExpireTime := nowTime.Add(time.Duration(application.RefreshExpireInHours) * time.Hour)
user.Password = "" user.Password = ""
origin := beego.AppConfig.String("origin") origin := conf.GetConfigString("origin")
_, originBackend := getOriginFromHost(host) _, originBackend := getOriginFromHost(host)
if origin != "" { if origin != "" {
originBackend = origin originBackend = origin

View File

@ -18,7 +18,7 @@ import (
"fmt" "fmt"
"strings" "strings"
"github.com/astaxie/beego" "github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"xorm.io/core" "xorm.io/core"
) )
@ -85,6 +85,7 @@ type User struct {
Gitlab string `xorm:"gitlab varchar(100)" json:"gitlab"` Gitlab string `xorm:"gitlab varchar(100)" json:"gitlab"`
Adfs string `xorm:"adfs varchar(100)" json:"adfs"` Adfs string `xorm:"adfs varchar(100)" json:"adfs"`
Baidu string `xorm:"baidu varchar(100)" json:"baidu"` Baidu string `xorm:"baidu varchar(100)" json:"baidu"`
Casdoor string `xorm:"casdoor varchar(100)" json:"casdoor"`
Infoflow string `xorm:"infoflow varchar(100)" json:"infoflow"` Infoflow string `xorm:"infoflow varchar(100)" json:"infoflow"`
Apple string `xorm:"apple varchar(100)" json:"apple"` Apple string `xorm:"apple varchar(100)" json:"apple"`
AzureAD string `xorm:"azuread varchar(100)" json:"azuread"` AzureAD string `xorm:"azuread varchar(100)" json:"azuread"`
@ -428,7 +429,7 @@ func GetUserInfo(userId string, scope string, aud string, host string) (*Userinf
if user == nil { if user == nil {
return nil, fmt.Errorf("the user: %s doesn't exist", userId) return nil, fmt.Errorf("the user: %s doesn't exist", userId)
} }
origin := beego.AppConfig.String("origin") origin := conf.GetConfigString("origin")
_, originBackend := getOriginFromHost(host) _, originBackend := getOriginFromHost(host)
if origin != "" { if origin != "" {
originBackend = origin originBackend = origin

View File

@ -52,8 +52,8 @@ func UploadUsers(owner string, fileId string) bool {
oldUserMap := getUserMap(owner) oldUserMap := getUserMap(owner)
newUsers := []*User{} newUsers := []*User{}
for _, line := range table { for index, line := range table {
if parseLineItem(&line, 0) == "" { if index == 0 || parseLineItem(&line, 0) == "" {
continue continue
} }
@ -67,38 +67,42 @@ func UploadUsers(owner string, fileId string) bool {
Password: parseLineItem(&line, 6), Password: parseLineItem(&line, 6),
PasswordSalt: parseLineItem(&line, 7), PasswordSalt: parseLineItem(&line, 7),
DisplayName: parseLineItem(&line, 8), DisplayName: parseLineItem(&line, 8),
Avatar: parseLineItem(&line, 9), FirstName: parseLineItem(&line, 9),
LastName: parseLineItem(&line, 10),
Avatar: parseLineItem(&line, 11),
PermanentAvatar: "", PermanentAvatar: "",
Email: parseLineItem(&line, 10), Email: parseLineItem(&line, 12),
Phone: parseLineItem(&line, 11), Phone: parseLineItem(&line, 13),
Location: parseLineItem(&line, 12), Location: parseLineItem(&line, 14),
Address: []string{parseLineItem(&line, 13)}, Address: []string{parseLineItem(&line, 15)},
Affiliation: parseLineItem(&line, 14), Affiliation: parseLineItem(&line, 16),
Title: parseLineItem(&line, 15), Title: parseLineItem(&line, 17),
IdCardType: parseLineItem(&line, 16), IdCardType: parseLineItem(&line, 18),
IdCard: parseLineItem(&line, 17), IdCard: parseLineItem(&line, 19),
Homepage: parseLineItem(&line, 18), Homepage: parseLineItem(&line, 20),
Bio: parseLineItem(&line, 19), Bio: parseLineItem(&line, 21),
Tag: parseLineItem(&line, 20), Tag: parseLineItem(&line, 22),
Region: parseLineItem(&line, 21), Region: parseLineItem(&line, 23),
Language: parseLineItem(&line, 22), Language: parseLineItem(&line, 24),
Gender: parseLineItem(&line, 23), Gender: parseLineItem(&line, 25),
Birthday: parseLineItem(&line, 24), Birthday: parseLineItem(&line, 26),
Education: parseLineItem(&line, 25), Education: parseLineItem(&line, 27),
Score: parseLineItemInt(&line, 26), Score: parseLineItemInt(&line, 28),
Ranking: parseLineItemInt(&line, 27), Karma: parseLineItemInt(&line, 29),
Ranking: parseLineItemInt(&line, 30),
IsDefaultAvatar: false, IsDefaultAvatar: false,
IsOnline: parseLineItemBool(&line, 28), IsOnline: parseLineItemBool(&line, 31),
IsAdmin: parseLineItemBool(&line, 29), IsAdmin: parseLineItemBool(&line, 32),
IsGlobalAdmin: parseLineItemBool(&line, 30), IsGlobalAdmin: parseLineItemBool(&line, 33),
IsForbidden: parseLineItemBool(&line, 31), IsForbidden: parseLineItemBool(&line, 34),
IsDeleted: parseLineItemBool(&line, 32), IsDeleted: parseLineItemBool(&line, 35),
SignupApplication: parseLineItem(&line, 33), SignupApplication: parseLineItem(&line, 36),
Hash: "", Hash: "",
PreHash: "", PreHash: "",
CreatedIp: parseLineItem(&line, 34), CreatedIp: parseLineItem(&line, 37),
LastSigninTime: parseLineItem(&line, 35), LastSigninTime: parseLineItem(&line, 38),
LastSigninIp: parseLineItem(&line, 36), LastSigninIp: parseLineItem(&line, 39),
Ldap: "",
Properties: map[string]string{}, Properties: map[string]string{},
} }

View File

@ -20,7 +20,7 @@ import (
"math/rand" "math/rand"
"time" "time"
"github.com/astaxie/beego" "github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"xorm.io/core" "xorm.io/core"
) )
@ -129,7 +129,7 @@ func CheckVerificationCode(dest, code string) string {
return "Code has not been sent yet!" return "Code has not been sent yet!"
} }
timeout, err := beego.AppConfig.Int64("verificationCodeTimeout") timeout, err := conf.GetConfigInt64("verificationCodeTimeout")
if err != nil { if err != nil {
panic(err) panic(err)
} }

View File

@ -21,7 +21,7 @@ import (
"strings" "strings"
"time" "time"
"github.com/astaxie/beego" "github.com/casdoor/casdoor/conf"
"golang.org/x/net/proxy" "golang.org/x/net/proxy"
) )
@ -54,7 +54,7 @@ func isAddressOpen(address string) bool {
} }
func getProxyHttpClient() *http.Client { func getProxyHttpClient() *http.Client {
sock5Proxy := beego.AppConfig.String("sock5Proxy") sock5Proxy := conf.GetConfigString("sock5Proxy")
if sock5Proxy == "" { if sock5Proxy == "" {
return &http.Client{} return &http.Client{}
} }

View File

@ -478,6 +478,39 @@
} }
} }
}, },
"/api/buy-product": {
"post": {
"tags": [
"Product API"
],
"description": "buy product",
"operationId": "ApiController.BuyProduct",
"parameters": [
{
"in": "query",
"name": "id",
"description": "The id of the product",
"required": true,
"type": "string"
},
{
"in": "query",
"name": "providerName",
"description": "The name of the provider",
"required": true,
"type": "string"
}
],
"responses": {
"200": {
"description": "The Response object",
"schema": {
"$ref": "#/definitions/controllers.Response"
}
}
}
}
},
"/api/check-ldap-users-exist": { "/api/check-ldap-users-exist": {
"post": { "post": {
"tags": [ "tags": [
@ -1710,6 +1743,49 @@
} }
} }
}, },
"/api/get-user-payments": {
"get": {
"tags": [
"Payment API"
],
"description": "get payments for a user",
"operationId": "ApiController.GetUserPayments",
"parameters": [
{
"in": "query",
"name": "owner",
"description": "The owner of payments",
"required": true,
"type": "string"
},
{
"in": "query",
"name": "organization",
"description": "The organization of the user",
"required": true,
"type": "string"
},
{
"in": "query",
"name": "user",
"description": "The username of the user",
"required": true,
"type": "string"
}
],
"responses": {
"200": {
"description": "The Response object",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/object.Payment"
}
}
}
}
}
},
"/api/get-users": { "/api/get-users": {
"get": { "get": {
"tags": [ "tags": [
@ -1936,6 +2012,36 @@
} }
} }
}, },
"/api/login/oauth/introspect": {
"post": {
"description": "The introspection endpoint is an OAuth 2.0 endpoint that takes a",
"operationId": "ApiController.IntrospectToken",
"parameters": [
{
"in": "formData",
"name": "token",
"description": "access_token's value or refresh_token's value",
"required": true,
"type": "string"
},
{
"in": "formData",
"name": "token_type_hint",
"description": "the token type access_token or refresh_token",
"required": true,
"type": "string"
}
],
"responses": {
"200": {
"description": "The Response object",
"schema": {
"$ref": "#/definitions/object.IntrospectionResponse"
}
}
}
}
},
"/api/login/oauth/logout": { "/api/login/oauth/logout": {
"get": { "get": {
"tags": [ "tags": [
@ -2015,7 +2121,6 @@
"in": "query", "in": "query",
"name": "client_secret", "name": "client_secret",
"description": "OAuth client secret", "description": "OAuth client secret",
"required": true,
"type": "string" "type": "string"
} }
], ],
@ -2046,6 +2151,34 @@
} }
} }
}, },
"/api/notify-payment": {
"post": {
"tags": [
"Payment API"
],
"description": "notify payment",
"operationId": "ApiController.NotifyPayment",
"parameters": [
{
"in": "body",
"name": "body",
"description": "The details of the payment",
"required": true,
"schema": {
"$ref": "#/definitions/object.Payment"
}
}
],
"responses": {
"200": {
"description": "The Response object",
"schema": {
"$ref": "#/definitions/controllers.Response"
}
}
}
}
},
"/api/send-verification-code": { "/api/send-verification-code": {
"post": { "post": {
"tags": [ "tags": [
@ -2664,11 +2797,11 @@
} }
}, },
"definitions": { "definitions": {
"2015.0xc0000edb90.false": { "2026.0xc000380de0.false": {
"title": "false", "title": "false",
"type": "object" "type": "object"
}, },
"2049.0xc0000edbc0.false": { "2060.0xc000380e10.false": {
"title": "false", "title": "false",
"type": "object" "type": "object"
}, },
@ -2685,10 +2818,10 @@
"type": "object", "type": "object",
"properties": { "properties": {
"data": { "data": {
"$ref": "#/definitions/2015.0xc0000edb90.false" "$ref": "#/definitions/2026.0xc000380de0.false"
}, },
"data2": { "data2": {
"$ref": "#/definitions/2049.0xc0000edbc0.false" "$ref": "#/definitions/2060.0xc000380e10.false"
}, },
"msg": { "msg": {
"type": "string" "type": "string"
@ -2709,10 +2842,10 @@
"type": "object", "type": "object",
"properties": { "properties": {
"data": { "data": {
"$ref": "#/definitions/2015.0xc0000edb90.false" "$ref": "#/definitions/2026.0xc000380de0.false"
}, },
"data2": { "data2": {
"$ref": "#/definitions/2049.0xc0000edbc0.false" "$ref": "#/definitions/2060.0xc000380e10.false"
}, },
"msg": { "msg": {
"type": "string" "type": "string"
@ -2864,6 +2997,12 @@
"title": "Cert", "title": "Cert",
"type": "object", "type": "object",
"properties": { "properties": {
"authorityPublicKey": {
"type": "string"
},
"authorityRootPublicKey": {
"type": "string"
},
"bitSize": { "bitSize": {
"type": "integer", "type": "integer",
"format": "int64" "format": "int64"
@ -2913,6 +3052,54 @@
} }
} }
}, },
"object.IntrospectionResponse": {
"title": "IntrospectionResponse",
"type": "object",
"properties": {
"active": {
"type": "boolean"
},
"aud": {
"type": "array",
"items": {
"type": "string"
}
},
"client_id": {
"type": "string"
},
"exp": {
"type": "integer",
"format": "int64"
},
"iat": {
"type": "integer",
"format": "int64"
},
"iss": {
"type": "string"
},
"jti": {
"type": "string"
},
"nbf": {
"type": "integer",
"format": "int64"
},
"scope": {
"type": "string"
},
"sub": {
"type": "string"
},
"token_type": {
"type": "string"
},
"username": {
"type": "string"
}
}
},
"object.Organization": { "object.Organization": {
"title": "Organization", "title": "Organization",
"type": "object", "type": "object",
@ -2950,6 +3137,12 @@
"phonePrefix": { "phonePrefix": {
"type": "string" "type": "string"
}, },
"tags": {
"type": "array",
"items": {
"type": "string"
}
},
"websiteUrl": { "websiteUrl": {
"type": "string" "type": "string"
} }
@ -2959,19 +3152,19 @@
"title": "Payment", "title": "Payment",
"type": "object", "type": "object",
"properties": { "properties": {
"amount": {
"type": "string"
},
"createdTime": { "createdTime": {
"type": "string" "type": "string"
}, },
"currency": { "currency": {
"type": "string" "type": "string"
}, },
"detail": {
"type": "string"
},
"displayName": { "displayName": {
"type": "string" "type": "string"
}, },
"good": { "message": {
"type": "string" "type": "string"
}, },
"name": { "name": {
@ -2983,12 +3176,31 @@
"owner": { "owner": {
"type": "string" "type": "string"
}, },
"payUrl": {
"type": "string"
},
"price": {
"type": "number",
"format": "double"
},
"productDisplayName": {
"type": "string"
},
"productName": {
"type": "string"
},
"provider": { "provider": {
"type": "string" "type": "string"
}, },
"returnUrl": {
"type": "string"
},
"state": { "state": {
"type": "string" "type": "string"
}, },
"tag": {
"type": "string"
},
"type": { "type": {
"type": "string" "type": "string"
}, },
@ -3074,8 +3286,8 @@
"type": "string" "type": "string"
}, },
"price": { "price": {
"type": "integer", "type": "number",
"format": "int64" "format": "double"
}, },
"providers": { "providers": {
"type": "array", "type": "array",
@ -3087,6 +3299,9 @@
"type": "integer", "type": "integer",
"format": "int64" "format": "int64"
}, },
"returnUrl": {
"type": "string"
},
"sold": { "sold": {
"type": "integer", "type": "integer",
"format": "int64" "format": "int64"
@ -3112,6 +3327,9 @@
"category": { "category": {
"type": "string" "type": "string"
}, },
"cert": {
"type": "string"
},
"clientId": { "clientId": {
"type": "string" "type": "string"
}, },
@ -3482,6 +3700,9 @@
"birthday": { "birthday": {
"type": "string" "type": "string"
}, },
"casdoor": {
"type": "string"
},
"createdIp": { "createdIp": {
"type": "string" "type": "string"
}, },

View File

@ -309,6 +309,28 @@ paths:
description: object description: object
schema: schema:
$ref: '#/definitions/Response' $ref: '#/definitions/Response'
/api/buy-product:
post:
tags:
- Product API
description: buy product
operationId: ApiController.BuyProduct
parameters:
- in: query
name: id
description: The id of the product
required: true
type: string
- in: query
name: providerName
description: The name of the provider
required: true
type: string
responses:
"200":
description: The Response object
schema:
$ref: '#/definitions/controllers.Response'
/api/check-ldap-users-exist: /api/check-ldap-users-exist:
post: post:
tags: tags:
@ -1111,6 +1133,35 @@ paths:
responses: responses:
"200": "200":
description: '{int} int The count of filtered users for an organization' description: '{int} int The count of filtered users for an organization'
/api/get-user-payments:
get:
tags:
- Payment API
description: get payments for a user
operationId: ApiController.GetUserPayments
parameters:
- in: query
name: owner
description: The owner of payments
required: true
type: string
- in: query
name: organization
description: The organization of the user
required: true
type: string
- in: query
name: user
description: The username of the user
required: true
type: string
responses:
"200":
description: The Response object
schema:
type: array
items:
$ref: '#/definitions/object.Payment'
/api/get-users: /api/get-users:
get: get:
tags: tags:
@ -1262,6 +1313,26 @@ paths:
description: The Response object description: The Response object
schema: schema:
$ref: '#/definitions/object.TokenWrapper' $ref: '#/definitions/object.TokenWrapper'
/api/login/oauth/introspect:
post:
description: The introspection endpoint is an OAuth 2.0 endpoint that takes a
operationId: ApiController.IntrospectToken
parameters:
- in: formData
name: token
description: access_token's value or refresh_token's value
required: true
type: string
- in: formData
name: token_type_hint
description: the token type access_token or refresh_token
required: true
type: string
responses:
"200":
description: The Response object
schema:
$ref: '#/definitions/object.IntrospectionResponse'
/api/login/oauth/logout: /api/login/oauth/logout:
get: get:
tags: tags:
@ -1318,7 +1389,6 @@ paths:
- in: query - in: query
name: client_secret name: client_secret
description: OAuth client secret description: OAuth client secret
required: true
type: string type: string
responses: responses:
"200": "200":
@ -1336,6 +1406,24 @@ paths:
description: The Response object description: The Response object
schema: schema:
$ref: '#/definitions/controllers.Response' $ref: '#/definitions/controllers.Response'
/api/notify-payment:
post:
tags:
- Payment API
description: notify payment
operationId: ApiController.NotifyPayment
parameters:
- in: body
name: body
description: The details of the payment
required: true
schema:
$ref: '#/definitions/object.Payment'
responses:
"200":
description: The Response object
schema:
$ref: '#/definitions/controllers.Response'
/api/send-verification-code: /api/send-verification-code:
post: post:
tags: tags:
@ -1743,10 +1831,10 @@ paths:
schema: schema:
$ref: '#/definitions/object.Userinfo' $ref: '#/definitions/object.Userinfo'
definitions: definitions:
2015.0xc0000edb90.false: 2026.0xc000380de0.false:
title: "false" title: "false"
type: object type: object
2049.0xc0000edbc0.false: 2060.0xc000380e10.false:
title: "false" title: "false"
type: object type: object
RequestForm: RequestForm:
@ -1760,9 +1848,9 @@ definitions:
type: object type: object
properties: properties:
data: data:
$ref: '#/definitions/2015.0xc0000edb90.false' $ref: '#/definitions/2026.0xc000380de0.false'
data2: data2:
$ref: '#/definitions/2049.0xc0000edbc0.false' $ref: '#/definitions/2060.0xc000380e10.false'
msg: msg:
type: string type: string
name: name:
@ -1776,9 +1864,9 @@ definitions:
type: object type: object
properties: properties:
data: data:
$ref: '#/definitions/2015.0xc0000edb90.false' $ref: '#/definitions/2026.0xc000380de0.false'
data2: data2:
$ref: '#/definitions/2049.0xc0000edbc0.false' $ref: '#/definitions/2060.0xc000380e10.false'
msg: msg:
type: string type: string
name: name:
@ -1880,6 +1968,10 @@ definitions:
title: Cert title: Cert
type: object type: object
properties: properties:
authorityPublicKey:
type: string
authorityRootPublicKey:
type: string
bitSize: bitSize:
type: integer type: integer
format: int64 format: int64
@ -1912,6 +2004,39 @@ definitions:
type: string type: string
value: value:
type: string type: string
object.IntrospectionResponse:
title: IntrospectionResponse
type: object
properties:
active:
type: boolean
aud:
type: array
items:
type: string
client_id:
type: string
exp:
type: integer
format: int64
iat:
type: integer
format: int64
iss:
type: string
jti:
type: string
nbf:
type: integer
format: int64
scope:
type: string
sub:
type: string
token_type:
type: string
username:
type: string
object.Organization: object.Organization:
title: Organization title: Organization
type: object type: object
@ -1938,21 +2063,25 @@ definitions:
type: string type: string
phonePrefix: phonePrefix:
type: string type: string
tags:
type: array
items:
type: string
websiteUrl: websiteUrl:
type: string type: string
object.Payment: object.Payment:
title: Payment title: Payment
type: object type: object
properties: properties:
amount:
type: string
createdTime: createdTime:
type: string type: string
currency: currency:
type: string type: string
detail:
type: string
displayName: displayName:
type: string type: string
good: message:
type: string type: string
name: name:
type: string type: string
@ -1960,10 +2089,23 @@ definitions:
type: string type: string
owner: owner:
type: string type: string
payUrl:
type: string
price:
type: number
format: double
productDisplayName:
type: string
productName:
type: string
provider: provider:
type: string type: string
returnUrl:
type: string
state: state:
type: string type: string
tag:
type: string
type: type:
type: string type: string
user: user:
@ -2021,8 +2163,8 @@ definitions:
owner: owner:
type: string type: string
price: price:
type: integer type: number
format: int64 format: double
providers: providers:
type: array type: array
items: items:
@ -2030,6 +2172,8 @@ definitions:
quantity: quantity:
type: integer type: integer
format: int64 format: int64
returnUrl:
type: string
sold: sold:
type: integer type: integer
format: int64 format: int64
@ -2047,6 +2191,8 @@ definitions:
type: string type: string
category: category:
type: string type: string
cert:
type: string
clientId: clientId:
type: string type: string
clientId2: clientId2:
@ -2296,6 +2442,8 @@ definitions:
type: string type: string
birthday: birthday:
type: string type: string
casdoor:
type: string
createdIp: createdIp:
type: string type: string
createdTime: createdTime:

View File

@ -39,4 +39,4 @@ func IsPhoneCnValid(phone string) bool {
func getMaskedPhone(phone string) string { func getMaskedPhone(phone string) string {
return rePhone.ReplaceAllString(phone, "$1****$2") return rePhone.ReplaceAllString(phone, "$1****$2")
} }

View File

@ -20,7 +20,7 @@ import (
"encoding/hex" "encoding/hex"
"errors" "errors"
"fmt" "fmt"
"os" "io/ioutil"
"strconv" "strconv"
"strings" "strings"
"time" "time"
@ -162,7 +162,7 @@ func GetMinLenStr(strs ...string) string {
} }
func ReadStringFromPath(path string) string { func ReadStringFromPath(path string) string {
data, err := os.ReadFile(path) data, err := ioutil.ReadFile(path)
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -171,7 +171,7 @@ func ReadStringFromPath(path string) string {
} }
func WriteStringToPath(s string, path string) { func WriteStringToPath(s string, path string) {
err := os.WriteFile(path, []byte(s), 0644) err := ioutil.WriteFile(path, []byte(s), 0644)
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -220,7 +220,7 @@ func GetMaskedEmail(email string) string {
username := maskString(tokens[0]) username := maskString(tokens[0])
domain := tokens[1] domain := tokens[1]
domainTokens := strings.Split(domain, ".") domainTokens := strings.Split(domain, ".")
domainTokens[len(domainTokens) - 2] = maskString(domainTokens[len(domainTokens) - 2]) domainTokens[len(domainTokens)-2] = maskString(domainTokens[len(domainTokens)-2])
return fmt.Sprintf("%s@%s", username, strings.Join(domainTokens, ".")) return fmt.Sprintf("%s@%s", username, strings.Join(domainTokens, "."))
} }
@ -228,6 +228,6 @@ func maskString(str string) string {
if len(str) <= 2 { if len(str) <= 2 {
return str return str
} else { } else {
return fmt.Sprintf("%c%s%c", str[0], strings.Repeat("*", len(str) - 2), str[len(str) - 1]) return fmt.Sprintf("%c%s%c", str[0], strings.Repeat("*", len(str)-2), str[len(str)-1])
} }
} }

View File

@ -245,3 +245,4 @@ func TestSnakeString(t *testing.T) {
}) })
} }
} }

View File

@ -235,8 +235,12 @@ class App extends Component {
}); });
Setting.showMessage("success", `Logged out successfully`); Setting.showMessage("success", `Logged out successfully`);
let redirectUri = res.data2;
Setting.goToLinkSoft(this, "/"); if (redirectUri !== null && redirectUri !== undefined && redirectUri !== "") {
Setting.goToLink(redirectUri);
}else{
Setting.goToLinkSoft(this, "/");
}
} else { } else {
Setting.showMessage("error", `Failed to log out: ${res.msg}`); Setting.showMessage("error", `Failed to log out: ${res.msg}`);
} }

View File

@ -303,7 +303,7 @@ class ProviderEditPage extends React.Component {
) )
} }
{ {
this.state.provider.type !== "Adfs" ? null : ( this.state.provider.type !== "Adfs" && this.state.provider.type !== "Casdoor" ? null : (
<Row style={{marginTop: '20px'}} > <Row style={{marginTop: '20px'}} >
<Col style={{marginTop: '5px'}} span={2}> <Col style={{marginTop: '5px'}} span={2}>
{Setting.getLabel(i18next.t("provider:Domain"), i18next.t("provider:Domain - Tooltip"))} : {Setting.getLabel(i18next.t("provider:Domain"), i18next.t("provider:Domain - Tooltip"))} :

View File

@ -70,15 +70,7 @@ export function isProviderVisible(providerItem) {
return false; return false;
} }
if (providerItem.provider.type === "GitHub") { return true;
if (isLocalhost()) {
return providerItem.provider.name.includes("localhost");
} else {
return !providerItem.provider.name.includes("localhost");
}
} else {
return true;
}
} }
export function isProviderVisibleForSignUp(providerItem) { export function isProviderVisibleForSignUp(providerItem) {
@ -404,6 +396,7 @@ export function getProviderTypeOptions(category) {
{id: 'GitLab', name: 'GitLab'}, {id: 'GitLab', name: 'GitLab'},
{id: 'Adfs', name: 'Adfs'}, {id: 'Adfs', name: 'Adfs'},
{id: 'Baidu', name: 'Baidu'}, {id: 'Baidu', name: 'Baidu'},
{id: 'Casdoor', name: 'Casdoor'},
{id: 'Infoflow', name: 'Infoflow'}, {id: 'Infoflow', name: 'Infoflow'},
{id: 'Apple', name: 'Apple'}, {id: 'Apple', name: 'Apple'},
{id: 'AzureAD', name: 'AzureAD'}, {id: 'AzureAD', name: 'AzureAD'},

View File

@ -106,6 +106,7 @@ class AuthCallback extends React.Component {
method: method, method: method,
}; };
const oAuthParams = Util.getOAuthGetParameters(innerParams); const oAuthParams = Util.getOAuthGetParameters(innerParams);
const concatChar = oAuthParams?.redirectUri?.includes('?') ? '&' : '?';
AuthBackend.login(body, oAuthParams) AuthBackend.login(body, oAuthParams)
.then((res) => { .then((res) => {
if (res.status === 'ok') { if (res.status === 'ok') {
@ -118,11 +119,11 @@ class AuthCallback extends React.Component {
Setting.goToLink(link); Setting.goToLink(link);
} else if (responseType === "code") { } else if (responseType === "code") {
const code = res.data; const code = res.data;
Setting.goToLink(`${oAuthParams.redirectUri}?code=${code}&state=${oAuthParams.state}`); Setting.goToLink(`${oAuthParams.redirectUri}${concatChar}code=${code}&state=${oAuthParams.state}`);
// Util.showMessage("success", `Authorization code: ${res.data}`); // Util.showMessage("success", `Authorization code: ${res.data}`);
} else if (responseType === "token" || responseType === "id_token"){ } else if (responseType === "token" || responseType === "id_token"){
const token = res.data; const token = res.data;
Setting.goToLink(`${oAuthParams.redirectUri}?${responseType}=${token}&state=${oAuthParams.state}&token_type=bearer`); Setting.goToLink(`${oAuthParams.redirectUri}${concatChar}${responseType}=${token}&state=${oAuthParams.state}&token_type=bearer`);
} else if (responseType === "link") { } else if (responseType === "link") {
const from = innerParams.get("from"); const from = innerParams.get("from");
Setting.goToLinkSoft(this, from); Setting.goToLinkSoft(this, from);

View File

@ -0,0 +1,32 @@
// Copyright 2022 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.
import {createButton} from "react-social-login-buttons";
import {StaticBaseUrl} from "../Setting";
function Icon({ width = 24, height = 24, color }) {
return <img src={`${StaticBaseUrl}/buttons/casdoor.svg`} alt="Sign in with Casdoor" style={{width: 24, height: 24}} />;
}
const config = {
text: "Sign in with Casdoor",
icon: Icon,
iconFormat: name => `fa fa-${name}`,
style: {background: "#ffffff", color: "#000000"},
activeStyle: {background: "#ededee"},
};
const CasdoorLoginButton = createButton(config);
export default CasdoorLoginButton;

View File

@ -36,6 +36,7 @@ import LarkLoginButton from "./LarkLoginButton";
import GitLabLoginButton from "./GitLabLoginButton"; import GitLabLoginButton from "./GitLabLoginButton";
import AdfsLoginButton from "./AdfsLoginButton"; import AdfsLoginButton from "./AdfsLoginButton";
import BaiduLoginButton from "./BaiduLoginButton"; import BaiduLoginButton from "./BaiduLoginButton";
import CasdoorLoginButton from "./CasdoorLoginButton";
import InfoflowLoginButton from "./InfoflowLoginButton"; import InfoflowLoginButton from "./InfoflowLoginButton";
import AppleLoginButton from "./AppleLoginButton" import AppleLoginButton from "./AppleLoginButton"
import AzureADLoginButton from "./AzureADLoginButton"; import AzureADLoginButton from "./AzureADLoginButton";
@ -56,7 +57,9 @@ class LoginPage extends React.Component {
isCodeSignin: false, isCodeSignin: false,
msg: null, msg: null,
username: null, username: null,
validEmailOrPhone: false validEmailOrPhone: false,
validEmail: false,
validPhone: false,
}; };
} }
@ -135,6 +138,7 @@ class LoginPage extends React.Component {
Setting.goToLink(link); Setting.goToLink(link);
} else if (responseType === "code") { } else if (responseType === "code") {
const code = res.data; const code = res.data;
const concatChar = oAuthParams?.redirectUri?.includes('?') ? '&' : '?';
if (Setting.hasPromptPage(application)) { if (Setting.hasPromptPage(application)) {
AuthBackend.getAccount("") AuthBackend.getAccount("")
@ -147,7 +151,7 @@ class LoginPage extends React.Component {
this.onUpdateAccount(account); this.onUpdateAccount(account);
if (Setting.isPromptAnswered(account, application)) { if (Setting.isPromptAnswered(account, application)) {
Setting.goToLink(`${oAuthParams.redirectUri}?code=${code}&state=${oAuthParams.state}`); Setting.goToLink(`${oAuthParams.redirectUri}${concatChar}code=${code}&state=${oAuthParams.state}`);
} else { } else {
Setting.goToLinkSoft(ths, `/prompt/${application.name}?redirectUri=${oAuthParams.redirectUri}&code=${code}&state=${oAuthParams.state}`); Setting.goToLinkSoft(ths, `/prompt/${application.name}?redirectUri=${oAuthParams.redirectUri}&code=${code}&state=${oAuthParams.state}`);
} }
@ -156,7 +160,7 @@ class LoginPage extends React.Component {
} }
}); });
} else { } else {
Setting.goToLink(`${oAuthParams.redirectUri}?code=${code}&state=${oAuthParams.state}`); Setting.goToLink(`${oAuthParams.redirectUri}${concatChar}code=${code}&state=${oAuthParams.state}`);
} }
// Util.showMessage("success", `Authorization code: ${res.data}`); // Util.showMessage("success", `Authorization code: ${res.data}`);
@ -198,6 +202,8 @@ class LoginPage extends React.Component {
return <GitLabLoginButton text={text} align={"center"} /> return <GitLabLoginButton text={text} align={"center"} />
} else if (type === "Adfs") { } else if (type === "Adfs") {
return <AdfsLoginButton text={text} align={"center"} /> return <AdfsLoginButton text={text} align={"center"} />
} else if (type === "Casdoor") {
return <CasdoorLoginButton text={text} align={"center"} />
} else if (type === "Baidu") { } else if (type === "Baidu") {
return <BaiduLoginButton text={text} align={"center"} /> return <BaiduLoginButton text={text} align={"center"} />
} else if (type === "Infoflow") { } else if (type === "Infoflow") {
@ -344,6 +350,12 @@ class LoginPage extends React.Component {
return Promise.reject(i18next.t("login:The input is not valid Email or Phone!")); return Promise.reject(i18next.t("login:The input is not valid Email or Phone!"));
} }
} }
if (Setting.isValidPhone(this.state.username)) {
this.setState({validPhone: true})
}
if (Setting.isValidEmail(this.state.username)) {
this.setState({validEmail: true})
}
this.setState({validEmailOrPhone: true}); this.setState({validEmailOrPhone: true});
return Promise.resolve(); return Promise.resolve();
} }
@ -369,7 +381,7 @@ class LoginPage extends React.Component {
> >
<CountDownInput <CountDownInput
disabled={this.state.username?.length === 0 || !this.state.validEmailOrPhone} disabled={this.state.username?.length === 0 || !this.state.validEmailOrPhone}
onButtonClickArgs={[this.state.username, "", Setting.getApplicationOrgName(application), true]} onButtonClickArgs={[this.state.username, this.state.validEmail ? "email" : "phone", Setting.getApplicationOrgName(application)]}
/> />
</Form.Item> </Form.Item>
) : ( ) : (

View File

@ -147,7 +147,10 @@ class PromptPage extends React.Component {
if (res.status === 'ok') { if (res.status === 'ok') {
this.onUpdateAccount(null); this.onUpdateAccount(null);
const redirectUrl = this.getRedirectUrl(); let redirectUrl = this.getRedirectUrl();
if (redirectUrl === "") {
redirectUrl = res.data2
}
if (redirectUrl !== "") { if (redirectUrl !== "") {
Setting.goToLink(redirectUrl); Setting.goToLink(redirectUrl);
} else { } else {

View File

@ -15,7 +15,7 @@
import React from "react"; import React from "react";
import {Tooltip} from "antd"; import {Tooltip} from "antd";
import * as Util from "./Util"; import * as Util from "./Util";
import {StaticBaseUrl} from "../Setting"; import * as Setting from "../Setting";
const authInfo = { const authInfo = {
Google: { Google: {
@ -78,6 +78,10 @@ const authInfo = {
scope: "basic", scope: "basic",
endpoint: "http://openapi.baidu.com/oauth/2.0/authorize", endpoint: "http://openapi.baidu.com/oauth/2.0/authorize",
}, },
Casdoor: {
scope: "openid%20profile%20email",
endpoint: "http://example.com",
},
Infoflow: { Infoflow: {
endpoint: "https://xpc.im.baidu.com/oauth2/authorize", endpoint: "https://xpc.im.baidu.com/oauth2/authorize",
}, },
@ -101,71 +105,71 @@ const authInfo = {
const otherProviderInfo = { const otherProviderInfo = {
SMS: { SMS: {
"Aliyun SMS": { "Aliyun SMS": {
logo: `${StaticBaseUrl}/img/social_aliyun.png`, logo: `${Setting.StaticBaseUrl}/img/social_aliyun.png`,
url: "https://aliyun.com/product/sms", url: "https://aliyun.com/product/sms",
}, },
"Tencent Cloud SMS": { "Tencent Cloud SMS": {
logo: `${StaticBaseUrl}/img/social_tencent_cloud.jpg`, logo: `${Setting.StaticBaseUrl}/img/social_tencent_cloud.jpg`,
url: "https://cloud.tencent.com/product/sms", url: "https://cloud.tencent.com/product/sms",
}, },
"Volc Engine SMS": { "Volc Engine SMS": {
logo: `${StaticBaseUrl}/img/social_volc_engine.jpg`, logo: `${Setting.StaticBaseUrl}/img/social_volc_engine.jpg`,
url: "https://www.volcengine.com/products/cloud-sms", url: "https://www.volcengine.com/products/cloud-sms",
}, },
"Huawei Cloud SMS": { "Huawei Cloud SMS": {
logo: `${StaticBaseUrl}/img/social_huawei.png`, logo: `${Setting.StaticBaseUrl}/img/social_huawei.png`,
url: "https://www.huaweicloud.com/product/msgsms.html", url: "https://www.huaweicloud.com/product/msgsms.html",
}, },
}, },
Email: { Email: {
"Default": { "Default": {
logo: `${StaticBaseUrl}/img/social_default.png`, logo: `${Setting.StaticBaseUrl}/img/social_default.png`,
url: "", url: "",
}, },
}, },
Storage: { Storage: {
"Local File System": { "Local File System": {
logo: `${StaticBaseUrl}/img/social_file.png`, logo: `${Setting.StaticBaseUrl}/img/social_file.png`,
url: "", url: "",
}, },
"AWS S3": { "AWS S3": {
logo: `${StaticBaseUrl}/img/social_aws.png`, logo: `${Setting.StaticBaseUrl}/img/social_aws.png`,
url: "https://aws.amazon.com/s3", url: "https://aws.amazon.com/s3",
}, },
"Aliyun OSS": { "Aliyun OSS": {
logo: `${StaticBaseUrl}/img/social_aliyun.png`, logo: `${Setting.StaticBaseUrl}/img/social_aliyun.png`,
url: "https://aliyun.com/product/oss", url: "https://aliyun.com/product/oss",
}, },
"Tencent Cloud COS": { "Tencent Cloud COS": {
logo: `${StaticBaseUrl}/img/social_tencent_cloud.jpg`, logo: `${Setting.StaticBaseUrl}/img/social_tencent_cloud.jpg`,
url: "https://cloud.tencent.com/product/cos", url: "https://cloud.tencent.com/product/cos",
}, },
}, },
SAML: { SAML: {
"Aliyun IDaaS": { "Aliyun IDaaS": {
logo: `${StaticBaseUrl}/img/social_aliyun.png`, logo: `${Setting.StaticBaseUrl}/img/social_aliyun.png`,
url: "https://aliyun.com/product/idaas" url: "https://aliyun.com/product/idaas"
}, },
"Keycloak": { "Keycloak": {
logo: `${StaticBaseUrl}/img/social_keycloak.png`, logo: `${Setting.StaticBaseUrl}/img/social_keycloak.png`,
url: "https://www.keycloak.org/" url: "https://www.keycloak.org/"
}, },
}, },
Payment: { Payment: {
"Alipay": { "Alipay": {
logo: `${StaticBaseUrl}/img/payment_alipay.png`, logo: `${Setting.StaticBaseUrl}/img/payment_alipay.png`,
url: "https://www.alipay.com/" url: "https://www.alipay.com/"
}, },
"WeChat Pay": { "WeChat Pay": {
logo: `${StaticBaseUrl}/img/payment_wechat_pay.png`, logo: `${Setting.StaticBaseUrl}/img/payment_wechat_pay.png`,
url: "https://pay.weixin.qq.com/" url: "https://pay.weixin.qq.com/"
}, },
"PayPal": { "PayPal": {
logo: `${StaticBaseUrl}/img/payment_paypal.png`, logo: `${Setting.StaticBaseUrl}/img/payment_paypal.png`,
url: "https://www.paypal.com/" url: "https://www.paypal.com/"
}, },
"GC": { "GC": {
logo: `${StaticBaseUrl}/img/payment_gc.png`, logo: `${Setting.StaticBaseUrl}/img/payment_gc.png`,
url: "https://gc.org" url: "https://gc.org"
}, },
}, },
@ -173,7 +177,7 @@ const otherProviderInfo = {
export function getProviderLogo(provider) { export function getProviderLogo(provider) {
if (provider.category === "OAuth") { if (provider.category === "OAuth") {
return `${StaticBaseUrl}/img/social_${provider.type.toLowerCase()}.png`; return `${Setting.StaticBaseUrl}/img/social_${provider.type.toLowerCase()}.png`;
} else { } else {
return otherProviderInfo[provider.category][provider.type].logo; return otherProviderInfo[provider.category][provider.type].logo;
} }
@ -283,6 +287,8 @@ export function getAuthUrl(application, provider, method) {
return `${provider.domain}/adfs/oauth2/authorize?client_id=${provider.clientId}&redirect_uri=${redirectUri}&state=${state}&response_type=code&nonce=casdoor&scope=openid`; return `${provider.domain}/adfs/oauth2/authorize?client_id=${provider.clientId}&redirect_uri=${redirectUri}&state=${state}&response_type=code&nonce=casdoor&scope=openid`;
} else if (provider.type === "Baidu") { } else if (provider.type === "Baidu") {
return `${endpoint}?client_id=${provider.clientId}&redirect_uri=${redirectUri}&state=${state}&response_type=code&scope=${scope}&display=popup`; return `${endpoint}?client_id=${provider.clientId}&redirect_uri=${redirectUri}&state=${state}&response_type=code&scope=${scope}&display=popup`;
} else if (provider.type === "Casdoor") {
return `${provider.domain}/login/oauth/authorize?client_id=${provider.clientId}&redirect_uri=${redirectUri}&state=${state}&response_type=code&scope=${scope}`;
} else if (provider.type === "Infoflow"){ } else if (provider.type === "Infoflow"){
return `${endpoint}?appid=${provider.clientId}&redirect_uri=${redirectUri}?state=${state}` return `${endpoint}?appid=${provider.clientId}&redirect_uri=${redirectUri}?state=${state}`
} else if (provider.type === "Apple") { } else if (provider.type === "Apple") {

View File

@ -20,8 +20,8 @@
"Password ON": "开启密码", "Password ON": "开启密码",
"Password ON - Tooltip": "是否允许密码登录", "Password ON - Tooltip": "是否允许密码登录",
"Please select a HTML file": "请选择一个HTML文件", "Please select a HTML file": "请选择一个HTML文件",
"Redirect URL": "回调URL", "Redirect URL": "重定向 URL",
"Redirect URLs": "回调URLs", "Redirect URLs": "重定向 URLs",
"Redirect URLs - Tooltip": "登录成功后重定向地址列表", "Redirect URLs - Tooltip": "登录成功后重定向地址列表",
"Refresh token expire": "Refresh Token过期时间", "Refresh token expire": "Refresh Token过期时间",
"Refresh token expire - Tooltip": "Refresh Token过期时间", "Refresh token expire - Tooltip": "Refresh Token过期时间",
@ -304,7 +304,7 @@
"Pay": "支付方式", "Pay": "支付方式",
"Payment providers": "支付提供商", "Payment providers": "支付提供商",
"Payment providers - Tooltip": "支付提供商 - 工具提示", "Payment providers - Tooltip": "支付提供商 - 工具提示",
"Paypal": "Paypal", "Paypal": "PayPal(贝宝)",
"Placing order...": "正在下单...", "Placing order...": "正在下单...",
"Price": "价格", "Price": "价格",
"Price - Tooltip": "价格 - 工具提示", "Price - Tooltip": "价格 - 工具提示",

BIN
xlsx/user_test.xlsx Normal file

Binary file not shown.