support reading basic_auth password_file for HTTP basic auth (#4077)

Issue: https://github.com/prometheus/prometheus/issues/4076

Signed-off-by: Adam Shannon <adamkshannon@gmail.com>
This commit is contained in:
Adam Shannon 2018-04-25 13:19:06 -04:00 committed by Brian Brazil
parent 91e470d733
commit 809881d7f5
19 changed files with 136 additions and 1155 deletions

View file

@ -30,7 +30,6 @@ import (
config_util "github.com/prometheus/common/config" config_util "github.com/prometheus/common/config"
"github.com/prometheus/common/model" "github.com/prometheus/common/model"
"github.com/prometheus/prometheus/discovery/targetgroup" "github.com/prometheus/prometheus/discovery/targetgroup"
"github.com/prometheus/prometheus/util/httputil"
"github.com/prometheus/prometheus/util/strutil" "github.com/prometheus/prometheus/util/strutil"
) )
@ -163,7 +162,7 @@ func NewDiscovery(conf *SDConfig, logger log.Logger) (*Discovery, error) {
logger = log.NewNopLogger() logger = log.NewNopLogger()
} }
tls, err := httputil.NewTLSConfig(conf.TLSConfig) tls, err := config_util.NewTLSConfig(&conf.TLSConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -31,7 +31,6 @@ import (
config_util "github.com/prometheus/common/config" config_util "github.com/prometheus/common/config"
"github.com/prometheus/common/model" "github.com/prometheus/common/model"
"github.com/prometheus/prometheus/discovery/targetgroup" "github.com/prometheus/prometheus/discovery/targetgroup"
"github.com/prometheus/prometheus/util/httputil"
"github.com/prometheus/prometheus/util/strutil" "github.com/prometheus/prometheus/util/strutil"
) )
@ -138,7 +137,7 @@ func NewDiscovery(conf SDConfig, logger log.Logger) (*Discovery, error) {
logger = log.NewNopLogger() logger = log.NewNopLogger()
} }
rt, err := httputil.NewRoundTripperFromConfig(conf.HTTPClientConfig, "marathon_sd") rt, err := config_util.NewRoundTripperFromConfig(conf.HTTPClientConfig, "marathon_sd")
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -29,7 +29,6 @@ import (
config_util "github.com/prometheus/common/config" config_util "github.com/prometheus/common/config"
"github.com/prometheus/prometheus/discovery/targetgroup" "github.com/prometheus/prometheus/discovery/targetgroup"
"github.com/prometheus/prometheus/util/httputil"
) )
const ( const (
@ -126,7 +125,7 @@ func New(logger log.Logger, conf *SDConfig) (*Discovery, error) {
logger = log.NewNopLogger() logger = log.NewNopLogger()
} }
tls, err := httputil.NewTLSConfig(conf.TLSConfig) tls, err := config_util.NewTLSConfig(&conf.TLSConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -144,9 +144,11 @@ params:
# Sets the `Authorization` header on every scrape request with the # Sets the `Authorization` header on every scrape request with the
# configured username and password. # configured username and password.
# password and password_file are mutually exclusive.
basic_auth: basic_auth:
[ username: <string> ] [ username: <string> ]
[ password: <secret> ] [ password: <secret> ]
[ password_file: <string> ]
# Sets the `Authorization` header on every scrape request with # Sets the `Authorization` header on every scrape request with
# the configured bearer token. It is mutually exclusive with `bearer_token_file`. # the configured bearer token. It is mutually exclusive with `bearer_token_file`.
@ -744,11 +746,13 @@ role: <role>
# Optional authentication information used to authenticate to the API server. # Optional authentication information used to authenticate to the API server.
# Note that `basic_auth`, `bearer_token` and `bearer_token_file` options are # Note that `basic_auth`, `bearer_token` and `bearer_token_file` options are
# mutually exclusive. # mutually exclusive.
# password and password_file are mutually exclusive.
# Optional HTTP basic authentication information. # Optional HTTP basic authentication information.
basic_auth: basic_auth:
[ username: <string> ] [ username: <string> ]
[ password: <secret> ] [ password: <secret> ]
[ password_file: <string> ]
# Optional bearer token authentication information. # Optional bearer token authentication information.
[ bearer_token: <secret> ] [ bearer_token: <secret> ]
@ -816,9 +820,11 @@ servers:
# Sets the `Authorization` header on every request with the # Sets the `Authorization` header on every request with the
# configured username and password. # configured username and password.
# This is mutually exclusive with other authentication mechanisms. # This is mutually exclusive with other authentication mechanisms.
# password and password_file are mutually exclusive.
basic_auth: basic_auth:
[ username: <string> ] [ username: <string> ]
[ password: <string> ] [ password: <string> ]
[ password_file: <string> ]
# Sets the `Authorization` header on every request with # Sets the `Authorization` header on every request with
# the configured bearer token. It is mutually exclusive with `bearer_token_file` and other authentication mechanisms. # the configured bearer token. It is mutually exclusive with `bearer_token_file` and other authentication mechanisms.
@ -1071,9 +1077,11 @@ through the `__alerts_path__` label.
# Sets the `Authorization` header on every request with the # Sets the `Authorization` header on every request with the
# configured username and password. # configured username and password.
# password and password_file are mutually exclusive.
basic_auth: basic_auth:
[ username: <string> ] [ username: <string> ]
[ password: <string> ] [ password: <string> ]
[ password_file: <string> ]
# Sets the `Authorization` header on every request with # Sets the `Authorization` header on every request with
# the configured bearer token. It is mutually exclusive with `bearer_token_file`. # the configured bearer token. It is mutually exclusive with `bearer_token_file`.
@ -1165,9 +1173,11 @@ write_relabel_configs:
# Sets the `Authorization` header on every remote write request with the # Sets the `Authorization` header on every remote write request with the
# configured username and password. # configured username and password.
# password and password_file are mutually exclusive.
basic_auth: basic_auth:
[ username: <string> ] [ username: <string> ]
[ password: <string> ] [ password: <string> ]
[ password_file: <string> ]
# Sets the `Authorization` header on every remote write request with # Sets the `Authorization` header on every remote write request with
# the configured bearer token. It is mutually exclusive with `bearer_token_file`. # the configured bearer token. It is mutually exclusive with `bearer_token_file`.
@ -1209,9 +1219,11 @@ required_matchers:
# Sets the `Authorization` header on every remote read request with the # Sets the `Authorization` header on every remote read request with the
# configured username and password. # configured username and password.
# password and password_file are mutually exclusive.
basic_auth: basic_auth:
[ username: <string> ] [ username: <string> ]
[ password: <string> ] [ password: <string> ]
[ password_file: <string> ]
# Sets the `Authorization` header on every remote read request with # Sets the `Authorization` header on every remote read request with
# the configured bearer token. It is mutually exclusive with `bearer_token_file`. # the configured bearer token. It is mutually exclusive with `bearer_token_file`.

View file

@ -31,6 +31,7 @@ import (
"github.com/go-kit/kit/log" "github.com/go-kit/kit/log"
"github.com/go-kit/kit/log/level" "github.com/go-kit/kit/log/level"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
config_util "github.com/prometheus/common/config"
"github.com/prometheus/common/model" "github.com/prometheus/common/model"
old_ctx "golang.org/x/net/context" old_ctx "golang.org/x/net/context"
"golang.org/x/net/context/ctxhttp" "golang.org/x/net/context/ctxhttp"
@ -39,7 +40,6 @@ import (
"github.com/prometheus/prometheus/discovery/targetgroup" "github.com/prometheus/prometheus/discovery/targetgroup"
"github.com/prometheus/prometheus/pkg/labels" "github.com/prometheus/prometheus/pkg/labels"
"github.com/prometheus/prometheus/pkg/relabel" "github.com/prometheus/prometheus/pkg/relabel"
"github.com/prometheus/prometheus/util/httputil"
) )
const ( const (
@ -545,7 +545,7 @@ type alertmanagerSet struct {
} }
func newAlertmanagerSet(cfg *config.AlertmanagerConfig, logger log.Logger) (*alertmanagerSet, error) { func newAlertmanagerSet(cfg *config.AlertmanagerConfig, logger log.Logger) (*alertmanagerSet, error) {
client, err := httputil.NewClientFromConfig(cfg.HTTPClientConfig, "alertmanager") client, err := config_util.NewClientFromConfig(cfg.HTTPClientConfig, "alertmanager")
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -33,7 +33,6 @@ import (
"github.com/prometheus/prometheus/config" "github.com/prometheus/prometheus/config"
"github.com/prometheus/prometheus/discovery/targetgroup" "github.com/prometheus/prometheus/discovery/targetgroup"
"github.com/prometheus/prometheus/pkg/labels" "github.com/prometheus/prometheus/pkg/labels"
"github.com/prometheus/prometheus/util/httputil"
"github.com/prometheus/prometheus/util/testutil" "github.com/prometheus/prometheus/util/testutil"
) )
@ -155,7 +154,7 @@ func TestHandlerSendAll(t *testing.T) {
h := NewManager(&Options{}, nil) h := NewManager(&Options{}, nil)
authClient, _ := httputil.NewClientFromConfig(config_util.HTTPClientConfig{ authClient, _ := config_util.NewClientFromConfig(config_util.HTTPClientConfig{
BasicAuth: &config_util.BasicAuth{ BasicAuth: &config_util.BasicAuth{
Username: "prometheus", Username: "prometheus",
Password: "testing_password", Password: "testing_password",

View file

@ -29,6 +29,7 @@ import (
"github.com/go-kit/kit/log" "github.com/go-kit/kit/log"
"github.com/go-kit/kit/log/level" "github.com/go-kit/kit/log/level"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
config_util "github.com/prometheus/common/config"
"github.com/prometheus/common/model" "github.com/prometheus/common/model"
"github.com/prometheus/common/version" "github.com/prometheus/common/version"
"golang.org/x/net/context/ctxhttp" "golang.org/x/net/context/ctxhttp"
@ -42,7 +43,6 @@ import (
"github.com/prometheus/prometheus/pkg/timestamp" "github.com/prometheus/prometheus/pkg/timestamp"
"github.com/prometheus/prometheus/pkg/value" "github.com/prometheus/prometheus/pkg/value"
"github.com/prometheus/prometheus/storage" "github.com/prometheus/prometheus/storage"
"github.com/prometheus/prometheus/util/httputil"
) )
var ( var (
@ -142,7 +142,7 @@ func newScrapePool(cfg *config.ScrapeConfig, app Appendable, logger log.Logger)
logger = log.NewNopLogger() logger = log.NewNopLogger()
} }
client, err := httputil.NewClientFromConfig(cfg.HTTPClientConfig, cfg.JobName) client, err := config_util.NewClientFromConfig(cfg.HTTPClientConfig, cfg.JobName)
if err != nil { if err != nil {
// Any errors that could occur here should be caught during config validation. // Any errors that could occur here should be caught during config validation.
level.Error(logger).Log("msg", "Error creating HTTP client", "err", err) level.Error(logger).Log("msg", "Error creating HTTP client", "err", err)
@ -212,7 +212,7 @@ func (sp *scrapePool) reload(cfg *config.ScrapeConfig) {
sp.mtx.Lock() sp.mtx.Lock()
defer sp.mtx.Unlock() defer sp.mtx.Unlock()
client, err := httputil.NewClientFromConfig(cfg.HTTPClientConfig, cfg.JobName) client, err := config_util.NewClientFromConfig(cfg.HTTPClientConfig, cfg.JobName)
if err != nil { if err != nil {
// Any errors that could occur here should be caught during config validation. // Any errors that could occur here should be caught during config validation.
level.Error(sp.logger).Log("msg", "Error creating HTTP client", "err", err) level.Error(sp.logger).Log("msg", "Error creating HTTP client", "err", err)

View file

@ -30,7 +30,6 @@ import (
config_util "github.com/prometheus/common/config" config_util "github.com/prometheus/common/config"
"github.com/prometheus/prometheus/pkg/labels" "github.com/prometheus/prometheus/pkg/labels"
"github.com/prometheus/prometheus/util/httputil"
) )
const ( const (
@ -151,7 +150,7 @@ func TestNewHTTPBearerToken(t *testing.T) {
cfg := config_util.HTTPClientConfig{ cfg := config_util.HTTPClientConfig{
BearerToken: "1234", BearerToken: "1234",
} }
c, err := httputil.NewClientFromConfig(cfg, "test") c, err := config_util.NewClientFromConfig(cfg, "test")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -178,7 +177,7 @@ func TestNewHTTPBearerTokenFile(t *testing.T) {
cfg := config_util.HTTPClientConfig{ cfg := config_util.HTTPClientConfig{
BearerTokenFile: "testdata/bearertoken.txt", BearerTokenFile: "testdata/bearertoken.txt",
} }
c, err := httputil.NewClientFromConfig(cfg, "test") c, err := config_util.NewClientFromConfig(cfg, "test")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -207,7 +206,7 @@ func TestNewHTTPBasicAuth(t *testing.T) {
Password: "password123", Password: "password123",
}, },
} }
c, err := httputil.NewClientFromConfig(cfg, "test") c, err := config_util.NewClientFromConfig(cfg, "test")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -235,7 +234,7 @@ func TestNewHTTPCACert(t *testing.T) {
CAFile: caCertPath, CAFile: caCertPath,
}, },
} }
c, err := httputil.NewClientFromConfig(cfg, "test") c, err := config_util.NewClientFromConfig(cfg, "test")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -269,7 +268,7 @@ func TestNewHTTPClientCert(t *testing.T) {
KeyFile: "testdata/client.key", KeyFile: "testdata/client.key",
}, },
} }
c, err := httputil.NewClientFromConfig(cfg, "test") c, err := config_util.NewClientFromConfig(cfg, "test")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -298,7 +297,7 @@ func TestNewHTTPWithServerName(t *testing.T) {
ServerName: "prometheus.rocks", ServerName: "prometheus.rocks",
}, },
} }
c, err := httputil.NewClientFromConfig(cfg, "test") c, err := config_util.NewClientFromConfig(cfg, "test")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -327,7 +326,7 @@ func TestNewHTTPWithBadServerName(t *testing.T) {
ServerName: "badname", ServerName: "badname",
}, },
} }
c, err := httputil.NewClientFromConfig(cfg, "test") c, err := config_util.NewClientFromConfig(cfg, "test")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -366,7 +365,7 @@ func TestNewClientWithBadTLSConfig(t *testing.T) {
KeyFile: "testdata/nonexistent_client.key", KeyFile: "testdata/nonexistent_client.key",
}, },
} }
_, err := httputil.NewClientFromConfig(cfg, "test") _, err := config_util.NewClientFromConfig(cfg, "test")
if err == nil { if err == nil {
t.Fatalf("Expected error, got nil.") t.Fatalf("Expected error, got nil.")
} }

View file

@ -30,7 +30,6 @@ import (
config_util "github.com/prometheus/common/config" config_util "github.com/prometheus/common/config"
"github.com/prometheus/prometheus/prompb" "github.com/prometheus/prometheus/prompb"
"github.com/prometheus/prometheus/util/httputil"
) )
const maxErrMsgLen = 256 const maxErrMsgLen = 256
@ -52,7 +51,7 @@ type ClientConfig struct {
// NewClient creates a new Client. // NewClient creates a new Client.
func NewClient(index int, conf *ClientConfig) (*Client, error) { func NewClient(index int, conf *ClientConfig) (*Client, error) {
httpClient, err := httputil.NewClientFromConfig(conf.HTTPClientConfig, "remote_storage") httpClient, err := config_util.NewClientFromConfig(conf.HTTPClientConfig, "remote_storage")
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -1,197 +0,0 @@
// Copyright 2013 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package httputil
import (
"crypto/tls"
"crypto/x509"
"fmt"
"io/ioutil"
"net/http"
"strings"
"time"
"github.com/mwitkow/go-conntrack"
config_util "github.com/prometheus/common/config"
)
// NewClient returns a http.Client using the specified http.RoundTripper.
func newClient(rt http.RoundTripper) *http.Client {
return &http.Client{Transport: rt}
}
// NewClientFromConfig returns a new HTTP client configured for the
// given config.HTTPClientConfig. The name is used as go-conntrack metric label.
func NewClientFromConfig(cfg config_util.HTTPClientConfig, name string) (*http.Client, error) {
rt, err := NewRoundTripperFromConfig(cfg, name)
if err != nil {
return nil, err
}
return newClient(rt), nil
}
// NewRoundTripperFromConfig returns a new HTTP RoundTripper configured for the
// given config.HTTPClientConfig. The name is used as go-conntrack metric label.
func NewRoundTripperFromConfig(cfg config_util.HTTPClientConfig, name string) (http.RoundTripper, error) {
tlsConfig, err := NewTLSConfig(cfg.TLSConfig)
if err != nil {
return nil, err
}
// The only timeout we care about is the configured scrape timeout.
// It is applied on request. So we leave out any timings here.
var rt http.RoundTripper = &http.Transport{
Proxy: http.ProxyURL(cfg.ProxyURL.URL),
MaxIdleConns: 20000,
MaxIdleConnsPerHost: 1000, // see https://github.com/golang/go/issues/13801
DisableKeepAlives: false,
TLSClientConfig: tlsConfig,
DisableCompression: true,
// 5 minutes is typically above the maximum sane scrape interval. So we can
// use keepalive for all configurations.
IdleConnTimeout: 5 * time.Minute,
DialContext: conntrack.NewDialContextFunc(
conntrack.DialWithTracing(),
conntrack.DialWithName(name),
),
}
// If a bearer token is provided, create a round tripper that will set the
// Authorization header correctly on each request.
if len(cfg.BearerToken) > 0 {
rt = NewBearerAuthRoundTripper(string(cfg.BearerToken), rt)
} else if len(cfg.BearerTokenFile) > 0 {
rt = NewBearerAuthFileRoundTripper(cfg.BearerTokenFile, rt)
}
if cfg.BasicAuth != nil {
rt = NewBasicAuthRoundTripper(cfg.BasicAuth.Username, string(cfg.BasicAuth.Password), rt)
}
// Return a new configured RoundTripper.
return rt, nil
}
type bearerAuthRoundTripper struct {
bearerToken string
rt http.RoundTripper
}
// NewBearerAuthRoundTripper adds the provided bearer token to a request unless the authorization
// header has already been set.
func NewBearerAuthRoundTripper(bearer string, rt http.RoundTripper) http.RoundTripper {
return &bearerAuthRoundTripper{bearer, rt}
}
func (rt *bearerAuthRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
if len(req.Header.Get("Authorization")) == 0 {
req = cloneRequest(req)
req.Header.Set("Authorization", "Bearer "+rt.bearerToken)
}
return rt.rt.RoundTrip(req)
}
type bearerAuthFileRoundTripper struct {
bearerFile string
rt http.RoundTripper
}
// NewBearerAuthFileRoundTripper adds the bearer token read from the provided file to a request unless
// the authorization header has already been set. This file is read for every request.
func NewBearerAuthFileRoundTripper(bearerFile string, rt http.RoundTripper) http.RoundTripper {
return &bearerAuthFileRoundTripper{bearerFile, rt}
}
func (rt *bearerAuthFileRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
if len(req.Header.Get("Authorization")) == 0 {
b, err := ioutil.ReadFile(rt.bearerFile)
if err != nil {
return nil, fmt.Errorf("unable to read bearer token file %s: %s", rt.bearerFile, err)
}
bearerToken := strings.TrimSpace(string(b))
req = cloneRequest(req)
req.Header.Set("Authorization", "Bearer "+bearerToken)
}
return rt.rt.RoundTrip(req)
}
type basicAuthRoundTripper struct {
username string
password string
rt http.RoundTripper
}
// NewBasicAuthRoundTripper will apply a BASIC auth authorization header to a request unless it has
// already been set.
func NewBasicAuthRoundTripper(username, password string, rt http.RoundTripper) http.RoundTripper {
return &basicAuthRoundTripper{username, password, rt}
}
func (rt *basicAuthRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
if len(req.Header.Get("Authorization")) != 0 {
return rt.rt.RoundTrip(req)
}
req = cloneRequest(req)
req.SetBasicAuth(rt.username, rt.password)
return rt.rt.RoundTrip(req)
}
// cloneRequest returns a clone of the provided *http.Request.
// The clone is a shallow copy of the struct and its Header map.
func cloneRequest(r *http.Request) *http.Request {
// Shallow copy of the struct.
r2 := new(http.Request)
*r2 = *r
// Deep copy of the Header.
r2.Header = make(http.Header)
for k, s := range r.Header {
r2.Header[k] = s
}
return r2
}
// NewTLSConfig creates a new tls.Config from the given config_util.TLSConfig.
func NewTLSConfig(cfg config_util.TLSConfig) (*tls.Config, error) {
tlsConfig := &tls.Config{InsecureSkipVerify: cfg.InsecureSkipVerify}
// If a CA cert is provided then let's read it in so we can validate the
// scrape target's certificate properly.
if len(cfg.CAFile) > 0 {
caCertPool := x509.NewCertPool()
// Load CA cert.
caCert, err := ioutil.ReadFile(cfg.CAFile)
if err != nil {
return nil, fmt.Errorf("unable to use specified CA cert %s: %s", cfg.CAFile, err)
}
caCertPool.AppendCertsFromPEM(caCert)
tlsConfig.RootCAs = caCertPool
}
if len(cfg.ServerName) > 0 {
tlsConfig.ServerName = cfg.ServerName
}
// If a client cert & key is provided then configure TLS config accordingly.
if len(cfg.CertFile) > 0 && len(cfg.KeyFile) > 0 {
cert, err := tls.LoadX509KeyPair(cfg.CertFile, cfg.KeyFile)
if err != nil {
return nil, fmt.Errorf("unable to use specified client cert (%s) & key (%s): %s", cfg.CertFile, cfg.KeyFile, err)
}
tlsConfig.Certificates = []tls.Certificate{cert}
}
tlsConfig.BuildNameToCertificate()
return tlsConfig, nil
}

View file

@ -1,468 +0,0 @@
// Copyright 2017 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package httputil
import (
"crypto/tls"
"crypto/x509"
"fmt"
"io/ioutil"
"net/http"
"net/http/httptest"
"reflect"
"strings"
"testing"
config_util "github.com/prometheus/common/config"
"github.com/prometheus/prometheus/util/testutil"
)
const (
TLSCAChainPath = "testdata/tls-ca-chain.pem"
ServerCertificatePath = "testdata/server.crt"
ServerKeyPath = "testdata/server.key"
BarneyCertificatePath = "testdata/barney.crt"
BarneyKeyNoPassPath = "testdata/barney-no-pass.key"
MissingCA = "missing/ca.crt"
MissingCert = "missing/cert.crt"
MissingKey = "missing/secret.key"
ExpectedMessage = "I'm here to serve you!!!"
BearerToken = "theanswertothegreatquestionoflifetheuniverseandeverythingisfortytwo"
BearerTokenFile = "testdata/bearer.token"
MissingBearerTokenFile = "missing/bearer.token"
ExpectedBearer = "Bearer " + BearerToken
ExpectedUsername = "arthurdent"
ExpectedPassword = "42"
)
func newTestServer(handler func(w http.ResponseWriter, r *http.Request)) (*httptest.Server, error) {
testServer := httptest.NewUnstartedServer(http.HandlerFunc(handler))
tlsCAChain, err := ioutil.ReadFile(TLSCAChainPath)
if err != nil {
return nil, fmt.Errorf("Can't read %s", TLSCAChainPath)
}
serverCertificate, err := tls.LoadX509KeyPair(ServerCertificatePath, ServerKeyPath)
if err != nil {
return nil, fmt.Errorf("Can't load X509 key pair %s - %s", ServerCertificatePath, ServerKeyPath)
}
rootCAs := x509.NewCertPool()
rootCAs.AppendCertsFromPEM(tlsCAChain)
testServer.TLS = &tls.Config{
Certificates: make([]tls.Certificate, 1),
RootCAs: rootCAs,
ClientAuth: tls.RequireAndVerifyClientCert,
ClientCAs: rootCAs}
testServer.TLS.Certificates[0] = serverCertificate
testServer.TLS.BuildNameToCertificate()
testServer.StartTLS()
return testServer, nil
}
func TestNewClientFromConfig(t *testing.T) {
var newClientValidConfig = []struct {
clientConfig config_util.HTTPClientConfig
handler func(w http.ResponseWriter, r *http.Request)
}{
{
clientConfig: config_util.HTTPClientConfig{
TLSConfig: config_util.TLSConfig{
CAFile: "",
CertFile: BarneyCertificatePath,
KeyFile: BarneyKeyNoPassPath,
ServerName: "",
InsecureSkipVerify: true},
},
handler: func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, ExpectedMessage)
},
}, {
clientConfig: config_util.HTTPClientConfig{
TLSConfig: config_util.TLSConfig{
CAFile: TLSCAChainPath,
CertFile: BarneyCertificatePath,
KeyFile: BarneyKeyNoPassPath,
ServerName: "",
InsecureSkipVerify: false},
},
handler: func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, ExpectedMessage)
},
}, {
clientConfig: config_util.HTTPClientConfig{
BearerToken: BearerToken,
TLSConfig: config_util.TLSConfig{
CAFile: TLSCAChainPath,
CertFile: BarneyCertificatePath,
KeyFile: BarneyKeyNoPassPath,
ServerName: "",
InsecureSkipVerify: false},
},
handler: func(w http.ResponseWriter, r *http.Request) {
bearer := r.Header.Get("Authorization")
if bearer != ExpectedBearer {
fmt.Fprintf(w, "The expected Bearer Authorization (%s) differs from the obtained Bearer Authorization (%s)",
ExpectedBearer, bearer)
} else {
fmt.Fprint(w, ExpectedMessage)
}
},
}, {
clientConfig: config_util.HTTPClientConfig{
BearerTokenFile: BearerTokenFile,
TLSConfig: config_util.TLSConfig{
CAFile: TLSCAChainPath,
CertFile: BarneyCertificatePath,
KeyFile: BarneyKeyNoPassPath,
ServerName: "",
InsecureSkipVerify: false},
},
handler: func(w http.ResponseWriter, r *http.Request) {
bearer := r.Header.Get("Authorization")
if bearer != ExpectedBearer {
fmt.Fprintf(w, "The expected Bearer Authorization (%s) differs from the obtained Bearer Authorization (%s)",
ExpectedBearer, bearer)
} else {
fmt.Fprint(w, ExpectedMessage)
}
},
}, {
clientConfig: config_util.HTTPClientConfig{
BasicAuth: &config_util.BasicAuth{
Username: ExpectedUsername,
Password: ExpectedPassword,
},
TLSConfig: config_util.TLSConfig{
CAFile: TLSCAChainPath,
CertFile: BarneyCertificatePath,
KeyFile: BarneyKeyNoPassPath,
ServerName: "",
InsecureSkipVerify: false},
},
handler: func(w http.ResponseWriter, r *http.Request) {
username, password, ok := r.BasicAuth()
if !ok {
fmt.Fprintf(w, "The Authorization header wasn't set")
} else if ExpectedUsername != username {
fmt.Fprintf(w, "The expected username (%s) differs from the obtained username (%s).", ExpectedUsername, username)
} else if ExpectedPassword != password {
fmt.Fprintf(w, "The expected password (%s) differs from the obtained password (%s).", ExpectedPassword, password)
} else {
fmt.Fprint(w, ExpectedMessage)
}
},
},
}
for _, validConfig := range newClientValidConfig {
testServer, err := newTestServer(validConfig.handler)
if err != nil {
t.Fatal(err.Error())
}
defer testServer.Close()
client, err := NewClientFromConfig(validConfig.clientConfig, "test")
if err != nil {
t.Errorf("Can't create a client from this config: %+v", validConfig.clientConfig)
continue
}
response, err := client.Get(testServer.URL)
if err != nil {
t.Errorf("Can't connect to the test server using this config: %+v", validConfig.clientConfig)
continue
}
message, err := ioutil.ReadAll(response.Body)
response.Body.Close()
if err != nil {
t.Errorf("Can't read the server response body using this config: %+v", validConfig.clientConfig)
continue
}
trimMessage := strings.TrimSpace(string(message))
if ExpectedMessage != trimMessage {
t.Errorf("The expected message (%s) differs from the obtained message (%s) using this config: %+v",
ExpectedMessage, trimMessage, validConfig.clientConfig)
}
}
}
func TestNewClientFromInvalidConfig(t *testing.T) {
var newClientInvalidConfig = []struct {
clientConfig config_util.HTTPClientConfig
errorMsg string
}{
{
clientConfig: config_util.HTTPClientConfig{
TLSConfig: config_util.TLSConfig{
CAFile: MissingCA,
CertFile: "",
KeyFile: "",
ServerName: "",
InsecureSkipVerify: true},
},
errorMsg: fmt.Sprintf("unable to use specified CA cert %s:", MissingCA),
},
}
for _, invalidConfig := range newClientInvalidConfig {
client, err := NewClientFromConfig(invalidConfig.clientConfig, "test")
if client != nil {
t.Errorf("A client instance was returned instead of nil using this config: %+v", invalidConfig.clientConfig)
}
if err == nil {
t.Errorf("No error was returned using this config: %+v", invalidConfig.clientConfig)
}
if !strings.Contains(err.Error(), invalidConfig.errorMsg) {
t.Errorf("Expected error %s does not contain %s", err.Error(), invalidConfig.errorMsg)
}
}
}
func TestMissingBearerAuthFile(t *testing.T) {
cfg := config_util.HTTPClientConfig{
BearerTokenFile: MissingBearerTokenFile,
TLSConfig: config_util.TLSConfig{
CAFile: TLSCAChainPath,
CertFile: BarneyCertificatePath,
KeyFile: BarneyKeyNoPassPath,
ServerName: "",
InsecureSkipVerify: false},
}
handler := func(w http.ResponseWriter, r *http.Request) {
bearer := r.Header.Get("Authorization")
if bearer != ExpectedBearer {
fmt.Fprintf(w, "The expected Bearer Authorization (%s) differs from the obtained Bearer Authorization (%s)",
ExpectedBearer, bearer)
} else {
fmt.Fprint(w, ExpectedMessage)
}
}
testServer, err := newTestServer(handler)
if err != nil {
t.Fatal(err.Error())
}
defer testServer.Close()
client, err := NewClientFromConfig(cfg, "test")
if err != nil {
t.Fatal(err)
}
_, err = client.Get(testServer.URL)
if err == nil {
t.Fatal("No error is returned here")
}
if !strings.Contains(err.Error(), "unable to read bearer token file missing/bearer.token: open missing/bearer.token: no such file or directory") {
t.Fatal("wrong error message being returned")
}
}
func TestBearerAuthRoundTripper(t *testing.T) {
const (
newBearerToken = "goodbyeandthankyouforthefish"
)
fakeRoundTripper := testutil.NewRoundTripCheckRequest(func(req *http.Request) {
bearer := req.Header.Get("Authorization")
if bearer != ExpectedBearer {
t.Errorf("The expected Bearer Authorization (%s) differs from the obtained Bearer Authorization (%s)",
ExpectedBearer, bearer)
}
}, nil, nil)
// Normal flow.
bearerAuthRoundTripper := NewBearerAuthRoundTripper(BearerToken, fakeRoundTripper)
request, _ := http.NewRequest("GET", "/hitchhiker", nil)
request.Header.Set("User-Agent", "Douglas Adams mind")
bearerAuthRoundTripper.RoundTrip(request)
// Should honor already Authorization header set.
bearerAuthRoundTripperShouldNotModifyExistingAuthorization := NewBearerAuthRoundTripper(newBearerToken, fakeRoundTripper)
request, _ = http.NewRequest("GET", "/hitchhiker", nil)
request.Header.Set("Authorization", ExpectedBearer)
bearerAuthRoundTripperShouldNotModifyExistingAuthorization.RoundTrip(request)
}
func TestBearerAuthFileRoundTripper(t *testing.T) {
const (
newBearerToken = "goodbyeandthankyouforthefish"
)
fakeRoundTripper := testutil.NewRoundTripCheckRequest(func(req *http.Request) {
bearer := req.Header.Get("Authorization")
if bearer != ExpectedBearer {
t.Errorf("The expected Bearer Authorization (%s) differs from the obtained Bearer Authorization (%s)",
ExpectedBearer, bearer)
}
}, nil, nil)
// Normal flow.
bearerAuthRoundTripper := NewBearerAuthFileRoundTripper(BearerTokenFile, fakeRoundTripper)
request, _ := http.NewRequest("GET", "/hitchhiker", nil)
request.Header.Set("User-Agent", "Douglas Adams mind")
bearerAuthRoundTripper.RoundTrip(request)
// Should honor already Authorization header set.
bearerAuthRoundTripperShouldNotModifyExistingAuthorization := NewBearerAuthFileRoundTripper(MissingBearerTokenFile, fakeRoundTripper)
request, _ = http.NewRequest("GET", "/hitchhiker", nil)
request.Header.Set("Authorization", ExpectedBearer)
bearerAuthRoundTripperShouldNotModifyExistingAuthorization.RoundTrip(request)
}
func TestBasicAuthRoundTripper(t *testing.T) {
const (
newUsername = "fordprefect"
newPassword = "towel"
)
fakeRoundTripper := testutil.NewRoundTripCheckRequest(func(req *http.Request) {
username, password, ok := req.BasicAuth()
if !ok {
t.Errorf("The Authorization header wasn't set")
}
if ExpectedUsername != username {
t.Errorf("The expected username (%s) differs from the obtained username (%s).", ExpectedUsername, username)
}
if ExpectedPassword != password {
t.Errorf("The expected password (%s) differs from the obtained password (%s).", ExpectedPassword, password)
}
}, nil, nil)
// Normal flow.
basicAuthRoundTripper := NewBasicAuthRoundTripper(ExpectedUsername,
ExpectedPassword, fakeRoundTripper)
request, _ := http.NewRequest("GET", "/hitchhiker", nil)
request.Header.Set("User-Agent", "Douglas Adams mind")
basicAuthRoundTripper.RoundTrip(request)
// Should honor already Authorization header set.
basicAuthRoundTripperShouldNotModifyExistingAuthorization := NewBasicAuthRoundTripper(newUsername,
newPassword, fakeRoundTripper)
request, _ = http.NewRequest("GET", "/hitchhiker", nil)
request.SetBasicAuth(ExpectedUsername, ExpectedPassword)
basicAuthRoundTripperShouldNotModifyExistingAuthorization.RoundTrip(request)
}
func TestTLSConfig(t *testing.T) {
configTLSConfig := config_util.TLSConfig{
CAFile: TLSCAChainPath,
CertFile: BarneyCertificatePath,
KeyFile: BarneyKeyNoPassPath,
ServerName: "localhost",
InsecureSkipVerify: false}
tlsCAChain, err := ioutil.ReadFile(TLSCAChainPath)
if err != nil {
t.Fatalf("Can't read the CA certificate chain (%s)",
TLSCAChainPath)
}
rootCAs := x509.NewCertPool()
rootCAs.AppendCertsFromPEM(tlsCAChain)
barneyCertificate, err := tls.LoadX509KeyPair(BarneyCertificatePath, BarneyKeyNoPassPath)
if err != nil {
t.Fatalf("Can't load the client key pair ('%s' and '%s'). Reason: %s",
BarneyCertificatePath, BarneyKeyNoPassPath, err)
}
expectedTLSConfig := &tls.Config{
RootCAs: rootCAs,
Certificates: []tls.Certificate{barneyCertificate},
ServerName: configTLSConfig.ServerName,
InsecureSkipVerify: configTLSConfig.InsecureSkipVerify}
expectedTLSConfig.BuildNameToCertificate()
tlsConfig, err := NewTLSConfig(configTLSConfig)
if err != nil {
t.Fatalf("Can't create a new TLS Config from a configuration (%s).", err)
}
if !reflect.DeepEqual(tlsConfig, expectedTLSConfig) {
t.Fatalf("Unexpected TLS Config result: \n\n%+v\n expected\n\n%+v", tlsConfig, expectedTLSConfig)
}
}
func TestTLSConfigEmpty(t *testing.T) {
configTLSConfig := config_util.TLSConfig{
CAFile: "",
CertFile: "",
KeyFile: "",
ServerName: "",
InsecureSkipVerify: true}
expectedTLSConfig := &tls.Config{
InsecureSkipVerify: configTLSConfig.InsecureSkipVerify}
expectedTLSConfig.BuildNameToCertificate()
tlsConfig, err := NewTLSConfig(configTLSConfig)
if err != nil {
t.Fatalf("Can't create a new TLS Config from a configuration (%s).", err)
}
if !reflect.DeepEqual(tlsConfig, expectedTLSConfig) {
t.Fatalf("Unexpected TLS Config result: \n\n%+v\n expected\n\n%+v", tlsConfig, expectedTLSConfig)
}
}
func TestTLSConfigInvalidCA(t *testing.T) {
var invalidTLSConfig = []struct {
configTLSConfig config_util.TLSConfig
errorMessage string
}{
{
configTLSConfig: config_util.TLSConfig{
CAFile: MissingCA,
CertFile: "",
KeyFile: "",
ServerName: "",
InsecureSkipVerify: false},
errorMessage: fmt.Sprintf("unable to use specified CA cert %s:", MissingCA),
}, {
configTLSConfig: config_util.TLSConfig{
CAFile: "",
CertFile: MissingCert,
KeyFile: BarneyKeyNoPassPath,
ServerName: "",
InsecureSkipVerify: false},
errorMessage: fmt.Sprintf("unable to use specified client cert (%s) & key (%s):", MissingCert, BarneyKeyNoPassPath),
}, {
configTLSConfig: config_util.TLSConfig{
CAFile: "",
CertFile: BarneyCertificatePath,
KeyFile: MissingKey,
ServerName: "",
InsecureSkipVerify: false},
errorMessage: fmt.Sprintf("unable to use specified client cert (%s) & key (%s):", BarneyCertificatePath, MissingKey),
},
}
for _, anInvalididTLSConfig := range invalidTLSConfig {
tlsConfig, err := NewTLSConfig(anInvalididTLSConfig.configTLSConfig)
if tlsConfig != nil && err == nil {
t.Errorf("The TLS Config could be created even with this %+v", anInvalididTLSConfig.configTLSConfig)
continue
}
if !strings.Contains(err.Error(), anInvalididTLSConfig.errorMessage) {
t.Errorf("The expected error should contain %s, but got %s", anInvalididTLSConfig.errorMessage, err)
}
}
}

