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

Dmm/add query to protocol report #11339

Merged
merged 4 commits into from
Oct 12, 2024
Merged
Show file tree
Hide file tree
Changes from 3 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
307 changes: 172 additions & 135 deletions lib/reporting/protocols_report.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ def as_tables
protocols_table,
saml_signature_issues_table,
deprecated_parameters_table,
feature_use_table,
]
end

Expand Down Expand Up @@ -84,110 +85,6 @@ def to_csvs
end
end

def protocol_data
@protocol_data ||= begin
results = cloudwatch_client.fetch(
query: protocol_query,
from: time_range.begin,
to: time_range.end,
)
{
saml: {
request_count: results.
select { |slice| slice['protocol'] == SAML_AUTH_EVENT }.
map { |slice| slice['request_count'].to_i }.
sum,
issuer_count: results.
select { |slice| slice['protocol'] == SAML_AUTH_EVENT }.
map { |slice| slice['issuer'] }.
uniq.
count,
},
oidc: {
request_count: results.
select { |slice| slice['protocol'] == OIDC_AUTH_EVENT }.
map { |slice| slice['request_count'].to_i }.
sum,
issuer_count: results.
select { |slice| slice['protocol'] == OIDC_AUTH_EVENT }.
map { |slice| slice['issuer'] }.
uniq.
count,
},
}
end
end

def saml_signature_data
@saml_signature_data ||= begin
results = cloudwatch_client.fetch(
query: saml_signature_query,
from: time_range.begin,
to: time_range.end,
)
{
unsigned: results.
select { |slice| slice['unsigned_count'].to_i > 0 }.
map { |slice| slice['issuer'] }.
uniq,
invalid_signature: results.
select { |slice| slice['invalid_signature_count'].to_i > 0 }.
map { |slice| slice['issuer'] }.
uniq,
}
end
end

def protocol_query
params = {
event: quote([SAML_AUTH_EVENT, OIDC_AUTH_EVENT]),
}

format(<<~QUERY, params)
fields
name AS protocol,
coalesce(properties.event_properties.service_provider, properties.event_properties.client_id) as issuer
| filter name IN %{event} AND properties.event_properties.success= 1
| stats
count(*) AS request_count
BY
protocol, issuer
QUERY
end

def saml_signature_query
params = {
event: quote([SAML_AUTH_EVENT]),
}

format(<<~QUERY, params)
fields
properties.event_properties.service_provider AS issuer,
properties.event_properties.request_signed = 1 AS signed,
properties.event_properties.request_signed != 1 AS not_signed,
isempty(properties.event_properties.matching_cert_serial) AND signed AS invalid_signature
| filter name IN %{event}
AND properties.event_properties.success = 1
| stats
sum(not_signed) AS unsigned_count,
sum(invalid_signature) AS invalid_signature_count
BY
issuer
| sort
issuer
QUERY
end

def cloudwatch_client
@cloudwatch_client ||= Reporting::CloudwatchClient.new(
num_threads: @threads,
ensure_complete_logs: false,
slice_interval: @slice,
progress: progress?,
logger: verbose? ? Logger.new(STDERR) : nil,
)
end

def overview_table
[
['Report Timeframe', "#{time_range.begin} to #{time_range.end}"],
Expand All @@ -196,22 +93,6 @@ def overview_table
]
end

def saml_count
protocol_data[:saml][:request_count]
end

def oidc_count
protocol_data[:oidc][:request_count]
end

def saml_issuer_count
protocol_data[:saml][:issuer_count]
end

def oidc_issuer_count
protocol_data[:oidc][:issuer_count]
end

