HTTP services need a way for clients to authenticate with them. This diff implements a middleware that will reject invalid requests and a UserIdentity extractor that is able to extract user identity from a correct request.
Details
Created a resource:
web::resource("/hello") .route( web::get() .to(|user: UserIdentity| async move { format!("{user:?}") }), ) .wrap(get_comm_authentication_middleware()),
- Made a request without adding Authorization token -> got a 401 response with www-authenticate: Bearer header
- Made a request with Authorization: Bearer eyJ1c2VySUQiOiAiMSIsICJhY2Nlc3NUb2tlbiI6ICIyIiwgInNpZ25pbmdQdWJsaWNLZXkiOiAiMyJ9 header
- got a 200 response with text: "UserIdentity { user_id: "1", access_token: "2", signing_public_key: "3" }"
Diff Detail
- Repository
- rCOMM Comm
- Lint
No Lint Coverage - Unit
No Test Coverage
Event Timeline
services/comm-services-lib/src/http/auth.rs | ||
---|---|---|
28–30 | I don't really like that we discard error cause here - we should at least log it with debug! | |
43–49 | Can we please save this parsed token into extensions? I'm relying on this in custom extractors. And repeating the code UserIdentity::from_request() doesn't really help here. This way, handlers and extractors can rely on existence of Some(user_identity) = req.extensions().get::<UserIdentity>() - if it's Some then it means authentication was successful. Alternatively, this can be done later after we implement the Identity Service call |
services/comm-services-lib/src/http/auth.rs | ||
---|---|---|
22–25 | Taking my below suggestion into account, this function could return already parsed UserIdentity from extensions() if exists and return early |
services/comm-services-lib/src/http/auth.rs | ||
---|---|---|
28–30 | Good point, will fix | |
43–49 |
Note that if authentication was unsuccessful the middleware is going to fail anyway and handlers and extractors won't be even run. So this: If "optional authorization" is required for sth than sure I can update it. But then I would prefer to have two middlewares, one for optional and one for required so we don't need to repeat if user.is_none() {return AuthorizationError} at the beginning of every handler. |
services/comm-services-lib/src/http/auth.rs | ||
---|---|---|
43–49 | Yep, you're right, this will fail. But I'd still be happy to have this available in extension |
services/comm-services-lib/src/auth.rs | ||
---|---|---|
16–24 | up to you |
services/comm-services-lib/src/auth.rs | ||
---|---|---|
22–23 | for context on deviceID: https://linear.app/comm/issue/ENG-4072. rename should be used when directly mapping to another attribute. alias allows of the alias or the rust name to be used. Probably doesn't make a big difference if you're only deserializing, but if we do serialization, I think it will matter. |
Respond to review
services/comm-services-lib/src/auth.rs | ||
---|---|---|
16–24 | Now with deviceID all two fields need custom renames so I will leave it as is. | |
22–23 | Thank you for linking ENG-4072, I wasn't aware of it! device_id is much clearer (at least for parts of the codebase that don't directly touch olm stuff). Agree with the rename, not sure where we would use serialization, but it's 99% going to be js so makes sense to also use camelCase |
services/comm-services-lib/src/http/auth.rs | ||
---|---|---|
47–49 ↗ | (On Diff #30275) | Forgot to add logging here, will do before landing. |
services/comm-services-lib/src/http/auth.rs | ||
---|---|---|
47–49 ↗ | (On Diff #30275) | ok |