View file

@ -1,27 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAxmYjfBZhZbAup9uSULehoqPCv/U+77ETxUNyS2nviWEHDAb/
pFS8Btx4oCQ1ECVSyxcUmXSlrvDjMY4sisOHvndNRlGi274M5a8Q5yD1BUqvxq3u
XB/+SYNVShBzaswrSjpzMe89AlOPxPjnE14OXh00j2hHunOG4jhlWgJnY0YyvUQQ
YWO6KrmKMiZ4MgmY0SWh/ZhlkDJPtkp3aUVM2sheCru/70E9viLGfdlhc2pIMshy
wNp4/5IkHBZwbqXFFGX4sRtSXI/auZNvcHOBse+3e3BonWvBWS2lIYbzpX3vLB7B
E9BGIxWn1fgNQr14yFPaccSszBvgtmEUONolnwIDAQABAoIBAQC7nBhQHgXKGBl2
Z97rb0pstrjRtsLl/Cg68LWi9LEr0tHMIM4bgnkvb8qtfK+k7fZl0BSNrE2EqYvd
75jVO2MgzEYJieccLpKZm7u7JGIut9qSYSU2fpaCw6uiVv4dbqY9EhqejKG/km8w
j0JMATRK8Qkj1zOE7/wL7dKBlCZaK3u+OT17spuA/21PG/cLiPaSGSA3CU/eqbkU
BD6JeBxp33XNTytwWoOvarsigpL0dGqQ7+qhGq6t69qFfWoe9rimV7Ya+tB9zF/U
HzOIEspOYvzxe+C7VJjlVFr4haMYmsrO9qRUJ2ofp49OLVdfEANsdVISSvS63BEp
gBZN8Ko5AoGBAO1z8y8YCsI+2vBG6nxZ1eMba0KHi3bS8db1TaenJBV22w6WQATh
hEaU6VLMFcMvrOUjXN/7HJfnEMyvFT6gb9obPDVEMZw88s9lVN6njgGLZR/jodyN
7N7utLopN043Ra0WfEILAXPSz8esT1yn05OZV6AFHxJEWMrX3/4+spCLAoGBANXl
RomieVY4u3FF/uzhbzKNNb9ETxrQuexfbangKp5eLniwnr2SQWIbyPzeurwp15J8
HvxB2vpNvs1khSwNx9dQfMdiUVPGLWj7MimAHTHsnQ9LVV9W28ghuSWbjQDGTUt1
WCCu1MkKIOzupbi+zgsNlI33yilRQKAb9SRxdy29AoGBAOKpvyZiPcrkMxwPpb/k
BU7QGpgcSR25CQ+Xg3QZEVHH7h1DgYLnPtwdQ4g8tj1mohTsp7hKvSWndRrdulrY
zUyWmOeD3BN2/pTI9rW/nceNp49EPHsLo2O+2xelRlzMWB98ikqEtPM59gt1SSB6
N3X6d3GR0fIe+d9PKEtK0Cs3AoGAZ9r8ReXSvm+ra5ON9Nx8znHMEAON2TpRnBi1
uY7zgpO+QrGXUfqKrqVJEKbgym4SkribnuYm+fP32eid1McYKk6VV4ZAcMm/0MJv
F8Fx64S0ufFdEX6uFl1xdXYyn5apfyMJ2EyrWrYFSKWTZ8GVb753S/tteGRQWa1Z
eQly0Y0CgYEAnI6G9KFvXI+MLu5y2LPYAwsesDFzaWwyDl96ioQTA9hNSrjR33Vw
xwpiEe0T/WKF8NQ0QWnrQDbTvuCvZUK37TVxscYWuItL6vnBrYqr4Ck0j1BcGwV5
jT581A/Vw8JJiR/vfcxgmrFYqoUmkMKDmCN1oImfz09GtQ4jQ1rlxz8=
-----END RSA PRIVATE KEY-----

