srpc

package
v0.3.1 Latest Latest
Warning

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

Go to latest
Published: Oct 6, 2022 License: Apache-2.0 Imports: 32 Imported by: 226

Documentation

Overview

Package srpc is similar to the net/rpc package in the Go standard library, except that it provides streaming RPC access, TLS support and authentication and authorisation using X509 client certificates.

Package srpc provides access to the exported methods of an object across a network or other I/O connection. A server registers an object, making it visible as a service with the name of the type of the object. After registration, exported methods of the object will be accessible remotely. A server may register multiple objects (services) of different types but it is an error to register multiple objects of the same type.

The remainder of this documentation describes the protocol, to assist the development of implementations in other languages.

Internally, multiple URL paths are registered with the HTTP default mux:

/_goSRPC_/              Unsecured (no TLS, no auth), GOB coder.
/_go_TLS_SRPC_/         Secured (TLS, full auth), GOB coder.
/_SRPC_/unsecured/JSON  Unsecured (no TLS, no auth), JSON coder.
/_SRPC_/TLS/JSON        Secured (TLS, full auth), JSON coder.

Thus, a web server may also support SRPC on the same port.

A client issues a HTTP CONNECT request to a server and (for secured connections) performs a TLS handshake. If the server requires the TLS handshake prior to the HTTP CONNECT, the client will retry with that mode.

Once connected, a client may issue a sequence of RPC calls, one at a time per connection. The client sends the name of the RPC method to call, followed by a newline character (a carriage return+newline is permitted). For a secured connection, the server will verify if the client X509 certificate is signed by a trusted CA and if the method is listed in the list of permitted methods in the certificate. If the method call is established, the server sends a newline character. If the method call is rejected then an error message followed by a newline is sent.

The server then calls a registered method hander. The client and server can exchange messages using the appropriate coder (GOB is preferred, JSON is available as a fallback). Most method handlers wait for client messages and then respond. Once the method handler exits (without an error code), the server waits for another method call.

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrorConnectionRefused    = errors.New("connection refused")
	ErrorNoRouteToHost        = errors.New("no route to host")
	ErrorMissingCertificate   = errors.New("missing certificate")
	ErrorBadCertificate       = errors.New("bad certificate")
	ErrorNoSrpcEndpoint       = errors.New("no SRPC endpoint")
	ErrorAccessToMethodDenied = errors.New("access to method denied")

	ErrorCloseClient = errors.New("close client")
)

Functions

func CheckTlsRequired

func CheckTlsRequired() bool

CheckTlsRequired returns true if the server requires TLS connections with trusted certificates. It returns false if unencrypted or unauthenticated connections are permitted (i.e. insecure mode).

func GetEarliestClientCertExpiration

func GetEarliestClientCertExpiration() time.Time

GetEarliestClientCertExpiration returns the earliest expiration time of any certificate registered with RegisterClientTlsConfig. The zero value is returned if there are no certificates with an expiration time.

func LoadCertificates

func LoadCertificates(directory string) ([]tls.Certificate, error)

LoadCertificates loads zero or more X509 certificates from directory. Each certificate must be stored in a pair of PEM-encoded files, with the private key in a file with extension '.key' and the corresponding public key certificate in a file with extension 'cert'. If there is an error loading a certificate pair then processing stops and the error is returned.

func RegisterClientTlsConfig

func RegisterClientTlsConfig(config *tls.Config)

RegisterClientTlsConfig registers the configuration for TLS client connections.

func RegisterFullAuthCA

func RegisterFullAuthCA(certPool *x509.CertPool)

RegisterFullAuthCA registers the CA certificate pool used for full authentication/authorisation checks (including method checks). If not specified, the CA certificate pool registered with RegisterServerTlsConfig is used for full auth checks. This allows for distinguishing between CAs trusted for everything versus CAs trusted only for identity (username and groups).

func RegisterName

func RegisterName(name string, rcvr interface{}) error

RegisterName publishes in the server the set of methods of the receiver value that satisfy one of the following interfaces:

func Method(*Conn) error
func Method(*Conn, Decoder, Encoder) error
func Method(*Conn, request, *response) error

The request/response method must not perform I/O on the Conn type. This is passed only to provide access to connection metadata. If rcvr implements MethodBlocker then the BlockMethod method will be called as needed. The name of the receiver (service) is given by name.

func RegisterNameWithOptions

func RegisterNameWithOptions(name string, rcvr interface{},
	options ReceiverOptions) error

func RegisterServerTlsConfig

func RegisterServerTlsConfig(config *tls.Config, requireTls bool)

RegisterServerTlsConfig registers the configuration for TLS server connections. If requireTls is true, any non-TLS connection will be rejected.

