workspaceapps
packageThis package is not in the latest version of its module.
Details
Validgo.mod file
The Go module system was introduced in Go 1.11 and is the official dependency management solution for Go.
Redistributable license
Redistributable licenses place minimal restrictions on how software can be used, modified, and redistributed.
Tagged version
Modules with tagged versions give importers more predictable builds.
Stable version
When a project reaches major version v1 it is considered stable.
- Learn more about best practices
Repository
Links
Documentation¶
Index¶
- Constants
- func WebsocketNetConn(ctx context.Context, conn *websocket.Conn, msgType websocket.MessageType) (context.Context, net.Conn)
- func WriteWorkspaceApp404(log slog.Logger, accessURL *url.URL, rw http.ResponseWriter, r *http.Request, ...)
- func WriteWorkspaceApp500(log slog.Logger, accessURL *url.URL, rw http.ResponseWriter, r *http.Request, ...)
- func WriteWorkspaceAppOffline(log slog.Logger, accessURL *url.URL, rw http.ResponseWriter, r *http.Request, ...)
- type AccessMethod
- type AgentProvider
- type DBTokenProvider
- type EncryptedAPIKeyPayload
- type IssueTokenRequest
- type Request
- type ResolveRequestOptions
- type SecurityKey
- func (k SecurityKey) DecryptAPIKey(encryptedAPIKey string) (string, error)
- func (k SecurityKey) EncryptAPIKey(payload EncryptedAPIKeyPayload) (string, error)
- func (k SecurityKey) SignToken(payload SignedToken) (string, error)
- func (k SecurityKey) String() string
- func (k SecurityKey) VerifySignedToken(str string) (SignedToken, error)
- type Server
- type SignedToken
- type SignedTokenProvider
Constants¶
const (// TODO(@deansheather): configurable expiryDefaultTokenExpiry =time.Minute// RedirectURIQueryParam is the query param for the app URL to be passed// back to the API auth endpoint on the main access URL.RedirectURIQueryParam = "redirect_uri")
const (// This needs to be a super unique query parameter because we don't want to// conflict with query parameters that users may use.//nolint:gosecSubdomainProxyAPIKeyParam = "coder_application_connect_api_key_35e783")
Variables¶
This section is empty.
Functions¶
funcWebsocketNetConn¶added inv0.22.0
func WebsocketNetConn(ctxcontext.Context, conn *websocket.Conn, msgTypewebsocket.MessageType) (context.Context,net.Conn)
WebsocketNetConn wraps websocket.NetConn and returns a context thatis tied to the parent context and the lifetime of the conn. Any errorduring read or write will cancel the context, but not close theconn. Close should be called to release context resources.
funcWriteWorkspaceApp404¶added inv0.22.0
func WriteWorkspaceApp404(logslog.Logger, accessURL *url.URL, rwhttp.ResponseWriter, r *http.Request, appReq *Request, msgstring)
WriteWorkspaceApp404 writes a HTML 404 error page for a workspace app. IfappReq is not nil, it will be used to log the request details at debug level.
funcWriteWorkspaceApp500¶added inv0.22.0
func WriteWorkspaceApp500(logslog.Logger, accessURL *url.URL, rwhttp.ResponseWriter, r *http.Request, appReq *Request, errerror, msgstring)
WriteWorkspaceApp500 writes a HTML 500 error page for a workspace app. IfappReq is not nil, it's fields will be added to the logged error message.
funcWriteWorkspaceAppOffline¶added inv0.22.0
func WriteWorkspaceAppOffline(logslog.Logger, accessURL *url.URL, rwhttp.ResponseWriter, r *http.Request, appReq *Request, msgstring)
WriteWorkspaceAppOffline writes a HTML 502 error page for a workspace app. IfappReq is not nil, it will be used to log the request details at debug level.
Types¶
typeAccessMethod¶
type AccessMethodstring
const (AccessMethodPathAccessMethod = "path"AccessMethodSubdomainAccessMethod = "subdomain"// AccessMethodTerminal is special since it's not a real app and only// applies to the PTY endpoint on the API.AccessMethodTerminalAccessMethod = "terminal")
typeAgentProvider¶added inv0.26.2
type AgentProvider interface {// ReverseProxy returns an httputil.ReverseProxy for proxying HTTP requests// to the specified agent.//// TODO: after wsconncache is deleted this doesn't need to return an error.ReverseProxy(targetURL, dashboardURL *url.URL, agentIDuuid.UUID) (_ *httputil.ReverseProxy, release func(), _error)// AgentConn returns a new connection to the specified agent.//// TODO: after wsconncache is deleted this doesn't need to return a release// func.AgentConn(ctxcontext.Context, agentIDuuid.UUID) (_ *codersdk.WorkspaceAgentConn, release func(), _error)Close()error}
typeDBTokenProvider¶added inv0.22.0
type DBTokenProvider struct {Loggerslog.Logger// DashboardURL is the main dashboard access URL for error pages.DashboardURL *url.URLAuthorizerrbac.AuthorizerDatabasedatabase.StoreDeploymentValues *codersdk.DeploymentValuesOAuth2Configs *httpmw.OAuth2ConfigsWorkspaceAgentInactiveTimeouttime.DurationSigningKeySecurityKey}
DBTokenProvider provides authentication and authorization for workspace appsby querying the database if the request is missing a valid token.
func (*DBTokenProvider)FromRequest¶added inv0.23.0
func (p *DBTokenProvider) FromRequest(r *http.Request) (*SignedToken,bool)
func (*DBTokenProvider)Issue¶added inv0.23.0
func (p *DBTokenProvider) Issue(ctxcontext.Context, rwhttp.ResponseWriter, r *http.Request, issueReqIssueTokenRequest) (*SignedToken,string,bool)
typeEncryptedAPIKeyPayload¶added inv0.22.0
typeIssueTokenRequest¶added inv0.23.0
type IssueTokenRequest struct {AppRequestRequest `json:"app_request"`// PathAppBaseURL is required.PathAppBaseURLstring `json:"path_app_base_url"`// AppHostname is the optional hostname for subdomain apps on the external// proxy. It must start with an asterisk.AppHostnamestring `json:"app_hostname"`// AppPath is the path of the user underneath the app base path.AppPathstring `json:"app_path"`// AppQuery is the query parameters the user provided in the app request.AppQuerystring `json:"app_query"`// SessionToken is the session token provided by the user.SessionTokenstring `json:"session_token"`}
func (IssueTokenRequest)AppBaseURL¶added inv0.23.0
func (rIssueTokenRequest) AppBaseURL() (*url.URL,error)
AppBaseURL returns the base URL of this specific app request. An error isreturned if a subdomain app hostname is not provided but the app is asubdomain app.
typeRequest¶
type Request struct {AccessMethodAccessMethod `json:"access_method"`// BasePath of the app. For path apps, this is the path prefix in the router// for this particular app. For subdomain apps, this should be "/". This is// used for setting the cookie path.BasePathstring `json:"base_path"`// For the following fields, if the AccessMethod is AccessMethodTerminal,// then only AgentNameOrID may be set and it must be a UUID. The other// fields must be left blank.UsernameOrIDstring `json:"username_or_id"`// WorkspaceAndAgent xor WorkspaceNameOrID are required.WorkspaceAndAgentstring `json:"-"`// "workspace" or "workspace.agent"WorkspaceNameOrIDstring `json:"workspace_name_or_id"`// AgentNameOrID is not required if the workspace has only one agent.AgentNameOrIDstring `json:"agent_name_or_id"`AppSlugOrPortstring `json:"app_slug_or_port"`}
typeResolveRequestOptions¶added inv0.23.0
type ResolveRequestOptions struct {Loggerslog.LoggerSignedTokenProviderSignedTokenProviderDashboardURL *url.URLPathAppBaseURL *url.URLAppHostnamestringAppRequestRequest// TODO: Replace these 2 fields with a "BrowserURL" field which is used for// redirecting the user back to their initial request after authenticating.// AppPath is the path under the app that was hit.AppPathstring// AppQuery is the raw query of the request.AppQuerystring}
typeSecurityKey¶added inv0.22.0
type SecurityKey [96]byte
SecurityKey is used for signing and encrypting app tokens and API keys.
The first 64 bytes of the key are used for signing tokens with HMAC-SHA256,and the last 32 bytes are used for encrypting API keys with AES-256-GCM.We use a single key for both operations to avoid having to store and managetwo keys.
funcKeyFromString¶added inv0.22.0
func KeyFromString(strstring) (SecurityKey,error)
func (SecurityKey)DecryptAPIKey¶added inv0.22.0
func (kSecurityKey) DecryptAPIKey(encryptedAPIKeystring) (string,error)
DecryptAPIKey undoes EncryptAPIKey and is used in the subdomain app handler.
func (SecurityKey)EncryptAPIKey¶added inv0.22.0
func (kSecurityKey) EncryptAPIKey(payloadEncryptedAPIKeyPayload) (string,error)
EncryptAPIKey encrypts an API key for subdomain token smuggling.
func (SecurityKey)SignToken¶added inv0.22.0
func (kSecurityKey) SignToken(payloadSignedToken) (string,error)
SignToken generates a signed workspace app token with the given payload. Ifthe payload doesn't have an expiry, it will be set to the current time plusthe default expiry.
func (SecurityKey)String¶added inv0.23.0
func (kSecurityKey) String()string
func (SecurityKey)VerifySignedToken¶added inv0.22.0
func (kSecurityKey) VerifySignedToken(strstring) (SignedToken,error)
VerifySignedToken parses a signed workspace app token with the given key andreturns the payload. If the token is invalid or expired, an error isreturned.
typeServer¶added inv0.22.0
type Server struct {Loggerslog.Logger// DashboardURL should be a url to the coderd dashboard. This can be the// same as the AccessURL if the Server is embedded.DashboardURL *url.URLAccessURL *url.URL// Hostname should be the wildcard hostname to use for workspace// applications INCLUDING the asterisk, (optional) suffix and leading dot.// It will use the same scheme and port number as the access URL.// E.g. "*.apps.coder.com" or "*-apps.coder.com".Hostnamestring// HostnameRegex contains the regex version of Hostname as generated by// httpapi.CompileHostnamePattern(). It MUST be set if Hostname is set.HostnameRegex *regexp.RegexpRealIPConfig *httpmw.RealIPConfigSignedTokenProviderSignedTokenProviderAppSecurityKeySecurityKey// DisablePathApps disables path-based apps. This is a security feature as path// based apps share the same cookie as the dashboard, and are susceptible to XSS// by a malicious workspace app.//// Subdomain apps are safer with their cookies scoped to the subdomain, and XSS// calls to the dashboard are not possible due to CORs.DisablePathAppsboolSecureAuthCookieboolAgentProviderAgentProvider// contains filtered or unexported fields}
Server serves workspace apps endpoints, including:- Path-based apps- Subdomain app middleware- Workspace reconnecting-pty (aka. web terminal)
func (*Server)Close¶added inv0.22.0
Close waits for all reconnecting-pty WebSocket connections to drain beforereturning.
func (*Server)HandleSubdomain¶added inv0.23.0
func (s *Server) HandleSubdomain(middlewares ...func(http.Handler)http.Handler) func(http.Handler)http.Handler
HandleSubdomain handles subdomain-based application proxy requests (aka.DevURLs in Coder V1).
There are a lot of paths here:
- If api.Hostname is not set then we pass on.
- If we can't read the request hostname then we return a 400.
- If the request hostname matches api.AccessURL then we pass on.
- We split the subdomain into the subdomain and the "rest". If there are noperiods in the hostname then we pass on.
- We parse the subdomain into a httpapi.ApplicationURL struct. If weencounter an error:a. If the "rest" does not match api.Hostname then we pass on;b. Otherwise, we return a 400.
- Finally, we verify that the "rest" matches api.Hostname, else wereturn a 404.
Rationales for each of the above steps:
- We pass on if api.Hostname is not set to avoid returning any errors if`--app-hostname` is not configured.
- Every request should have a valid Host header anyways.
- We pass on if the request hostname matches api.AccessURL so we cansupport having the access URL be at the same level as the applicationbase hostname.
- We pass on if there are no periods in the hostname as application URLsmust be a subdomain of a hostname, which implies there must be at leastone period.
- a. If the request subdomain is not a valid application URL, and the"rest" does not match api.Hostname, then it is very unlikely thatthe request was intended for this handler. We pass on.b. If the request subdomain is not a valid application URL, but the"rest" matches api.Hostname, then we return a 400 because therequest is probably a typo or something.
- We finally verify that the "rest" matches api.Hostname for securitypurposes regarding re-authentication and application proxy sessiontokens.
typeSignedToken¶added inv0.22.0
type SignedToken struct {// Request details.Request `json:"request"`// Trusted resolved details.Expirytime.Time `json:"expiry"`// set by GenerateToken if unsetUserIDuuid.UUID `json:"user_id"`WorkspaceIDuuid.UUID `json:"workspace_id"`AgentIDuuid.UUID `json:"agent_id"`AppURLstring `json:"app_url"`}
SignedToken is the struct data contained inside a workspace app JWE. Itcontains the details of the workspace app that the token is valid for toavoid database queries.
funcFromRequest¶added inv0.23.0
func FromRequest(r *http.Request, keySecurityKey) (*SignedToken,bool)
FromRequest returns the signed token from the request, if it exists and isvalid. The caller must check that the token matches the request.
funcResolveRequest¶added inv0.22.0
func ResolveRequest(rwhttp.ResponseWriter, r *http.Request, optsResolveRequestOptions) (*SignedToken,bool)
func (SignedToken)MatchesRequest¶added inv0.22.0
func (tSignedToken) MatchesRequest(reqRequest)bool
MatchesRequest returns true if the token matches the request. Any token thatdoes not match the request should be considered invalid.
typeSignedTokenProvider¶added inv0.22.0
type SignedTokenProvider interface {// FromRequest returns a parsed token from the request. If the request does// not contain a signed app token or is is invalid (expired, invalid// signature, etc.), it returns false.FromRequest(r *http.Request) (*SignedToken,bool)// Issue mints a new token for the given app request. It uses the long-lived// session token in the HTTP request to authenticate and authorize the// client for the given workspace app. The token is returned in struct and// string form. The string form should be written as a cookie.//// If the request is invalid or the user is not authorized to access the// app, false is returned. An error page is written to the response writer// in this case.Issue(ctxcontext.Context, rwhttp.ResponseWriter, r *http.Request, appReqIssueTokenRequest) (*SignedToken,string,bool)}
SignedTokenProvider provides signed workspace app tokens (aka. app tickets).
funcNewDBTokenProvider¶added inv0.22.0
func NewDBTokenProvider(logslog.Logger, accessURL *url.URL, authzrbac.Authorizer, dbdatabase.Store, cfg *codersdk.DeploymentValues, oauth2Cfgs *httpmw.OAuth2Configs, workspaceAgentInactiveTimeouttime.Duration, signingKeySecurityKey)SignedTokenProvider