Skip to content

Commit

Permalink
digest auth
Browse files Browse the repository at this point in the history
  • Loading branch information
yesoreyeram committed May 17, 2022
1 parent 646bb51 commit b9281b3
Show file tree
Hide file tree
Showing 17 changed files with 157 additions and 15 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ Change history of the project. All the feature updates, bug fixes, breaking chan
## [ 1.0.0 ] - unreleased

- New Query Type: JSON Backend ( _experimental_ )
- New Auth Type: Digest auth support
- New Macro: Support for macros (`$__combineValues()`,`$__customInterval()`) added in URL, Body, Inline data, UQL queries
- New Variable Query Type: Random String from given array of strings
- UQL: new root level command `where` added to support basic filters
- UQL: new method `extract` added to extract part of the string using regex
- UQL: new summarize methods `countif`, `sumif`, `minif` and `maxif`
- UQL: new methods `percentage`,`split`,`replace_string`,`reverse`,`pack`,`array_to_map` and `array_from_entries`
- As-Is: Support for URL when using As-Is format with JSON
- Chore: Test coverage improved
- Chore: Added `vitest` for dev improvements
Expand Down
1 change: 1 addition & 0 deletions cspell.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@
"vitest",
"vlookup",
"vuepress",
"xinsnake",
"yesoreyeram",
"youtube"
]
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ require (
github.com/graphql-go/handler v0.2.3
github.com/stretchr/testify v1.7.0
github.com/tidwall/gjson v1.14.1
github.com/xinsnake/go-http-digest-auth-client v0.6.0
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8
moul.io/http2curl v1.0.0
)
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,8 @@ github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/xinsnake/go-http-digest-auth-client v0.6.0 h1:nrYFWDrB2F7VwYlNravXZS0nOtg9axlATH3Jns55/F0=
github.com/xinsnake/go-http-digest-auth-client v0.6.0/go.mod h1:QK1t1v7ylyGb363vGWu+6Irh7gyFj+N7+UZzM0L6g8I=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "grafana-infinity-datasource",
"version": "1.0.0-dev.2",
"version": "1.0.0-dev.3",
"description": "JSON, CSV, XML, GraphQL & HTML datasource for Grafana. Do infinite things with Grafana.",
"main": "dist/module.js",
"scripts": {
Expand Down Expand Up @@ -64,7 +64,7 @@
"react": "16.12.0",
"react-dom": "16.12.0",
"rxjs": "6.6.3",
"uql": "0.0.16",
"uql": "0.0.17",
"xml2js": "^0.4.23"
},
"devDependencies": {
Expand Down
1 change: 1 addition & 0 deletions pkg/infinity/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ func NewClient(settings InfinitySettings) (client *Client, err error) {
Transport: transport,
Timeout: time.Second * time.Duration(settings.TimeoutInSeconds),
}
httpClient = ApplyDigestAuth(httpClient, settings)
httpClient = ApplyOAuthClientCredentials(httpClient, settings)
httpClient = ApplyOAuthJWT(httpClient, settings)
return &Client{
Expand Down
8 changes: 8 additions & 0 deletions pkg/infinity/oauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"net/url"
"strings"

dac "github.com/xinsnake/go-http-digest-auth-client"
"golang.org/x/oauth2"
"golang.org/x/oauth2/clientcredentials"
"golang.org/x/oauth2/jwt"
Expand Down Expand Up @@ -55,3 +56,10 @@ func ApplyOAuthJWT(httpClient *http.Client, settings InfinitySettings) *http.Cli
}
return httpClient
}
func ApplyDigestAuth(httpClient *http.Client, settings InfinitySettings) *http.Client {
if settings.AuthenticationMethod == AuthenticationMethodDigestAuth {
a := dac.NewTransport(settings.UserName, settings.Password)
httpClient.Transport = &a
}
return httpClient
}
1 change: 1 addition & 0 deletions pkg/infinity/settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const (
AuthenticationMethodApiKey = "apiKey"
AuthenticationMethodBearerToken = "bearerToken"
AuthenticationMethodForwardOauth = "oauthPassThru"
AuthenticationMethodDigestAuth = "digestAuth"
AuthenticationMethodOAuth = "oauth2"
)

Expand Down
100 changes: 100 additions & 0 deletions src/app/uql.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { uql } from 'uql';

