Skip to content

Conversation

@hgiasac
Copy link
Contributor

@hgiasac hgiasac commented Oct 15, 2024

fix #7

Forward headers from Grafana requests to upstream GraphQL requests

return nil, err
}

for key, value := range req.Headers {
Copy link
Member

Choose a reason for hiding this comment

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

I'll admit I'm unfamiliar with this part of the backend, but I was looking around and I noticed that the function GetHTTPHeaders() also exists. I'm wondering if we are supposed to use that instead or what the different would be.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You're right. The GetHTTPHeaders method filters unused headers (source). We can use that method for the better security.

@retrodaredevil
Copy link
Member

Can I ask what your use case for this is? I'm also curious if this is standard to pass headers to the server the backend is communicating with. Do other Grafana plugins do this?

My guess is that this is useful so that you can tell which user a particular query has come from? Do you know if these headers can be spoofed by the frontend, or are these headers validated by Grafana before passing them to us?

I ask this because I'm curious if you have any additional knowledge that might help me understand if this is something that many Grafana plugins do (the documentation for this sort of thing is non-existent).

@retrodaredevil
Copy link
Member

retrodaredevil commented Oct 18, 2024

Additionally, I'm wondering if there's a chance that making a change like this could unintentionally pass headers to a GraphQL server that really don't need to be passed (I mean, there are public GraphQL servers out there, and GraphQL serveres that might become unhappy if you pass invalid headers to them). This change seems useful, but I'm wondering if we should have a toggle for it. (I'm not saying to add a toggle yet, just want some discussion around this)

@hgiasac
Copy link
Contributor Author

hgiasac commented Oct 18, 2024

@retrodaredevil This issue happens in other data sources as well. We need to pass Cookie or OAuth identity for the session auth.

grafana/grafana#60510
https://community.grafana.com/t/elasticsearch-datasource-withcredentials-doesnt-seem-to-send-cookie/5063

You already knew that Grafana had provided the new HTTP auth UI. Those auth headers are also configurable in the data source config. Therefore that should be fine I guess.
graphql

@retrodaredevil
Copy link
Member

Oh that makes sense. Have you confirmed that Grafana will automatically filter out headers if we don't have any of those checkboxes checked? We don't have to do the filtering of headers manually, right?

@hgiasac
Copy link
Contributor Author

hgiasac commented Oct 18, 2024

Yes, as you can see in the source code, the GetHTTPHeaders function filters the following headers:

  • Cookie
  • Authorization
  • X-Id-Token
  • Custom headers with http_ prefix
func getHTTPHeadersFromStringMap(headers map[string]string) http.Header {
	httpHeaders := http.Header{}

	for k, v := range headers {
		if textproto.CanonicalMIMEHeaderKey(k) == OAuthIdentityTokenHeaderName {
			httpHeaders.Set(k, v)
		}

		if textproto.CanonicalMIMEHeaderKey(k) == OAuthIdentityIDTokenHeaderName {
			httpHeaders.Set(k, v)
		}

		if textproto.CanonicalMIMEHeaderKey(k) == CookiesHeaderName {
			httpHeaders.Set(k, v)
		}

		if strings.HasPrefix(k, httpHeaderPrefix) {
			hKey := strings.TrimPrefix(k, httpHeaderPrefix)
			httpHeaders.Set(hKey, v)
		}
	}

	return httpHeaders
}

@retrodaredevil
Copy link
Member

retrodaredevil commented Oct 18, 2024

Yeah I saw that. I'm wondering if the headers present within req.Headers will have already been filtered based on whether or not the user has checked those check boxes.

For instance, if a user does not have the "Forward OAuth Identity" checked, do we have to be the ones to not send the header, or will Grafana have already filtered it for us?

@hgiasac
Copy link
Contributor Author

hgiasac commented Oct 18, 2024

As I read from Grafana's source code, Grafana already filters those headers before sending them to the data source.
Even if there are unexpected headers from Grafana that would be a Grafana's bug, not from us.

@retrodaredevil
Copy link
Member

Awesome. If you have a source for where it's doing that filtering, I'd appreciate a link so I can look at it. (I'm just curious)

As an additional note, it looks like even with all those checkboxes unchecked, it looks like for requests from a query, these headers get passed each time:

  • X-Datasource-Uid
  • X-Grafana-Org-Id
  • X-Panel-Id
  • X-Dashboard-Uid

Just wanted to document that those are the headers I observed being passed to the GraphQL server.

Obviously most GraphQL servers aren't going to utilize those additional headers, so it shouldn't break anything. I do wonder if it's a bad practice to pass those headers to all GraphQL servers, but I'm not convinced we need to introduce a toggle right now.

Looks good to me. I think I'll merge this now.

@retrodaredevil retrodaredevil merged commit 6f4adf1 into wildmountainfarms:main Oct 18, 2024
@hgiasac
Copy link
Contributor Author

hgiasac commented Oct 18, 2024

@retrodaredevil you can look at plugin integration middleware

Each middleware applies validation for those auth headers

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Headers of Grafana requests aren't forwarded to the HTTP request

2 participants