View file

@ -1,96 +0,0 @@
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 2 (0x2)
Signature Algorithm: sha1WithRSAEncryption
Issuer: C=NO, O=Green AS, OU=Green Certificate Authority, CN=Green TLS CA
Validity
Not Before: Jul 13 04:02:47 2017 GMT
Not After : Jul 13 04:02:47 2019 GMT
Subject: C=NO, O=Telenor AS, OU=Support, CN=Barney Rubble
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:c6:66:23:7c:16:61:65:b0:2e:a7:db:92:50:b7:
a1:a2:a3:c2:bf:f5:3e:ef:b1:13:c5:43:72:4b:69:
ef:89:61:07:0c:06:ff:a4:54:bc:06:dc:78:a0:24:
35:10:25:52:cb:17:14:99:74:a5:ae:f0:e3:31:8e:
2c:8a:c3:87:be:77:4d:46:51:a2:db:be:0c:e5:af:
10:e7:20:f5:05:4a:af:c6:ad:ee:5c:1f:fe:49:83:
55:4a:10:73:6a:cc:2b:4a:3a:73:31:ef:3d:02:53:
8f:c4:f8:e7:13:5e:0e:5e:1d:34:8f:68:47:ba:73:
86:e2:38:65:5a:02:67:63:46:32:bd:44:10:61:63:
ba:2a:b9:8a:32:26:78:32:09:98:d1:25:a1:fd:98:
65:90:32:4f:b6:4a:77:69:45:4c:da:c8:5e:0a:bb:
bf:ef:41:3d:be:22:c6:7d:d9:61:73:6a:48:32:c8:
72:c0:da:78:ff:92:24:1c:16:70:6e:a5:c5:14:65:
f8:b1:1b:52:5c:8f:da:b9:93:6f:70:73:81:b1:ef:
b7:7b:70:68:9d:6b:c1:59:2d:a5:21:86:f3:a5:7d:
ef:2c:1e:c1:13:d0:46:23:15:a7:d5:f8:0d:42:bd:
78:c8:53:da:71:c4:ac:cc:1b:e0:b6:61:14:38:da:
25:9f
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Key Usage: critical
Digital Signature
X509v3 Basic Constraints:
CA:FALSE
X509v3 Extended Key Usage:
TLS Web Client Authentication
X509v3 Subject Key Identifier:
F4:17:02:DD:1B:01:AB:C5:BC:17:A4:5C:4B:75:8E:EC:B1:E0:C8:F1
X509v3 Authority Key Identifier:
keyid:AE:42:88:75:DD:05:A6:8E:48:7F:50:69:F9:B7:34:23:49:B8:B4:71
Authority Information Access:
CA Issuers - URI:http://green.no/ca/tls-ca.cer
X509v3 CRL Distribution Points:
Full Name:
URI:http://green.no/ca/tls-ca.crl
X509v3 Subject Alternative Name:
email:barney@telenor.no
Signature Algorithm: sha1WithRSAEncryption
96:9a:c5:41:8a:2f:4a:c4:80:d9:2b:1a:cf:07:85:e9:b6:18:
01:20:41:b9:c3:d4:ca:d3:2d:66:c3:1d:52:7f:25:d7:92:0c:
e9:a9:ae:e6:2e:fa:9d:0a:cf:84:b9:03:f2:63:e3:d3:c9:70:
6a:ac:04:5e:a9:2d:a2:43:7a:34:60:f7:a9:32:e1:48:ec:c6:
03:ac:b3:06:2e:48:6e:d0:35:11:31:3d:0c:04:66:41:e6:b2:
ec:8c:68:f8:e4:bc:47:85:39:60:69:a9:8a:ee:2f:56:88:8a:
19:45:d0:84:8e:c2:27:2c:82:9c:07:6c:34:ae:41:61:63:f9:
32:cb:8b:33:ea:2c:15:5f:f9:35:b0:3c:51:4d:5f:30:de:0b:
88:28:94:79:f3:bd:69:37:ad:12:20:e1:6b:1d:b6:77:d9:83:
db:81:a4:53:6c:0f:6a:17:5e:2b:c1:94:c6:42:e3:73:cd:9e:
79:1b:8c:89:cd:da:ce:b0:f4:21:c5:32:25:04:6e:68:9f:a7:
ca:f4:c5:86:e5:4e:d9:fd:69:73:e6:15:50:6e:76:0f:73:5e:
7a:a3:f4:dc:15:4a:ab:bb:3c:9a:fa:9f:01:7a:5c:47:a9:a3:
68:1c:49:e0:37:37:77:af:87:07:16:e4:e1:d7:98:39:15:a6:
51:5d:4c:db
-----BEGIN CERTIFICATE-----
MIIEITCCAwmgAwIBAgIBAjANBgkqhkiG9w0BAQUFADBdMQswCQYDVQQGEwJOTzER
MA8GA1UECgwIR3JlZW4gQVMxJDAiBgNVBAsMG0dyZWVuIENlcnRpZmljYXRlIEF1
dGhvcml0eTEVMBMGA1UEAwwMR3JlZW4gVExTIENBMB4XDTE3MDcxMzA0MDI0N1oX
DTE5MDcxMzA0MDI0N1owTDELMAkGA1UEBhMCTk8xEzARBgNVBAoMClRlbGVub3Ig
QVMxEDAOBgNVBAsMB1N1cHBvcnQxFjAUBgNVBAMMDUJhcm5leSBSdWJibGUwggEi
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGZiN8FmFlsC6n25JQt6Gio8K/
9T7vsRPFQ3JLae+JYQcMBv+kVLwG3HigJDUQJVLLFxSZdKWu8OMxjiyKw4e+d01G
UaLbvgzlrxDnIPUFSq/Gre5cH/5Jg1VKEHNqzCtKOnMx7z0CU4/E+OcTXg5eHTSP
aEe6c4biOGVaAmdjRjK9RBBhY7oquYoyJngyCZjRJaH9mGWQMk+2SndpRUzayF4K
u7/vQT2+IsZ92WFzakgyyHLA2nj/kiQcFnBupcUUZfixG1Jcj9q5k29wc4Gx77d7
cGida8FZLaUhhvOlfe8sHsET0EYjFafV+A1CvXjIU9pxxKzMG+C2YRQ42iWfAgMB
AAGjgfwwgfkwDgYDVR0PAQH/BAQDAgeAMAkGA1UdEwQCMAAwEwYDVR0lBAwwCgYI
KwYBBQUHAwIwHQYDVR0OBBYEFPQXAt0bAavFvBekXEt1juyx4MjxMB8GA1UdIwQY
MBaAFK5CiHXdBaaOSH9Qafm3NCNJuLRxMDkGCCsGAQUFBwEBBC0wKzApBggrBgEF
BQcwAoYdaHR0cDovL2dyZWVuLm5vL2NhL3Rscy1jYS5jZXIwLgYDVR0fBCcwJTAj
oCGgH4YdaHR0cDovL2dyZWVuLm5vL2NhL3Rscy1jYS5jcmwwHAYDVR0RBBUwE4ER
YmFybmV5QHRlbGVub3Iubm8wDQYJKoZIhvcNAQEFBQADggEBAJaaxUGKL0rEgNkr
Gs8Hhem2GAEgQbnD1MrTLWbDHVJ/JdeSDOmpruYu+p0Kz4S5A/Jj49PJcGqsBF6p
LaJDejRg96ky4UjsxgOsswYuSG7QNRExPQwEZkHmsuyMaPjkvEeFOWBpqYruL1aI
ihlF0ISOwicsgpwHbDSuQWFj+TLLizPqLBVf+TWwPFFNXzDeC4golHnzvWk3rRIg
4WsdtnfZg9uBpFNsD2oXXivBlMZC43PNnnkbjInN2s6w9CHFMiUEbmifp8r0xYbl
Ttn9aXPmFVBudg9zXnqj9NwVSqu7PJr6nwF6XEepo2gcSeA3N3evhwcW5OHXmDkV
plFdTNs=
-----END CERTIFICATE-----

View file

@ -1 +0,0 @@
theanswertothegreatquestionoflifetheuniverseandeverythingisfortytwo

View file

@ -1,96 +0,0 @@
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 4 (0x4)
Signature Algorithm: sha1WithRSAEncryption
Issuer: C=NO, O=Green AS, OU=Green Certificate Authority, CN=Green TLS CA
Validity
Not Before: Jul 26 12:47:08 2017 GMT
Not After : Jul 26 12:47:08 2019 GMT
Subject: C=NO, O=Green AS, OU=Green Certificate Authority, CN=Green TLS CA
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:97:43:c5:f6:24:b8:ce:30:12:70:ea:17:9c:c0:
ce:f2:ef:58:8b:12:7d:46:5e:01:f1:1a:93:b2:3e:
d8:cf:99:bc:10:32:f1:12:b0:ef:00:6c:d6:c4:45:
85:a8:33:7b:cd:ec:8f:4a:92:d0:5a:4a:41:69:7f:
e3:dd:7e:71:d2:21:9c:df:43:b5:6c:60:bb:2a:12:
a8:08:cf:c5:ee:08:7d:48:ea:4b:54:e4:82:d9:88:
b0:b8:5e:02:12:cb:0e:09:99:b7:5f:42:b6:d7:26:
34:0f:4a:e7:fc:ac:9c:59:cd:a1:50:4c:88:5f:f1:
d2:7e:5b:21:41:f0:37:50:80:48:71:50:26:61:26:
79:64:4b:7e:91:8d:0e:f4:27:fe:19:80:bf:39:55:
b7:f3:d0:cd:61:6c:d8:c1:c7:d3:26:77:92:1a:14:
42:56:cb:bc:fd:1a:4a:eb:17:d8:8d:af:d1:c0:46:
9f:f0:40:5e:0e:34:2f:e7:db:be:66:fd:89:0b:6b:
8c:71:c1:0b:0a:c5:c4:c4:eb:7f:44:c1:75:36:23:
fd:ed:b6:ee:87:d9:88:47:e1:4b:7c:60:53:e7:85:
1c:2f:82:4b:2b:5e:63:1a:49:17:36:2c:fc:39:23:
49:22:4d:43:b5:51:22:12:24:9e:31:44:d8:16:4e:
a8:eb
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Key Usage: critical
Digital Signature, Key Encipherment
X509v3 Basic Constraints:
CA:FALSE
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
X509v3 Subject Key Identifier:
70:A9:FB:44:66:3C:63:96:E6:05:B2:74:47:C8:18:7E:43:6D:EE:8B
X509v3 Authority Key Identifier:
keyid:AE:42:88:75:DD:05:A6:8E:48:7F:50:69:F9:B7:34:23:49:B8:B4:71
Authority Information Access:
CA Issuers - URI:http://green.no/ca/tls-ca.cer
X509v3 CRL Distribution Points:
Full Name:
URI:http://green.no/ca/tls-ca.crl
X509v3 Subject Alternative Name:
IP Address:127.0.0.1, IP Address:127.0.0.0, DNS:localhost
Signature Algorithm: sha1WithRSAEncryption
56:1e:b8:52:ba:f5:72:42:ad:15:71:c1:5e:00:63:c9:4d:56:
f2:8d:a3:a9:91:db:d0:b5:1b:88:80:93:80:28:48:b2:d0:a9:
d0:ea:de:40:78:cc:57:8c:00:b8:65:99:68:95:98:9b:fb:a2:
43:21:ea:00:37:01:77:c7:3b:1a:ec:58:2d:25:9c:ad:23:41:
5e:ae:fd:ac:2f:26:81:b8:a7:49:9b:5a:10:fe:ad:c3:86:ab:
59:67:b0:c7:81:72:95:60:b5:cb:fc:9f:ad:27:16:50:85:76:
33:16:20:2c:1f:c6:14:09:0c:48:9f:c0:19:16:c9:fa:b0:d8:
bf:b7:8d:a7:aa:eb:fe:f8:6f:dd:2b:83:ee:c7:8a:df:c8:59:
e6:2e:13:1f:57:cc:6f:31:db:f7:b7:5c:3f:78:ad:22:2c:48:
bb:6d:c4:ab:dc:c1:76:34:29:d9:1e:67:e0:ac:37:2b:90:f9:
71:bd:cf:a1:01:b9:eb:0b:0b:79:2e:8b:52:3d:8e:13:97:c8:
05:a3:ef:68:82:49:12:2a:25:1a:48:49:b8:7c:3c:66:0d:74:
f9:00:8c:5b:57:d7:76:b1:26:95:86:b2:2e:a3:b2:9c:e0:eb:
2d:fc:77:03:8f:cd:56:46:3a:c9:6a:fa:72:e3:19:d8:ef:de:
4b:36:95:79
-----BEGIN CERTIFICATE-----
MIIEQjCCAyqgAwIBAgIBBDANBgkqhkiG9w0BAQUFADBdMQswCQYDVQQGEwJOTzER
MA8GA1UECgwIR3JlZW4gQVMxJDAiBgNVBAsMG0dyZWVuIENlcnRpZmljYXRlIEF1
dGhvcml0eTEVMBMGA1UEAwwMR3JlZW4gVExTIENBMB4XDTE3MDcyNjEyNDcwOFoX
DTE5MDcyNjEyNDcwOFowXTELMAkGA1UEBhMCTk8xETAPBgNVBAoMCEdyZWVuIEFT
MSQwIgYDVQQLDBtHcmVlbiBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxFTATBgNVBAMM
DEdyZWVuIFRMUyBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJdD
xfYkuM4wEnDqF5zAzvLvWIsSfUZeAfEak7I+2M+ZvBAy8RKw7wBs1sRFhagze83s
j0qS0FpKQWl/491+cdIhnN9DtWxguyoSqAjPxe4IfUjqS1TkgtmIsLheAhLLDgmZ
t19CttcmNA9K5/ysnFnNoVBMiF/x0n5bIUHwN1CASHFQJmEmeWRLfpGNDvQn/hmA
vzlVt/PQzWFs2MHH0yZ3khoUQlbLvP0aSusX2I2v0cBGn/BAXg40L+fbvmb9iQtr
jHHBCwrFxMTrf0TBdTYj/e227ofZiEfhS3xgU+eFHC+CSyteYxpJFzYs/DkjSSJN
Q7VRIhIknjFE2BZOqOsCAwEAAaOCAQswggEHMA4GA1UdDwEB/wQEAwIFoDAJBgNV
HRMEAjAAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAdBgNVHQ4EFgQU
cKn7RGY8Y5bmBbJ0R8gYfkNt7oswHwYDVR0jBBgwFoAUrkKIdd0Fpo5If1Bp+bc0
I0m4tHEwOQYIKwYBBQUHAQEELTArMCkGCCsGAQUFBzAChh1odHRwOi8vZ3JlZW4u
bm8vY2EvdGxzLWNhLmNlcjAuBgNVHR8EJzAlMCOgIaAfhh1odHRwOi8vZ3JlZW4u
bm8vY2EvdGxzLWNhLmNybDAgBgNVHREEGTAXhwR/AAABhwR/AAAAgglsb2NhbGhv
c3QwDQYJKoZIhvcNAQEFBQADggEBAFYeuFK69XJCrRVxwV4AY8lNVvKNo6mR29C1
G4iAk4AoSLLQqdDq3kB4zFeMALhlmWiVmJv7okMh6gA3AXfHOxrsWC0lnK0jQV6u
/awvJoG4p0mbWhD+rcOGq1lnsMeBcpVgtcv8n60nFlCFdjMWICwfxhQJDEifwBkW
yfqw2L+3jaeq6/74b90rg+7Hit/IWeYuEx9XzG8x2/e3XD94rSIsSLttxKvcwXY0
KdkeZ+CsNyuQ+XG9z6EBuesLC3kui1I9jhOXyAWj72iCSRIqJRpISbh8PGYNdPkA
jFtX13axJpWGsi6jspzg6y38dwOPzVZGOslq+nLjGdjv3ks2lXk=
-----END CERTIFICATE-----

View file

@ -1,28 +0,0 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCXQ8X2JLjOMBJw
6hecwM7y71iLEn1GXgHxGpOyPtjPmbwQMvESsO8AbNbERYWoM3vN7I9KktBaSkFp
f+PdfnHSIZzfQ7VsYLsqEqgIz8XuCH1I6ktU5ILZiLC4XgISyw4JmbdfQrbXJjQP
Suf8rJxZzaFQTIhf8dJ+WyFB8DdQgEhxUCZhJnlkS36RjQ70J/4ZgL85Vbfz0M1h
bNjBx9Mmd5IaFEJWy7z9GkrrF9iNr9HARp/wQF4ONC/n275m/YkLa4xxwQsKxcTE
639EwXU2I/3ttu6H2YhH4Ut8YFPnhRwvgksrXmMaSRc2LPw5I0kiTUO1USISJJ4x
RNgWTqjrAgMBAAECggEAVurwo4FyV7gzwIIi00XPJLT3ceJL7dUy1HHrEG8gchnq
gHxlHdJhYyMnPVydcosyxp75r2YxJtCoSZDdRHbVvGLoGzpy0zW6FnDl8TpCh4aF
RxKp+rvbnFf5A9ew5U+cX1PelHRnT7V6EJeAOiaNKOUJnnR7oHX59/UxZQw9HJnX
3H4xUdRDmSS3BGKXEswbd7beQjqJtEIkbConfaw32yEod0w2MC0LI4miZ87/6Hsk
pyvfpeYxXp4z3BTvFBbf/GEBFuozu63VWHayB9PDmEN/TlphoQpJQihdR2r1lz/H
I5QwVlFTDvUSFitNLu+FoaHOfgLprQndbojBXb+tcQKBgQDHCPyM4V7k97RvJgmB
ELgZiDYufDrjRLXvFzrrZ7ySU3N+nx3Gz/EhtgbHicDjnRVagHBIwi/QAfBJksCd
xcioY5k2OW+8PSTsfFZTAA6XwJp/LGfJik/JjvAVv5CnxBu9lYG4WiSBJFp59ojC
zTmfEuB4GPwrjQvzjlqaSpij9QKBgQDCjriwAB2UJIdlgK+DkryLqgim5I4cteB3
+juVKz+S8ufFmVvmIXkyDcpyy/26VLC6esy8dV0JoWc4EeitoJvQD1JVZ5+CBTY+
r9umx18oe2A/ZgcEf/A3Zd94jM1MwriF6YC+eIOhwhpi7T1xTLf3hc9B0OJ5B1mA
vob9rGDtXwKBgD4rkW+UCictNIAvenKFPWxEPuBgT6ij0sx/DhlwCtgOFxprK0rp
syFbkVyMq+KtM3lUez5O4c5wfJUOsPnXSOlISxhD8qHy23C/GdvNPcGrGNc2kKjE
ek20R0wTzWSJ/jxG0gE6rwJjz5sfJfLrVd9ZbyI0c7hK03vdcHGXcXxtAoGAeGHl
BwnbQ3niyTx53VijD2wTVGjhQgSLstEDowYSnTNtk8eTpG6b1gvQc32jLnMOsyQe
oJGiEr5q5re2GBDjuDZyxGOMv9/Hs7wOlkCQsbS9Vh0kRHWBRlXjk2zT7yYhFMLp
pXFeSW2X9BRFS2CkCCUkm93K9AZHLDE3x6ishNMCgYEAsDsUCzGhI49Aqe+CMP2l
WPZl7SEMYS5AtdC5sLtbLYBl8+rMXVGL2opKXqVFYBYkqMJiHGdX3Ub6XSVKLYkN
vm4PWmlQS24ZT+jlUl4jk6JU6SAlM/o6ixZl5KNR7yQm6zN2O/RHDeYm0urUQ9tF
9dux7LbIFeOoJmoDTWG2+fI=
-----END PRIVATE KEY-----

