mirror of
https://github.com/docker/docs.git
synced 2026-11-05 00:14:17 +03:00
Merge pull request #729 from cyli/server-gun-prefixes
Server gun prefix requirement feature
This commit is contained in:
@@ -140,7 +140,7 @@ func fullTestServer(t *testing.T) *httptest.Server {
|
||||
ctx = ctxu.WithLogger(ctx, logrus.NewEntry(l))
|
||||
|
||||
cryptoService := cryptoservice.NewCryptoService(trustmanager.NewKeyMemoryStore(passphraseRetriever))
|
||||
return httptest.NewServer(server.RootHandler(nil, ctx, cryptoService, nil, nil))
|
||||
return httptest.NewServer(server.RootHandler(nil, ctx, cryptoService, nil, nil, nil))
|
||||
}
|
||||
|
||||
// server that returns some particular error code all the time
|
||||
|
||||
@@ -3,7 +3,9 @@ package main
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
@@ -21,9 +23,21 @@ import (
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/spf13/viper"
|
||||
"golang.org/x/net/context"
|
||||
"gopkg.in/dancannon/gorethink.v2"
|
||||
gorethink "gopkg.in/dancannon/gorethink.v2"
|
||||
)
|
||||
|
||||
// gets the required gun prefixes accepted by this server
|
||||
func getRequiredGunPrefixes(configuration *viper.Viper) ([]string, error) {
|
||||
prefixes := configuration.GetStringSlice("repositories.gun_prefixes")
|
||||
for _, prefix := range prefixes {
|
||||
p := path.Clean(strings.TrimSpace(prefix))
|
||||
if p+"/" != prefix || strings.HasPrefix(p, "/") || strings.HasPrefix(p, "..") {
|
||||
return nil, fmt.Errorf("invalid GUN prefix %s", prefix)
|
||||
}
|
||||
}
|
||||
return prefixes, nil
|
||||
}
|
||||
|
||||
// get the address for the HTTP server, and parses the optional TLS
|
||||
// configuration for the server - if no TLS configuration is specified,
|
||||
// TLS is not enabled.
|
||||
@@ -217,6 +231,11 @@ func parseServerConfig(configFilePath string, hRegister healthRegister) (context
|
||||
}
|
||||
logrus.SetLevel(lvl)
|
||||
|
||||
prefixes, err := getRequiredGunPrefixes(config)
|
||||
if err != nil {
|
||||
return nil, server.Config{}, err
|
||||
}
|
||||
|
||||
// parse bugsnag config
|
||||
bugsnagConf, err := utils.ParseBugsnag(config)
|
||||
if err != nil {
|
||||
@@ -252,6 +271,7 @@ func parseServerConfig(configFilePath string, hRegister healthRegister) (context
|
||||
Trust: trust,
|
||||
AuthMethod: config.GetString("auth.type"),
|
||||
AuthOpts: config.Get("auth.options"),
|
||||
RepoPrefixes: prefixes,
|
||||
CurrentCacheControlConfig: currentCache,
|
||||
ConsistentCacheControlConfig: consistentCache,
|
||||
}, nil
|
||||
|
||||
@@ -403,6 +403,32 @@ func TestGetCacheConfig(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetGUNPRefixes(t *testing.T) {
|
||||
valids := map[string][]string{
|
||||
`{}`: nil,
|
||||
`{"repositories": {"gun_prefixes": []}}`: nil,
|
||||
`{"repositories": {}}`: nil,
|
||||
`{"repositories": {"gun_prefixes": ["hello/"]}}`: {"hello/"},
|
||||
}
|
||||
invalids := []string{
|
||||
`{"repositories": {"gun_prefixes": " / "}}`,
|
||||
`{"repositories": {"gun_prefixes": "nope"}}`,
|
||||
`{"repositories": {"gun_prefixes": ["nope"]}}`,
|
||||
`{"repositories": {"gun_prefixes": ["/nope/"]}}`,
|
||||
`{"repositories": {"gun_prefixes": ["../nope/"]}}`,
|
||||
}
|
||||
|
||||
for valid, expected := range valids {
|
||||
prefixes, err := getRequiredGunPrefixes(configure(valid))
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, expected, prefixes)
|
||||
}
|
||||
for _, invalid := range invalids {
|
||||
_, err := getRequiredGunPrefixes(configure(invalid))
|
||||
require.Error(t, err, "expected error with %s", invalid)
|
||||
}
|
||||
}
|
||||
|
||||
// For sanity, make sure we can always parse the sample config
|
||||
func TestSampleConfig(t *testing.T) {
|
||||
var registerCalled = 0
|
||||
|
||||
@@ -73,7 +73,7 @@ func setupServerHandler(metaStore storage.MetaStore) http.Handler {
|
||||
ctx = ctxu.WithLogger(ctx, logrus.NewEntry(l))
|
||||
|
||||
cryptoService := cryptoservice.NewCryptoService(trustmanager.NewKeyMemoryStore(passphrase.ConstantRetriever("pass")))
|
||||
return server.RootHandler(nil, ctx, cryptoService, nil, nil)
|
||||
return server.RootHandler(nil, ctx, cryptoService, nil, nil, nil)
|
||||
}
|
||||
|
||||
// makes a testing notary-server
|
||||
|
||||
@@ -327,7 +327,7 @@ func setUpRepo(t *testing.T, tempBaseDir, gun string, ret passphrase.Retriever)
|
||||
ctx = ctxu.WithLogger(ctx, logrus.NewEntry(l))
|
||||
|
||||
cryptoService := cryptoservice.NewCryptoService(trustmanager.NewKeyMemoryStore(ret))
|
||||
ts := httptest.NewServer(server.RootHandler(nil, ctx, cryptoService, nil, nil))
|
||||
ts := httptest.NewServer(server.RootHandler(nil, ctx, cryptoService, nil, nil, nil))
|
||||
|
||||
repo, err := client.NewNotaryRepository(
|
||||
tempBaseDir, gun, ts.URL, http.DefaultTransport, ret, trustpinning.TrustPinConfig{})
|
||||
|
||||
@@ -58,12 +58,15 @@ learn more about the configuration section corresponding to that key:
|
||||
"api_key": "c9d60ae4c7e70c4b6c4ebd3e8056d2b8",
|
||||
"release_stage": "production"
|
||||
}
|
||||
}
|
||||
},
|
||||
<a href="#caching-section-optional">"caching"</a>: {
|
||||
"max_age": {
|
||||
"current_metadata": 300,
|
||||
"consistent_metadata": 31536000,
|
||||
}
|
||||
},
|
||||
<a href="#repositories-section-optional">"repositories"</a>: {
|
||||
"gun_prefixes": ["docker.io/", "my-own-registry.com/"]
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
@@ -329,6 +332,33 @@ Example:
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
## repositories section (optional)
|
||||
|
||||
Example:
|
||||
|
||||
```json
|
||||
"repositories": {
|
||||
"gun_prefixes": ["docker.io/", "my-own-registry.com/"]
|
||||
}
|
||||
```
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Parameter</th>
|
||||
<th>Required</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><code>gun_prefixes</code></td>
|
||||
<td valign="top">no</td>
|
||||
<td valign="top">A list of GUN prefixes that will be accepted by this
|
||||
server. POST operations on an image beginning with any other prefix
|
||||
will be rejected with a 400, and GET/DELETE operations will be rejected
|
||||
with a 404.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
## Related information
|
||||
|
||||
* [Notary Signer Configuration File](signer-config.md)
|
||||
|
||||
@@ -83,8 +83,14 @@ var (
|
||||
ErrNoKeyAlgorithm = errcode.Register(errGroup, errcode.ErrorDescriptor{
|
||||
Value: "NO_KEYALGORITHM",
|
||||
Message: "The server does not have a key algorithm configured.",
|
||||
Description: "No key algorihtm has been configured for the server and it has been asked to perform an operation that requires generation.",
|
||||
Description: "No key algorithm has been configured for the server and it has been asked to perform an operation that requires generation.",
|
||||
HTTPStatusCode: http.StatusInternalServerError,
|
||||
})
|
||||
ErrInvalidGUN = errcode.Register(errGroup, errcode.ErrorDescriptor{
|
||||
Value: "INVALID_GUN",
|
||||
Message: "The server does not support actions on images of this name.",
|
||||
Description: "The server does not support actions on images of this name",
|
||||
HTTPStatusCode: http.StatusBadRequest,
|
||||
})
|
||||
ErrUnknown = errcode.ErrorCodeUnknown
|
||||
)
|
||||
|
||||
@@ -24,7 +24,7 @@ func TestValidationErrorFormat(t *testing.T) {
|
||||
context.Background(), "metaStore", storage.NewMemStorage())
|
||||
ctx = context.WithValue(ctx, "keyAlgorithm", data.ED25519Key)
|
||||
|
||||
handler := RootHandler(nil, ctx, signed.NewEd25519(), nil, nil)
|
||||
handler := RootHandler(nil, ctx, signed.NewEd25519(), nil, nil, nil)
|
||||
server := httptest.NewServer(handler)
|
||||
defer server.Close()
|
||||
|
||||
|
||||
116
server/server.go
116
server/server.go
@@ -5,11 +5,14 @@ import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/distribution/health"
|
||||
"github.com/docker/distribution/registry/api/errcode"
|
||||
"github.com/docker/distribution/registry/auth"
|
||||
"github.com/docker/notary"
|
||||
"github.com/docker/notary/server/errors"
|
||||
"github.com/docker/notary/server/handlers"
|
||||
"github.com/docker/notary/tuf/data"
|
||||
"github.com/docker/notary/tuf/signed"
|
||||
@@ -38,6 +41,7 @@ type Config struct {
|
||||
Trust signed.CryptoService
|
||||
AuthMethod string
|
||||
AuthOpts interface{}
|
||||
RepoPrefixes []string
|
||||
ConsistentCacheControlConfig utils.CacheControlConfig
|
||||
CurrentCacheControlConfig utils.CacheControlConfig
|
||||
}
|
||||
@@ -74,8 +78,11 @@ func Run(ctx context.Context, conf Config) error {
|
||||
}
|
||||
|
||||
svr := http.Server{
|
||||
Addr: conf.Addr,
|
||||
Handler: RootHandler(ac, ctx, conf.Trust, conf.ConsistentCacheControlConfig, conf.CurrentCacheControlConfig),
|
||||
Addr: conf.Addr,
|
||||
Handler: RootHandler(
|
||||
ac, ctx, conf.Trust,
|
||||
conf.ConsistentCacheControlConfig, conf.CurrentCacheControlConfig,
|
||||
conf.RepoPrefixes),
|
||||
}
|
||||
|
||||
logrus.Info("Starting on ", conf.Addr)
|
||||
@@ -85,41 +92,98 @@ func Run(ctx context.Context, conf Config) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// assumes that required prefixes is not empty
|
||||
func filterImagePrefixes(requiredPrefixes []string, err error, handler http.Handler) http.Handler {
|
||||
if len(requiredPrefixes) == 0 {
|
||||
return handler
|
||||
}
|
||||
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
imageName := mux.Vars(r)["imageName"]
|
||||
|
||||
for _, prefix := range requiredPrefixes {
|
||||
if strings.HasPrefix(imageName, prefix) {
|
||||
handler.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
errcode.ServeJSON(w, err)
|
||||
})
|
||||
}
|
||||
|
||||
type _serverEndpoint struct {
|
||||
OperationName string
|
||||
ServerHandler utils.ContextHandler
|
||||
ErrorIfGUNInvalid error
|
||||
IncludeCacheHeaders bool
|
||||
CacheControlConfig utils.CacheControlConfig
|
||||
PermissionsRequired []string
|
||||
}
|
||||
|
||||
// RootHandler returns the handler that routes all the paths from / for the
|
||||
// server.
|
||||
func RootHandler(ac auth.AccessController, ctx context.Context, trust signed.CryptoService,
|
||||
consistent, current utils.CacheControlConfig) http.Handler {
|
||||
consistent, current utils.CacheControlConfig, repoPrefixes []string) http.Handler {
|
||||
|
||||
hand := utils.RootHandlerFactory(ac, ctx, trust)
|
||||
authWrapper := utils.RootHandlerFactory(ac, ctx, trust)
|
||||
|
||||
createHandler := func(opts _serverEndpoint) http.Handler {
|
||||
var wrapped http.Handler
|
||||
wrapped = authWrapper(opts.ServerHandler, opts.PermissionsRequired...)
|
||||
if opts.IncludeCacheHeaders {
|
||||
wrapped = utils.WrapWithCacheHandler(opts.CacheControlConfig, wrapped)
|
||||
}
|
||||
wrapped = filterImagePrefixes(repoPrefixes, opts.ErrorIfGUNInvalid, wrapped)
|
||||
return prometheus.InstrumentHandlerWithOpts(prometheusOpts(opts.OperationName), wrapped)
|
||||
}
|
||||
|
||||
invalidGUNErr := errors.ErrInvalidGUN.WithDetail(fmt.Sprintf("Require GUNs with prefix: %v", repoPrefixes))
|
||||
notFoundError := errors.ErrMetadataNotFound.WithDetail(nil)
|
||||
|
||||
r := mux.NewRouter()
|
||||
r.Methods("GET").Path("/v2/").Handler(hand(handlers.MainHandler))
|
||||
r.Methods("POST").Path("/v2/{imageName:.*}/_trust/tuf/").Handler(
|
||||
prometheus.InstrumentHandlerWithOpts(
|
||||
prometheusOpts("UpdateTuf"),
|
||||
hand(handlers.AtomicUpdateHandler, "push", "pull")))
|
||||
r.Methods("GET").Path("/v2/{imageName:.*}/_trust/tuf/{tufRole:root|targets(?:/[^/\\s]+)*|snapshot|timestamp}.{checksum:[a-fA-F0-9]{64}|[a-fA-F0-9]{96}|[a-fA-F0-9]{128}}.json").Handler(
|
||||
prometheus.InstrumentHandlerWithOpts(
|
||||
prometheusOpts("GetRoleByHash"),
|
||||
utils.WrapWithCacheHandler(consistent, hand(handlers.GetHandler, "pull"))))
|
||||
r.Methods("GET").Path("/v2/{imageName:.*}/_trust/tuf/{tufRole:root|targets(?:/[^/\\s]+)*|snapshot|timestamp}.json").Handler(
|
||||
prometheus.InstrumentHandlerWithOpts(
|
||||
prometheusOpts("GetRole"),
|
||||
utils.WrapWithCacheHandler(current, hand(handlers.GetHandler, "pull"))))
|
||||
r.Methods("GET").Path("/v2/").Handler(authWrapper(handlers.MainHandler))
|
||||
|
||||
r.Methods("POST").Path("/v2/{imageName:.*}/_trust/tuf/").Handler(createHandler(_serverEndpoint{
|
||||
OperationName: "UpdateTuf",
|
||||
ErrorIfGUNInvalid: invalidGUNErr,
|
||||
ServerHandler: handlers.AtomicUpdateHandler,
|
||||
PermissionsRequired: []string{"push", "pull"},
|
||||
}))
|
||||
r.Methods("GET").Path("/v2/{imageName:.*}/_trust/tuf/{tufRole:root|targets(?:/[^/\\s]+)*|snapshot|timestamp}.{checksum:[a-fA-F0-9]{64}|[a-fA-F0-9]{96}|[a-fA-F0-9]{128}}.json").Handler(createHandler(_serverEndpoint{
|
||||
OperationName: "GetRoleByHash",
|
||||
ErrorIfGUNInvalid: notFoundError,
|
||||
IncludeCacheHeaders: true,
|
||||
CacheControlConfig: consistent,
|
||||
ServerHandler: handlers.GetHandler,
|
||||
PermissionsRequired: []string{"pull"},
|
||||
}))
|
||||
r.Methods("GET").Path("/v2/{imageName:.*}/_trust/tuf/{tufRole:root|targets(?:/[^/\\s]+)*|snapshot|timestamp}.json").Handler(createHandler(_serverEndpoint{
|
||||
OperationName: "GetRole",
|
||||
ErrorIfGUNInvalid: notFoundError,
|
||||
IncludeCacheHeaders: true,
|
||||
CacheControlConfig: current,
|
||||
ServerHandler: handlers.GetHandler,
|
||||
PermissionsRequired: []string{"pull"},
|
||||
}))
|
||||
r.Methods("GET").Path(
|
||||
"/v2/{imageName:.*}/_trust/tuf/{tufRole:snapshot|timestamp}.key").Handler(
|
||||
prometheus.InstrumentHandlerWithOpts(
|
||||
prometheusOpts("GetKey"),
|
||||
hand(handlers.GetKeyHandler, "push", "pull")))
|
||||
r.Methods("DELETE").Path("/v2/{imageName:.*}/_trust/tuf/").Handler(
|
||||
prometheus.InstrumentHandlerWithOpts(
|
||||
prometheusOpts("DeleteTuf"),
|
||||
hand(handlers.DeleteHandler, "push", "pull")))
|
||||
"/v2/{imageName:.*}/_trust/tuf/{tufRole:snapshot|timestamp}.key").Handler(createHandler(_serverEndpoint{
|
||||
OperationName: "GetKey",
|
||||
ErrorIfGUNInvalid: notFoundError,
|
||||
ServerHandler: handlers.GetKeyHandler,
|
||||
PermissionsRequired: []string{"push", "pull"},
|
||||
}))
|
||||
r.Methods("DELETE").Path("/v2/{imageName:.*}/_trust/tuf/").Handler(createHandler(_serverEndpoint{
|
||||
OperationName: "DeleteTuf",
|
||||
ErrorIfGUNInvalid: notFoundError,
|
||||
ServerHandler: handlers.DeleteHandler,
|
||||
PermissionsRequired: []string{"push", "pull"},
|
||||
}))
|
||||
|
||||
r.Methods("GET").Path("/_notary_server/health").HandlerFunc(health.StatusHandler)
|
||||
r.Methods("GET").Path("/metrics").Handler(prometheus.Handler())
|
||||
r.Methods("GET", "POST", "PUT", "HEAD", "DELETE").Path("/{other:.*}").Handler(
|
||||
hand(handlers.NotFoundHandler))
|
||||
authWrapper(handlers.NotFoundHandler))
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
@@ -14,10 +14,13 @@ import (
|
||||
"testing"
|
||||
|
||||
_ "github.com/docker/distribution/registry/auth/silly"
|
||||
"github.com/docker/notary"
|
||||
"github.com/docker/notary/server/storage"
|
||||
"github.com/docker/notary/tuf/data"
|
||||
"github.com/docker/notary/tuf/signed"
|
||||
"github.com/docker/notary/tuf/store"
|
||||
"github.com/docker/notary/tuf/testutils"
|
||||
tufutils "github.com/docker/notary/tuf/utils"
|
||||
"github.com/docker/notary/utils"
|
||||
"github.com/stretchr/testify/require"
|
||||
"golang.org/x/net/context"
|
||||
@@ -55,9 +58,98 @@ func TestRunReservedPort(t *testing.T) {
|
||||
)
|
||||
}
|
||||
|
||||
func TestRepoPrefixMatches(t *testing.T) {
|
||||
gun := "docker.io/notary"
|
||||
meta, cs, err := testutils.NewRepoMetadata(gun)
|
||||
require.NoError(t, err)
|
||||
|
||||
ctx := context.WithValue(context.Background(), "metaStore", storage.NewMemStorage())
|
||||
ctx = context.WithValue(ctx, "keyAlgorithm", data.ED25519Key)
|
||||
|
||||
snChecksumBytes := sha256.Sum256(meta[data.CanonicalSnapshotRole])
|
||||
|
||||
// successful gets
|
||||
handler := RootHandler(nil, ctx, cs, nil, nil, []string{"docker.io"})
|
||||
ts := httptest.NewServer(handler)
|
||||
|
||||
url := fmt.Sprintf("%s/v2/%s/_trust/tuf/", ts.URL, gun)
|
||||
uploader, err := store.NewHTTPStore(url, "", "json", "key", http.DefaultTransport)
|
||||
require.NoError(t, err)
|
||||
|
||||
// uploading is cool
|
||||
require.NoError(t, uploader.SetMultiMeta(meta))
|
||||
// getting is cool
|
||||
_, err = uploader.GetMeta(data.CanonicalSnapshotRole, notary.MaxDownloadSize)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = uploader.GetMeta(
|
||||
tufutils.ConsistentName(data.CanonicalSnapshotRole, snChecksumBytes[:]), notary.MaxDownloadSize)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = uploader.GetKey(data.CanonicalTimestampRole)
|
||||
require.NoError(t, err)
|
||||
|
||||
// the httpstore doesn't actually delete all, so we do it manually
|
||||
req, err := http.NewRequest("DELETE", url, nil)
|
||||
require.NoError(t, err)
|
||||
res, err := http.DefaultTransport.RoundTrip(req)
|
||||
require.NoError(t, err)
|
||||
defer res.Body.Close()
|
||||
require.Equal(t, http.StatusOK, res.StatusCode)
|
||||
}
|
||||
|
||||
func TestRepoPrefixDoesNotMatch(t *testing.T) {
|
||||
gun := "docker.io/notary"
|
||||
meta, cs, err := testutils.NewRepoMetadata(gun)
|
||||
require.NoError(t, err)
|
||||
s := storage.NewMemStorage()
|
||||
|
||||
ctx := context.WithValue(context.Background(), "metaStore", s)
|
||||
ctx = context.WithValue(ctx, "keyAlgorithm", data.ED25519Key)
|
||||
|
||||
snChecksumBytes := sha256.Sum256(meta[data.CanonicalSnapshotRole])
|
||||
|
||||
// successful gets
|
||||
handler := RootHandler(nil, ctx, cs, nil, nil, []string{"nope"})
|
||||
ts := httptest.NewServer(handler)
|
||||
|
||||
url := fmt.Sprintf("%s/v2/%s/_trust/tuf/", ts.URL, gun)
|
||||
uploader, err := store.NewHTTPStore(url, "", "json", "key", http.DefaultTransport)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Error(t, uploader.SetMultiMeta(meta))
|
||||
|
||||
// update the storage so we don't fail just because the metadata is missing
|
||||
for _, roleName := range data.BaseRoles {
|
||||
require.NoError(t, s.UpdateCurrent(gun, storage.MetaUpdate{
|
||||
Role: roleName,
|
||||
Data: meta[roleName],
|
||||
Version: 1,
|
||||
}))
|
||||
}
|
||||
|
||||
_, err = uploader.GetMeta(data.CanonicalSnapshotRole, notary.MaxDownloadSize)
|
||||
require.Error(t, err)
|
||||
|
||||
_, err = uploader.GetMeta(
|
||||
tufutils.ConsistentName(data.CanonicalSnapshotRole, snChecksumBytes[:]), notary.MaxDownloadSize)
|
||||
require.Error(t, err)
|
||||
|
||||
_, err = uploader.GetKey(data.CanonicalTimestampRole)
|
||||
require.Error(t, err)
|
||||
|
||||
// the httpstore doesn't actually delete all, so we do it manually
|
||||
req, err := http.NewRequest("DELETE", url, nil)
|
||||
require.NoError(t, err)
|
||||
res, err := http.DefaultTransport.RoundTrip(req)
|
||||
require.NoError(t, err)
|
||||
defer res.Body.Close()
|
||||
require.Equal(t, http.StatusNotFound, res.StatusCode)
|
||||
}
|
||||
|
||||
func TestMetricsEndpoint(t *testing.T) {
|
||||
handler := RootHandler(nil, context.Background(), signed.NewEd25519(),
|
||||
nil, nil)
|
||||
nil, nil, nil)
|
||||
ts := httptest.NewServer(handler)
|
||||
defer ts.Close()
|
||||
|
||||
@@ -72,7 +164,7 @@ func TestGetKeysEndpoint(t *testing.T) {
|
||||
context.Background(), "metaStore", storage.NewMemStorage())
|
||||
ctx = context.WithValue(ctx, "keyAlgorithm", data.ED25519Key)
|
||||
|
||||
handler := RootHandler(nil, ctx, signed.NewEd25519(), nil, nil)
|
||||
handler := RootHandler(nil, ctx, signed.NewEd25519(), nil, nil, nil)
|
||||
ts := httptest.NewServer(handler)
|
||||
defer ts.Close()
|
||||
|
||||
@@ -144,7 +236,7 @@ func TestGetRoleByHash(t *testing.T) {
|
||||
ctx = context.WithValue(ctx, "keyAlgorithm", data.ED25519Key)
|
||||
|
||||
ccc := utils.NewCacheControlConfig(10, false)
|
||||
handler := RootHandler(nil, ctx, signed.NewEd25519(), ccc, ccc)
|
||||
handler := RootHandler(nil, ctx, signed.NewEd25519(), ccc, ccc, nil)
|
||||
serv := httptest.NewServer(handler)
|
||||
defer serv.Close()
|
||||
|
||||
@@ -188,7 +280,7 @@ func TestGetCurrentRole(t *testing.T) {
|
||||
ctx = context.WithValue(ctx, "keyAlgorithm", data.ED25519Key)
|
||||
|
||||
ccc := utils.NewCacheControlConfig(10, false)
|
||||
handler := RootHandler(nil, ctx, signed.NewEd25519(), ccc, ccc)
|
||||
handler := RootHandler(nil, ctx, signed.NewEd25519(), ccc, ccc, nil)
|
||||
serv := httptest.NewServer(handler)
|
||||
defer serv.Close()
|
||||
|
||||
|
||||
@@ -15,14 +15,14 @@ import (
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// contextHandler defines an alterate HTTP handler interface which takes in
|
||||
// ContextHandler defines an alterate HTTP handler interface which takes in
|
||||
// a context for authorization and returns an HTTP application error.
|
||||
type contextHandler func(ctx context.Context, w http.ResponseWriter, r *http.Request) error
|
||||
type ContextHandler func(ctx context.Context, w http.ResponseWriter, r *http.Request) error
|
||||
|
||||
// rootHandler is an implementation of an HTTP request handler which handles
|
||||
// authorization and calling out to the defined alternate http handler.
|
||||
type rootHandler struct {
|
||||
handler contextHandler
|
||||
handler ContextHandler
|
||||
auth auth.AccessController
|
||||
actions []string
|
||||
context context.Context
|
||||
@@ -34,8 +34,8 @@ type rootHandler struct {
|
||||
// Context creator and authorizer. The returned factory allows creating
|
||||
// new rootHandlers from the alternate http handler contextHandler and
|
||||
// a scope.
|
||||
func RootHandlerFactory(auth auth.AccessController, ctx context.Context, trust signed.CryptoService) func(contextHandler, ...string) *rootHandler {
|
||||
return func(handler contextHandler, actions ...string) *rootHandler {
|
||||
func RootHandlerFactory(auth auth.AccessController, ctx context.Context, trust signed.CryptoService) func(ContextHandler, ...string) *rootHandler {
|
||||
return func(handler ContextHandler, actions ...string) *rootHandler {
|
||||
return &rootHandler{
|
||||
handler: handler,
|
||||
auth: auth,
|
||||
|
||||
Reference in New Issue
Block a user