rest

package
Version: v2.2.0+incompatible Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 23, 2019 License: Apache-2.0 Imports: 18 Imported by: 81

README

HTTPmux

The REST Plugin is a infrastructure Plugin which allows app plugins to handle HTTP requests (see the diagram below) in this sequence:

  1. httpmux starts the HTTP server in its own goroutine
  2. Plugins register their handlers with REST Plugin. To service HTTP requests, a plugin must first implement a handler function and register it at a given URL path using the RegisterHTTPHandler method. REST Plugin uses an HTTP request multiplexer from the gorilla/mux package to register the HTTP handlers by the specified URL path.
  3. HTTP server routes HTTP requests to their respective registered handlers using the gorilla/mux multiplexer.

http

Configuration

  • the server's port can be defined using commandline flag http-port or via the environment variable HTTP_PORT.

Example

The following example demonstrates the usage of the REST Plugin plugin API:

// httpExampleHandler returns a very simple HTTP request handler.
func httpExampleHandler(formatter *render.Render) http.HandlerFunc {

    // An example HTTP request handler which prints out attributes of 
    // a trivial Go structure in JSON format.
    return func(w http.ResponseWriter, req *http.Request) {
        formatter.JSON(w, http.StatusOK, struct{ Example string }{"This is an example"})
    }
}

// Register our HTTP request handler as a GET method serving at 
// the URL path "/example".
httpmux.RegisterHTTPHandler("/example", httpExampleHandler, "GET")

Once the handler is registered with REST Plugin and the agent is running, you can use curl to verify that it is operating properly:

$ curl -X GET http://localhost:9191/example
{
  "Example": "This is an example"
}

Security

REST plugin allows to optionally configure following security features:

  • server certificate (HTTPS)
  • Basic HTTP Authentication - username & password
  • client certificates
  • token based authorization

All of them are disabled by default and can be enabled by config file:

endpoint: 127.0.0.1:9292
server-cert-file: server.crt
server-key-file: server.key
client-cert-files:
  - "ca.crt"
client-basic-auth:
  - "user:pass"
  - "foo:bar"

If server-cert-file and server-key-file are defined the server requires HTTPS instead of HTTP for all its endpoints.

client-cert-files the list of the root certificate authorities that server uses to validate client certificates. If the list is not empty only client who provide a valid certificate is allowed to access the server.

client-basic-auth allows to define user password pairs that are allowed to access the server. The config option defines a static list of allowed user. If the list is not empty default staticAuthenticator is instantiated. Alternatively, you can implement custom authenticator and inject it into the plugin (e.g.: if you want to read credentials from ETCD).

Example

In order to generated self-signed certificates you can use the following commands:

#generate key for "Our Certificate Authority"
openssl genrsa -out ca.key 2048

#generate certificate for CA
openssl req -new -nodes -x509 -key ca.key -out ca.crt  -subj '/CN=CA'

#generate certificate for the server assume that server will be accessed by 127.0.0.1
openssl genrsa -out server.key 2048
openssl req -new -key server.key -out server.csr -subj '/CN=127.0.0.1'
openssl x509 -req -extensions client_server_ssl -extfile openssl_ext.conf -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt

#generate client certificate
openssl genrsa -out client.key 2048
openssl req -new -key client.key -out client.csr -subj '/CN=client'
openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -days 360

Once the security features are enabled, the endpoint can be accessed by the following commands:

  • HTTPS where ca.pem is a certificate authority where server certificate should be validated (in case of self-signed certificates)

    curl --cacert ca.crt  https://127.0.0.1:9292/log/list
    
  • HTTPS + client cert where client.crt is a valid client certificate.

    curl --cacert ca.crt  --cert client.crt --key client.key  https://127.0.0.1:9292/log/list
    
  • HTTPS + basic auth where user:pass is a valid username password pair.

    curl --cacert ca.crt  -u user:pass  https://127.0.0.1:9292/log/list
    
  • HTTPS + client cert + basic auth

    curl --cacert ca.crt  --cert client.crt --key client.key -u user:pass  https://127.0.0.1:9292/log/list
    
Token-based authorization

REST plugin supports authorization based on tokens. To enable the feature, use http.conf file:

enable-token-auth: true

Authorization restricts access to every registered permission group URLs. The user receives token after login, which grants him access to all permitted sites. The token is valid until the user is logged in, or until it expires.

The expiration time is a token claim, set in the config file:

token-expiration: 600000000000  

Note that time is in nanoseconds. If no time is provided, the default value of 1 hour is set.

Token uses by default pre-defined signature string as the key to sign it. This can be also changed via config file:

token-signature: <string>

After login, the token is required in authentication header in the format Bearer <token>, so it can be validated. If REST interface is accessed via a browser, the token is written to cookie file.

Users and permission groups

