Closed eratio08 closed 2 years ago
Eike,
Thanks for the kind words. I sincerely apologize for the late reply. I'm in the middle of moving my family and a job search. Can you provide a full code example showing the issue?
Thanks and again, I apologize for the delay.
Best regards,
Roland
Hey Roland,
thanks for you reply!
So I'm trying to implement the IdentityPolicy
Trait of actix_identity to store a paseto token in a Cookie.
pub struct PasetoCookieIdentityPolicy {}
impl IdentityPolicy for PasetoCookieIdentityPolicy {
type Future = Ready<Result<Option<String>, Error>>;
type ResponseFuture = Ready<Result<(), Error>>;
fn from_request(&self, request: &mut ServiceRequest) -> Self::Future {
ready(Ok({
request
.cookie(&EnvVar::TokenCookieName.get_expect())
.and_then(|cookie| {
let key = PasetoSymmetricKey::<V4, Local>::from(
request.app_data::<AppData>().unwrap().paseto_key.clone(),
);
let token: &str = cookie.value();
PasetoParser::<V4, Local>::default()
.parse(token, &key)
.ok()
.map(|token| token["sup"].to_string())
})
}))
}
fn to_response<B>(
&self,
identity: Option<String>,
changed: bool,
response: &mut ServiceResponse<B>,
) -> Self::ResponseFuture {
if changed {
let id = match identity {
None => return ready(Ok(())),
Some(id) => id,
};
let key = PasetoSymmetricKey::<V4, Local>::from(
response
.request()
.app_data::<AppData>()
.unwrap()
.paseto_key
.clone(),
);
let claim = SubjectClaim::from(SubjectClaim::from(&id[..])); <-- failing here because string slice of id can not have a 'static lifetime
let token = PasetoBuilder::<V4, Local>::default()
.set_claim(claim)
.build(&key)
.unwrap();
let mut cookie = Cookie::new(EnvVar::TokenCookieName.get_expect().to_owned(), &token);
cookie.set_expires(OffsetDateTime::now_utc() + Duration::hours(1));
cookie.set_secure(true);
cookie.set_http_only(true);
cookie.set_same_site(SameSite::Strict);
let val = HeaderValue::from_str(&cookie.to_string()).unwrap();
response.headers_mut().append(header::SET_COOKIE, val);
}
ready(Ok(()))
}
}
Will try to get the repo up for a full code example if this snippet is not sufficient.
So the simple solution here is to turn your string into a & 'static str
like so:
let id : &'static str = Box::leak(identity.into_boxed_str());
let claim = SubjectClaim::from(id);
However I don't recommend building a token for every request in a policy like this. I'd suggest using a middleware to validate an existing token (or you could create a policy that only validates).
The reason for this is because encrypting a token is IO heavy on the CPU. If you attempt to encrypt a token on every single request you'll rapidly get bogged down. Instead, I recommend creating a token when the user has been authenticated and storing that in a cookie (or passing it to a client to be used in subsequent requests) so that the policy or middleware can be used to validate the token on each request which is a much quicker process.
I've added an example to the repository which does this. However, I think a cleaner solution would be to use a middleware instead of a policy but I've created it as a policy since that's what you're attempting to do. Good luck and have fun!
Thank you for the advice and the great example!
Is the usage of https://doc.rust-lang.org/std/boxed/struct.Box.html#method.leak save? From the description it sounds like using it will cause a memory leak as the box will never be released.
Was not planning to create a token on each request, but only to it on the login case, need to figure out how this is signaled to the policy, possibly with the changed
flag.
Yes, I should have been more clear. Box::leak
is safe, however, as indicated in the name, it leaks the memory which is what you would expect when you make a value live as 'static
since it will live for the life of the program. Given that it looks like you're writing a server, this is probably not what you want to do if you're going to be calling this repeatedly. The correct way would for me to just get rid of the need for the value to live for 'static
so I've done that and uploaded version 0.4.0 and updated the example so you no longer need to use Box::leak and your original implementation should now work. Thanks!
Hey hey,
really nice implementation and an amazing documentation!
I'm new to rust and my problem might just stem from the fact that I do not know how to archive this the rust-way.
I'm trying to set a subject claim from a non-static reference/dynamic value in a trait implementation.
From what I understand the signature of
set_claim
required the argument to have a'static
lifetime which will not be possible for a dynamic value (I could be wrong).How could this be archived?