mirror of
https://github.com/kanidm/kanidm.git
synced 2025-04-22 10:15:39 +02:00
Handle form-post as a response mode (#3467)
Some oauth2 clients apparently ignore what we tell them and request response modes we don't support. First, we should deserialise these and error correctly. Second, to maintain temporary compatibility, we remap form-post to query. This will be removed in future.
This commit is contained in:
parent
7b2bd38ab2
commit
dcd5cd23f4
|
@ -7,7 +7,8 @@ use serde::{Deserialize, Serialize};
|
|||
use serde_with::base64::{Base64, UrlSafe};
|
||||
use serde_with::formats::SpaceSeparator;
|
||||
use serde_with::{
|
||||
formats, serde_as, skip_serializing_none, NoneAsEmptyString, StringWithSeparator,
|
||||
formats, rust::deserialize_ignore_any, serde_as, skip_serializing_none, NoneAsEmptyString,
|
||||
StringWithSeparator,
|
||||
};
|
||||
use url::Url;
|
||||
use uuid::Uuid;
|
||||
|
@ -353,6 +354,9 @@ pub enum ResponseType {
|
|||
pub enum ResponseMode {
|
||||
Query,
|
||||
Fragment,
|
||||
FormPost,
|
||||
#[serde(other, deserialize_with = "deserialize_ignore_any")]
|
||||
Invalid,
|
||||
}
|
||||
|
||||
fn response_modes_supported_default() -> Vec<ResponseMode> {
|
||||
|
|
|
@ -122,6 +122,11 @@ impl std::fmt::Display for Oauth2Error {
|
|||
}
|
||||
|
||||
// == internal state formats that we encrypt and send.
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
enum SupportedResponseMode {
|
||||
Query,
|
||||
Fragment,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
|
@ -145,7 +150,7 @@ struct ConsentToken {
|
|||
// We stash some details here for oidc.
|
||||
pub nonce: Option<String>,
|
||||
/// The format the response should be returned to the application in.
|
||||
pub response_mode: ResponseMode,
|
||||
pub response_mode: SupportedResponseMode,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
|
@ -239,7 +244,7 @@ pub struct AuthorisePermitSuccess {
|
|||
// The exchange code as a String
|
||||
pub code: String,
|
||||
/// The format the response should be returned to the application in.
|
||||
pub response_mode: ResponseMode,
|
||||
response_mode: SupportedResponseMode,
|
||||
}
|
||||
|
||||
impl AuthorisePermitSuccess {
|
||||
|
@ -252,7 +257,7 @@ impl AuthorisePermitSuccess {
|
|||
redirect_uri.set_fragment(None);
|
||||
|
||||
match self.response_mode {
|
||||
ResponseMode::Query => {
|
||||
SupportedResponseMode::Query => {
|
||||
redirect_uri
|
||||
.query_pairs_mut()
|
||||
.append_pair("code", &self.code);
|
||||
|
@ -261,7 +266,7 @@ impl AuthorisePermitSuccess {
|
|||
redirect_uri.query_pairs_mut().append_pair("state", state);
|
||||
};
|
||||
}
|
||||
ResponseMode::Fragment => {
|
||||
SupportedResponseMode::Fragment => {
|
||||
redirect_uri.set_query(None);
|
||||
|
||||
// Per [the RFC](https://www.rfc-editor.org/rfc/rfc6749#section-3.1.2), we can't set query pairs on fragment-containing redirects, only query ones.
|
||||
|
@ -285,7 +290,7 @@ pub struct AuthoriseReject {
|
|||
// Where the client wants us to go back to.
|
||||
pub redirect_uri: Url,
|
||||
/// The format the response should be returned to the application in.
|
||||
pub response_mode: ResponseMode,
|
||||
response_mode: SupportedResponseMode,
|
||||
}
|
||||
|
||||
impl AuthoriseReject {
|
||||
|
@ -305,8 +310,8 @@ impl AuthoriseReject {
|
|||
.finish();
|
||||
|
||||
match self.response_mode {
|
||||
ResponseMode::Query => redirect_uri.set_query(Some(&encoded)),
|
||||
ResponseMode::Fragment => redirect_uri.set_fragment(Some(&encoded)),
|
||||
SupportedResponseMode::Query => redirect_uri.set_query(Some(&encoded)),
|
||||
SupportedResponseMode::Fragment => redirect_uri.set_fragment(Some(&encoded)),
|
||||
}
|
||||
|
||||
redirect_uri
|
||||
|
@ -1873,15 +1878,31 @@ impl IdmServerProxyReadTransaction<'_> {
|
|||
admin_warn!("Unsupported OAuth2 response_type (should be 'code')");
|
||||
return Err(Oauth2Error::UnsupportedResponseType);
|
||||
}
|
||||
|
||||
let Some(response_mode) = auth_req.get_response_mode() else {
|
||||
admin_warn!(
|
||||
warn!(
|
||||
"Invalid response_mode {:?} for response_type {:?}",
|
||||
auth_req.response_mode,
|
||||
auth_req.response_type
|
||||
auth_req.response_mode, auth_req.response_type
|
||||
);
|
||||
return Err(Oauth2Error::InvalidRequest);
|
||||
};
|
||||
|
||||
let response_mode = match response_mode {
|
||||
ResponseMode::Query => SupportedResponseMode::Query,
|
||||
ResponseMode::Fragment => SupportedResponseMode::Fragment,
|
||||
ResponseMode::FormPost => {
|
||||
warn!(
|
||||
"Invalid response mode form_post requested - many clients request this incorrectly but proceed with response_mode=query. Remapping to query."
|
||||
);
|
||||
warn!("This behaviour WILL BE REMOVED in a future release.");
|
||||
SupportedResponseMode::Query
|
||||
}
|
||||
ResponseMode::Invalid => {
|
||||
warn!("Invalid response mode requested, unable to proceed");
|
||||
return Err(Oauth2Error::InvalidRequest);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* 4.1.2.1. Error Response
|
||||
*
|
||||
|
|
Loading…
Reference in a new issue