beats icon indicating copy to clipboard operation
beats copied to clipboard

[Metricbeat] MSSQL module cannot parse username if domain is included within the host string

Open geekpete opened this issue 6 years ago • 11 comments

Please include configurations and logs if available.

For confirmed bugs, please report:

  • Version: Metricbeat 7.3.0
  • Operating System: Windows
  • Discuss Forum URL:
  • Steps to Reproduce:

Using a domain within the username in credentials doesn't seem to parse regardless of escaping.

Typical configuration example might look like:

------------
# Module: mssql
# Docs: https://www.elastic.co/guide/en/beats/metricbeat/7.3/metricbeat-module-mssql.html

- module: mssql
  metricsets:
    - "transaction_log"
    - "performance"
  hosts: ["sqlserver://sa@localhost"]
  period: 10s

But when attempting to use an Active Domain user rather than the SA service account, there doesn't seem to be a way to specify the domain within the hosts connection string and have it work.

Examples of what doesn't work:

hosts: ["sqlserver://domain\user:password@server01"]
hosts: ["sqlserver://domain\\user:password@server01"]
hosts: ["sqlserver://domain/user:password@server01"]
hosts: ["sqlserver://domain\/user:password@server01"]
hosts: ["domain\user:password@server01"]
hosts: ["domain\\user:password@server01"]
hosts: ["domain/user:password@server01"]
hosts: ["domain\/user:password@server01"]

Example errors

When trying with domain:

2019-08-28T12:54:59.661+1200    ERROR   instance/beat.go:802    Exiting: 1 error: 2 errors: host parsing failed for mssql-transaction_log: error parsing URL: parse sqlserver://mydomain\user:password@server01: net/url: invalid userinfo; host parsing failed for mssql-performance: error parsing URL: parse sqlserver://mydomain\user:password@server01: net/url: invalid userinfo

Exiting: 1 error: 2 errors: host parsing failed for mssql-transaction_log: error parsing URL: parse sqlserver://mydomain\user:password@server01: net/url: invalid userinfo; host parsing failed for mssql-performance: error parsing URL: parse sqlserver://mydomain\user:password@server01: net/url: invalid userinfo

If leaving the domain out, the error is that the native user with that name cannot log in as the user with access is the domain user with that name not a native user:

2019-08-28T12:56:25.383+1200    ERROR   instance/beat.go:802    Exiting: 1 error: 2 errors: could not create connection to db: error doing ping to db: Login error: mssql: Login failed for user 'user'.; could not create connection to db: error doing ping to db: Login error: mssql: Login failed for user 'user'. 

Exiting: 1 error: 2 errors: could not create connection to db: error doing ping to db: Login error: mssql: Login failed for user 'user'.; could not create connection to db: error doing ping to db: Login error: mssql: Login failed for user 'user'.

Interestingly the domain credentials can be made to work if set separately via:

metricbeat.modules:
- module: mssql
  metricsets:
    - "transaction_log"
    - "performance"
  hosts: ["sqlserver://localhost"]
  username: domain\username
  password: verysecurepassword
  period: 10s

Related:

  • https://github.com/elastic/beats/pull/13363
  • https://github.com/elastic/beats/issues/13006

geekpete avatar Aug 28 '19 04:08 geekpete

Pinging @elastic/integrations (Team:Integrations)

elasticmachine avatar Mar 04 '21 17:03 elasticmachine

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

botelastic[bot] avatar Mar 04 '22 17:03 botelastic[bot]

@geekpete

Please try out the below:

hosts: ["sqlserver://domain//user:password@server01"]

and ignore the username and password in config.yml

ManojS-shetty avatar Apr 20 '22 06:04 ManojS-shetty

@geekpete Any update on the above suggestion?

ManojS-shetty avatar Apr 25 '22 04:04 ManojS-shetty

@geekpete Any Update here?

ManojS-shetty avatar May 03 '22 09:05 ManojS-shetty

Sorry, I'm still working to follow up on this one.

geekpete avatar May 24 '22 00:05 geekpete

@geekpete Any update on the suggested method?

ManojS-shetty avatar May 31 '22 05:05 ManojS-shetty

@geekpete Any inputs so that we can proceed with the further about this?

ManojS-shetty avatar Jul 22 '22 05:07 ManojS-shetty

So in the original testing for this issue it looks like we'd tried everything except the way you're suggesting:

hosts: ["sqlserver://domain\user:password@server01"]
hosts: ["sqlserver://domain\\user:password@server01"]
hosts: ["sqlserver://domain/user:password@server01"]
hosts: ["sqlserver://domain\/user:password@server01"]

but not with two forward slashes after the domain

hosts: ["sqlserver://domain//user:password@server01"]

I'll see if I can get this tested and report back.

geekpete avatar Jul 22 '22 05:07 geekpete

So in the original testing for this issue it looks like we'd tried everything except the way you're suggesting:

hosts: ["sqlserver://domain\user:password@server01"]
hosts: ["sqlserver://domain\\user:password@server01"]
hosts: ["sqlserver://domain/user:password@server01"]
hosts: ["sqlserver://domain\/user:password@server01"]

but not with two forward slashes after the domain

hosts: ["sqlserver://domain//user:password@server01"]

I'll see if I can get this tested and report back.

Thank you @geekpete

ManojS-shetty avatar Jul 22 '22 09:07 ManojS-shetty

The issue here is that the \ character is not a valid character for userinfo. This can be worked around by percent encoding the backslash (See https://play.golang.com/p/ldyqlqiG8f7). url.PathEscape should be used on the username prior to constructing the connection URL. This looks like it can be done like this:

diff --git a/metricbeat/mb/parse/url.go b/metricbeat/mb/parse/url.go
index c0b23f421d..5c2ff19e86 100644
--- a/metricbeat/mb/parse/url.go
+++ b/metricbeat/mb/parse/url.go
@@ -71,6 +71,8 @@ func (b URLHostParserBuilder) Build() mb.HostParser {
                } else {
                        user = b.DefaultUsername
                }
+               user = url.PathEscape(user)
+
                t, ok = conf["password"]
                if ok {
                        pass, ok = t.(string)

efd6 avatar Oct 04 '22 07:10 efd6

Until the codebase is adjusted to automatically escape/encode the slash, it's also likely you can configure the string without the slash by manually passing the encoded value %5C directly instead of "\" in the domain user name.

ie for domain user: domain%5Cusername eg: sqlserver://domain%5Cusername:pass@ip

geekpete avatar May 03 '23 00:05 geekpete

Related issue to sanitize input in Kibana https://github.com/elastic/integrations/issues/5213

geekpete avatar Jul 20 '23 00:07 geekpete