Skip to content

Commit a17a865

Browse files
authored
Merge pull request #964 from lindseysimple/issue-963
feat: Add model/DTOs and HTTP client for security-proxy-auth
2 parents 3954224 + 8d9ce4b commit a17a865

File tree

12 files changed

+495
-0
lines changed

12 files changed

+495
-0
lines changed

clients/http/auth.go

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
//
2+
// Copyright (C) 2024 IOTech Ltd
3+
//
4+
// SPDX-License-Identifier: Apache-2.0
5+
6+
package http
7+
8+
import (
9+
"context"
10+
11+
"github.com/edgexfoundry/go-mod-core-contracts/v4/clients/http/utils"
12+
"github.com/edgexfoundry/go-mod-core-contracts/v4/clients/interfaces"
13+
"github.com/edgexfoundry/go-mod-core-contracts/v4/common"
14+
dtoCommon "github.com/edgexfoundry/go-mod-core-contracts/v4/dtos/common"
15+
"github.com/edgexfoundry/go-mod-core-contracts/v4/dtos/requests"
16+
"github.com/edgexfoundry/go-mod-core-contracts/v4/dtos/responses"
17+
"github.com/edgexfoundry/go-mod-core-contracts/v4/errors"
18+
)
19+
20+
type AuthClient struct {
21+
baseUrl string
22+
authInjector interfaces.AuthenticationInjector
23+
}
24+
25+
// NewAuthClient creates an instance of AuthClient
26+
func NewAuthClient(baseUrl string, authInjector interfaces.AuthenticationInjector) interfaces.AuthClient {
27+
return &AuthClient{
28+
baseUrl: baseUrl,
29+
authInjector: authInjector,
30+
}
31+
}
32+
33+
// AddKey adds new key
34+
func (ac *AuthClient) AddKey(ctx context.Context, req requests.AddKeyDataRequest) (dtoCommon.BaseResponse, errors.EdgeX) {
35+
var response dtoCommon.BaseResponse
36+
err := utils.PostRequestWithRawData(ctx, &response, ac.baseUrl, common.ApiKeyRoute, nil, req, ac.authInjector)
37+
if err != nil {
38+
return response, errors.NewCommonEdgeXWrapper(err)
39+
}
40+
return response, nil
41+
}
42+
43+
func (ac *AuthClient) VerificationKeyByIssuer(ctx context.Context, issuer string) (res responses.KeyDataResponse, err errors.EdgeX) {
44+
path := common.NewPathBuilder().SetPath(common.ApiKeyRoute).SetPath(common.VerificationKeyType).SetPath(common.Issuer).SetNameFieldPath(issuer).BuildPath()
45+
err = utils.GetRequest(ctx, &res, ac.baseUrl, path, nil, ac.authInjector)
46+
if err != nil {
47+
return res, errors.NewCommonEdgeXWrapper(err)
48+
}
49+
return res, nil
50+
}

clients/http/auth_test.go

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//
2+
// Copyright (C) 2024 IOTech Ltd
3+
//
4+
// SPDX-License-Identifier: Apache-2.0
5+
6+
package http
7+
8+
import (
9+
"context"
10+
"net/http"
11+
"testing"
12+
13+
"github.com/edgexfoundry/go-mod-core-contracts/v4/common"
14+
dtoCommon "github.com/edgexfoundry/go-mod-core-contracts/v4/dtos/common"
15+
"github.com/edgexfoundry/go-mod-core-contracts/v4/dtos/requests"
16+
"github.com/edgexfoundry/go-mod-core-contracts/v4/dtos/responses"
17+
18+
"github.com/stretchr/testify/require"
19+
)
20+
21+
func TestAddKey(t *testing.T) {
22+
ts := newTestServer(http.MethodPost, common.ApiKeyRoute, dtoCommon.BaseResponse{})
23+
defer ts.Close()
24+
25+
client := NewAuthClient(ts.URL, NewNullAuthenticationInjector())
26+
res, err := client.AddKey(context.Background(), requests.AddKeyDataRequest{})
27+
require.NoError(t, err)
28+
require.IsType(t, dtoCommon.BaseResponse{}, res)
29+
}
30+
31+
func TestVerificationKeyByIssuer(t *testing.T) {
32+
mockIssuer := "mockIssuer"
33+
34+
path := common.NewPathBuilder().EnableNameFieldEscape(false).
35+
SetPath(common.ApiKeyRoute).SetPath(common.VerificationKeyType).SetPath(common.Issuer).SetNameFieldPath(mockIssuer).BuildPath()
36+
ts := newTestServer(http.MethodGet, path, responses.KeyDataResponse{})
37+
defer ts.Close()
38+
39+
client := NewAuthClient(ts.URL, NewNullAuthenticationInjector())
40+
res, err := client.VerificationKeyByIssuer(context.Background(), mockIssuer)
41+
require.NoError(t, err)
42+
require.IsType(t, responses.KeyDataResponse{}, res)
43+
}