View file

@ -1,172 +0,0 @@
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 2 (0x2)
Signature Algorithm: sha1WithRSAEncryption
Issuer: C=NO, O=Green AS, OU=Green Certificate Authority, CN=Green Root CA
Validity
Not Before: Jul 13 03:47:20 2017 GMT
Not After : Jul 13 03:47:20 2027 GMT
Subject: C=NO, O=Green AS, OU=Green Certificate Authority, CN=Green TLS CA
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:b5:5a:b3:7a:7f:6a:5b:e9:ee:62:ee:4f:61:42:
79:93:06:bf:81:fc:9a:1f:b5:80:83:7c:b3:a6:94:
54:58:8a:b1:74:cb:c3:b8:3c:23:a8:69:1f:ca:2b:
af:be:97:ba:31:73:b5:b8:ce:d9:bf:bf:9a:7a:cf:
3a:64:51:83:c9:36:d2:f7:3b:3a:0e:4c:c7:66:2e:
bf:1a:df:ce:10:aa:3d:0f:19:74:03:7e:b5:10:bb:
e8:37:bd:62:f0:42:2d:df:3d:ca:70:50:10:17:ce:
a9:ec:55:8e:87:6f:ce:9a:04:36:14:96:cb:d1:a5:
48:d5:d2:87:02:62:93:4e:21:4a:ff:be:44:f1:d2:
7e:ed:74:da:c2:51:26:8e:03:a0:c2:bd:bd:5f:b0:
50:11:78:fd:ab:1d:04:86:6c:c1:8d:20:bd:05:5f:
51:67:c6:d3:07:95:92:2d:92:90:00:c6:9f:2d:dd:
36:5c:dc:78:10:7c:f6:68:39:1d:2c:e0:e1:26:64:
4f:36:34:66:a7:84:6a:90:15:3a:94:b7:79:b1:47:
f5:d2:51:95:54:bf:92:76:9a:b9:88:ee:63:f9:6c:
0d:38:c6:b6:1c:06:43:ed:24:1d:bb:6c:72:48:cc:
8c:f4:35:bc:43:fe:a6:96:4c:31:5f:82:0d:0d:20:
2a:3d
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Key Usage: critical
Certificate Sign, CRL Sign
X509v3 Basic Constraints: critical
CA:TRUE, pathlen:0
X509v3 Subject Key Identifier:
AE:42:88:75:DD:05:A6:8E:48:7F:50:69:F9:B7:34:23:49:B8:B4:71
X509v3 Authority Key Identifier:
keyid:60:93:53:2F:C7:CF:2A:D7:F3:09:28:F6:3C:AE:9C:50:EC:93:63:E5
Authority Information Access:
CA Issuers - URI:http://green.no/ca/root-ca.cer
X509v3 CRL Distribution Points:
Full Name:
URI:http://green.no/ca/root-ca.crl
Signature Algorithm: sha1WithRSAEncryption
15:a7:ac:d7:25:9e:2a:d4:d1:14:b4:99:38:3d:2f:73:61:2a:
d9:b6:8b:13:ea:fe:db:78:d9:0a:6c:df:26:6e:c1:d5:4a:97:
42:19:dd:97:05:03:e4:2b:fc:1e:1f:38:3c:4e:b0:3b:8c:38:
ad:2b:65:fa:35:2d:81:8e:e0:f6:0a:89:4c:38:97:01:4b:9c:
ac:4e:e1:55:17:ef:0a:ad:a7:eb:1e:4b:86:23:12:f1:52:69:
cb:a3:8a:ce:fb:14:8b:86:d7:bb:81:5e:bd:2a:c7:a7:79:58:
00:10:c0:db:ff:d4:a5:b9:19:74:b3:23:19:4a:1f:78:4b:a8:
b6:f6:20:26:c1:69:f9:89:7f:b8:1c:3b:a2:f9:37:31:80:2c:
b0:b6:2b:d2:84:44:d7:42:e4:e6:44:51:04:35:d9:1c:a4:48:
c6:b7:35:de:f2:ae:da:4b:ba:c8:09:42:8d:ed:7a:81:dc:ed:
9d:f0:de:6e:21:b9:01:1c:ad:64:3d:25:4c:91:94:f1:13:18:
bb:89:e9:48:ac:05:73:07:c8:db:bd:69:8e:6f:02:9d:b0:18:
c0:b9:e1:a8:b1:17:50:3d:ac:05:6e:6f:63:4f:b1:73:33:60:
9a:77:d2:81:8a:01:38:43:e9:4c:3c:90:63:a4:99:4b:d2:1b:
f9:1b:ec:ee
-----BEGIN CERTIFICATE-----
MIIECzCCAvOgAwIBAgIBAjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJOTzER
MA8GA1UECgwIR3JlZW4gQVMxJDAiBgNVBAsMG0dyZWVuIENlcnRpZmljYXRlIEF1
dGhvcml0eTEWMBQGA1UEAwwNR3JlZW4gUm9vdCBDQTAeFw0xNzA3MTMwMzQ3MjBa
Fw0yNzA3MTMwMzQ3MjBaMF0xCzAJBgNVBAYTAk5PMREwDwYDVQQKDAhHcmVlbiBB
UzEkMCIGA1UECwwbR3JlZW4gQ2VydGlmaWNhdGUgQXV0aG9yaXR5MRUwEwYDVQQD
DAxHcmVlbiBUTFMgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC1
WrN6f2pb6e5i7k9hQnmTBr+B/JoftYCDfLOmlFRYirF0y8O4PCOoaR/KK6++l7ox
c7W4ztm/v5p6zzpkUYPJNtL3OzoOTMdmLr8a384Qqj0PGXQDfrUQu+g3vWLwQi3f
PcpwUBAXzqnsVY6Hb86aBDYUlsvRpUjV0ocCYpNOIUr/vkTx0n7tdNrCUSaOA6DC
vb1fsFAReP2rHQSGbMGNIL0FX1FnxtMHlZItkpAAxp8t3TZc3HgQfPZoOR0s4OEm
ZE82NGanhGqQFTqUt3mxR/XSUZVUv5J2mrmI7mP5bA04xrYcBkPtJB27bHJIzIz0
NbxD/qaWTDFfgg0NICo9AgMBAAGjgdQwgdEwDgYDVR0PAQH/BAQDAgEGMBIGA1Ud
EwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFK5CiHXdBaaOSH9Qafm3NCNJuLRxMB8G
A1UdIwQYMBaAFGCTUy/HzyrX8wko9jyunFDsk2PlMDoGCCsGAQUFBwEBBC4wLDAq
BggrBgEFBQcwAoYeaHR0cDovL2dyZWVuLm5vL2NhL3Jvb3QtY2EuY2VyMC8GA1Ud
HwQoMCYwJKAioCCGHmh0dHA6Ly9ncmVlbi5uby9jYS9yb290LWNhLmNybDANBgkq
hkiG9w0BAQUFAAOCAQEAFaes1yWeKtTRFLSZOD0vc2Eq2baLE+r+23jZCmzfJm7B
1UqXQhndlwUD5Cv8Hh84PE6wO4w4rStl+jUtgY7g9gqJTDiXAUucrE7hVRfvCq2n
6x5LhiMS8VJpy6OKzvsUi4bXu4FevSrHp3lYABDA2//UpbkZdLMjGUofeEuotvYg
JsFp+Yl/uBw7ovk3MYAssLYr0oRE10Lk5kRRBDXZHKRIxrc13vKu2ku6yAlCje16
gdztnfDebiG5ARytZD0lTJGU8RMYu4npSKwFcwfI271pjm8CnbAYwLnhqLEXUD2s
BW5vY0+xczNgmnfSgYoBOEPpTDyQY6SZS9Ib+Rvs7g==
-----END CERTIFICATE-----
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 1 (0x1)
Signature Algorithm: sha1WithRSAEncryption
Issuer: C=NO, O=Green AS, OU=Green Certificate Authority, CN=Green Root CA
Validity
Not Before: Jul 13 03:44:39 2017 GMT
Not After : Dec 31 23:59:59 2030 GMT
Subject: C=NO, O=Green AS, OU=Green Certificate Authority, CN=Green Root CA
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:a7:e8:ed:de:d4:54:08:41:07:40:d5:c0:43:d6:
ab:d3:9e:21:87:c6:13:bf:a7:cf:3d:08:4f:c1:fe:
8f:e5:6c:c5:89:97:e5:27:75:26:c3:2a:73:2d:34:
7c:6f:35:8d:40:66:61:05:c0:eb:e9:b3:38:47:f8:
8b:26:35:2c:df:dc:24:31:fe:72:e3:87:10:d1:f7:
a0:57:b7:f3:b1:1a:fe:c7:4b:f8:7b:14:6d:73:08:
54:eb:63:3c:0c:ce:22:95:5f:3f:f2:6f:89:ae:63:
da:80:74:36:21:13:e8:91:01:58:77:cc:c2:f2:42:
bf:eb:b3:60:a7:21:ed:88:24:7f:eb:ff:07:41:9b:
93:c8:5f:6a:8e:a6:1a:15:3c:bc:e7:0d:fd:05:fd:
3c:c1:1c:1d:1f:57:2b:40:27:62:a1:7c:48:63:c1:
45:e7:2f:20:ed:92:1c:42:94:e4:58:70:7a:b6:d2:
85:c5:61:d8:cd:c6:37:6b:72:3b:7f:af:55:81:d6:
9d:dc:10:c9:d8:0e:81:e4:5e:40:13:2f:20:e8:6b:
46:81:ce:88:47:dd:38:71:3d:ef:21:cc:c0:67:cf:
0a:f4:e9:3f:a8:9d:26:25:2e:23:1e:a3:11:18:cb:
d1:70:1c:9e:7d:09:b1:a4:20:dc:95:15:1d:49:cf:
1b:ad
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Key Usage: critical
Certificate Sign, CRL Sign
X509v3 Basic Constraints: critical
CA:TRUE
X509v3 Subject Key Identifier:
60:93:53:2F:C7:CF:2A:D7:F3:09:28:F6:3C:AE:9C:50:EC:93:63:E5
X509v3 Authority Key Identifier:
keyid:60:93:53:2F:C7:CF:2A:D7:F3:09:28:F6:3C:AE:9C:50:EC:93:63:E5
Signature Algorithm: sha1WithRSAEncryption
a7:77:71:8b:1a:e5:5a:5b:87:54:08:bf:07:3e:cb:99:2f:dc:
0e:8d:63:94:95:83:19:c9:92:82:d5:cb:5b:8f:1f:86:55:bc:
70:01:1d:33:46:ec:99:de:6b:1f:c3:c2:7a:dd:ef:69:ab:96:
58:ec:6c:6f:6c:70:82:71:8a:7f:f0:3b:80:90:d5:64:fa:80:
27:b8:7b:50:69:98:4b:37:99:ad:bf:a2:5b:93:22:5e:96:44:
3c:5a:cf:0c:f4:62:63:4a:6f:72:a7:f6:89:1d:09:26:3d:8f:
a8:86:d4:b4:bc:dd:b3:38:ca:c0:59:16:8c:20:1f:89:35:12:
b4:2d:c0:e9:de:93:e0:39:76:32:fc:80:db:da:44:26:fd:01:
32:74:97:f8:44:ae:fe:05:b1:34:96:13:34:56:73:b4:93:a5:
55:56:d1:01:51:9d:9c:55:e7:38:53:28:12:4e:38:72:0c:8f:
bd:91:4c:45:48:3b:e1:0d:03:5f:58:40:c9:d3:a0:ac:b3:89:
ce:af:27:8a:0f:ab:ec:72:4d:40:77:30:6b:36:fd:32:46:9f:
ee:f9:c4:f5:17:06:0f:4b:d3:88:f5:a4:2f:3d:87:9e:f5:26:
74:f0:c9:dc:cb:ad:d9:a7:8a:d3:71:15:00:d3:5d:9f:4c:59:
3e:24:63:f5
-----BEGIN CERTIFICATE-----
MIIDnDCCAoSgAwIBAgIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJOTzER
MA8GA1UECgwIR3JlZW4gQVMxJDAiBgNVBAsMG0dyZWVuIENlcnRpZmljYXRlIEF1
dGhvcml0eTEWMBQGA1UEAwwNR3JlZW4gUm9vdCBDQTAgFw0xNzA3MTMwMzQ0Mzla
GA8yMDMwMTIzMTIzNTk1OVowXjELMAkGA1UEBhMCTk8xETAPBgNVBAoMCEdyZWVu
IEFTMSQwIgYDVQQLDBtHcmVlbiBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxFjAUBgNV
BAMMDUdyZWVuIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
AQCn6O3e1FQIQQdA1cBD1qvTniGHxhO/p889CE/B/o/lbMWJl+UndSbDKnMtNHxv
NY1AZmEFwOvpszhH+IsmNSzf3CQx/nLjhxDR96BXt/OxGv7HS/h7FG1zCFTrYzwM
ziKVXz/yb4muY9qAdDYhE+iRAVh3zMLyQr/rs2CnIe2IJH/r/wdBm5PIX2qOphoV
PLznDf0F/TzBHB0fVytAJ2KhfEhjwUXnLyDtkhxClORYcHq20oXFYdjNxjdrcjt/
r1WB1p3cEMnYDoHkXkATLyDoa0aBzohH3ThxPe8hzMBnzwr06T+onSYlLiMeoxEY
y9FwHJ59CbGkINyVFR1JzxutAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNV
HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRgk1Mvx88q1/MJKPY8rpxQ7JNj5TAfBgNV
HSMEGDAWgBRgk1Mvx88q1/MJKPY8rpxQ7JNj5TANBgkqhkiG9w0BAQUFAAOCAQEA
p3dxixrlWluHVAi/Bz7LmS/cDo1jlJWDGcmSgtXLW48fhlW8cAEdM0bsmd5rH8PC
et3vaauWWOxsb2xwgnGKf/A7gJDVZPqAJ7h7UGmYSzeZrb+iW5MiXpZEPFrPDPRi
Y0pvcqf2iR0JJj2PqIbUtLzdszjKwFkWjCAfiTUStC3A6d6T4Dl2MvyA29pEJv0B
MnSX+ESu/gWxNJYTNFZztJOlVVbRAVGdnFXnOFMoEk44cgyPvZFMRUg74Q0DX1hA
ydOgrLOJzq8nig+r7HJNQHcwazb9Mkaf7vnE9RcGD0vTiPWkLz2HnvUmdPDJ3Mut
2aeK03EVANNdn0xZPiRj9Q==
-----END CERTIFICATE-----