describe('uql', () => {
it('nested array parsing', async () => {
const data = `{
"totalCount": 3,
"nextPageKey": "null",
"resolution": "1h",
"warnings": [
"The contains filter transformation is deprecated and will be removed in a future release."
],
"result": [
{
"metricId": "builtin:host.disk.avail",
"dataPointCountRatio": "0.1211",
"dimensionCountRatio": "0.0322",
"data": [
{
"dimensions": [
"HOST-F1266E1D0AAC2C3C",
"DISK-F1266E1D0AAC2C3F"
],
"timestamps": [
3151435100000,
3151438700000,
3151442300000
],
"values": [
11.1,
22.2,
33.3
]
},
{
"dimensions": [
"HOST-F1266E1D0AAC2C3C",
"DISK-F1266E1D0AAC2C3D"
],
"timestamps": [
3151435100000,
3151438700000,
3151442300000
],
"values": [
111.1,
222.2,
333.3
]
}
]
},
{
"metricId": "builtin:host.cpu.idle",
"data": [
{
"dimensions": [
"HOST-F1266E1D0AAC2C3C"
],
"timestamps": [
3151435100000,
3151438700000,
3151442300000
],
"values": [
1.1,
2.2,
3.3
]
}
]
}
]
}`;
expect(
await uql(
`parse-json
| scope "result"
| project-away "dataPointCountRatio", "dimensionCountRatio"
| mv-expand "data"
| project "dimensions"=array_to_map("data.dimensions",'host','disk'), "series"=array_from_entries('timestamp',"data.timestamps",'value',"data.values"), "metricId"
| project "host"="dimensions.host", "disk"="dimensions.disk", "series", "metricId"
| mv-expand "series"
| project "timestamp"="series.timestamp", "value"="series.value", "host", "disk", "metricId"
| extend "timestamp"=unixtime_milliseconds_todatetime("timestamp")
| order by "timestamp" asc`,
{ data }
)
).toStrictEqual([
{ timestamp: new Date('2069-11-11 22:38:20'), disk: 'DISK-F1266E1D0AAC2C3F', host: 'HOST-F1266E1D0AAC2C3C', value: 11.1, metricId: 'builtin:host.disk.avail' },
{ timestamp: new Date('2069-11-11 22:38:20'), disk: 'DISK-F1266E1D0AAC2C3D', host: 'HOST-F1266E1D0AAC2C3C', value: 111.1, metricId: 'builtin:host.disk.avail' },
{ timestamp: new Date('2069-11-11 22:38:20'), disk: undefined, host: 'HOST-F1266E1D0AAC2C3C', value: 1.1, metricId: 'builtin:host.cpu.idle' },
{ timestamp: new Date('2069-11-11 23:38:20'), disk: 'DISK-F1266E1D0AAC2C3F', host: 'HOST-F1266E1D0AAC2C3C', value: 22.2, metricId: 'builtin:host.disk.avail' },
{ timestamp: new Date('2069-11-11 23:38:20'), disk: 'DISK-F1266E1D0AAC2C3D', host: 'HOST-F1266E1D0AAC2C3C', value: 222.2, metricId: 'builtin:host.disk.avail' },
{ timestamp: new Date('2069-11-11 23:38:20'), disk: undefined, host: 'HOST-F1266E1D0AAC2C3C', value: 2.2, metricId: 'builtin:host.cpu.idle' },
{ timestamp: new Date('2069-11-12 00:38:20'), disk: 'DISK-F1266E1D0AAC2C3F', host: 'HOST-F1266E1D0AAC2C3C', value: 33.3, metricId: 'builtin:host.disk.avail' },
{ timestamp: new Date('2069-11-12 00:38:20'), disk: 'DISK-F1266E1D0AAC2C3D', host: 'HOST-F1266E1D0AAC2C3C', value: 333.3, metricId: 'builtin:host.disk.avail' },
{ timestamp: new Date('2069-11-12 00:38:20'), disk: undefined, host: 'HOST-F1266E1D0AAC2C3C', value: 3.3, metricId: 'builtin:host.cpu.idle' },
]);
});
});
4 changes: 3 additions & 1 deletion src/editors/config/Auth.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const authTypes: Array<SelectableValue<AuthType>> = [
{ value: 'basicAuth', label: 'Basic Authentication' },
{ value: 'apiKey', label: 'API Key' },
{ value: 'bearerToken', label: 'Bearer Token' },
{ value: 'digestAuth', label: 'Digest Auth' },
{ value: 'oauthPassThru', label: 'Forward OAuth' },
{ value: 'oauth2', label: 'OAuth2' },
];
Expand All @@ -33,6 +34,7 @@ export const AuthEditor = (props: DataSourcePluginOptionsEditorProps<InfinityOpt
case 'apiKey':
case 'bearerToken':
case 'oauthPassThru':
case 'digestAuth':
default:
onOptionsChange({ ...options, basicAuth: false, jsonData: { ...options.jsonData, oauthPassThru: false, auth_method: authMethod } });
break;
Expand Down Expand Up @@ -60,7 +62,7 @@ export const AuthEditor = (props: DataSourcePluginOptionsEditorProps<InfinityOpt
<InlineFormLabel width={10}>Auth Type</InlineFormLabel>
<RadioButtonGroup<AuthType> options={authTypes} value={authType} onChange={(e = 'none') => onAuthTypeChange(e!)}></RadioButtonGroup>
</div>
{authType === 'basicAuth' && (
{(authType === 'basicAuth' || authType === 'digestAuth') && (
<>
<div className="gf-form">
<FormField label="User Name" placeholder="username" labelWidth={10} value={props.options.basicAuthUser || ''} onChange={(e) => onUserNameChange(e.currentTarget.value)}></FormField>
Expand Down
8 changes: 4 additions & 4 deletions src/editors/query/query.filters.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { useState } from 'react';
import { SelectableValue } from '@grafana/data';
import { Modal } from '@grafana/ui';
import { Select } from './../../components/extended/ui';
import { SelectableValue } from '@grafana/data';
import { filterOperators } from '../../app/parsers/filter';
import { isDataQuery } from './../../app/utils';
import { InfinityQuery, InfinityFilter, FilterOperator } from '../../types';
Expand All @@ -15,8 +15,8 @@ export const TableFilter = (props: { query: InfinityQuery; onChange: (value: any
const getFields = () => {
return query.columns.map((col) => {
return {
label: col.text,
value: col.text,
label: col.text || col.selector,
value: col.text || col.selector,
};
});
};
Expand Down Expand Up @@ -61,7 +61,7 @@ export const TableFilter = (props: { query: InfinityQuery; onChange: (value: any
role="button"
title={query.filters && query.filters.length > 0 ? query.filters.length + ' filters configured' : ''}
className="btn btn-secondary btn-medium width-2"
onClick={(e) => setPopupOpenStatus(true)}
onClick={() => setPopupOpenStatus(true)}
style={{ padding: '10px' }}
>
<i className="fa fa-filter fa-large btn btn-medium"></i>
Expand Down
4 changes: 2 additions & 2 deletions src/interpolate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@ export const interpolateQuery = (query: InfinityQuery, scopedVars: ScopedVars):
}
if (isDataQuery(newQuery)) {
newQuery.filters = (newQuery.filters || []).map((filter) => {
filter.value = filter.value.map((val) => {
const value = (filter.value || []).map((val) => {
return getTemplateSrv().replace(val || '', scopedVars, 'glob');
});
return filter;
return { ...filter, value };
});
}
if (newQuery.type === 'uql') {
Expand Down
2 changes: 1 addition & 1 deletion src/types/config.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export interface GlobalInfinityQuery {
id: string;
query: InfinityQuery;
}
export type AuthType = 'none' | 'basicAuth' | 'apiKey' | 'bearerToken' | 'oauthPassThru' | 'oauth2';
export type AuthType = 'none' | 'basicAuth' | 'apiKey' | 'bearerToken' | 'oauthPassThru' | 'digestAuth' | 'oauth2';
export type OAuth2Type = 'client_credentials' | 'jwt' | 'others';
export type APIKeyType = 'header' | 'query';
export type OAuth2Props = {
Expand Down
2 changes: 1 addition & 1 deletion website/src/components/SearchBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ const sitemap: any[] = [
title: 'Authentication',
slug: '/wiki/authentication',
description: 'Various authentication methods',
tags: ['authentication', 'auth', 'username', 'password', 'secure', 'security', 'oauth', 'oauth2', 'api token', 'api key', 'bearer token', 'forward oauth identity'],
tags: ['authentication', 'auth', 'username', 'password', 'secure', 'security', 'oauth', 'oauth2', 'api token', 'api key', 'bearer token', 'forward oauth identity', 'digest authentication'],
},
{
title: 'Global Queries',
Expand Down
5 changes: 5 additions & 0 deletions website/src/wiki/authentication.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Infinity datasource supports following authentication methods
- Basic authentication
- Bearer token authentication
- API Key authentication
- Digest authentication
- OAuth passthrough
- OAuth2 client credentials
- OAuth2 JWT authentication
Expand All @@ -37,6 +38,10 @@ With API key authentication, you can send a key-value pair to the API via reques
| Value | Value of the API token |
| In | Accepts `header`/`query`. Most APIs accept API keys via headers which is preferred way of sending api keys. Sending API keys via the query parameter is not suggested way. |

## Digest Authentication

Digest authentication enable requests to authenticate using [RFC7616 HTTP Digest Access Authentication protocol](https://www.rfc-editor.org/rfc/rfc7616.txt).

## Bearer Token Authentication

Bearer token enable requests to authenticate using an access key, such as a JSON Web Token (JWT), personal access token. In the request Headers, the Authorization header will be sent in the `Bearer <Your API key>` format.
Expand Down
19 changes: 19 additions & 0 deletions website/src/wiki/uql.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,12 @@ following are some of the available functions
| sum | sum("col1","col2") | sum of two or more columns | 0.8.0 |
| diff | diff("col1","col2") | difference between two columns | 0.8.0 |
| mul | mul("col1","col2") | multiplication of two columns | 0.8.0 |
| div | div("col1","col2") | division of two columns (col1/col2) | 0.8.0 |
| percentage | percentage("col1","col2") | percentage of two columns ((col1/col2)\*100) | 1.0.0 |
| strcat | strcat("col1","col2") | concatenates two or more columns | 0.8.0 |
| split | split("col1",'delimiter') | splits a string using delimiter | 1.0.0 |
| replace_string | replace_string("col1",'src','replacer') | replace a portion of string with another | 1.0.0 |
| reverse | revers("col1") | reverse a string | 1.0.0 |
| floor | floor("col1") | calculates the floor value of given numeric field | 0.8.7 |
| ceil | ceil("col1") | calculates the ceil value of given numeric field | 0.8.7 |
| round | round("col1") | calculates the round value of given numeric field | 0.8.7 |
Expand Down Expand Up @@ -145,6 +150,20 @@ a,triple,thrice,sum,diff,mul

To apply multiple transformations over a field, repeat them with the same field name. For example, the uql query `extend "name"=tolower("name"), "name"=trim("name")` will apply tolower function and then trim function over the name field.

There are few other extend/project methods also available to deal with array

#### pack

pack method converts array of key value pairs into a map. Example `extend "foo"=pack('key1',"value1",'key1',"value2")` will yield a object `{key1:value1,key2:value2}`

#### array_from_entries

array_from_entries method builds an array of objects from entries. Example `extend "foo"=array_from_entries('timestamp',[2010,2020,2030])` will yield an array `[{timestamp:2010},{timestamp:2020},{timestamp:2030}]`

#### array_to_map

array_to_map converts an array of entries to a map. Optionally, one can provide alias for keys instead of index. Example `extend "foo"=array_to_map(['chennai','india'],'city','country')` will yield `{ 'city': 'chennai', 'country':'india'}`

### summarize

`summarize` command aggregates the data by a string column. summarize command expects alias, summarize by fields and summarize function. Following are the valid summarize functions.
Expand Down
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -15870,10 +15870,10 @@ upper-case@^1.1.1:
resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598"
integrity sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=

uql@0.0.16:
version "0.0.16"
resolved "https://registry.yarnpkg.com/uql/-/uql-0.0.16.tgz#4af1b94d40493b73c30c72fe6985cf4f6d2f44a2"
integrity sha512-VXHmKxZN9beFZNo//2QcIMTtQ6eZWBVj2aoacnjkZtFqYTddA8TBoE7Ro34zJz3dtaw5pAU7zmRj6d9hp0ztdQ==
uql@0.0.17:
version "0.0.17"
resolved "https://registry.yarnpkg.com/uql/-/uql-0.0.17.tgz#41ed4e1f407a3f096fbe3c2d8e1653ee0b9503f2"
integrity sha512-oftlcre5vBVDEGQvgFkAPwZAC425JMP91PJLoJMMiNZtUIt7c7Dm9XJW2lzG2PcFyjh+L+A97b26J2t0e6IOzw==
dependencies:
csv-parse "4.12.0"
dayjs "^1.10.7"
Expand Down

1 comment on commit b9281b3

@vercel
Copy link

@vercel vercel bot commented on b9281b3 May 17, 2022

Choose a reason for hiding this comment

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

Please sign in to comment.