Compare commits

...

2 Commits

Author SHA1 Message Date
copilot-swe-agent[bot]
c8ee37cc90 Add OAuth scope validation to return invalid_scope per RFC 6749
Co-authored-by: hsluoyz <3787410+hsluoyz@users.noreply.github.com>
2026-02-21 09:28:44 +00:00
copilot-swe-agent[bot]
e3d9a69dd0 Initial plan 2026-02-21 09:16:15 +00:00
13 changed files with 64 additions and 3 deletions

View File

@@ -185,10 +185,14 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
} else {
scope := c.Ctx.Input.Query("scope")
nonce := c.Ctx.Input.Query("nonce")
token, _ := object.GetTokenByUser(application, user, scope, nonce, c.Ctx.Request.Host)
resp = tokenToResponse(token)
if !object.IsScopeValid(scope, application) {
resp = &Response{Status: "error", Msg: "error: invalid_scope", Data: ""}
} else {
token, _ := object.GetTokenByUser(application, user, scope, nonce, c.Ctx.Request.Host)
resp = tokenToResponse(token)
resp.Data3 = user.NeedUpdatePassword
resp.Data3 = user.NeedUpdatePassword
}
}
} else if form.Type == ResponseTypeDevice {
authCache, ok := object.DeviceAuthMap.LoadAndDelete(form.UserCode)

View File

@@ -187,6 +187,7 @@
"Grant_type: %s is not supported in this application": "Grant_type: %s wird von dieser Anwendung nicht unterstützt",
"Invalid application or wrong clientSecret": "Ungültige Anwendung oder falsches clientSecret",
"Invalid client_id": "Ungültige client_id",
"Invalid scope": "Ungültiger Scope",
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Weiterleitungs-URI: %s ist nicht in der Liste erlaubter Weiterleitungs-URIs vorhanden",
"Token not found, invalid accessToken": "Token nicht gefunden, ungültiger Zugriffs-Token"
},

View File

@@ -187,6 +187,7 @@
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
"Invalid client_id": "Invalid client_id",
"Invalid scope": "Invalid scope",
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Redirect URI: %s doesn't exist in the allowed Redirect URI list",
"Token not found, invalid accessToken": "Token not found, invalid accessToken"
},

View File

@@ -187,6 +187,7 @@
"Grant_type: %s is not supported in this application": "El tipo de subvención: %s no es compatible con esta aplicación",
"Invalid application or wrong clientSecret": "Solicitud inválida o clientSecret incorrecto",
"Invalid client_id": "Identificador de cliente no válido",
"Invalid scope": "Alcance no válido",
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "El URI de redirección: %s no existe en la lista de URI de redirección permitidos",
"Token not found, invalid accessToken": "Token no encontrado, accessToken inválido"
},

View File

@@ -187,6 +187,7 @@
"Grant_type: %s is not supported in this application": "Type_de_subvention : %s n'est pas pris en charge dans cette application",
"Invalid application or wrong clientSecret": "Application invalide ou clientSecret incorrect",
"Invalid client_id": "Identifiant de client invalide",
"Invalid scope": "Portée invalide",
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "URI de redirection: %s n'existe pas dans la liste des URI de redirection autorisés",
"Token not found, invalid accessToken": "Jeton non trouvé, accessToken invalide"
},

View File

@@ -187,6 +187,7 @@
"Grant_type: %s is not supported in this application": "grant_type%sはこのアプリケーションでサポートされていません",
"Invalid application or wrong clientSecret": "無効なアプリケーションまたは誤ったクライアントシークレットです",
"Invalid client_id": "client_idが無効です",
"Invalid scope": "スコープが無効です",
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "リダイレクトURI%sは許可されたリダイレクトURIリストに存在しません",
"Token not found, invalid accessToken": "トークンが見つかりません。無効なアクセストークンです"
},

View File

@@ -187,6 +187,7 @@
"Grant_type: %s is not supported in this application": "Grant_type: %s nie jest obsługiwany w tej aplikacji",
"Invalid application or wrong clientSecret": "Nieprawidłowa aplikacja lub błędny clientSecret",
"Invalid client_id": "Nieprawidłowy client_id",
"Invalid scope": "Nieprawidłowy zakres",
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Redirect URI: %s nie istnieje na liście dozwolonych Redirect URI",
"Token not found, invalid accessToken": "Token nie znaleziony, nieprawidłowy accessToken"
},

View File

@@ -187,6 +187,7 @@
"Grant_type: %s is not supported in this application": "Grant_type: %s não é suportado neste aplicativo",
"Invalid application or wrong clientSecret": "Aplicativo inválido ou clientSecret incorreto",
"Invalid client_id": "client_id inválido",
"Invalid scope": "Escopo inválido",
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "O URI de redirecionamento: %s não existe na lista de URIs permitidos",
"Token not found, invalid accessToken": "Token não encontrado, accessToken inválido"
},

View File