Users have to be pre-defined in http.conf file. User definition consists of name, hashed password and permission groups.

Name defines username (login). Name "admin" is forbidden since the admin user is created automatically with full permissions and password "ligato123"

Password has to be hashed. It is possible to use password-hasher to help with it. Password also has to be hashed with the same cost value, as defined in the configuration file:

password-hash-cost: <number>

Minimal hash cost is 4, maximal value is 31. The higher the cost, the more CPU time memory is required to hash the password.

Permission Groups define a list of permissions; allowed URLs and methods. Every user needs at least one permission group defined, otherwise it will not have access to anything. Permission group is described in proto model.

To add permission group, use rest plugin API:

RegisterPermissionGroup(group ...*access.PermissionGroup)

Every permission group has a name and a list o permissions. Permission defines URL and a list of methods which may be performed.

To add permission group to the user, put its name to the config file under user's field permissions.

Login and logout

To log in a user, follow the URL http://localhost:9191/login. The site is enabled for two methods. It is possible to use a POST to directly provide credentials in the format:

{
	"username": "<name>",
	"password": "<pass>"
}

The site returns access token as plain text. If URL is accessed with GET, it shows the login page where the credentials are supposed to be put. After successful submit, it redirects to the index.

To log out, post username to http://localhost:9191/logout.

{
	"username": "<name>"
}

Documentation

Overview

Package rest implements the HTTP server through which plugins can expose their REST APIs to the outside world.

Index

Constants

View Source
const (
	// DefaultHost is a host used by default
	DefaultHost = "0.0.0.0"
	// DefaultHTTPPort is a port used by default
	DefaultHTTPPort = "9191"
	// DefaultEndpoint 0.0.0.0:9191
	DefaultEndpoint = DefaultHost + ":" + DefaultHTTPPort
)

Variables

View Source
var DefaultPlugin = *NewPlugin()

DefaultPlugin is a default instance of Plugin.

Functions

func DeclareHTTPPortFlag added in v1.0.4

func DeclareHTTPPortFlag(pluginName infra.PluginName, defaultPortOpts ...uint)

DeclareHTTPPortFlag declares http port (with usage & default value) a flag for a particular plugin name

func FixConfig added in v1.0.4

func FixConfig(cfg *Config)

FixConfig fill default values for empty fields

func ListenAndServe

func ListenAndServe(config Config, handler http.Handler) (srv *http.Server, err error)

ListenAndServe starts a http server.

func PluginConfig added in v1.0.4

func PluginConfig(pluginCfg config.PluginConfig, cfg *Config, pluginName infra.PluginName) error

PluginConfig tries : - to load flag <plugin-name>-port and then FixConfig() just in case - alternatively <plugin-name>-config and then FixConfig() just in case - alternatively DefaultConfig()

Types

type BasicHTTPAuthenticator added in v1.4.0

type BasicHTTPAuthenticator interface {
	// Authenticate returns true if user is authenticated successfully, false otherwise.
	Authenticate(user string, pass string) bool
}

BasicHTTPAuthenticator is a delegate that implements basic HTTP authentication

type Config

type Config struct {
	// Endpoint is an address of HTTP server
	Endpoint string

	// ReadTimeout is the maximum duration for reading the entire
	// request, including the body.
	//
	// Because ReadTimeout does not let Handlers make per-request
	// decisions on each request body's acceptable deadline or
	// upload rate, most users will prefer to use
	// ReadHeaderTimeout. It is valid to use them both.
	ReadTimeout time.Duration

	// ReadHeaderTimeout is the amount of time allowed to read
	// request headers. The connection's read deadline is reset
	// after reading the headers and the Handler can decide what
	// is considered too slow for the body.
	ReadHeaderTimeout time.Duration

	// WriteTimeout is the maximum duration before timing out
	// writes of the response. It is reset whenever a new
	// request's header is read. Like ReadTimeout, it does not
	// let Handlers make decisions on a per-request basis.
	WriteTimeout time.Duration

	// IdleTimeout is the maximum amount of time to wait for the
	// next request when keep-alives are enabled. If IdleTimeout
	// is zero, the value of ReadTimeout is used. If both are
	// zero, there is no timeout.
	IdleTimeout time.Duration

	// MaxHeaderBytes controls the maximum number of bytes the
	// server will read parsing the request header's keys and
	// values, including the request line. It does not limit the
	// size of the request body.
	// If zero, DefaultMaxHeaderBytes is used.
	MaxHeaderBytes int

	// ServerCertfile is path to the server certificate. If the certificate and corresponding
	// key (see config item below) is defined server uses HTTPS instead of HTTP.
	ServerCertfile string `json:"server-cert-file"`

	// ServerKeyfile is path to the server key file.
	ServerKeyfile string `json:"server-key-file"`

	// ClientBasicAuth is a slice of credentials in form "username:password"
	// used for basic HTTP authentication. If defined only authenticated users are allowed
	// to access the server.
	ClientBasicAuth []string `json:"client-basic-auth"`

	// ClientCerts is a slice of the root certificate authorities
	// that servers uses to verify a client certificate
	ClientCerts []string `json:"client-cert-files"`

	// EnableTokenAuth enables token authorization for HTTP requests
	EnableTokenAuth bool `json:"enable-token-auth"`

	// TokenExpiration set globaly for all user tokens
	TokenExpiration time.Duration `json:"token-expiration"`

	// Users laoded from config file
	Users []access.User `json:"users"`

	// Hash cost for password. High values take a lot of time to process.
	PasswordHashCost int `json:"password-hash-cost"`

	// TokenSignature is used to sign a token. Default value is used if not set.
	TokenSignature string `json:"token-signature"`
}

