Skip to content

Commit

Permalink
feat: check if profile is active on a profile reader level
Browse files Browse the repository at this point in the history
Signed-off-by: Mykhailo Sizov <mykhailo.sizov@securekey.com>
  • Loading branch information
mishasizov-SK committed Apr 8, 2024
1 parent b90afe6 commit 8baac02
Show file tree
Hide file tree
Showing 8 changed files with 50 additions and 110 deletions.
49 changes: 44 additions & 5 deletions component/profile/reader/file/reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"github.com/trustbloc/vcs/internal/logfields"
vcskms "github.com/trustbloc/vcs/pkg/kms"
profileapi "github.com/trustbloc/vcs/pkg/profile"
"github.com/trustbloc/vcs/pkg/restapi/resterr"
)

const (
Expand Down Expand Up @@ -62,7 +63,7 @@ type VerifierReader struct {
verifiers map[string]*profileapi.Verifier
}

type profile struct {
type profileData struct {
IssuersData []*issuerProfile `json:"issuers"`
VerifiersData []*verifierProfile `json:"verifiers"`
}
Expand Down Expand Up @@ -96,7 +97,7 @@ func NewIssuerReader(config *Config) (*IssuerReader, error) {
return nil, err
}

var p profile
var p profileData
if err = json.Unmarshal(jsonBytes, &p); err != nil {
return nil, err
}
Expand Down Expand Up @@ -142,7 +143,26 @@ func NewIssuerReader(config *Config) (*IssuerReader, error) {
// GetProfile returns profile with given id.
func (p *IssuerReader) GetProfile(
profileID profileapi.ID, profileVersion profileapi.Version) (*profileapi.Issuer, error) {
return p.issuers[fmt.Sprintf("%s_%s", profileID, profileVersion)], nil
profile, ok := p.issuers[fmt.Sprintf("%s_%s", profileID, profileVersion)]
if !ok {
return nil, resterr.ErrProfileNotFound
}

if !profile.Active {
return nil, resterr.ErrProfileInactive
}

// Check latest version of given profileID if it is inactive.
latestProfileVersion, ok := p.issuers[fmt.Sprintf("%s_%s", profileID, latest)]
if !ok {
return nil, resterr.ErrProfileNotFound
}

if !latestProfileVersion.Active {
return nil, resterr.ErrProfileInactive
}

return profile, nil
}

// GetAllProfiles returns all profiles with given organization id.
Expand All @@ -167,7 +187,7 @@ func NewVerifierReader(config *Config) (*VerifierReader, error) {
return nil, err
}

var p profile
var p profileData
if err = json.Unmarshal(jsonBytes, &p); err != nil {
return nil, err
}
Expand Down Expand Up @@ -225,7 +245,26 @@ func (p *VerifierReader) setTrustList(
// GetProfile returns profile with given id.
func (p *VerifierReader) GetProfile(
profileID profileapi.ID, profileVersion profileapi.Version) (*profileapi.Verifier, error) {
return p.verifiers[fmt.Sprintf("%s_%s", profileID, profileVersion)], nil
profile, ok := p.verifiers[fmt.Sprintf("%s_%s", profileID, profileVersion)]
if !ok {
return nil, resterr.ErrProfileNotFound
}

if !profile.Active {
return nil, resterr.ErrProfileInactive
}

// Check latest version of given profileID if it is inactive.
latestProfileVersion, ok := p.verifiers[fmt.Sprintf("%s_%s", profileID, latest)]
if !ok {
return nil, resterr.ErrProfileNotFound
}

if !latestProfileVersion.Active {
return nil, resterr.ErrProfileInactive
}

return profile, nil
}

// GetAllProfiles returns all profiles with given organization id.
Expand Down
8 changes: 5 additions & 3 deletions component/profile/reader/file/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import (
"github.com/hashicorp/go-version"
)

const latest = "latest"

type profileVersionKey string

func getProfileVersionKey(profileID string, profileVersion *version.Version) profileVersionKey {
Expand All @@ -31,10 +33,10 @@ func populateLatestTag[Profile any](
latestVersion := versions[len(versions)-1]
latestMajorVersion := latestVersion.Segments()[0]
// Set latest tag.
store[fmt.Sprintf("%s_latest", profileID)] =
store[fmt.Sprintf("%s_%s", profileID, latest)] =
profileData[getProfileVersionKey(profileID, latestVersion)]
// Set v<MAJOR>.latest tag for the latest version.
store[fmt.Sprintf("%s_v%d.latest", profileID, latestMajorVersion)] =
store[fmt.Sprintf("%s_v%d.%s", profileID, latestMajorVersion, latest)] =
profileData[getProfileVersionKey(profileID, latestVersion)]

for i := versions.Len() - 1; i >= 0; i-- {
Expand All @@ -45,7 +47,7 @@ func populateLatestTag[Profile any](
latestMajorVersion = currentMajorVersion

// Set v<MAJOR>.latest tag points to the most recent version of the current <MAJOR> version number.
store[fmt.Sprintf("%s_v%d.latest", profileID, currentMajorVersion)] =
store[fmt.Sprintf("%s_v%d.%s", profileID, currentMajorVersion, latest)] =
profileData[getProfileVersionKey(profileID, currentVersion)]
}
}
Expand Down
1 change: 1 addition & 0 deletions pkg/restapi/resterr/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ var (
ErrDataNotFound = NewCustomError(DataNotFound, errors.New("data not found"))
ErrOpStateKeyDuplication = NewCustomError(OpStateKeyDuplication, errors.New("op state key duplication"))
ErrProfileInactive = NewCustomError(ProfileInactive, errors.New("profile not active"))
ErrProfileNotFound = NewCustomError(ProfileNotFound, errors.New("profile doesn't exist"))
ErrCredentialTemplateNotFound = NewCustomError(CredentialTemplateNotFound, errors.New("credential template not found")) //nolint:lll
ErrCredentialTemplateNotConfigured = NewCustomError(CredentialTemplateNotConfigured, errors.New("credential template not configured")) //nolint:lll
ErrCredentialTemplateIDRequired = NewCustomError(CredentialTemplateIDRequired, errors.New("credential template ID is required")) //nolint:lll
Expand Down
4 changes: 0 additions & 4 deletions pkg/restapi/v1/verifier/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -340,10 +340,6 @@ func (c *Controller) initiateOidcInteraction(
data *InitiateOIDC4VPData,
profile *profileapi.Verifier,
) (*InitiateOIDC4VPResponse, error) {
if !profile.Active {
return nil, resterr.ErrProfileInactive
}

if profile.OIDCConfig == nil {
return nil, resterr.NewValidationError(resterr.ConditionNotMet, "profile.OIDCConfig",
errors.New("OIDC not configured"))
Expand Down
18 changes: 0 additions & 18 deletions pkg/restapi/v1/verifier/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2077,24 +2077,6 @@ func TestController_initiateOidcInteraction(t *testing.T) {
"invalid-value[presentationDefinitionID]: presentation definition id= not found for profile with id=profile-id")
})

t.Run("Should be active", func(t *testing.T) {
controller := NewController(&Config{
ProfileSvc: mockProfileSvc,
KMSRegistry: kmsRegistry,
OIDCVPService: oidc4VPSvc,
})

_, err := controller.initiateOidcInteraction(context.TODO(), &InitiateOIDC4VPData{},
&profileapi.Verifier{
OrganizationID: tenantID,
Active: false,
OIDCConfig: &profileapi.OIDC4VPConfig{},
SigningDID: &profileapi.SigningDID{},
})

requireCustomError(t, resterr.ProfileInactive, err)
})

t.Run("Error - With Presentation Definition and PD filters", func(t *testing.T) {
controller := NewController(&Config{
ProfileSvc: mockProfileSvc,
Expand Down
4 changes: 0 additions & 4 deletions pkg/service/oidc4ci/oidc4ci_service_initiate_issuance.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,6 @@ func (s *Service) InitiateIssuance( // nolint:funlen,gocyclo,gocognit
req.OpState = uuid.NewString()
}

if !profile.Active {
return nil, resterr.ErrProfileInactive
}

if profile.VCConfig == nil {
return nil, resterr.ErrVCOptionsNotConfigured
}
Expand Down
25 changes: 0 additions & 25 deletions pkg/service/oidc4ci/oidc4ci_service_initiate_issuance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1200,31 +1200,6 @@ func TestService_InitiateIssuance(t *testing.T) {
require.Nil(t, resp)
},
},
{
name: "Profile is not active",
setup: func(mocks *mocks) {
issuanceReq = &oidc4ci.InitiateIssuanceRequest{
ClientInitiateIssuanceURL: "https://wallet.example.com/initiate_issuance",
OpState: "eyJhbGciOiJSU0Et",
CredentialConfiguration: []oidc4ci.InitiateIssuanceCredentialConfiguration{
{
ClaimEndpoint: "https://vcs.pb.example.com/claim",
CredentialTemplateID: "templateID",
},
},
}

profile = &profileapi.Issuer{
Active: false,
OIDCConfig: &profileapi.OIDCConfig{},
VCConfig: &profileapi.VCConfig{},
}
},
check: func(t *testing.T, resp *oidc4ci.InitiateIssuanceResponse, err error) {
require.Nil(t, resp)
require.ErrorIs(t, err, resterr.ErrProfileInactive)
},
},
{
name: "VC options not configured",
setup: func(mocks *mocks) {
Expand Down
51 changes: 0 additions & 51 deletions pkg/service/oidc4ci/oidc4ci_service_store_auth_code_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,57 +166,6 @@ func TestInitiateWalletFlowFromStoreCode(t *testing.T) {
assert.ErrorContains(t, err, "issuer not found")
})

t.Run("error init", func(t *testing.T) {
store := NewMockTransactionStore(gomock.NewController(t))
eventMock := NewMockEventService(gomock.NewController(t))
profileSvc := NewMockProfileService(gomock.NewController(t))
wellKnown := NewMockWellKnownService(gomock.NewController(t))

srv, err := oidc4ci.NewService(&oidc4ci.Config{
TransactionStore: store,
EventService: eventMock,
EventTopic: spi.IssuerEventTopic,
ProfileService: profileSvc,
WellKnownService: wellKnown,
})
assert.NoError(t, err)

profileSvc.EXPECT().GetProfile(profileapi.ID("bank_issuer1"), "v111.0").
Return(&profileapi.Issuer{
CredentialTemplates: []*profileapi.CredentialTemplate{
{
ID: "some-template",
},
},
Active: false,
VCConfig: &profileapi.VCConfig{},
SigningDID: &profileapi.SigningDID{},
OIDCConfig: &profileapi.OIDCConfig{
WalletInitiatedAuthFlowSupported: true,
IssuerWellKnownURL: "https://awesome.local",
ClaimsEndpoint: "https://awesome.claims.local",
GrantTypesSupported: []string{
"authorization_code",
},
ScopesSupported: []string{
"scope1",
"scope2",
"scope3",
},
},
}, nil)

resp, err := srv.StoreAuthorizationCode(context.TODO(), "random-op-state", "code123",
&common.WalletInitiatedFlowData{
OpState: "random-op-state",
ProfileId: "bank_issuer1",
ProfileVersion: "v111.0",
},
)
assert.Empty(t, resp)
assert.ErrorContains(t, err,
"can not initiate issuance for wallet-initiated flow: profile-inactive")
})
t.Run("success", func(t *testing.T) {
store := NewMockTransactionStore(gomock.NewController(t))
eventMock := NewMockEventService(gomock.NewController(t))
Expand Down

0 comments on commit 8baac02

Please sign in to comment.