@@ -187,6 +187,7 @@
"Grant_type: %s is not supported in this application": "Grant_type: %s bu uygulamada desteklenmiyor",
"Invalid application or wrong clientSecret": "Geçersiz uygulama veya yanlış clientSecret",
"Invalid client_id": "Geçersiz client_id",
"Invalid scope": "Geçersiz kapsam",
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Redirect URI: %s izin verilen Redirect URI listesinde yok",
"Token not found, invalid accessToken": "Token bulunamadı, geçersiz accessToken"
},

View File

@@ -187,6 +187,7 @@
"Grant_type: %s is not supported in this application": "Grant_type: %s не підтримується в цьому додатку",
"Invalid application or wrong clientSecret": "Недійсний додаток або неправильний clientSecret",
"Invalid client_id": "Недійсний client_id",
"Invalid scope": "Недійсний scope",
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Redirect URI: %s відсутній у списку дозволених",
"Token not found, invalid accessToken": "Токен не знайдено, недійсний accessToken"
},

View File

@@ -187,6 +187,7 @@
"Grant_type: %s is not supported in this application": "Loại cấp phép: %s không được hỗ trợ trong ứng dụng này",
"Invalid application or wrong clientSecret": "Đơn đăng ký không hợp lệ hoặc sai clientSecret",
"Invalid client_id": "Client_id không hợp lệ",
"Invalid scope": "Phạm vi không hợp lệ",
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Đường dẫn chuyển hướng URI: %s không tồn tại trong danh sách URI được phép chuyển hướng",
"Token not found, invalid accessToken": "Token không tìm thấy, accessToken không hợp lệ"
},

View File

@@ -187,6 +187,7 @@
"Grant_type: %s is not supported in this application": "该应用不支持Grant_type: %s",
"Invalid application or wrong clientSecret": "无效应用或错误的clientSecret",
"Invalid client_id": "无效的ClientId",
"Invalid scope": "无效的scope",
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "重定向 URI%s在许可跳转列表中未找到",
"Token not found, invalid accessToken": "未查询到对应token, accessToken无效"
},

View File

@@ -154,6 +154,10 @@ func CheckOAuthLogin(clientId string, responseType string, redirectUri string, s
return fmt.Sprintf(i18n.Translate(lang, "token:Redirect URI: %s doesn't exist in the allowed Redirect URI list"), redirectUri), application, nil
}
if !IsScopeValid(scope, application) {
return i18n.Translate(lang, "token:Invalid scope"), application, nil
}
// Mask application for /api/get-app-login
application.ClientSecret = ""
return "", application, nil
@@ -486,6 +490,28 @@ func IsGrantTypeValid(method string, grantTypes []string) bool {
return false
}
// IsScopeValid checks whether all space-separated scopes in the scope string
// are defined in the application's Scopes list.
// If the application has no defined scopes, every scope is considered valid
// (backward-compatible behaviour).
func IsScopeValid(scope string, application *Application) bool {
if len(application.Scopes) == 0 || scope == "" {
return true
}
allowed := make(map[string]bool, len(application.Scopes))
for _, s := range application.Scopes {
allowed[s.Name] = true
}
for _, s := range strings.Fields(scope) {
if !allowed[s] {
return false
}
}
return true
}
// createGuestUserToken creates a new guest user and returns a token for them
func createGuestUserToken(application *Application, clientSecret string, verifier string) (*Token, *TokenError, error) {
// Verify client secret if provided
@@ -715,6 +741,13 @@ func GetAuthorizationCodeToken(application *Application, clientSecret string, co
// GetPasswordToken
// Resource Owner Password Credentials flow
func GetPasswordToken(application *Application, username string, password string, scope string, host string) (*Token, *TokenError, error) {
if !IsScopeValid(scope, application) {
return nil, &TokenError{
Error: InvalidScope,
ErrorDescription: "the requested scope is invalid or not defined in the application",
}, nil
}
user, err := GetUserByFields(application.Organization, username)
if err != nil {
return nil, nil, err
@@ -796,6 +829,12 @@ func GetClientCredentialsToken(application *Application, clientSecret string, sc
ErrorDescription: "client_secret is invalid",
}, nil
}
if !IsScopeValid(scope, application) {
return nil, &TokenError{
Error: InvalidScope,
ErrorDescription: "the requested scope is invalid or not defined in the application",
}, nil
}
nullUser := &User{
Owner: application.Owner,
Id: application.GetId(),
@@ -835,6 +874,13 @@ func GetClientCredentialsToken(application *Application, clientSecret string, sc
// GetImplicitToken
// Implicit flow
func GetImplicitToken(application *Application, username string, scope string, nonce string, host string) (*Token, *TokenError, error) {
if !IsScopeValid(scope, application) {
return nil, &TokenError{
Error: InvalidScope,
ErrorDescription: "the requested scope is invalid or not defined in the application",
}, nil
}
user, err := GetUserByFields(application.Organization, username)
if err != nil {
return nil, nil, err