mirror of
https://github.com/kanidm/kanidm.git
synced 2025-05-21 00:13:55 +02:00
Test for corrupted unicode in SSH keys, keep the key title on error/resubmit (#3618)
This commit is contained in:
parent
8daeddb9e7
commit
47b091cd49
8
Makefile
8
Makefile
|
@ -368,3 +368,11 @@ publish:
|
|||
cargo publish -p kanidm_client
|
||||
cargo publish -p kanidm_tools
|
||||
|
||||
.PHONY: rust_container
|
||||
rust_container: # Build and run a container based on the Linux rust base container, with our requirements included
|
||||
rust_container:
|
||||
docker build --pull -t kanidm_rust -f scripts/Dockerfile.devcontainer .
|
||||
docker run \
|
||||
--rm -it \
|
||||
--name kanidm \
|
||||
--mount type=bind,source=$(PWD),target=/kanidm -w /kanidm kanidm_rust:latest
|
||||
|
|
6
scripts/Dockerfile.devcontainer
Normal file
6
scripts/Dockerfile.devcontainer
Normal file
|
@ -0,0 +1,6 @@
|
|||
FROM rust:latest
|
||||
|
||||
COPY ./scripts/install_ubuntu_dependencies.sh /tmp/
|
||||
RUN /tmp/install_ubuntu_dependencies.sh
|
||||
|
||||
WORKDIR /kanidm
|
|
@ -45,7 +45,7 @@ fi
|
|||
|
||||
# defaults
|
||||
KANIDM_CONFIG_FILE="./insecure_server.toml"
|
||||
KANIDM_URL="$(rg origin "${KANIDM_CONFIG_FILE}" | awk '{print $NF}' | tr -d '"')"
|
||||
KANIDM_URL="$(grep origin "${KANIDM_CONFIG_FILE}" | awk '{print $NF}' | tr -d '"')"
|
||||
KANIDM_CA_PATH="/tmp/kanidm/ca.pem"
|
||||
|
||||
# wait for them to shut down the server if it's running...
|
||||
|
@ -89,7 +89,7 @@ IDM_ADMIN_USER="idm_admin@localhost"
|
|||
echo "Resetting the idm_admin user..."
|
||||
IDM_ADMIN_PASS_RAW="$(${KANIDMD} recover-account idm_admin -o json 2>&1)"
|
||||
IDM_ADMIN_PASS="$(echo "${IDM_ADMIN_PASS_RAW}" | grep password | jq -r .password)"
|
||||
if [ -z "${IDM_ADMIN_PASS}" ] || [ "${IDM_ADMIN_PASS}" == "null " ]; then
|
||||
if [ -z "${IDM_ADMIN_PASS}" ] || [ "${IDM_ADMIN_PASS}" == "null" ]; then
|
||||
echo "Failed to reset idm_admin password!"
|
||||
echo "Raw output:"
|
||||
echo "${IDM_ADMIN_PASS_RAW}"
|
||||
|
|
|
@ -40,7 +40,6 @@ cargo run --bin kanidmd --release server &
|
|||
KANIDMD_PID=$!
|
||||
echo "Kanidm PID: ${KANIDMD_PID}"
|
||||
|
||||
|
||||
if [ "$(jobs -p | wc -l)" -eq 0 ]; then
|
||||
echo "Kanidmd failed to start!"
|
||||
exit 1
|
||||
|
@ -49,12 +48,18 @@ fi
|
|||
ATTEMPT=0
|
||||
|
||||
KANIDM_CONFIG_FILE="./insecure_server.toml"
|
||||
KANIDM_URL="$(rg origin "${KANIDM_CONFIG_FILE}" | awk '{print $NF}' | tr -d '"')"
|
||||
if [ -f "${KANIDM_CONFIG_FILE}" ]; then
|
||||
echo "Found config file ${KANIDM_CONFIG_FILE}"
|
||||
else
|
||||
echo "Config file ${KANIDM_CONFIG_FILE} not found!"
|
||||
exit 1
|
||||
fi
|
||||
KANIDM_URL="$(grep origin "${KANIDM_CONFIG_FILE}" | awk '{print $NF}' | tr -d '"')"
|
||||
KANIDM_CA_PATH="/tmp/kanidm/ca.pem"
|
||||
|
||||
while true; do
|
||||
echo "Waiting for the server to start... testing ${KANIDM_URL}"
|
||||
curl --cacert "${KANIDM_CA_PATH}" -fs "${KANIDM_URL}/status" >/dev/null && break
|
||||
echo "Waiting for the server to start... testing url '${KANIDM_URL}'"
|
||||
curl --cacert "${KANIDM_CA_PATH}" -f "${KANIDM_URL}/status" >/dev/null && break
|
||||
sleep 2
|
||||
ATTEMPT="$((ATTEMPT + 1))"
|
||||
if [ "${ATTEMPT}" -gt 3 ]; then
|
||||
|
|
|
@ -211,7 +211,6 @@ impl Modify for SecurityAddon {
|
|||
schemas(
|
||||
attribute::Attribute,
|
||||
|
||||
|
||||
scim_v1::ScimSyncState,
|
||||
scim_v1::ScimSyncRequest,
|
||||
scim_v1::ScimSyncRetentionMode,
|
||||
|
|
|
@ -119,9 +119,10 @@ struct SetUnixCredPartial {
|
|||
#[derive(Template)]
|
||||
#[template(path = "credential_update_add_ssh_publickey_partial.html")]
|
||||
struct AddSshPublicKeyPartial {
|
||||
key_title: Option<String>,
|
||||
title_error: Option<String>,
|
||||
key_error: Option<String>,
|
||||
key_value: Option<String>,
|
||||
key_error: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
|
@ -901,9 +902,10 @@ pub(crate) async fn view_add_ssh_publickey(
|
|||
let new_key = match opt_form {
|
||||
None => {
|
||||
return Ok((AddSshPublicKeyPartial {
|
||||
key_title: None,
|
||||
title_error: None,
|
||||
key_error: None,
|
||||
key_value: None,
|
||||
key_error: None,
|
||||
},)
|
||||
.into_response());
|
||||
}
|
||||
|
@ -920,9 +922,10 @@ pub(crate) async fn view_add_ssh_publickey(
|
|||
let publickey = match SshPublicKey::from_string(&new_key.key) {
|
||||
Err(_) => {
|
||||
return Ok((AddSshPublicKeyPartial {
|
||||
key_title: Some(new_key.title),
|
||||
title_error: None,
|
||||
key_error: Some("Key cannot be parsed".to_string()),
|
||||
key_value: Some(new_key.key),
|
||||
key_error: Some("Key cannot be parsed".to_string()),
|
||||
},)
|
||||
.into_response());
|
||||
}
|
||||
|
@ -932,7 +935,7 @@ pub(crate) async fn view_add_ssh_publickey(
|
|||
.qe_r_ref
|
||||
.handle_idmcredentialupdate(
|
||||
cu_session_token,
|
||||
CURequest::SshPublicKey(new_key.title, publickey),
|
||||
CURequest::SshPublicKey(new_key.title.clone(), publickey),
|
||||
kopid.eventid,
|
||||
)
|
||||
.await;
|
||||
|
@ -966,6 +969,7 @@ pub(crate) async fn view_add_ssh_publickey(
|
|||
status,
|
||||
HxPushUrl(Uri::from_static("/ui/reset/add_ssh_publickey")),
|
||||
AddSshPublicKeyPartial {
|
||||
key_title: Some(new_key.title),
|
||||
title_error,
|
||||
key_error,
|
||||
key_value: Some(new_key.key),
|
||||
|
|
|
@ -6,26 +6,38 @@
|
|||
hx-post="/ui/reset/add_ssh_publickey">
|
||||
<div>
|
||||
<label for="key-title" class="form-label">Title</label>
|
||||
<input type="text" class="form-control(% if let Some(_) = title_error %) is-invalid(% endif %)" id="key-title" name="title" aria-describedby="title-validation-feedback">
|
||||
<input type="text"
|
||||
class="form-control(% if let Some(_) = title_error %) is-invalid(% endif %)"
|
||||
id="key-title" name="title"
|
||||
aria-describedby="title-validation-feedback"
|
||||
autocapitalize="off" autocomplete="off" required
|
||||
value="(% if let Some(key_title) = key_title %)(( key_title ))(% endif %)">
|
||||
(% if let Some(title_error) = title_error %)
|
||||
<div id="title-validation-feedback" class="invalid-feedback">
|
||||
(% if let Some(title_error) = title_error %)(( title_error ))(% endif %)
|
||||
(( title_error ))
|
||||
</div>
|
||||
(% endif %)
|
||||
</div>
|
||||
<div>
|
||||
<label for="key-content" class="form-label">Key</label>
|
||||
<textarea class="form-control(% if let Some(_) = key_error %) is-invalid(% endif %)" id="key-content" rows="5" name="key"
|
||||
<textarea
|
||||
class="form-control(% if let Some(_) = key_error %) is-invalid(% endif %)"
|
||||
id="key-content" rows="5" name="key"
|
||||
aria-describedby="key-validation-feedback"
|
||||
placeholder="Begins with 'ssh-rsa', 'ecdsa-sha2-nistp256', 'ecdsa-sha2-nistp384', 'ecdsa-sha2-nistp521', 'ssh-ed25519', 'sk-ecdsa-sha2-nistp256@openssh.com', or 'sk-ssh-ed25519@openssh.com'"
|
||||
>(% if let Some(key_value) = key_value %)(( key_value ))(% endif %)</textarea>
|
||||
autocapitalize="off" autocomplete="off" required
|
||||
placeholder="Begins with 'ssh-rsa', 'ecdsa-sha2-nistp256', 'ecdsa-sha2-nistp384', 'ecdsa-sha2-nistp521', 'ssh-ed25519', 'sk-ecdsa-sha2-nistp256@openssh.com', or 'sk-ssh-ed25519@openssh.com'">(% if let Some(key_value) = key_value %)(( key_value ))(% endif %)</textarea>
|
||||
(% if let Some(key_error) = key_error %)
|
||||
<div id="key-validation-feedback" class="invalid-feedback">
|
||||
(% if let Some(key_error) = key_error %)(( key_error ))(% endif %)
|
||||
(( key_error ))
|
||||
</div>
|
||||
</div>
|
||||
(% endif%)
|
||||
</div>
|
||||
|
||||
<div class="column-gap-2 d-flex justify-content-end mt-2" hx-target="#credentialUpdateDynamicSection">
|
||||
<button type="button" class="btn btn-danger" hx-get=((Urls::CredReset)) hx-target="body">Cancel</button>
|
||||
<div class="column-gap-2 d-flex justify-content-end mt-2"
|
||||
hx-target="#credentialUpdateDynamicSection">
|
||||
<button type="button" class="btn btn-danger"
|
||||
hx-get=((Urls::CredReset)) hx-target="body">Cancel</button>
|
||||
<button type="submit" class="btn btn-primary">Submit</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -252,4 +252,30 @@ mod tests {
|
|||
// Test that we can parse json values into a valueset.
|
||||
crate::valueset::scim_json_put_reflexive::<ValueSetSshKey>(&vs, &[])
|
||||
}
|
||||
|
||||
#[test]
|
||||
/// this is a test case for bad characters in SSH keys
|
||||
fn test_invalid_character() {
|
||||
let ecdsa = concat!("ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEÀAAAIbmlzdHA1MjEAAACFBAGyIY7o3B",
|
||||
// ^ note the À here
|
||||
"tOzRiJ9vvjj96bRImwmyy5GvFSIUPlK00HitiAWGhiO1jGZKmK7220Oe4rqU3uAwA00a0758UODs+0OQHLMDRtl81l",
|
||||
"zPrVSdrYEDldxH9+a86dBZhdm0è15+ODDts2LHUknsJCRRldO4o9R9VrohlF7cbyBlnhJQrR4S+Oag== william@a",
|
||||
"methyst");
|
||||
println!("bytes of À {:?}", "À".as_bytes());
|
||||
let found_index = ecdsa.find("À").expect("Failed to find è in string");
|
||||
assert_eq!(found_index, 51, "Expected index 51");
|
||||
let bad_ssh_error = SshPublicKey::from_string(ecdsa);
|
||||
|
||||
assert!(
|
||||
bad_ssh_error.is_err(),
|
||||
"Expected error, but got: {:?}",
|
||||
bad_ssh_error
|
||||
);
|
||||
if let Err(err) = bad_ssh_error {
|
||||
assert_eq!(
|
||||
err.to_string(),
|
||||
format!("Invalid symbol 195, offset {}.", found_index - 20)
|
||||
); // the offset is 31 because the string has a 20 character leading key type plus the space
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue