mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Added basic auth to data source edit/create, add support for basic auth in data source proxy code, Closes #1510
This commit is contained in:
parent
ea1164322b
commit
9710771f16
@ -73,7 +73,10 @@ func Register(r *macaron.Macaron) {
|
||||
|
||||
// Data sources
|
||||
r.Group("/datasources", func() {
|
||||
r.Combo("/").Get(GetDataSources).Put(AddDataSource).Post(bind(m.UpdateDataSourceCommand{}), UpdateDataSource)
|
||||
r.Combo("/").
|
||||
Get(GetDataSources).
|
||||
Put(bind(m.AddDataSourceCommand{}), AddDataSource).
|
||||
Post(bind(m.UpdateDataSourceCommand{}), UpdateDataSource)
|
||||
r.Delete("/:id", DeleteDataSource)
|
||||
r.Get("/:id", GetDataSourceById)
|
||||
r.Get("/plugins", GetDataSourcePlugins)
|
||||
|
@ -35,6 +35,10 @@ func NewReverseProxy(ds *m.DataSource, proxyPath string) *httputil.ReverseProxy
|
||||
} else {
|
||||
req.URL.Path = util.JoinUrlFragments(target.Path, proxyPath)
|
||||
}
|
||||
|
||||
if ds.BasicAuth {
|
||||
req.Header.Add("Authorization", util.GetBasicAuthHeader(ds.BasicAuthUser, ds.BasicAuthPassword))
|
||||
}
|
||||
}
|
||||
|
||||
return &httputil.ReverseProxy{Director: director}
|
||||
|
@ -50,18 +50,20 @@ func GetDataSourceById(c *middleware.Context) {
|
||||
ds := query.Result
|
||||
|
||||
c.JSON(200, &dtos.DataSource{
|
||||
Id: ds.Id,
|
||||
OrgId: ds.OrgId,
|
||||
Name: ds.Name,
|
||||
Url: ds.Url,
|
||||
Type: ds.Type,
|
||||
Access: ds.Access,
|
||||
Password: ds.Password,
|
||||
Database: ds.Database,
|
||||
User: ds.User,
|
||||
BasicAuth: ds.BasicAuth,
|
||||
IsDefault: ds.IsDefault,
|
||||
JsonData: ds.JsonData,
|
||||
Id: ds.Id,
|
||||
OrgId: ds.OrgId,
|
||||
Name: ds.Name,
|
||||
Url: ds.Url,
|
||||
Type: ds.Type,
|
||||
Access: ds.Access,
|
||||
Password: ds.Password,
|
||||
Database: ds.Database,
|
||||
User: ds.User,
|
||||
BasicAuth: ds.BasicAuth,
|
||||
BasicAuthUser: ds.BasicAuthUser,
|
||||
BasicAuthPassword: ds.BasicAuthPassword,
|
||||
IsDefault: ds.IsDefault,
|
||||
JsonData: ds.JsonData,
|
||||
})
|
||||
}
|
||||
|
||||
@ -84,14 +86,7 @@ func DeleteDataSource(c *middleware.Context) {
|
||||
c.JsonOK("Data source deleted")
|
||||
}
|
||||
|
||||
func AddDataSource(c *middleware.Context) {
|
||||
cmd := m.AddDataSourceCommand{}
|
||||
|
||||
if !c.JsonBody(&cmd) {
|
||||
c.JsonApiErr(400, "Validation failed", nil)
|
||||
return
|
||||
}
|
||||
|
||||
func AddDataSource(c *middleware.Context, cmd m.AddDataSourceCommand) {
|
||||
cmd.OrgId = c.OrgId
|
||||
|
||||
if err := bus.Dispatch(&cmd); err != nil {
|
||||
|
@ -38,18 +38,20 @@ type Dashboard struct {
|
||||
}
|
||||
|
||||
type DataSource struct {
|
||||
Id int64 `json:"id"`
|
||||
OrgId int64 `json:"orgId"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
Access m.DsAccess `json:"access"`
|
||||
Url string `json:"url"`
|
||||
Password string `json:"password"`
|
||||
User string `json:"user"`
|
||||
Database string `json:"database"`
|
||||
BasicAuth bool `json:"basicAuth"`
|
||||
IsDefault bool `json:"isDefault"`
|
||||
JsonData map[string]interface{} `json:"jsonData"`
|
||||
Id int64 `json:"id"`
|
||||
OrgId int64 `json:"orgId"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
Access m.DsAccess `json:"access"`
|
||||
Url string `json:"url"`
|
||||
Password string `json:"password"`
|
||||
User string `json:"user"`
|
||||
Database string `json:"database"`
|
||||
BasicAuth bool `json:"basicAuth"`
|
||||
BasicAuthUser string `json:"basicAuthUser"`
|
||||
BasicAuthPassword string `json:"basicAuthPassword"`
|
||||
IsDefault bool `json:"isDefault"`
|
||||
JsonData map[string]interface{} `json:"jsonData"`
|
||||
}
|
||||
|
||||
type MetricQueryResultDto struct {
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
m "github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
)
|
||||
|
||||
func getFrontendSettingsMap(c *middleware.Context) (map[string]interface{}, error) {
|
||||
@ -53,16 +54,18 @@ func getFrontendSettingsMap(c *middleware.Context) (map[string]interface{}, erro
|
||||
defaultDatasource = ds.Name
|
||||
}
|
||||
|
||||
if ds.Type == m.DS_INFLUXDB_08 {
|
||||
if ds.Access == m.DS_ACCESS_DIRECT {
|
||||
if ds.Access == m.DS_ACCESS_DIRECT {
|
||||
if ds.BasicAuth {
|
||||
dsMap["basicAuth"] = util.GetBasicAuthHeader(ds.BasicAuthUser, ds.BasicAuthPassword)
|
||||
}
|
||||
|
||||
if ds.Type == m.DS_INFLUXDB_08 {
|
||||
dsMap["username"] = ds.User
|
||||
dsMap["password"] = ds.Password
|
||||
dsMap["url"] = url + "/db/" + ds.Database
|
||||
}
|
||||
}
|
||||
|
||||
if ds.Type == m.DS_INFLUXDB {
|
||||
if ds.Access == m.DS_ACCESS_DIRECT {
|
||||
if ds.Type == m.DS_INFLUXDB {
|
||||
dsMap["username"] = ds.User
|
||||
dsMap["password"] = ds.Password
|
||||
dsMap["database"] = ds.Database
|
||||
|
@ -49,31 +49,39 @@ type DataSource struct {
|
||||
|
||||
// Also acts as api DTO
|
||||
type AddDataSourceCommand struct {
|
||||
OrgId int64 `json:"-"`
|
||||
Name string
|
||||
Type string
|
||||
Access DsAccess
|
||||
Url string
|
||||
Password string
|
||||
Database string
|
||||
User string
|
||||
IsDefault bool
|
||||
Name string `json:"name" binding:"Required"`
|
||||
Type string `json:"type" binding:"Required"`
|
||||
Access DsAccess `json:"access" binding:"Required"`
|
||||
Url string `json:"url"`
|
||||
Password string `json:"password"`
|
||||
Database string `json:"database"`
|
||||
User string `json:"user"`
|
||||
BasicAuth bool `json:"basicAuth"`
|
||||
BasicAuthUser string `json:"basicAuthUser"`
|
||||
BasicAuthPassword string `json:"basicAuthPassword"`
|
||||
IsDefault bool `json:"isDefault"`
|
||||
JsonData map[string]interface{} `json:"jsonData"`
|
||||
|
||||
OrgId int64 `json:"-"`
|
||||
|
||||
Result *DataSource
|
||||
}
|
||||
|
||||
// Also acts as api DTO
|
||||
type UpdateDataSourceCommand struct {
|
||||
Id int64 `json:"id" binding:"Required"`
|
||||
Name string `json:"name" binding:"Required"`
|
||||
Type string `json:"type" binding:"Required"`
|
||||
Access DsAccess `json:"access" binding:"Required"`
|
||||
Url string `json:"url"`
|
||||
Password string `json:"password"`
|
||||
User string `json:"user"`
|
||||
Database string `json:"database"`
|
||||
IsDefault bool `json:"isDefault"`
|
||||
JsonData map[string]interface{} `json:"jsonData"`
|
||||
Id int64 `json:"id" binding:"Required"`
|
||||
Name string `json:"name" binding:"Required"`
|
||||
Type string `json:"type" binding:"Required"`
|
||||
Access DsAccess `json:"access" binding:"Required"`
|
||||
Url string `json:"url"`
|
||||
Password string `json:"password"`
|
||||
User string `json:"user"`
|
||||
Database string `json:"database"`
|
||||
BasicAuth bool `json:"basicAuth"`
|
||||
BasicAuthUser string `json:"basicAuthUser"`
|
||||
BasicAuthPassword string `json:"basicAuthPassword"`
|
||||
IsDefault bool `json:"isDefault"`
|
||||
JsonData map[string]interface{} `json:"jsonData"`
|
||||
|
||||
OrgId int64 `json:"-"`
|
||||
}
|
||||
|
@ -57,17 +57,21 @@ func AddDataSource(cmd *m.AddDataSourceCommand) error {
|
||||
|
||||
return inTransaction(func(sess *xorm.Session) error {
|
||||
ds := &m.DataSource{
|
||||
OrgId: cmd.OrgId,
|
||||
Name: cmd.Name,
|
||||
Type: cmd.Type,
|
||||
Access: cmd.Access,
|
||||
Url: cmd.Url,
|
||||
User: cmd.User,
|
||||
Password: cmd.Password,
|
||||
Database: cmd.Database,
|
||||
IsDefault: cmd.IsDefault,
|
||||
Created: time.Now(),
|
||||
Updated: time.Now(),
|
||||
OrgId: cmd.OrgId,
|
||||
Name: cmd.Name,
|
||||
Type: cmd.Type,
|
||||
Access: cmd.Access,
|
||||
Url: cmd.Url,
|
||||
User: cmd.User,
|
||||
Password: cmd.Password,
|
||||
Database: cmd.Database,
|
||||
IsDefault: cmd.IsDefault,
|
||||
BasicAuth: cmd.BasicAuth,
|
||||
BasicAuthUser: cmd.BasicAuthUser,
|
||||
BasicAuthPassword: cmd.BasicAuthPassword,
|
||||
JsonData: cmd.JsonData,
|
||||
Created: time.Now(),
|
||||
Updated: time.Now(),
|
||||
}
|
||||
|
||||
if _, err := sess.Insert(ds); err != nil {
|
||||
@ -97,21 +101,25 @@ func UpdateDataSource(cmd *m.UpdateDataSourceCommand) error {
|
||||
|
||||
return inTransaction(func(sess *xorm.Session) error {
|
||||
ds := &m.DataSource{
|
||||
Id: cmd.Id,
|
||||
OrgId: cmd.OrgId,
|
||||
Name: cmd.Name,
|
||||
Type: cmd.Type,
|
||||
Access: cmd.Access,
|
||||
Url: cmd.Url,
|
||||
User: cmd.User,
|
||||
Password: cmd.Password,
|
||||
Database: cmd.Database,
|
||||
IsDefault: cmd.IsDefault,
|
||||
JsonData: cmd.JsonData,
|
||||
Updated: time.Now(),
|
||||
Id: cmd.Id,
|
||||
OrgId: cmd.OrgId,
|
||||
Name: cmd.Name,
|
||||
Type: cmd.Type,
|
||||
Access: cmd.Access,
|
||||
Url: cmd.Url,
|
||||
User: cmd.User,
|
||||
Password: cmd.Password,
|
||||
Database: cmd.Database,
|
||||
IsDefault: cmd.IsDefault,
|
||||
BasicAuth: cmd.BasicAuth,
|
||||
BasicAuthUser: cmd.BasicAuthUser,
|
||||
BasicAuthPassword: cmd.BasicAuthPassword,
|
||||
JsonData: cmd.JsonData,
|
||||
Updated: time.Now(),
|
||||
}
|
||||
|
||||
sess.UseBool("is_default")
|
||||
sess.UseBool("basic_auth")
|
||||
|
||||
_, err := sess.Where("id=? and org_id=?", ds.Id, ds.OrgId).Update(ds)
|
||||
if err != nil {
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"crypto/md5"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"hash"
|
||||
@ -74,3 +75,8 @@ func PBKDF2(password, salt []byte, iter, keyLen int, h func() hash.Hash) []byte
|
||||
}
|
||||
return dk[:keyLen]
|
||||
}
|
||||
|
||||
func GetBasicAuthHeader(user string, password string) string {
|
||||
var userAndPass = user + ":" + password
|
||||
return "Basic " + base64.StdEncoding.EncodeToString([]byte(userAndPass))
|
||||
}
|
||||
|
16
pkg/util/encoding_test.go
Normal file
16
pkg/util/encoding_test.go
Normal file
@ -0,0 +1,16 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
func TestEncoding(t *testing.T) {
|
||||
|
||||
Convey("When generating base64 header", t, func() {
|
||||
result := GetBasicAuthHeader("grafana", "1234")
|
||||
|
||||
So(result, ShouldEqual, "Z3JhZmFuYToxMjM0")
|
||||
})
|
||||
}
|
@ -41,7 +41,9 @@
|
||||
</ul>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
<div class="tight-form last">
|
||||
|
||||
<h5>Http settings</h5>
|
||||
<div class="tight-form">
|
||||
<ul class="tight-form-list">
|
||||
<li class="tight-form-item" style="width: 80px">
|
||||
Url
|
||||
@ -58,6 +60,31 @@
|
||||
</ul>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
<div class="tight-form">
|
||||
<ul class="tight-form-list">
|
||||
<li class="tight-form-item" style="width: 80px">
|
||||
Basic Auth
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
Enable
|
||||
<input class="cr1" id="current.basicAuth" type="checkbox" ng-model="current.basicAuth" ng-checked="current.basicAuth">
|
||||
<label for="current.basicAuth" class="cr1"></label>
|
||||
</li>
|
||||
<li class="tight-form-item" ng-if="current.basicAuth">
|
||||
User
|
||||
</li>
|
||||
<li ng-if="current.basicAuth">
|
||||
<input type="text" class="tight-form-input input-medium" style="width: 139px" ng-model='current.basicAuthUser' placeholder="user" required></input>
|
||||
</li>
|
||||
<li class="tight-form-item" style="width: 67px" ng-if="current.basicAuth">
|
||||
Password
|
||||
</li>
|
||||
<li ng-if="current.basicAuth">
|
||||
<input type="password" class="tight-form-input input-medium" ng-model='current.basicAuthPassword' placeholder="password" required></input>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
|
||||
<div ng-include="datasourceMeta.partials.config" ng-if="datasourceMeta.partials.config"></div>
|
||||
<br>
|
||||
|
@ -34,7 +34,7 @@ function (angular, _, config, kbn, moment) {
|
||||
if (this.basicAuth) {
|
||||
options.withCredentials = true;
|
||||
options.headers = {
|
||||
"Authorization": "Basic " + this.basicAuth
|
||||
"Authorization": this.basicAuth
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -212,7 +212,7 @@ function (angular, _, $, config, kbn, moment) {
|
||||
}
|
||||
if (this.basicAuth) {
|
||||
options.headers = options.headers || {};
|
||||
options.headers.Authorization = 'Basic ' + this.basicAuth;
|
||||
options.headers.Authorization = this.basicAuth;
|
||||
}
|
||||
|
||||
options.url = this.url + options.url;
|
||||
|
@ -181,7 +181,7 @@ function (angular, _, kbn, InfluxSeries, InfluxQueryBuilder) {
|
||||
|
||||
options.headers = options.headers || {};
|
||||
if (self.basicAuth) {
|
||||
options.headers.Authorization = 'Basic ' + self.basicAuth;
|
||||
options.headers.Authorization = self.basicAuth;
|
||||
}
|
||||
|
||||
return $http(options).success(function (data) {
|
||||
|
Loading…
Reference in New Issue
Block a user