Skip to content

Commit

Permalink
fix: Add authentication to support-scheduler actions
Browse files Browse the repository at this point in the history
Signed-off-by: Bryon Nevis <bryon.nevis@intel.com>
  • Loading branch information
bnevis-i committed Mar 8, 2023
1 parent 58b8fd4 commit 54caeec
Show file tree
Hide file tree
Showing 8 changed files with 44 additions and 6 deletions.
2 changes: 2 additions & 0 deletions cmd/support-scheduler/res/configuration.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ Name = "scheduler"
Path = "/api/v2/event/age/604800000000000" # Remove events older than 7 days
Interval = "midnight"
AdminState = "UNLOCKED"
# AuthMethod = JWT degrades to no auth in security-disabled EdgeX
AuthMethod = "JWT"

[MessageBus]
[MessageBus.Optional]
Expand Down
11 changes: 10 additions & 1 deletion internal/pkg/utils/restaddress.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"strconv"
"strings"

"github.com/edgexfoundry/go-mod-core-contracts/v3/clients/interfaces"
"github.com/edgexfoundry/go-mod-core-contracts/v3/clients/logger"
"github.com/edgexfoundry/go-mod-core-contracts/v3/common"
"github.com/edgexfoundry/go-mod-core-contracts/v3/errors"
Expand All @@ -25,14 +26,22 @@ var methods = map[string]struct{}{
}

