From 2842422bb04d176b7f41888e6eed10cd4b81bbac Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Tue, 18 Sep 2018 11:12:47 -0700 Subject: first attempt at auth in API spec --- fatcat-openapi2.yml | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) (limited to 'fatcat-openapi2.yml') diff --git a/fatcat-openapi2.yml b/fatcat-openapi2.yml index 0f52a8b6..713cb116 100644 --- a/fatcat-openapi2.yml +++ b/fatcat-openapi2.yml @@ -13,6 +13,12 @@ consumes: produces: - application/json +securityDefinitions: + Bearer: + type: apiKey + name: Authorization + in: header + tags: # TAGLINE - name: containers # TAGLINE descriptions: "Container entities: such as journals, conferences, book series" # TAGLINE @@ -548,6 +554,13 @@ x-entity-responses: &ENTITYRESPONSES description: Bad Request schema: $ref: "#/definitions/error_response" + 401: + description: Not Authorized # "Authentication information is missing or invalid" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: string 404: description: Not Found schema: @@ -573,6 +586,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 201: description: Created Entity @@ -602,6 +617,8 @@ paths: type: array items: $ref: "#/definitions/container_entity" + security: + - Bearer: [] responses: 201: description: Created Entities @@ -651,6 +668,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 200: description: Updated Entity @@ -666,6 +685,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 200: description: Deleted Entity @@ -816,6 +837,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 201: description: Created Entity @@ -845,6 +868,8 @@ paths: type: array items: $ref: "#/definitions/creator_entity" + security: + - Bearer: [] responses: 201: description: Created Entities @@ -894,6 +919,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 200: description: Updated Entity @@ -909,6 +936,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 200: description: Deleted Entity @@ -1082,6 +1111,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 201: description: Created Entity @@ -1111,6 +1142,8 @@ paths: type: array items: $ref: "#/definitions/file_entity" + security: + - Bearer: [] responses: 201: description: Created Entities @@ -1160,6 +1193,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 200: description: Updated Entity @@ -1175,6 +1210,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 200: description: Deleted Entity -- cgit v1.2.3 From 0ac74e169ca5f0b6897375edb38d9d1fe63b7166 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Mon, 31 Dec 2018 14:56:55 -0800 Subject: api spec: more auth responses --- fatcat-openapi2.yml | 52 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 47 insertions(+), 5 deletions(-) (limited to 'fatcat-openapi2.yml') diff --git a/fatcat-openapi2.yml b/fatcat-openapi2.yml index 713cb116..98b9e4b0 100644 --- a/fatcat-openapi2.yml +++ b/fatcat-openapi2.yml @@ -549,11 +549,7 @@ definitions: role: type: string -x-entity-responses: &ENTITYRESPONSES - 400: - description: Bad Request - schema: - $ref: "#/definitions/error_response" +x-auth-responses: &AUTHRESPONSES 401: description: Not Authorized # "Authentication information is missing or invalid" schema: @@ -561,6 +557,15 @@ x-entity-responses: &ENTITYRESPONSES headers: WWW_Authenticate: type: string + 403: + description: Forbidden + schema: + $ref: "#/definitions/error_response" +x-entity-responses: &ENTITYRESPONSES + 400: + description: Bad Request + schema: + $ref: "#/definitions/error_response" 404: description: Not Found schema: @@ -594,6 +599,7 @@ paths: schema: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /container/batch: post: operationId: "create_container_batch" @@ -627,6 +633,7 @@ paths: items: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /container/{ident}: parameters: - name: ident @@ -676,6 +683,7 @@ paths: schema: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES delete: operationId: "delete_container" tags: # TAGLINE @@ -693,6 +701,7 @@ paths: schema: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /container/rev/{rev_id}: parameters: - name: rev_id @@ -822,6 +831,7 @@ paths: schema: $ref: "#/definitions/success" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /creator: post: operationId: "create_creator" @@ -845,6 +855,7 @@ paths: schema: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /creator/batch: post: operationId: "create_creator_batch" @@ -878,6 +889,7 @@ paths: items: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /creator/{ident}: parameters: - name: ident @@ -927,6 +939,7 @@ paths: schema: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES delete: operationId: "delete_creator" tags: # TAGLINE @@ -944,6 +957,7 @@ paths: schema: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /creator/rev/{rev_id}: parameters: - name: rev_id @@ -1096,6 +1110,7 @@ paths: schema: $ref: "#/definitions/success" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /file: post: operationId: "create_file" @@ -1119,6 +1134,7 @@ paths: schema: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /file/batch: post: operationId: "create_file_batch" @@ -1152,6 +1168,7 @@ paths: items: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /file/{ident}: parameters: - name: ident @@ -1201,6 +1218,7 @@ paths: schema: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES delete: operationId: "delete_file" tags: # TAGLINE @@ -1218,6 +1236,7 @@ paths: schema: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /file/rev/{rev_id}: parameters: - name: rev_id @@ -1352,6 +1371,7 @@ paths: schema: $ref: "#/definitions/success" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /fileset: post: operationId: "create_fileset" @@ -1373,6 +1393,7 @@ paths: schema: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /fileset/batch: post: operationId: "create_fileset_batch" @@ -1404,6 +1425,7 @@ paths: items: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /fileset/{ident}: parameters: - name: ident @@ -1451,6 +1473,7 @@ paths: schema: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES delete: operationId: "delete_fileset" tags: # TAGLINE @@ -1466,6 +1489,7 @@ paths: schema: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /fileset/rev/{rev_id}: parameters: - name: rev_id @@ -1566,6 +1590,7 @@ paths: schema: $ref: "#/definitions/success" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /webcapture: post: operationId: "create_webcapture" @@ -1587,6 +1612,7 @@ paths: schema: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /webcapture/batch: post: operationId: "create_webcapture_batch" @@ -1618,6 +1644,7 @@ paths: items: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /webcapture/{ident}: parameters: - name: ident @@ -1665,6 +1692,7 @@ paths: schema: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES delete: operationId: "delete_webcapture" tags: # TAGLINE @@ -1680,6 +1708,7 @@ paths: schema: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /webcapture/rev/{rev_id}: parameters: - name: rev_id @@ -1780,6 +1809,7 @@ paths: schema: $ref: "#/definitions/success" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /release: post: operationId: "create_release" @@ -1801,6 +1831,7 @@ paths: schema: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /release/batch: post: operationId: "create_release_batch" @@ -1832,6 +1863,7 @@ paths: items: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /release/{ident}: parameters: - name: ident @@ -1879,6 +1911,7 @@ paths: schema: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES delete: operationId: "delete_release" tags: # TAGLINE @@ -1894,6 +1927,7 @@ paths: schema: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /release/rev/{rev_id}: parameters: - name: rev_id @@ -2109,6 +2143,7 @@ paths: schema: $ref: "#/definitions/success" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /work: post: operationId: "create_work" @@ -2130,6 +2165,7 @@ paths: schema: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /work/batch: post: operationId: "create_work_batch" @@ -2161,6 +2197,7 @@ paths: items: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /work/{ident}: parameters: - name: ident @@ -2208,6 +2245,7 @@ paths: schema: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES delete: operationId: "delete_work" tags: # TAGLINE @@ -2223,6 +2261,7 @@ paths: schema: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /work/rev/{rev_id}: parameters: - name: rev_id @@ -2346,6 +2385,7 @@ paths: schema: $ref: "#/definitions/success" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /editor/{editor_id}: parameters: - name: editor_id @@ -2422,6 +2462,7 @@ paths: description: Generic Error schema: $ref: "#/definitions/error_response" + <<: *AUTHRESPONSES /editgroup/{editgroup_id}: parameters: - name: editgroup_id @@ -2480,6 +2521,7 @@ paths: description: Generic Error schema: $ref: "#/definitions/error_response" + <<: *AUTHRESPONSES /changelog: parameters: - name: limit -- cgit v1.2.3 From 42ffee8c583729287aed7eaa6df4b7b121c1f7f6 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Mon, 31 Dec 2018 18:05:24 -0800 Subject: make editor_id optional when createding editgroup The editor_id can be infered from auth metadata. --- fatcat-openapi2.yml | 2 -- rust/fatcat-api-spec/README.md | 2 +- rust/fatcat-api-spec/api.yaml | 2 -- rust/fatcat-api-spec/api/swagger.yaml | 2 -- rust/fatcat-api-spec/src/models.rs | 7 ++++--- rust/src/api_server.rs | 6 +++--- rust/src/api_wrappers.rs | 13 +++++++++++++ rust/src/bin/fatcatd.rs | 7 ++++++- rust/src/database_models.rs | 2 +- rust/src/lib.rs | 3 +-- rust/tests/test_api_server_http.rs | 33 +++++++++++++++++++++++++++++++++ rust/tests/test_old_python_tests.rs | 7 +++++-- 12 files changed, 67 insertions(+), 19 deletions(-) (limited to 'fatcat-openapi2.yml') diff --git a/fatcat-openapi2.yml b/fatcat-openapi2.yml index 98b9e4b0..80db5074 100644 --- a/fatcat-openapi2.yml +++ b/fatcat-openapi2.yml @@ -445,8 +445,6 @@ definitions: example: "zerocool93" editgroup: type: object - required: - - editor_id properties: editgroup_id: <<: *FATCATIDENT diff --git a/rust/fatcat-api-spec/README.md b/rust/fatcat-api-spec/README.md index bed47c45..7e946b16 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: 2018-12-31T22:21:53.785Z +- Build date: 2019-01-01T01:45:02.795Z This autogenerated project defines an API crate `fatcat` which contains: * An `Api` trait defining the API in Rust. diff --git a/rust/fatcat-api-spec/api.yaml b/rust/fatcat-api-spec/api.yaml index 98b9e4b0..80db5074 100644 --- a/rust/fatcat-api-spec/api.yaml +++ b/rust/fatcat-api-spec/api.yaml @@ -445,8 +445,6 @@ definitions: example: "zerocool93" editgroup: type: object - required: - - editor_id properties: editgroup_id: <<: *FATCATIDENT diff --git a/rust/fatcat-api-spec/api/swagger.yaml b/rust/fatcat-api-spec/api/swagger.yaml index 670d3551..12bfe192 100644 --- a/rust/fatcat-api-spec/api/swagger.yaml +++ b/rust/fatcat-api-spec/api/swagger.yaml @@ -7598,8 +7598,6 @@ definitions: upperCaseName: "EDITOR" editgroup: type: "object" - required: - - "editor_id" properties: editgroup_id: type: "string" diff --git a/rust/fatcat-api-spec/src/models.rs b/rust/fatcat-api-spec/src/models.rs index 01b4c28e..4d7575b6 100644 --- a/rust/fatcat-api-spec/src/models.rs +++ b/rust/fatcat-api-spec/src/models.rs @@ -190,7 +190,8 @@ pub struct Editgroup { /// base32-encoded unique identifier #[serde(rename = "editor_id")] - pub editor_id: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub editor_id: Option, #[serde(rename = "description")] #[serde(skip_serializing_if = "Option::is_none")] @@ -206,10 +207,10 @@ pub struct Editgroup { } impl Editgroup { - pub fn new(editor_id: String) -> Editgroup { + pub fn new() -> Editgroup { Editgroup { editgroup_id: None, - editor_id: editor_id, + editor_id: None, description: None, extra: None, edits: None, diff --git a/rust/src/api_server.rs b/rust/src/api_server.rs index 853f7bc2..be9f1883 100644 --- a/rust/src/api_server.rs +++ b/rust/src/api_server.rs @@ -384,7 +384,7 @@ impl Server { ) -> Result { let row: EditgroupRow = insert_into(editgroup::table) .values(( - editgroup::editor_id.eq(FatCatId::from_str(&entity.editor_id)?.to_uuid()), + editgroup::editor_id.eq(FatCatId::from_str(&entity.editor_id.unwrap())?.to_uuid()), editgroup::description.eq(entity.description), editgroup::extra_json.eq(entity.extra), )) @@ -392,7 +392,7 @@ impl Server { Ok(Editgroup { editgroup_id: Some(uuid2fcid(&row.id)), - editor_id: uuid2fcid(&row.editor_id), + editor_id: Some(uuid2fcid(&row.editor_id)), description: row.description, edits: None, extra: row.extra_json, @@ -467,7 +467,7 @@ impl Server { let eg = Editgroup { editgroup_id: Some(uuid2fcid(&row.id)), - editor_id: uuid2fcid(&row.editor_id), + editor_id: Some(uuid2fcid(&row.editor_id)), description: row.description, edits: Some(edits), extra: row.extra_json, diff --git a/rust/src/api_wrappers.rs b/rust/src/api_wrappers.rs index ae070e02..3dec1c26 100644 --- a/rust/src/api_wrappers.rs +++ b/rust/src/api_wrappers.rs @@ -988,6 +988,19 @@ impl Api for Server { .auth_confectionary .require_auth(&conn, &context.auth_data)?; auth_context.require_role(FatcatRole::Editor)?; + let mut entity = entity.clone(); + match entity.editor_id.clone() { + Some(editor_id) => { + if !auth_context.has_role(FatcatRole::Admin) { + if editor_id != auth_context.editor_id.to_string() { + bail!("not authorized to create editgroups in others' names"); + } + } + }, + None => { + entity.editor_id = Some(auth_context.editor_id.to_string()); + } + }; self.create_editgroup_handler(entity, &conn) }) { Ok(eg) => CreateEditgroupResponse::SuccessfullyCreated(eg), diff --git a/rust/src/bin/fatcatd.rs b/rust/src/bin/fatcatd.rs index 04f88948..682f5038 100644 --- a/rust/src/bin/fatcatd.rs +++ b/rust/src/bin/fatcatd.rs @@ -45,7 +45,12 @@ fn main() { ); info!( logger, - "all auth keys: {:?}", server.auth_confectionary.root_keys.keys().collect::>(), + "all auth keys: {:?}", + server + .auth_confectionary + .root_keys + .keys() + .collect::>(), ); let mut router = fatcat_api_spec::router(server); diff --git a/rust/src/database_models.rs b/rust/src/database_models.rs index f6cca3e1..7a65f901 100644 --- a/rust/src/database_models.rs +++ b/rust/src/database_models.rs @@ -564,7 +564,7 @@ impl EditgroupRow { pub fn into_model_partial(self) -> Editgroup { Editgroup { editgroup_id: Some(uuid2fcid(&self.id)), - editor_id: uuid2fcid(&self.editor_id), + editor_id: Some(uuid2fcid(&self.editor_id)), description: self.description, extra: self.extra_json, edits: None, diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 7d00641a..b3e6c813 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -134,9 +134,8 @@ pub fn env_confectionary() -> Result { } info!("Loading alt auth key: {}", pair[0]); confectionary.add_keypair(pair[0].to_string(), pair[1].to_string())?; - } - }, + } Err(_) => (), } Ok(confectionary) diff --git a/rust/tests/test_api_server_http.rs b/rust/tests/test_api_server_http.rs index 2160a0a0..d975fe6e 100644 --- a/rust/tests/test_api_server_http.rs +++ b/rust/tests/test_api_server_http.rs @@ -1545,3 +1545,36 @@ fn test_release_types() { Some("release_type"), ); } + +#[test] +fn test_create_editgroup() { + let (headers, router, _conn) = setup_http(); + + // We're authenticated, so don't need to supply editor_id + check_http_response( + request::post( + &format!( + "http://localhost:9411/v0/editgroup", + ), + headers.clone(), + "{}", + &router, + ), + status::Created, + None, + ); + + // But can if we want to + check_http_response( + request::post( + &format!( + "http://localhost:9411/v0/editgroup", + ), + headers.clone(), + r#"{"editor_id": "aaaaaaaaaaaabkvkaaaaaaaaae"}"#, + &router, + ), + status::Created, + None, + ); +} diff --git a/rust/tests/test_old_python_tests.rs b/rust/tests/test_old_python_tests.rs index 1f91c7db..afeff55e 100644 --- a/rust/tests/test_old_python_tests.rs +++ b/rust/tests/test_old_python_tests.rs @@ -22,7 +22,8 @@ fn test_api_rich_create() { let admin_id = "aaaaaaaaaaaabkvkaaaaaaaaae".to_string(); - let mut new_eg = Editgroup::new(admin_id); + let mut new_eg = Editgroup::new(); + new_eg.editor_id = Some(admin_id); new_eg.description = Some("a unit test edit".to_string()); let resp = client.create_editgroup(new_eg).wait().unwrap(); let editgroup_id = match resp { @@ -196,8 +197,10 @@ fn test_merge_works() { let admin_id = "aaaaaaaaaaaabkvkaaaaaaaaae".to_string(); + let mut eg = Editgroup::new(); + eg.editor_id = Some(admin_id); let resp = client - .create_editgroup(Editgroup::new(admin_id)) + .create_editgroup(eg) .wait() .unwrap(); let editgroup_id = match resp { -- cgit v1.2.3 From 7b7e271decb2fbd5858aaae03616aa0da57a9429 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Mon, 31 Dec 2018 18:43:22 -0800 Subject: add missing security/auth declarations --- fatcat-openapi2.yml | 50 +++++++++++++++++++++ python/fatcat_client/README.md | 12 +++++- python/fatcat_client/api/default_api.py | 74 ++++++++++++++++---------------- python/fatcat_client/configuration.py | 7 +++ python/fatcat_client/models/editgroup.py | 5 +-- rust/fatcat-api-spec/README.md | 2 +- rust/fatcat-api-spec/api.yaml | 50 +++++++++++++++++++++ rust/fatcat-api-spec/api/swagger.yaml | 50 +++++++++++++++++++++ rust/fatcat-api-spec/src/server.rs | 50 +++++++++++++++++++++ 9 files changed, 258 insertions(+), 42 deletions(-) (limited to 'fatcat-openapi2.yml') diff --git a/fatcat-openapi2.yml b/fatcat-openapi2.yml index 80db5074..b7f7fbb3 100644 --- a/fatcat-openapi2.yml +++ b/fatcat-openapi2.yml @@ -823,6 +823,8 @@ paths: in: path required: true <<: *FATCATUUID + security: + - Bearer: [] responses: 200: description: Deleted Edit @@ -1102,6 +1104,8 @@ paths: in: path required: true <<: *FATCATUUID + security: + - Bearer: [] responses: 200: description: Deleted Edit @@ -1363,6 +1367,8 @@ paths: in: path required: true <<: *FATCATUUID + security: + - Bearer: [] responses: 200: description: Deleted Edit @@ -1385,6 +1391,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 201: description: Created Entity @@ -1415,6 +1423,8 @@ paths: type: array items: $ref: "#/definitions/fileset_entity" + security: + - Bearer: [] responses: 201: description: Created Entities @@ -1465,6 +1475,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 200: description: Updated Entity @@ -1481,6 +1493,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 200: description: Deleted Entity @@ -1582,6 +1596,8 @@ paths: in: path required: true <<: *FATCATUUID + security: + - Bearer: [] responses: 200: description: Deleted Edit @@ -1604,6 +1620,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 201: description: Created Entity @@ -1634,6 +1652,8 @@ paths: type: array items: $ref: "#/definitions/webcapture_entity" + security: + - Bearer: [] responses: 201: description: Created Entities @@ -1684,6 +1704,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 200: description: Updated Entity @@ -1700,6 +1722,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 200: description: Deleted Entity @@ -1801,6 +1825,8 @@ paths: in: path required: true <<: *FATCATUUID + security: + - Bearer: [] responses: 200: description: Deleted Edit @@ -1823,6 +1849,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 201: description: Created Entity @@ -1853,6 +1881,8 @@ paths: type: array items: $ref: "#/definitions/release_entity" + security: + - Bearer: [] responses: 201: description: Created Entities @@ -1903,6 +1933,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 200: description: Updated Entity @@ -1919,6 +1951,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 200: description: Deleted Entity @@ -2135,6 +2169,8 @@ paths: in: path required: true <<: *FATCATUUID + security: + - Bearer: [] responses: 200: description: Deleted Edit @@ -2157,6 +2193,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 201: description: Created Entity @@ -2187,6 +2225,8 @@ paths: type: array items: $ref: "#/definitions/work_entity" + security: + - Bearer: [] responses: 201: description: Created Entities @@ -2237,6 +2277,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 200: description: Updated Entity @@ -2253,6 +2295,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 200: description: Deleted Entity @@ -2377,6 +2421,8 @@ paths: in: path required: true <<: *FATCATUUID + security: + - Bearer: [] responses: 200: description: Deleted Edit @@ -2447,6 +2493,8 @@ paths: required: true schema: $ref: "#/definitions/editgroup" + security: + - Bearer: [] responses: 201: description: Successfully Created @@ -2498,6 +2546,8 @@ paths: operationId: "accept_editgroup" tags: # TAGLINE - edit-lifecycle # TAGLINE + security: + - Bearer: [] responses: 200: description: Merged Successfully diff --git a/python/fatcat_client/README.md b/python/fatcat_client/README.md index 0f170925..069eb1b4 100644 --- a/python/fatcat_client/README.md +++ b/python/fatcat_client/README.md @@ -50,6 +50,11 @@ import time import fatcat_client from fatcat_client.rest import ApiException from pprint import pprint + +# Configure API key authorization: Bearer +fatcat_client.configuration.api_key['Authorization'] = 'YOUR_API_KEY' +# Uncomment below to setup prefix (e.g. Bearer) for API key, if needed +# fatcat_client.configuration.api_key_prefix['Authorization'] = 'Bearer' # create an instance of the API class api_instance = fatcat_client.DefaultApi() editgroup_id = 'editgroup_id_example' # str | base32-encoded unique identifier @@ -184,7 +189,12 @@ Class | Method | HTTP request | Description ## Documentation For Authorization - All endpoints do not require authorization. + +## Bearer + +- **Type**: API key +- **API key parameter name**: Authorization +- **Location**: HTTP header ## Author diff --git a/python/fatcat_client/api/default_api.py b/python/fatcat_client/api/default_api.py index 9f7edf07..5cb5dc64 100644 --- a/python/fatcat_client/api/default_api.py +++ b/python/fatcat_client/api/default_api.py @@ -120,7 +120,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/editgroup/{editgroup_id}/accept', 'POST', @@ -221,7 +221,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/container', 'POST', @@ -326,7 +326,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/container/batch', 'POST', @@ -427,7 +427,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/creator', 'POST', @@ -532,7 +532,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/creator/batch', 'POST', @@ -629,7 +629,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/editgroup', 'POST', @@ -730,7 +730,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/file', 'POST', @@ -835,7 +835,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/file/batch', 'POST', @@ -936,7 +936,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/fileset', 'POST', @@ -1041,7 +1041,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/fileset/batch', 'POST', @@ -1142,7 +1142,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/release', 'POST', @@ -1247,7 +1247,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/release/batch', 'POST', @@ -1348,7 +1348,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/webcapture', 'POST', @@ -1453,7 +1453,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/webcapture/batch', 'POST', @@ -1554,7 +1554,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/work', 'POST', @@ -1659,7 +1659,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/work/batch', 'POST', @@ -1760,7 +1760,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/container/{ident}', 'DELETE', @@ -1865,7 +1865,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/container/edit/{edit_id}', 'DELETE', @@ -1966,7 +1966,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/creator/{ident}', 'DELETE', @@ -2071,7 +2071,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/creator/edit/{edit_id}', 'DELETE', @@ -2172,7 +2172,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/file/{ident}', 'DELETE', @@ -2277,7 +2277,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/file/edit/{edit_id}', 'DELETE', @@ -2378,7 +2378,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/fileset/{ident}', 'DELETE', @@ -2483,7 +2483,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/fileset/edit/{edit_id}', 'DELETE', @@ -2584,7 +2584,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/release/{ident}', 'DELETE', @@ -2689,7 +2689,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/release/edit/{edit_id}', 'DELETE', @@ -2790,7 +2790,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/webcapture/{ident}', 'DELETE', @@ -2895,7 +2895,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/webcapture/edit/{edit_id}', 'DELETE', @@ -2996,7 +2996,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/work/{ident}', 'DELETE', @@ -3101,7 +3101,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/work/edit/{edit_id}', 'DELETE', @@ -8331,7 +8331,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/container/{ident}', 'PUT', @@ -8440,7 +8440,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/creator/{ident}', 'PUT', @@ -8549,7 +8549,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/file/{ident}', 'PUT', @@ -8658,7 +8658,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/fileset/{ident}', 'PUT', @@ -8767,7 +8767,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/release/{ident}', 'PUT', @@ -8876,7 +8876,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/webcapture/{ident}', 'PUT', @@ -8985,7 +8985,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/work/{ident}', 'PUT', diff --git a/python/fatcat_client/configuration.py b/python/fatcat_client/configuration.py index 1dc47841..69b54edb 100644 --- a/python/fatcat_client/configuration.py +++ b/python/fatcat_client/configuration.py @@ -224,6 +224,13 @@ class Configuration(six.with_metaclass(TypeWithDefault, object)): :return: The Auth Settings information dict. """ return { + 'Bearer': + { + 'type': 'api_key', + 'in': 'header', + 'key': 'Authorization', + 'value': self.get_api_key_with_prefix('Authorization') + }, } diff --git a/python/fatcat_client/models/editgroup.py b/python/fatcat_client/models/editgroup.py index 5b1573ed..4c877685 100644 --- a/python/fatcat_client/models/editgroup.py +++ b/python/fatcat_client/models/editgroup.py @@ -60,7 +60,8 @@ class Editgroup(object): if editgroup_id is not None: self.editgroup_id = editgroup_id - self.editor_id = editor_id + if editor_id is not None: + self.editor_id = editor_id if description is not None: self.description = description if extra is not None: @@ -117,8 +118,6 @@ class Editgroup(object): :param editor_id: The editor_id of this Editgroup. # noqa: E501 :type: str """ - if editor_id is None: - raise ValueError("Invalid value for `editor_id`, must not be `None`") # noqa: E501 if editor_id is not None and len(editor_id) > 26: raise ValueError("Invalid value for `editor_id`, length must be less than or equal to `26`") # noqa: E501 if editor_id is not None and len(editor_id) < 26: diff --git a/rust/fatcat-api-spec/README.md b/rust/fatcat-api-spec/README.md index 7e946b16..4f7f811f 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-01T01:45:02.795Z +- Build date: 2019-01-01T02:26:01.855Z This autogenerated project defines an API crate `fatcat` which contains: * An `Api` trait defining the API in Rust. diff --git a/rust/fatcat-api-spec/api.yaml b/rust/fatcat-api-spec/api.yaml index 80db5074..b7f7fbb3 100644 --- a/rust/fatcat-api-spec/api.yaml +++ b/rust/fatcat-api-spec/api.yaml @@ -823,6 +823,8 @@ paths: in: path required: true <<: *FATCATUUID + security: + - Bearer: [] responses: 200: description: Deleted Edit @@ -1102,6 +1104,8 @@ paths: in: path required: true <<: *FATCATUUID + security: + - Bearer: [] responses: 200: description: Deleted Edit @@ -1363,6 +1367,8 @@ paths: in: path required: true <<: *FATCATUUID + security: + - Bearer: [] responses: 200: description: Deleted Edit @@ -1385,6 +1391,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 201: description: Created Entity @@ -1415,6 +1423,8 @@ paths: type: array items: $ref: "#/definitions/fileset_entity" + security: + - Bearer: [] responses: 201: description: Created Entities @@ -1465,6 +1475,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 200: description: Updated Entity @@ -1481,6 +1493,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 200: description: Deleted Entity @@ -1582,6 +1596,8 @@ paths: in: path required: true <<: *FATCATUUID + security: + - Bearer: [] responses: 200: description: Deleted Edit @@ -1604,6 +1620,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 201: description: Created Entity @@ -1634,6 +1652,8 @@ paths: type: array items: $ref: "#/definitions/webcapture_entity" + security: + - Bearer: [] responses: 201: description: Created Entities @@ -1684,6 +1704,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 200: description: Updated Entity @@ -1700,6 +1722,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 200: description: Deleted Entity @@ -1801,6 +1825,8 @@ paths: in: path required: true <<: *FATCATUUID + security: + - Bearer: [] responses: 200: description: Deleted Edit @@ -1823,6 +1849,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 201: description: Created Entity @@ -1853,6 +1881,8 @@ paths: type: array items: $ref: "#/definitions/release_entity" + security: + - Bearer: [] responses: 201: description: Created Entities @@ -1903,6 +1933,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 200: description: Updated Entity @@ -1919,6 +1951,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 200: description: Deleted Entity @@ -2135,6 +2169,8 @@ paths: in: path required: true <<: *FATCATUUID + security: + - Bearer: [] responses: 200: description: Deleted Edit @@ -2157,6 +2193,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 201: description: Created Entity @@ -2187,6 +2225,8 @@ paths: type: array items: $ref: "#/definitions/work_entity" + security: + - Bearer: [] responses: 201: description: Created Entities @@ -2237,6 +2277,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 200: description: Updated Entity @@ -2253,6 +2295,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 200: description: Deleted Entity @@ -2377,6 +2421,8 @@ paths: in: path required: true <<: *FATCATUUID + security: + - Bearer: [] responses: 200: description: Deleted Edit @@ -2447,6 +2493,8 @@ paths: required: true schema: $ref: "#/definitions/editgroup" + security: + - Bearer: [] responses: 201: description: Successfully Created @@ -2498,6 +2546,8 @@ paths: operationId: "accept_editgroup" tags: # TAGLINE - edit-lifecycle # TAGLINE + security: + - Bearer: [] responses: 200: description: Merged Successfully diff --git a/rust/fatcat-api-spec/api/swagger.yaml b/rust/fatcat-api-spec/api/swagger.yaml index 12bfe192..89017877 100644 --- a/rust/fatcat-api-spec/api/swagger.yaml +++ b/rust/fatcat-api-spec/api/swagger.yaml @@ -860,6 +860,8 @@ paths: uppercase_operation_id: "DELETE_CONTAINER_EDIT" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "delete_container_edit" uppercase_operation_id: "DELETE_CONTAINER_EDIT" path: "/container/edit/:edit_id" @@ -1768,6 +1770,8 @@ paths: uppercase_operation_id: "DELETE_CREATOR_EDIT" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "delete_creator_edit" uppercase_operation_id: "DELETE_CREATOR_EDIT" path: "/creator/edit/:edit_id" @@ -2625,6 +2629,8 @@ paths: uppercase_operation_id: "DELETE_FILE_EDIT" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "delete_file_edit" uppercase_operation_id: "DELETE_FILE_EDIT" path: "/file/edit/:edit_id" @@ -2712,6 +2718,8 @@ paths: uppercase_operation_id: "CREATE_FILESET" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "create_fileset" uppercase_operation_id: "CREATE_FILESET" path: "/fileset" @@ -2812,6 +2820,8 @@ paths: uppercase_operation_id: "CREATE_FILESET_BATCH" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "create_fileset_batch" uppercase_operation_id: "CREATE_FILESET_BATCH" path: "/fileset/batch" @@ -2974,6 +2984,8 @@ paths: uppercase_operation_id: "UPDATE_FILESET" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "update_fileset" uppercase_operation_id: "UPDATE_FILESET" path: "/fileset/:ident" @@ -3055,6 +3067,8 @@ paths: uppercase_operation_id: "DELETE_FILESET" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "delete_fileset" uppercase_operation_id: "DELETE_FILESET" path: "/fileset/:ident" @@ -3384,6 +3398,8 @@ paths: uppercase_operation_id: "DELETE_FILESET_EDIT" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "delete_fileset_edit" uppercase_operation_id: "DELETE_FILESET_EDIT" path: "/fileset/edit/:edit_id" @@ -3471,6 +3487,8 @@ paths: uppercase_operation_id: "CREATE_WEBCAPTURE" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "create_webcapture" uppercase_operation_id: "CREATE_WEBCAPTURE" path: "/webcapture" @@ -3571,6 +3589,8 @@ paths: uppercase_operation_id: "CREATE_WEBCAPTURE_BATCH" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "create_webcapture_batch" uppercase_operation_id: "CREATE_WEBCAPTURE_BATCH" path: "/webcapture/batch" @@ -3733,6 +3753,8 @@ paths: uppercase_operation_id: "UPDATE_WEBCAPTURE" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "update_webcapture" uppercase_operation_id: "UPDATE_WEBCAPTURE" path: "/webcapture/:ident" @@ -3814,6 +3836,8 @@ paths: uppercase_operation_id: "DELETE_WEBCAPTURE" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "delete_webcapture" uppercase_operation_id: "DELETE_WEBCAPTURE" path: "/webcapture/:ident" @@ -4143,6 +4167,8 @@ paths: uppercase_operation_id: "DELETE_WEBCAPTURE_EDIT" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "delete_webcapture_edit" uppercase_operation_id: "DELETE_WEBCAPTURE_EDIT" path: "/webcapture/edit/:edit_id" @@ -4230,6 +4256,8 @@ paths: uppercase_operation_id: "CREATE_RELEASE" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "create_release" uppercase_operation_id: "CREATE_RELEASE" path: "/release" @@ -4330,6 +4358,8 @@ paths: uppercase_operation_id: "CREATE_RELEASE_BATCH" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "create_release_batch" uppercase_operation_id: "CREATE_RELEASE_BATCH" path: "/release/batch" @@ -4492,6 +4522,8 @@ paths: uppercase_operation_id: "UPDATE_RELEASE" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "update_release" uppercase_operation_id: "UPDATE_RELEASE" path: "/release/:ident" @@ -4573,6 +4605,8 @@ paths: uppercase_operation_id: "DELETE_RELEASE" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "delete_release" uppercase_operation_id: "DELETE_RELEASE" path: "/release/:ident" @@ -5193,6 +5227,8 @@ paths: uppercase_operation_id: "DELETE_RELEASE_EDIT" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "delete_release_edit" uppercase_operation_id: "DELETE_RELEASE_EDIT" path: "/release/edit/:edit_id" @@ -5280,6 +5316,8 @@ paths: uppercase_operation_id: "CREATE_WORK" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "create_work" uppercase_operation_id: "CREATE_WORK" path: "/work" @@ -5380,6 +5418,8 @@ paths: uppercase_operation_id: "CREATE_WORK_BATCH" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "create_work_batch" uppercase_operation_id: "CREATE_WORK_BATCH" path: "/work/batch" @@ -5542,6 +5582,8 @@ paths: uppercase_operation_id: "UPDATE_WORK" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "update_work" uppercase_operation_id: "UPDATE_WORK" path: "/work/:ident" @@ -5623,6 +5665,8 @@ paths: uppercase_operation_id: "DELETE_WORK" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "delete_work" uppercase_operation_id: "DELETE_WORK" path: "/work/:ident" @@ -6016,6 +6060,8 @@ paths: uppercase_operation_id: "DELETE_WORK_EDIT" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "delete_work_edit" uppercase_operation_id: "DELETE_WORK_EDIT" path: "/work/edit/:edit_id" @@ -6194,6 +6240,8 @@ paths: uppercase_operation_id: "CREATE_EDITGROUP" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "create_editgroup" uppercase_operation_id: "CREATE_EDITGROUP" path: "/editgroup" @@ -6341,6 +6389,8 @@ paths: uppercase_operation_id: "ACCEPT_EDITGROUP" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "accept_editgroup" uppercase_operation_id: "ACCEPT_EDITGROUP" path: "/editgroup/:editgroup_id/accept" diff --git a/rust/fatcat-api-spec/src/server.rs b/rust/fatcat-api-spec/src/server.rs index 268d194c..19e33194 100644 --- a/rust/fatcat-api-spec/src/server.rs +++ b/rust/fatcat-api-spec/src/server.rs @@ -510,6 +510,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Path parameters let param_edit_id = { let param = req @@ -1716,6 +1718,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Path parameters let param_edit_id = { let param = req @@ -2794,6 +2798,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Path parameters let param_editgroup_id = { let param = req @@ -2916,6 +2922,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + 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. @@ -3663,6 +3671,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Path parameters let param_edit_id = { let param = req @@ -4471,6 +4481,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) let query_params = req.get::().unwrap_or_default(); let param_editgroup_id = query_params.get("editgroup_id").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); @@ -4609,6 +4621,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) let query_params = req.get::().unwrap_or_default(); let param_autoaccept = query_params.get("autoaccept").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); @@ -4748,6 +4762,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Path parameters let param_ident = { let param = req @@ -4864,6 +4880,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Path parameters let param_edit_id = { let param = req @@ -5435,6 +5453,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Path parameters let param_ident = { let param = req @@ -5588,6 +5608,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) let query_params = req.get::().unwrap_or_default(); let param_editgroup_id = query_params.get("editgroup_id").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); @@ -5726,6 +5748,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) let query_params = req.get::().unwrap_or_default(); let param_autoaccept = query_params.get("autoaccept").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); @@ -5865,6 +5889,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) let query_params = req.get::().unwrap_or_default(); let param_editgroup_id = query_params.get("editgroup_id").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); @@ -6003,6 +6029,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Path parameters let param_ident = { let param = req @@ -6119,6 +6147,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Path parameters let param_edit_id = { let param = req @@ -7057,6 +7087,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Path parameters let param_ident = { let param = req @@ -7210,6 +7242,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) let query_params = req.get::().unwrap_or_default(); let param_editgroup_id = query_params.get("editgroup_id").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); @@ -7348,6 +7382,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) let query_params = req.get::().unwrap_or_default(); let param_autoaccept = query_params.get("autoaccept").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); @@ -7487,6 +7523,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Path parameters let param_ident = { let param = req @@ -7603,6 +7641,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Path parameters let param_edit_id = { let param = req @@ -8174,6 +8214,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Path parameters let param_ident = { let param = req @@ -8327,6 +8369,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) let query_params = req.get::().unwrap_or_default(); let param_autoaccept = query_params.get("autoaccept").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); @@ -8466,6 +8510,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Path parameters let param_ident = { let param = req @@ -8582,6 +8628,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Path parameters let param_edit_id = { let param = req @@ -9246,6 +9294,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Path parameters let param_ident = { let param = req -- cgit v1.2.3 From 2ff1adeeb85c23df1dd6de3c2dd9ebede2a04954 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Thu, 3 Jan 2019 16:52:42 -0800 Subject: crude /auth/oidc endpoint (and codegen) --- fatcat-openapi2.yml | 65 ++++++++ rust/fatcat-api-spec/README.md | 3 +- rust/fatcat-api-spec/api.yaml | 65 ++++++++ rust/fatcat-api-spec/api/swagger.yaml | 133 ++++++++++++++++ rust/fatcat-api-spec/examples/client.rs | 8 +- rust/fatcat-api-spec/examples/server_lib/server.rs | 30 ++-- rust/fatcat-api-spec/src/client.rs | 118 ++++++++++++-- rust/fatcat-api-spec/src/lib.rs | 26 ++++ rust/fatcat-api-spec/src/mimetypes.rs | 32 ++++ rust/fatcat-api-spec/src/models.rs | 57 ++++++- rust/fatcat-api-spec/src/server.rs | 172 +++++++++++++++++++-- 11 files changed, 670 insertions(+), 39 deletions(-) (limited to 'fatcat-openapi2.yml') 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(""))); // }, + + // 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(""))); + // }, 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(""))); 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 + Send> { + let context = context.clone(); + println!("auth_oidc({:?}) - X-Span-ID: {:?}", oidc_params, context.x_span_id.unwrap_or(String::from("")).clone()); + Box::new(futures::failed("Generic failure".into())) + } + fn get_editor(&self, editor_id: String, context: &Context) -> Box + Send> { let context = context.clone(); println!("get_editor(\"{}\") - X-Span-ID: {:?}", editor_id, context.x_span_id.unwrap_or(String::from("")).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 + 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 { + 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::(&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::(&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::(&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::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .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::(&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::(&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::(&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!("", &buf[..len].to_vec())), + }, + Err(e) => Cow::from(format!("", 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 + 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 @@ -348,6 +348,24 @@ pub enum UpdateCreatorResponse { GenericError(models::ErrorResponse), } +#[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 @@ -1281,6 +1299,8 @@ pub trait Api { fn update_creator(&self, ident: String, entity: models::CreatorEntity, editgroup_id: Option, context: &Context) -> Box + Send>; + fn auth_oidc(&self, oidc_params: models::AuthOidc, context: &Context) -> Box + Send>; + fn get_editor(&self, editor_id: String, context: &Context) -> Box + Send>; fn get_editor_changelog(&self, editor_id: String, context: &Context) -> Box + Send>; @@ -1527,6 +1547,8 @@ pub trait ApiNoContext { fn update_creator(&self, ident: String, entity: models::CreatorEntity, editgroup_id: Option) -> Box + Send>; + fn auth_oidc(&self, oidc_params: models::AuthOidc) -> Box + Send>; + fn get_editor(&self, editor_id: String) -> Box + Send>; fn get_editor_changelog(&self, editor_id: String) -> Box + 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 + Send> { + self.api().auth_oidc(oidc_params, &self.context()) + } + fn get_editor(&self, editor_id: String) -> Box + 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 @@ -9,6 +9,43 @@ use models; 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")] @@ -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, + + #[serde(rename = "is_bot")] + #[serde(skip_serializing_if = "Option::is_none")] + pub is_bot: Option, + + #[serde(rename = "is_active")] + #[serde(skip_serializing_if = "Option::is_none")] + pub is_active: Option, } 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] } @@ -2605,6 +2605,154 @@ where "UpdateCreator", ); + 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(req: &mut Request, api: &T, context: &mut Context) -> Result + where + T: Api, + { + context.x_span_id = Some(req.headers.get::().map(XSpanId::to_string).unwrap_or_else(|| self::uuid::Uuid::new_v4().to_string())); + context.auth_data = req.extensions.remove::(); + context.authorization = req.extensions.remove::(); + + 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::() + .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 = 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", -- cgit v1.2.3 From 9de1a1e01c20fc7df06fa09277d6a4f928b81a67 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Thu, 3 Jan 2019 17:42:47 -0800 Subject: schema for username updates --- fatcat-openapi2.yml | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'fatcat-openapi2.yml') diff --git a/fatcat-openapi2.yml b/fatcat-openapi2.yml index fcef1c46..b9a61fe4 100644 --- a/fatcat-openapi2.yml +++ b/fatcat-openapi2.yml @@ -2484,6 +2484,34 @@ paths: description: Generic Error schema: $ref: "#/definitions/error_response" + put: + operationId: "update_editor" + parameters: + - name: editor + in: body + required: true + schema: + $ref: "#/definitions/editor" + security: + - Bearer: [] + responses: + 200: + description: Updated Editor + schema: + $ref: "#/definitions/editor" + 400: + description: Bad Request + schema: + $ref: "#/definitions/error_response" + 404: + description: Not Found + schema: + $ref: "#/definitions/error_response" + 500: + description: Generic Error + schema: + $ref: "#/definitions/error_response" + <<: *AUTHRESPONSES /editor/{editor_id}/changelog: parameters: - name: editor_id -- cgit v1.2.3 From ab4e1bbf2bb9bb67d6639b90a10970b54dd1aa03 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Thu, 3 Jan 2019 22:08:47 -0800 Subject: allow passing prefered_username in oidc signup/login --- fatcat-openapi2.yml | 3 +++ python/fatcat_client/models/auth_oidc.py | 33 +++++++++++++++++++++++++++++--- rust/fatcat-api-spec/README.md | 2 +- rust/fatcat-api-spec/api.yaml | 3 +++ rust/fatcat-api-spec/api/swagger.yaml | 3 +++ rust/fatcat-api-spec/src/models.rs | 6 +++++- 6 files changed, 45 insertions(+), 5 deletions(-) (limited to 'fatcat-openapi2.yml') diff --git a/fatcat-openapi2.yml b/fatcat-openapi2.yml index b9a61fe4..501a1296 100644 --- a/fatcat-openapi2.yml +++ b/fatcat-openapi2.yml @@ -558,6 +558,7 @@ definitions: - provider - sub - iss + - preferred_username properties: provider: type: string @@ -565,6 +566,8 @@ definitions: type: string iss: type: string + preferred_username: + type: string auth_oidc_result: type: object required: diff --git a/python/fatcat_client/models/auth_oidc.py b/python/fatcat_client/models/auth_oidc.py index 871cc23d..1ee4c429 100644 --- a/python/fatcat_client/models/auth_oidc.py +++ b/python/fatcat_client/models/auth_oidc.py @@ -33,26 +33,30 @@ class AuthOidc(object): swagger_types = { 'provider': 'str', 'sub': 'str', - 'iss': 'str' + 'iss': 'str', + 'preferred_username': 'str' } attribute_map = { 'provider': 'provider', 'sub': 'sub', - 'iss': 'iss' + 'iss': 'iss', + 'preferred_username': 'preferred_username' } - def __init__(self, provider=None, sub=None, iss=None): # noqa: E501 + def __init__(self, provider=None, sub=None, iss=None, preferred_username=None): # noqa: E501 """AuthOidc - a model defined in Swagger""" # noqa: E501 self._provider = None self._sub = None self._iss = None + self._preferred_username = None self.discriminator = None self.provider = provider self.sub = sub self.iss = iss + self.preferred_username = preferred_username @property def provider(self): @@ -123,6 +127,29 @@ class AuthOidc(object): self._iss = iss + @property + def preferred_username(self): + """Gets the preferred_username of this AuthOidc. # noqa: E501 + + + :return: The preferred_username of this AuthOidc. # noqa: E501 + :rtype: str + """ + return self._preferred_username + + @preferred_username.setter + def preferred_username(self, preferred_username): + """Sets the preferred_username of this AuthOidc. + + + :param preferred_username: The preferred_username of this AuthOidc. # noqa: E501 + :type: str + """ + if preferred_username is None: + raise ValueError("Invalid value for `preferred_username`, must not be `None`") # noqa: E501 + + self._preferred_username = preferred_username + def to_dict(self): """Returns the model properties as a dict""" result = {} diff --git a/rust/fatcat-api-spec/README.md b/rust/fatcat-api-spec/README.md index c33509da..f81f641a 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-04T01:38:25.420Z +- Build date: 2019-01-04T05:57:03.701Z This autogenerated project defines an API crate `fatcat` which contains: * An `Api` trait defining the API in Rust. diff --git a/rust/fatcat-api-spec/api.yaml b/rust/fatcat-api-spec/api.yaml index b9a61fe4..501a1296 100644 --- a/rust/fatcat-api-spec/api.yaml +++ b/rust/fatcat-api-spec/api.yaml @@ -558,6 +558,7 @@ definitions: - provider - sub - iss + - preferred_username properties: provider: type: string @@ -565,6 +566,8 @@ definitions: type: string iss: type: string + preferred_username: + type: string auth_oidc_result: type: object required: diff --git a/rust/fatcat-api-spec/api/swagger.yaml b/rust/fatcat-api-spec/api/swagger.yaml index d58785c8..a19d6ae1 100644 --- a/rust/fatcat-api-spec/api/swagger.yaml +++ b/rust/fatcat-api-spec/api/swagger.yaml @@ -8179,6 +8179,7 @@ definitions: type: "object" required: - "iss" + - "preferred_username" - "provider" - "sub" properties: @@ -8188,6 +8189,8 @@ definitions: type: "string" iss: type: "string" + preferred_username: + type: "string" upperCaseName: "AUTH_OIDC" auth_oidc_result: type: "object" diff --git a/rust/fatcat-api-spec/src/models.rs b/rust/fatcat-api-spec/src/models.rs index 8c17cf66..536bdd24 100644 --- a/rust/fatcat-api-spec/src/models.rs +++ b/rust/fatcat-api-spec/src/models.rs @@ -19,14 +19,18 @@ pub struct AuthOidc { #[serde(rename = "iss")] pub iss: String, + + #[serde(rename = "preferred_username")] + pub preferred_username: String, } impl AuthOidc { - pub fn new(provider: String, sub: String, iss: String) -> AuthOidc { + pub fn new(provider: String, sub: String, iss: String, preferred_username: String) -> AuthOidc { AuthOidc { provider: provider, sub: sub, iss: iss, + preferred_username: preferred_username, } } } -- cgit v1.2.3 From 35f3f55aac364373ba16191abdb3c0c585249245 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Mon, 7 Jan 2019 18:08:09 -0800 Subject: add auth/check endpoint --- fatcat-openapi2.yml | 26 +++++ rust/HACKING.md | 9 ++ rust/fatcat-api-spec/README.md | 3 +- rust/fatcat-api-spec/api.yaml | 26 +++++ rust/fatcat-api-spec/api/swagger.yaml | 66 ++++++++++++ rust/fatcat-api-spec/examples/client.rs | 9 +- rust/fatcat-api-spec/examples/server_lib/server.rs | 8 +- rust/fatcat-api-spec/src/client.rs | 103 +++++++++++++++--- rust/fatcat-api-spec/src/lib.rs | 22 ++++ rust/fatcat-api-spec/src/mimetypes.rs | 20 ++++ rust/fatcat-api-spec/src/server.rs | 118 ++++++++++++++++++--- rust/src/api_wrappers.rs | 96 ++++++++++++++--- rust/src/auth.rs | 21 +++- 13 files changed, 480 insertions(+), 47 deletions(-) (limited to 'fatcat-openapi2.yml') diff --git a/fatcat-openapi2.yml b/fatcat-openapi2.yml index 501a1296..625a0143 100644 --- a/fatcat-openapi2.yml +++ b/fatcat-openapi2.yml @@ -2711,4 +2711,30 @@ paths: schema: $ref: "#/definitions/error_response" <<: *AUTHRESPONSES + /auth/check: + get: + operationId: "auth_check" + tags: # TAGLINE + security: + # required admin privs + - Bearer: [] + parameters: + - name: role + in: query + required: false + type: string + responses: + 200: + description: Success + schema: + $ref: "#/definitions/success" + 400: + description: Bad Request + schema: + $ref: "#/definitions/error_response" + 500: + description: Generic Error + schema: + $ref: "#/definitions/error_response" + <<: *AUTHRESPONSES diff --git a/rust/HACKING.md b/rust/HACKING.md index 9d161b87..b3a551fa 100644 --- a/rust/HACKING.md +++ b/rust/HACKING.md @@ -54,6 +54,15 @@ Debug SQL schema errors (if diesel commands fail): ## Direct API Interaction +First setup an auth token and check that authentication is working + + EDITOR_ID='aaaaaaaaaaaabkvkaaaaaaaaay' + AUTH_TOKEN=`./target/debug/fatcat-auth create-token $EDITOR_ID` + http get :9411/v0/auth/check "Authorization:Bearer $AUTH_TOKEN" + http get :9411/v0/auth/check?role=admin "Authorization:Bearer $AUTH_TOKEN" + +You'll need to add the `$AUTH_TOKEN` bit to all requests below. + Creating entities via API: http --json post localhost:9411/v0/container name=asdf issn=1234-5678 diff --git a/rust/fatcat-api-spec/README.md b/rust/fatcat-api-spec/README.md index f81f641a..f8a6e817 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-04T05:57:03.701Z +- Build date: 2019-01-08T01:49:55.777Z 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 AuthCheck cargo run --example client AuthOidc cargo run --example client GetEditor cargo run --example client GetEditorChangelog diff --git a/rust/fatcat-api-spec/api.yaml b/rust/fatcat-api-spec/api.yaml index 501a1296..625a0143 100644 --- a/rust/fatcat-api-spec/api.yaml +++ b/rust/fatcat-api-spec/api.yaml @@ -2711,4 +2711,30 @@ paths: schema: $ref: "#/definitions/error_response" <<: *AUTHRESPONSES + /auth/check: + get: + operationId: "auth_check" + tags: # TAGLINE + security: + # required admin privs + - Bearer: [] + parameters: + - name: role + in: query + required: false + type: string + responses: + 200: + description: Success + schema: + $ref: "#/definitions/success" + 400: + description: Bad Request + 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 a19d6ae1..9d4767c0 100644 --- a/rust/fatcat-api-spec/api/swagger.yaml +++ b/rust/fatcat-api-spec/api/swagger.yaml @@ -6659,6 +6659,72 @@ paths: HttpMethod: "Post" httpmethod: "post" noClientExample: true + /auth/check: + get: + operationId: "auth_check" + parameters: + - name: "role" + in: "query" + required: false + type: "string" + formatString: "{:?}" + example: "Some(\"role_example\".to_string())" + responses: + 200: + description: "Success" + schema: + $ref: "#/definitions/success" + x-responseId: "Success" + x-uppercaseResponseId: "SUCCESS" + uppercase_operation_id: "AUTH_CHECK" + uppercase_data_type: "SUCCESS" + producesJson: true + 400: + description: "Bad Request" + schema: + $ref: "#/definitions/error_response" + x-responseId: "BadRequest" + x-uppercaseResponseId: "BAD_REQUEST" + uppercase_operation_id: "AUTH_CHECK" + 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_CHECK" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true + 403: + description: "Forbidden" + schema: + $ref: "#/definitions/error_response" + x-responseId: "Forbidden" + x-uppercaseResponseId: "FORBIDDEN" + uppercase_operation_id: "AUTH_CHECK" + 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_CHECK" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true + security: + - Bearer: [] + operation_id: "auth_check" + uppercase_operation_id: "AUTH_CHECK" + path: "/auth/check" + HttpMethod: "Get" + httpmethod: "get" securityDefinitions: Bearer: type: "apiKey" diff --git a/rust/fatcat-api-spec/examples/client.rs b/rust/fatcat-api-spec/examples/client.rs index 4eed8ae4..5a43a33c 100644 --- a/rust/fatcat-api-spec/examples/client.rs +++ b/rust/fatcat-api-spec/examples/client.rs @@ -12,8 +12,8 @@ extern crate uuid; use clap::{App, Arg}; #[allow(unused_imports)] use fatcat::{ - AcceptEditgroupResponse, ApiError, ApiNoContext, AuthOidcResponse, ContextWrapperExt, CreateContainerBatchResponse, CreateContainerResponse, CreateCreatorBatchResponse, CreateCreatorResponse, - CreateEditgroupResponse, CreateFileBatchResponse, CreateFileResponse, CreateFilesetBatchResponse, CreateFilesetResponse, CreateReleaseBatchResponse, CreateReleaseResponse, + AcceptEditgroupResponse, ApiError, ApiNoContext, AuthCheckResponse, 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, DeleteWebcaptureEditResponse, DeleteWebcaptureResponse, DeleteWorkEditResponse, DeleteWorkResponse, GetChangelogEntryResponse, GetChangelogResponse, GetContainerEditResponse, @@ -54,6 +54,7 @@ fn main() { "GetCreatorReleases", "GetCreatorRevision", "LookupCreator", + "AuthCheck", "GetEditor", "GetEditorChangelog", "AcceptEditgroup", @@ -272,6 +273,10 @@ 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(""))); // }, + Some("AuthCheck") => { + let result = client.auth_check(Some("role_example".to_string())).wait(); + println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from(""))); + } // Disabled because there's no example. // Some("AuthOidc") => { diff --git a/rust/fatcat-api-spec/examples/server_lib/server.rs b/rust/fatcat-api-spec/examples/server_lib/server.rs index 5e86a10e..73917351 100644 --- a/rust/fatcat-api-spec/examples/server_lib/server.rs +++ b/rust/fatcat-api-spec/examples/server_lib/server.rs @@ -11,7 +11,7 @@ use swagger; use fatcat::models; use fatcat::{ - AcceptEditgroupResponse, Api, ApiError, AuthOidcResponse, Context, CreateContainerBatchResponse, CreateContainerResponse, CreateCreatorBatchResponse, CreateCreatorResponse, + AcceptEditgroupResponse, Api, ApiError, AuthCheckResponse, 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, @@ -297,6 +297,12 @@ impl Api for Server { Box::new(futures::failed("Generic failure".into())) } + fn auth_check(&self, role: Option, context: &Context) -> Box + Send> { + let context = context.clone(); + println!("auth_check({:?}) - X-Span-ID: {:?}", role, context.x_span_id.unwrap_or(String::from("")).clone()); + Box::new(futures::failed("Generic failure".into())) + } + fn auth_oidc(&self, oidc_params: models::AuthOidc, context: &Context) -> Box + Send> { let context = context.clone(); println!("auth_oidc({:?}) - X-Span-ID: {:?}", oidc_params, context.x_span_id.unwrap_or(String::from("")).clone()); diff --git a/rust/fatcat-api-spec/src/client.rs b/rust/fatcat-api-spec/src/client.rs index 470a5350..7f364eb4 100644 --- a/rust/fatcat-api-spec/src/client.rs +++ b/rust/fatcat-api-spec/src/client.rs @@ -35,18 +35,19 @@ use swagger::{ApiError, Context, XSpanId}; use models; use { - 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, UpdateEditorResponse, UpdateFileResponse, UpdateFilesetResponse, UpdateReleaseResponse, UpdateWebcaptureResponse, UpdateWorkResponse, + AcceptEditgroupResponse, Api, AuthCheckResponse, 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, UpdateEditorResponse, 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 +2031,84 @@ impl Api for Client { Box::new(futures::done(result)) } + fn auth_check(&self, param_role: Option, context: &Context) -> Box + Send> { + // Query parameters + let query_role = param_role.map_or_else(String::new, |query| format!("role={role}&", role = query.to_string())); + + let url = format!("{}/v0/auth/check?{role}", self.base_path, role = utf8_percent_encode(&query_role, QUERY_ENCODE_SET)); + + let hyper_client = (self.hyper_client)(); + let request = hyper_client.request(hyper::method::Method::Get, &url); + let mut custom_headers = hyper::header::Headers::new(); + + 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 { + 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::(&buf)?; + + Ok(AuthCheckResponse::Success(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::(&buf)?; + + Ok(AuthCheckResponse::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::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(AuthCheckResponse::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::(&buf)?; + + Ok(AuthCheckResponse::Forbidden(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::(&buf)?; + + Ok(AuthCheckResponse::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!("", &buf[..len].to_vec())), + }, + Err(e) => Cow::from(format!("", 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 auth_oidc(&self, param_oidc_params: models::AuthOidc, context: &Context) -> Box + Send> { let url = format!("{}/v0/auth/oidc", self.base_path); diff --git a/rust/fatcat-api-spec/src/lib.rs b/rust/fatcat-api-spec/src/lib.rs index 258b635b..17c74384 100644 --- a/rust/fatcat-api-spec/src/lib.rs +++ b/rust/fatcat-api-spec/src/lib.rs @@ -348,6 +348,20 @@ pub enum UpdateCreatorResponse { GenericError(models::ErrorResponse), } +#[derive(Debug, PartialEq)] +pub enum AuthCheckResponse { + /// Success + Success(models::Success), + /// Bad Request + BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, + /// Forbidden + Forbidden(models::ErrorResponse), + /// Generic Error + GenericError(models::ErrorResponse), +} + #[derive(Debug, PartialEq)] pub enum AuthOidcResponse { /// Found @@ -1315,6 +1329,8 @@ pub trait Api { fn update_creator(&self, ident: String, entity: models::CreatorEntity, editgroup_id: Option, context: &Context) -> Box + Send>; + fn auth_check(&self, role: Option, context: &Context) -> Box + Send>; + fn auth_oidc(&self, oidc_params: models::AuthOidc, context: &Context) -> Box + Send>; fn get_editor(&self, editor_id: String, context: &Context) -> Box + Send>; @@ -1565,6 +1581,8 @@ pub trait ApiNoContext { fn update_creator(&self, ident: String, entity: models::CreatorEntity, editgroup_id: Option) -> Box + Send>; + fn auth_check(&self, role: Option) -> Box + Send>; + fn auth_oidc(&self, oidc_params: models::AuthOidc) -> Box + Send>; fn get_editor(&self, editor_id: String) -> Box + Send>; @@ -1852,6 +1870,10 @@ impl<'a, T: Api> ApiNoContext for ContextWrapper<'a, T> { self.api().update_creator(ident, entity, editgroup_id, &self.context()) } + fn auth_check(&self, role: Option) -> Box + Send> { + self.api().auth_check(role, &self.context()) + } + fn auth_oidc(&self, oidc_params: models::AuthOidc) -> Box + Send> { self.api().auth_oidc(oidc_params, &self.context()) } diff --git a/rust/fatcat-api-spec/src/mimetypes.rs b/rust/fatcat-api-spec/src/mimetypes.rs index cfdd357d..83add9e3 100644 --- a/rust/fatcat-api-spec/src/mimetypes.rs +++ b/rust/fatcat-api-spec/src/mimetypes.rs @@ -452,6 +452,26 @@ 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 AuthCheck + lazy_static! { + pub static ref AUTH_CHECK_SUCCESS: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for AuthCheck + lazy_static! { + pub static ref AUTH_CHECK_BAD_REQUEST: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for AuthCheck + lazy_static! { + pub static ref AUTH_CHECK_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for AuthCheck + lazy_static! { + pub static ref AUTH_CHECK_FORBIDDEN: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for AuthCheck + lazy_static! { + pub static ref AUTH_CHECK_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); diff --git a/rust/fatcat-api-spec/src/server.rs b/rust/fatcat-api-spec/src/server.rs index c0903676..d8fc7dc2 100644 --- a/rust/fatcat-api-spec/src/server.rs +++ b/rust/fatcat-api-spec/src/server.rs @@ -37,18 +37,19 @@ use swagger::{ApiError, Context, XSpanId}; #[allow(unused_imports)] use models; use { - 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, UpdateEditorResponse, UpdateFileResponse, UpdateFilesetResponse, UpdateReleaseResponse, UpdateWebcaptureResponse, UpdateWorkResponse, + AcceptEditgroupResponse, Api, AuthCheckResponse, 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, UpdateEditorResponse, UpdateFileResponse, UpdateFilesetResponse, UpdateReleaseResponse, UpdateWebcaptureResponse, + UpdateWorkResponse, }; header! { (Warning, "Warning") => [String] } @@ -2605,6 +2606,99 @@ where "UpdateCreator", ); + let api_clone = api.clone(); + router.get( + "/v0/auth/check", + 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(req: &mut Request, api: &T, context: &mut Context) -> Result + where + T: Api, + { + context.x_span_id = Some(req.headers.get::().map(XSpanId::to_string).unwrap_or_else(|| self::uuid::Uuid::new_v4().to_string())); + context.auth_data = req.extensions.remove::(); + context.authorization = req.extensions.remove::(); + + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + + // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) + let query_params = req.get::().unwrap_or_default(); + let param_role = query_params.get("role").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); + + match api.auth_check(param_role, context).wait() { + Ok(rsp) => match rsp { + AuthCheckResponse::Success(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_CHECK_SUCCESS.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } + AuthCheckResponse::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_CHECK_BAD_REQUEST.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } + AuthCheckResponse::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_CHECK_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } + AuthCheckResponse::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_CHECK_FORBIDDEN.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } + AuthCheckResponse::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_CHECK_GENERIC_ERROR.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + 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) + }) + }, + "AuthCheck", + ); + let api_clone = api.clone(); router.post( "/v0/auth/oidc", diff --git a/rust/src/api_wrappers.rs b/rust/src/api_wrappers.rs index 614a0007..818a41c2 100644 --- a/rust/src/api_wrappers.rs +++ b/rust/src/api_wrappers.rs @@ -404,8 +404,7 @@ macro_rules! wrap_entity_handlers { $model::db_delete_edit(&conn, edit_id) }) { Ok(()) => - $delete_edit_resp::DeletedEdit(Success { message: format!("Successfully deleted work-in-progress {} edit: {}", stringify!($model), edit_id) } ), - Err(Error(ErrorKind::Diesel(::diesel::result::Error::NotFound), _)) => + $delete_edit_resp::DeletedEdit(Success { message: format!("Successfully deleted work-in-progress {} edit: {}", stringify!($model), edit_id) } ), Err(Error(ErrorKind::Diesel(::diesel::result::Error::NotFound), _)) => $delete_edit_resp::NotFound(ErrorResponse { message: format!("No such {} edit: {}", stringify!($model), edit_id) }), Err(Error(ErrorKind::Diesel(e), _)) => $delete_edit_resp::BadRequest(ErrorResponse { message: e.to_string() }), @@ -918,9 +917,11 @@ impl Api for Server { ErrorKind::OtherBadRequest("editor_id doesn't match".to_string()).into(), ); } - let auth_context = self - .auth_confectionary - .require_auth(&conn, &context.auth_data, Some("update_editor"))?; + let auth_context = self.auth_confectionary.require_auth( + &conn, + &context.auth_data, + Some("update_editor"), + )?; let editor_id = FatCatId::from_str(&editor_id)?; // DANGER! these permissions are for username updates only! if editor_id == auth_context.editor_id { @@ -986,9 +987,11 @@ impl Api for Server { let conn = self.db_pool.get().expect("db_pool error"); let ret = match conn.transaction(|| { let editgroup_id = FatCatId::from_str(&editgroup_id)?; - let auth_context = self - .auth_confectionary - .require_auth(&conn, &context.auth_data, Some("accept_editgroup"))?; + let auth_context = self.auth_confectionary.require_auth( + &conn, + &context.auth_data, + Some("accept_editgroup"), + )?; auth_context.require_role(FatcatRole::Admin)?; // NOTE: this is currently redundant, but zero-cost auth_context.require_editgroup(&conn, editgroup_id)?; @@ -1058,9 +1061,11 @@ impl Api for Server { ) -> Box + Send> { let conn = self.db_pool.get().expect("db_pool error"); let ret = match conn.transaction(|| { - let auth_context = self - .auth_confectionary - .require_auth(&conn, &context.auth_data, Some("create_editgroup"))?; + let auth_context = self.auth_confectionary.require_auth( + &conn, + &context.auth_data, + Some("create_editgroup"), + )?; auth_context.require_role(FatcatRole::Editor)?; let mut entity = entity.clone(); match entity.editor_id.clone() { @@ -1149,9 +1154,11 @@ impl Api for Server { ) -> Box + Send> { let conn = self.db_pool.get().expect("db_pool error"); let ret = match conn.transaction(|| { - let auth_context = self - .auth_confectionary - .require_auth(&conn, &context.auth_data, Some("auth_oidc"))?; + let auth_context = self.auth_confectionary.require_auth( + &conn, + &context.auth_data, + Some("auth_oidc"), + )?; auth_context.require_role(FatcatRole::Superuser)?; let (editor, created) = self.auth_oidc_handler(params, &conn)?; // create an auth token; leave it to webface to attenuate to a given duration @@ -1221,4 +1228,65 @@ impl Api for Server { }; Box::new(futures::done(Ok(ret))) } + + fn auth_check( + &self, + role: Option, + context: &Context, + ) -> Box + Send> { + let conn = self.db_pool.get().expect("db_pool error"); + let ret = match conn.transaction(|| { + let auth_context = self.auth_confectionary.require_auth( + &conn, + &context.auth_data, + Some("auth_check"), + )?; + if let Some(role) = role { + let role = match role.to_lowercase().as_ref() { + "superuser" => FatcatRole::Superuser, + "admin" => FatcatRole::Admin, + "editor" => FatcatRole::Editor, + "bot" => FatcatRole::Bot, + "human" => FatcatRole::Human, + "public" => FatcatRole::Public, + _ => bail!("unknown auth role: {}", role), + }; + auth_context.require_role(role)?; + }; + Ok(()) + }) { + Ok(()) => AuthCheckResponse::Success(Success { + message: "auth check successful!".to_string() }), + Err(Error(ErrorKind::Diesel(e), _)) => AuthCheckResponse::BadRequest(ErrorResponse { + message: e.to_string(), + }), + Err(Error(ErrorKind::Uuid(e), _)) => AuthCheckResponse::BadRequest(ErrorResponse { + message: e.to_string(), + }), + Err(Error(ErrorKind::InvalidCredentials(e), _)) => + // TODO: why can't I NotAuthorized here? + { + AuthCheckResponse::Forbidden(ErrorResponse { + message: e.to_string(), + }) + }, + Err(Error(ErrorKind::InsufficientPrivileges(e), _)) => { + AuthCheckResponse::Forbidden(ErrorResponse { + message: e.to_string(), + }) + }, + Err(Error(ErrorKind::OtherBadRequest(e), _)) => { + AuthCheckResponse::BadRequest(ErrorResponse { + message: e.to_string(), + }) + }, + Err(e) => { + error!("{}", e); + AuthCheckResponse::GenericError(ErrorResponse { + message: e.to_string(), + }) + }, + }; + Box::new(futures::done(Ok(ret))) + } } diff --git a/rust/src/auth.rs b/rust/src/auth.rs index 8894e33b..c20b9b71 100644 --- a/rust/src/auth.rs +++ b/rust/src/auth.rs @@ -56,9 +56,10 @@ impl AuthContext { pub fn require_role(&self, role: FatcatRole) -> Result<()> { match self.has_role(role) { true => Ok(()), - false => Err(ErrorKind::InsufficientPrivileges( - format!("doesn't have required role: {:?}", role), - ) + false => Err(ErrorKind::InsufficientPrivileges(format!( + "doesn't have required role: {:?}", + role + )) .into()), } } @@ -230,7 +231,12 @@ impl AuthConfectionary { Ok(BASE64.encode(&raw)) } - pub fn parse_macaroon_token(&self, conn: &DbConn, s: &str, endpoint: Option<&str>) -> Result { + pub fn parse_macaroon_token( + &self, + conn: &DbConn, + s: &str, + endpoint: Option<&str>, + ) -> Result { let raw = BASE64.decode(s.as_bytes())?; let mac = match Macaroon::deserialize(&raw) { Ok(m) => m, @@ -371,7 +377,12 @@ impl AuthConfectionary { })) } - pub fn require_auth(&self, conn: &DbConn, auth_data: &Option, endpoint: Option<&str>) -> Result { + pub fn require_auth( + &self, + conn: &DbConn, + auth_data: &Option, + endpoint: Option<&str>, + ) -> Result { match self.parse_swagger(conn, auth_data, endpoint)? { Some(auth) => Ok(auth), None => Err(ErrorKind::InvalidCredentials("no token supplied".to_string()).into()), -- cgit v1.2.3