Skip to main content

openstack_keystone_core/federation/api/
error.rs

1// Licensed under the Apache License, Version 2.0 (the "License");
2// you may not use this file except in compliance with the License.
3// You may obtain a copy of the License at
4//
5//     http://www.apache.org/licenses/LICENSE-2.0
6//
7// Unless required by applicable law or agreed to in writing, software
8// distributed under the License is distributed on an "AS IS" BASIS,
9// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10// See the License for the specific language governing permissions and
11// limitations under the License.
12//
13// SPDX-License-Identifier: Apache-2.0
14
15//use thiserror::Error;
16//use tracing::{Level, error, instrument};
17
18use crate::api::error::KeystoneApiError;
19//use crate::federation::api::types::*;
20use crate::federation::error::FederationProviderError;
21
22//#[derive(Error, Debug)]
23//pub enum OidcError {
24//    /// OIDC Discovery error.
25//    #[error("discovery error for {url}: {msg}")]
26//    Discovery {
27//        /// IdP URL.
28//        url: String,
29//        /// Error message.
30//        msg: String,
31//    },
32//
33//    #[error("client without discovery is not supported")]
34//    ClientWithoutDiscoveryNotSupported,
35//
36//    #[error(
37//        "federated authentication requires mapping being specified in the payload or default set on the identity provider"
38//    )]
39//    MappingRequired,
40//
41//    #[error("JWT login requires `openstack-mapping` header to be present.")]
42//    MappingRequiredJwt,
43//
44//    #[error("`bearer` authorization token is missing.")]
45//    BearerJwtTokenMissing,
46//
47//    #[error("mapping id or mapping name with idp id must be specified")]
48//    MappingIdOrNameWithIdp,
49//
50//    #[error("groups claim must be an array of strings")]
51//    GroupsClaimNotArrayOfStrings,
52//
53//    /// IdP is disabled.
54//    #[error("identity provider is disabled")]
55//    IdentityProviderDisabled,
56//
57//    /// Mapping is disabled.
58//    #[error("mapping is disabled")]
59//    MappingDisabled,
60//
61//    #[error("request token error")]
62//    RequestToken { msg: String },
63//
64//    #[error("claim verification error")]
65//    ClaimVerification {
66//        #[from]
67//        source: openidconnect::ClaimsVerificationError,
68//    },
69//
70//    #[error(transparent)]
71//    OpenIdConnectReqwest {
72//        #[from]
73//        source: openidconnect::reqwest::Error,
74//    },
75//
76//    #[error(transparent)]
77//    OpenIdConnectConfiguration {
78//        #[from]
79//        source: openidconnect::ConfigurationError,
80//    },
81//
82//    #[error(transparent)]
83//    UrlParse {
84//        #[from]
85//        source: url::ParseError,
86//    },
87//
88//    #[error("server did not returned an ID token")]
89//    NoToken,
90//
91//    #[error("identity Provider client_id is missing")]
92//    ClientIdRequired,
93//
94//    #[error("ID token does not contain user id claim {0}")]
95//    UserIdClaimRequired(String),
96//
97//    #[error("ID token does not contain user id claim {0}")]
98//    UserNameClaimRequired(String),
99//
100//    /// Domain_id for the user cannot be identified.
101//    #[error("can not identify resulting domain_id for the user")]
102//    UserDomainUnbound,
103//
104//    /// Bound subject mismatch.
105//    #[error("bound subject mismatches {expected} != {found}")]
106//    BoundSubjectMismatch { expected: String, found: String },
107//
108//    /// Bound audiences mismatch.
109//    #[error("bound audiences mismatch {expected} != {found}")]
110//    BoundAudiencesMismatch { expected: String, found: String },
111//
112//    /// Bound claims mismatch.
113//    #[error("bound claims mismatch")]
114//    BoundClaimsMismatch {
115//        claim: String,
116//        expected: String,
117//        found: String,
118//    },
119//
120//    /// Error building user data.
121//    #[error(transparent)]
122//    MappedUserDataBuilder {
123//        #[from]
124//        #[allow(private_interfaces)]
125//        source: MappedUserDataBuilderError,
126//    },
127//
128//    /// Authentication expired.
129//    #[error("authentication expired")]
130//    AuthStateExpired,
131//
132//    /// Cannot use OIDC attribute mapping for JWT login.
133//    #[error("non jwt mapping requested for jwt login")]
134//    NonJwtMapping,
135//
136//    /// No JWT issuer can be identified for the mapping.
137//    #[error("no jwt issuer can be determined")]
138//    NoJwtIssuer,
139//
140//    /// User not found.
141//    #[error("token user not found")]
142//    UserNotFound(String),
143//}
144//
145//impl OidcError {
146//    pub fn discovery<U: AsRef<str>, T: std::error::Error>(url: U, fail: &T) -> Self {
147//        Self::Discovery {
148//            url: url.as_ref().to_string(),
149//            msg: fail.to_string(),
150//        }
151//    }
152//    pub fn request_token<T: std::error::Error>(fail: &T) -> Self {
153//        Self::RequestToken {
154//            msg: fail.to_string(),
155//        }
156//    }
157//}
158//
159///// Convert OIDC error into the [HTTP](KeystoneApiError) with the expected
160///// message.
161//impl From<OidcError> for KeystoneApiError {
162//    #[instrument(level = Level::ERROR)]
163//    fn from(value: OidcError) -> Self {
164//        error!("Federation error: {:#?}", value);
165//        match value {
166//            e @ OidcError::Discovery { .. } => {
167//                KeystoneApiError::InternalError(e.to_string())
168//            }
169//            e @ OidcError::ClientWithoutDiscoveryNotSupported => {
170//                KeystoneApiError::InternalError(e.to_string())
171//            }
172//            OidcError::IdentityProviderDisabled => {
173//                KeystoneApiError::BadRequest("Federated Identity Provider is disabled.".to_string())
174//            }
175//            OidcError::MappingDisabled => {
176//                KeystoneApiError::BadRequest("Federated Identity Provider mapping is disabled.".to_string())
177//            }
178//            OidcError::MappingRequired => {
179//                KeystoneApiError::BadRequest("Federated authentication requires mapping being specified in the payload or default set on the identity provider.".to_string())
180//            }
181//            OidcError::MappingRequiredJwt => {
182//                KeystoneApiError::BadRequest("JWT authentication requires `openstack-mapping` header to be provided.".to_string())
183//            }
184//            OidcError::BearerJwtTokenMissing => {
185//                KeystoneApiError::BadRequest("`bearer` token is missing in the `Authorization` header.".to_string())
186//            }
187//            OidcError::MappingIdOrNameWithIdp => {
188//                KeystoneApiError::BadRequest("Federated authentication requires mapping being specified in the payload either with ID or name with identity provider id.".to_string())
189//            }
190//            OidcError::GroupsClaimNotArrayOfStrings => {
191//                KeystoneApiError::BadRequest("Groups claim must be an array of strings representing group names.".to_string())
192//            }
193//            OidcError::RequestToken { msg } => {
194//                KeystoneApiError::BadRequest(format!("Error exchanging authorization code for the authorization token: {msg}"))
195//            }
196//            OidcError::ClaimVerification { source } => {
197//                KeystoneApiError::BadRequest(format!("Error in claims verification: {source}"))
198//            }
199//            OidcError::OpenIdConnectReqwest { source } => {
200//                KeystoneApiError::InternalError(format!("Error in OpenIDConnect logic: {source}"))
201//            }
202//            OidcError::OpenIdConnectConfiguration { source } => {
203//                KeystoneApiError::InternalError(format!("Error in OpenIDConnect logic: {source}"))
204//            }
205//            OidcError::UrlParse { source } => {
206//                KeystoneApiError::BadRequest(format!("Error in OpenIDConnect logic: {source}"))
207//            }
208//            e @ OidcError::NoToken => {
209//                KeystoneApiError::InternalError(format!("Error in OpenIDConnect logic: {e}"))
210//            }
211//            OidcError::ClientIdRequired => {
212//                KeystoneApiError::BadRequest("Identity Provider mut set `client_id`.".to_string())
213//            }
214//            OidcError::UserIdClaimRequired(source) => {
215//                KeystoneApiError::BadRequest(format!("OIDC ID token does not contain user id claim: {source}"))
216//            }
217//            OidcError::UserNameClaimRequired(source) => {
218//                KeystoneApiError::BadRequest(format!("OIDC ID token does not contain user name claim: {source}"))
219//            }
220//            OidcError::UserDomainUnbound => {
221//                KeystoneApiError::BadRequest("Cannot identify domain_id of the user.".to_string())
222//            }
223//            OidcError::BoundSubjectMismatch{ expected, found } => {
224//                KeystoneApiError::BadRequest(format!("OIDC Bound subject mismatches: {expected} != {found}"))
225//            }
226//            OidcError::BoundAudiencesMismatch{ expected, found } => {
227//                KeystoneApiError::BadRequest(format!("OIDC Bound audiences mismatches: {expected} != {found}"))
228//            }
229//            OidcError::BoundClaimsMismatch{ claim, expected, found } => {
230//                KeystoneApiError::BadRequest(format!("OIDC Bound claim {claim} mismatch: {expected} != {found}"))
231//            }
232//            e @ OidcError::MappedUserDataBuilder { .. } => {
233//                KeystoneApiError::InternalError(e.to_string())
234//            }
235//            OidcError::AuthStateExpired => {
236//                KeystoneApiError::BadRequest("Authentication has expired. Please start again.".to_string())
237//            }
238//            OidcError::NonJwtMapping | OidcError::NoJwtIssuer => {
239//                // Not exposing info about mapping and idp existence.
240//                KeystoneApiError::unauthorized(value, Some("mapping error"))
241//            }
242//            OidcError::UserNotFound(_) => {
243//                // Not exposing info about mapping and idp existence.
244//                KeystoneApiError::unauthorized(value, Some("User not found"))
245//            }
246//        }
247//    }
248//}
249
250impl From<FederationProviderError> for KeystoneApiError {
251    fn from(source: FederationProviderError) -> Self {
252        match source {
253            FederationProviderError::IdentityProviderNotFound(x) => Self::NotFound {
254                resource: "identity provider".into(),
255                identifier: x,
256            },
257            FederationProviderError::MappingNotFound(x) => Self::NotFound {
258                resource: "mapping provider".into(),
259                identifier: x,
260            },
261            FederationProviderError::Conflict(x) => Self::Conflict(x),
262            other => Self::InternalError(other.to_string()),
263        }
264    }
265}