Files
windows_exporter/internal/collector/adfs/adfs.go
T

699 lines
22 KiB
Go

// SPDX-License-Identifier: Apache-2.0
//
// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//go:build windows
package adfs
import (
"fmt"
"log/slog"
"time"
"github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/pdh"
"github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus/client_golang/prometheus"
)
const Name = "adfs"
type Config struct{}
//nolint:gochecknoglobals
var ConfigDefaults = Config{}
type Collector struct {
config Config
perfDataCollector *pdh.Collector[perfDataCounterValues]
perfDataObject []perfDataCounterValues
adLoginConnectionFailures *prometheus.Desc
artifactDBFailures *prometheus.Desc
artifactDBQueries *prometheus.Desc
artifactDBQueryTime *prometheus.Desc
configDBQueries *prometheus.Desc
configDBQueryTime *prometheus.Desc
certificateAuthentications *prometheus.Desc
configDBFailures *prometheus.Desc
deviceAuthentications *prometheus.Desc
externalAuthenticationFailures *prometheus.Desc
externalAuthentications *prometheus.Desc
extranetAccountLockouts *prometheus.Desc
federatedAuthentications *prometheus.Desc
federationMetadataRequests *prometheus.Desc
oAuthAuthZRequests *prometheus.Desc
oAuthClientAuthentications *prometheus.Desc
oAuthClientAuthenticationsFailures *prometheus.Desc
oAuthClientCredentialsRequestFailures *prometheus.Desc
oAuthClientCredentialsRequests *prometheus.Desc
oAuthClientPrivateKeyJwtAuthenticationFailures *prometheus.Desc
oAuthClientPrivateKeyJwtAuthentications *prometheus.Desc
oAuthClientSecretBasicAuthenticationFailures *prometheus.Desc
oAuthClientSecretBasicAuthentications *prometheus.Desc
oAuthClientSecretPostAuthenticationFailures *prometheus.Desc
oAuthClientSecretPostAuthentications *prometheus.Desc
oAuthClientWindowsIntegratedAuthenticationFailures *prometheus.Desc
oAuthClientWindowsIntegratedAuthentications *prometheus.Desc
oAuthLogonCertificateRequestFailures *prometheus.Desc
oAuthLogonCertificateTokenRequests *prometheus.Desc
oAuthPasswordGrantRequestFailures *prometheus.Desc
oAuthPasswordGrantRequests *prometheus.Desc
oAuthTokenRequests *prometheus.Desc
passiveRequests *prometheus.Desc
passportAuthentications *prometheus.Desc
passwordChangeFailed *prometheus.Desc
passwordChangeSucceeded *prometheus.Desc
samlPTokenRequests *prometheus.Desc
ssoAuthenticationFailures *prometheus.Desc
ssoAuthentications *prometheus.Desc
tokenRequests *prometheus.Desc
upAuthenticationFailures *prometheus.Desc
upAuthentications *prometheus.Desc
windowsIntegratedAuthentications *prometheus.Desc
wsFedTokenRequests *prometheus.Desc
wsTrustTokenRequests *prometheus.Desc
}
func New(config *Config) *Collector {
if config == nil {
config = &ConfigDefaults
}
c := &Collector{
config: *config,
}
return c
}
func NewWithFlags(_ *kingpin.Application) *Collector {
return &Collector{}
}
func (c *Collector) GetName() string {
return Name
}
func (c *Collector) Close() error {
c.perfDataCollector.Close()
return nil
}
func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error {
c.buildDescriptors()
var err error
c.perfDataCollector, err = pdh.NewCollector[perfDataCounterValues](logger.With(slog.String("collector", Name)), pdh.CounterTypeRaw, "AD FS", nil)
if err != nil {
return fmt.Errorf("failed to create AD FS collector: %w", err)
}
return nil
}
func (c *Collector) buildDescriptors() {
c.adLoginConnectionFailures = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "ad_login_connection_failures_total"),
"Total number of connection failures to an Active Directory domain controller",
nil,
nil,
)
c.certificateAuthentications = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "certificate_authentications_total"),
"Total number of User Certificate authentications",
nil,
nil,
)
c.deviceAuthentications = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "device_authentications_total"),
"Total number of Device authentications",
nil,
nil,
)
c.extranetAccountLockouts = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "extranet_account_lockouts_total"),
"Total number of Extranet Account Lockouts",
nil,
nil,
)
c.federatedAuthentications = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "federated_authentications_total"),
"Total number of authentications from a federated source",
nil,
nil,
)
c.passportAuthentications = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "passport_authentications_total"),
"Total number of Microsoft Passport SSO authentications",
nil,
nil,
)
c.passiveRequests = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "passive_requests_total"),
"Total number of passive (browser-based) requests",
nil,
nil,
)
c.passwordChangeFailed = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "password_change_failed_total"),
"Total number of failed password changes",
nil,
nil,
)
c.passwordChangeSucceeded = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "password_change_succeeded_total"),
"Total number of successful password changes",
nil,
nil,
)
c.tokenRequests = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "token_requests_total"),
"Total number of token requests",
nil,
nil,
)
c.windowsIntegratedAuthentications = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "windows_integrated_authentications_total"),
"Total number of Windows integrated authentications (Kerberos/NTLM)",
nil,
nil,
)
c.oAuthAuthZRequests = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "oauth_authorization_requests_total"),
"Total number of incoming requests to the OAuth Authorization endpoint",
nil,
nil,
)
c.oAuthClientAuthentications = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "oauth_client_authentication_success_total"),
"Total number of successful OAuth client Authentications",
nil,
nil,
)
c.oAuthClientAuthenticationsFailures = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "oauth_client_authentication_failure_total"),
"Total number of failed OAuth client Authentications",
nil,
nil,
)
c.oAuthClientCredentialsRequestFailures = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "oauth_client_credentials_failure_total"),
"Total number of failed OAuth Client Credentials Requests",
nil,
nil,
)
c.oAuthClientCredentialsRequests = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "oauth_client_credentials_success_total"),
"Total number of successful RP tokens issued for OAuth Client Credentials Requests",
nil,
nil,
)
c.oAuthClientPrivateKeyJwtAuthenticationFailures = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "oauth_client_privkey_jwt_authentication_failure_total"),
"Total number of failed OAuth Client Private Key Jwt Authentications",
nil,
nil,
)
c.oAuthClientPrivateKeyJwtAuthentications = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "oauth_client_privkey_jwt_authentications_success_total"),
"Total number of successful OAuth Client Private Key Jwt Authentications",
nil,
nil,
)
c.oAuthClientSecretBasicAuthenticationFailures = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "oauth_client_secret_basic_authentications_failure_total"),
"Total number of failed OAuth Client Secret Basic Authentications",
nil,
nil,
)
c.oAuthClientSecretBasicAuthentications = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "oauth_client_secret_basic_authentications_success_total"),
"Total number of successful OAuth Client Secret Basic Authentications",
nil,
nil,
)
c.oAuthClientSecretPostAuthenticationFailures = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "oauth_client_secret_post_authentications_failure_total"),
"Total number of failed OAuth Client Secret Post Authentications",
nil,
nil,
)
c.oAuthClientSecretPostAuthentications = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "oauth_client_secret_post_authentications_success_total"),
"Total number of successful OAuth Client Secret Post Authentications",
nil,
nil,
)
c.oAuthClientWindowsIntegratedAuthenticationFailures = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "oauth_client_windows_authentications_failure_total"),
"Total number of failed OAuth Client Windows Integrated Authentications",
nil,
nil,
)
c.oAuthClientWindowsIntegratedAuthentications = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "oauth_client_windows_authentications_success_total"),
"Total number of successful OAuth Client Windows Integrated Authentications",
nil,
nil,
)
c.oAuthLogonCertificateRequestFailures = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "oauth_logon_certificate_requests_failure_total"),
"Total number of failed OAuth Logon Certificate Requests",
nil,
nil,
)
c.oAuthLogonCertificateTokenRequests = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "oauth_logon_certificate_token_requests_success_total"),
"Total number of successful RP tokens issued for OAuth Logon Certificate Requests",
nil,
nil,
)
c.oAuthPasswordGrantRequestFailures = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "oauth_password_grant_requests_failure_total"),
"Total number of failed OAuth Password Grant Requests",
nil,
nil,
)
c.oAuthPasswordGrantRequests = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "oauth_password_grant_requests_success_total"),
"Total number of successful OAuth Password Grant Requests",
nil,
nil,
)
c.oAuthTokenRequests = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "oauth_token_requests_success_total"),
"Total number of successful RP tokens issued over OAuth protocol",
nil,
nil,
)
c.samlPTokenRequests = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "samlp_token_requests_success_total"),
"Total number of successful RP tokens issued over SAML-P protocol",
nil,
nil,
)
c.ssoAuthenticationFailures = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "sso_authentications_failure_total"),
"Total number of failed SSO authentications",
nil,
nil,
)
c.ssoAuthentications = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "sso_authentications_success_total"),
"Total number of successful SSO authentications",
nil,
nil,
)
c.wsFedTokenRequests = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "wsfed_token_requests_success_total"),
"Total number of successful RP tokens issued over WS-Fed protocol",
nil,
nil,
)
c.wsTrustTokenRequests = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "wstrust_token_requests_success_total"),
"Total number of successful RP tokens issued over WS-Trust protocol",
nil,
nil,
)
c.upAuthenticationFailures = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "userpassword_authentications_failure_total"),
"Total number of failed AD U/P authentications",
nil,
nil,
)
c.upAuthentications = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "userpassword_authentications_success_total"),
"Total number of successful AD U/P authentications",
nil,
nil,
)
c.externalAuthenticationFailures = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "external_authentications_failure_total"),
"Total number of failed authentications from external MFA providers",
nil,
nil,
)
c.externalAuthentications = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "external_authentications_success_total"),
"Total number of successful authentications from external MFA providers",
nil,
nil,
)
c.artifactDBFailures = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "db_artifact_failure_total"),
"Total number of failures connecting to the artifact database",
nil,
nil,
)
c.artifactDBQueryTime = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "db_artifact_query_time_seconds_total"),
"Total time spent on artifact database queries, in seconds",
nil,
nil,
)
c.artifactDBQueries = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "db_artifact_queries_total"),
"Total number of artifact database queries",
nil,
nil,
)
c.configDBFailures = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "db_config_failure_total"),
"Total number of failures connecting to the configuration database",
nil,
nil,
)
c.configDBQueryTime = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "db_config_query_time_seconds_total"),
"Total time spent on configuration database queries, in seconds",
nil,
nil,
)
c.configDBQueries = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "db_config_queries_total"),
"Total number of configuration database queries",
nil,
nil,
)
c.federationMetadataRequests = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "federation_metadata_requests_total"),
"Total number of Federation Metadata requests",
nil,
nil,
)
}
func (c *Collector) Collect(ch chan<- prometheus.Metric, _ time.Duration) error {
err := c.perfDataCollector.Collect(&c.perfDataObject)
if err != nil {
return fmt.Errorf("failed to collect ADFS metrics: %w", err)
} else if len(c.perfDataObject) == 0 {
return fmt.Errorf("failed to collect ADFS metrics: %w", types.ErrNoDataUnexpected)
}
// The query times are PERF_AVERAGE_TIMER counters: the raw value is the
// summed duration in ticks of the counter's time base.
artifactDBFrequency, _ := c.perfDataCollector.Frequency(counterArtifactDBQueryTime)
configDBFrequency, _ := c.perfDataCollector.Frequency(counterConfigDBQueryTime)
c.collectMetrics(ch, c.perfDataObject[0], artifactDBFrequency, configDBFrequency)
return nil
}
// collectMetrics sends the metrics of data. A query time is only sent if the
// frequency of its counter is known.
func (c *Collector) collectMetrics(ch chan<- prometheus.Metric, data perfDataCounterValues, artifactDBFrequency, configDBFrequency int64) {
ch <- prometheus.MustNewConstMetric(
c.adLoginConnectionFailures,
prometheus.CounterValue,
data.AdLoginConnectionFailures,
)
ch <- prometheus.MustNewConstMetric(
c.certificateAuthentications,
prometheus.CounterValue,
data.CertificateAuthentications,
)
ch <- prometheus.MustNewConstMetric(
c.deviceAuthentications,
prometheus.CounterValue,
data.DeviceAuthentications,
)
ch <- prometheus.MustNewConstMetric(
c.extranetAccountLockouts,
prometheus.CounterValue,
data.ExtranetAccountLockouts,
)
ch <- prometheus.MustNewConstMetric(
c.federatedAuthentications,
prometheus.CounterValue,
data.FederatedAuthentications,
)
ch <- prometheus.MustNewConstMetric(
c.passportAuthentications,
prometheus.CounterValue,
data.PassportAuthentications,
)
ch <- prometheus.MustNewConstMetric(
c.passiveRequests,
prometheus.CounterValue,
data.PassiveRequests,
)
ch <- prometheus.MustNewConstMetric(
c.passwordChangeFailed,
prometheus.CounterValue,
data.PasswordChangeFailed,
)
ch <- prometheus.MustNewConstMetric(
c.passwordChangeSucceeded,
prometheus.CounterValue,
data.PasswordChangeSucceeded,
)
ch <- prometheus.MustNewConstMetric(
c.tokenRequests,
prometheus.CounterValue,
data.TokenRequests,
)
ch <- prometheus.MustNewConstMetric(
c.windowsIntegratedAuthentications,
prometheus.CounterValue,
data.WindowsIntegratedAuthentications,
)
ch <- prometheus.MustNewConstMetric(
c.oAuthAuthZRequests,
prometheus.CounterValue,
data.OAuthAuthZRequests,
)
ch <- prometheus.MustNewConstMetric(
c.oAuthClientAuthentications,
prometheus.CounterValue,
data.OAuthClientAuthentications,
)
ch <- prometheus.MustNewConstMetric(
c.oAuthClientAuthenticationsFailures,
prometheus.CounterValue,
data.OAuthClientAuthenticationFailures,
)
ch <- prometheus.MustNewConstMetric(
c.oAuthClientCredentialsRequestFailures,
prometheus.CounterValue,
data.OAuthClientCredentialRequestFailures,
)
ch <- prometheus.MustNewConstMetric(
c.oAuthClientCredentialsRequests,
prometheus.CounterValue,
data.OAuthClientCredentialRequests,
)
ch <- prometheus.MustNewConstMetric(
c.oAuthClientPrivateKeyJwtAuthenticationFailures,
prometheus.CounterValue,
data.OAuthClientPrivateKeyJWTAuthenticationFailures,
)
ch <- prometheus.MustNewConstMetric(
c.oAuthClientPrivateKeyJwtAuthentications,
prometheus.CounterValue,
data.OAuthClientPrivateKeyJWTAuthentications,
)
ch <- prometheus.MustNewConstMetric(
c.oAuthClientSecretBasicAuthenticationFailures,
prometheus.CounterValue,
data.OAuthClientBasicAuthenticationFailures,
)
ch <- prometheus.MustNewConstMetric(
c.oAuthClientSecretBasicAuthentications,
prometheus.CounterValue,
data.OAuthClientBasicAuthentications,
)
ch <- prometheus.MustNewConstMetric(
c.oAuthClientSecretPostAuthenticationFailures,
prometheus.CounterValue,
data.OAuthClientSecretPostAuthenticationFailures,
)
ch <- prometheus.MustNewConstMetric(
c.oAuthClientSecretPostAuthentications,
prometheus.CounterValue,
data.OAuthClientSecretPostAuthentications,
)
ch <- prometheus.MustNewConstMetric(
c.oAuthClientWindowsIntegratedAuthenticationFailures,
prometheus.CounterValue,
data.OAuthClientWindowsAuthenticationFailures,
)
ch <- prometheus.MustNewConstMetric(
c.oAuthClientWindowsIntegratedAuthentications,
prometheus.CounterValue,
data.OAuthClientWindowsAuthentications,
)
ch <- prometheus.MustNewConstMetric(
c.oAuthLogonCertificateRequestFailures,
prometheus.CounterValue,
data.OAuthLogonCertRequestFailures,
)
ch <- prometheus.MustNewConstMetric(
c.oAuthLogonCertificateTokenRequests,
prometheus.CounterValue,
data.OAuthLogonCertTokenRequests,
)
ch <- prometheus.MustNewConstMetric(
c.oAuthPasswordGrantRequestFailures,
prometheus.CounterValue,
data.OAuthPasswordGrantRequestFailures,
)
ch <- prometheus.MustNewConstMetric(
c.oAuthPasswordGrantRequests,
prometheus.CounterValue,
data.OAuthPasswordGrantRequests,
)
ch <- prometheus.MustNewConstMetric(
c.oAuthTokenRequests,
prometheus.CounterValue,
data.OAuthTokenRequests,
)
ch <- prometheus.MustNewConstMetric(
c.samlPTokenRequests,
prometheus.CounterValue,
data.SamlPTokenRequests,
)
ch <- prometheus.MustNewConstMetric(
c.ssoAuthenticationFailures,
prometheus.CounterValue,
data.SsoAuthenticationFailures,
)
ch <- prometheus.MustNewConstMetric(
c.ssoAuthentications,
prometheus.CounterValue,
data.SsoAuthentications,
)
ch <- prometheus.MustNewConstMetric(
c.wsFedTokenRequests,
prometheus.CounterValue,
data.WsFedTokenRequests,
)
ch <- prometheus.MustNewConstMetric(
c.wsTrustTokenRequests,
prometheus.CounterValue,
data.WsTrustTokenRequests,
)
ch <- prometheus.MustNewConstMetric(
c.upAuthenticationFailures,
prometheus.CounterValue,
data.UsernamePasswordAuthenticationFailures,
)
ch <- prometheus.MustNewConstMetric(
c.upAuthentications,
prometheus.CounterValue,
data.UsernamePasswordAuthentications,
)
ch <- prometheus.MustNewConstMetric(
c.externalAuthenticationFailures,
prometheus.CounterValue,
data.ExternalAuthNFailures,
)
ch <- prometheus.MustNewConstMetric(
c.externalAuthentications,
prometheus.CounterValue,
data.ExternalAuthentications,
)
ch <- prometheus.MustNewConstMetric(
c.artifactDBFailures,
prometheus.CounterValue,
data.ArtifactDBFailures,
)
ch <- prometheus.MustNewConstMetric(
c.artifactDBQueries,
prometheus.CounterValue,
data.ArtifactDBQueries,
)
if artifactDBFrequency > 0 {
ch <- prometheus.MustNewConstMetric(
c.artifactDBQueryTime,
prometheus.CounterValue,
data.ArtifactDBQueryTimeTicks/float64(artifactDBFrequency),
)
}
ch <- prometheus.MustNewConstMetric(
c.configDBFailures,
prometheus.CounterValue,
data.ConfigDBFailures,
)
ch <- prometheus.MustNewConstMetric(
c.configDBQueries,
prometheus.CounterValue,
data.ConfigDBQueries,
)
if configDBFrequency > 0 {
ch <- prometheus.MustNewConstMetric(
c.configDBQueryTime,
prometheus.CounterValue,
data.ConfigDBQueryTimeTicks/float64(configDBFrequency),
)
}
ch <- prometheus.MustNewConstMetric(
c.federationMetadataRequests,
prometheus.CounterValue,
data.FederationMetadataRequests,
)
}