func SetDefaultGrantMethod

func SetDefaultGrantMethod(grantMethod func(serviceMethod string,
	authInfo *AuthInformation) bool)

SetDefaultGrantMethod registers the grantMethod function which will be called to grant access to methods (if access is not granted by the built-in authorisation mechanism) for all receivers. This is overridden by receivers which implement the MethodGranter interface. The default is to not grant access to methods (if the built-in authorisation mechanism does not grant access).

Types

type AuthInformation

type AuthInformation struct {
	GroupList        map[string]struct{}
	HaveMethodAccess bool
	Username         string
}

type Client

type Client struct {
	// contains filtered or unexported fields
}

func DialHTTP

func DialHTTP(network, address string, timeout time.Duration) (*Client, error)

DialHTTP connects to an HTTP SRPC server at the specified network address listening on the HTTP SRPC path. If timeout is zero or less, the underlying OS timeout is used (typically 3 minutes for TCP).

func DialHTTPWithDialer

func DialHTTPWithDialer(network, address string, dialer Dialer) (
	*Client, error)

DialHTTPWithDialer is similar to DialHTTP except that the dialer is used to create the underlying connection.

func DialTlsHTTP

func DialTlsHTTP(network, address string, tlsConfig *tls.Config,
	timeout time.Duration) (
	*Client, error)

DialTlsHTTP connects to an HTTP SRPC TLS server at the specified network address listening on the HTTP SRPC TLS path. If timeout is zero or less, the underlying OS timeout is used (typically 3 minutes for TCP).

func DialTlsHTTPWithDialer

func DialTlsHTTPWithDialer(network, address string, tlsConfig *tls.Config,
	dialer Dialer) (
	*Client, error)

DialTlsHTTPWithDialer is similar to DialTlsHTTP except that the dialer is used to create the underlying connection.

func (*Client) Call

func (client *Client) Call(serviceMethod string) (*Conn, error)

Call opens a buffered connection to the named Service.Method function, and returns a connection handle and an error status. The connection handle wraps a *bufio.ReadWriter. Only one connection can be made per Client. The Call method will block if another Call is in progress. The Close method must be called prior to attempting another Call.

func (*Client) Close

func (client *Client) Close() error

Close will close a client, immediately releasing the internal connection.

func (*Client) IsEncrypted

func (client *Client) IsEncrypted() bool

IsEncrypted will return true if the underlying connection is TLS-encrypted.

func (*Client) Ping

func (client *Client) Ping() error

Ping sends a short "are you alive?" request and waits for a response. No method permissions are required for this operation. The Ping method is a wrapper around the Call method and hence will block if a Call is already in progress.

func (*Client) Put

func (client *Client) Put()

Put releases a client that was previously created using one of the Get* methods. It may be internally closed later if required to free limited resources (such as file descriptors). No methods may be called after Put is called. If Put is called after Close, no action is taken (this is a safe operation and is commonly used in some programming patterns).

func (*Client) RequestReply

func (client *Client) RequestReply(serviceMethod string, request interface{},
	reply interface{}) error

RequestReply sends a request message to the named Service.Method function, and waits for a reply. The request and reply messages are GOB encoded and decoded, respectively. This method is a convenience wrapper around the Call method.

func (*Client) SetKeepAlive

func (client *Client) SetKeepAlive(keepalive bool) error

SetKeepAlive sets whether the operating system should send keepalive messages on the connection.

func (*Client) SetKeepAlivePeriod

func (client *Client) SetKeepAlivePeriod(d time.Duration) error

SetKeepAlivePeriod sets the period between keepalive messages.

type ClientResource

type ClientResource struct {
	// contains filtered or unexported fields
}

func NewClientResource

func NewClientResource(network, address string) *ClientResource

NewClientResource returns a ClientResource which may be later used to Get* a Client which is part of a managed pool of connection slots (to limit consumption of resources such as file descriptors). Clients can be released with the Put method but the underlying connection may be kept open for later re-use. The Client is placed on an internal list. A typical programming pattern is:

cr := NewClientResource(...)
c := cr.GetHttp(...)
defer c.Put()
if err { c.Close() }
c := cr.GetHttp(...)
defer c.Put()
if err { c.Close() }

This pattern ensures Get* and Put are always matched, and if there is a communications error, Close shuts down the client so that a subsequent Get* creates a new connection.

func (*ClientResource) GetHTTP

func (cr *ClientResource) GetHTTP(cancelChannel <-chan struct{},
	timeout time.Duration) (*Client, error)