View file

@ -21,14 +21,17 @@ import (
"net/http" "net/http"
"net/url" "net/url"
"strings" "strings"
"time"
"github.com/mwitkow/go-conntrack"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
) )
// BasicAuth contains basic HTTP authentication credentials. // BasicAuth contains basic HTTP authentication credentials.
type BasicAuth struct { type BasicAuth struct {
Username string `yaml:"username"` Username string `yaml:"username"`
Password Secret `yaml:"password"` Password Secret `yaml:"password,omitempty"`
PasswordFile string `yaml:"password_file,omitempty"`
// Catches all undefined fields and must be empty after parsing. // Catches all undefined fields and must be empty after parsing.
XXX map[string]interface{} `yaml:",inline"` XXX map[string]interface{} `yaml:",inline"`
@ -88,6 +91,12 @@ func (c *HTTPClientConfig) Validate() error {
if c.BasicAuth != nil && (len(c.BearerToken) > 0 || len(c.BearerTokenFile) > 0) { if c.BasicAuth != nil && (len(c.BearerToken) > 0 || len(c.BearerTokenFile) > 0) {
return fmt.Errorf("at most one of basic_auth, bearer_token & bearer_token_file must be configured") return fmt.Errorf("at most one of basic_auth, bearer_token & bearer_token_file must be configured")
} }
if c.BasicAuth != nil && c.BasicAuth.Username == "" {
return fmt.Errorf("basic_auth requires a username")
}
if c.BasicAuth != nil && (string(c.BasicAuth.Password) != "" && c.BasicAuth.PasswordFile != "") {
return fmt.Errorf("at most one of basic_auth password & password_file must be configured")
}
return nil return nil
} }
@ -115,42 +124,60 @@ func (a *BasicAuth) UnmarshalYAML(unmarshal func(interface{}) error) error {
return checkOverflow(a.XXX, "basic_auth") return checkOverflow(a.XXX, "basic_auth")
} }
// NewHTTPClientFromConfig returns a new HTTP client configured for the // NewClient returns a http.Client using the specified http.RoundTripper.
// given config.HTTPClientConfig. func newClient(rt http.RoundTripper) *http.Client {
func NewHTTPClientFromConfig(cfg *HTTPClientConfig) (*http.Client, error) { return &http.Client{Transport: rt}
}
// NewClientFromConfig returns a new HTTP client configured for the
// given config.HTTPClientConfig. The name is used as go-conntrack metric label.
func NewClientFromConfig(cfg HTTPClientConfig, name string) (*http.Client, error) {
rt, err := NewRoundTripperFromConfig(cfg, name)
if err != nil {
return nil, err
}
return newClient(rt), nil
}
// NewRoundTripperFromConfig returns a new HTTP RoundTripper configured for the
// given config.HTTPClientConfig. The name is used as go-conntrack metric label.
func NewRoundTripperFromConfig(cfg HTTPClientConfig, name string) (http.RoundTripper, error) {
tlsConfig, err := NewTLSConfig(&cfg.TLSConfig) tlsConfig, err := NewTLSConfig(&cfg.TLSConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// The only timeout we care about is the configured scrape timeout.
// It's the caller's job to handle timeouts // It is applied on request. So we leave out any timings here.
var rt http.RoundTripper = &http.Transport{ var rt http.RoundTripper = &http.Transport{
Proxy: http.ProxyURL(cfg.ProxyURL.URL), Proxy: http.ProxyURL(cfg.ProxyURL.URL),
DisableKeepAlives: true, MaxIdleConns: 20000,
MaxIdleConnsPerHost: 1000, // see https://github.com/golang/go/issues/13801
DisableKeepAlives: false,
TLSClientConfig: tlsConfig, TLSClientConfig: tlsConfig,
DisableCompression: true,
// 5 minutes is typically above the maximum sane scrape interval. So we can
// use keepalive for all configurations.
IdleConnTimeout: 5 * time.Minute,
DialContext: conntrack.NewDialContextFunc(
conntrack.DialWithTracing(),
conntrack.DialWithName(name),
),
} }
// If a bearer token is provided, create a round tripper that will set the // If a bearer token is provided, create a round tripper that will set the
// Authorization header correctly on each request. // Authorization header correctly on each request.
bearerToken := cfg.BearerToken if len(cfg.BearerToken) > 0 {
if len(bearerToken) == 0 && len(cfg.BearerTokenFile) > 0 { rt = NewBearerAuthRoundTripper(cfg.BearerToken, rt)
b, err := ioutil.ReadFile(cfg.BearerTokenFile) } else if len(cfg.BearerTokenFile) > 0 {
if err != nil { rt = NewBearerAuthFileRoundTripper(cfg.BearerTokenFile, rt)
return nil, fmt.Errorf("unable to read bearer token file %s: %s", cfg.BearerTokenFile, err)
}
bearerToken = Secret(strings.TrimSpace(string(b)))
}
if len(bearerToken) > 0 {
rt = NewBearerAuthRoundTripper(bearerToken, rt)
} }
if cfg.BasicAuth != nil { if cfg.BasicAuth != nil {
rt = NewBasicAuthRoundTripper(cfg.BasicAuth.Username, Secret(cfg.BasicAuth.Password), rt) rt = NewBasicAuthRoundTripper(cfg.BasicAuth.Username, cfg.BasicAuth.Password, cfg.BasicAuth.PasswordFile, rt)
} }
// Return a new client with the configured round tripper. // Return a new configured RoundTripper.
return &http.Client{Transport: rt}, nil return rt, nil
} }
type bearerAuthRoundTripper struct { type bearerAuthRoundTripper struct {
@ -158,39 +185,73 @@ type bearerAuthRoundTripper struct {
rt http.RoundTripper rt http.RoundTripper
} }
type basicAuthRoundTripper struct { // NewBearerAuthRoundTripper adds the provided bearer token to a request unless the authorization
username string // header has already been set.
password Secret func NewBearerAuthRoundTripper(token Secret, rt http.RoundTripper) http.RoundTripper {
rt http.RoundTripper return &bearerAuthRoundTripper{token, rt}
}
// NewBasicAuthRoundTripper will apply a BASIC auth authorization header to a request unless it has
// already been set.
func NewBasicAuthRoundTripper(username string, password Secret, rt http.RoundTripper) http.RoundTripper {
return &basicAuthRoundTripper{username, password, rt}
} }
func (rt *bearerAuthRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { func (rt *bearerAuthRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
if len(req.Header.Get("Authorization")) == 0 { if len(req.Header.Get("Authorization")) == 0 {
req = cloneRequest(req) req = cloneRequest(req)
req.Header.Set("Authorization", "Bearer "+string(rt.bearerToken)) req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", string(rt.bearerToken)))
}
return rt.rt.RoundTrip(req)
}
type bearerAuthFileRoundTripper struct {
bearerFile string
rt http.RoundTripper
}
// NewBearerAuthFileRoundTripper adds the bearer token read from the provided file to a request unless
// the authorization header has already been set. This file is read for every request.
func NewBearerAuthFileRoundTripper(bearerFile string, rt http.RoundTripper) http.RoundTripper {
return &bearerAuthFileRoundTripper{bearerFile, rt}
}
func (rt *bearerAuthFileRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
if len(req.Header.Get("Authorization")) == 0 {
b, err := ioutil.ReadFile(rt.bearerFile)
if err != nil {
return nil, fmt.Errorf("unable to read bearer token file %s: %s", rt.bearerFile, err)
}
bearerToken := strings.TrimSpace(string(b))
req = cloneRequest(req)
req.Header.Set("Authorization", "Bearer "+bearerToken)
} }
return rt.rt.RoundTrip(req) return rt.rt.RoundTrip(req)
} }
// NewBearerAuthRoundTripper adds the provided bearer token to a request unless the authorization type basicAuthRoundTripper struct {
// header has already been set. username string
func NewBearerAuthRoundTripper(bearer Secret, rt http.RoundTripper) http.RoundTripper { password Secret
return &bearerAuthRoundTripper{bearer, rt} passwordFile string
rt http.RoundTripper
}
// NewBasicAuthRoundTripper will apply a BASIC auth authorization header to a request unless it has
// already been set.
func NewBasicAuthRoundTripper(username string, password Secret, passwordFile string, rt http.RoundTripper) http.RoundTripper {
return &basicAuthRoundTripper{username, password, passwordFile, rt}
} }
func (rt *basicAuthRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { func (rt *basicAuthRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
if len(req.Header.Get("Authorization")) != 0 { if len(req.Header.Get("Authorization")) != 0 {
return rt.RoundTrip(req) return rt.rt.RoundTrip(req)
} }
req = cloneRequest(req) req = cloneRequest(req)
req.SetBasicAuth(rt.username, string(rt.password)) if rt.passwordFile != "" {
bs, err := ioutil.ReadFile(rt.passwordFile)
if err != nil {
return nil, fmt.Errorf("unable to read basic auth password file %s: %s", rt.passwordFile, err)
}
req.SetBasicAuth(rt.username, strings.TrimSpace(string(bs)))
} else {
req.SetBasicAuth(rt.username, strings.TrimSpace(string(rt.password)))
}
return rt.rt.RoundTrip(req) return rt.rt.RoundTrip(req)
} }
@ -208,7 +269,7 @@ func cloneRequest(r *http.Request) *http.Request {
return r2 return r2
} }
// NewTLSConfig creates a new tls.Config from the given config.TLSConfig. // NewTLSConfig creates a new tls.Config from the given TLSConfig.
func NewTLSConfig(cfg *TLSConfig) (*tls.Config, error) { func NewTLSConfig(cfg *TLSConfig) (*tls.Config, error) {
tlsConfig := &tls.Config{InsecureSkipVerify: cfg.InsecureSkipVerify} tlsConfig := &tls.Config{InsecureSkipVerify: cfg.InsecureSkipVerify}
@ -228,7 +289,6 @@ func NewTLSConfig(cfg *TLSConfig) (*tls.Config, error) {
if len(cfg.ServerName) > 0 { if len(cfg.ServerName) > 0 {
tlsConfig.ServerName = cfg.ServerName tlsConfig.ServerName = cfg.ServerName
} }
// If a client cert & key is provided then configure TLS config accordingly. // If a client cert & key is provided then configure TLS config accordingly.
if len(cfg.CertFile) > 0 && len(cfg.KeyFile) == 0 { if len(cfg.CertFile) > 0 && len(cfg.KeyFile) == 0 {
return nil, fmt.Errorf("client cert file %q specified without client key file", cfg.CertFile) return nil, fmt.Errorf("client cert file %q specified without client key file", cfg.CertFile)

6
vendor/vendor.json vendored
View file

@ -772,10 +772,10 @@
"revisionTime": "2015-02-12T10:17:44Z" "revisionTime": "2015-02-12T10:17:44Z"
}, },
{ {
"checksumSHA1": "i+0TxE6bOpJdPNOeNHpO0vMzFh4=", "checksumSHA1": "bgmAaHIDapEUVLIWaqpxG9t4mYQ=",
"path": "github.com/prometheus/common/config", "path": "github.com/prometheus/common/config",
"revision": "38c53a9f4bfcd932d1b00bfc65e256a7fba6b37a", "revision": "e5b036cc37a466a0af27d604d1ee500211d16d6a",
"revisionTime": "2018-03-26T16:04:09Z" "revisionTime": "2018-04-23T14:05:01Z"
}, },
{ {
"checksumSHA1": "+wZ+Pa6NX+NOxUvayXBXGOcqFe8=", "checksumSHA1": "+wZ+Pa6NX+NOxUvayXBXGOcqFe8=",