Skip to content

Commit

Permalink
Merge remote-tracking branch 'grafana/master'
Browse files Browse the repository at this point in the history
* grafana/master: (41 commits)
  Fixes undefined issue with angular panels and editorTabs
  changelog: adds note about closing grafana#14562
  Update field name
  Add documentation
  Rename the setting and add description
  export init notifier func
  Increase recent and starred limit in search and home dashboard, closes grafana#13950
  changelog: adds note about closing grafana#14486
  Panel help view fixes
  Add min/max height when resizing and replace debounce with throttle
  changelog: adds note about closing grafana#14546
  Adding tests for auth proxy CIDR support
  changelog: adds note about closing grafana#14109
  fix signed in user for orgId=0 result should return active org id
  Another take on resizing the panel, now using react-draggable
  Raise datasources number to 5000
  copy props to state to make it visible in the view
  refactor to not crash when no links
  updating snaps
  renaming component
  ...
  • Loading branch information
ryantxu committed Dec 19, 2018
2 parents f717082 + 2325c5d commit 9c086be
Show file tree
Hide file tree
Showing 76 changed files with 1,000 additions and 387 deletions.
10 changes: 5 additions & 5 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ version: 2
jobs:
mysql-integration-test:
docker:
- image: circleci/golang:1.11
- image: circleci/golang:1.11.4
- image: circleci/mysql:5.6-ram
environment:
MYSQL_ROOT_PASSWORD: rootpass
Expand All @@ -39,7 +39,7 @@ jobs:

postgres-integration-test:
docker:
- image: circleci/golang:1.11
- image: circleci/golang:1.11.4
- image: circleci/postgres:9.3-ram
environment:
POSTGRES_USER: grafanatest
Expand Down Expand Up @@ -74,7 +74,7 @@ jobs:

gometalinter:
docker:
- image: circleci/golang:1.11
- image: circleci/golang:1.11.4
environment:
# we need CGO because of go-sqlite3
CGO_ENABLED: 1
Expand Down Expand Up @@ -117,7 +117,7 @@ jobs:

test-backend:
docker:
- image: circleci/golang:1.11
- image: circleci/golang:1.11.4
working_directory: /go/src/github.com/grafana/grafana
steps:
- checkout
Expand Down Expand Up @@ -175,7 +175,7 @@ jobs:

build:
docker:
- image: grafana/build-container:1.2.1
- image: grafana/build-container:1.2.2
working_directory: /go/src/github.com/grafana/grafana
steps:
- checkout
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

