Skip to content

Commit

Permalink
small refactoring to make it easier to use notary as a library
Browse files Browse the repository at this point in the history
Signed-off-by: Evan Cordell <[email protected]>
  • Loading branch information
ecordell committed Jan 10, 2017
1 parent eae6372 commit 42d8809
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 26 deletions.
62 changes: 41 additions & 21 deletions server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,13 +117,25 @@ func filterImagePrefixes(requiredPrefixes []string, err error, handler http.Hand
})
}

type _serverEndpoint struct {
type ServerEndpoint struct {
OperationName string
ServerHandler utils.ContextHandler
ErrorIfGUNInvalid error
IncludeCacheHeaders bool
CacheControlConfig utils.CacheControlConfig
PermissionsRequired []string
AuthWrapper utils.AuthWrapper
RepoPrefixes []string
}

func CreateHandler(opts ServerEndpoint) http.Handler {
var wrapped http.Handler
wrapped = opts.AuthWrapper(opts.ServerHandler, opts.PermissionsRequired...)
if opts.IncludeCacheHeaders {
wrapped = utils.WrapWithCacheHandler(opts.CacheControlConfig, wrapped)
}
wrapped = filterImagePrefixes(opts.RepoPrefixes, opts.ErrorIfGUNInvalid, wrapped)
return prometheus.InstrumentHandlerWithOpts(prometheusOpts(opts.OperationName), wrapped)
}

// RootHandler returns the handler that routes all the paths from / for the
Expand All @@ -132,83 +144,91 @@ func RootHandler(ctx context.Context, ac auth.AccessController, trust signed.Cry
consistent, current utils.CacheControlConfig, repoPrefixes []string) http.Handler {

authWrapper := utils.RootHandlerFactory(ctx, ac, 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(authWrapper(handlers.MainHandler))

r.Methods("POST").Path("/v2/{imageName:[^*]+}/_trust/tuf/").Handler(createHandler(_serverEndpoint{
r.Methods("POST").Path("/v2/{imageName:[^*]+}/_trust/tuf/").Handler(CreateHandler(ServerEndpoint{
OperationName: "UpdateTUF",
ErrorIfGUNInvalid: invalidGUNErr,
ServerHandler: handlers.AtomicUpdateHandler,
PermissionsRequired: []string{"push", "pull"},
AuthWrapper: authWrapper,
RepoPrefixes: repoPrefixes,
}))
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{
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"},
AuthWrapper: authWrapper,
RepoPrefixes: repoPrefixes,
}))
r.Methods("GET").Path("/v2/{imageName:[^*]+}/_trust/tuf/{version:[1-9]*[0-9]+}.{tufRole:root|targets(?:/[^/\\s]+)*|snapshot|timestamp}.json").Handler(createHandler(_serverEndpoint{
r.Methods("GET").Path("/v2/{imageName:[^*]+}/_trust/tuf/{version:[1-9]*[0-9]+}.{tufRole:root|targets(?:/[^/\\s]+)*|snapshot|timestamp}.json").Handler(CreateHandler(ServerEndpoint{
OperationName: "GetRoleByVersion",
ErrorIfGUNInvalid: notFoundError,
IncludeCacheHeaders: true,
CacheControlConfig: consistent,
ServerHandler: handlers.GetHandler,
PermissionsRequired: []string{"pull"},
AuthWrapper: authWrapper,
RepoPrefixes: repoPrefixes,
}))
r.Methods("GET").Path("/v2/{imageName:[^*]+}/_trust/tuf/{tufRole:root|targets(?:/[^/\\s]+)*|snapshot|timestamp}.json").Handler(createHandler(_serverEndpoint{

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"},
AuthWrapper: authWrapper,
RepoPrefixes: repoPrefixes,
}))
r.Methods("GET").Path(
"/v2/{imageName:[^*]+}/_trust/tuf/{tufRole:snapshot|timestamp}.key").Handler(createHandler(_serverEndpoint{
"/v2/{imageName:[^*]+}/_trust/tuf/{tufRole:snapshot|timestamp}.key").Handler(CreateHandler(ServerEndpoint{
OperationName: "GetKey",
ErrorIfGUNInvalid: notFoundError,
ServerHandler: handlers.GetKeyHandler,
PermissionsRequired: []string{"push", "pull"},
AuthWrapper: authWrapper,
RepoPrefixes: repoPrefixes,
}))
r.Methods("POST").Path(
"/v2/{imageName:[^*]+}/_trust/tuf/{tufRole:snapshot|timestamp}.key").Handler(createHandler(_serverEndpoint{
"/v2/{imageName:[^*]+}/_trust/tuf/{tufRole:snapshot|timestamp}.key").Handler(CreateHandler(ServerEndpoint{
OperationName: "RotateKey",
ErrorIfGUNInvalid: notFoundError,
ServerHandler: handlers.RotateKeyHandler,
PermissionsRequired: []string{"*"},
AuthWrapper: authWrapper,
RepoPrefixes: repoPrefixes,
}))
r.Methods("DELETE").Path("/v2/{imageName:[^*]+}/_trust/tuf/").Handler(createHandler(_serverEndpoint{
r.Methods("DELETE").Path("/v2/{imageName:[^*]+}/_trust/tuf/").Handler(CreateHandler(ServerEndpoint{
OperationName: "DeleteTUF",
ErrorIfGUNInvalid: notFoundError,
ServerHandler: handlers.DeleteHandler,
PermissionsRequired: []string{"*"},
AuthWrapper: authWrapper,
RepoPrefixes: repoPrefixes,
}))
r.Methods("GET").Path("/v2/{imageName:[^*]+}/_trust/changefeed").Handler(createHandler(_serverEndpoint{
r.Methods("GET").Path("/v2/{imageName:[^*]+}/_trust/changefeed").Handler(CreateHandler(ServerEndpoint{
OperationName: "Changefeed",
ErrorIfGUNInvalid: notFoundError,
ServerHandler: handlers.Changefeed,
PermissionsRequired: []string{"pull"},
AuthWrapper: authWrapper,
RepoPrefixes: repoPrefixes,
}))
r.Methods("GET").Path("/v2/_trust/changefeed").Handler(createHandler(_serverEndpoint{
r.Methods("GET").Path("/v2/_trust/changefeed").Handler(CreateHandler(ServerEndpoint{
OperationName: "Changefeed",
ServerHandler: handlers.Changefeed,
PermissionsRequired: []string{"*"},
AuthWrapper: authWrapper,
RepoPrefixes: repoPrefixes,
}))

r.Methods("GET").Path("/_notary_server/health").HandlerFunc(health.StatusHandler)
Expand Down
14 changes: 12 additions & 2 deletions server/storage/sql_models.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,16 @@ const (
changeCategoryDeletion = "deletion"
)

// TUFFileTableName returns the name used for the tuf file table
var TUFFileTableName = func() string {
return "tuf_files"
}

// ChangefeedTableName returns the name used for the changefeed table
var ChangefeedTableName = func() string {
return "changefeed"
}

// TUFFile represents a TUF file in the database
type TUFFile struct {
gorm.Model
Expand All @@ -23,7 +33,7 @@ type TUFFile struct {

// TableName sets a specific table name for TUFFile
func (g TUFFile) TableName() string {
return "tuf_files"
return TUFFileTableName()
}

// Change defines the the fields required for an object in the changefeed
Expand All @@ -38,7 +48,7 @@ type Change struct {

// TableName sets a specific table name for Changefeed
func (c Change) TableName() string {
return "changefeed"
return ChangefeedTableName()
}

// CreateTUFTable creates the DB table for TUFFile
Expand Down
8 changes: 5 additions & 3 deletions utils/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ type rootHandler struct {
trust signed.CryptoService
}

// AuthWrapper wraps a Handler with and Auth requirement
type AuthWrapper func(ContextHandler, ...string) *rootHandler

// RootHandlerFactory creates a new rootHandler factory using the given
// Context creator and authorizer. The returned factory allows creating
// new rootHandlers from the alternate http handler contextHandler and
Expand Down Expand Up @@ -56,10 +59,9 @@ func (root *rootHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
ctx, w = ctxu.WithResponseWriter(ctx, w)
ctx = ctxu.WithLogger(ctx, log)
ctx = context.WithValue(ctx, notary.CtxKeyCryptoSvc, root.trust)

defer func() {
defer func(ctx context.Context) {
ctxu.GetResponseLogger(ctx).Info("response completed")
}()
}(ctx)

if root.auth != nil {
ctx = context.WithValue(ctx, notary.CtxKeyRepo, vars["imageName"])
Expand Down

0 comments on commit 42d8809

Please sign in to comment.