Closed greglearns closed 5 years ago
Thanks for reporting this!
I'm not sure if there's a quick workaround, because I'm not super familiar with Heroku. It's this app.json
file that determines the environment, and maybe there's something we can roll back there, like a buildpack? https://github.com/portier/portier-broker/blob/master/app.json
Otherwise, I suspect this is the old openssl bindings 0.9 causing an issue, which we indirectly depend on via an old Hyper 0.11. We may magically fix this by upgrading to Hyper 0.12, but there's also Hyper 0.13 and async/await around the corner, so I'm a bit hesitant to work on that angle until then.
@stephank it does appear to be an openssl v0.9.24
problem. I just tried to update Portier-broker to use Hyper 0.12, but I gave up. In the mean time, that means that portier-broker cannot be deployed to Heroku.
Does anyone have thoughts on alternatives, since portier-broker cannot be deployed to Heroku? One option is that I could temporarily point at https://portier-demo.herokuapp.com/
for the time being since the site doesn't get much traffic currently, BUT, in order to verify / decode the JSON Web Token from the public instance, I need the public_key... is it possible to get that?
e.g. when I run my own broker, I generated my own public/private key, and then use the public key to decode/verify the token (see code below). However, if if I use https://portier-demo.herokuapp.com/
then I need the public key:
decode::<Claims>(&token, include_bytes!("../../public_key.der"), &validation)
used in this context...
pub fn verify_token(
token: String,
_iss: String,
_aud: String,
_leeway: i64,
) -> Result<UserEmail, Error> {
let validation = Validation {
algorithms: vec![jsonwebtoken::Algorithm::RS256],
iss: Some("https://portier-demo.herokuapp.com/".to_string()),
leeway: 60,
validate_exp: true,
..Default::default()
};
decode::<Claims>(&token, include_bytes!("../../public_key.der"), &validation)
.map(|data| {
dbg!(&data);
Ok(UserEmail::from(data.claims))
})
.map_err(|_err| {
dbg!(&_err);
format_err!("ServiceError::Unauthorized")
})?
}
We also deploy the public broker to Heroku, but using git. I tried to redeploy, and ran into the same error. Downgrading the stack to heroku-16
helps, though, and it looks like that stack is supported until somewhere in 2021, which should be fine.
It looks like we can pin the stack in app.json
simply by setting stack
there. Could you try using this deploy link? https://heroku.com/deploy?template=https://github.com/portier/portier-broker/tree/fix/heroku
As for the keys, we follow OpenID connect, so you can actually fetch those keys as JWK by fetching /.well-known/openid-configuration
, then following the URL in the jwks_uri
property of that document. (Both of these can be cached according to HTTP headers.)
Keys are intended to rotate. That currently doesn't happen for most of our deploys, unfortunately. But when we get around to fixing it, hardcoding keys is going to break.
1) The Heroku button works now. Great! Thank you!
2) Having just deployed the broker to Heroku, it will use the private key I created and pasted into BROKER_KEYTEXT
. But when you deployed broker.portier.io
, do you have to do the same thing? (I'm assuming the answer is "yes", but I just want to confirm.)
3) For verifying JWKs from the new instance I launched to Heroku or from broker.portier.io
, I don't see how to get public key from the /keys.json
(which the jwks_uri
property in /.well-known/openid-configuration
points to), because keys.json has the public components (n and e), but not the actual public key. Using Rust, I can't figure out how to validate the broker.portier.io
JWKs because https://github.com/Keats/jsonwebtoken
does not support generating the public key from the public components (which broker.portier.io/keys.json exposes) except in the experimental https://github.com/Keats/jsonwebtoken/tree/next
branch that has some other issues. Is there a recommended way in Rust to validate the JWKs generated by broker.portier.io
, or from the new Heroku instance I just deployed?
And, if there is an answer, I couldn't find it in the documentation. I can help put it into the documentation if needed.
jsonwebtoken
before, and ran into the same problem. I'm not sure the library support is there in Rust. :/ For now, your solution of including the public key will work fine, I guess.Oh, that's right! I guess I was confused. But that's exactly the code we use to verify a token signature.
And this, specifically, is how we parse a JWK: https://github.com/portier/portier-broker/blob/a0b3daed7c8c65b1c92b06328bd7d65accf1a3eb/src/crypto.rs#L180-L183
I guess we don't use any libraries to abstract it, though, just plain openssl.
(I think I was maybe confused about trying to use the ring crate before, and having trouble using that. The jsonwebtoken crate also uses ring instead of openssl, IIRC.)
That's right that the jsonwebtoken crate uses ring. So, basically, I can just lift that code from crypto.rs and use that it sounds like. Thank you. (but, I'm curious, why do this crate need to verify a token, since I thought it just generates them?)
I think that should work, yes.
The broker has to verify tokens from identity providers. The protocol between client -> broker and broker -> idp is roughly the same.
The "Deploy to Heroku" button stopped working. It gives this output