def protocols_table
[
['Authentication Protocol', '% of requests', 'Total requests', 'Count of issuers'],
Expand All @@ -232,7 +113,7 @@ def protocols_table

def saml_signature_issues_table
[
['Issue', 'Count of issuers with the issue', 'List of issuers with the issue'],
['Issue', 'Count of issuers', 'List of issuers'],
[
'Not signing SAML authentication requests',
saml_signature_data[:unsigned].length,
Expand All @@ -250,8 +131,8 @@ def deprecated_parameters_table
[
[
'Deprecated Parameter',
'Count of issuers using the parameter',
'List of issuers using the parameter',
'Count of issuers',
'List of issuers',
],
[
'LOA',
Expand All @@ -266,6 +147,37 @@ def deprecated_parameters_table
]
end

def feature_use_table
[
[
'Feature',
'Count of issuers',
'List of issuers',
],
[
'IdV with Facial Match',
facial_match_data.length,
facial_match_data.join(', '),
],
]
end

def saml_count
protocol_data[:saml][:request_count]
end

def oidc_count
protocol_data[:oidc][:request_count]
end

def saml_issuer_count
protocol_data[:saml][:issuer_count]
end

def oidc_issuer_count
protocol_data[:oidc][:issuer_count]
end

def loa_issuers_data
@loa_issuers_data ||= cloudwatch_client.fetch(
query: loa_issuers_query,
Expand All @@ -276,7 +188,81 @@ def loa_issuers_data
uniq
end

def loa_issuers_query
def aal3_issuers_data
@aal3_issuers_data ||= cloudwatch_client.fetch(
query: aal3_issuers_query,
from: time_range.begin,
to: time_range.end,
).
map { |slice| slice['issuer'] }.
uniq
end

def facial_match_data
@facial_match_data ||= cloudwatch_client.fetch(
query: facial_match_issuers_query,
from: time_range.begin,
to: time_range.end,
).
map { |slice| slice['issuer'] }.
uniq
end

def protocol_data
@protocol_data ||= begin
results = cloudwatch_client.fetch(
query: protocol_query,
from: time_range.begin,
to: time_range.end,
)
{
saml: {
request_count: results.
select { |slice| slice['protocol'] == SAML_AUTH_EVENT }.
map { |slice| slice['request_count'].to_i }.
sum,
issuer_count: results.
select { |slice| slice['protocol'] == SAML_AUTH_EVENT }.
map { |slice| slice['issuer'] }.
uniq.
count,
},
oidc: {
request_count: results.
select { |slice| slice['protocol'] == OIDC_AUTH_EVENT }.
map { |slice| slice['request_count'].to_i }.
sum,
issuer_count: results.
select { |slice| slice['protocol'] == OIDC_AUTH_EVENT }.
map { |slice| slice['issuer'] }.
uniq.
count,
},
}
end
end

def saml_signature_data
@saml_signature_data ||= begin
results = cloudwatch_client.fetch(
query: saml_signature_query,
from: time_range.begin,
to: time_range.end,
)
{
unsigned: results.
select { |slice| slice['unsigned_count'].to_i > 0 }.
map { |slice| slice['issuer'] }.
uniq,
invalid_signature: results.
select { |slice| slice['invalid_signature_count'].to_i > 0 }.
map { |slice| slice['issuer'] }.
uniq,
}
end
end

def aal3_issuers_query
params = {
event: quote([SAML_AUTH_EVENT, OIDC_AUTH_EVENT]),
}
Expand All @@ -288,25 +274,26 @@ def loa_issuers_query
| parse @message '"authn_context":[*]' as authn
| filter
name IN %{event}
AND (authn like /ns\\/assurance\\/loa/ OR acr like /ns\\/assurance\\/loa/)
AND (authn like /aal\\/3/ or acr like /aal\\/3/)
AND properties.event_properties.success= 1
| display issuer
| sort issuer
| dedup issuer
QUERY
end

def aal3_issuers_data
@aal3_issuers_data ||= cloudwatch_client.fetch(
query: aal3_issuers_query,
from: time_range.begin,
to: time_range.end,
).
map { |slice| slice['issuer'] }.
uniq
def facial_match_issuers_query
format(<<~QUERY)
fields
coalesce(properties.event_properties.service_provider, properties.event_properties.client_id, properties.service_provider) as issuer
| filter properties.sp_request.facial_match
Sgtpluck marked this conversation as resolved.
Show resolved Hide resolved
| display issuer
| sort issuer
| dedup issuer
QUERY
end

def aal3_issuers_query
def loa_issuers_query
params = {
event: quote([SAML_AUTH_EVENT, OIDC_AUTH_EVENT]),
}
Expand All @@ -318,14 +305,64 @@ def aal3_issuers_query
| parse @message '"authn_context":[*]' as authn
| filter
name IN %{event}
AND (authn like /aal\\/3/ or acr like /aal\\/3/)
AND (authn like /ns\\/assurance\\/loa/ OR acr like /ns\\/assurance\\/loa/)
AND properties.event_properties.success= 1
| display issuer
| sort issuer
| dedup issuer
QUERY
end

def protocol_query
params = {
event: quote([SAML_AUTH_EVENT, OIDC_AUTH_EVENT]),
}

format(<<~QUERY, params)
fields
name AS protocol,
coalesce(properties.event_properties.service_provider, properties.event_properties.client_id) as issuer
| filter name IN %{event} AND properties.event_properties.success= 1
Comment on lines +320 to +327
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. I'd consider calling it "events" (plural) since it's a list
  2. updating spacing around success = 1
Suggested change
event: quote([SAML_AUTH_EVENT, OIDC_AUTH_EVENT]),
}
format(<<~QUERY, params)
fields
name AS protocol,
coalesce(properties.event_properties.service_provider, properties.event_properties.client_id) as issuer
| filter name IN %{event} AND properties.event_properties.success= 1
events: quote([SAML_AUTH_EVENT, OIDC_AUTH_EVENT]),
}
format(<<~QUERY, params)
fields
name AS protocol,
coalesce(properties.event_properties.service_provider, properties.event_properties.client_id) as issuer
| filter name IN %{events} AND properties.event_properties.success = 1

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure, i'll fix as long as i'm in here e5d1685

| stats
count(*) AS request_count
BY
protocol, issuer
QUERY
end

def saml_signature_query
params = {
event: quote([SAML_AUTH_EVENT]),
}

format(<<~QUERY, params)
fields
properties.event_properties.service_provider AS issuer,
properties.event_properties.request_signed = 1 AS signed,
properties.event_properties.request_signed != 1 AS not_signed,
isempty(properties.event_properties.matching_cert_serial) AND signed AS invalid_signature
| filter name IN %{event}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

events (plural)

Suggested change
event: quote([SAML_AUTH_EVENT]),
}
format(<<~QUERY, params)
fields
properties.event_properties.service_provider AS issuer,
properties.event_properties.request_signed = 1 AS signed,
properties.event_properties.request_signed != 1 AS not_signed,
isempty(properties.event_properties.matching_cert_serial) AND signed AS invalid_signature
| filter name IN %{event}
events: quote([SAML_AUTH_EVENT]),
}
format(<<~QUERY, params)
fields
properties.event_properties.service_provider AS issuer,
properties.event_properties.request_signed = 1 AS signed,
properties.event_properties.request_signed != 1 AS not_signed,
isempty(properties.event_properties.matching_cert_serial) AND signed AS invalid_signature
| filter name IN %{events}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed in e5d1685

AND properties.event_properties.success = 1
| stats
sum(not_signed) AS unsigned_count,
sum(invalid_signature) AS invalid_signature_count
BY
issuer
| sort
issuer
QUERY
end

def cloudwatch_client
@cloudwatch_client ||= Reporting::CloudwatchClient.new(
num_threads: @threads,
ensure_complete_logs: false,
slice_interval: @slice,
progress: progress?,
logger: verbose? ? Logger.new(STDERR) : nil,
)
end

def to_percent(numerator, denominator)
(100.0 * numerator / denominator).round(2)
end
Expand Down
Loading