GetHTTP is similar to DialHTTP except that the returned Client is part of a managed pool of connection slots (to limit consumption of resources such as file descriptors). GetHTTP will wait until a resource is available or a message is received on cancelChannel. If cancelChannel is nil then GetHTTP will wait indefinitely until a resource is available. If the wait is cancelled then GetHTTP will return ErrorResourceLimitExceeded. The timeout specifies how long to wait (after a resource is available) to make the connection. If timeout is zero or less, the underlying OS timeout is used (typically 3 minutes for TCP).

func (*ClientResource) GetHTTPWithDialer

func (cr *ClientResource) GetHTTPWithDialer(cancelChannel <-chan struct{},
	dialer Dialer) (*Client, error)

GetHTTPWithDialer is similar to GetHTTP except that the dialer is used to create the underlying connection.

func (*ClientResource) GetTlsHTTP

func (cr *ClientResource) GetTlsHTTP(tlsConfig *tls.Config,
	cancelChannel <-chan struct{}, timeout time.Duration) (*Client, error)

GetTlsHTTP is similar to DialTlsHTTP but returns a Client that is part of a managed pool like the GetHTTP method returns.

func (*ClientResource) GetTlsHTTPWithDialer

func (cr *ClientResource) GetTlsHTTPWithDialer(tlsConfig *tls.Config,
	cancelChannel <-chan struct{}, dialer Dialer) (*Client, error)

GetTlsHTTPWithDialer is similar to GetTlsHTTP except that the dialer is used to create the underlying connection.

func (*ClientResource) ScheduleClose

func (cr *ClientResource) ScheduleClose()

type Conn

type Conn struct {
	Decoder
	Encoder

	*bufio.ReadWriter
	// contains filtered or unexported fields
}

func (*Conn) Close

func (conn *Conn) Close() error

Close will close the connection to the Sevice.Method function, releasing the Client for a subsequent Call.

func (*Conn) GetAuthInformation

func (conn *Conn) GetAuthInformation() *AuthInformation

GetAuthInformation will return authentication information for the client who holds the certificate used to authenticate the connection to the server. If the connection was not authenticated nil is returned. If the connection is a client connection, then GetAuthInformation will panic.

func (*Conn) GetCloseNotifier

func (conn *Conn) GetCloseNotifier() <-chan error

GetCloseNotifier will create a goroutine which reads from the connection until it closes or there is a read error. The error (which is nil if the connection closed) is sent to the channel. All data read are discarded.

func (*Conn) IsEncrypted

func (conn *Conn) IsEncrypted() bool

IsEncrypted will return true if the underlying connection is TLS-encrypted.

func (*Conn) RemoteAddr

func (conn *Conn) RemoteAddr() string

RemoteAddr returns the remote network address. This is currently only implemented for server-side connections.

func (*Conn) RequestReply

func (conn *Conn) RequestReply(request interface{}, reply interface{}) error

RequestReply sends a request message to a connection and waits for a reply. The request and reply messages are GOB encoded and decoded, respectively.

func (*Conn) Username

func (conn *Conn) Username() string

Username will return the username of the client who holds the certificate used to authenticate the connection to the server. If the connection was not authenticated the empty string is returned. If the connection is a client connection, then Username will panic.

type Decoder

type Decoder interface {
	Decode(e interface{}) error
}

type Dialer

type Dialer interface {
	Dial(network, address string) (net.Conn, error)
}

Dialer implements a dialer that can be use to create connections.

type Encoder

type Encoder interface {
	Encode(e interface{}) error
}

type MethodBlocker

type MethodBlocker interface {
	// BlockMethod is called after method access is granted, prior to calling
	// the method. After the method call completes, the returned function is
	// called. If this is nil, no function is called. If a non-nil error is
	// returned then the method call is blocked and the remote caller will
	// receive the error.
	BlockMethod(methodName string, authInfo *AuthInformation) (func(), error)
}

MethodBlocker defines an interface to block method calls (after possible authorisation) for a receiver (passed to RegisterName). This may be used to attach rate limiting polcies for method calls.

type MethodGranter

type MethodGranter interface {
	// GrantMethod is called to check if method access should be granted. If
	// access should be granted, the method should return true.
	GrantMethod(serviceMethod string, authInfo *AuthInformation) bool
}

MethodGranter defines an interface to grant method calls (if access is not granted by the built-in authorisation mechanism) for a receiver (passed to RegisterName).

type ReceiverOptions

type ReceiverOptions struct {
	PublicMethods []string
}

Directories

Path Synopsis
Package setupclient assists in setting up TLS credentials for a client.
Package setupclient assists in setting up TLS credentials for a client.
Package setupserver assists in setting up TLS credentials for a server.
Package setupserver assists in setting up TLS credentials for a server.

Jump to

Keyboard shortcuts

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