Skip to content

Commit 9feb81d

Browse files
authored
chore: email lowercase handling (#5196)
* email lowercase handling * removing request email from update call * authenticator update * adding argocd assets * converting email to lower cse * updating authorizer * adding argocd assets * removing email from auth verification * authenticator lib update
1 parent 530088a commit 9feb81d

27 files changed

+163
-94
lines changed

api/auth/user/UserAuthHandler.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ func (handler UserAuthHandlerImpl) AddDefaultPolicyAndRoles(w http.ResponseWrite
237237

238238
}
239239
func (handler UserAuthHandlerImpl) AuthVerification(w http.ResponseWriter, r *http.Request) {
240-
verified, err := handler.userAuthService.AuthVerification(r)
240+
verified, _, err := handler.userAuthService.AuthVerification(r)
241241
if err != nil {
242242
handler.logger.Errorw("service err, AuthVerification", "err", err)
243243
common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
@@ -253,13 +253,14 @@ func (handler UserAuthHandlerImpl) AuthVerificationV2(w http.ResponseWriter, r *
253253
isSuperAdmin = true
254254
}
255255
response := make(map[string]interface{})
256-
verified, err := handler.userAuthService.AuthVerification(r)
256+
verified, emailId, err := handler.userAuthService.AuthVerification(r)
257257
if err != nil {
258258
handler.logger.Errorw("service err, AuthVerification", "err", err)
259259
common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
260260
return
261261
}
262262
response["isSuperAdmin"] = isSuperAdmin
263263
response["isVerified"] = verified
264+
response["emailId"] = emailId
264265
common.WriteJsonResp(w, nil, response, http.StatusOK)
265266
}

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ require (
1717
github.com/coreos/go-oidc v2.2.1+incompatible
1818
github.com/davecgh/go-spew v1.1.1
1919
github.com/deckarep/golang-set v1.8.0
20-
github.com/devtron-labs/authenticator v0.4.35-0.20240405091826-a91813c53470
20+
github.com/devtron-labs/authenticator v0.4.35-0.20240607135426-c86e868ecee1
2121
github.com/devtron-labs/common-lib v0.0.19-0.20240607054959-82c79c23b046
2222
github.com/devtron-labs/protos v0.0.3-0.20240326053929-48e42d9d4534
2323
github.com/evanphx/json-patch v5.6.0+incompatible

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -205,8 +205,8 @@ github.com/deckarep/golang-set v1.8.0 h1:sk9/l/KqpunDwP7pSjUg0keiOOLEnOBHzykLrsP
205205
github.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS383rP6+o6qqo=
206206
github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4 h1:YcpmyvADGYw5LqMnHqSkyIELsHCGF6PkrmM31V8rF7o=
207207
github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM=
208-
github.com/devtron-labs/authenticator v0.4.35-0.20240405091826-a91813c53470 h1:AUTYcDnL6w6Ux+264VldYaOUQAP6pDZ5Tq8wCKJyiEg=
209-
github.com/devtron-labs/authenticator v0.4.35-0.20240405091826-a91813c53470/go.mod h1:JQxTCMmQisrpjzETJr0tzVadV+wW23rHEZAY7JVyK3s=
208+
github.com/devtron-labs/authenticator v0.4.35-0.20240607135426-c86e868ecee1 h1:qdkpTAo2Kr0ZicZIVXfNwsGSshpc9OB9j9RzmKYdIwY=
209+
github.com/devtron-labs/authenticator v0.4.35-0.20240607135426-c86e868ecee1/go.mod h1:IkKPPEfgLCMR29he5yv2OCC6iM2R7K5/0AA3k8b9XNc=
210210
github.com/devtron-labs/common-lib v0.0.19-0.20240607054959-82c79c23b046 h1:hOyqkgILg+eDttLV6X7OAAo9PKEHzInUmBTVy/EY/iI=
211211
github.com/devtron-labs/common-lib v0.0.19-0.20240607054959-82c79c23b046/go.mod h1:deAcJ5IjUjM6ozZQLJEgPWDUA0mKa632LBsKx8uM9TE=
212212
github.com/devtron-labs/protos v0.0.3-0.20240326053929-48e42d9d4534 h1:TElPRU69QedW7DIQiiQxtjwSQ6cK0fCTAMGvSLhP0ac=

internal/sql/repository/UserAttributesRepository.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ func (repo UserAttributesRepositoryImpl) UpdateDataValByKey(attrDto *UserAttribu
8888
if err != nil {
8989
return err
9090
}
91-
query := "update user_attributes SET user_data = user_data::jsonb - ? || ? where email_id = ?"
91+
query := "update user_attributes SET user_data = user_data::jsonb - ? || ? where email_id ilike ?"
9292

9393
_, err = repo.dbConnection.
9494
Query(userAttr, query, attrDto.Key, string(updatedValJson), attrDto.EmailId)
@@ -97,7 +97,8 @@ func (repo UserAttributesRepositoryImpl) UpdateDataValByKey(attrDto *UserAttribu
9797

9898
func (repo UserAttributesRepositoryImpl) GetDataValueByKey(attrDto *UserAttributesDao) (string, error) {
9999
model := &UserAttributes{}
100-
err := repo.dbConnection.Model(model).Where("email_id = ?", attrDto.EmailId).
100+
err := repo.dbConnection.Model(model).Where("email_id ilike ?", attrDto.EmailId).
101+
Limit(1).
101102
Select()
102103
if err != nil {
103104
return "", err
@@ -118,7 +119,8 @@ func (repo UserAttributesRepositoryImpl) GetDataValueByKey(attrDto *UserAttribut
118119

119120
func (repo UserAttributesRepositoryImpl) GetUserDataByEmailId(emailId string) (string, error) {
120121
model := &UserAttributes{}
121-
err := repo.dbConnection.Model(model).Where("email_id = ?", emailId).
122+
err := repo.dbConnection.Model(model).Where("email_id ilike ?", emailId).
123+
Limit(1).
122124
Select()
123125
if err != nil {
124126
return "", err

pkg/auth/user/UserAuthService.go

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"encoding/json"
2323
"errors"
2424
"fmt"
25+
util2 "github.com/devtron-labs/devtron/pkg/auth/user/util"
2526
"log"
2627
"math/rand"
2728
"net/http"
@@ -53,13 +54,13 @@ type UserAuthService interface {
5354
HandleRefresh(w http.ResponseWriter, r *http.Request)
5455

5556
CreateRole(roleData *bean.RoleData) (bool, error)
56-
AuthVerification(r *http.Request) (bool, error)
57+
AuthVerification(r *http.Request) (bool, string, error)
5758
DeleteRoles(entityType string, entityName string, tx *pg.Tx, envIdentifier string, workflowName string) error
5859
}
5960

6061
type UserAuthServiceImpl struct {
6162
userAuthRepository repository.UserAuthRepository
62-
//sessionClient is being used for argocd username-password login proxy
63+
// sessionClient is being used for argocd username-password login proxy
6364
sessionClient session2.ServiceClient
6465
logger *zap.SugaredLogger
6566
userRepository repository.UserRepository
@@ -71,7 +72,7 @@ type UserAuthServiceImpl struct {
7172
var (
7273
cStore *sessions.CookieStore
7374
dexOauthConfig *oauth2.Config
74-
//googleOauthConfig *oauth2.Config
75+
// googleOauthConfig *oauth2.Config
7576
oauthStateString = randToken()
7677
idTokenVerifier *oidc.IDTokenVerifier
7778
jwtKey = randKey()
@@ -202,6 +203,7 @@ func (impl UserAuthServiceImpl) HandleRefresh(w http.ResponseWriter, r *http.Req
202203
writeResponse(http.StatusBadRequest, "StatusBadRequest", w, errors.New("StatusBadRequest"))
203204
return
204205
}
206+
claims.Email = util2.ConvertEmailToLowerCase(claims.Email)
205207
bearerToken := claims.Token
206208
user, err := authorize(context.Background(), bearerToken)
207209
if err != nil {
@@ -257,11 +259,12 @@ func (impl UserAuthServiceImpl) HandleRefresh(w http.ResponseWriter, r *http.Req
257259
}
258260

259261
func (impl UserAuthServiceImpl) HandleLoginWithClientIp(ctx context.Context, username, password, clientIp string) (string, error) {
262+
impl.logger.Info("login with client ip")
260263
token, err := impl.HandleLogin(username, password)
261264
if err == nil {
262265
id, _, err := impl.userService.GetUserByToken(ctx, token)
263266
if err != nil {
264-
impl.logger.Infow("error occured while getting user by token", "err", err)
267+
impl.logger.Errorw("error occurred while getting user by token", "err", err)
265268
} else {
266269
impl.userService.SaveLoginAudit("", clientIp, id)
267270
}
@@ -308,14 +311,15 @@ func (impl UserAuthServiceImpl) HandleDexCallback(w http.ResponseWriter, r *http
308311
// Rollback tx on error.
309312
defer tx.Rollback()
310313

314+
Claims.Email = util2.ConvertEmailToLowerCase(Claims.Email)
311315
dbUser, err := impl.userRepository.FetchUserDetailByEmail(Claims.Email)
312316
if err != nil {
313317
impl.logger.Errorw("Exception while fetching user from db", "err", err)
314318
}
315319
if dbUser.Id > 0 {
316320
// Do nothing, User already exist in our db. (unique check by email id)
317321
} else {
318-
//create new user in our db on d basis of info got from google api or hex. assign a basic role
322+
// create new user in our db on d basis of info got from google api or hex. assign a basic role
319323
model := &repository.UserModel{
320324
EmailId: Claims.Email,
321325
AccessToken: rawIDToken,
@@ -449,7 +453,7 @@ func (impl UserAuthServiceImpl) CreateRole(roleData *bean.RoleData) (bool, error
449453
return true, nil
450454
}
451455

452-
func (impl UserAuthServiceImpl) AuthVerification(r *http.Request) (bool, error) {
456+
func (impl UserAuthServiceImpl) AuthVerification(r *http.Request) (bool, string, error) {
453457
token := r.Header.Get("token")
454458
if token == "" {
455459
impl.logger.Infow("no token provided")
@@ -458,7 +462,7 @@ func (impl UserAuthServiceImpl) AuthVerification(r *http.Request) (bool, error)
458462
Code: constants.UserNoTokenProvided,
459463
InternalMessage: "no token provided",
460464
}
461-
return false, err
465+
return false, "", err
462466
}
463467

464468
_, err := impl.sessionManager.VerifyToken(token)
@@ -470,12 +474,12 @@ func (impl UserAuthServiceImpl) AuthVerification(r *http.Request) (bool, error)
470474
InternalMessage: "failed to verify token",
471475
UserMessage: "token verification failed while getting logged in user",
472476
}
473-
return false, err
477+
return false, "", err
474478
}
475479
emailId, version, err := impl.userService.GetEmailAndVersionFromToken(token)
476480
if err != nil {
477481
impl.logger.Errorw("AuthVerification failed ", "error", err)
478-
return false, err
482+
return false, "", err
479483
}
480484
exists := impl.userService.UserExists(emailId)
481485
if !exists {
@@ -485,7 +489,7 @@ func (impl UserAuthServiceImpl) AuthVerification(r *http.Request) (bool, error)
485489
InternalMessage: "user does not exist",
486490
UserMessage: "active user does not exist",
487491
}
488-
return false, err
492+
return false, "", err
489493
}
490494
// checking length of version, to ensure backward compatibility as earlier we did not
491495
// have version for api-tokens
@@ -494,12 +498,12 @@ func (impl UserAuthServiceImpl) AuthVerification(r *http.Request) (bool, error)
494498
err := impl.userService.CheckIfTokenIsValid(emailId, version)
495499
if err != nil {
496500
impl.logger.Errorw("token is not valid", "error", err, "token", token)
497-
return false, err
501+
return false, "", err
498502
}
499503
}
500504

501505
//TODO - extends for other purpose
502-
return true, nil
506+
return true, emailId, nil
503507
}
504508

505509
func (impl UserAuthServiceImpl) DeleteRoles(entityType string, entityName string, tx *pg.Tx, envIdentifier string, workflowName string) (err error) {

pkg/auth/user/UserService.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"github.com/devtron-labs/devtron/pkg/auth/user/adapter"
2323
userHelper "github.com/devtron-labs/devtron/pkg/auth/user/helper"
2424
"github.com/devtron-labs/devtron/pkg/auth/user/repository/helper"
25+
util3 "github.com/devtron-labs/devtron/pkg/auth/user/util"
2526
"net/http"
2627
"strconv"
2728
"strings"
@@ -1364,7 +1365,7 @@ func (impl *UserServiceImpl) GetEmailAndVersionFromToken(token string) (string,
13641365
email = "admin"
13651366
}
13661367

1367-
return email, tokenVersion, nil
1368+
return util3.ConvertEmailToLowerCase(email), tokenVersion, nil
13681369
}
13691370

13701371
func (impl *UserServiceImpl) GetByIds(ids []int32) ([]bean.UserInfo, error) {

pkg/auth/user/repository/UserRepository.go

Lines changed: 41 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,11 @@
2020
package repository
2121

2222
import (
23+
"fmt"
2324
"github.com/devtron-labs/devtron/api/bean"
2425
userBean "github.com/devtron-labs/devtron/pkg/auth/user/bean"
26+
"github.com/devtron-labs/devtron/pkg/auth/user/repository/helper"
27+
"github.com/devtron-labs/devtron/pkg/auth/user/util"
2528
"github.com/devtron-labs/devtron/pkg/sql"
2629
"github.com/go-pg/pg"
2730
"go.uber.org/zap"
@@ -59,13 +62,14 @@ func NewUserRepositoryImpl(dbConnection *pg.DB, logger *zap.SugaredLogger) *User
5962
}
6063

6164
type UserModel struct {
62-
TableName struct{} `sql:"users" pg:",discard_unknown_columns"`
63-
Id int32 `sql:"id,pk"`
64-
EmailId string `sql:"email_id,notnull"`
65-
AccessToken string `sql:"access_token"`
66-
Active bool `sql:"active,notnull"`
67-
UserType string `sql:"user_type"`
68-
UserAudit *UserAudit `sql:"-"`
65+
TableName struct{} `sql:"users" pg:",discard_unknown_columns"`
66+
Id int32 `sql:"id,pk"`
67+
EmailId string `sql:"email_id,notnull"`
68+
RequestEmailId string `sql:"request_email_id"`
69+
AccessToken string `sql:"access_token"`
70+
Active bool `sql:"active,notnull"`
71+
UserType string `sql:"user_type"`
72+
UserAudit *UserAudit `sql:"-"`
6973
sql.AuditLog
7074
}
7175

@@ -79,6 +83,8 @@ type UserRoleModel struct {
7983
}
8084

8185
func (impl UserRepositoryImpl) CreateUser(userModel *UserModel, tx *pg.Tx) (*UserModel, error) {
86+
userModel.RequestEmailId = userModel.EmailId
87+
userModel.EmailId = util.ConvertEmailToLowerCase(userModel.EmailId)
8288
err := tx.Insert(userModel)
8389
if err != nil {
8490
impl.Logger.Error(err)
@@ -88,6 +94,7 @@ func (impl UserRepositoryImpl) CreateUser(userModel *UserModel, tx *pg.Tx) (*Use
8894
return userModel, nil
8995
}
9096
func (impl UserRepositoryImpl) UpdateUser(userModel *UserModel, tx *pg.Tx) (*UserModel, error) {
97+
userModel.EmailId = util.ConvertEmailToLowerCase(userModel.EmailId)
9198
err := tx.Update(userModel)
9299
if err != nil {
93100
impl.Logger.Error(err)
@@ -117,6 +124,7 @@ func (impl UserRepositoryImpl) UpdateToInactiveByIds(ids []int32, tx *pg.Tx, log
117124
func (impl UserRepositoryImpl) GetById(id int32) (*UserModel, error) {
118125
var model UserModel
119126
err := impl.dbConnection.Model(&model).Where("id = ?", id).Where("active = ?", true).Select()
127+
model.EmailId = util.ConvertEmailToLowerCase(model.EmailId)
120128
return &model, err
121129
}
122130

@@ -134,13 +142,14 @@ func (impl UserRepositoryImpl) GetEmailByIds(ids []int32) ([]string, error) {
134142
for _, model := range models {
135143
userEmails = append(userEmails, model.EmailId)
136144
}
137-
return userEmails, err
145+
return util.ConvertEmailsToLowerCase(userEmails), err
138146

139147
}
140148

141149
func (impl UserRepositoryImpl) GetByIdIncludeDeleted(id int32) (*UserModel, error) {
142150
var model UserModel
143151
err := impl.dbConnection.Model(&model).Where("id = ?", id).Select()
152+
model.EmailId = util.ConvertEmailToLowerCase(model.EmailId)
144153
return &model, err
145154
}
146155

@@ -150,6 +159,9 @@ func (impl UserRepositoryImpl) GetAllExcludingApiTokenUser() ([]UserModel, error
150159
Where("active = ?", true).
151160
Where("user_type is NULL or user_type != ?", bean.USER_TYPE_API_TOKEN).
152161
Order("updated_on desc").Select()
162+
for i, user := range userModel {
163+
userModel[i].EmailId = util.ConvertEmailToLowerCase(user.EmailId)
164+
}
153165
return userModel, err
154166
}
155167

@@ -160,20 +172,23 @@ func (impl UserRepositoryImpl) GetAllExecutingQuery(query string) ([]UserModel,
160172
impl.Logger.Error("error in GetAllExecutingQuery", "err", err, "query", query)
161173
return nil, err
162174
}
175+
for i, user := range userModel {
176+
userModel[i].EmailId = util.ConvertEmailToLowerCase(user.EmailId)
177+
}
163178
return userModel, err
164179
}
165180

166181
func (impl UserRepositoryImpl) FetchActiveUserByEmail(email string) (bean.UserInfo, error) {
167182
var users bean.UserInfo
168183

169-
query := "SELECT u.id, u.email_id, u.access_token, u.user_type FROM users u " +
170-
"WHERE u.active = true and u.email_id ILIKE ? order by u.updated_on desc"
184+
query := fmt.Sprintf("SELECT u.id, u.email_id, u.access_token, u.user_type FROM users u"+
185+
" WHERE u.active = true and %s order by u.updated_on desc", helper.GetEmailSearchQuery("u", email))
171186
_, err := impl.dbConnection.Query(&users, query, email)
172187
if err != nil {
173-
impl.Logger.Error("Exception caught:", err)
188+
impl.Logger.Errorw("Exception caught:", "err", err)
174189
return users, err
175190
}
176-
191+
users.EmailId = util.ConvertEmailToLowerCase(email)
177192
return users, nil
178193
}
179194

@@ -182,11 +197,11 @@ func (impl UserRepositoryImpl) FetchUserDetailByEmail(email string) (bean.UserIn
182197
var users []bean.UserRole
183198
var userFinal bean.UserInfo
184199

185-
query := "SELECT u.id, u.email_id, u.user_type, r.role FROM users u" +
186-
" INNER JOIN user_roles ur ON ur.user_id=u.id" +
187-
" INNER JOIN roles r ON r.id=ur.role_id" +
188-
" WHERE u.email_id= ? and u.active = true" +
189-
" ORDER BY u.updated_on desc;"
200+
query := fmt.Sprintf("SELECT u.id, u.email_id, u.user_type, r.role FROM users u"+
201+
" INNER JOIN user_roles ur ON ur.user_id=u.id"+
202+
" INNER JOIN roles r ON r.id=ur.role_id"+
203+
" WHERE %s and u.active = true"+
204+
" ORDER BY u.updated_on desc;", helper.GetEmailSearchQuery("u", email))
190205
_, err := impl.dbConnection.Query(&users, query, email)
191206
if err != nil {
192207
return userFinal, err
@@ -196,7 +211,7 @@ func (impl UserRepositoryImpl) FetchUserDetailByEmail(email string) (bean.UserIn
196211
for _, item := range users {
197212
userFinal.Exist = true
198213
userFinal.Id = item.Id
199-
userFinal.EmailId = item.EmailId
214+
userFinal.EmailId = util.ConvertEmailToLowerCase(item.EmailId)
200215
role = append(role, item.Role)
201216
}
202217
userFinal.Roles = role
@@ -205,6 +220,9 @@ func (impl UserRepositoryImpl) FetchUserDetailByEmail(email string) (bean.UserIn
205220
func (impl UserRepositoryImpl) GetByIds(ids []int32) ([]UserModel, error) {
206221
var model []UserModel
207222
err := impl.dbConnection.Model(&model).Where("id in (?)", pg.In(ids)).Where("active = ?", true).Select()
223+
for i, m := range model {
224+
model[i].EmailId = util.ConvertEmailToLowerCase(m.EmailId)
225+
}
208226
return model, err
209227
}
210228

@@ -215,15 +233,19 @@ func (impl *UserRepositoryImpl) GetConnection() (dbConnection *pg.DB) {
215233
func (impl UserRepositoryImpl) FetchUserMatchesByEmailIdExcludingApiTokenUser(email string) ([]UserModel, error) {
216234
var model []UserModel
217235
err := impl.dbConnection.Model(&model).
218-
Where("email_id like (?)", "%"+email+"%").
236+
Where("email_id ilike (?)", "%"+email+"%").
219237
Where("user_type is NULL or user_type != ?", bean.USER_TYPE_API_TOKEN).
220238
Where("active = ?", true).Select()
239+
for i, m := range model {
240+
model[i].EmailId = util.ConvertEmailToLowerCase(m.EmailId)
241+
}
221242
return model, err
222243
}
223244

224245
func (impl UserRepositoryImpl) FetchActiveOrDeletedUserByEmail(email string) (*UserModel, error) {
225246
var model UserModel
226247
err := impl.dbConnection.Model(&model).Where("email_id ILIKE (?)", email).Limit(1).Select()
248+
model.EmailId = util.ConvertEmailToLowerCase(email)
227249
return &model, err
228250
}
229251

0 commit comments

Comments
 (0)