mirror of
https://github.com/gocsaf/csaf.git
synced 2025-12-22 11:55:40 +01:00
Fixed handling of unauthorited HTTP client, too.
This commit is contained in:
parent
d8ad56956d
commit
a95ff9faf0
2 changed files with 108 additions and 78 deletions
|
|
@ -40,10 +40,11 @@ import (
|
||||||
type topicMessages []Message
|
type topicMessages []Message
|
||||||
|
|
||||||
type processor struct {
|
type processor struct {
|
||||||
opts *options
|
opts *options
|
||||||
validator csaf.RemoteValidator
|
validator csaf.RemoteValidator
|
||||||
client util.Client
|
client util.Client
|
||||||
ageAccept func(time.Time) bool
|
unauthClient util.Client
|
||||||
|
ageAccept func(time.Time) bool
|
||||||
|
|
||||||
redirects map[string][]string
|
redirects map[string][]string
|
||||||
noneTLS util.Set[string]
|
noneTLS util.Set[string]
|
||||||
|
|
@ -462,15 +463,27 @@ func (p *processor) basicClient() *http.Client {
|
||||||
// httpClient returns a cached HTTP client to be used to
|
// httpClient returns a cached HTTP client to be used to
|
||||||
// download remote ressources.
|
// download remote ressources.
|
||||||
func (p *processor) httpClient() util.Client {
|
func (p *processor) httpClient() util.Client {
|
||||||
|
if p.client == nil {
|
||||||
if p.client != nil {
|
p.client = p.fullClient()
|
||||||
return p.client
|
|
||||||
}
|
}
|
||||||
|
|
||||||
p.client = p.fullClient()
|
|
||||||
return p.client
|
return p.client
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// unauthorizedClient returns a cached HTTP client without
|
||||||
|
// authentification.
|
||||||
|
func (p *processor) unauthorizedClient() util.Client {
|
||||||
|
if p.unauthClient == nil {
|
||||||
|
p.unauthClient = p.basicClient()
|
||||||
|
}
|
||||||
|
return p.unauthClient
|
||||||
|
}
|
||||||
|
|
||||||
|
// usedAuthorizedClient tells if an authorized client is used
|
||||||
|
// for downloading.
|
||||||
|
func (p *processor) usedAuthorizedClient() bool {
|
||||||
|
return p.opts.protectedAccess()
|
||||||
|
}
|
||||||
|
|
||||||
// rolieFeedEntries loads the references to the advisory files for a given feed.
|
// rolieFeedEntries loads the references to the advisory files for a given feed.
|
||||||
func (p *processor) rolieFeedEntries(feed string) ([]csaf.AdvisoryFile, error) {
|
func (p *processor) rolieFeedEntries(feed string) ([]csaf.AdvisoryFile, error) {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,6 @@ type rolieLabelChecker struct {
|
||||||
feedLabel csaf.TLPLabel
|
feedLabel csaf.TLPLabel
|
||||||
|
|
||||||
advisories map[csaf.TLPLabel]util.Set[string]
|
advisories map[csaf.TLPLabel]util.Set[string]
|
||||||
openClient util.Client
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// tlpLevel returns an inclusion order of TLP colors.
|
// tlpLevel returns an inclusion order of TLP colors.
|
||||||
|
|
@ -53,39 +52,103 @@ func tlpLabel(label *csaf.TLPLabel) csaf.TLPLabel {
|
||||||
return csaf.TLPLabelUnlabeled
|
return csaf.TLPLabelUnlabeled
|
||||||
}
|
}
|
||||||
|
|
||||||
// check tests if in advisory is in the right TLP color of the
|
// add registers a given url to a label.
|
||||||
// currently tested feed.
|
func (ca *rolieLabelChecker) add(label csaf.TLPLabel, url string) {
|
||||||
func (ca *rolieLabelChecker) check(
|
advs := ca.advisories[label]
|
||||||
p *processor,
|
|
||||||
advisoryLabel csaf.TLPLabel,
|
|
||||||
advisory string,
|
|
||||||
) {
|
|
||||||
// Assign int to tlp levels for easy comparison
|
|
||||||
var (
|
|
||||||
advisoryRank = tlpLevel(advisoryLabel)
|
|
||||||
feedRank = tlpLevel(ca.feedLabel)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Associate advisory label to urls.
|
|
||||||
advs := ca.advisories[advisoryLabel]
|
|
||||||
if advs == nil {
|
if advs == nil {
|
||||||
advs = util.Set[string]{}
|
advs = util.Set[string]{}
|
||||||
ca.advisories[advisoryLabel] = advs
|
ca.advisories[label] = advs
|
||||||
}
|
}
|
||||||
advs.Add(advisory)
|
advs.Add(url)
|
||||||
|
}
|
||||||
|
|
||||||
// If entry shows up in feed of higher tlp level,
|
// check tests if the TLP label of an advisory is used correctly.
|
||||||
// give out info or warning
|
func (ca *rolieLabelChecker) check(
|
||||||
|
p *processor,
|
||||||
|
label csaf.TLPLabel,
|
||||||
|
url string,
|
||||||
|
) {
|
||||||
|
// Associate advisory label to urls.
|
||||||
|
ca.add(label, url)
|
||||||
|
|
||||||
|
// If entry shows up in feed of higher tlp level, give out info or warning.
|
||||||
|
ca.checkRank(p, label, url)
|
||||||
|
|
||||||
|
// Issue warnings or errors if the advisory is not protected properly.
|
||||||
|
ca.checkProtection(p, label, url)
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkProtection tests if a given advisory has the right level
|
||||||
|
// of protection.
|
||||||
|
func (ca *rolieLabelChecker) checkProtection(
|
||||||
|
p *processor,
|
||||||
|
label csaf.TLPLabel,
|
||||||
|
url string,
|
||||||
|
) {
|
||||||
switch {
|
switch {
|
||||||
|
// If we are checking WHITE and we have a test client
|
||||||
|
// and we get a status forbidden then the access is not open.
|
||||||
|
case label == csaf.TLPLabelWhite:
|
||||||
|
p.badWhitePermissions.use()
|
||||||
|
// We only need to download it with an unauthorized client
|
||||||
|
// if have not done it yet.
|
||||||
|
if p.usedAuthorizedClient() {
|
||||||
|
res, err := p.unauthorizedClient().Get(url)
|
||||||
|
if err != nil {
|
||||||
|
p.badWhitePermissions.error(
|
||||||
|
"Unexpected Error %v when trying to fetch: %s", err, url)
|
||||||
|
} else if res.StatusCode == http.StatusForbidden {
|
||||||
|
p.badWhitePermissions.error(
|
||||||
|
"Advisory %s of TLP level WHITE is access protected.", url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we are checking AMBER or above we need to download
|
||||||
|
// the data again with the open client.
|
||||||
|
// If this does not result in status forbidden the
|
||||||
|
// server may be wrongly configured.
|
||||||
|
case label >= csaf.TLPLabelAmber:
|
||||||
|
p.badAmberRedPermissions.use()
|
||||||
|
// It is an error if we downloaded the advisory with
|
||||||
|
// an unauthorized client.
|
||||||
|
if !p.usedAuthorizedClient() {
|
||||||
|
p.badAmberRedPermissions.error(
|
||||||
|
"Advisory %s of TLP level %v is not properly access protected.",
|
||||||
|
url, label)
|
||||||
|
} else {
|
||||||
|
// We came here by an authorized download which is okay.
|
||||||
|
// So its bad if we can download it with an unauthorized client, too.
|
||||||
|
res, err := p.unauthorizedClient().Get(url)
|
||||||
|
if err != nil {
|
||||||
|
p.badAmberRedPermissions.error(
|
||||||
|
"Unexpected Error %v when trying to fetch: %s", err, url)
|
||||||
|
} else if res.StatusCode == http.StatusOK {
|
||||||
|
p.badAmberRedPermissions.error(
|
||||||
|
"Advisory %s of TLP level %v is not properly access protected.",
|
||||||
|
url, label)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkRank tests if a given advisory is contained by the
|
||||||
|
// the right feed color.
|
||||||
|
func (ca *rolieLabelChecker) checkRank(
|
||||||
|
p *processor,
|
||||||
|
label csaf.TLPLabel,
|
||||||
|
url string,
|
||||||
|
) {
|
||||||
|
switch advisoryRank, feedRank := tlpLevel(label), tlpLevel(ca.feedLabel); {
|
||||||
|
|
||||||
case advisoryRank < feedRank:
|
case advisoryRank < feedRank:
|
||||||
if advisoryRank == 0 { // All kinds of 'UNLABELED'
|
if advisoryRank == 0 { // All kinds of 'UNLABELED'
|
||||||
p.badROLIEFeed.info(
|
p.badROLIEFeed.info(
|
||||||
"Found unlabeled advisory %q in feed %q.",
|
"Found unlabeled advisory %q in feed %q.",
|
||||||
advisory, ca.feedURL)
|
url, ca.feedURL)
|
||||||
} else {
|
} else {
|
||||||
p.badROLIEFeed.warn(
|
p.badROLIEFeed.warn(
|
||||||
"Found advisory %q labled TLP:%s in feed %q (TLP:%s).",
|
"Found advisory %q labled TLP:%s in feed %q (TLP:%s).",
|
||||||
advisory, advisoryLabel,
|
url, label,
|
||||||
ca.feedURL, ca.feedLabel)
|
ca.feedURL, ca.feedLabel)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -93,43 +156,7 @@ func (ca *rolieLabelChecker) check(
|
||||||
// Must not happen, give error
|
// Must not happen, give error
|
||||||
p.badROLIEFeed.error(
|
p.badROLIEFeed.error(
|
||||||
"%s of TLP level %s must not be listed in feed %s of TLP level %s",
|
"%s of TLP level %s must not be listed in feed %s of TLP level %s",
|
||||||
advisory, advisoryLabel, ca.feedURL, ca.feedLabel)
|
url, label, ca.feedURL, ca.feedLabel)
|
||||||
}
|
|
||||||
|
|
||||||
// If we have an open client then the actual data was downloaded
|
|
||||||
// through an authorizing client.
|
|
||||||
if ca.openClient != nil {
|
|
||||||
switch {
|
|
||||||
// If we are checking WHITE and we have a test client
|
|
||||||
// and we get a status forbidden then the access is not open.
|
|
||||||
case advisoryLabel == csaf.TLPLabelWhite:
|
|
||||||
p.badWhitePermissions.use()
|
|
||||||
res, err := ca.openClient.Get(advisory)
|
|
||||||
if err != nil {
|
|
||||||
p.badWhitePermissions.error(
|
|
||||||
"Unexpected Error %v when trying to fetch: %s", err, advisory)
|
|
||||||
} else if res.StatusCode == http.StatusForbidden {
|
|
||||||
p.badWhitePermissions.error(
|
|
||||||
"Advisory %s of TLP level WHITE is access protected.", advisory)
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we are checking AMBER or above we need to download
|
|
||||||
// the data again with the open client.
|
|
||||||
// If this does not result in status forbidden the
|
|
||||||
// server may be wrongly configured.
|
|
||||||
case advisoryLabel >= csaf.TLPLabelAmber:
|
|
||||||
p.badAmberRedPermissions.use()
|
|
||||||
res, err := ca.openClient.Get(advisory)
|
|
||||||
if err != nil {
|
|
||||||
p.badAmberRedPermissions.error(
|
|
||||||
"Unexpected Error %v when trying to fetch: %s", err, advisory)
|
|
||||||
} else if res.StatusCode == http.StatusOK {
|
|
||||||
p.badAmberRedPermissions.error(
|
|
||||||
"Advisory %s of TLP level %v is not properly access protected.",
|
|
||||||
advisory, advisoryLabel)
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -211,16 +238,6 @@ func (p *processor) processROLIEFeeds(feeds [][]csaf.Feed) error {
|
||||||
p.labelChecker.feedURL = feedURL.String()
|
p.labelChecker.feedURL = feedURL.String()
|
||||||
p.labelChecker.feedLabel = label
|
p.labelChecker.feedLabel = label
|
||||||
|
|
||||||
// If we are using an authorizing client
|
|
||||||
// we need an open client to check
|
|
||||||
// WHITE, AMBER and RED feeds.
|
|
||||||
var openClient util.Client
|
|
||||||
if (label == csaf.TLPLabelWhite || label >= csaf.TLPLabelAmber) &&
|
|
||||||
p.opts.protectedAccess() {
|
|
||||||
openClient = p.basicClient()
|
|
||||||
}
|
|
||||||
p.labelChecker.openClient = openClient
|
|
||||||
|
|
||||||
// TODO: Issue a warning if we want check AMBER+ without an
|
// TODO: Issue a warning if we want check AMBER+ without an
|
||||||
// authorizing client.
|
// authorizing client.
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue