Merged in feature/support-empty-email-jwt (pull request #209)
handle missing email in jwt * handle missing email
This commit is contained in:
@@ -244,22 +244,45 @@ func TestAgreeToEula(t *testing.T) {
|
||||
assert.Equal(t, http.StatusUnauthorized, rec.Code)
|
||||
})
|
||||
|
||||
t.Run("succeeds with username fallback when email claim is missing", func(t *testing.T) {
|
||||
// Simulate a Cognito access token that has 'sub' and 'cognito:username'
|
||||
// but no 'email' claim. This is the default for Cognito access tokens.
|
||||
t.Run("succeeds with username fallback when email is missing (access token)", func(t *testing.T) {
|
||||
// Simulate a real Cognito access token: has 'sub' and 'username' (not
|
||||
// 'cognito:username') and no 'email'. This is the default for access tokens.
|
||||
userSubject := "no-email-user-" + uuid.New().String()[:8]
|
||||
ctx, rec := setupEulaTestContext(http.MethodPost, "/eula/agree", nil)
|
||||
ctx.Request().RemoteAddr = "192.168.1.100:12345"
|
||||
|
||||
// Set claims with sub but without email (mimics access token)
|
||||
ctx.Set("user_claims", map[string]interface{}{
|
||||
"sub": userSubject,
|
||||
"cognito:username": "testuser",
|
||||
})
|
||||
ctx.Set("user_info", cognitoauth.UserInfo{
|
||||
Username: "testuser",
|
||||
Email: "", // empty - no email in access token
|
||||
})
|
||||
// Mimic what the middleware produces from a real access token:
|
||||
// ExtractUserInfo sees "username" (not "cognito:username") and no "email".
|
||||
claims := map[string]interface{}{
|
||||
"sub": userSubject,
|
||||
"username": "accessuser",
|
||||
"token_use": "access",
|
||||
}
|
||||
ctx.Set("user_claims", claims)
|
||||
ctx.Set("user_info", cognitoauth.ExtractUserInfo(claims))
|
||||
|
||||
err := cons.AgreeToEula(ctx)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, http.StatusCreated, rec.Code)
|
||||
|
||||
var response queryapi.EulaAgreementResponse
|
||||
err = json.Unmarshal(rec.Body.Bytes(), &response)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, versionStr, response.EulaVersion)
|
||||
})
|
||||
|
||||
t.Run("succeeds with subject ID fallback when email and username are both missing", func(t *testing.T) {
|
||||
// Edge case: token has sub but neither email nor any username claim.
|
||||
userSubject := "bare-token-user-" + uuid.New().String()[:8]
|
||||
ctx, rec := setupEulaTestContext(http.MethodPost, "/eula/agree", nil)
|
||||
ctx.Request().RemoteAddr = "192.168.1.100:12345"
|
||||
|
||||
claims := map[string]interface{}{
|
||||
"sub": userSubject,
|
||||
"token_use": "access",
|
||||
}
|
||||
ctx.Set("user_claims", claims)
|
||||
ctx.Set("user_info", cognitoauth.ExtractUserInfo(claims))
|
||||
|
||||
err := cons.AgreeToEula(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -135,14 +135,19 @@ func (s *Controllers) AgreeToEula(ctx echo.Context) error {
|
||||
|
||||
// Resolve the user identifier for the agreement record.
|
||||
// Cognito access tokens do not include the email claim by default (only ID tokens do).
|
||||
// Fall back to the username (cognito:username), which is always present in access tokens.
|
||||
// Fall back to username, then to subject ID (always present in any Cognito token).
|
||||
userIdentifier := userInfo.Email
|
||||
if userIdentifier == "" {
|
||||
userIdentifier = userInfo.Username
|
||||
s.cfg.GetAuthLogger().Info("AgreeToEula: email claim missing from token, using username as fallback",
|
||||
s.cfg.GetAuthLogger().Info("AgreeToEula: email missing from token, using username fallback",
|
||||
"user_subject", userSubject,
|
||||
"username", userInfo.Username)
|
||||
}
|
||||
if userIdentifier == "" {
|
||||
userIdentifier = userSubject
|
||||
s.cfg.GetAuthLogger().Info("AgreeToEula: email and username missing from token, using subject ID fallback",
|
||||
"user_subject", userSubject)
|
||||
}
|
||||
|
||||
// Get current EULA version
|
||||
currentVersion, err := s.svc.Eula.GetCurrentVersion(ctx.Request().Context())
|
||||
|
||||
Reference in New Issue
Block a user