-
Notifications
You must be signed in to change notification settings - Fork 62
Console API: sessions + static assets #384
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
| // but we don't return it from the scheme. The result of that scheme | ||
| // only tells us the Actor, i.e., the user ID. We can't just delete all | ||
| // sessions for that user ID because a user could have sessions going in | ||
| // multiple browsers and only want to log out one. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@davepacheco Interesting question here. We could just stick the token in the authn context, but it would only be there when the session cookie scheme is the one being used. It would be very simple but a little weird to just make it an optional field on the actor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
or we could write a Cookies extractor and just pull it again. prototype here 490a1e5
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It makes sense to me to pull it out again, at least for now. I like the idea of keeping the extractor in Omicron for now. What did you need from Dropshot to do that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just this
diff --git a/dropshot/src/lib.rs b/dropshot/src/lib.rs
index 66c516e..c6e6f3d 100644
--- a/dropshot/src/lib.rs
+++ b/dropshot/src/lib.rs
@@ -532,6 +532,7 @@ pub use config::ConfigDropshot;
pub use error::HttpError;
pub use error::HttpErrorResponseBody;
pub use handler::Extractor;
+pub use handler::ExtractorMetadata;
pub use handler::HttpResponse;
pub use handler::HttpResponseAccepted;
pub use handler::HttpResponseCreated;4f42add to
785adc5
Compare
Agreed. My first thought was to use something like Where do these files come from today? Is there going to be a circular dependency (assets shipped by console, so Nexus depends on console, but console also depends on Nexus)? |
davepacheco
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool.
| [dropshot_external] | ||
| bind_address = "127.0.0.1:0" | ||
|
|
||
| # |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
nexus/examples/config.toml
Outdated
| # IP address and TCP port on which to listen for the internal API | ||
| bind_address = "127.0.0.1:12221" | ||
|
|
||
| [dropshot_console] |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
| // but we don't return it from the scheme. The result of that scheme | ||
| // only tells us the Actor, i.e., the user ID. We can't just delete all | ||
| // sessions for that user ID because a user could have sessions going in | ||
| // multiple browsers and only want to log out one. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It makes sense to me to pull it out again, at least for now. I like the idea of keeping the extractor in Omicron for now. What did you need from Dropshot to do that?
|
Today on GCP these files are pushed around by the console's Dockerfile. For the last milestone demo I sent @jclulow a tarball of the files and he manually dropped them in the right place to be served by nginx. From #356:
|
6111086 to
356cf7c
Compare
| } | ||
|
|
||
| Ok(current) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is based on the file server example @ahl added to Dropshot for me.
| assets_directory.exists(), | ||
| "assets directory must exist at start time" | ||
| ); | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't feel confident about this, it's just meant to provisionally show the whole thing works.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we want to blow an assertion for this condition.
We could have this function return Result. It looks like the caller already does so it's not hard to propagate the error.
Maybe a little friendlier would be to have the caller construct an object from this path that can be used to resolve or serve file names within that tree. e.g., FileLoader or something. Then we store that in the context, instead of just the path that gets re-resolved every time we access it. In an ideal world, this might store an open fd and subsequent calls would use openat. I'm not sure that Rust's built-in fs supports this -- there's this, which sounds right, but the docs aren't clear.
It'd also be neat to sanity-check some well-known assets, but I'm not sure if that's too much knowledge to bake in here.
I keep wondering too if we should bake these assets into the Nexus binary, but I guess that's more trouble than it's worth.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minimal version done in 33ec251, no fancy FileLoader but I'll add a to-do comment about it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Made what I think is an improvement — using CARGO_MANIFEST_DIR, which consistently points at the nexus dir. Otherwise you get different results depending on the current working directory you're running the command from.
nexus/tests/test_console_api.rs
Outdated
|
|
||
| // TODO: responses with set-cookie in them won't work until this uses the | ||
| // new test helpers that don't lock you into a particular set of allowed | ||
| // headers. See https://github.com/oxidecomputer/omicron/pull/403 |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
| // TODO: /c/ prefix is def not what we want long-term but it makes things easy for now | ||
| #[endpoint { | ||
| method = GET, | ||
| path = "/c/{path:.*}", | ||
| }] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm fine with this for now, but for the future state: do we have route ranking mechanism? I don't (yet) have a solid understanding of how we know which api gets a request that comes into Nexus.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right now, no. You can’t define a wildcard route that overlaps another route.
| // we *could* auth gate the static assets but it would be kind of weird. | ||
| // prob not necessary. one way would be to have two directories, one that | ||
| // requires auth and one that doesn't. I'd rather not |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I'm with you. I definitely don't think we should do this. There should be nothing sensitive in our static assets. Also, we'd have a really hard time rendering a login or error page for the user if we couldn't send them the bundle to be able to render said page 😅
davepacheco
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if you were looking for another round.
| assets_directory.exists(), | ||
| "assets directory must exist at start time" | ||
| ); | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we want to blow an assertion for this condition.
We could have this function return Result. It looks like the caller already does so it's not hard to propagate the error.
Maybe a little friendlier would be to have the caller construct an object from this path that can be used to resolve or serve file names within that tree. e.g., FileLoader or something. Then we store that in the context, instead of just the path that gets re-resolved every time we access it. In an ideal world, this might store an open fd and subsequent calls would use openat. I'm not sure that Rust's built-in fs supports this -- there's this, which sounds right, but the docs aren't clear.
It'd also be neat to sanity-check some well-known assets, but I'm not sure if that's too much knowledge to bake in here.
I keep wondering too if we should bake these assets into the Nexus binary, but I guess that's more trouble than it's worth.
nexus/tests/common/http_testing.rs
Outdated
| }); | ||
| match (header_name, header_value) { | ||
| (Ok(name), Ok(value)) => { | ||
| self.expected_response_headers.append(name, value); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Presumably we could commonize these?
| let actual_value = headers.get(header_name).unwrap(); | ||
| ensure!( | ||
| actual_value == expected_value, | ||
| "response contained expected header {:?}, but with value {:?} instead of expected {:?}", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Love the detailed message!
8dd134a to
88df393
Compare
88df393 to
9332861
Compare
4aafb58 to
d0a871d
Compare
df69e5f to
ebb6303
Compare
ebb6303 to
eeaefc4
Compare
| let msg = format!("errors shutting down: ({})", errors.join(", ")); | ||
| Err(msg) | ||
| } else { | ||
| Ok(()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is left over from when I added the third dropshot server. it's no longer necessary, but it's an improvement and makes adding a third one later trivial, so I'm leaving it in
f3809e8 to
159c4d0
Compare
Serve the console from Nexus. Closes #356
For routes that go to console pages, we check auth server-side — if the client is authed, we will send down an HTML response that loads the JS bundle in a script tag. If the client is not, we redirect to whatever IdP is configured. For testing/demo purposes this will probably be a provisional login page served by Nexus.
What's in here
POST /logincreate session in DB and sets session cookieGET /loginserves console bundle, but without auth gate, so we can show a login formPOST /logoutdeletes session in DB and clears session cookie in browserGET /orgs/*serves console pages, e.g., if you go toconsole.oxide.rack/projectsor whateverGET /assets/*for serving assets from a configurable directory. no auth: static assets MUST NOT be sensitive[console]section to config for assets dir and cache timeExtractorimpl so we can get the session token out of the request in order to delete the session during logoutbodyfield onTestResponsepublic (so I can assert about it as bytes)response_body()toparsed_body()expect_response_headertoTestResponsePlaces I especially want feedback
NormalConfig & ConsoleConfig, but intersection types aren't clean in Rust like they are in, e.g., TypeScriptCookiesextractor and the cookie header value helperPathBufin place where it seems like I could be usingPath, but I couldn't get it to compile. Does it matter?There will be more to add to this list.
Things left to do
Open questions to punt on
See it in action