Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
6d21b37
feat: add --app-hostname flag to coder server
deansheather Sep 19, 2022
b8a7a45
chore: add test for subdomain proxy passthrough
deansheather Sep 19, 2022
3b875b2
fixup! chore: add test for subdomain proxy passthrough
deansheather Sep 19, 2022
39e9b6f
chore: reorganize subdomain app handler
deansheather Sep 19, 2022
3a099ba
chore: add authorization check endpoint
deansheather Sep 20, 2022
25b8182
Merge branch 'main' into dean/app-tokens
deansheather Sep 20, 2022
e864f27
chore: improve proxy auth tests
deansheather Sep 20, 2022
b5d2be3
chore: refactor ExtractAPIKey to accept struct
deansheather Sep 20, 2022
d9b404d
feat: end-to-end workspace application authentication
deansheather Sep 21, 2022
da5f656
Merge branch 'main' into dean/app-tokens
deansheather Sep 21, 2022
312e0d5
fixup! Merge branch 'main' into dean/app-tokens
deansheather Sep 21, 2022
16bbcbe
feat: use a custom cookie name for devurls to avoid clashes
deansheather Sep 21, 2022
a172cd5
feat: /api/v2/applications/host endpoint, PR comments
deansheather Sep 21, 2022
d4986d2
fixup! feat: /api/v2/applications/host endpoint, PR comments
deansheather Sep 21, 2022
9b56f02
fixup! feat: /api/v2/applications/host endpoint, PR comments
deansheather Sep 21, 2022
d9186a8
chore: more pr comments
deansheather Sep 21, 2022
35962fc
Remove checkUserPermissions
kylecarbs Sep 21, 2022
b1436ec
fixup! Remove checkUserPermissions
deansheather Sep 21, 2022
11e985f
Merge branch 'main' into dean/app-tokens
deansheather Sep 21, 2022
496fde3
fixup! Merge branch 'main' into dean/app-tokens
deansheather Sep 21, 2022
3e30a9f
chore: more security stuff
deansheather Sep 21, 2022
11e6061
fixup! chore: more security stuff
deansheather Sep 21, 2022
cf70650
chore: more comments
deansheather Sep 21, 2022
6d66f55
Merge branch 'main' into dean/app-tokens
deansheather Sep 22, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Merge branch 'main' into dean/app-tokens
  • Loading branch information
