mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Merge branch 'mattbostock-verify_datasource_tls'
This commit is contained in:
commit
4ca3cc90dd
@ -6,14 +6,13 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gopkg.in/macaron.v1"
|
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/api/pluginproxy"
|
"github.com/grafana/grafana/pkg/api/pluginproxy"
|
||||||
"github.com/grafana/grafana/pkg/log"
|
"github.com/grafana/grafana/pkg/log"
|
||||||
"github.com/grafana/grafana/pkg/middleware"
|
"github.com/grafana/grafana/pkg/middleware"
|
||||||
m "github.com/grafana/grafana/pkg/models"
|
m "github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/plugins"
|
"github.com/grafana/grafana/pkg/plugins"
|
||||||
"github.com/grafana/grafana/pkg/util"
|
"github.com/grafana/grafana/pkg/util"
|
||||||
|
macaron "gopkg.in/macaron.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
var pluginProxyTransport = &http.Transport{
|
var pluginProxyTransport = &http.Transport{
|
||||||
|
@ -3,6 +3,7 @@ package models
|
|||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
|
"errors"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"sync"
|
"sync"
|
||||||
@ -45,9 +46,16 @@ func (ds *DataSource) GetHttpTransport() (*http.Transport, error) {
|
|||||||
return t.Transport, nil
|
return t.Transport, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var tlsSkipVerify, tlsClientAuth, tlsAuthWithCACert bool
|
||||||
|
if ds.JsonData != nil {
|
||||||
|
tlsClientAuth = ds.JsonData.Get("tlsAuth").MustBool(false)
|
||||||
|
tlsAuthWithCACert = ds.JsonData.Get("tlsAuthWithCACert").MustBool(false)
|
||||||
|
tlsSkipVerify = ds.JsonData.Get("tlsSkipVerify").MustBool(false)
|
||||||
|
}
|
||||||
|
|
||||||
transport := &http.Transport{
|
transport := &http.Transport{
|
||||||
TLSClientConfig: &tls.Config{
|
TLSClientConfig: &tls.Config{
|
||||||
InsecureSkipVerify: true,
|
InsecureSkipVerify: tlsSkipVerify,
|
||||||
Renegotiation: tls.RenegotiateFreelyAsClient,
|
Renegotiation: tls.RenegotiateFreelyAsClient,
|
||||||
},
|
},
|
||||||
Proxy: http.ProxyFromEnvironment,
|
Proxy: http.ProxyFromEnvironment,
|
||||||
@ -62,30 +70,24 @@ func (ds *DataSource) GetHttpTransport() (*http.Transport, error) {
|
|||||||
IdleConnTimeout: 90 * time.Second,
|
IdleConnTimeout: 90 * time.Second,
|
||||||
}
|
}
|
||||||
|
|
||||||
var tlsAuth, tlsAuthWithCACert bool
|
if tlsClientAuth || tlsAuthWithCACert {
|
||||||
if ds.JsonData != nil {
|
|
||||||
tlsAuth = ds.JsonData.Get("tlsAuth").MustBool(false)
|
|
||||||
tlsAuthWithCACert = ds.JsonData.Get("tlsAuthWithCACert").MustBool(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
if tlsAuth {
|
|
||||||
transport.TLSClientConfig.InsecureSkipVerify = false
|
|
||||||
|
|
||||||
decrypted := ds.SecureJsonData.Decrypt()
|
decrypted := ds.SecureJsonData.Decrypt()
|
||||||
|
|
||||||
if tlsAuthWithCACert && len(decrypted["tlsCACert"]) > 0 {
|
if tlsAuthWithCACert && len(decrypted["tlsCACert"]) > 0 {
|
||||||
caPool := x509.NewCertPool()
|
caPool := x509.NewCertPool()
|
||||||
ok := caPool.AppendCertsFromPEM([]byte(decrypted["tlsCACert"]))
|
ok := caPool.AppendCertsFromPEM([]byte(decrypted["tlsCACert"]))
|
||||||
if ok {
|
if !ok {
|
||||||
transport.TLSClientConfig.RootCAs = caPool
|
return nil, errors.New("Failed to parse TLS CA PEM certificate")
|
||||||
}
|
}
|
||||||
|
transport.TLSClientConfig.RootCAs = caPool
|
||||||
}
|
}
|
||||||
|
|
||||||
cert, err := tls.X509KeyPair([]byte(decrypted["tlsClientCert"]), []byte(decrypted["tlsClientKey"]))
|
if tlsClientAuth {
|
||||||
if err != nil {
|
cert, err := tls.X509KeyPair([]byte(decrypted["tlsClientCert"]), []byte(decrypted["tlsClientKey"]))
|
||||||
return nil, err
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
transport.TLSClientConfig.Certificates = []tls.Certificate{cert}
|
||||||
}
|
}
|
||||||
transport.TLSClientConfig.Certificates = []tls.Certificate{cert}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ptc.cache[ds.Id] = cachedTransport{
|
ptc.cache[ds.Id] = cachedTransport{
|
||||||
|
@ -29,61 +29,140 @@ func TestDataSourceCache(t *testing.T) {
|
|||||||
Convey("Should be using the cached proxy", func() {
|
Convey("Should be using the cached proxy", func() {
|
||||||
So(t2, ShouldEqual, t1)
|
So(t2, ShouldEqual, t1)
|
||||||
})
|
})
|
||||||
|
Convey("Should verify TLS by default", func() {
|
||||||
|
So(t1.TLSClientConfig.InsecureSkipVerify, ShouldEqual, false)
|
||||||
|
})
|
||||||
|
Convey("Should have no TLS client certificate configured", func() {
|
||||||
|
So(len(t1.TLSClientConfig.Certificates), ShouldEqual, 0)
|
||||||
|
})
|
||||||
|
Convey("Should have no user-supplied TLS CA onfigured", func() {
|
||||||
|
So(t1.TLSClientConfig.RootCAs, ShouldBeNil)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
Convey("When getting kubernetes datasource proxy", t, func() {
|
Convey("When caching a datasource proxy then updating it", t, func() {
|
||||||
|
clearCache()
|
||||||
|
setting.SecretKey = "password"
|
||||||
|
|
||||||
|
json := simplejson.New()
|
||||||
|
json.Set("tlsAuthWithCACert", true)
|
||||||
|
|
||||||
|
tlsCaCert, err := util.Encrypt([]byte(caCert), "password")
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
ds := DataSource{
|
||||||
|
Id: 1,
|
||||||
|
Url: "http://k8s:8001",
|
||||||
|
Type: "Kubernetes",
|
||||||
|
SecureJsonData: map[string][]byte{"tlsCACert": tlsCaCert},
|
||||||
|
Updated: time.Now().Add(-2 * time.Minute),
|
||||||
|
}
|
||||||
|
|
||||||
|
t1, err := ds.GetHttpTransport()
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
|
Convey("Should verify TLS by default", func() {
|
||||||
|
So(t1.TLSClientConfig.InsecureSkipVerify, ShouldEqual, false)
|
||||||
|
})
|
||||||
|
Convey("Should have no TLS client certificate configured", func() {
|
||||||
|
So(len(t1.TLSClientConfig.Certificates), ShouldEqual, 0)
|
||||||
|
})
|
||||||
|
Convey("Should have no user-supplied TLS CA configured", func() {
|
||||||
|
So(t1.TLSClientConfig.RootCAs, ShouldBeNil)
|
||||||
|
})
|
||||||
|
|
||||||
|
ds.JsonData = nil
|
||||||
|
ds.SecureJsonData = map[string][]byte{}
|
||||||
|
ds.Updated = time.Now()
|
||||||
|
|
||||||
|
t2, err := ds.GetHttpTransport()
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
|
Convey("Should have no user-supplied TLS CA configured after the update", func() {
|
||||||
|
So(t2.TLSClientConfig.RootCAs, ShouldBeNil)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("When caching a datasource proxy with TLS client authentication enabled", t, func() {
|
||||||
clearCache()
|
clearCache()
|
||||||
setting.SecretKey = "password"
|
setting.SecretKey = "password"
|
||||||
|
|
||||||
json := simplejson.New()
|
json := simplejson.New()
|
||||||
json.Set("tlsAuth", true)
|
json.Set("tlsAuth", true)
|
||||||
|
|
||||||
|
tlsClientCert, err := util.Encrypt([]byte(clientCert), "password")
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
tlsClientKey, err := util.Encrypt([]byte(clientKey), "password")
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
|
ds := DataSource{
|
||||||
|
Id: 1,
|
||||||
|
Url: "http://k8s:8001",
|
||||||
|
Type: "Kubernetes",
|
||||||
|
JsonData: json,
|
||||||
|
SecureJsonData: map[string][]byte{
|
||||||
|
"tlsClientCert": tlsClientCert,
|
||||||
|
"tlsClientKey": tlsClientKey,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
tr, err := ds.GetHttpTransport()
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
|
Convey("Should verify TLS by default", func() {
|
||||||
|
So(tr.TLSClientConfig.InsecureSkipVerify, ShouldEqual, false)
|
||||||
|
})
|
||||||
|
Convey("Should have a TLS client certificate configured", func() {
|
||||||
|
So(len(tr.TLSClientConfig.Certificates), ShouldEqual, 1)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("When caching a datasource proxy with a user-supplied TLS CA", t, func() {
|
||||||
|
clearCache()
|
||||||
|
setting.SecretKey = "password"
|
||||||
|
|
||||||
|
json := simplejson.New()
|
||||||
json.Set("tlsAuthWithCACert", true)
|
json.Set("tlsAuthWithCACert", true)
|
||||||
|
|
||||||
t := time.Now()
|
tlsCaCert, err := util.Encrypt([]byte(caCert), "password")
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
ds := DataSource{
|
ds := DataSource{
|
||||||
Url: "http://k8s:8001",
|
Id: 1,
|
||||||
Type: "Kubernetes",
|
Url: "http://k8s:8001",
|
||||||
Updated: t.Add(-2 * time.Minute),
|
Type: "Kubernetes",
|
||||||
|
JsonData: json,
|
||||||
|
SecureJsonData: map[string][]byte{"tlsCACert": tlsCaCert},
|
||||||
}
|
}
|
||||||
|
|
||||||
transport, err := ds.GetHttpTransport()
|
tr, err := ds.GetHttpTransport()
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
Convey("Should have no cert", func() {
|
Convey("Should verify TLS by default", func() {
|
||||||
So(transport.TLSClientConfig.InsecureSkipVerify, ShouldEqual, true)
|
So(tr.TLSClientConfig.InsecureSkipVerify, ShouldEqual, false)
|
||||||
})
|
})
|
||||||
|
Convey("Should have a TLS CA configured", func() {
|
||||||
|
So(len(tr.TLSClientConfig.RootCAs.Subjects()), ShouldEqual, 1)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
ds.JsonData = json
|
Convey("When caching a datasource proxy when user skips TLS verification", t, func() {
|
||||||
|
clearCache()
|
||||||
|
|
||||||
tlsCaCert, _ := util.Encrypt([]byte(caCert), "password")
|
json := simplejson.New()
|
||||||
tlsClientCert, _ := util.Encrypt([]byte(clientCert), "password")
|
json.Set("tlsSkipVerify", true)
|
||||||
tlsClientKey, _ := util.Encrypt([]byte(clientKey), "password")
|
|
||||||
|
|
||||||
ds.SecureJsonData = map[string][]byte{
|
ds := DataSource{
|
||||||
"tlsCACert": tlsCaCert,
|
Id: 1,
|
||||||
"tlsClientCert": tlsClientCert,
|
Url: "http://k8s:8001",
|
||||||
"tlsClientKey": tlsClientKey,
|
Type: "Kubernetes",
|
||||||
|
JsonData: json,
|
||||||
}
|
}
|
||||||
ds.Updated = t.Add(-1 * time.Minute)
|
|
||||||
|
|
||||||
transport, err = ds.GetHttpTransport()
|
tr, err := ds.GetHttpTransport()
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
Convey("Should add cert", func() {
|
Convey("Should skip TLS verification", func() {
|
||||||
So(transport.TLSClientConfig.InsecureSkipVerify, ShouldEqual, false)
|
So(tr.TLSClientConfig.InsecureSkipVerify, ShouldEqual, true)
|
||||||
So(len(transport.TLSClientConfig.Certificates), ShouldEqual, 1)
|
|
||||||
})
|
|
||||||
|
|
||||||
ds.JsonData = nil
|
|
||||||
ds.SecureJsonData = map[string][]byte{}
|
|
||||||
ds.Updated = t
|
|
||||||
|
|
||||||
transport, err = ds.GetHttpTransport()
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
|
|
||||||
Convey("Should remove cert", func() {
|
|
||||||
So(transport.TLSClientConfig.InsecureSkipVerify, ShouldEqual, true)
|
|
||||||
So(len(transport.TLSClientConfig.Certificates), ShouldEqual, 0)
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -115,7 +194,8 @@ FHoXIyGOdq1chmRVocdGBCF8fUoGIbuF14r53rpvcbEKtKnnP8+96luKAZLq0a4n
|
|||||||
3lb92xM=
|
3lb92xM=
|
||||||
-----END CERTIFICATE-----`
|
-----END CERTIFICATE-----`
|
||||||
|
|
||||||
const clientCert string = `-----BEGIN CERTIFICATE-----
|
const clientCert string = `
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
MIICsjCCAZoCCQCcd8sOfstQLzANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxj
|
MIICsjCCAZoCCQCcd8sOfstQLzANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxj
|
||||||
YS1rOHMtc3RobG0wHhcNMTYxMTAyMDkyNTE1WhcNMTcxMTAyMDkyNTE1WjAfMR0w
|
YS1rOHMtc3RobG0wHhcNMTYxMTAyMDkyNTE1WhcNMTcxMTAyMDkyNTE1WjAfMR0w
|
||||||
GwYDVQQDDBRhZG0tZGFuaWVsLWs4cy1zdGhsbTCCASIwDQYJKoZIhvcNAQEBBQAD
|
GwYDVQQDDBRhZG0tZGFuaWVsLWs4cy1zdGhsbTCCASIwDQYJKoZIhvcNAQEBBQAD
|
||||||
|
@ -1,23 +1,23 @@
|
|||||||
|
|
||||||
|
|
||||||
<div class="gf-form-group">
|
<div class="gf-form-group">
|
||||||
<h3 class="page-heading">Http settings</h3>
|
<h3 class="page-heading">HTTP settings</h3>
|
||||||
<div class="gf-form-group">
|
<div class="gf-form-group">
|
||||||
<div class="gf-form-inline">
|
<div class="gf-form-inline">
|
||||||
<div class="gf-form max-width-30">
|
<div class="gf-form max-width-30">
|
||||||
<span class="gf-form-label width-7">Url</span>
|
<span class="gf-form-label width-7">URL</span>
|
||||||
<input class="gf-form-input" type="text"
|
<input class="gf-form-input" type="text"
|
||||||
ng-model='current.url' placeholder="{{suggestUrl}}"
|
ng-model='current.url' placeholder="{{suggestUrl}}"
|
||||||
bs-typeahead="getSuggestUrls" min-length="0"
|
bs-typeahead="getSuggestUrls" min-length="0"
|
||||||
ng-pattern="/^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/" required></input>
|
ng-pattern="/^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/" required></input>
|
||||||
<info-popover mode="right-absolute">
|
<info-popover mode="right-absolute">
|
||||||
<p>Specify a complete HTTP url (for example http://your_server:8080)</p>
|
<p>Specify a complete HTTP URL (for example http://your_server:8080)</p>
|
||||||
<span ng-show="current.access === 'direct'">
|
<span ng-show="current.access === 'direct'">
|
||||||
Your access method is <em>Direct</em>, this means the url
|
Your access method is <em>Direct</em>, this means the URL
|
||||||
needs to be accessible from the browser.
|
needs to be accessible from the browser.
|
||||||
</span>
|
</span>
|
||||||
<span ng-show="current.access === 'proxy'">
|
<span ng-show="current.access === 'proxy'">
|
||||||
Your access method is currently <em>Proxy</em>, this means the url
|
Your access method is currently <em>Proxy</em>, this means the URL
|
||||||
needs to be accessible from the grafana backend.
|
needs to be accessible from the grafana backend.
|
||||||
</span>
|
</span>
|
||||||
</info-popover>
|
</info-popover>
|
||||||
@ -30,7 +30,7 @@
|
|||||||
<div class="gf-form-select-wrapper gf-form-select-wrapper--has-help-icon max-width-24">
|
<div class="gf-form-select-wrapper gf-form-select-wrapper--has-help-icon max-width-24">
|
||||||
<select class="gf-form-input" ng-model="current.access" ng-options="f for f in ['direct', 'proxy']"></select>
|
<select class="gf-form-input" ng-model="current.access" ng-options="f for f in ['direct', 'proxy']"></select>
|
||||||
<info-popover mode="right-absolute">
|
<info-popover mode="right-absolute">
|
||||||
Direct = url is used directly from browser<br>
|
Direct = URL is used directly from browser<br>
|
||||||
Proxy = Grafana backend will proxy the request
|
Proxy = Grafana backend will proxy the request
|
||||||
</info-popover>
|
</info-popover>
|
||||||
</div>
|
</div>
|
||||||
@ -38,27 +38,21 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h3 class="page-heading">Http Auth</h3>
|
<h3 class="page-heading">HTTP Auth</h3>
|
||||||
|
<div class="gf-form-group">
|
||||||
|
<div class="gf-form-inline">
|
||||||
|
<gf-form-switch class="gf-form" label="Basic Auth" checked="current.basicAuth" label-class="width-8" switch-class="max-width-6"></gf-form-switch>
|
||||||
|
<gf-form-switch class="gf-form" label="With Credentials" tooltip="Whether credentials such as cookies or auth headers should be sent with cross-site requests." checked="current.withCredentials" label-class="width-11" switch-class="max-width-6"></gf-form-switch>
|
||||||
|
</div>
|
||||||
|
<div class="gf-form-inline">
|
||||||
|
<gf-form-switch class="gf-form" ng-if="current.access=='proxy'" label="TLS Client Auth" label-class="width-8" checked="current.jsonData.tlsAuth" switch-class="max-width-6"></gf-form-switch>
|
||||||
|
<gf-form-switch class="gf-form" ng-if="current.access=='proxy'" label="With CA Cert" tooltip="Needed for verifing self-signed TLS Certs" checked="current.jsonData.tlsAuthWithCACert" label-class="width-11" switch-class="max-width-6"></gf-form-switch>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="gf-form-inline">
|
<div class="gf-form-inline">
|
||||||
<gf-form-switch class="gf-form"
|
<gf-form-switch class="gf-form" ng-if="current.access=='proxy'" label="Skip TLS Verification (Insecure)" label-class="width-16" checked="current.jsonData.tlsSkipVerify" switch-class="max-width-6"></gf-form-switch>
|
||||||
label="Basic Auth"
|
</div>
|
||||||
checked="current.basicAuth" label-class="width-8" switch-class="max-width-6">
|
|
||||||
</gf-form-switch>
|
|
||||||
<gf-form-switch class="gf-form"
|
|
||||||
label="With Credentials" tooltip="Whether credentials such as cookies or auth headers should be sent with cross-site requests."
|
|
||||||
checked="current.withCredentials" label-class="width-11" switch-class="max-width-6">
|
|
||||||
</gf-form-switch>
|
|
||||||
</div>
|
|
||||||
<div class="gf-form-inline">
|
|
||||||
<gf-form-switch class="gf-form" ng-if="current.access=='proxy'"
|
|
||||||
label="TLS Client Auth" label-class="width-8"
|
|
||||||
checked="current.jsonData.tlsAuth" switch-class="max-width-6">
|
|
||||||
</gf-form-switch>
|
|
||||||
<gf-form-switch class="gf-form" ng-if="current.access=='proxy'"
|
|
||||||
label="With CA Cert" tooltip="Optional. Needed for self-signed TLS Certs."
|
|
||||||
checked="current.jsonData.tlsAuthWithCACert" label-class="width-11" switch-class="max-width-6">
|
|
||||||
</gf-form-switch>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -79,7 +73,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="gf-form-group" ng-if="current.jsonData.tlsAuth && current.access=='proxy'">
|
<div class="gf-form-group" ng-if="(current.jsonData.tlsAuth || current.jsonData.tlsAuthWithCACert) && current.access=='proxy'">
|
||||||
<div class="gf-form">
|
<div class="gf-form">
|
||||||
<h6>TLS Auth Details</h6>
|
<h6>TLS Auth Details</h6>
|
||||||
<info-popover mode="header">TLS Certs are encrypted and stored in the Grafana database.</info-popover>
|
<info-popover mode="header">TLS Certs are encrypted and stored in the Grafana database.</info-popover>
|
||||||
@ -90,7 +84,7 @@
|
|||||||
<label class="gf-form-label width-7">CA Cert</label>
|
<label class="gf-form-label width-7">CA Cert</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="gf-form gf-form--grow" ng-if="!current.secureJsonFields.tlsCACert">
|
<div class="gf-form gf-form--grow" ng-if="!current.secureJsonFields.tlsCACert">
|
||||||
<textarea rows="7" class="gf-form-input gf-form-textarea" ng-model="current.secureJsonData.tlsCACert" placeholder="Begins with -----BEGIN CERTIFICATE-----. The CA Certificate is necessary if you are using self-signed certificates."></textarea>
|
<textarea rows="7" class="gf-form-input gf-form-textarea" ng-model="current.secureJsonData.tlsCACert" placeholder="Begins with -----BEGIN CERTIFICATE-----"></textarea>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="gf-form" ng-if="current.secureJsonFields.tlsCACert">
|
<div class="gf-form" ng-if="current.secureJsonFields.tlsCACert">
|
||||||
@ -100,29 +94,31 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="gf-form-inline">
|
<div ng-if="current.jsonData.tlsAuth">
|
||||||
<div class="gf-form gf-form--v-stretch">
|
<div class="gf-form-inline">
|
||||||
<label class="gf-form-label width-7">Client Cert</label>
|
<div class="gf-form gf-form--v-stretch">
|
||||||
|
<label class="gf-form-label width-7">Client Cert</label>
|
||||||
|
</div>
|
||||||
|
<div class="gf-form gf-form--grow" ng-if="!current.secureJsonFields.tlsClientCert">
|
||||||
|
<textarea rows="7" class="gf-form-input gf-form-textarea" ng-model="current.secureJsonData.tlsClientCert" placeholder="Begins with -----BEGIN CERTIFICATE-----" required></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="gf-form" ng-if="current.secureJsonFields.tlsClientCert">
|
||||||
|
<input type="text" class="gf-form-input max-width-12" disabled="disabled" value="configured">
|
||||||
|
<a class="btn btn-secondary gf-form-btn" href="#" ng-click="current.secureJsonFields.tlsClientCert = false">reset</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="gf-form gf-form--grow" ng-if="!current.secureJsonFields.tlsClientCert">
|
|
||||||
<textarea rows="7" class="gf-form-input gf-form-textarea" ng-model="current.secureJsonData.tlsClientCert" placeholder="Begins with -----BEGIN CERTIFICATE-----" required></textarea>
|
|
||||||
</div>
|
|
||||||
<div class="gf-form" ng-if="current.secureJsonFields.tlsClientCert">
|
|
||||||
<input type="text" class="gf-form-input max-width-12" disabled="disabled" value="configured">
|
|
||||||
<a class="btn btn-secondary gf-form-btn" href="#" ng-click="current.secureJsonFields.tlsClientCert = false">reset</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="gf-form-inline">
|
<div class="gf-form-inline">
|
||||||
<div class="gf-form gf-form--v-stretch">
|
<div class="gf-form gf-form--v-stretch">
|
||||||
<label class="gf-form-label width-7">Client Key</label>
|
<label class="gf-form-label width-7">Client Key</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="gf-form gf-form--grow" ng-if="!current.secureJsonFields.tlsClientKey">
|
<div class="gf-form gf-form--grow" ng-if="!current.secureJsonFields.tlsClientKey">
|
||||||
<textarea rows="7" class="gf-form-input gf-form-textarea" ng-model="current.secureJsonData.tlsClientKey" placeholder="Begins with -----BEGIN RSA PRIVATE KEY-----" required></textarea>
|
<textarea rows="7" class="gf-form-input gf-form-textarea" ng-model="current.secureJsonData.tlsClientKey" placeholder="Begins with -----BEGIN RSA PRIVATE KEY-----" required></textarea>
|
||||||
</div>
|
</div>
|
||||||
<div class="gf-form" ng-if="current.secureJsonFields.tlsClientKey">
|
<div class="gf-form" ng-if="current.secureJsonFields.tlsClientKey">
|
||||||
<input type="text" class="gf-form-input max-width-12" disabled="disabled" value="configured">
|
<input type="text" class="gf-form-input max-width-12" disabled="disabled" value="configured">
|
||||||
<a class="btn btn-secondary gf-form-btn" href="#" ng-click="current.secureJsonFields.tlsClientKey = false">reset</a>
|
<a class="btn btn-secondary gf-form-btn" href="#" ng-click="current.secureJsonFields.tlsClientKey = false">reset</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user