Skip to content

Commit

Permalink
Add tests for missing authentication rule
Browse files Browse the repository at this point in the history
  • Loading branch information
Yevhen Zavhorodnii committed May 29, 2024
1 parent e380cfb commit cf4f39f
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 24 deletions.
51 changes: 27 additions & 24 deletions pkg/security/risks/builtin/missing_authentication_rule.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,36 +47,39 @@ func (r *MissingAuthenticationRule) GenerateRisks(input *types.Model) ([]*types.
continue
}

if technicalAsset.HighestProcessedConfidentiality(input) >= types.Confidential ||
technicalAsset.HighestProcessedIntegrity(input) >= types.Critical ||
technicalAsset.HighestProcessedAvailability(input) >= types.Critical ||
technicalAsset.MultiTenant {
// check each incoming data flow
commLinks := input.IncomingTechnicalCommunicationLinksMappedByTargetId[technicalAsset.Id]
for _, commLink := range commLinks {
caller := input.TechnicalAssets[commLink.SourceId]
if caller.Technologies.GetAttribute(types.IsUnprotectedCommunicationsTolerated) || caller.Type == types.Datastore {
continue
}
highRisk := commLink.HighestConfidentiality(input) == types.StrictlyConfidential ||
commLink.HighestIntegrity(input) == types.MissionCritical
lowRisk := commLink.HighestConfidentiality(input) <= types.Internal &&
commLink.HighestIntegrity(input) == types.Operational
impact := types.MediumImpact
if highRisk {
impact = types.HighImpact
} else if lowRisk {
impact = types.LowImpact
}
if commLink.Authentication == types.NoneAuthentication && !commLink.Protocol.IsProcessLocal() {
risks = append(risks, r.createRisk(input, technicalAsset, commLink, commLink, "", impact, types.Likely, false, r.Category()))
}
if technicalAsset.HighestProcessedConfidentiality(input) < types.Confidential &&
technicalAsset.HighestProcessedIntegrity(input) < types.Critical &&
technicalAsset.HighestProcessedAvailability(input) < types.Critical &&
!technicalAsset.MultiTenant {
continue
}

// check each incoming data flow
commLinks := input.IncomingTechnicalCommunicationLinksMappedByTargetId[technicalAsset.Id]
for _, commLink := range commLinks {
caller := input.TechnicalAssets[commLink.SourceId]
if caller.Technologies.GetAttribute(types.IsUnprotectedCommunicationsTolerated) || caller.Type == types.Datastore {
continue
}
impact := r.calculateImpact(commLink, input)
if commLink.Authentication == types.NoneAuthentication && !commLink.Protocol.IsProcessLocal() {
risks = append(risks, r.createRisk(input, technicalAsset, commLink, commLink, "", impact, types.Likely, false, r.Category()))
}
}
}
return risks, nil
}

func (r *MissingAuthenticationRule) calculateImpact(commLink *types.CommunicationLink, input *types.Model) types.RiskExploitationImpact {
if commLink.HighestConfidentiality(input) == types.StrictlyConfidential || commLink.HighestIntegrity(input) == types.MissionCritical {
return types.HighImpact
}
if commLink.HighestConfidentiality(input) <= types.Internal && commLink.HighestIntegrity(input) == types.Operational {
return types.LowImpact
}
return types.MediumImpact
}

func (r *MissingAuthenticationRule) createRisk(input *types.Model, technicalAsset *types.TechnicalAsset, incomingAccess, incomingAccessOrigin *types.CommunicationLink, hopBetween string,
impact types.RiskExploitationImpact, likelihood types.RiskExploitationLikelihood, twoFactor bool, category *types.RiskCategory) *types.Risk {
factorString := ""
Expand Down
40 changes: 40 additions & 0 deletions pkg/security/risks/builtin/missing_authentication_rule_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -324,3 +324,43 @@ func TestMissingAuthenticationRuleGenerateRisksOperationalIntegrityRisksCreatedW
assert.Equal(t, "<b>Missing Authentication</b> covering communication link <b>User Access via Browser</b> from <b>User Interface</b> to <b>Test Technical Asset</b>", risks[0].Title)
assert.Equal(t, types.LowImpact, risks[0].ExploitationImpact)
}

func TestMissingAuthenticationRuleGenerateRisksProcessingConfidentialDataRisksCreated(t *testing.T) {
rule := NewMissingAuthenticationRule()

risks, err := rule.GenerateRisks(&types.Model{
TechnicalAssets: map[string]*types.TechnicalAsset{
"ta1": {
Id: "ta1",
Title: "Test Technical Asset",
DataAssetsProcessed: []string{"confidential"},
},
"ta2": {
Id: "ta2",
Title: "User Interface",
},
},
IncomingTechnicalCommunicationLinksMappedByTargetId: map[string][]*types.CommunicationLink{
"ta1": {
{
Title: "User Access via Browser",
SourceId: "ta2",
Authentication: types.NoneAuthentication,
Protocol: types.HTTPS,
},
},
},
DataAssets: map[string]*types.DataAsset{
"confidential": {
Id: "confidential",
Title: "Confidential Data",
Confidentiality: types.Confidential,
},
},
})

assert.Nil(t, err)
assert.Len(t, risks, 1)
assert.Equal(t, "<b>Missing Authentication</b> covering communication link <b>User Access via Browser</b> from <b>User Interface</b> to <b>Test Technical Asset</b>", risks[0].Title)
assert.Equal(t, types.MediumImpact, risks[0].ExploitationImpact)
}

0 comments on commit cf4f39f

Please sign in to comment.