mirror of
https://github.com/casdoor/casdoor.git
synced 2025-08-09 14:37:58 +08:00
Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
a783315fa2 | ||
![]() |
1d0af9cf7b | ||
![]() |
4d48517be9 | ||
![]() |
178cf7945d | ||
![]() |
ab5af979c8 | ||
![]() |
e31aaf5657 | ||
![]() |
eaf5cb66f3 | ||
![]() |
83a6b757a4 |
@@ -85,13 +85,9 @@ p, *, *, POST, /api/login/oauth/access_token, *, *
|
||||
p, *, *, POST, /api/login/oauth/refresh_token, *, *
|
||||
p, *, *, GET, /api/login/oauth/logout, *, *
|
||||
p, *, *, GET, /api/get-application, *, *
|
||||
p, *, *, GET, /api/get-users, *, *
|
||||
p, *, *, GET, /api/get-user, *, *
|
||||
p, *, *, GET, /api/get-organizations, *, *
|
||||
p, *, *, GET, /api/get-user-application, *, *
|
||||
p, *, *, GET, /api/get-default-providers, *, *
|
||||
p, *, *, GET, /api/get-resources, *, *
|
||||
p, *, *, POST, /api/upload-avatar, *, *
|
||||
p, *, *, POST, /api/unlink, *, *
|
||||
p, *, *, POST, /api/set-password, *, *
|
||||
p, *, *, POST, /api/send-verification-code, *, *
|
||||
|
@@ -12,7 +12,7 @@ redisEndpoint =
|
||||
defaultStorageProvider =
|
||||
isCloudIntranet = false
|
||||
authState = "casdoor"
|
||||
httpProxy = "127.0.0.1:10808"
|
||||
sock5Proxy = "127.0.0.1:10808"
|
||||
verificationCodeTimeout = 10
|
||||
initScore = 2000
|
||||
logPostOnly = true
|
||||
|
@@ -130,8 +130,6 @@ func (c *ApiController) Signup() {
|
||||
}
|
||||
}
|
||||
|
||||
userId := fmt.Sprintf("%s/%s", form.Organization, form.Username)
|
||||
|
||||
id := util.GenerateId()
|
||||
if application.GetSignupItemRule("ID") == "Incremental" {
|
||||
lastUser := object.GetLastUser(form.Organization)
|
||||
@@ -149,8 +147,6 @@ func (c *ApiController) Signup() {
|
||||
username = id
|
||||
}
|
||||
|
||||
userCount := object.GetUserCount(form.Organization, "", "") + 1
|
||||
|
||||
user := &object.User{
|
||||
Owner: form.Organization,
|
||||
Name: username,
|
||||
@@ -173,7 +169,6 @@ func (c *ApiController) Signup() {
|
||||
IsDeleted: false,
|
||||
SignupApplication: application.Name,
|
||||
Properties: map[string]string{},
|
||||
Ranking: userCount + 1,
|
||||
Karma: 0,
|
||||
}
|
||||
|
||||
@@ -206,6 +201,7 @@ func (c *ApiController) Signup() {
|
||||
record.User = user.Name
|
||||
go object.AddRecord(record)
|
||||
|
||||
userId := fmt.Sprintf("%s/%s", user.Owner, user.Name)
|
||||
util.LogInfo(c.Ctx, "API: [%s] is signed up as new user", userId)
|
||||
|
||||
c.ResponseOk(userId)
|
||||
|
@@ -118,6 +118,7 @@ func (c *ApiController) GetApplicationLogin() {
|
||||
state := c.Input().Get("state")
|
||||
|
||||
msg, application := object.CheckOAuthLogin(clientId, responseType, redirectUri, scope, state)
|
||||
application = object.GetMaskedApplication(application, "")
|
||||
if msg != "" {
|
||||
c.ResponseError(msg, application)
|
||||
} else {
|
||||
|
@@ -229,3 +229,65 @@ func (c *ApiController) TokenLogout() {
|
||||
c.Data["json"] = wrapActionResponse(flag)
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
// IntrospectToken
|
||||
// @Title IntrospectToken
|
||||
// @Description The introspection endpoint is an OAuth 2.0 endpoint that takes a
|
||||
// parameter representing an OAuth 2.0 token and returns a JSON document
|
||||
// representing the meta information surrounding the
|
||||
// token, including whether this token is currently active.
|
||||
// This endpoint only support Basic Authorization.
|
||||
// @Param token formData string true "access_token's value or refresh_token's value"
|
||||
// @Param token_type_hint formData string true "the token type access_token or refresh_token"
|
||||
// @Success 200 {object} object.IntrospectionResponse The Response object
|
||||
// @router /login/oauth/introspect [post]
|
||||
func (c *ApiController) IntrospectToken() {
|
||||
tokenValue := c.Input().Get("token")
|
||||
clientId, clientSecret, ok := c.Ctx.Request.BasicAuth()
|
||||
if !ok {
|
||||
util.LogWarning(c.Ctx, "Basic Authorization parses failed")
|
||||
c.Data["json"] = Response{Status: "error", Msg: "Unauthorized operation"}
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
application := object.GetApplicationByClientId(clientId)
|
||||
if application == nil || application.ClientSecret != clientSecret {
|
||||
util.LogWarning(c.Ctx, "Basic Authorization failed")
|
||||
c.Data["json"] = Response{Status: "error", Msg: "Unauthorized operation"}
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
token := object.GetTokenByTokenAndApplication(tokenValue, application.Name)
|
||||
if token == nil {
|
||||
util.LogWarning(c.Ctx, "application: %s can not find token", application.Name)
|
||||
c.Data["json"] = &object.IntrospectionResponse{Active: false}
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
jwtToken, err := object.ParseJwtTokenByApplication(tokenValue, application)
|
||||
if err != nil || jwtToken.Valid() != nil {
|
||||
// and token revoked case. but we not implement
|
||||
// TODO: 2022-03-03 add token revoked check, when we implemented the Token Revocation(rfc7009) Specs.
|
||||
// refs: https://tools.ietf.org/html/rfc7009
|
||||
util.LogWarning(c.Ctx, "token invalid")
|
||||
c.Data["json"] = &object.IntrospectionResponse{Active: false}
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
|
||||
c.Data["json"] = &object.IntrospectionResponse{
|
||||
Active: true,
|
||||
Scope: jwtToken.Scope,
|
||||
ClientId: clientId,
|
||||
Username: token.User,
|
||||
TokenType: token.TokenType,
|
||||
Exp: jwtToken.ExpiresAt.Unix(),
|
||||
Iat: jwtToken.IssuedAt.Unix(),
|
||||
Nbf: jwtToken.NotBefore.Unix(),
|
||||
Sub: jwtToken.Subject,
|
||||
Aud: jwtToken.Audience,
|
||||
Iss: jwtToken.Issuer,
|
||||
Jti: jwtToken.Id,
|
||||
}
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
@@ -44,6 +44,7 @@ func (c *ApiController) GetGlobalUsers() {
|
||||
limit := util.ParseInt(limit)
|
||||
paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetGlobalUserCount(field, value)))
|
||||
users := object.GetPaginationGlobalUsers(paginator.Offset(), limit, field, value, sortField, sortOrder)
|
||||
users = object.GetMaskedUsers(users)
|
||||
c.ResponseOk(users, paginator.Nums())
|
||||
}
|
||||
}
|
||||
@@ -70,6 +71,7 @@ func (c *ApiController) GetUsers() {
|
||||
limit := util.ParseInt(limit)
|
||||
paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetUserCount(owner, field, value)))
|
||||
users := object.GetPaginationUsers(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
||||
users = object.GetMaskedUsers(users)
|
||||
c.ResponseOk(users, paginator.Nums())
|
||||
}
|
||||
}
|
||||
|
@@ -16,7 +16,7 @@ data:
|
||||
defaultStorageProvider =
|
||||
isCloudIntranet = false
|
||||
authState = "casdoor"
|
||||
httpProxy = "127.0.0.1:10808"
|
||||
sock5Proxy = "127.0.0.1:10808"
|
||||
verificationCodeTimeout = 10
|
||||
initScore = 2000
|
||||
logPostOnly = true
|
||||
|
@@ -217,7 +217,19 @@ func GetMaskedApplication(application *Application, userId string) *Application
|
||||
if application.ClientSecret != "" {
|
||||
application.ClientSecret = "***"
|
||||
}
|
||||
return application
|
||||
|
||||
if application.OrganizationObj != nil {
|
||||
if application.OrganizationObj.MasterPassword != "" {
|
||||
application.OrganizationObj.MasterPassword = "***"
|
||||
}
|
||||
if application.OrganizationObj.PasswordType != "" {
|
||||
application.OrganizationObj.PasswordType = "***"
|
||||
}
|
||||
if application.OrganizationObj.PasswordSalt != "" {
|
||||
application.OrganizationObj.PasswordSalt = "***"
|
||||
}
|
||||
}
|
||||
return application
|
||||
}
|
||||
|
||||
func GetMaskedApplications(applications []*Application, userId string) []*Application {
|
||||
|
@@ -30,6 +30,7 @@ type OidcDiscovery struct {
|
||||
TokenEndpoint string `json:"token_endpoint"`
|
||||
UserinfoEndpoint string `json:"userinfo_endpoint"`
|
||||
JwksUri string `json:"jwks_uri"`
|
||||
IntrospectionEndpoint string `json:"introspection_endpoint"`
|
||||
ResponseTypesSupported []string `json:"response_types_supported"`
|
||||
ResponseModesSupported []string `json:"response_modes_supported"`
|
||||
GrantTypesSupported []string `json:"grant_types_supported"`
|
||||
@@ -74,6 +75,7 @@ func GetOidcDiscovery(host string) OidcDiscovery {
|
||||
TokenEndpoint: fmt.Sprintf("%s/api/login/oauth/access_token", originBackend),
|
||||
UserinfoEndpoint: fmt.Sprintf("%s/api/userinfo", originBackend),
|
||||
JwksUri: fmt.Sprintf("%s/.well-known/jwks", originBackend),
|
||||
IntrospectionEndpoint: fmt.Sprintf("%s/api/login/oauth/introspect", originBackend),
|
||||
ResponseTypesSupported: []string{"id_token"},
|
||||
ResponseModesSupported: []string{"login", "code", "link"},
|
||||
GrantTypesSupported: []string{"password", "authorization_code"},
|
||||
|
@@ -60,6 +60,21 @@ type TokenWrapper struct {
|
||||
Scope string `json:"scope"`
|
||||
}
|
||||
|
||||
type IntrospectionResponse struct {
|
||||
Active bool `json:"active"`
|
||||
Scope string `json:"scope,omitempty"`
|
||||
ClientId string `json:"client_id,omitempty"`
|
||||
Username string `json:"username,omitempty"`
|
||||
TokenType string `json:"token_type,omitempty"`
|
||||
Exp int64 `json:"exp,omitempty"`
|
||||
Iat int64 `json:"iat,omitempty"`
|
||||
Nbf int64 `json:"nbf,omitempty"`
|
||||
Sub string `json:"sub,omitempty"`
|
||||
Aud []string `json:"aud,omitempty"`
|
||||
Iss string `json:"iss,omitempty"`
|
||||
Jti string `json:"jti,omitempty"`
|
||||
}
|
||||
|
||||
func GetTokenCount(owner, field, value string) int {
|
||||
session := GetSession(owner, -1, -1, field, value, "", "")
|
||||
count, err := session.Count(&Token{})
|
||||
@@ -198,6 +213,15 @@ func GetTokenByAccessToken(accessToken string) *Token {
|
||||
return &token
|
||||
}
|
||||
|
||||
func GetTokenByTokenAndApplication(token string, application string) *Token {
|
||||
tokenResult := Token{}
|
||||
existed, err := adapter.Engine.Where("(refresh_token = ? or access_token = ? ) and application = ?", token, token, application).Get(&tokenResult)
|
||||
if err != nil || !existed {
|
||||
return nil
|
||||
}
|
||||
return &tokenResult
|
||||
}
|
||||
|
||||
func CheckOAuthLogin(clientId string, responseType string, redirectUri string, scope string, state string) (string, *Application) {
|
||||
if responseType != "code" && responseType != "token" && responseType != "id_token" {
|
||||
return fmt.Sprintf("error: grant_type: %s is not supported in this application", responseType), nil
|
||||
@@ -532,7 +556,9 @@ func GetClientCredentialsToken(application *Application, clientSecret string, sc
|
||||
return nil, errors.New("error: invalid client_secret")
|
||||
}
|
||||
nullUser := &User{
|
||||
Name: fmt.Sprintf("app/%s", application.Name),
|
||||
Owner: application.Owner,
|
||||
Id: application.GetId(),
|
||||
Name: fmt.Sprintf("app/%s", application.Name),
|
||||
}
|
||||
accessToken, _, err := generateJwtToken(application, nullUser, "", scope, host)
|
||||
if err != nil {
|
||||
|
@@ -147,3 +147,7 @@ func ParseJwtToken(token string, cert *Cert) (*Claims, error) {
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func ParseJwtTokenByApplication(token string, application *Application) (*Claims, error) {
|
||||
return ParseJwtToken(token, getCertByApplication(application))
|
||||
}
|
||||
|
@@ -352,6 +352,8 @@ func AddUser(user *User) bool {
|
||||
|
||||
user.PermanentAvatar = getPermanentAvatarUrl(user.Owner, user.Name, user.Avatar)
|
||||
|
||||
user.Ranking = GetUserCount(user.Owner, "", "") + 1
|
||||
|
||||
affected, err := adapter.Engine.Insert(user)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
@@ -54,17 +54,17 @@ func isAddressOpen(address string) bool {
|
||||
}
|
||||
|
||||
func getProxyHttpClient() *http.Client {
|
||||
httpProxy := beego.AppConfig.String("httpProxy")
|
||||
if httpProxy == "" {
|
||||
sock5Proxy := beego.AppConfig.String("sock5Proxy")
|
||||
if sock5Proxy == "" {
|
||||
return &http.Client{}
|
||||
}
|
||||
|
||||
if !isAddressOpen(httpProxy) {
|
||||
if !isAddressOpen(sock5Proxy) {
|
||||
return &http.Client{}
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/questions/33585587/creating-a-go-socks5-client
|
||||
dialer, err := proxy.SOCKS5("tcp", httpProxy, nil, proxy.Direct)
|
||||
dialer, err := proxy.SOCKS5("tcp", sock5Proxy, nil, proxy.Direct)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@@ -127,6 +127,7 @@ func initAPI() {
|
||||
beego.Router("/api/login/oauth/code", &controllers.ApiController{}, "POST:GetOAuthCode")
|
||||
beego.Router("/api/login/oauth/access_token", &controllers.ApiController{}, "POST:GetOAuthToken")
|
||||
beego.Router("/api/login/oauth/refresh_token", &controllers.ApiController{}, "POST:RefreshToken")
|
||||
beego.Router("/api/login/oauth/introspect", &controllers.ApiController{}, "POST:IntrospectToken")
|
||||
beego.Router("/api/login/oauth/logout", &controllers.ApiController{}, "GET:TokenLogout")
|
||||
|
||||
beego.Router("/api/get-records", &controllers.ApiController{}, "GET:GetRecords")
|
||||
|
Reference in New Issue
Block a user