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}