Offer configuration of images for Oauth2 resources (#2665)

This commit is contained in:
Merlijn 2024-07-06 04:25:55 +02:00 committed by GitHub
parent f9a77ee1f3
commit 4795541719
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 87 additions and 9 deletions

1
Cargo.lock generated
View file

@ -3316,6 +3316,7 @@ dependencies = [
name = "kanidm_tools"
version = "1.3.0-dev"
dependencies = [
"anyhow",
"async-recursion",
"clap",
"clap_complete",

View file

@ -140,6 +140,7 @@ kanidm_unix_common = { path = "./unix_integration/common", version = "=1.3.0-dev
kanidm_utils_users = { path = "./libs/users", version = "=1.3.0-dev" }
sketching = { path = "./libs/sketching", version = "=1.3.0-dev" }
anyhow = { version = "1.0.86" }
argon2 = { version = "0.5.3", features = ["alloc"] }
askama = { version = "0.12.1", features = ["serde"] }
async-recursion = "1.1.0"

View file

@ -35,8 +35,8 @@ pub enum AppLink {
name: String,
display_name: String,
redirect_url: Url,
// Where the icon can be retrieved from.
icon: Option<Url>,
// Whether this oauth2 resource has an image.
has_image: bool,
},
}

View file

@ -51,11 +51,13 @@ impl<'a> IdmServerProxyReadTransaction<'a> {
.get_ava_single_iname(Attribute::Name)
.map(str::to_string)?;
let has_image = entry.get_ava_single_image(Attribute::Image).is_some();
Some(AppLink::Oauth2 {
name,
display_name,
redirect_url,
icon: None,
has_image,
})
})
.collect::<Vec<_>>();
@ -181,14 +183,14 @@ mod tests {
name,
display_name,
redirect_url,
icon,
has_image,
} => {
name == "test_resource_server"
&& display_name == "test_resource_server"
&& redirect_url
== &Url::parse("https://demo.example.com/landing")
.expect("Failed to parse URL")
&& icon.is_none()
&& !has_image
} // _ => false,
})
}

View file

@ -121,7 +121,7 @@ impl AppsApp {
name,
display_name,
redirect_url,
icon: _,
has_image: _,
} => {
let redirect_url = redirect_url.to_string();
html!{

View file

@ -35,6 +35,7 @@ test = true
doctest = false
[dependencies]
anyhow = { workspace = true }
async-recursion = { workspace = true }
clap = { workspace = true, features = ["derive", "env"] }
compact_jwt = { workspace = true, features = ["openssl"] }

View file

@ -1,10 +1,11 @@
use anyhow::{Context, Error};
use std::fs::read;
use std::process::exit;
use crate::common::OpType;
use crate::{handle_client_error, Oauth2Opt, OutputMode};
use crate::Oauth2ClaimMapJoin;
use kanidm_proto::internal::Oauth2ClaimMapJoin as ProtoOauth2ClaimMapJoin;
use kanidm_proto::internal::{ImageValue, Oauth2ClaimMapJoin as ProtoOauth2ClaimMapJoin};
impl Oauth2Opt {
pub fn debug(&self) -> bool {
@ -22,6 +23,8 @@ impl Oauth2Opt {
Oauth2Opt::SetDisplayname(cbopt) => cbopt.nopt.copt.debug,
Oauth2Opt::SetName { nopt, .. } => nopt.copt.debug,
Oauth2Opt::SetLandingUrl { nopt, .. } => nopt.copt.debug,
Oauth2Opt::SetImage { nopt, .. } => nopt.copt.debug,
Oauth2Opt::RemoveImage(nopt) => nopt.copt.debug,
Oauth2Opt::EnablePkce(nopt) => nopt.copt.debug,
Oauth2Opt::DisablePkce(nopt) => nopt.copt.debug,
Oauth2Opt::EnableLegacyCrypto(nopt) => nopt.copt.debug,
@ -248,6 +251,64 @@ impl Oauth2Opt {
Err(e) => handle_client_error(e, nopt.copt.output_mode),
}
}
Oauth2Opt::SetImage {
nopt,
path,
image_type,
} => {
let client = nopt.copt.to_client(OpType::Write).await;
let img_res: Result<ImageValue, Error> = (move || {
let file_name = path
.file_name()
.context("Please pass a file")?
.to_str()
.context("Path contains non utf-8")?
.to_string();
let image_type = if let Some(image_type) = image_type {
image_type.as_str().try_into().map_err(Error::msg)?
} else {
path
.extension().context("Path has no extension so we can't infer the imageType, or you could pass the optional imageType argument yourself.")?
.to_str().context("Path contains invalid utf-8")?
.try_into()
.map_err(Error::msg)?
};
let read_res = read(path);
match read_res {
Ok(data) => Ok(ImageValue::new(file_name, image_type, data)),
Err(err) => Err(err).context("Reading error"),
}
})();
let img = match img_res {
Ok(img) => img,
Err(err) => {
eprintln!("{err}");
return;
}
};
match client
.idm_oauth2_rs_update_image(nopt.name.as_str(), img)
.await
{
Ok(_) => println!("Success"),
Err(e) => handle_client_error(e, nopt.copt.output_mode),
}
}
Oauth2Opt::RemoveImage(nopt) => {
let client = nopt.copt.to_client(OpType::Write).await;
match client
.idm_oauth2_rs_delete_image(nopt.name.as_str())
.await
{
Ok(_) => println!("Success"),
Err(e) => handle_client_error(e, nopt.copt.output_mode),
}
}
Oauth2Opt::EnablePkce(nopt) => {
let client = nopt.copt.to_client(OpType::Write).await;
match client.idm_oauth2_rs_enable_pkce(nopt.name.as_str()).await {

View file

@ -1048,6 +1048,19 @@ pub enum Oauth2Opt {
#[clap(name = "landing-url")]
url: Url,
},
/// The image presented on the Kanidm Apps Listing page for an oauth2 resource server.
#[clap(name="set-image")]
SetImage {
#[clap(flatten)]
nopt: Named,
#[clap(name = "file-path")]
path: PathBuf,
#[clap(name = "image-type")]
image_type: Option<String>,
},
/// Removes the custom image previously set.
#[clap(name="remove-image")]
RemoveImage(Named),
/// Add a supplemental origin as a redirection target. For example a phone app
/// may use a redirect URL such as `app://my-cool-app` to trigger a native
@ -1070,7 +1083,6 @@ pub enum Oauth2Opt {
#[clap(flatten)]
copt: CommonOpt,
},
#[clap(name = "enable-pkce")]
/// Enable PKCE on this oauth2 client. This defaults to being enabled.
EnablePkce(Named),