deansheather committed Sep 21, 2022
commit 11e985fb9a7064b78585af6f40c8881fbe403d9e
9 changes: 5 additions & 4 deletions coderd/authorize.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,14 +88,15 @@ func (h *HTTPAuthorizer) Authorize(r *http.Request, action rbac.Action, object r
// checkAuthorization returns if the current API key can use the given
// permissions, factoring in the current user's roles and the API key scopes.
func (api *API) checkAuthorization(rw http.ResponseWriter, r *http.Request) {
ctx := r.Context()
auth := httpmw.UserAuthorization(r)

var params codersdk.AuthorizationRequest
if !httpapi.Read(rw, r, &params) {
if !httpapi.Read(ctx, rw, r, &params) {
return
}

api.Logger.Warn(r.Context(), "check-auth",
api.Logger.Warn(ctx, "check-auth",
slog.F("my_id", httpmw.APIKey(r).UserID),
slog.F("got_id", auth.ID),
slog.F("name", auth.Username),
Expand All @@ -105,7 +106,7 @@ func (api *API) checkAuthorization(rw http.ResponseWriter, r *http.Request) {
response := make(codersdk.AuthorizationResponse)
for k, v := range params.Checks {
if v.Object.ResourceType == "" {
httpapi.Write(rw, http.StatusBadRequest, codersdk.Response{
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
Message: fmt.Sprintf("Object's \"resource_type\" field must be defined for key %q.", k),
})
return
Expand All @@ -123,5 +124,5 @@ func (api *API) checkAuthorization(rw http.ResponseWriter, r *http.Request) {
response[k] = err == nil
}

httpapi.Write(rw, http.StatusOK, response)
httpapi.Write(ctx, rw, http.StatusOK, response)
}
2 changes: 1 addition & 1 deletion coderd/users.go
Original file line number Diff line number Diff line change
Expand Up @@ -1088,7 +1088,7 @@ func (api *API) createAPIKey(ctx context.Context, params createAPIKeyParams) (*h
scope = params.Scope
}

key, err := api.Database.InsertAPIKey(r.Context(), database.InsertAPIKeyParams{
key, err := api.Database.InsertAPIKey(ctx, database.InsertAPIKeyParams{
ID: keyID,
UserID: params.UserID,
LifetimeSeconds: params.LifetimeSeconds,
Expand Down
29 changes: 16 additions & 13 deletions coderd/workspaceapps.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ const (
redirectURIQueryParam = "redirect_uri"
)

func (api *API) appHost(rw http.ResponseWriter, _ *http.Request) {
httpapi.Write(rw, http.StatusOK, codersdk.GetAppHostResponse{
func (api *API) appHost(rw http.ResponseWriter, r *http.Request) {
httpapi.Write(r.Context(), rw, http.StatusOK, codersdk.GetAppHostResponse{
Host: api.AppHostname,
})
}
Expand Down Expand Up @@ -175,6 +175,7 @@ func (api *API) handleSubdomainApplications(middlewares ...func(http.Handler) ht
}

func (api *API) parseWorkspaceApplicationHostname(rw http.ResponseWriter, r *http.Request, next http.Handler, host string) (httpapi.ApplicationURL, bool) {
ctx := r.Context()
// Check if the hostname matches the access URL. If it does, the
// user was definitely trying to connect to the dashboard/API.
if httpapi.HostnamesMatch(api.AccessURL.Hostname(), host) {
Expand Down Expand Up @@ -204,7 +205,7 @@ func (api *API) parseWorkspaceApplicationHostname(rw http.ResponseWriter, r *htt
return httpapi.ApplicationURL{}, false
}

httpapi.Write(rw, http.StatusBadRequest, codersdk.Response{
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
Message: "Could not parse subdomain application URL.",
Detail: err.Error(),
})
Expand All @@ -215,7 +216,7 @@ func (api *API) parseWorkspaceApplicationHostname(rw http.ResponseWriter, r *htt
// valid application URL, so the base hostname should match the
// configured app hostname.
if !matchingBaseHostname {
httpapi.Write(rw, http.StatusNotFound, codersdk.Response{
httpapi.Write(ctx, rw, http.StatusNotFound, codersdk.Response{
Message: "The server does not accept application requests on this hostname.",
})
return httpapi.ApplicationURL{}, false
Expand All @@ -229,6 +230,7 @@ func (api *API) parseWorkspaceApplicationHostname(rw http.ResponseWriter, r *htt
// they will be redirected to the route below. If the user does have a session
// key but insufficient permissions a static error page will be rendered.
func (api *API) verifyWorkspaceApplicationAuth(rw http.ResponseWriter, r *http.Request, workspace database.Workspace, host string) bool {
ctx := r.Context()
_, ok := httpmw.APIKeyOptional(r)
if ok {
if !api.Authorize(r, rbac.ActionCreate, workspace.ApplicationConnectRBAC()) {
Expand All @@ -247,7 +249,7 @@ func (api *API) verifyWorkspaceApplicationAuth(rw http.ResponseWriter, r *http.R
// Exchange the encoded API key for a real one.
_, apiKey, err := decryptAPIKey(r.Context(), api.Database, encryptedAPIKey)
if err != nil {
httpapi.Write(rw, http.StatusBadRequest, codersdk.Response{
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
Message: "Could not decrypt API key. Please remove the query parameter and try again.",
Detail: err.Error(),
})
Expand Down Expand Up @@ -294,8 +296,9 @@ func (api *API) verifyWorkspaceApplicationAuth(rw http.ResponseWriter, r *http.R
// workspaceApplicationAuth is an endpoint on the main router that handles
// redirects from the subdomain handler.
func (api *API) workspaceApplicationAuth(rw http.ResponseWriter, r *http.Request) {
ctx := r.Context()
if api.AppHostname == "" {
httpapi.Write(rw, http.StatusNotFound, codersdk.Response{
httpapi.Write(ctx, rw, http.StatusNotFound, codersdk.Response{
Message: "The server does not accept subdomain-based application requests.",
})
return
Expand All @@ -310,14 +313,14 @@ func (api *API) workspaceApplicationAuth(rw http.ResponseWriter, r *http.Request
// Get the redirect URI from the query parameters and parse it.
redirectURI := r.URL.Query().Get(redirectURIQueryParam)
if redirectURI == "" {
httpapi.Write(rw, http.StatusBadRequest, codersdk.Response{
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
Message: "Missing redirect_uri query parameter.",
})
return
}
u, err := url.Parse(redirectURI)
if err != nil {
httpapi.Write(rw, http.StatusBadRequest, codersdk.Response{
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
Message: "Invalid redirect_uri query parameter.",
Detail: err.Error(),
})
Expand All @@ -328,14 +331,14 @@ func (api *API) workspaceApplicationAuth(rw http.ResponseWriter, r *http.Request
// valid app subdomain.
subdomain, rest := httpapi.SplitSubdomain(u.Hostname())
if !httpapi.HostnamesMatch(api.AppHostname, rest) {
httpapi.Write(rw, http.StatusBadRequest, codersdk.Response{
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
Message: "The redirect_uri query parameter must be a valid app subdomain.",
})
return
}
_, err = httpapi.ParseSubdomainAppURL(subdomain)
if err != nil {
httpapi.Write(rw, http.StatusBadRequest, codersdk.Response{
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
Message: "The redirect_uri query parameter must be a valid app subdomain.",
Detail: err.Error(),
})
Expand All @@ -355,15 +358,15 @@ func (api *API) workspaceApplicationAuth(rw http.ResponseWriter, r *http.Request
if lifetime > int64((time.Hour * 24 * 7).Seconds()) {
lifetime = int64((time.Hour * 24 * 7).Seconds())
}
cookie, err := api.createAPIKey(r, createAPIKeyParams{
cookie, err := api.createAPIKey(ctx, createAPIKeyParams{
UserID: apiKey.UserID,
LoginType: database.LoginTypePassword,
ExpiresAt: exp,
LifetimeSeconds: lifetime,
Scope: database.APIKeyScopeApplicationConnect,
})
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, codersdk.Response{
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
Message: "Failed to create API key.",
Detail: err.Error(),
})
Expand All @@ -375,7 +378,7 @@ func (api *API) workspaceApplicationAuth(rw http.ResponseWriter, r *http.Request
APIKey: cookie.Value,
})
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, codersdk.Response{
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
Message: "Failed to encrypt API key.",
Detail: err.Error(),
})
Expand Down
You are viewing a condensed version of this merge commit. You can view the full changes here.