Documentation
¶
Index ¶
- Constants
- Variables
- func AddSessionFromToken(userAuthn messaging.IAuthenticator) func(next http.Handler) http.Handler
- func GetClientIdFromContext(r *http.Request) (clientID string, err error)
- type HttpActionStatusMessage
- type HttpBasicServer
- func (srv *HttpBasicServer) AddAffordanceForms(tdoc *td.TD)
- func (srv *HttpBasicServer) AddTDForms(tdoc *td.TD, includeAffordances bool)
- func (srv *HttpBasicServer) CloseAll()
- func (srv *HttpBasicServer) CloseAllClientConnections(clientID string)
- func (srv *HttpBasicServer) EnableStatic(base string, staticRoot string) error
- func (srv *HttpBasicServer) GetAuthServerURI() string
- func (srv *HttpBasicServer) GetConnectURL() string
- func (srv *HttpBasicServer) GetConnectionByClientID(agentID string) messaging.IConnection
- func (srv *HttpBasicServer) GetConnectionByConnectionID(clientID, cid string) messaging.IConnection
- func (srv *HttpBasicServer) GetForm(operation string, thingID string, name string) *td.Form
- func (srv *HttpBasicServer) GetProtectedRouter() chi.Router
- func (srv *HttpBasicServer) GetProtocolType() string
- func (srv *HttpBasicServer) GetPublicRouter() chi.Router
- func (srv *HttpBasicServer) HandleAuthRefresh(w http.ResponseWriter, r *http.Request)
- func (srv *HttpBasicServer) HandleLogin(w http.ResponseWriter, r *http.Request)
- func (srv *HttpBasicServer) HandleLogout(w http.ResponseWriter, r *http.Request)
- func (srv *HttpBasicServer) HandlePing(w http.ResponseWriter, r *http.Request)
- func (srv *HttpBasicServer) SendNotification(msg *messaging.NotificationMessage)
- func (srv *HttpBasicServer) Start() error
- func (srv *HttpBasicServer) Stop()
- type HttpErrorResponse
- type RequestParams
- type StaticFSWrapper
- type StaticFileInfoWrapper
- type StaticFileWrapper
Constants ¶
const ( // ConnectionIDHeader is intended for linking return channels to requests. // intended for separated return channel like sse. ConnectionIDHeader = "cid" // CorrelationIDHeader is the header to be able to link requests to out of band responses // tentative as it isn't part of the wot spec CorrelationIDHeader = "correlationID" // HttpPostLoginPath is the fixed authentication endpoint of the hub HttpPostLoginPath = "/authn/login" HttpPostLogoutPath = "/authn/logout" HttpPostRefreshPath = "/authn/refresh" HttpGetPingPath = "/ping" // The generic path for thing operations over http using URI variables HttpBaseFormOp = "/things" HttpBasicAffordanceOperationPath = "/things/{operation}/{thingID}/{name}" HttpBasicThingOperationPath = "/things/{operation}/{thingID}" HttpBasicOperationURIVar = "operation" HttpBasicThingIDURIVar = "thingID" HttpBasicNameURIVar = "name" // static file server routes DefaultHttpStaticBase = "/static" DefaultHttpStaticDirectory = "stores/httpstatic" // relative to home )
HTTP-basic profile constants
const ContextClientID = "clientID"
const SessionContextID = "session"
Variables ¶
var HttpKnownOperations = []string{ wot.OpQueryAllActions, wot.OpReadAllProperties, wot.OpWriteMultipleProperties, wot.OpReadProperty, wot.OpWriteProperty, wot.OpInvokeAction, wot.OpQueryAction}
Functions ¶
func AddSessionFromToken ¶
AddSessionFromToken middleware decodes the bearer session token in the authorization header.
Session tokens can be provided through a bearer token or a client cookie. The token must match with an existing session ID.
This distinguishes two types of tokens. Those with and those without a session ID. If the token contains a session ID then that session must exist or the token is invalid. User tokens are typically session tokens. Closing the session (logout) invalidates the token, even if it hasn't yet expired. Sessions are currently only stored in memory so a service restart also invalidates all session tokens.
Non-session tokens, are used by services and device agents. These tokens are generated on provisioning or token renewal and last until their expiry.
The session can be retrieved from the request context using GetSessionFromContext()
The client session contains the client ID, and stats for the current session. If no valid session is found this will reply with an unauthorized status code.
pubKey is the public key from the keypair used in creating the session token.
Types ¶
type HttpActionStatusMessage ¶
type HttpActionStatusMessage struct {
// Status is one of "pending","running","completed" or "failed"
Status string `json:"status,omitempty"`
Output any `json:"output,omitempty"`
//Error message, if any, containing problem details format (RF7807)
// For now just text
Error string `json:"error,omitempty"`
// The [URL] of an HttpActionStatus resource which can be used by queryaction
// and cancelaction operations
Href string `json:"href,omitempty"`
// A timestamp indicating the time at which the Thing received the request
// to execute the action.
TimeRequested string `json:"timeRequested,omitempty"`
//A timestamp indicating the time at which the Thing successfully completed
//executing the action, or failed to execute the action.
TimeEnded string `json:"timeEnded,omitempty"`
}
HttpActionStatusMessage the status of an asynchronous action invocation request
type HttpBasicServer ¶
type HttpBasicServer struct {
// contains filtered or unexported fields
}
HttpBasicServer provides the http-basic protocol binding using the provided http server. This is the simplest protocol binding supported by hiveot. Features: - security bootstrapping as per https://w3c.github.io/wot-discovery/#exploration-secboot
- login to obtain a bearer token: POST {base}/authn/login
- refresh bearer token: POST {base}/authn/refresh
- post/get thing operations: POST {base}/things/{op}/{thingID} - post/get affordance operations: POST {base}/things/{op}/{thingID}/{name}
This uses the provided httpserver instance.
func NewHttpBasicServer ¶
func NewHttpBasicServer( connectAddr string, router *chi.Mux, authenticator messaging.IAuthenticator, handleNotification messaging.NotificationHandler, handleRequest messaging.RequestHandler, handleResponse messaging.ResponseHandler, ) *HttpBasicServer
NewHttpBasicServer creates a new http-basic protocol binding. Intended for use as server for sub-protocols such as sse and wss.
connectAddr is the host:port the server can be reached at. router is the router to register paths at.
On startup this creates a public and protected route. Protected routes can be registered by sub-protocols. This http-basic handles the connection authentication.
func (*HttpBasicServer) AddAffordanceForms ¶
func (srv *HttpBasicServer) AddAffordanceForms(tdoc *td.TD)
AddAffordanceForms adds forms to affordances for interacting using the websocket protocol binding http-basic only supports read-write
func (*HttpBasicServer) AddTDForms ¶
func (srv *HttpBasicServer) AddTDForms(tdoc *td.TD, includeAffordances bool)
AddTDForms sets the forms for use of http-basic to the given TD.
This sets the base to the http connect URL and uses relative hrefs for the forms. The href MUST match the route defined in: HttpBasicRoutes.HttpBasicAffordanceOperationPath e.g.: "https://host:port/things/{op}/{thingID}/{name}"
As content-Type is the default application/json it is omitted.
If the method names for get operations is default GET then it is omitted from the form.
includeAffordances adds forms for all affordances to be compliant with the specifications.
func (*HttpBasicServer) CloseAll ¶
func (srv *HttpBasicServer) CloseAll()
CloseAll does nothing as http is connectionless.
func (*HttpBasicServer) CloseAllClientConnections ¶
func (srv *HttpBasicServer) CloseAllClientConnections(clientID string)
CloseAllClientConnections does nothing as http is connectionless.
func (*HttpBasicServer) EnableStatic ¶
func (srv *HttpBasicServer) EnableStatic(base string, staticRoot string) error
EnableStatic adds a path to read files from the static directory. Auth required.
base is the base path on which to serve the static files, eg: "/static" staticRoot is the root directory where static files are kept. This must be a full path.
func (*HttpBasicServer) GetAuthServerURI ¶
func (srv *HttpBasicServer) GetAuthServerURI() string
GetAuthServerURI returns the URI of the authentication server to include in the TD security scheme FIXME: Should this be some kind of authorization flow with a web page? This is currently just the login endpoint (post /authn/login). The http server might need to include a web page where users can enter their login name and password, although that won't work for machines... tbd
Note that web browsers do not directly access the runtime endpoints. Instead a web server (hiveoview or other) provides the user interface. Including the auth endpoint here is currently just a hint. How to integrate this?
func (*HttpBasicServer) GetConnectURL ¶
func (srv *HttpBasicServer) GetConnectURL() string
GetConnectURL returns connection url of the http server
func (*HttpBasicServer) GetConnectionByClientID ¶
func (srv *HttpBasicServer) GetConnectionByClientID(agentID string) messaging.IConnection
GetConnectionByClientID returns returns nil as http-basic is connectionless
func (*HttpBasicServer) GetConnectionByConnectionID ¶
func (srv *HttpBasicServer) GetConnectionByConnectionID(clientID, cid string) messaging.IConnection
GetConnectionByConnectionID returns nil as http-basic is connectionless
func (*HttpBasicServer) GetProtectedRouter ¶
func (srv *HttpBasicServer) GetProtectedRouter() chi.Router
GetProtectedRouter return the router for adding protected paths. Protected means the client is authenticated.
func (*HttpBasicServer) GetProtocolType ¶
func (srv *HttpBasicServer) GetProtocolType() string
func (*HttpBasicServer) GetPublicRouter ¶
func (srv *HttpBasicServer) GetPublicRouter() chi.Router
GetPublicRouter return the router for adding public paths.
func (*HttpBasicServer) HandleAuthRefresh ¶
func (srv *HttpBasicServer) HandleAuthRefresh(w http.ResponseWriter, r *http.Request)
HandleAuthRefresh refreshes the auth token using the session authenticator. The session authenticator is that of the authn service. This allows testing with a dummy authenticator without having to run the authn service.
func (*HttpBasicServer) HandleLogin ¶
func (srv *HttpBasicServer) HandleLogin(w http.ResponseWriter, r *http.Request)
HandleLogin handles a login request and returns an auth token.
Body contains {"login":name, "password":pass} format This is the only unprotected route supported. This uses the configured session authenticator.
func (*HttpBasicServer) HandleLogout ¶
func (srv *HttpBasicServer) HandleLogout(w http.ResponseWriter, r *http.Request)
HandleLogout ends the session and closes all client connections
func (*HttpBasicServer) HandlePing ¶
func (srv *HttpBasicServer) HandlePing(w http.ResponseWriter, r *http.Request)
HandlePing with http handler returns a pong response
func (*HttpBasicServer) SendNotification ¶
func (srv *HttpBasicServer) SendNotification(msg *messaging.NotificationMessage)
SendNotification does nothing as http-basic is connectionless
func (*HttpBasicServer) Start ¶
func (srv *HttpBasicServer) Start() error
Start listening on the routes
func (*HttpBasicServer) Stop ¶
func (srv *HttpBasicServer) Stop()
type HttpErrorResponse ¶
type HttpErrorResponse struct {
// URI reference identifying the problem type
// Not sure what to put in here. Problem types don't exist in URI format.
Type string `json:"type,omitempty"`
// Human readable short summary
Title string `json:"title"`
// HTTP status code generated by the origin server
// Likely 403 (no auth
Status int `json:"status.omitempty"`
Detail string `json:"detail,omitempty"` // Detail of the error
Instance string `json:"instance,omitempty"` // Resource that identifies the occurrance of the problem
}
https://w3c.github.io/wot-profile/#error-responses If an HTTP error response contains a body, the content of that body MUST conform with the Problem Details format [RFC7807]. https://www.rfc-editor.org/rfc/rfc7807#section-3
type RequestParams ¶
type RequestParams struct {
ClientID string // authenticated client ID
ThingID string // the thing ID if defined in the URL as {thingID}
CorrelationID string // tentative as it isn't in the spec
Name string // the affordance name if defined in the URL as {name}
ConnectionID string // connectionID as provided by the client
Op string // the operation if defined in the URL as {op}
Payload []byte // the raw request payload (body)
}
RequestParams contains the parameters read from the HTTP request
func GetRequestParams ¶
func GetRequestParams(r *http.Request) (reqParam RequestParams, err error)
GetRequestParams reads the client session, URL parameters and body payload from the http request context.
The session context is set by the http middleware. If the session is not available then this returns an error. Note that the session middleware handler will block any request that requires a session.
This protocol binding determines three variables, {thingID}, {name} and {op} from the path. It unmarshal's the request body into 'data', if given.
{operation} is the operation
{thingID} is the agent or digital twin thing ID
{name} is the property, event or action name. '+' means 'all'
func (*RequestParams) Unmarshal ¶
func (rp *RequestParams) Unmarshal(data any) error
Convenience function to unmarshal the payload into the given data struct If no payload is available this does nothing and data remains unchanged
type StaticFSWrapper ¶
type StaticFSWrapper struct {
http.FileSystem
FixedModTime time.Time
}
StaticFSWrapper adds a timestamp to files from embed. Without it, static files have the current time, causing cache-control to fail. From: https://github.com/golang/go/issues/44854
type StaticFileInfoWrapper ¶
func (*StaticFileInfoWrapper) ModTime ¶
func (f *StaticFileInfoWrapper) ModTime() time.Time