// SendRequestWithRESTAddress sends request with REST address
func SendRequestWithRESTAddress(lc logger.LoggingClient, content string, contentType string, address models.RESTAddress) (res string, err errors.EdgeX) {
func SendRequestWithRESTAddress(lc logger.LoggingClient, content string, contentType string,
address models.RESTAddress, jwtSecretProvider interfaces.AuthenticationInjector) (res string, err errors.EdgeX) {

executingUrl := getUrlStr(address)

req, err := getHttpRequest(address.HTTPMethod, executingUrl, content, contentType)
if err != nil {
return "", errors.NewCommonEdgeX(errors.KindServerError, "fail to create http request", err)
}

if jwtSecretProvider != nil {
if err2 := jwtSecretProvider.AddAuthenticationData(req); err2 != nil {
return "", errors.NewCommonEdgeXWrapper(err2)
}
}

client := &http.Client{}
res, err = sendRequestAndGetResponse(client, req)
if err != nil {
Expand Down
4 changes: 3 additions & 1 deletion internal/support/notifications/application/channel/sender.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ func (sender *RESTSender) Send(notification models.Notification, address models.
if !ok {
return "", errors.NewCommonEdgeX(errors.KindContractInvalid, "fail to cast Address to RESTAddress", nil)
}
return utils.SendRequestWithRESTAddress(lc, notification.Content, notification.ContentType, restAddress)
// NOTE: Not currently passing an AuthenticationInjector here;
// no current notifications are calling EdgeX services
return utils.SendRequestWithRESTAddress(lc, notification.Content, notification.ContentType, restAddress, nil)
}

// EmailSender is the implementation of the interfaces.ChannelSender, which is used to send the notifications via email
Expand Down
1 change: 1 addition & 0 deletions internal/support/scheduler/application/intervalaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ func LoadIntervalActionToSchedulerManager(dic *di.Container) errors.EdgeX {
Content: configuration.IntervalActions[i].Content,
ContentType: configuration.IntervalActions[i].ContentType,
AdminState: configuration.IntervalActions[i].AdminState,
AuthMethod: configuration.IntervalActions[i].AuthMethod,
}
validateErr := common.Validate(dto)
if validateErr != nil {
Expand Down
20 changes: 18 additions & 2 deletions internal/support/scheduler/application/scheduler/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ import (
"github.com/edgexfoundry/edgex-go/internal/support/scheduler/config"
"github.com/edgexfoundry/edgex-go/internal/support/scheduler/infrastructure/interfaces"

bootstrapInterfaces "github.com/edgexfoundry/go-mod-bootstrap/v3/bootstrap/interfaces"
"github.com/edgexfoundry/go-mod-bootstrap/v3/bootstrap/secret"

clientInterfaces "github.com/edgexfoundry/go-mod-core-contracts/v3/clients/interfaces"

"github.com/edgexfoundry/go-mod-core-contracts/v3/clients/logger"
"github.com/edgexfoundry/go-mod-core-contracts/v3/common"
"github.com/edgexfoundry/go-mod-core-contracts/v3/errors"
Expand All @@ -30,17 +35,19 @@ type manager struct {
executorQueue *queue.Queue
intervalToExecutorMap map[string]*Executor
actionToIntervalMap map[string]string
secretProvider bootstrapInterfaces.SecretProvider
}

// NewManager creates a new scheduler manager for running the interval job
func NewManager(lc logger.LoggingClient, config *config.ConfigurationStruct) interfaces.SchedulerManager {
func NewManager(lc logger.LoggingClient, config *config.ConfigurationStruct, secretProvider bootstrapInterfaces.SecretProvider) interfaces.SchedulerManager {
return &manager{
ticker: time.NewTicker(time.Duration(config.ScheduleIntervalTime) * time.Millisecond),
lc: lc,
config: config,
executorQueue: queue.New(),
intervalToExecutorMap: make(map[string]*Executor),
actionToIntervalMap: make(map[string]string),
secretProvider: secretProvider,
}
}

Expand Down Expand Up @@ -134,7 +141,16 @@ func (m *manager) executeAction(action models.IntervalAction) errors.EdgeX {
if !ok {
return errors.NewCommonEdgeX(errors.KindContractInvalid, "fail to cast Address to RESTAddress", nil)
}
_, err := utils.SendRequestWithRESTAddress(m.lc, action.Content, action.ContentType, restAddress)

var jwtSecretProvider clientInterfaces.AuthenticationInjector
// Awaiting change to go-mod-core-contracts
if action.AuthMethod == config.AuthMethodJWT {
jwtSecretProvider = secret.NewJWTSecretProvider(m.secretProvider)
} else {
jwtSecretProvider = secret.NewJWTSecretProvider(nil)
}

_, err := utils.SendRequestWithRESTAddress(m.lc, action.Content, action.ContentType, restAddress, jwtSecretProvider)
if err != nil {
m.lc.Errorf("fail to send request with RESTAddress, err: %v", err)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,6 @@ func TestNewManager(t *testing.T) {
IntervalActions: nil,
ScheduleIntervalTime: 500,
}
manager := NewManager(lc, config)
manager := NewManager(lc, config, nil)
require.NotNil(t, manager)
}
7 changes: 7 additions & 0 deletions internal/support/scheduler/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,15 @@ type IntervalActionInfo struct {
ContentType string
// Administrative state (LOCKED/UNLOCKED)
AdminState string
// AuthMethod indicates how to authenticate the outbound URL -- "none" (default) or "jwt"
AuthMethod string
}

const (
AuthMethodNone = "NONE"
AuthMethodJWT = "JWT"
)

// URI constructs a URI from the protocol, host and port and returns that as a string.
func (e IntervalActionInfo) URL() string {
return fmt.Sprintf("%s://%s:%v", e.Protocol, e.Host, e.Port)
Expand Down
3 changes: 2 additions & 1 deletion internal/support/scheduler/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,11 @@ func (b *Bootstrap) BootstrapHandler(ctx context.Context, wg *sync.WaitGroup, _
LoadRestRoutes(b.router, dic, b.serviceName)

lc := bootstrapContainer.LoggingClientFrom(dic.Get)
secretProvider := bootstrapContainer.SecretProviderFrom(dic.Get)
configuration := container.ConfigurationFrom(dic.Get)

// V2 Scheduler
schedulerManager := scheduler.NewManager(lc, configuration)
schedulerManager := scheduler.NewManager(lc, configuration, secretProvider)
dic.Update(di.ServiceConstructorMap{
container.SchedulerManagerName: func(get di.Get) interface{} {
return schedulerManager
Expand Down

0 comments on commit 54caeec

Please sign in to comment.