### New Features
* **Alerting**: Adds support for Google Hangouts Chat notifications [#11221](https://github.com/grafana/grafana/issues/11221), thx [@PatrickSchuster](https://github.com/PatrickSchuster)
* **Snapshots**: Enable deletion of public snapshot [#14109](https://github.com/grafana/grafana/issues/14109)

### Minor

Expand All @@ -13,6 +14,11 @@
* **Templating**: Escaping "Custom" template variables [#13754](https://github.com/grafana/grafana/issues/13754), thx [@IntegersOfK](https://github.com/IntegersOfK)
* **Admin**: When multiple user invitations, all links are the same as the first user who was invited [#14483](https://github.com/grafana/grafana/issues/14483)
* **LDAP**: Upgrade go-ldap to v3 [#14548](https://github.com/grafana/grafana/issues/14548)
* **Proxy whitelist**: Add CIDR capability to auth_proxy whitelist [#14546](https://github.com/grafana/grafana/issues/14546), thx [@jacobrichard](https://github.com/jacobrichard)
* **OAuth**: Support OAuth providers that are not RFC6749 compliant [#14562](https://github.com/grafana/grafana/issues/14562), thx [@tdabasinskas](https://github.com/tdabasinskas)

### Bug fixes
* **Search**: Fix for issue with scrolling the "tags filter" dropdown, fixes [#14486](https://github.com/grafana/grafana/issues/14486)

# 5.4.2 (2018-12-13)

Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Golang build container
FROM golang:1.11
FROM golang:1.11.4

WORKDIR $GOPATH/src/github.com/grafana/grafana

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ Choose this option to build on platforms other than linux/amd64 and/or not have

The resulting image will be tagged as `grafana/grafana:dev`

Notice: If you are using Docker for MacOS, be sure to let limit of Memory bigger than 2 GiB (at docker -> Perferences -> Advanced), otherwize you may faild at `grunt build`
Notice: If you are using Docker for MacOS, be sure to let limit of Memory bigger than 2 GiB (at docker -> Preferences -> Advanced), otherwize you may faild at `grunt build`

### Dev config

Expand Down
2 changes: 1 addition & 1 deletion appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ clone_folder: c:\gopath\src\github.com\grafana\grafana
environment:
nodejs_version: "8"
GOPATH: C:\gopath
GOVERSION: 1.11
GOVERSION: 1.11.4

install:
- rmdir c:\go /s /q
Expand Down
1 change: 1 addition & 0 deletions conf/defaults.ini
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,7 @@ tls_skip_verify_insecure = false
tls_client_cert =
tls_client_key =
tls_client_ca =
send_client_credentials_via_post = false

#################################### Basic Auth ##########################
[auth.basic]
Expand Down
4 changes: 4 additions & 0 deletions conf/sample.ini
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,10 @@ log_queries =
;tls_client_key =
;tls_client_ca =

; Set to true to enable sending client_id and client_secret via POST body instead of Basic authentication HTTP header
; This might be required if the OAuth provider is not RFC6749 compliant, only supporting credentials passed via POST payload
;send_client_credentials_via_post = false

#################################### Grafana.com Auth ####################
[auth.grafana_com]
;enabled = false
Expand Down
13 changes: 12 additions & 1 deletion docs/sources/auth/generic-oauth.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ can find examples using Okta, BitBucket, OneLogin and Azure.

This callback URL must match the full HTTP address that you use in your browser to access Grafana, but with the prefix path of `/login/generic_oauth`.

You may have to set the `root_url` option of `[server]` for the callback URL to be
You may have to set the `root_url` option of `[server]` for the callback URL to be
correct. For example in case you are serving Grafana behind a proxy.

Example config:
Expand Down Expand Up @@ -209,6 +209,17 @@ allowed_organizations =
token_url = https://<your domain>.my.centrify.com/OAuth2/Token/<Application ID>
```
## Set up OAuth2 with non-compliant providers
Some OAuth2 providers might not support `client_id` and `client_secret` passed via Basic Authentication HTTP header, which
results in `invalid_client` error. To allow Grafana to authenticate via these type of providers, the client identifiers must be
send via POST body, which can be enabled via the following settings:
```bash
[auth.generic_oauth]
send_client_credentials_via_post = true
```
<hr>
120 changes: 112 additions & 8 deletions pkg/api/dashboard_snapshot.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,27 @@
package api

import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"time"

"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/metrics"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util"
)

var client = &http.Client{
Timeout: time.Second * 5,
Transport: &http.Transport{Proxy: http.ProxyFromEnvironment},
}

func GetSharingOptions(c *m.ReqContext) {
c.JSON(200, util.DynMap{
"externalSnapshotURL": setting.ExternalSnapshotUrl,
Expand All @@ -20,26 +30,79 @@ func GetSharingOptions(c *m.ReqContext) {
})
}

type CreateExternalSnapshotResponse struct {
Key string `json:"key"`
DeleteKey string `json:"deleteKey"`
Url string `json:"url"`
DeleteUrl string `json:"deleteUrl"`
}

func createExternalDashboardSnapshot(cmd m.CreateDashboardSnapshotCommand) (*CreateExternalSnapshotResponse, error) {
var createSnapshotResponse CreateExternalSnapshotResponse
message := map[string]interface{}{
"name": cmd.Name,
"expires": cmd.Expires,
"dashboard": cmd.Dashboard,
}

messageBytes, err := simplejson.NewFromAny(message).Encode()
if err != nil {
return nil, err
}

response, err := client.Post(setting.ExternalSnapshotUrl+"/api/snapshots", "application/json", bytes.NewBuffer(messageBytes))
if err != nil {
return nil, err
}
defer response.Body.Close()

if response.StatusCode != 200 {
return nil, fmt.Errorf("Create external snapshot response status code %d", response.StatusCode)
}

if err := json.NewDecoder(response.Body).Decode(&createSnapshotResponse); err != nil {
return nil, err
}

return &createSnapshotResponse, nil
}

// POST /api/snapshots
func CreateDashboardSnapshot(c *m.ReqContext, cmd m.CreateDashboardSnapshotCommand) {
if cmd.Name == "" {
cmd.Name = "Unnamed snapshot"
}

var url string
cmd.ExternalUrl = ""
cmd.OrgId = c.OrgId
cmd.UserId = c.UserId

if cmd.External {
// external snapshot ref requires key and delete key
if cmd.Key == "" || cmd.DeleteKey == "" {
c.JsonApiErr(400, "Missing key and delete key for external snapshot", nil)
if !setting.ExternalEnabled {
c.JsonApiErr(403, "External dashboard creation is disabled", nil)
return
}

response, err := createExternalDashboardSnapshot(cmd)
if err != nil {
c.JsonApiErr(500, "Failed to create external snaphost", err)
return
}

cmd.OrgId = -1
cmd.UserId = -1
url = response.Url
cmd.Key = response.Key
cmd.DeleteKey = response.DeleteKey
cmd.ExternalUrl = response.Url
cmd.ExternalDeleteUrl = response.DeleteUrl
cmd.Dashboard = simplejson.New()

metrics.M_Api_Dashboard_Snapshot_External.Inc()
} else {
cmd.Key = util.GetRandomString(32)
cmd.DeleteKey = util.GetRandomString(32)
cmd.OrgId = c.OrgId
cmd.UserId = c.UserId
url = setting.ToAbsUrl("dashboard/snapshot/" + cmd.Key)

metrics.M_Api_Dashboard_Snapshot_Create.Inc()
}

Expand All @@ -51,7 +114,7 @@ func CreateDashboardSnapshot(c *m.ReqContext, cmd m.CreateDashboardSnapshotComma
c.JSON(200, util.DynMap{
"key": cmd.Key,
"deleteKey": cmd.DeleteKey,
"url": setting.ToAbsUrl("dashboard/snapshot/" + cmd.Key),
"url": url,
"deleteUrl": setting.ToAbsUrl("api/snapshots-delete/" + cmd.DeleteKey),
})
}
Expand Down Expand Up @@ -91,6 +154,33 @@ func GetDashboardSnapshot(c *m.ReqContext) {
c.JSON(200, dto)
}

func deleteExternalDashboardSnapshot(externalUrl string) error {
response, err := client.Get(externalUrl)
if err != nil {
return err
}
defer response.Body.Close()

if response.StatusCode == 200 {
return nil
}

// Gracefully ignore "snapshot not found" errors as they could have already
// been removed either via the cleanup script or by request.
if response.StatusCode == 500 {
var respJson map[string]interface{}
if err := json.NewDecoder(response.Body).Decode(&respJson); err != nil {
return err
}

if respJson["message"] == "Failed to get dashboard snapshot" {
return nil
}
}

return fmt.Errorf("Unexpected response when deleting external snapshot. Status code: %d", response.StatusCode)
}

// GET /api/snapshots-delete/:deleteKey
func DeleteDashboardSnapshotByDeleteKey(c *m.ReqContext) Response {
key := c.Params(":deleteKey")
Expand All @@ -102,6 +192,13 @@ func DeleteDashboardSnapshotByDeleteKey(c *m.ReqContext) Response {
return Error(500, "Failed to get dashboard snapshot", err)
}

if query.Result.External {
err := deleteExternalDashboardSnapshot(query.Result.ExternalDeleteUrl)
if err != nil {
return Error(500, "Failed to delete external dashboard", err)
}
}

cmd := &m.DeleteDashboardSnapshotCommand{DeleteKey: query.Result.DeleteKey}

if err := bus.Dispatch(cmd); err != nil {
Expand Down Expand Up @@ -138,6 +235,13 @@ func DeleteDashboardSnapshot(c *m.ReqContext) Response {
return Error(403, "Access denied to this snapshot", nil)
}

if query.Result.External {
err := deleteExternalDashboardSnapshot(query.Result.ExternalDeleteUrl)
if err != nil {
return Error(500, "Failed to delete external dashboard", err)
}
}

cmd := &m.DeleteDashboardSnapshotCommand{DeleteKey: query.Result.DeleteKey}

if err := bus.Dispatch(cmd); err != nil {
Expand Down
Loading

0 comments on commit 9c086be

Please sign in to comment.