clients/interfaces/auth.go

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//
2+
// Copyright (C) 2024 IOTech Ltd
3+
//
4+
// SPDX-License-Identifier: Apache-2.0
5+
6+
package interfaces
7+
8+
import (
9+
"context"
10+
11+
"github.com/edgexfoundry/go-mod-core-contracts/v4/dtos/common"
12+
"github.com/edgexfoundry/go-mod-core-contracts/v4/dtos/requests"
13+
"github.com/edgexfoundry/go-mod-core-contracts/v4/dtos/responses"
14+
"github.com/edgexfoundry/go-mod-core-contracts/v4/errors"
15+
)
16+
17+
// AuthClient defines the interface for interactions with the auth API endpoint on the security-proxy-auth service.
18+
type AuthClient interface {
19+
// AddKey adds the JWT signing or verification key
20+
AddKey(ctx context.Context, req requests.AddKeyDataRequest) (common.BaseResponse, errors.EdgeX)
21+
// VerificationKeyByIssuer returns the JWT verification key by the specified issuer
22+
VerificationKeyByIssuer(ctx context.Context, issuer string) (res responses.KeyDataResponse, err errors.EdgeX)
23+
}

clients/interfaces/mocks/AuthClient.go

+96
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

common/constants.go

+10
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,9 @@ const (
132132
ApiAllRegistrationsRoute = ApiRegisterRoute + "/" + All
133133
ApiKVSByKeyRoute = ApiKVSRoute + "/" + Key + "/:" + Key
134134
ApiRegistrationByServiceIdRoute = ApiRegisterRoute + "/" + ServiceId + "/:" + ServiceId
135+
136+
ApiKeyRoute = ApiBase + "/key"
137+
ApiVerificationKeyByIssuerRoute = ApiKeyRoute + "/" + VerificationKeyType + "/" + Issuer + "/:" + Issuer
135138
)
136139

137140
// Constants related to defined url path names and parameters in the v3 service APIs
@@ -394,3 +397,10 @@ const (
394397
// App Service Topics
395398
// App Service topics remain configurable inorder to filter by subscription.
396399
)
400+
401+
// Constants related to the security-proxy-auth service
402+
const (
403+
VerificationKeyType = "verification"
404+
SigningKeyType = "signing"
405+
Issuer = "issuer"
406+
)

dtos/keydata.go

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//
2+
// Copyright (C) 2024 IOTech Ltd
3+
//
4+
// SPDX-License-Identifier: Apache-2.0
5+
6+
package dtos
7+
8+
import (
9+
"strings"
10+
11+
"github.com/edgexfoundry/go-mod-core-contracts/v4/models"
12+
)
13+
14+
type KeyData struct {
15+
Issuer string `json:"issuer" validate:"required"`
16+
Type string `json:"type" validate:"omitempty,oneof=verification signing"`
17+
Key string `json:"key" validate:"required"`
18+
}
19+
20+
// ToKeyDataModel transforms the KeyData DTO to the KeyData Model
21+
func ToKeyDataModel(keyData KeyData) models.KeyData {
22+
return models.KeyData{
23+
Issuer: keyData.Issuer,
24+
Type: strings.ToLower(keyData.Type),
25+
Key: keyData.Key,
26+
}
27+
}

dtos/keydata_test.go

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//
2+
// Copyright (C) 2024 IOTech Ltd
3+
//
4+
// SPDX-License-Identifier: Apache-2.0
5+
6+
package dtos
7+
8+
import (
9+
"testing"
10+
11+
"github.com/edgexfoundry/go-mod-core-contracts/v4/models"
12+
13+
"github.com/stretchr/testify/require"
14+
)
15+
16+
func TestToKeyDataModel(t *testing.T) {
17+
mockIssuer := "mockIssuer"
18+
mockType := "verification"
19+
mockKey := "mockKey"
20+
mockKeyDataDTO := KeyData{
21+
Issuer: mockIssuer,
22+
Type: mockType,
23+
Key: mockKey,
24+
}
25+
mockModel := models.KeyData{
26+
Issuer: mockIssuer,
27+
Type: mockType,
28+
Key: mockKey,
29+
}
30+
31+
model := ToKeyDataModel(mockKeyDataDTO)
32+
require.Equal(t, mockModel, model)
33+
}

dtos/requests/keydata.go

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
//
2+
// Copyright (C) 2024 IOTech Ltd
3+
//
4+
// SPDX-License-Identifier: Apache-2.0
5+
6+
package requests
7+
8+
import (
9+
"encoding/json"
10+
11+
"github.com/edgexfoundry/go-mod-core-contracts/v4/common"
12+
"github.com/edgexfoundry/go-mod-core-contracts/v4/dtos"
13+
dtoCommon "github.com/edgexfoundry/go-mod-core-contracts/v4/dtos/common"
14+
"github.com/edgexfoundry/go-mod-core-contracts/v4/errors"
15+
)
16+
17+
// AddKeyDataRequest defines the Request Content for POST Key DTO.
18+
type AddKeyDataRequest struct {
19+
dtoCommon.BaseRequest `json:",inline"`
20+
KeyData dtos.KeyData `json:"keyData"`
21+
}
22+
23+
// Validate satisfies the Validator interface
24+
func (a *AddKeyDataRequest) Validate() error {
25+
err := common.Validate(a)
26+
return err
27+
}
28+
29+
// UnmarshalJSON implements the Unmarshaler interface for the AddUserRequest type
30+
func (a *AddKeyDataRequest) UnmarshalJSON(b []byte) error {
31+
var alias struct {
32+
dtoCommon.BaseRequest
33+
KeyData dtos.KeyData
34+
}
35+
if err := json.Unmarshal(b, &alias); err != nil {
36+
return errors.NewCommonEdgeX(errors.KindContractInvalid, "Failed to unmarshal request body as JSON.", err)
37+
}
38+
39+
*a = AddKeyDataRequest(alias)
40+
if err := a.Validate(); err != nil {
41+
return err
42+
}
43+
return nil
44+
}

0 commit comments

Comments
 (0)