Feat(auth0.go) Cache for users in idpmanager

This commit is contained in:
shatoboar
2022-06-01 21:52:16 +02:00
parent 49ec33504a
commit cea5693512
2 changed files with 94 additions and 58 deletions

View File

@@ -333,6 +333,7 @@ func (am *DefaultAccountManager) GetUsersFromAccount(accountID string) ([]*UserI
return nil, err return nil, err
} }
} }
// TODO: we need to check whether we need to refresh our cache or not
userInfo := make([]*UserInfo, 0) userInfo := make([]*UserInfo, 0)
@@ -352,7 +353,6 @@ func (am *DefaultAccountManager) GetUsersFromAccount(accountID string) ([]*UserI
for _, queriedUser := range queriedUsers { for _, queriedUser := range queriedUsers {
if localUser, contains := account.Users[queriedUser.ID]; contains { if localUser, contains := account.Users[queriedUser.ID]; contains {
userInfo = append(userInfo, mergeLocalAndQueryUser(*queriedUser, *localUser)) userInfo = append(userInfo, mergeLocalAndQueryUser(*queriedUser, *localUser))
log.Debugf("Merged userinfo to send back; %v", userInfo)
} }
} }

View File

@@ -57,6 +57,7 @@ type Auth0Credentials struct {
type Auth0Profile struct { type Auth0Profile struct {
UserID string `json:"user_id"` UserID string `json:"user_id"`
Name string `json:"name"`
Email string `json:"email"` Email string `json:"email"`
CreatedAt string `json:"created_at"` CreatedAt string `json:"created_at"`
LastLogin string `json:"last_login"` LastLogin string `json:"last_login"`
@@ -115,6 +116,7 @@ func NewAuth0Manager(config Auth0ClientConfig) (*Auth0Manager, error) {
httpClient: httpClient, httpClient: httpClient,
helper: helper, helper: helper,
} }
return &Auth0Manager{ return &Auth0Manager{
authIssuer: config.AuthIssuer, authIssuer: config.AuthIssuer,
credentials: credentials, credentials: credentials,
@@ -294,6 +296,7 @@ func (am *Auth0Manager) CreateExportUsersJob(accountId string) error {
jobResp, err := am.httpClient.Do(exportJobReq) jobResp, err := am.httpClient.Do(exportJobReq)
if err != nil { if err != nil {
log.Debug("Couldn't get job response %v", err)
return err return err
} }
@@ -311,11 +314,13 @@ func (am *Auth0Manager) CreateExportUsersJob(accountId string) error {
body, err := ioutil.ReadAll(jobResp.Body) body, err := ioutil.ReadAll(jobResp.Body)
if err != nil { if err != nil {
log.Debug("Coudln't read export job response; %v", err)
return err return err
} }
err = am.helper.Unmarshal(body, &exportJobResp) err = am.helper.Unmarshal(body, &exportJobResp)
if err != nil { if err != nil {
log.Debug("Coudln't unmarshal export job response; %v", err)
return err return err
} }
@@ -323,16 +328,22 @@ func (am *Auth0Manager) CreateExportUsersJob(accountId string) error {
return fmt.Errorf("couldn't get an batch id status %d, %s, response body: %v", jobResp.StatusCode, jobResp.Status, exportJobResp) return fmt.Errorf("couldn't get an batch id status %d, %s, response body: %v", jobResp.StatusCode, jobResp.Status, exportJobResp)
} }
log.Debugf("batch id status %d, %s, response body: %v", jobResp.StatusCode, jobResp.Status, exportJobResp)
ctx, cancel := context.WithTimeout(context.TODO(), 90*time.Second) ctx, cancel := context.WithTimeout(context.TODO(), 90*time.Second)
defer cancel() defer cancel()
done, downloadLink, err := am.checkExportJobStatus(ctx, exportJobResp.Id) done, downloadLink, err := am.checkExportJobStatus(ctx, exportJobResp.Id)
if err != nil { if err != nil {
log.Debugf("Failed at getting status checks from exportJob; %v", err)
return err return err
} }
if done { if done {
am.cacheUsers(downloadLink) err = am.cacheUsers(downloadLink)
if err != nil {
log.Debugf("Failed to cache users via download link; %v", err)
}
} }
return nil return nil
@@ -343,6 +354,7 @@ func (am *Auth0Manager) CreateExportUsersJob(accountId string) error {
func (am *Auth0Manager) cacheUsers(location string) error { func (am *Auth0Manager) cacheUsers(location string) error {
body, err := doGetReq(am.httpClient, location, "") body, err := doGetReq(am.httpClient, location, "")
if err != nil { if err != nil {
log.Debugf("Can't download cached users; %v", err)
return err return err
} }
@@ -371,7 +383,7 @@ func (am *Auth0Manager) cacheUsers(location string) error {
// This checks the status of the job created at CreateExportUsersJob. // This checks the status of the job created at CreateExportUsersJob.
// If the status is "completed", then return the downloadLink // If the status is "completed", then return the downloadLink
func (am *Auth0Manager) checkExportJobStatus(ctx context.Context, jobId string) (bool, string, error) { func (am *Auth0Manager) checkExportJobStatus(ctx context.Context, jobId string) (bool, string, error) {
retry := time.NewTicker(5 * time.Second) retry := time.NewTicker(500 * time.Millisecond)
for { for {
select { select {
case <-ctx.Done(): case <-ctx.Done():
@@ -382,7 +394,7 @@ func (am *Auth0Manager) checkExportJobStatus(ctx context.Context, jobId string)
return false, "", err return false, "", err
} }
statusUrl := am.authIssuer + "api/v2/jobs/" + jobId statusUrl := am.authIssuer + "/api/v2/jobs/" + jobId
body, err := doGetReq(am.httpClient, statusUrl, jwtToken.AccessToken) body, err := doGetReq(am.httpClient, statusUrl, jwtToken.AccessToken)
if err != nil { if err != nil {
return false, "", err return false, "", err
@@ -403,70 +415,94 @@ func (am *Auth0Manager) checkExportJobStatus(ctx context.Context, jobId string)
} }
} }
// GetBatchedUserData requests users in batches from Auth0
func (am *Auth0Manager) GetBatchedUserData(accountId string) ([]*UserData, error) { func (am *Auth0Manager) GetBatchedUserData(accountId string) ([]*UserData, error) {
jwtToken, err := am.credentials.Authenticate() // first time calling this
if err != nil { // we need to check whether we need to call for users we don't have
return nil, err if len(am.cachedUsers) == 0 {
err := am.CreateExportUsersJob(accountId)
if err != nil {
log.Debugf("Couldn't cache users; %v", err)
return nil, err
}
} }
var list []*UserData var list []*UserData
// https://auth0.com/docs/manage-users/user-search/retrieve-users-with-get-users-endpoint#limitations for _, val := range am.cachedUsers {
// auth0 limitation of 1000 users via this endpoint list = append(list, &UserData{
for page := 0; page < 20; page++ { Name: val.Name,
reqURL, query, err := batchRequestUsersUrl(am.authIssuer, accountId, page) Email: val.Email,
if err != nil { ID: val.UserID,
return nil, err })
}
req, err := http.NewRequest(http.MethodGet, reqURL, strings.NewReader(query.Encode()))
if err != nil {
return nil, err
}
req.Header.Add("authorization", "Bearer "+jwtToken.AccessToken)
req.Header.Add("content-type", "application/json")
res, err := am.httpClient.Do(req)
if err != nil {
return nil, err
}
body, err := io.ReadAll(res.Body)
if err != nil {
return nil, err
}
var batch []UserData
err = json.Unmarshal(body, &batch)
if err != nil {
return nil, err
}
log.Debugf("requested batch; %v", batch)
err = res.Body.Close()
if err != nil {
return nil, err
}
if res.StatusCode != 200 {
return nil, fmt.Errorf("unable to request UserData from auth0, statusCode %d", res.StatusCode)
}
if len(batch) == 0 {
return list, nil
}
for user := range batch {
list = append(list, &batch[user])
}
} }
return list, nil return list, nil
} }
// GetBatchedUserData requests users in batches from Auth0
// func (am *Auth0Manager) GetBatchedUserData(accountId string) ([]*UserData, error) {
// jwtToken, err := am.credentials.Authenticate()
// if err != nil {
// return nil, err
// }
// var list []*UserData
// // https://auth0.com/docs/manage-users/user-search/retrieve-users-with-get-users-endpoint#limitations
// // auth0 limitation of 1000 users via this endpoint
// for page := 0; page < 20; page++ {
// reqURL, query, err := batchRequestUsersUrl(am.authIssuer, accountId, page)
// if err != nil {
// return nil, err
// }
// req, err := http.NewRequest(http.MethodGet, reqURL, strings.NewReader(query.Encode()))
// if err != nil {
// return nil, err
// }
// req.Header.Add("authorization", "Bearer "+jwtToken.AccessToken)
// req.Header.Add("content-type", "application/json")
// res, err := am.httpClient.Do(req)
// if err != nil {
// return nil, err
// }
// body, err := io.ReadAll(res.Body)
// if err != nil {
// return nil, err
// }
// var batch []UserData
// err = json.Unmarshal(body, &batch)
// if err != nil {
// return nil, err
// }
// log.Debugf("requested batch; %v", batch)
// err = res.Body.Close()
// if err != nil {
// return nil, err
// }
// if res.StatusCode != 200 {
// return nil, fmt.Errorf("unable to request UserData from auth0, statusCode %d", res.StatusCode)
// }
// if len(batch) == 0 {
// return list, nil
// }
// for user := range batch {
// list = append(list, &batch[user])
// }
// }
// return list, nil
// }
// GetUserDataByID requests user data from auth0 via ID // GetUserDataByID requests user data from auth0 via ID
func (am *Auth0Manager) GetUserDataByID(userId string, appMetadata AppMetadata) (*UserData, error) { func (am *Auth0Manager) GetUserDataByID(userId string, appMetadata AppMetadata) (*UserData, error) {
jwtToken, err := am.credentials.Authenticate() jwtToken, err := am.credentials.Authenticate()