Config is a configuration for HTTP server It is meant to be extended with security (TLS...)

func DefaultConfig added in v1.0.4

func DefaultConfig() *Config

DefaultConfig returns new instance of config with default endpoint

func (*Config) GetPort added in v1.0.4

func (cfg *Config) GetPort() int

GetPort parses suffix from endpoint & returns integer after last ":" (otherwise it returns 0)

func (*Config) UseHTTPS added in v1.4.0

func (cfg *Config) UseHTTPS() bool

UseHTTPS returns true if server certificate and key is defined.

type Deps

type Deps struct {
	infra.PluginDeps

	// Authenticator can be injected in a flavor inject method.
	// If there is no authenticator injected and config contains
	// user password, the default staticAuthenticator is instantiated.
	// By default the authenticator is disabled.
	Authenticator BasicHTTPAuthenticator
}

Deps lists the dependencies of the Rest plugin.

type HTTPHandlers

type HTTPHandlers interface {
	// RegisterHTTPHandler propagates to Gorilla mux
	RegisterHTTPHandler(path string, provider HandlerProvider, methods ...string) *mux.Route

	// RegisterPermissionGroup registers new permission groups for users
	RegisterPermissionGroup(group ...*access.PermissionGroup)

	// GetPort returns configured port number (for debugging purposes)
	GetPort() int
}

HTTPHandlers defines the API exposed by the REST plugin. Use this interface to declare dependency on the REST functionality, i.e.:

type Deps struct {

HTTP rest.HTTPHandlers // inject plugin implementing RegisterHTTPHandler
// other dependencies ...

}

type HandlerProvider added in v1.5.0

type HandlerProvider func(formatter *render.Render) http.HandlerFunc

HandlerProvider is a function used for registering handlers via HTTPHandlers

type Option added in v1.5.0

type Option func(*Plugin)

Option is a function that can be used in NewPlugin to customize Plugin.

func UseAuthenticator added in v1.5.0

func UseAuthenticator(a BasicHTTPAuthenticator) Option

UseAuthenticator returns an Option which sets HTTP Authenticator.

func UseConf added in v1.5.0

func UseConf(conf Config) Option

UseConf returns Option which injects a particular configuration.

func UseDeps added in v1.5.0

func UseDeps(cb func(*Deps)) Option

UseDeps returns Option that can inject custom dependencies.

type Plugin

type Plugin struct {
	Deps

	*Config
	// contains filtered or unexported fields
}

Plugin struct holds all plugin-related data.

func NewPlugin added in v1.5.0

func NewPlugin(opts ...Option) *Plugin

NewPlugin creates a new Plugin with the provided Options.

func (*Plugin) AfterInit

func (p *Plugin) AfterInit() (err error)

AfterInit starts the HTTP server.

func (*Plugin) Close

func (p *Plugin) Close() error

Close stops the HTTP server.

func (*Plugin) GetPort added in v1.0.4

func (p *Plugin) GetPort() int

GetPort returns plugin configuration port

func (*Plugin) Init

func (p *Plugin) Init() (err error)

Init is the plugin entry point called by Agent Core - It prepares Gorilla MUX HTTP Router

func (*Plugin) RegisterHTTPHandler

func (p *Plugin) RegisterHTTPHandler(path string, provider HandlerProvider, methods ...string) *mux.Route

RegisterHTTPHandler registers HTTP <handler> at the given <path>. Every request is validated if enabled.

func (*Plugin) RegisterPermissionGroup added in v1.6.0

func (p *Plugin) RegisterPermissionGroup(group ...*access.PermissionGroup)

RegisterPermissionGroup adds new permission group if token authentication is enabled

Directories

Path Synopsis
Package mock implements a mock HTTP server.
Package mock implements a mock HTTP server.
password-hasher
package vpp-agent-ctl implements the vpp-agent-ctl test tool for testing VPP Agent plugins.
package vpp-agent-ctl implements the vpp-agent-ctl test tool for testing VPP Agent plugins.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL