diff options
| -rw-r--r-- | fatcat-openapi2.yml | 65 | ||||
| -rw-r--r-- | rust/fatcat-api-spec/README.md | 3 | ||||
| -rw-r--r-- | rust/fatcat-api-spec/api.yaml | 65 | ||||
| -rw-r--r-- | rust/fatcat-api-spec/api/swagger.yaml | 133 | ||||
| -rw-r--r-- | rust/fatcat-api-spec/examples/client.rs | 8 | ||||
| -rw-r--r-- | rust/fatcat-api-spec/examples/server_lib/server.rs | 30 | ||||
| -rw-r--r-- | rust/fatcat-api-spec/src/client.rs | 118 | ||||
| -rw-r--r-- | rust/fatcat-api-spec/src/lib.rs | 26 | ||||
| -rw-r--r-- | rust/fatcat-api-spec/src/mimetypes.rs | 32 | ||||
| -rw-r--r-- | rust/fatcat-api-spec/src/models.rs | 57 | ||||
| -rw-r--r-- | rust/fatcat-api-spec/src/server.rs | 172 | 
11 files changed, 670 insertions, 39 deletions
diff --git a/fatcat-openapi2.yml b/fatcat-openapi2.yml index b7f7fbb3..fcef1c46 100644 --- a/fatcat-openapi2.yml +++ b/fatcat-openapi2.yml @@ -443,6 +443,12 @@ definitions:        username:          type: string          example: "zerocool93" +      is_admin: +        type: boolean +      is_bot: +        type: boolean +      is_active: +        type: boolean    editgroup:      type: object      properties: @@ -546,6 +552,29 @@ definitions:          additionalProperties: {}        role:          type: string +  auth_oidc: +    type: object +    required: +      - provider +      - sub +      - iss +    properties: +      provider: +        type: string +      sub: +        type: string +      iss: +        type: string +  auth_oidc_result: +    type: object +    required: +      - editor +      - token +    properties: +      editor: +        $ref: "#/definitions/editor" +      token: +        type: string  x-auth-responses: &AUTHRESPONSES    401: @@ -2616,3 +2645,39 @@ paths:            description: Generic Error            schema:              $ref: "#/definitions/error_response" +  /auth/oidc: +    post: +      operationId: "auth_oidc" +      tags: # TAGLINE +      security: +        # required admin privs +        - Bearer: [] +      parameters: +        - name: oidc_params +          in: body +          required: true +          schema: +            $ref: "#/definitions/auth_oidc" +      responses: +        200: +          description: Found +          schema: +            $ref: "#/definitions/auth_oidc_result" +        201: +          description: Created +          schema: +            $ref: "#/definitions/auth_oidc_result" +        400: +          description: Bad Request +          schema: +            $ref: "#/definitions/error_response" +        409: +          description: Conflict +          schema: +            $ref: "#/definitions/error_response" +        500: +          description: Generic Error +          schema: +            $ref: "#/definitions/error_response" +        <<: *AUTHRESPONSES + diff --git a/rust/fatcat-api-spec/README.md b/rust/fatcat-api-spec/README.md index 4f7f811f..e4fba05b 100644 --- a/rust/fatcat-api-spec/README.md +++ b/rust/fatcat-api-spec/README.md @@ -13,7 +13,7 @@ To see how to make this your own, look here:  [README](https://github.com/swagger-api/swagger-codegen/blob/master/README.md)  - API version: 0.1.0 -- Build date: 2019-01-01T02:26:01.855Z +- Build date: 2019-01-04T00:25:33.063Z  This autogenerated project defines an API crate `fatcat` which contains:  * An `Api` trait defining the API in Rust. @@ -79,6 +79,7 @@ cargo run --example client GetCreatorReleases  cargo run --example client GetCreatorRevision  cargo run --example client LookupCreator  cargo run --example client UpdateCreator +cargo run --example client AuthOidc  cargo run --example client GetEditor  cargo run --example client GetEditorChangelog  cargo run --example client AcceptEditgroup diff --git a/rust/fatcat-api-spec/api.yaml b/rust/fatcat-api-spec/api.yaml index b7f7fbb3..fcef1c46 100644 --- a/rust/fatcat-api-spec/api.yaml +++ b/rust/fatcat-api-spec/api.yaml @@ -443,6 +443,12 @@ definitions:        username:          type: string          example: "zerocool93" +      is_admin: +        type: boolean +      is_bot: +        type: boolean +      is_active: +        type: boolean    editgroup:      type: object      properties: @@ -546,6 +552,29 @@ definitions:          additionalProperties: {}        role:          type: string +  auth_oidc: +    type: object +    required: +      - provider +      - sub +      - iss +    properties: +      provider: +        type: string +      sub: +        type: string +      iss: +        type: string +  auth_oidc_result: +    type: object +    required: +      - editor +      - token +    properties: +      editor: +        $ref: "#/definitions/editor" +      token: +        type: string  x-auth-responses: &AUTHRESPONSES    401: @@ -2616,3 +2645,39 @@ paths:            description: Generic Error            schema:              $ref: "#/definitions/error_response" +  /auth/oidc: +    post: +      operationId: "auth_oidc" +      tags: # TAGLINE +      security: +        # required admin privs +        - Bearer: [] +      parameters: +        - name: oidc_params +          in: body +          required: true +          schema: +            $ref: "#/definitions/auth_oidc" +      responses: +        200: +          description: Found +          schema: +            $ref: "#/definitions/auth_oidc_result" +        201: +          description: Created +          schema: +            $ref: "#/definitions/auth_oidc_result" +        400: +          description: Bad Request +          schema: +            $ref: "#/definitions/error_response" +        409: +          description: Conflict +          schema: +            $ref: "#/definitions/error_response" +        500: +          description: Generic Error +          schema: +            $ref: "#/definitions/error_response" +        <<: *AUTHRESPONSES + diff --git a/rust/fatcat-api-spec/api/swagger.yaml b/rust/fatcat-api-spec/api/swagger.yaml index 89017877..f2a58670 100644 --- a/rust/fatcat-api-spec/api/swagger.yaml +++ b/rust/fatcat-api-spec/api/swagger.yaml @@ -6481,6 +6481,97 @@ paths:        path: "/changelog/:index"        HttpMethod: "Get"        httpmethod: "get" +  /auth/oidc: +    post: +      operationId: "auth_oidc" +      parameters: +      - in: "body" +        name: "oidc_params" +        required: true +        schema: +          $ref: "#/definitions/auth_oidc" +        uppercase_data_type: "AUTHOIDC" +        refName: "auth_oidc" +        formatString: "{:?}" +        example: "???" +        model_key: "editgroup_edits" +        uppercase_operation_id: "AUTH_OIDC" +        consumesJson: true +      responses: +        200: +          description: "Found" +          schema: +            $ref: "#/definitions/auth_oidc_result" +          x-responseId: "Found" +          x-uppercaseResponseId: "FOUND" +          uppercase_operation_id: "AUTH_OIDC" +          uppercase_data_type: "AUTHOIDCRESULT" +          producesJson: true +        201: +          description: "Created" +          schema: +            $ref: "#/definitions/auth_oidc_result" +          x-responseId: "Created" +          x-uppercaseResponseId: "CREATED" +          uppercase_operation_id: "AUTH_OIDC" +          uppercase_data_type: "AUTHOIDCRESULT" +          producesJson: true +        400: +          description: "Bad Request" +          schema: +            $ref: "#/definitions/error_response" +          x-responseId: "BadRequest" +          x-uppercaseResponseId: "BAD_REQUEST" +          uppercase_operation_id: "AUTH_OIDC" +          uppercase_data_type: "ERRORRESPONSE" +          producesJson: true +        401: +          description: "Not Authorized" +          schema: +            $ref: "#/definitions/error_response" +          headers: +            WWW_Authenticate: +              type: "string" +          x-responseId: "NotAuthorized" +          x-uppercaseResponseId: "NOT_AUTHORIZED" +          uppercase_operation_id: "AUTH_OIDC" +          uppercase_data_type: "ERRORRESPONSE" +          producesJson: true +        403: +          description: "Forbidden" +          schema: +            $ref: "#/definitions/error_response" +          x-responseId: "Forbidden" +          x-uppercaseResponseId: "FORBIDDEN" +          uppercase_operation_id: "AUTH_OIDC" +          uppercase_data_type: "ERRORRESPONSE" +          producesJson: true +        409: +          description: "Conflict" +          schema: +            $ref: "#/definitions/error_response" +          x-responseId: "Conflict" +          x-uppercaseResponseId: "CONFLICT" +          uppercase_operation_id: "AUTH_OIDC" +          uppercase_data_type: "ERRORRESPONSE" +          producesJson: true +        500: +          description: "Generic Error" +          schema: +            $ref: "#/definitions/error_response" +          x-responseId: "GenericError" +          x-uppercaseResponseId: "GENERIC_ERROR" +          uppercase_operation_id: "AUTH_OIDC" +          uppercase_data_type: "ERRORRESPONSE" +          producesJson: true +      security: +      - Bearer: [] +      operation_id: "auth_oidc" +      uppercase_operation_id: "AUTH_OIDC" +      path: "/auth/oidc" +      HttpMethod: "Post" +      httpmethod: "post" +      noClientExample: true  securityDefinitions:    Bearer:      type: "apiKey" @@ -7642,8 +7733,17 @@ definitions:        username:          type: "string"          example: "zerocool93" +      is_admin: +        type: "boolean" +      is_bot: +        type: "boolean" +      is_active: +        type: "boolean"      example: +      is_admin: true +      is_active: true        editor_id: "q3nouwy3nnbsvo3h5klxsx4a7y" +      is_bot: true        username: "zerocool93"      upperCaseName: "EDITOR"    editgroup: @@ -7988,6 +8088,39 @@ definitions:        creator_id: "creator_id"        index: 1      upperCaseName: "RELEASE_CONTRIB" +  auth_oidc: +    type: "object" +    required: +    - "iss" +    - "provider" +    - "sub" +    properties: +      provider: +        type: "string" +      sub: +        type: "string" +      iss: +        type: "string" +    upperCaseName: "AUTH_OIDC" +  auth_oidc_result: +    type: "object" +    required: +    - "editor" +    - "token" +    properties: +      editor: +        $ref: "#/definitions/editor" +      token: +        type: "string" +    example: +      editor: +        is_admin: true +        is_active: true +        editor_id: "q3nouwy3nnbsvo3h5klxsx4a7y" +        is_bot: true +        username: "zerocool93" +      token: "token" +    upperCaseName: "AUTH_OIDC_RESULT"    file_entity_urls:      required:      - "rel" diff --git a/rust/fatcat-api-spec/examples/client.rs b/rust/fatcat-api-spec/examples/client.rs index bf0c07b3..d95b4ffd 100644 --- a/rust/fatcat-api-spec/examples/client.rs +++ b/rust/fatcat-api-spec/examples/client.rs @@ -12,7 +12,7 @@ extern crate uuid;  use clap::{App, Arg};  #[allow(unused_imports)]  use fatcat::{ -    AcceptEditgroupResponse, ApiError, ApiNoContext, ContextWrapperExt, CreateContainerBatchResponse, CreateContainerResponse, CreateCreatorBatchResponse, CreateCreatorResponse, +    AcceptEditgroupResponse, ApiError, ApiNoContext, AuthOidcResponse, ContextWrapperExt, CreateContainerBatchResponse, CreateContainerResponse, CreateCreatorBatchResponse, CreateCreatorResponse,      CreateEditgroupResponse, CreateFileBatchResponse, CreateFileResponse, CreateFilesetBatchResponse, CreateFilesetResponse, CreateReleaseBatchResponse, CreateReleaseResponse,      CreateWebcaptureBatchResponse, CreateWebcaptureResponse, CreateWorkBatchResponse, CreateWorkResponse, DeleteContainerEditResponse, DeleteContainerResponse, DeleteCreatorEditResponse,      DeleteCreatorResponse, DeleteFileEditResponse, DeleteFileResponse, DeleteFilesetEditResponse, DeleteFilesetResponse, DeleteReleaseEditResponse, DeleteReleaseResponse, @@ -271,6 +271,12 @@ fn main() {          //     let result = client.update_creator("ident_example".to_string(), ???, Some("editgroup_id_example".to_string())).wait();          //     println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>")));          //  }, + +        // Disabled because there's no example. +        // Some("AuthOidc") => { +        //     let result = client.auth_oidc(???).wait(); +        //     println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>"))); +        //  },          Some("GetEditor") => {              let result = client.get_editor("editor_id_example".to_string()).wait();              println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>"))); diff --git a/rust/fatcat-api-spec/examples/server_lib/server.rs b/rust/fatcat-api-spec/examples/server_lib/server.rs index a9301650..b6408343 100644 --- a/rust/fatcat-api-spec/examples/server_lib/server.rs +++ b/rust/fatcat-api-spec/examples/server_lib/server.rs @@ -11,18 +11,18 @@ use swagger;  use fatcat::models;  use fatcat::{ -    AcceptEditgroupResponse, Api, ApiError, Context, CreateContainerBatchResponse, CreateContainerResponse, CreateCreatorBatchResponse, CreateCreatorResponse, CreateEditgroupResponse, -    CreateFileBatchResponse, CreateFileResponse, CreateFilesetBatchResponse, CreateFilesetResponse, CreateReleaseBatchResponse, CreateReleaseResponse, CreateWebcaptureBatchResponse, -    CreateWebcaptureResponse, CreateWorkBatchResponse, CreateWorkResponse, DeleteContainerEditResponse, DeleteContainerResponse, DeleteCreatorEditResponse, DeleteCreatorResponse, -    DeleteFileEditResponse, DeleteFileResponse, DeleteFilesetEditResponse, DeleteFilesetResponse, DeleteReleaseEditResponse, DeleteReleaseResponse, DeleteWebcaptureEditResponse, -    DeleteWebcaptureResponse, DeleteWorkEditResponse, DeleteWorkResponse, GetChangelogEntryResponse, GetChangelogResponse, GetContainerEditResponse, GetContainerHistoryResponse, -    GetContainerRedirectsResponse, GetContainerResponse, GetContainerRevisionResponse, GetCreatorEditResponse, GetCreatorHistoryResponse, GetCreatorRedirectsResponse, GetCreatorReleasesResponse, -    GetCreatorResponse, GetCreatorRevisionResponse, GetEditgroupResponse, GetEditorChangelogResponse, GetEditorResponse, GetFileEditResponse, GetFileHistoryResponse, GetFileRedirectsResponse, -    GetFileResponse, GetFileRevisionResponse, GetFilesetEditResponse, GetFilesetHistoryResponse, GetFilesetRedirectsResponse, GetFilesetResponse, GetFilesetRevisionResponse, GetReleaseEditResponse, -    GetReleaseFilesResponse, GetReleaseFilesetsResponse, GetReleaseHistoryResponse, GetReleaseRedirectsResponse, GetReleaseResponse, GetReleaseRevisionResponse, GetReleaseWebcapturesResponse, -    GetWebcaptureEditResponse, GetWebcaptureHistoryResponse, GetWebcaptureRedirectsResponse, GetWebcaptureResponse, GetWebcaptureRevisionResponse, GetWorkEditResponse, GetWorkHistoryResponse, -    GetWorkRedirectsResponse, GetWorkReleasesResponse, GetWorkResponse, GetWorkRevisionResponse, LookupContainerResponse, LookupCreatorResponse, LookupFileResponse, LookupReleaseResponse, -    UpdateContainerResponse, UpdateCreatorResponse, UpdateFileResponse, UpdateFilesetResponse, UpdateReleaseResponse, UpdateWebcaptureResponse, UpdateWorkResponse, +    AcceptEditgroupResponse, Api, ApiError, AuthOidcResponse, Context, CreateContainerBatchResponse, CreateContainerResponse, CreateCreatorBatchResponse, CreateCreatorResponse, +    CreateEditgroupResponse, CreateFileBatchResponse, CreateFileResponse, CreateFilesetBatchResponse, CreateFilesetResponse, CreateReleaseBatchResponse, CreateReleaseResponse, +    CreateWebcaptureBatchResponse, CreateWebcaptureResponse, CreateWorkBatchResponse, CreateWorkResponse, DeleteContainerEditResponse, DeleteContainerResponse, DeleteCreatorEditResponse, +    DeleteCreatorResponse, DeleteFileEditResponse, DeleteFileResponse, DeleteFilesetEditResponse, DeleteFilesetResponse, DeleteReleaseEditResponse, DeleteReleaseResponse, +    DeleteWebcaptureEditResponse, DeleteWebcaptureResponse, DeleteWorkEditResponse, DeleteWorkResponse, GetChangelogEntryResponse, GetChangelogResponse, GetContainerEditResponse, +    GetContainerHistoryResponse, GetContainerRedirectsResponse, GetContainerResponse, GetContainerRevisionResponse, GetCreatorEditResponse, GetCreatorHistoryResponse, GetCreatorRedirectsResponse, +    GetCreatorReleasesResponse, GetCreatorResponse, GetCreatorRevisionResponse, GetEditgroupResponse, GetEditorChangelogResponse, GetEditorResponse, GetFileEditResponse, GetFileHistoryResponse, +    GetFileRedirectsResponse, GetFileResponse, GetFileRevisionResponse, GetFilesetEditResponse, GetFilesetHistoryResponse, GetFilesetRedirectsResponse, GetFilesetResponse, GetFilesetRevisionResponse, +    GetReleaseEditResponse, GetReleaseFilesResponse, GetReleaseFilesetsResponse, GetReleaseHistoryResponse, GetReleaseRedirectsResponse, GetReleaseResponse, GetReleaseRevisionResponse, +    GetReleaseWebcapturesResponse, GetWebcaptureEditResponse, GetWebcaptureHistoryResponse, GetWebcaptureRedirectsResponse, GetWebcaptureResponse, GetWebcaptureRevisionResponse, GetWorkEditResponse, +    GetWorkHistoryResponse, GetWorkRedirectsResponse, GetWorkReleasesResponse, GetWorkResponse, GetWorkRevisionResponse, LookupContainerResponse, LookupCreatorResponse, LookupFileResponse, +    LookupReleaseResponse, UpdateContainerResponse, UpdateCreatorResponse, UpdateFileResponse, UpdateFilesetResponse, UpdateReleaseResponse, UpdateWebcaptureResponse, UpdateWorkResponse,  };  #[derive(Copy, Clone)] @@ -296,6 +296,12 @@ impl Api for Server {          Box::new(futures::failed("Generic failure".into()))      } +    fn auth_oidc(&self, oidc_params: models::AuthOidc, context: &Context) -> Box<Future<Item = AuthOidcResponse, Error = ApiError> + Send> { +        let context = context.clone(); +        println!("auth_oidc({:?}) - X-Span-ID: {:?}", oidc_params, context.x_span_id.unwrap_or(String::from("<none>")).clone()); +        Box::new(futures::failed("Generic failure".into())) +    } +      fn get_editor(&self, editor_id: String, context: &Context) -> Box<Future<Item = GetEditorResponse, Error = ApiError> + Send> {          let context = context.clone();          println!("get_editor(\"{}\") - X-Span-ID: {:?}", editor_id, context.x_span_id.unwrap_or(String::from("<none>")).clone()); diff --git a/rust/fatcat-api-spec/src/client.rs b/rust/fatcat-api-spec/src/client.rs index b67e193a..44bcd54d 100644 --- a/rust/fatcat-api-spec/src/client.rs +++ b/rust/fatcat-api-spec/src/client.rs @@ -35,18 +35,18 @@ use swagger::{ApiError, Context, XSpanId};  use models;  use { -    AcceptEditgroupResponse, Api, CreateContainerBatchResponse, CreateContainerResponse, CreateCreatorBatchResponse, CreateCreatorResponse, CreateEditgroupResponse, CreateFileBatchResponse, -    CreateFileResponse, CreateFilesetBatchResponse, CreateFilesetResponse, CreateReleaseBatchResponse, CreateReleaseResponse, CreateWebcaptureBatchResponse, CreateWebcaptureResponse, -    CreateWorkBatchResponse, CreateWorkResponse, DeleteContainerEditResponse, DeleteContainerResponse, DeleteCreatorEditResponse, DeleteCreatorResponse, DeleteFileEditResponse, DeleteFileResponse, -    DeleteFilesetEditResponse, DeleteFilesetResponse, DeleteReleaseEditResponse, DeleteReleaseResponse, DeleteWebcaptureEditResponse, DeleteWebcaptureResponse, DeleteWorkEditResponse, -    DeleteWorkResponse, GetChangelogEntryResponse, GetChangelogResponse, GetContainerEditResponse, GetContainerHistoryResponse, GetContainerRedirectsResponse, GetContainerResponse, -    GetContainerRevisionResponse, GetCreatorEditResponse, GetCreatorHistoryResponse, GetCreatorRedirectsResponse, GetCreatorReleasesResponse, GetCreatorResponse, GetCreatorRevisionResponse, -    GetEditgroupResponse, GetEditorChangelogResponse, GetEditorResponse, GetFileEditResponse, GetFileHistoryResponse, GetFileRedirectsResponse, GetFileResponse, GetFileRevisionResponse, -    GetFilesetEditResponse, GetFilesetHistoryResponse, GetFilesetRedirectsResponse, GetFilesetResponse, GetFilesetRevisionResponse, GetReleaseEditResponse, GetReleaseFilesResponse, -    GetReleaseFilesetsResponse, GetReleaseHistoryResponse, GetReleaseRedirectsResponse, GetReleaseResponse, GetReleaseRevisionResponse, GetReleaseWebcapturesResponse, GetWebcaptureEditResponse, -    GetWebcaptureHistoryResponse, GetWebcaptureRedirectsResponse, GetWebcaptureResponse, GetWebcaptureRevisionResponse, GetWorkEditResponse, GetWorkHistoryResponse, GetWorkRedirectsResponse, -    GetWorkReleasesResponse, GetWorkResponse, GetWorkRevisionResponse, LookupContainerResponse, LookupCreatorResponse, LookupFileResponse, LookupReleaseResponse, UpdateContainerResponse, -    UpdateCreatorResponse, UpdateFileResponse, UpdateFilesetResponse, UpdateReleaseResponse, UpdateWebcaptureResponse, UpdateWorkResponse, +    AcceptEditgroupResponse, Api, AuthOidcResponse, CreateContainerBatchResponse, CreateContainerResponse, CreateCreatorBatchResponse, CreateCreatorResponse, CreateEditgroupResponse, +    CreateFileBatchResponse, CreateFileResponse, CreateFilesetBatchResponse, CreateFilesetResponse, CreateReleaseBatchResponse, CreateReleaseResponse, CreateWebcaptureBatchResponse, +    CreateWebcaptureResponse, CreateWorkBatchResponse, CreateWorkResponse, DeleteContainerEditResponse, DeleteContainerResponse, DeleteCreatorEditResponse, DeleteCreatorResponse, +    DeleteFileEditResponse, DeleteFileResponse, DeleteFilesetEditResponse, DeleteFilesetResponse, DeleteReleaseEditResponse, DeleteReleaseResponse, DeleteWebcaptureEditResponse, +    DeleteWebcaptureResponse, DeleteWorkEditResponse, DeleteWorkResponse, GetChangelogEntryResponse, GetChangelogResponse, GetContainerEditResponse, GetContainerHistoryResponse, +    GetContainerRedirectsResponse, GetContainerResponse, GetContainerRevisionResponse, GetCreatorEditResponse, GetCreatorHistoryResponse, GetCreatorRedirectsResponse, GetCreatorReleasesResponse, +    GetCreatorResponse, GetCreatorRevisionResponse, GetEditgroupResponse, GetEditorChangelogResponse, GetEditorResponse, GetFileEditResponse, GetFileHistoryResponse, GetFileRedirectsResponse, +    GetFileResponse, GetFileRevisionResponse, GetFilesetEditResponse, GetFilesetHistoryResponse, GetFilesetRedirectsResponse, GetFilesetResponse, GetFilesetRevisionResponse, GetReleaseEditResponse, +    GetReleaseFilesResponse, GetReleaseFilesetsResponse, GetReleaseHistoryResponse, GetReleaseRedirectsResponse, GetReleaseResponse, GetReleaseRevisionResponse, GetReleaseWebcapturesResponse, +    GetWebcaptureEditResponse, GetWebcaptureHistoryResponse, GetWebcaptureRedirectsResponse, GetWebcaptureResponse, GetWebcaptureRevisionResponse, GetWorkEditResponse, GetWorkHistoryResponse, +    GetWorkRedirectsResponse, GetWorkReleasesResponse, GetWorkResponse, GetWorkRevisionResponse, LookupContainerResponse, LookupCreatorResponse, LookupFileResponse, LookupReleaseResponse, +    UpdateContainerResponse, UpdateCreatorResponse, UpdateFileResponse, UpdateFilesetResponse, UpdateReleaseResponse, UpdateWebcaptureResponse, UpdateWorkResponse,  };  /// Convert input into a base path, e.g. "http://example:123". Also checks the scheme as it goes. @@ -2030,6 +2030,100 @@ impl Api for Client {          Box::new(futures::done(result))      } +    fn auth_oidc(&self, param_oidc_params: models::AuthOidc, context: &Context) -> Box<Future<Item = AuthOidcResponse, Error = ApiError> + Send> { +        let url = format!("{}/v0/auth/oidc", self.base_path); + +        let body = serde_json::to_string(¶m_oidc_params).expect("impossible to fail to serialize"); + +        let hyper_client = (self.hyper_client)(); +        let request = hyper_client.request(hyper::method::Method::Post, &url); +        let mut custom_headers = hyper::header::Headers::new(); + +        let request = request.body(&body); + +        custom_headers.set(ContentType(mimetypes::requests::AUTH_OIDC.clone())); +        context.x_span_id.as_ref().map(|header| custom_headers.set(XSpanId(header.clone()))); + +        let request = request.headers(custom_headers); + +        // Helper function to provide a code block to use `?` in (to be replaced by the `catch` block when it exists). +        fn parse_response(mut response: hyper::client::response::Response) -> Result<AuthOidcResponse, ApiError> { +            match response.status.to_u16() { +                200 => { +                    let mut buf = String::new(); +                    response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; +                    let body = serde_json::from_str::<models::AuthOidcResult>(&buf)?; + +                    Ok(AuthOidcResponse::Found(body)) +                } +                201 => { +                    let mut buf = String::new(); +                    response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; +                    let body = serde_json::from_str::<models::AuthOidcResult>(&buf)?; + +                    Ok(AuthOidcResponse::Created(body)) +                } +                400 => { +                    let mut buf = String::new(); +                    response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; +                    let body = serde_json::from_str::<models::ErrorResponse>(&buf)?; + +                    Ok(AuthOidcResponse::BadRequest(body)) +                } +                401 => { +                    let mut buf = String::new(); +                    response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; +                    let body = serde_json::from_str::<models::ErrorResponse>(&buf)?; +                    header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } +                    let response_www_authenticate = response +                        .headers +                        .get::<ResponseWwwAuthenticate>() +                        .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + +                    Ok(AuthOidcResponse::NotAuthorized { +                        body: body, +                        www_authenticate: response_www_authenticate.0.clone(), +                    }) +                } +                403 => { +                    let mut buf = String::new(); +                    response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; +                    let body = serde_json::from_str::<models::ErrorResponse>(&buf)?; + +                    Ok(AuthOidcResponse::Forbidden(body)) +                } +                409 => { +                    let mut buf = String::new(); +                    response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; +                    let body = serde_json::from_str::<models::ErrorResponse>(&buf)?; + +                    Ok(AuthOidcResponse::Conflict(body)) +                } +                500 => { +                    let mut buf = String::new(); +                    response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; +                    let body = serde_json::from_str::<models::ErrorResponse>(&buf)?; + +                    Ok(AuthOidcResponse::GenericError(body)) +                } +                code => { +                    let mut buf = [0; 100]; +                    let debug_body = match response.read(&mut buf) { +                        Ok(len) => match str::from_utf8(&buf[..len]) { +                            Ok(body) => Cow::from(body), +                            Err(_) => Cow::from(format!("<Body was not UTF8: {:?}>", &buf[..len].to_vec())), +                        }, +                        Err(e) => Cow::from(format!("<Failed to read body: {}>", e)), +                    }; +                    Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", code, response.headers, debug_body))) +                } +            } +        } + +        let result = request.send().map_err(|e| ApiError(format!("No response received: {}", e))).and_then(parse_response); +        Box::new(futures::done(result)) +    } +      fn get_editor(&self, param_editor_id: String, context: &Context) -> Box<Future<Item = GetEditorResponse, Error = ApiError> + Send> {          let url = format!(              "{}/v0/editor/{editor_id}", diff --git a/rust/fatcat-api-spec/src/lib.rs b/rust/fatcat-api-spec/src/lib.rs index c6126c9c..c89dc90c 100644 --- a/rust/fatcat-api-spec/src/lib.rs +++ b/rust/fatcat-api-spec/src/lib.rs @@ -349,6 +349,24 @@ pub enum UpdateCreatorResponse {  }  #[derive(Debug, PartialEq)] +pub enum AuthOidcResponse { +    /// Found +    Found(models::AuthOidcResult), +    /// Created +    Created(models::AuthOidcResult), +    /// Bad Request +    BadRequest(models::ErrorResponse), +    /// Not Authorized +    NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, +    /// Forbidden +    Forbidden(models::ErrorResponse), +    /// Conflict +    Conflict(models::ErrorResponse), +    /// Generic Error +    GenericError(models::ErrorResponse), +} + +#[derive(Debug, PartialEq)]  pub enum GetEditorResponse {      /// Found      Found(models::Editor), @@ -1281,6 +1299,8 @@ pub trait Api {      fn update_creator(&self, ident: String, entity: models::CreatorEntity, editgroup_id: Option<String>, context: &Context) -> Box<Future<Item = UpdateCreatorResponse, Error = ApiError> + Send>; +    fn auth_oidc(&self, oidc_params: models::AuthOidc, context: &Context) -> Box<Future<Item = AuthOidcResponse, Error = ApiError> + Send>; +      fn get_editor(&self, editor_id: String, context: &Context) -> Box<Future<Item = GetEditorResponse, Error = ApiError> + Send>;      fn get_editor_changelog(&self, editor_id: String, context: &Context) -> Box<Future<Item = GetEditorChangelogResponse, Error = ApiError> + Send>; @@ -1527,6 +1547,8 @@ pub trait ApiNoContext {      fn update_creator(&self, ident: String, entity: models::CreatorEntity, editgroup_id: Option<String>) -> Box<Future<Item = UpdateCreatorResponse, Error = ApiError> + Send>; +    fn auth_oidc(&self, oidc_params: models::AuthOidc) -> Box<Future<Item = AuthOidcResponse, Error = ApiError> + Send>; +      fn get_editor(&self, editor_id: String) -> Box<Future<Item = GetEditorResponse, Error = ApiError> + Send>;      fn get_editor_changelog(&self, editor_id: String) -> Box<Future<Item = GetEditorChangelogResponse, Error = ApiError> + Send>; @@ -1810,6 +1832,10 @@ impl<'a, T: Api> ApiNoContext for ContextWrapper<'a, T> {          self.api().update_creator(ident, entity, editgroup_id, &self.context())      } +    fn auth_oidc(&self, oidc_params: models::AuthOidc) -> Box<Future<Item = AuthOidcResponse, Error = ApiError> + Send> { +        self.api().auth_oidc(oidc_params, &self.context()) +    } +      fn get_editor(&self, editor_id: String) -> Box<Future<Item = GetEditorResponse, Error = ApiError> + Send> {          self.api().get_editor(editor_id, &self.context())      } diff --git a/rust/fatcat-api-spec/src/mimetypes.rs b/rust/fatcat-api-spec/src/mimetypes.rs index 77a66c46..322ab045 100644 --- a/rust/fatcat-api-spec/src/mimetypes.rs +++ b/rust/fatcat-api-spec/src/mimetypes.rs @@ -452,6 +452,34 @@ pub mod responses {      lazy_static! {          pub static ref UPDATE_CREATOR_GENERIC_ERROR: Mime = mime!(Application / Json);      } +    /// Create Mime objects for the response content types for AuthOidc +    lazy_static! { +        pub static ref AUTH_OIDC_FOUND: Mime = mime!(Application / Json); +    } +    /// Create Mime objects for the response content types for AuthOidc +    lazy_static! { +        pub static ref AUTH_OIDC_CREATED: Mime = mime!(Application / Json); +    } +    /// Create Mime objects for the response content types for AuthOidc +    lazy_static! { +        pub static ref AUTH_OIDC_BAD_REQUEST: Mime = mime!(Application / Json); +    } +    /// Create Mime objects for the response content types for AuthOidc +    lazy_static! { +        pub static ref AUTH_OIDC_NOT_AUTHORIZED: Mime = mime!(Application / Json); +    } +    /// Create Mime objects for the response content types for AuthOidc +    lazy_static! { +        pub static ref AUTH_OIDC_FORBIDDEN: Mime = mime!(Application / Json); +    } +    /// Create Mime objects for the response content types for AuthOidc +    lazy_static! { +        pub static ref AUTH_OIDC_CONFLICT: Mime = mime!(Application / Json); +    } +    /// Create Mime objects for the response content types for AuthOidc +    lazy_static! { +        pub static ref AUTH_OIDC_GENERIC_ERROR: Mime = mime!(Application / Json); +    }      /// Create Mime objects for the response content types for GetEditor      lazy_static! {          pub static ref GET_EDITOR_FOUND: Mime = mime!(Application / Json); @@ -1693,6 +1721,10 @@ pub mod requests {      lazy_static! {          pub static ref UPDATE_CREATOR: Mime = mime!(Application / Json);      } +    /// Create Mime objects for the request content types for AuthOidc +    lazy_static! { +        pub static ref AUTH_OIDC: Mime = mime!(Application / Json); +    }      /// Create Mime objects for the request content types for CreateEditgroup      lazy_static! {          pub static ref CREATE_EDITGROUP: Mime = mime!(Application / Json); diff --git a/rust/fatcat-api-spec/src/models.rs b/rust/fatcat-api-spec/src/models.rs index 4d7575b6..8c17cf66 100644 --- a/rust/fatcat-api-spec/src/models.rs +++ b/rust/fatcat-api-spec/src/models.rs @@ -10,6 +10,43 @@ use std::collections::HashMap;  use swagger;  #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct AuthOidc { +    #[serde(rename = "provider")] +    pub provider: String, + +    #[serde(rename = "sub")] +    pub sub: String, + +    #[serde(rename = "iss")] +    pub iss: String, +} + +impl AuthOidc { +    pub fn new(provider: String, sub: String, iss: String) -> AuthOidc { +        AuthOidc { +            provider: provider, +            sub: sub, +            iss: iss, +        } +    } +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct AuthOidcResult { +    #[serde(rename = "editor")] +    pub editor: models::Editor, + +    #[serde(rename = "token")] +    pub token: String, +} + +impl AuthOidcResult { +    pub fn new(editor: models::Editor, token: String) -> AuthOidcResult { +        AuthOidcResult { editor: editor, token: token } +    } +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]  pub struct ChangelogEntry {      #[serde(rename = "index")]      pub index: i64, @@ -272,11 +309,29 @@ pub struct Editor {      #[serde(rename = "username")]      pub username: String, + +    #[serde(rename = "is_admin")] +    #[serde(skip_serializing_if = "Option::is_none")] +    pub is_admin: Option<bool>, + +    #[serde(rename = "is_bot")] +    #[serde(skip_serializing_if = "Option::is_none")] +    pub is_bot: Option<bool>, + +    #[serde(rename = "is_active")] +    #[serde(skip_serializing_if = "Option::is_none")] +    pub is_active: Option<bool>,  }  impl Editor {      pub fn new(username: String) -> Editor { -        Editor { editor_id: None, username: username } +        Editor { +            editor_id: None, +            username: username, +            is_admin: None, +            is_bot: None, +            is_active: None, +        }      }  } diff --git a/rust/fatcat-api-spec/src/server.rs b/rust/fatcat-api-spec/src/server.rs index 19e33194..8a515e43 100644 --- a/rust/fatcat-api-spec/src/server.rs +++ b/rust/fatcat-api-spec/src/server.rs @@ -37,18 +37,18 @@ use swagger::{ApiError, Context, XSpanId};  #[allow(unused_imports)]  use models;  use { -    AcceptEditgroupResponse, Api, CreateContainerBatchResponse, CreateContainerResponse, CreateCreatorBatchResponse, CreateCreatorResponse, CreateEditgroupResponse, CreateFileBatchResponse, -    CreateFileResponse, CreateFilesetBatchResponse, CreateFilesetResponse, CreateReleaseBatchResponse, CreateReleaseResponse, CreateWebcaptureBatchResponse, CreateWebcaptureResponse, -    CreateWorkBatchResponse, CreateWorkResponse, DeleteContainerEditResponse, DeleteContainerResponse, DeleteCreatorEditResponse, DeleteCreatorResponse, DeleteFileEditResponse, DeleteFileResponse, -    DeleteFilesetEditResponse, DeleteFilesetResponse, DeleteReleaseEditResponse, DeleteReleaseResponse, DeleteWebcaptureEditResponse, DeleteWebcaptureResponse, DeleteWorkEditResponse, -    DeleteWorkResponse, GetChangelogEntryResponse, GetChangelogResponse, GetContainerEditResponse, GetContainerHistoryResponse, GetContainerRedirectsResponse, GetContainerResponse, -    GetContainerRevisionResponse, GetCreatorEditResponse, GetCreatorHistoryResponse, GetCreatorRedirectsResponse, GetCreatorReleasesResponse, GetCreatorResponse, GetCreatorRevisionResponse, -    GetEditgroupResponse, GetEditorChangelogResponse, GetEditorResponse, GetFileEditResponse, GetFileHistoryResponse, GetFileRedirectsResponse, GetFileResponse, GetFileRevisionResponse, -    GetFilesetEditResponse, GetFilesetHistoryResponse, GetFilesetRedirectsResponse, GetFilesetResponse, GetFilesetRevisionResponse, GetReleaseEditResponse, GetReleaseFilesResponse, -    GetReleaseFilesetsResponse, GetReleaseHistoryResponse, GetReleaseRedirectsResponse, GetReleaseResponse, GetReleaseRevisionResponse, GetReleaseWebcapturesResponse, GetWebcaptureEditResponse, -    GetWebcaptureHistoryResponse, GetWebcaptureRedirectsResponse, GetWebcaptureResponse, GetWebcaptureRevisionResponse, GetWorkEditResponse, GetWorkHistoryResponse, GetWorkRedirectsResponse, -    GetWorkReleasesResponse, GetWorkResponse, GetWorkRevisionResponse, LookupContainerResponse, LookupCreatorResponse, LookupFileResponse, LookupReleaseResponse, UpdateContainerResponse, -    UpdateCreatorResponse, UpdateFileResponse, UpdateFilesetResponse, UpdateReleaseResponse, UpdateWebcaptureResponse, UpdateWorkResponse, +    AcceptEditgroupResponse, Api, AuthOidcResponse, CreateContainerBatchResponse, CreateContainerResponse, CreateCreatorBatchResponse, CreateCreatorResponse, CreateEditgroupResponse, +    CreateFileBatchResponse, CreateFileResponse, CreateFilesetBatchResponse, CreateFilesetResponse, CreateReleaseBatchResponse, CreateReleaseResponse, CreateWebcaptureBatchResponse, +    CreateWebcaptureResponse, CreateWorkBatchResponse, CreateWorkResponse, DeleteContainerEditResponse, DeleteContainerResponse, DeleteCreatorEditResponse, DeleteCreatorResponse, +    DeleteFileEditResponse, DeleteFileResponse, DeleteFilesetEditResponse, DeleteFilesetResponse, DeleteReleaseEditResponse, DeleteReleaseResponse, DeleteWebcaptureEditResponse, +    DeleteWebcaptureResponse, DeleteWorkEditResponse, DeleteWorkResponse, GetChangelogEntryResponse, GetChangelogResponse, GetContainerEditResponse, GetContainerHistoryResponse, +    GetContainerRedirectsResponse, GetContainerResponse, GetContainerRevisionResponse, GetCreatorEditResponse, GetCreatorHistoryResponse, GetCreatorRedirectsResponse, GetCreatorReleasesResponse, +    GetCreatorResponse, GetCreatorRevisionResponse, GetEditgroupResponse, GetEditorChangelogResponse, GetEditorResponse, GetFileEditResponse, GetFileHistoryResponse, GetFileRedirectsResponse, +    GetFileResponse, GetFileRevisionResponse, GetFilesetEditResponse, GetFilesetHistoryResponse, GetFilesetRedirectsResponse, GetFilesetResponse, GetFilesetRevisionResponse, GetReleaseEditResponse, +    GetReleaseFilesResponse, GetReleaseFilesetsResponse, GetReleaseHistoryResponse, GetReleaseRedirectsResponse, GetReleaseResponse, GetReleaseRevisionResponse, GetReleaseWebcapturesResponse, +    GetWebcaptureEditResponse, GetWebcaptureHistoryResponse, GetWebcaptureRedirectsResponse, GetWebcaptureResponse, GetWebcaptureRevisionResponse, GetWorkEditResponse, GetWorkHistoryResponse, +    GetWorkRedirectsResponse, GetWorkReleasesResponse, GetWorkResponse, GetWorkRevisionResponse, LookupContainerResponse, LookupCreatorResponse, LookupFileResponse, LookupReleaseResponse, +    UpdateContainerResponse, UpdateCreatorResponse, UpdateFileResponse, UpdateFilesetResponse, UpdateReleaseResponse, UpdateWebcaptureResponse, UpdateWorkResponse,  };  header! { (Warning, "Warning") => [String] } @@ -2606,6 +2606,154 @@ where      );      let api_clone = api.clone(); +    router.post( +        "/v0/auth/oidc", +        move |req: &mut Request| { +            let mut context = Context::default(); + +            // Helper function to provide a code block to use `?` in (to be replaced by the `catch` block when it exists). +            fn handle_request<T>(req: &mut Request, api: &T, context: &mut Context) -> Result<Response, Response> +            where +                T: Api, +            { +                context.x_span_id = Some(req.headers.get::<XSpanId>().map(XSpanId::to_string).unwrap_or_else(|| self::uuid::Uuid::new_v4().to_string())); +                context.auth_data = req.extensions.remove::<AuthData>(); +                context.authorization = req.extensions.remove::<Authorization>(); + +                let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + +                // Body parameters (note that non-required body parameters will ignore garbage +                // values, rather than causing a 400 response). Produce warning header and logs for +                // any unused fields. + +                let param_oidc_params = req +                    .get::<bodyparser::Raw>() +                    .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse body parameter oidc_params - not valid UTF-8: {}", e))))?; + +                let mut unused_elements = Vec::new(); + +                let param_oidc_params = if let Some(param_oidc_params_raw) = param_oidc_params { +                    let deserializer = &mut serde_json::Deserializer::from_str(¶m_oidc_params_raw); + +                    let param_oidc_params: Option<models::AuthOidc> = serde_ignored::deserialize(deserializer, |path| { +                        warn!("Ignoring unknown field in body: {}", path); +                        unused_elements.push(path.to_string()); +                    }) +                    .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse body parameter oidc_params - doesn't match schema: {}", e))))?; + +                    param_oidc_params +                } else { +                    None +                }; +                let param_oidc_params = param_oidc_params.ok_or_else(|| Response::with((status::BadRequest, "Missing required body parameter oidc_params".to_string())))?; + +                match api.auth_oidc(param_oidc_params, context).wait() { +                    Ok(rsp) => match rsp { +                        AuthOidcResponse::Found(body) => { +                            let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + +                            let mut response = Response::with((status::Status::from_u16(200), body_string)); +                            response.headers.set(ContentType(mimetypes::responses::AUTH_OIDC_FOUND.clone())); + +                            context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); +                            if !unused_elements.is_empty() { +                                response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); +                            } +                            Ok(response) +                        } +                        AuthOidcResponse::Created(body) => { +                            let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + +                            let mut response = Response::with((status::Status::from_u16(201), body_string)); +                            response.headers.set(ContentType(mimetypes::responses::AUTH_OIDC_CREATED.clone())); + +                            context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); +                            if !unused_elements.is_empty() { +                                response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); +                            } +                            Ok(response) +                        } +                        AuthOidcResponse::BadRequest(body) => { +                            let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + +                            let mut response = Response::with((status::Status::from_u16(400), body_string)); +                            response.headers.set(ContentType(mimetypes::responses::AUTH_OIDC_BAD_REQUEST.clone())); + +                            context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); +                            if !unused_elements.is_empty() { +                                response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); +                            } +                            Ok(response) +                        } +                        AuthOidcResponse::NotAuthorized { body, www_authenticate } => { +                            let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + +                            let mut response = Response::with((status::Status::from_u16(401), body_string)); +                            header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } +                            response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + +                            response.headers.set(ContentType(mimetypes::responses::AUTH_OIDC_NOT_AUTHORIZED.clone())); + +                            context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); +                            if !unused_elements.is_empty() { +                                response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); +                            } +                            Ok(response) +                        } +                        AuthOidcResponse::Forbidden(body) => { +                            let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + +                            let mut response = Response::with((status::Status::from_u16(403), body_string)); +                            response.headers.set(ContentType(mimetypes::responses::AUTH_OIDC_FORBIDDEN.clone())); + +                            context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); +                            if !unused_elements.is_empty() { +                                response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); +                            } +                            Ok(response) +                        } +                        AuthOidcResponse::Conflict(body) => { +                            let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + +                            let mut response = Response::with((status::Status::from_u16(409), body_string)); +                            response.headers.set(ContentType(mimetypes::responses::AUTH_OIDC_CONFLICT.clone())); + +                            context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); +                            if !unused_elements.is_empty() { +                                response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); +                            } +                            Ok(response) +                        } +                        AuthOidcResponse::GenericError(body) => { +                            let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + +                            let mut response = Response::with((status::Status::from_u16(500), body_string)); +                            response.headers.set(ContentType(mimetypes::responses::AUTH_OIDC_GENERIC_ERROR.clone())); + +                            context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); +                            if !unused_elements.is_empty() { +                                response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); +                            } +                            Ok(response) +                        } +                    }, +                    Err(_) => { +                        // Application code returned an error. This should not happen, as the implementation should +                        // return a valid response. +                        Err(Response::with((status::InternalServerError, "An internal error occurred".to_string()))) +                    } +                } +            } + +            handle_request(req, &api_clone, &mut context).or_else(|mut response| { +                context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); +                Ok(response) +            }) +        }, +        "AuthOidc", +    ); + +    let api_clone = api.clone();      router.get(          "/v0/editor/:editor_id",          move |req: &mut Request| {  | 
