Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: oauth access denied handling #3960

Merged
merged 34 commits into from
Oct 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
f199f6b
fix: access_denied error handling for OAuth destinations
Sep 11, 2023
bec2e34
fix: mock oauth service
Sep 12, 2023
12c46ff
Merge remote-tracking branch 'origin' into feat.oauth-access-denied-h…
Sep 12, 2023
84261c8
chore: rename ref_token_invalid_grant constant
Sep 12, 2023
07fa015
Merge remote-tracking branch 'origin' into feat.oauth-access-denied-h…
Sep 12, 2023
e49076a
Merge remote-tracking branch 'origin' into feat.oauth-access-denied-h…
Sep 14, 2023
9b1cb61
chore: update the method for authStatus toggle to PUT
Sep 14, 2023
fe203c1
Merge remote-tracking branch 'origin' into feat.oauth-access-denied-h…
Sep 15, 2023
3bf7054
chore: include contract changes
Sep 15, 2023
520b123
Merge remote-tracking branch 'origin' into feat.oauth-access-denied-h…
Sep 26, 2023
301e33b
Merge remote-tracking branch 'origin' into feat.oauth-access-denied-h…
Sep 29, 2023
f720182
fix: add AUTH_STATUS_INACTIVE handling in regulation-worker
Sep 29, 2023
096f232
chore: refactoring some changes, adding logic for handling invalid_gr…
Oct 8, 2023
9a571e1
fix: address comments
Oct 8, 2023
a1f1261
fix: send badrequest when required parameters are not sent in tests
Oct 8, 2023
d3755ba
fix: change response error message for authStatusInactive req(both fa…
Oct 8, 2023
c3d1772
Merge remote-tracking branch 'origin' into feat.oauth-access-denied-h…
Oct 8, 2023
404a323
fix: add multiple go-routines tests for authStatus/toggle
Oct 9, 2023
8783ea5
fix: formatting
Oct 9, 2023
7cefefe
fix: rename variables, send right error message post inactivation of …
Oct 9, 2023
053a1db
fix: comment correction
Oct 9, 2023
17e633e
fix: remove unused argument
Oct 9, 2023
068d20f
Merge remote-tracking branch 'origin' into feat.oauth-access-denied-h…
Oct 9, 2023
716db0b
fix: updated wrong url status-code to 404
Oct 9, 2023
8dd4a5d
Merge remote-tracking branch 'origin' into feat.oauth-access-denied-h…
Oct 9, 2023
c834a57
Merge remote-tracking branch 'origin' into feat.oauth-access-denied-h…
Oct 9, 2023
ba9829f
Merge remote-tracking branch 'origin' into feat.oauth-access-denied-h…
Oct 10, 2023
8064184
fix: propagate error message rather than error type
Oct 11, 2023
c3ea97a
fix: unused return variable removal
Oct 11, 2023
ab951a9
Merge remote-tracking branch 'origin' into feat.oauth-access-denied-h…
Oct 16, 2023
7762042
fix: remove secret info from cache after inactivating authStatus
Oct 16, 2023
150b30a
fix: rename oauth function & update related mock
Oct 17, 2023
0eb5714
Merge remote-tracking branch 'origin' into feat.oauth-access-denied-h…
Oct 18, 2023
000c6f9
Merge branch 'master' into feat.oauth-access-denied-handling
fracasula Oct 18, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 6 additions & 7 deletions mocks/services/oauth/mock_oauth.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

76 changes: 54 additions & 22 deletions regulation-worker/internal/delete/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@ import (
"os"
"strings"

"github.com/samber/lo"

"github.com/rudderlabs/rudder-go-kit/logger"
"github.com/rudderlabs/rudder-go-kit/stats"
backendconfig "github.com/rudderlabs/rudder-server/backend-config"
"github.com/rudderlabs/rudder-server/regulation-worker/internal/model"
"github.com/rudderlabs/rudder-server/services/oauth"
"github.com/rudderlabs/rudder-server/utils/httputil"
Expand Down Expand Up @@ -109,17 +112,23 @@ func (api *APIManager) deleteWithRetry(ctx context.Context, job model.Job, desti
jobStatus := getJobStatus(resp.StatusCode, jobResp)
pkgLogger.Debugf("[%v] Job: %v, JobStatus: %v", destination.Name, job.ID, jobStatus)

if isOAuthEnabled && isTokenExpired(jobResp) && currentOauthRetryAttempt < api.MaxOAuthRefreshRetryAttempts {
err = api.refreshOAuthToken(destination.Name, job.WorkspaceID, oAuthDetail)
if err != nil {
pkgLogger.Error(err)
return model.JobStatus{Status: model.JobStatusFailed, Error: err}
oauthErrJob, oauthErrJobFound := getOAuthErrorJob(jobResp)

if oauthErrJobFound && isOAuthEnabled {
if oauthErrJob.AuthErrorCategory == oauth.AUTH_STATUS_INACTIVE {
return api.inactivateAuthStatus(&destination, job, oAuthDetail)
}
if oauthErrJob.AuthErrorCategory == oauth.REFRESH_TOKEN && currentOauthRetryAttempt < api.MaxOAuthRefreshRetryAttempts {
err = api.refreshOAuthToken(&destination, job, oAuthDetail)
if err != nil {
pkgLogger.Error(err)
return model.JobStatus{Status: model.JobStatusFailed, Error: err}
}
// retry the request
pkgLogger.Infof("[%v] Retrying deleteRequest job(id: %v) for the whole batch, RetryAttempt: %v", destination.Name, job.ID, currentOauthRetryAttempt+1)
return api.deleteWithRetry(ctx, job, destination, currentOauthRetryAttempt+1)
}
// retry the request
pkgLogger.Infof("[%v] Retrying deleteRequest job(id: %v) for the whole batch, RetryAttempt: %v", destination.Name, job.ID, currentOauthRetryAttempt+1)
return api.deleteWithRetry(ctx, job, destination, currentOauthRetryAttempt+1)
}

return jobStatus
}

Expand Down Expand Up @@ -160,13 +169,10 @@ func mapJobToPayload(job model.Job, destName string, destConfig map[string]inter
}
}

func isTokenExpired(jobResponses []JobRespSchema) bool {
for _, jobResponse := range jobResponses {
if jobResponse.AuthErrorCategory == oauth.REFRESH_TOKEN {
return true
}
}
return false
func getOAuthErrorJob(jobResponses []JobRespSchema) (JobRespSchema, bool) {
return lo.Find(jobResponses, func(item JobRespSchema) bool {
return lo.Contains([]string{oauth.AUTH_STATUS_INACTIVE, oauth.REFRESH_TOKEN}, item.AuthErrorCategory)
})
}

func setOAuthHeader(secretToken *oauth.AuthResponse, req *http.Request) error {
Expand All @@ -192,29 +198,55 @@ func (api *APIManager) getOAuthDetail(destDetail *model.Destination, workspaceId
EventNamePrefix: "fetch_token",
})
if tokenStatusCode != http.StatusOK {
return oauthDetail{}, fmt.Errorf("[%s][FetchToken] Error in Token Fetch statusCode: %d\t error: %s", destDetail.Name, tokenStatusCode, secretToken.Err)
return oauthDetail{}, fmt.Errorf("[%s][FetchToken] Error in Token Fetch statusCode: %d\t error: %s", destDetail.Name, tokenStatusCode, secretToken.ErrorMessage)
}
return oauthDetail{
id: id,
secretToken: secretToken,
}, nil
}

func (api *APIManager) refreshOAuthToken(destName, workspaceId string, oAuthDetail oauthDetail) error {
func (api *APIManager) inactivateAuthStatus(destination *model.Destination, job model.Job, oAuthDetail oauthDetail) (jobStatus model.JobStatus) {
dest := &backendconfig.DestinationT{
ID: destination.DestinationID,
Config: destination.Config,
DestinationDefinition: backendconfig.DestinationDefinitionT{
Name: destination.Name,
Config: destination.DestDefConfig,
},
}
_, resp := api.OAuth.AuthStatusToggle(&oauth.AuthStatusToggleParams{
Destination: dest,
WorkspaceId: job.WorkspaceID,
RudderAccountId: oAuthDetail.id,
AuthStatus: oauth.AuthStatusInactive,
})
jobStatus.Status = model.JobStatusAborted
jobStatus.Error = fmt.Errorf(resp)
return jobStatus
}

func (api *APIManager) refreshOAuthToken(destination *model.Destination, job model.Job, oAuthDetail oauthDetail) error {
refTokenParams := &oauth.RefreshTokenParams{
Secret: oAuthDetail.secretToken.Account.Secret,
WorkspaceId: workspaceId,
WorkspaceId: job.WorkspaceID,
AccountId: oAuthDetail.id,
DestDefName: destName,
DestDefName: destination.Name,
EventNamePrefix: "refresh_token",
}
statusCode, refreshResponse := api.OAuth.RefreshToken(refTokenParams)
if statusCode != http.StatusOK {
if refreshResponse.Err == oauth.REF_TOKEN_INVALID_GRANT {
// authStatus should be made inactive
api.inactivateAuthStatus(destination, job, oAuthDetail)
return fmt.Errorf(refreshResponse.ErrorMessage)
}

var refreshRespErr string
if refreshResponse != nil {
refreshRespErr = refreshResponse.Err
refreshRespErr = refreshResponse.ErrorMessage
}
return fmt.Errorf("[%v] Failed to refresh token for destination in workspace(%v) & account(%v) with %v", destName, workspaceId, oAuthDetail.id, refreshRespErr)
return fmt.Errorf("[%v] Failed to refresh token for destination in workspace(%v) & account(%v) with %v", destination.Name, job.WorkspaceID, oAuthDetail.id, refreshRespErr)
}
return nil
}
Loading
Loading