diff --git a/internal/executors/executor.go b/internal/executors/executor.go index 9225c36..0417f73 100644 --- a/internal/executors/executor.go +++ b/internal/executors/executor.go @@ -1,5 +1,5 @@ package executors type Executor interface { - Execute(ctx ExecutorContext) *ExecutorResult + Execute(Context) *ExecutorResult } diff --git a/internal/executors/executor_context.go b/internal/executors/executor_context.go index d112c0d..dcbb43b 100644 --- a/internal/executors/executor_context.go +++ b/internal/executors/executor_context.go @@ -29,10 +29,13 @@ var ( } ) -func NewExecutorContext(input map[string]string, store map[string]string) ExecutorContext { - return ExecutorContext{ +func NewExecutorContext(input map[string]string, store map[string]string) Context { + if store == nil { + store = make(map[string]string) + } + return &ExecutorContext{ input: input, - store: store, // copy? + store: store, } } diff --git a/internal/executors/executor_result.go b/internal/executors/executor_result.go index 2b2f1d2..1f72d97 100644 --- a/internal/executors/executor_result.go +++ b/internal/executors/executor_result.go @@ -4,7 +4,6 @@ import pb "github.com/SAP/remote-work-processor/build/proto/generated" type ExecutorResult struct { Output map[string]string - Store map[string]string Status pb.TaskExecutionResponseMessage_TaskState Error string } @@ -12,9 +11,7 @@ type ExecutorResult struct { type ExecutorResultOption func(*ExecutorResult) func NewExecutorResult(opts ...ExecutorResultOption) *ExecutorResult { - r := &ExecutorResult{ - Store: make(map[string]string), - } + r := &ExecutorResult{} for _, opt := range opts { opt(r) diff --git a/internal/executors/http/authorization_header.go b/internal/executors/http/authorization_header.go index d7318c8..50497ce 100644 --- a/internal/executors/http/authorization_header.go +++ b/internal/executors/http/authorization_header.go @@ -1,11 +1,8 @@ package http import ( - "github.com/SAP/remote-work-processor/internal/utils" - "regexp" - "strconv" - "github.com/SAP/remote-work-processor/internal/executors" + "regexp" ) const ( @@ -15,119 +12,14 @@ const ( var iasTokenUrlRegex = regexp.MustCompile(IasTokenUrlPattern) -type AuthorizationHeader interface { - GetName() string - GetValue() string - HasValue() bool -} - -type CacheableAuthorizationHeader interface { - AuthorizationHeader - GetCachingKey() string - GetCacheableValue() (string, error) - ApplyCachedToken(token string) (CacheableAuthorizationHeader, error) -} - -type AuthorizationHeaderView string - -type CacheableAuthorizationHeaderView struct { - AuthorizationHeaderView - header *oAuthorizationHeader -} - -type CachedToken struct { - Token string `json:"token,omitempty"` - Timestamp string `json:"timestamp,omitempty"` -} - -func NewCacheableAuthorizationHeaderView(value string, header *oAuthorizationHeader) CacheableAuthorizationHeaderView { - return CacheableAuthorizationHeaderView{ - AuthorizationHeaderView: AuthorizationHeaderView(value), - header: header, - } -} - -func (h CacheableAuthorizationHeaderView) GetCachingKey() string { - //return h.header.cachingKey - return "" -} - -func (h CacheableAuthorizationHeaderView) GetCacheableValue() (string, error) { - token := h.header.token - if token == nil { - return "", nil - } - - t, err := utils.ToJson(token) - if err != nil { - return "", err - } - - cached := CachedToken{ - Token: t, - Timestamp: strconv.FormatInt(token.issuedAt, 10), - } - - value, err := utils.ToJson(cached) - if err != nil { - return "", err - } - return value, nil -} - -func (h CacheableAuthorizationHeaderView) ApplyCachedToken(token string) (CacheableAuthorizationHeader, error) { - if token == "" { - return h, nil - } - - cached := &CachedToken{} - err := utils.FromJson(token, cached) - if err != nil { - return nil, err - } - - if cached.Token == "" || cached.Timestamp == "" { - return h, nil - } - - // TODO: try direct deserialization of a timestamp instead of first to string and then manual parsing - issuedAt, err := strconv.ParseInt(cached.Timestamp, 10, 64) - if err != nil { - return nil, err - } - - err = h.header.setToken(cached.Token, issuedAt) - return h, err -} - -func EmptyAuthorizationHeader() AuthorizationHeaderView { - return "" -} - -func NewAuthorizationHeaderView(value string) AuthorizationHeaderView { - return AuthorizationHeaderView(value) -} - -func (h AuthorizationHeaderView) GetName() string { - return AuthorizationHeaderName -} - -func (h AuthorizationHeaderView) GetValue() string { - return string(h) -} - -func (h AuthorizationHeaderView) HasValue() bool { - return h != "" -} - // Currently only Basic and Bearer token authentication is supported. // OAuth 2.0 will be added later -func CreateAuthorizationHeader(params *HttpRequestParameters) (AuthorizationHeader, error) { +func CreateAuthorizationHeader(params *HttpRequestParameters) (string, error) { authHeader := params.GetAuthorizationHeader() if authHeader != "" { - return AuthorizationHeaderView(authHeader), nil + return authHeader, nil } user := params.GetUser() @@ -138,7 +30,7 @@ func CreateAuthorizationHeader(params *HttpRequestParameters) (AuthorizationHead if user != "" && iasTokenUrlRegex.Match([]byte(tokenUrl)) { return NewIasAuthorizationHeader(tokenUrl, user, params.GetCertificateAuthentication().GetClientCertificate()).Generate() } - return NewOAuthHeaderGenerator(params).Generate() + return NewOAuthHeaderGenerator(params).GenerateWithCacheAside() } if user != "" { @@ -146,10 +38,10 @@ func CreateAuthorizationHeader(params *HttpRequestParameters) (AuthorizationHead } if noAuthorizationRequired(params) { - return EmptyAuthorizationHeader(), nil + return "", nil } - return nil, executors.NewNonRetryableError("Input values for the authentication-related keys " + + return "", executors.NewNonRetryableError("Input values for the authentication-related keys " + "(user, password & authorizationHeader) are not combined properly.") } diff --git a/internal/executors/http/basic_authorization_header.go b/internal/executors/http/basic_authorization_header.go index 298ee65..ebee025 100644 --- a/internal/executors/http/basic_authorization_header.go +++ b/internal/executors/http/basic_authorization_header.go @@ -7,19 +7,19 @@ import ( type basicAuthorizationHeader struct { username string - password string + password []byte } func NewBasicAuthorizationHeader(u string, p string) AuthorizationHeaderGenerator { return &basicAuthorizationHeader{ username: u, - password: p, + password: []byte(p), } } -func (h *basicAuthorizationHeader) Generate() (AuthorizationHeader, error) { - str := fmt.Sprintf("%s:%s", h.username, h.password) +func (h *basicAuthorizationHeader) Generate() (string, error) { + str := fmt.Sprintf("%s:%s", h.username, string(h.password)) encoded := base64.StdEncoding.EncodeToString([]byte(str)) - return NewAuthorizationHeaderView(fmt.Sprintf("Basic %s", encoded)), nil + return fmt.Sprintf("Basic %s", encoded), nil } diff --git a/internal/executors/http/csrf_token_fetcher.go b/internal/executors/http/csrf_token_fetcher.go index ddf9726..ae8c069 100644 --- a/internal/executors/http/csrf_token_fetcher.go +++ b/internal/executors/http/csrf_token_fetcher.go @@ -8,7 +8,7 @@ import ( "github.com/SAP/remote-work-processor/internal/functional" ) -const CSRF_VERB = "fetch" +const CsrfVerb = "fetch" var csrfTokenHeaders = []string{"X-Csrf-Token", "X-Xsrf-Token"} @@ -19,7 +19,7 @@ type csrfTokenFetcher struct { succeedOnTimeout bool } -func NewCsrfTokenFetcher(p *HttpRequestParameters, authHeader AuthorizationHeader) TokenFetcher { +func NewCsrfTokenFetcher(p *HttpRequestParameters, authHeader string) TokenFetcher { return &csrfTokenFetcher{ HttpExecutor: NewDefaultHttpRequestExecutor(), csrfUrl: p.csrfUrl, @@ -44,14 +44,14 @@ func (f *csrfTokenFetcher) Fetch() (string, error) { return "", fmt.Errorf("no csrf header present in response from %s", f.csrfUrl) } -func createCsrfHeaders(authHeader AuthorizationHeader) HttpHeaders { +func createCsrfHeaders(authHeader string) HttpHeaders { csrfHeaders := make(map[string]string) for _, headerKey := range csrfTokenHeaders { - csrfHeaders[headerKey] = CSRF_VERB + csrfHeaders[headerKey] = CsrfVerb } - if authHeader.HasValue() { - csrfHeaders[authHeader.GetName()] = authHeader.GetValue() + if authHeader != "" { + csrfHeaders[AuthorizationHeaderName] = authHeader } return csrfHeaders } diff --git a/internal/executors/http/generator.go b/internal/executors/http/generator.go index 9f7b354..17d149a 100644 --- a/internal/executors/http/generator.go +++ b/internal/executors/http/generator.go @@ -1,5 +1,10 @@ package http type AuthorizationHeaderGenerator interface { - Generate() (AuthorizationHeader, error) + Generate() (string, error) +} + +type CacheableAuthorizationHeaderGenerator interface { + AuthorizationHeaderGenerator + GenerateWithCacheAside() (string, error) } diff --git a/internal/executors/http/http_executor.go b/internal/executors/http/http_executor.go index 96a20b3..360db67 100644 --- a/internal/executors/http/http_executor.go +++ b/internal/executors/http/http_executor.go @@ -28,7 +28,7 @@ func NewDefaultHttpRequestExecutor() *HttpRequestExecutor { return &HttpRequestExecutor{} } -func (e *HttpRequestExecutor) Execute(ctx executors.ExecutorContext) *executors.ExecutorResult { +func (e *HttpRequestExecutor) Execute(ctx executors.Context) *executors.ExecutorResult { log.Println("Executing HttpRequest command...") params, err := NewHttpRequestParametersFromContext(ctx) if err != nil { @@ -74,10 +74,6 @@ func (e *HttpRequestExecutor) ExecuteWithParameters(p *HttpRequestParameters) (* return nil, err } - // TODO: get cached token from server request message store - // apply to *http.Request if present and do not request new auth header - // otherwise, request it, set in store (add it to ExecutionResponse) and return in message to server - authHeader, err := CreateAuthorizationHeader(p) if err != nil { return nil, err @@ -91,7 +87,7 @@ func (e *HttpRequestExecutor) ExecuteWithParameters(p *HttpRequestParameters) (* return execute(client, p, authHeader) } -func obtainCsrf(p *HttpRequestParameters, authHeader AuthorizationHeader) error { +func obtainCsrf(p *HttpRequestParameters, authHeader string) error { fetcher := NewCsrfTokenFetcher(p, authHeader) token, err := fetcher.Fetch() if err != nil { @@ -102,7 +98,7 @@ func obtainCsrf(p *HttpRequestParameters, authHeader AuthorizationHeader) error return nil } -func execute(c *http.Client, p *HttpRequestParameters, authHeader AuthorizationHeader) (*HttpResponse, error) { +func execute(c *http.Client, p *HttpRequestParameters, authHeader string) (*HttpResponse, error) { req, timeCh, err := createRequest(p.method, p.url, p.headers, p.body, authHeader) if err != nil { return nil, executors.NewNonRetryableError("could not create http request: %v", err).WithCause(err) @@ -150,8 +146,7 @@ func requestTimedOut(err error) bool { return errors.As(err, &e) && e.Timeout() } -func createRequest(method string, url string, headers map[string]string, body string, - authHeader AuthorizationHeader) (*http.Request, <-chan int64, error) { +func createRequest(method string, url string, headers map[string]string, body, authHeader string) (*http.Request, <-chan int64, error) { timeCh := make(chan int64, 1) req, err := http.NewRequest(method, url, bytes.NewBuffer([]byte(body))) @@ -173,13 +168,13 @@ func createRequest(method string, url string, headers map[string]string, body st return req.WithContext(httptrace.WithClientTrace(req.Context(), trace)), timeCh, nil } -func addHeaders(req *http.Request, headers map[string]string, authHeader AuthorizationHeader) { +func addHeaders(req *http.Request, headers map[string]string, authHeader string) { for k, v := range headers { req.Header.Add(k, v) } - if authHeader.HasValue() { - req.Header.Set(authHeader.GetName(), authHeader.GetValue()) + if authHeader != "" { + req.Header.Set(AuthorizationHeaderName, authHeader) } } diff --git a/internal/executors/http/http_executor_parameters.go b/internal/executors/http/http_executor_parameters.go index 0662e67..0cb49b1 100644 --- a/internal/executors/http/http_executor_parameters.go +++ b/internal/executors/http/http_executor_parameters.go @@ -48,27 +48,30 @@ type HttpRequestParameters struct { succeedOnTimeout bool certAuthentication *tls.CertificateAuthentication authorizationHeader string + + store map[string]string } -func NewHttpRequestParametersFromContext(ctx executors.ExecutorContext) (*HttpRequestParameters, error) { +func NewHttpRequestParametersFromContext(ctx executors.Context) (*HttpRequestParameters, error) { opts := []functional.OptionWithError[HttpRequestParameters]{ - withMethodFromContext(&ctx), - withUrlFromContext(&ctx), - withTokenUrlFromContext(&ctx), - withCsrfUrlFromContext(&ctx), - withClientIdFromContext(&ctx), - withClientSecretFromContext(&ctx), - withRefreshTokenFromContext(&ctx), - withResponseBodyTransformerFromContext(&ctx), - withHeadersFromContext(&ctx), - withBodyFromContext(&ctx), - withUserFromContext(&ctx), - withPasswordFromContext(&ctx), - withTimeoutFromContext(&ctx), - withSuccessResponseCodesFromContext(&ctx), - withSucceedOnTimeoutFromContext(&ctx), - withCertAuthenticationFromContext(&ctx), - withAuthorizationHeaderFromContext(&ctx), + withMethodFromContext(ctx), + withUrlFromContext(ctx), + withTokenUrlFromContext(ctx), + withCsrfUrlFromContext(ctx), + withClientIdFromContext(ctx), + withClientSecretFromContext(ctx), + withRefreshTokenFromContext(ctx), + withResponseBodyTransformerFromContext(ctx), + withHeadersFromContext(ctx), + withBodyFromContext(ctx), + withUserFromContext(ctx), + withPasswordFromContext(ctx), + withTimeoutFromContext(ctx), + withSuccessResponseCodesFromContext(ctx), + withSucceedOnTimeoutFromContext(ctx), + withCertAuthenticationFromContext(ctx), + withAuthorizationHeaderFromContext(ctx), + withStoreFromContext(ctx), } return applyBuildOptions(&HttpRequestParameters{}, opts...) } @@ -123,291 +126,291 @@ func (p HttpRequestParameters) GetCertificateAuthentication() *tls.CertificateAu } func WithMethod(m string) functional.OptionWithError[HttpRequestParameters] { - return func(hrp *HttpRequestParameters) error { - hrp.method = m + return func(params *HttpRequestParameters) error { + params.method = m return nil } } func WithUrl(u string) functional.OptionWithError[HttpRequestParameters] { - return func(hrp *HttpRequestParameters) error { - hrp.url = u + return func(params *HttpRequestParameters) error { + params.url = u return nil } } func WithTokenUrl(u string) functional.OptionWithError[HttpRequestParameters] { - return func(hrp *HttpRequestParameters) error { - hrp.tokenUrl = u + return func(params *HttpRequestParameters) error { + params.tokenUrl = u return nil } } func WithCsrfUrl(u string) functional.OptionWithError[HttpRequestParameters] { - return func(hrp *HttpRequestParameters) error { - hrp.csrfUrl = u + return func(params *HttpRequestParameters) error { + params.csrfUrl = u return nil } } func WithClientId(id string) functional.OptionWithError[HttpRequestParameters] { - return func(hrp *HttpRequestParameters) error { - hrp.clientId = id + return func(params *HttpRequestParameters) error { + params.clientId = id return nil } } func WithClientSecret(s string) functional.OptionWithError[HttpRequestParameters] { - return func(hrp *HttpRequestParameters) error { - hrp.clientSecret = s + return func(params *HttpRequestParameters) error { + params.clientSecret = s return nil } } func WithRefreshToken(rt string) functional.OptionWithError[HttpRequestParameters] { - return func(hrp *HttpRequestParameters) error { - hrp.refreshToken = rt + return func(params *HttpRequestParameters) error { + params.refreshToken = rt return nil } } func WithHeaders(h map[string]string) functional.OptionWithError[HttpRequestParameters] { - return func(hrp *HttpRequestParameters) error { - hrp.headers = h + return func(params *HttpRequestParameters) error { + params.headers = h return nil } } func WithBody(b string) functional.OptionWithError[HttpRequestParameters] { - return func(hrp *HttpRequestParameters) error { - hrp.body = b + return func(params *HttpRequestParameters) error { + params.body = b return nil } } func WithUser(u string) functional.OptionWithError[HttpRequestParameters] { - return func(hrp *HttpRequestParameters) error { - hrp.user = u + return func(params *HttpRequestParameters) error { + params.user = u return nil } } func WithPassword(p string) functional.OptionWithError[HttpRequestParameters] { - return func(hrp *HttpRequestParameters) error { - hrp.password = p + return func(params *HttpRequestParameters) error { + params.password = p return nil } } func WithTimeout(t uint64) functional.OptionWithError[HttpRequestParameters] { - return func(hrp *HttpRequestParameters) error { - hrp.timeout = t + return func(params *HttpRequestParameters) error { + params.timeout = t return nil } } func WithSuccessResponseCodes(src []string) functional.OptionWithError[HttpRequestParameters] { - return func(hrp *HttpRequestParameters) error { - hrp.successResponseCodes = src + return func(params *HttpRequestParameters) error { + params.successResponseCodes = src return nil } } func WithSucceedOnTimeout(s bool) functional.OptionWithError[HttpRequestParameters] { - return func(hrp *HttpRequestParameters) error { - hrp.succeedOnTimeout = s + return func(params *HttpRequestParameters) error { + params.succeedOnTimeout = s return nil } } func WithCertificateAuthentication(cauth *tls.CertificateAuthentication) functional.OptionWithError[HttpRequestParameters] { - return func(hrp *HttpRequestParameters) error { - hrp.certAuthentication = cauth + return func(params *HttpRequestParameters) error { + params.certAuthentication = cauth return nil } } func WithAuthorizationHeader(h string) functional.OptionWithError[HttpRequestParameters] { - return func(hrp *HttpRequestParameters) error { - hrp.authorizationHeader = h + return func(params *HttpRequestParameters) error { + params.authorizationHeader = h return nil } } -func withMethodFromContext(ctx *executors.ExecutorContext) functional.OptionWithError[HttpRequestParameters] { - return func(hrp *HttpRequestParameters) error { +func withMethodFromContext(ctx executors.Context) functional.OptionWithError[HttpRequestParameters] { + return func(params *HttpRequestParameters) error { m, err := ctx.GetRequiredString(METHOD) if err != nil { return nonRetryableError(err) } - hrp.method = m + params.method = m return nil } } -func withUrlFromContext(ctx *executors.ExecutorContext) functional.OptionWithError[HttpRequestParameters] { - return func(hrp *HttpRequestParameters) error { +func withUrlFromContext(ctx executors.Context) functional.OptionWithError[HttpRequestParameters] { + return func(params *HttpRequestParameters) error { u, err := ctx.GetRequiredString(URL) if err != nil { return nonRetryableError(err) } - hrp.url = u + params.url = u return nil } } -func withTokenUrlFromContext(ctx *executors.ExecutorContext) functional.OptionWithError[HttpRequestParameters] { - return func(hrp *HttpRequestParameters) error { +func withTokenUrlFromContext(ctx executors.Context) functional.OptionWithError[HttpRequestParameters] { + return func(params *HttpRequestParameters) error { u := ctx.GetString(TOKEN_URL) - hrp.tokenUrl = u + params.tokenUrl = u return nil } } -func withCsrfUrlFromContext(ctx *executors.ExecutorContext) functional.OptionWithError[HttpRequestParameters] { - return func(hrp *HttpRequestParameters) error { +func withCsrfUrlFromContext(ctx executors.Context) functional.OptionWithError[HttpRequestParameters] { + return func(params *HttpRequestParameters) error { u := ctx.GetString(CSRF_URL) - hrp.csrfUrl = u + params.csrfUrl = u return nil } } -func withClientIdFromContext(ctx *executors.ExecutorContext) functional.OptionWithError[HttpRequestParameters] { - return func(hrp *HttpRequestParameters) error { +func withClientIdFromContext(ctx executors.Context) functional.OptionWithError[HttpRequestParameters] { + return func(params *HttpRequestParameters) error { id := ctx.GetString(CLIENT_ID) - hrp.clientId = id + params.clientId = id return nil } } -func withClientSecretFromContext(ctx *executors.ExecutorContext) functional.OptionWithError[HttpRequestParameters] { - return func(hrp *HttpRequestParameters) error { +func withClientSecretFromContext(ctx executors.Context) functional.OptionWithError[HttpRequestParameters] { + return func(params *HttpRequestParameters) error { s := ctx.GetString(CLIENT_SECRET) - hrp.clientSecret = s + params.clientSecret = s return nil } } -func withRefreshTokenFromContext(ctx *executors.ExecutorContext) functional.OptionWithError[HttpRequestParameters] { - return func(hrp *HttpRequestParameters) error { +func withRefreshTokenFromContext(ctx executors.Context) functional.OptionWithError[HttpRequestParameters] { + return func(params *HttpRequestParameters) error { rt := ctx.GetString(REFRESH_TOKEN) - hrp.refreshToken = rt + params.refreshToken = rt return nil } } -func withResponseBodyTransformerFromContext(ctx *executors.ExecutorContext) functional.OptionWithError[HttpRequestParameters] { - return func(hrp *HttpRequestParameters) error { +func withResponseBodyTransformerFromContext(ctx executors.Context) functional.OptionWithError[HttpRequestParameters] { + return func(params *HttpRequestParameters) error { t := ctx.GetString(RESPONSE_BODY_TRANSFORMER) - hrp.responseBodyTransformer = t + params.responseBodyTransformer = t return nil } } -func withHeadersFromContext(ctx *executors.ExecutorContext) functional.OptionWithError[HttpRequestParameters] { - return func(hrp *HttpRequestParameters) error { +func withHeadersFromContext(ctx executors.Context) functional.OptionWithError[HttpRequestParameters] { + return func(params *HttpRequestParameters) error { h, err := ctx.GetMap(HEADERS) if err != nil { return nonRetryableError(err) } - hrp.headers = h + params.headers = h return nil } } -func withBodyFromContext(ctx *executors.ExecutorContext) functional.OptionWithError[HttpRequestParameters] { - return func(hrp *HttpRequestParameters) error { +func withBodyFromContext(ctx executors.Context) functional.OptionWithError[HttpRequestParameters] { + return func(params *HttpRequestParameters) error { b := ctx.GetString(BODY) - hrp.body = b + params.body = b return nil } } -func withUserFromContext(ctx *executors.ExecutorContext) functional.OptionWithError[HttpRequestParameters] { - return func(hrp *HttpRequestParameters) error { +func withUserFromContext(ctx executors.Context) functional.OptionWithError[HttpRequestParameters] { + return func(params *HttpRequestParameters) error { u := ctx.GetString(USER) - hrp.user = u + params.user = u return nil } } -func withPasswordFromContext(ctx *executors.ExecutorContext) functional.OptionWithError[HttpRequestParameters] { - return func(hrp *HttpRequestParameters) error { +func withPasswordFromContext(ctx executors.Context) functional.OptionWithError[HttpRequestParameters] { + return func(params *HttpRequestParameters) error { p := ctx.GetString(PASSWORD) - hrp.password = p + params.password = p return nil } } -func withTimeoutFromContext(ctx *executors.ExecutorContext) functional.OptionWithError[HttpRequestParameters] { - return func(hrp *HttpRequestParameters) error { +func withTimeoutFromContext(ctx executors.Context) functional.OptionWithError[HttpRequestParameters] { + return func(params *HttpRequestParameters) error { timeout, err := ctx.GetNumber(TIMEOUT) if err != nil { return nonRetryableError(err) } - hrp.timeout = timeout + params.timeout = timeout return nil } } -func withSuccessResponseCodesFromContext(ctx *executors.ExecutorContext) functional.OptionWithError[HttpRequestParameters] { - return func(hrp *HttpRequestParameters) error { +func withSuccessResponseCodesFromContext(ctx executors.Context) functional.OptionWithError[HttpRequestParameters] { + return func(params *HttpRequestParameters) error { src, err := ctx.GetList(SUCCESS_RESPONSE_CODES) if err != nil { return nonRetryableError(err) } if len(src) == 0 { - hrp.successResponseCodes = defaultSuccessResponseCodes + params.successResponseCodes = defaultSuccessResponseCodes } else { - hrp.successResponseCodes = src + params.successResponseCodes = src } return nil } } -func withSucceedOnTimeoutFromContext(ctx *executors.ExecutorContext) functional.OptionWithError[HttpRequestParameters] { - return func(hrp *HttpRequestParameters) error { +func withSucceedOnTimeoutFromContext(ctx executors.Context) functional.OptionWithError[HttpRequestParameters] { + return func(params *HttpRequestParameters) error { s, err := ctx.GetBoolean(SUCCEED_ON_TIMEOUT) if err != nil { return nonRetryableError(err) } - hrp.succeedOnTimeout = s + params.succeedOnTimeout = s return nil } } -func withCertAuthenticationFromContext(ctx *executors.ExecutorContext) functional.OptionWithError[HttpRequestParameters] { +func withCertAuthenticationFromContext(ctx executors.Context) functional.OptionWithError[HttpRequestParameters] { return func(params *HttpRequestParameters) error { var opts []tls.CertificateAuthenticationOption @@ -433,11 +436,18 @@ func withCertAuthenticationFromContext(ctx *executors.ExecutorContext) functiona } } -func withAuthorizationHeaderFromContext(ctx *executors.ExecutorContext) functional.OptionWithError[HttpRequestParameters] { - return func(hrp *HttpRequestParameters) error { +func withAuthorizationHeaderFromContext(ctx executors.Context) functional.OptionWithError[HttpRequestParameters] { + return func(params *HttpRequestParameters) error { h := ctx.GetString(AUTHORIZATION_HEADER) - hrp.authorizationHeader = h + params.authorizationHeader = h + return nil + } +} + +func withStoreFromContext(ctx executors.Context) functional.OptionWithError[HttpRequestParameters] { + return func(params *HttpRequestParameters) error { + params.store = ctx.GetStore() return nil } } diff --git a/internal/executors/http/ias_authorization_header.go b/internal/executors/http/ias_authorization_header.go index 4a7cd90..37e29d4 100644 --- a/internal/executors/http/ias_authorization_header.go +++ b/internal/executors/http/ias_authorization_header.go @@ -19,20 +19,20 @@ func NewIasAuthorizationHeader(tokenUrl, user, clientCert string) AuthorizationH } } -func (h *iasAuthorizationHeader) Generate() (AuthorizationHeader, error) { +func (h *iasAuthorizationHeader) Generate() (string, error) { raw, err := h.fetcher.Fetch() if err != nil { - return nil, fmt.Errorf("failed to fetch IAS token: %v", err) + return "", fmt.Errorf("failed to fetch IAS token: %v", err) } parsed := make(map[string]any) if err = utils.FromJson(raw, &parsed); err != nil { - return nil, fmt.Errorf("failed to parse IAS token response: %v", err) + return "", fmt.Errorf("failed to parse IAS token response: %v", err) } pass, prs := parsed[PASSCODE] if !prs { - return nil, fmt.Errorf("passcode does not exist in the HTTP response") + return "", fmt.Errorf("passcode does not exist in the HTTP response") } return NewBasicAuthorizationHeader(h.user, pass.(string)).Generate() diff --git a/internal/executors/http/oauth_header.go b/internal/executors/http/oauth_header.go deleted file mode 100644 index 58c1176..0000000 --- a/internal/executors/http/oauth_header.go +++ /dev/null @@ -1,103 +0,0 @@ -package http - -import ( - "fmt" - "sync" - "time" - - "github.com/SAP/remote-work-processor/internal/executors/http/tls" -) - -type OAuthorizationHeaderOption func(*oAuthorizationHeader) - -type oAuthorizationHeader struct { - tokenType TokenType - token *OAuthToken - certAuthentication *tls.CertificateAuthentication - authHeader string - fetcher TokenFetcher - m *sync.Mutex -} - -func NewOAuthorizationHeader(tokenType TokenType, tokenUrl string, executor HttpExecutor, requestBody string, - opts ...OAuthorizationHeaderOption) AuthorizationHeaderGenerator { - h := &oAuthorizationHeader{ - tokenType: tokenType, - token: &OAuthToken{}, - m: &sync.Mutex{}, - } - - for _, opt := range opts { - opt(h) - } - - h.fetcher = NewOAuthTokenFetcher( - withExecutor(executor), - withTokenUrl(tokenUrl), - withRequestBody(requestBody), - withCertificateAuthentication(h.certAuthentication, func(auth *tls.CertificateAuthentication) bool { return auth != nil }), - withAuthHeader(h.authHeader), - ) - - return h -} - -func UseCertificateAuthentication(certAuthentication *tls.CertificateAuthentication) OAuthorizationHeaderOption { - return func(h *oAuthorizationHeader) { - h.certAuthentication = certAuthentication - } -} - -func WithAuthenticationHeader(header AuthorizationHeader) OAuthorizationHeaderOption { - return func(h *oAuthorizationHeader) { - h.authHeader = header.GetValue() - } -} - -func (h *oAuthorizationHeader) Generate() (AuthorizationHeader, error) { - h.m.Lock() - defer h.m.Unlock() - - if !h.token.HasValue() || h.tokenAboutToExpire() { - if err := h.fetchToken(); err != nil { - return nil, fmt.Errorf("failed to fetch OAuth token: %v", err) - } - } - - var token string - switch h.tokenType { - case TokenType_ACCESS: - token = h.token.AccessToken - case TokenType_ID: - token = h.token.IdToken - default: - return nil, NewIllegalTokenTypeError(h.tokenType) - } - - return NewCacheableAuthorizationHeaderView(fmt.Sprintf("Bearer %s", token), h), nil -} - -func (h *oAuthorizationHeader) tokenAboutToExpire() bool { - // copied from OAuth2BearerAuthorizationHeader.java::isTokenAboutToExpire - return time.Now().Add(30 * time.Second).After(time.UnixMilli(h.token.issuedAt + h.token.ExpiresIn)) -} - -func (h *oAuthorizationHeader) setToken(token string, issuedAt int64) error { - t, err := NewOAuthToken(token, issuedAt) - if err != nil { - return err - } - - h.token = t - return nil -} - -func (h *oAuthorizationHeader) fetchToken() error { - token, err := h.fetcher.Fetch() - if err != nil { - return err - } - - issuedAt := time.Now().UnixMilli() - return h.setToken(token, issuedAt) -} diff --git a/internal/executors/http/oauth_header_generator.go b/internal/executors/http/oauth_header_generator.go index d75d6b9..2c2d921 100644 --- a/internal/executors/http/oauth_header_generator.go +++ b/internal/executors/http/oauth_header_generator.go @@ -2,135 +2,129 @@ package http import ( "fmt" - "net/url" + "github.com/SAP/remote-work-processor/internal/utils" + "time" "github.com/SAP/remote-work-processor/internal/executors/http/tls" ) -const ( - CACHING_KEY_FORMAT string = "tokenUrl=%s&oAuthUser=%s&oAuthPwd=%s&getTokenBody=%s" - PASSWORD_GRANT_FORMAT string = "grant_type=password&username=%s&password=%s" - PASSWORD_CREDENTIALS_FORMAT_WITH_CLIENT_ID string = "grant_type=password&client_id=%s&username=%s&password=%s" - CLIENT_CREDENTIALS_FORMAT string = "grant_type=client_credentials&client_id=%s&client_secret=%s" - REFRESH_TOKEN_FORMAT string = "grant_type=refresh_token&refresh_token=%s" - REFRESH_TOKEN_FORMAT_WITH_CERT string = "grant_type=refresh_token&client_id=%s&refresh_token=%s" -) - -func NewOAuthHeaderGenerator(p *HttpRequestParameters) AuthorizationHeaderGenerator { - user := p.GetUser() - clientId := p.GetClientId() - refreshToken := p.GetRefreshToken() +type OAuthorizationHeaderOption func(*oAuthorizationHeaderGenerator) - if refreshToken != "" { - return refreshTokenGenerator(p) - } +type oAuthorizationHeaderGenerator struct { + tokenType TokenType + certAuthentication *tls.CertificateAuthentication + authHeader string + cachingKey string + requestStore map[string]string + fetcher TokenFetcher +} - if user != "" && clientId != "" { - if p.GetCertificateAuthentication().GetClientCertificate() != "" { - return passwordGrantWithClientCertificateGenerator(p) - } +type cachedToken struct { + *OAuthToken + IssuedAt int64 `json:"timestamp,omitempty"` +} - return passwordGrantGenerator(p) +func NewOAuthorizationHeaderGenerator(tokenType TokenType, tokenUrl string, executor HttpExecutor, requestBody string, + opts ...OAuthorizationHeaderOption) CacheableAuthorizationHeaderGenerator { + h := &oAuthorizationHeaderGenerator{ + tokenType: tokenType, } - if user != "" { - return clientCredentialsGenerator(p, user, p.GetPassword()) + for _, opt := range opts { + opt(h) } - if clientId != "" { - return clientCredentialsGenerator(p, clientId, p.GetClientSecret()) - } + h.fetcher = NewOAuthTokenFetcher( + withExecutor(executor), + withTokenUrl(tokenUrl), + withRequestBody(requestBody), + withCertificateAuthentication(h.certAuthentication), + withAuthHeader(h.authHeader), + ) - return nil + return h } -func passwordGrantGenerator(p *HttpRequestParameters) AuthorizationHeaderGenerator { - tokenUrl := p.GetTokenUrl() - clientId := p.GetClientId() - clientSecret := p.GetClientSecret() - body := fmt.Sprintf(PASSWORD_GRANT_FORMAT, urlEncoded(p.GetUser()), urlEncoded(p.GetPassword())) - - return NewOAuthorizationHeader(TokenType_ACCESS, - tokenUrl, - NewDefaultHttpRequestExecutor(), - body, - WithAuthenticationHeader(generateBasicAuthorizationHeader(clientId, clientSecret))) +func UseCertificateAuthentication(certAuthentication *tls.CertificateAuthentication) OAuthorizationHeaderOption { + return func(h *oAuthorizationHeaderGenerator) { + h.certAuthentication = certAuthentication + } } -func passwordGrantWithClientCertificateGenerator(p *HttpRequestParameters) AuthorizationHeaderGenerator { - clientId := p.GetClientId() - body := fmt.Sprintf(PASSWORD_CREDENTIALS_FORMAT_WITH_CLIENT_ID, urlEncoded(clientId), urlEncoded(p.GetUser()), - urlEncoded(p.GetPassword())) - - return NewOAuthorizationHeader(TokenType_ACCESS, - p.GetTokenUrl(), - NewDefaultHttpRequestExecutor(), - body, - UseCertificateAuthentication(p.certAuthentication)) +func WithAuthenticationHeader(header string) OAuthorizationHeaderOption { + return func(h *oAuthorizationHeaderGenerator) { + h.authHeader = header + } } -func clientCredentialsGenerator(p *HttpRequestParameters, clientId string, clientSecret string) AuthorizationHeaderGenerator { - tokenUrl := p.GetTokenUrl() - body := fmt.Sprintf(CLIENT_CREDENTIALS_FORMAT, urlEncoded(clientId), urlEncoded(clientSecret)) - - var opt OAuthorizationHeaderOption +func WithCachingKey(cacheKey string) OAuthorizationHeaderOption { + return func(h *oAuthorizationHeaderGenerator) { + h.cachingKey = cacheKey + } +} - if clientId != "" && p.certAuthentication.GetClientCertificate() == "" { - opt = WithAuthenticationHeader(generateBasicAuthorizationHeader(clientId, clientSecret)) - } else { - opt = UseCertificateAuthentication(p.certAuthentication) +func (h *oAuthorizationHeaderGenerator) Generate() (string, error) { + oAuthToken, err := h.fetchToken() + if err != nil { + return "", err } - return NewOAuthorizationHeader(TokenType_ACCESS, - tokenUrl, - NewDefaultHttpRequestExecutor(), - body, - opt) + return h.formatToken(oAuthToken) } -func refreshTokenGenerator(p *HttpRequestParameters) AuthorizationHeaderGenerator { - tokenUrl := p.GetTokenUrl() - clientId := p.GetClientId() - clientSecret := p.GetClientSecret() - refreshToken := p.GetRefreshToken() - - if p.certAuthentication.GetClientCertificate() == "" { - return refreshTokenGrant(tokenUrl, clientId, clientSecret, refreshToken) - } else { - return refreshTokenGrantWithClientCert(tokenUrl, clientId, refreshToken, p.certAuthentication) +func (h *oAuthorizationHeaderGenerator) GenerateWithCacheAside() (string, error) { + var cached cachedToken + if cachedValue, inCache := h.requestStore[h.cachingKey]; inCache { + if err := utils.FromJson(cachedValue, &cached); err != nil { + return "", fmt.Errorf("failed to deserialize cached OAuth token: %v", err) + } } -} -func refreshTokenGrantWithClientCert(tokenUrl, clientId, refreshToken string, certAuthentication *tls.CertificateAuthentication) AuthorizationHeaderGenerator { - body := fmt.Sprintf(REFRESH_TOKEN_FORMAT_WITH_CERT, urlEncoded(clientId), urlEncoded(refreshToken)) + if h.tokenAboutToExpire(cached) { + newToken, err := h.fetchToken() + if err != nil { + return "", err + } - return NewOAuthorizationHeader(TokenType_ACCESS, - tokenUrl, - NewDefaultHttpRequestExecutor(), - body, - UseCertificateAuthentication(certAuthentication)) -} + cached = cachedToken{ + OAuthToken: newToken, + IssuedAt: time.Now().UnixMilli(), + } -func refreshTokenGrant(tokenUrl, clientId, clientSecret, refreshToken string) AuthorizationHeaderGenerator { - body := fmt.Sprintf(REFRESH_TOKEN_FORMAT, urlEncoded(refreshToken)) + newCachedToken, err := utils.ToJson(cached) + if err != nil { + return "", fmt.Errorf("failed to serialize cached OAuth token: %v", err) + } - var opts []OAuthorizationHeaderOption - if clientId != "" { - opts = append(opts, WithAuthenticationHeader(generateBasicAuthorizationHeader(clientId, clientSecret))) + h.requestStore[h.cachingKey] = newCachedToken } - return NewOAuthorizationHeader(TokenType_ACCESS, - tokenUrl, - NewDefaultHttpRequestExecutor(), - body, - opts...) + return h.formatToken(cached.OAuthToken) +} + +func (h *oAuthorizationHeaderGenerator) tokenAboutToExpire(token cachedToken) bool { + // copied from OAuth2BearerAuthorizationHeader.java::isTokenAboutToExpire + return time.Now().Add(30 * time.Second).After(time.UnixMilli(token.IssuedAt + token.ExpiresIn)) } -func generateBasicAuthorizationHeader(clientId string, clientSecret string) AuthorizationHeader { - header, _ := NewBasicAuthorizationHeader(clientId, clientSecret).Generate() - return header +func (h *oAuthorizationHeaderGenerator) fetchToken() (*OAuthToken, error) { + rawToken, err := h.fetcher.Fetch() + if err != nil { + return nil, fmt.Errorf("failed to fetch OAuth token: %v", err) + } + return NewOAuthToken(rawToken) } -func urlEncoded(query string) string { - return url.QueryEscape(query) +func (h *oAuthorizationHeaderGenerator) formatToken(oAuthToken *OAuthToken) (string, error) { + var token string + switch h.tokenType { + case TokenType_ACCESS: + token = oAuthToken.AccessToken + case TokenType_ID: + token = oAuthToken.IdToken + default: + return "", NewIllegalTokenTypeError(h.tokenType) + } + + return fmt.Sprintf("Bearer %s", token), nil } diff --git a/internal/executors/http/oauth_header_generator_factory.go b/internal/executors/http/oauth_header_generator_factory.go new file mode 100644 index 0000000..3ac402c --- /dev/null +++ b/internal/executors/http/oauth_header_generator_factory.go @@ -0,0 +1,151 @@ +package http + +import ( + "crypto/sha256" + "encoding/hex" + "fmt" + "net/url" + + "github.com/SAP/remote-work-processor/internal/executors/http/tls" +) + +const ( + CACHING_KEY_FORMAT string = "tokenUrl=%s&oAuthUser=%s&oAuthPwd=%s&getTokenBody=%s" + PASSWORD_GRANT_FORMAT string = "grant_type=password&username=%s&password=%s" + PASSWORD_CREDENTIALS_FORMAT_WITH_CLIENT_ID string = "grant_type=password&client_id=%s&username=%s&password=%s" + CLIENT_CREDENTIALS_FORMAT string = "grant_type=client_credentials&client_id=%s&client_secret=%s" + REFRESH_TOKEN_FORMAT string = "grant_type=refresh_token&refresh_token=%s" + REFRESH_TOKEN_FORMAT_WITH_CERT string = "grant_type=refresh_token&client_id=%s&refresh_token=%s" +) + +func NewOAuthHeaderGenerator(p *HttpRequestParameters) CacheableAuthorizationHeaderGenerator { + user := p.GetUser() + clientId := p.GetClientId() + refreshToken := p.GetRefreshToken() + + if refreshToken != "" { + return refreshTokenGenerator(p) + } + + if user != "" && clientId != "" { + if p.GetCertificateAuthentication().GetClientCertificate() != "" { + return passwordGrantWithClientCertificateGenerator(p) + } + + return passwordGrantGenerator(p) + } + + if user != "" { + return clientCredentialsGenerator(p, user, p.GetPassword()) + } + + if clientId != "" { + return clientCredentialsGenerator(p, clientId, p.GetClientSecret()) + } + + return nil // what happens here? +} + +func passwordGrantGenerator(p *HttpRequestParameters) CacheableAuthorizationHeaderGenerator { + tokenUrl := p.GetTokenUrl() + clientId := p.GetClientId() + clientSecret := p.GetClientSecret() + body := fmt.Sprintf(PASSWORD_GRANT_FORMAT, urlEncoded(p.GetUser()), urlEncoded(p.GetPassword())) + + return NewOAuthorizationHeaderGenerator(TokenType_ACCESS, + tokenUrl, + NewDefaultHttpRequestExecutor(), + body, + WithAuthenticationHeader(generateBasicAuthorizationHeader(clientId, clientSecret)), + WithCachingKey(generateCachingKey(tokenUrl, clientId, clientSecret, body))) +} + +func passwordGrantWithClientCertificateGenerator(p *HttpRequestParameters) CacheableAuthorizationHeaderGenerator { + tokenUrl := p.GetTokenUrl() + clientId := p.GetClientId() + body := fmt.Sprintf(PASSWORD_CREDENTIALS_FORMAT_WITH_CLIENT_ID, urlEncoded(clientId), urlEncoded(p.GetUser()), + urlEncoded(p.GetPassword())) + + return NewOAuthorizationHeaderGenerator(TokenType_ACCESS, + p.GetTokenUrl(), + NewDefaultHttpRequestExecutor(), + body, + UseCertificateAuthentication(p.GetCertificateAuthentication()), + WithCachingKey(generateCachingKey(tokenUrl, clientId, "", body))) +} + +func clientCredentialsGenerator(p *HttpRequestParameters, clientId string, clientSecret string) CacheableAuthorizationHeaderGenerator { + tokenUrl := p.GetTokenUrl() + body := fmt.Sprintf(CLIENT_CREDENTIALS_FORMAT, urlEncoded(clientId), urlEncoded(clientSecret)) + + var opt OAuthorizationHeaderOption + + if clientId != "" && p.GetCertificateAuthentication().GetClientCertificate() == "" { + opt = WithAuthenticationHeader(generateBasicAuthorizationHeader(clientId, clientSecret)) + } else { + opt = UseCertificateAuthentication(p.GetCertificateAuthentication()) + } + + return NewOAuthorizationHeaderGenerator(TokenType_ACCESS, + tokenUrl, + NewDefaultHttpRequestExecutor(), + body, + opt, + WithCachingKey(generateCachingKey(tokenUrl, clientId, clientSecret, body))) +} + +func refreshTokenGenerator(p *HttpRequestParameters) CacheableAuthorizationHeaderGenerator { + tokenUrl := p.GetTokenUrl() + clientId := p.GetClientId() + clientSecret := p.GetClientSecret() + refreshToken := p.GetRefreshToken() + + if p.GetCertificateAuthentication().GetClientCertificate() == "" { + return refreshTokenGrant(tokenUrl, clientId, clientSecret, refreshToken) + } else { + return refreshTokenGrantWithClientCert(tokenUrl, clientId, refreshToken, p.GetCertificateAuthentication()) + } +} + +func refreshTokenGrantWithClientCert(tokenUrl, clientId, refreshToken string, certAuthentication *tls.CertificateAuthentication) CacheableAuthorizationHeaderGenerator { + body := fmt.Sprintf(REFRESH_TOKEN_FORMAT_WITH_CERT, urlEncoded(clientId), urlEncoded(refreshToken)) + + return NewOAuthorizationHeaderGenerator(TokenType_ACCESS, + tokenUrl, + NewDefaultHttpRequestExecutor(), + body, + UseCertificateAuthentication(certAuthentication), + WithCachingKey(generateCachingKey(tokenUrl, clientId, "", body))) +} + +func refreshTokenGrant(tokenUrl, clientId, clientSecret, refreshToken string) CacheableAuthorizationHeaderGenerator { + body := fmt.Sprintf(REFRESH_TOKEN_FORMAT, urlEncoded(refreshToken)) + + var opts []OAuthorizationHeaderOption + if clientId != "" { + opts = append(opts, WithAuthenticationHeader(generateBasicAuthorizationHeader(clientId, clientSecret))) + } + opts = append(opts, WithCachingKey(generateCachingKey(tokenUrl, clientId, clientSecret, body))) + + return NewOAuthorizationHeaderGenerator(TokenType_ACCESS, + tokenUrl, + NewDefaultHttpRequestExecutor(), + body, + opts...) +} + +func generateBasicAuthorizationHeader(clientId string, clientSecret string) string { + header, _ := NewBasicAuthorizationHeader(clientId, clientSecret).Generate() + return header +} + +func urlEncoded(query string) string { + return url.QueryEscape(query) +} + +// TODO: TOTP should be considered as part of caching key here as well +func generateCachingKey(tokenUrl string, clientId string, clientSecret string, requestBody string) string { + h := sha256.New() + h.Write(fmt.Appendf(nil, CACHING_KEY_FORMAT, tokenUrl, clientId, clientSecret, requestBody)) + return hex.EncodeToString(h.Sum(nil)) +} diff --git a/internal/executors/http/token.go b/internal/executors/http/oauth_token.go similarity index 69% rename from internal/executors/http/token.go rename to internal/executors/http/oauth_token.go index e0d0557..7baf1e6 100644 --- a/internal/executors/http/token.go +++ b/internal/executors/http/oauth_token.go @@ -10,20 +10,12 @@ type OAuthToken struct { AccessToken string `json:"access_token"` IdToken string `json:"id_token,omitempty"` ExpiresIn int64 `json:"expires_in,omitempty"` - - issuedAt int64 } -func NewOAuthToken(token string, issuedAt int64) (*OAuthToken, error) { +func NewOAuthToken(token string) (*OAuthToken, error) { oauth := &OAuthToken{} if err := json.Unmarshal([]byte(token), oauth); err != nil { return nil, fmt.Errorf("failed to parse OAuth token: %v", err) } - - oauth.issuedAt = issuedAt return oauth, nil } - -func (t OAuthToken) HasValue() bool { - return t.AccessToken != "" -} diff --git a/internal/executors/http/oauth_token_fetcher.go b/internal/executors/http/oauth_token_fetcher.go index c8ae64b..0b5b54f 100644 --- a/internal/executors/http/oauth_token_fetcher.go +++ b/internal/executors/http/oauth_token_fetcher.go @@ -49,11 +49,9 @@ func withAuthHeader(header string) functional.Option[oAuthTokenFetcher] { } } -func withCertificateAuthentication(auth *tls.CertificateAuthentication, p func(*tls.CertificateAuthentication) bool) functional.Option[oAuthTokenFetcher] { +func withCertificateAuthentication(auth *tls.CertificateAuthentication) functional.Option[oAuthTokenFetcher] { return func(f *oAuthTokenFetcher) { - if p(auth) { - f.certAuthentication = auth - } + f.certAuthentication = auth } } diff --git a/internal/executors/void/void_executor.go b/internal/executors/void/void_executor.go index dcfc518..c264cfb 100644 --- a/internal/executors/void/void_executor.go +++ b/internal/executors/void/void_executor.go @@ -12,7 +12,7 @@ const ( type VoidExecutor struct{} -func (VoidExecutor) Execute(ctx executors.ExecutorContext) *executors.ExecutorResult { +func (VoidExecutor) Execute(ctx executors.Context) *executors.ExecutorResult { log.Println("Executing Void command...") msg := ctx.GetString(MESSAGE_KEY) return executors.NewExecutorResult( diff --git a/internal/grpc/processors/remote_task_processor.go b/internal/grpc/processors/remote_task_processor.go index 8839b02..4293142 100644 --- a/internal/grpc/processors/remote_task_processor.go +++ b/internal/grpc/processors/remote_task_processor.go @@ -40,18 +40,18 @@ func (p RemoteTaskProcessor) Process(_ context.Context) (*pb.ClientMessage, erro res := executor.Execute(ctx) return &pb.ClientMessage{ - Body: buildResult(p.req, res), + Body: buildResult(ctx, p.req, res), }, nil } -func buildResult(req *pb.TaskExecutionRequestMessage, res *executors.ExecutorResult) *pb.ClientMessage_TaskExecutionResponse { +func buildResult(ctx executors.Context, req *pb.TaskExecutionRequestMessage, res *executors.ExecutorResult) *pb.ClientMessage_TaskExecutionResponse { return &pb.ClientMessage_TaskExecutionResponse{ TaskExecutionResponse: &pb.TaskExecutionResponseMessage{ ExecutionId: req.GetExecutionId(), ExecutionVersion: req.GetExecutionVersion(), State: res.Status, Output: res.Output, - Store: res.Store, + Store: ctx.GetStore(), Error: &wrapperspb.StringValue{ Value: res.Error, },