Automatic Merge
Этот коммит содержится в:
Mattermost Build
2025-10-27 12:59:15 +02:00
коммит произвёл GitHub
родитель 56163e9e0e
Коммит f361e7d75a
14 изменённых файлов: 352 добавлений и 32 удалений

Просмотреть файл

@@ -130,7 +130,7 @@ func loginSSOCodeExchange(c *Context, w http.ResponseWriter, r *http.Request) {
}
// Consume one-time code atomically
token, appErr := c.App.ConsumeTokenOnce(loginCode)
token, appErr := c.App.ConsumeTokenOnce(model.TokenTypeSSOCodeExchange, loginCode)
if appErr != nil {
c.Err = appErr
return

Просмотреть файл

@@ -6,6 +6,8 @@ package api4
import (
"bytes"
"context"
"crypto/sha256"
"encoding/base64"
"encoding/json"
"fmt"
"image/png"
@@ -8673,6 +8675,85 @@ func TestLoginWithDesktopToken(t *testing.T) {
})
}
func TestLoginSSOCodeExchange(t *testing.T) {
mainHelper.Parallel(t)
th := Setup(t).InitBasic()
defer th.TearDown()
t.Run("wrong token type cannot be used for code exchange", func(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) {
cfg.FeatureFlags.MobileSSOCodeExchange = true
})
token := model.NewToken(model.TokenTypeOAuth, "extra-data")
require.NoError(t, th.App.Srv().Store().Token().Save(token))
defer func() {
_ = th.App.Srv().Store().Token().Delete(token.Token)
}()
props := map[string]string{
"login_code": token.Token,
"code_verifier": "test_verifier",
"state": "test_state",
}
resp, err := th.Client.DoAPIPost(context.Background(), "/users/login/sso/code-exchange", model.MapToJSON(props))
require.Error(t, err)
require.Equal(t, http.StatusNotFound, resp.StatusCode)
})
t.Run("successful code exchange with S256 challenge", func(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) {
cfg.FeatureFlags.MobileSSOCodeExchange = true
})
samlUser := th.CreateUserWithAuth(model.UserAuthServiceSaml)
codeVerifier := "test_code_verifier_123456789"
state := "test_state_value"
sum := sha256.Sum256([]byte(codeVerifier))
codeChallenge := base64.RawURLEncoding.EncodeToString(sum[:])
extra := map[string]string{
"user_id": samlUser.Id,
"code_challenge": codeChallenge,
"code_challenge_method": "S256",
"state": state,
}
token := model.NewToken(model.TokenTypeSSOCodeExchange, model.MapToJSON(extra))
require.NoError(t, th.App.Srv().Store().Token().Save(token))
props := map[string]string{
"login_code": token.Token,
"code_verifier": codeVerifier,
"state": state,
}
resp, err := th.Client.DoAPIPost(context.Background(), "/users/login/sso/code-exchange", model.MapToJSON(props))
require.NoError(t, err)
require.Equal(t, http.StatusOK, resp.StatusCode)
var result map[string]string
require.NoError(t, json.NewDecoder(resp.Body).Decode(&result))
assert.NotEmpty(t, result["token"])
assert.NotEmpty(t, result["csrf"])
_, err = th.App.Srv().Store().Token().GetByToken(token.Token)
require.Error(t, err)
authenticatedClient := model.NewAPIv4Client(th.Client.URL)
authenticatedClient.SetToken(result["token"])
user, _, err := authenticatedClient.GetMe(context.Background(), "")
require.NoError(t, err)
assert.Equal(t, samlUser.Id, user.Id)
assert.Equal(t, samlUser.Email, user.Email)
assert.Equal(t, samlUser.Username, user.Username)
})
}
func TestGetUsersByNames(t *testing.T) {
mainHelper.Parallel(t)
th := Setup(t).InitBasic()