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: check if profile is active on a profile reader level #1693

Merged
merged 1 commit into from
Apr 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
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
Loading