├── .gitignore ├── .github ├── FUNDING.yml └── workflows │ └── integration.yml ├── .cargo-config.toml ├── docker └── Dockerfile ├── COPYING ├── src ├── resource │ ├── workflow_steps.rs │ ├── key.rs │ ├── client_registration_policy.rs │ ├── client_initial_access.rs │ ├── mod.rs │ ├── attack_detection.rs │ ├── client_attribute_certificate.rs │ ├── client_scopes.rs │ ├── component.rs │ ├── roles_by_id.rs │ └── role_mapper.rs ├── rest │ ├── generated_rest │ │ ├── workflow_steps.rs │ │ ├── key.rs │ │ ├── client_registration_policy.rs │ │ ├── mod.rs │ │ ├── client_initial_access.rs │ │ ├── attack_detection.rs │ │ ├── component.rs │ │ ├── client_attribute_certificate.rs │ │ ├── client_scopes.rs │ │ ├── roles_by_id.rs │ │ ├── client_role_mappings.rs │ │ ├── role_mapper.rs │ │ └── groups.rs │ ├── url_enc.rs │ ├── default_response.rs │ ├── manual_rest.rs │ └── mod.rs ├── builder.rs ├── error.rs └── lib.rs ├── update.sh ├── docker-compose.yml ├── templates ├── src │ └── lib.rs └── README.md ├── examples ├── openapi.patch.toml ├── importconfig.rs ├── resource_adduser.rs ├── adduser.rs └── metadata.xml ├── MIT-LICENSE ├── UNLICENSE ├── Cargo.toml └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | Cargo.lock 4 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: kilork 2 | ko_fi: kilork 3 | -------------------------------------------------------------------------------- /.cargo-config.toml: -------------------------------------------------------------------------------- 1 | [resolver] 2 | incompatible-rust-versions = "fallback" -------------------------------------------------------------------------------- /docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM quay.io/keycloak/keycloak:${KEYCLOAK_VERSION} 2 | ENTRYPOINT /opt/keycloak/bin/kc.sh 3 | CMD start-dev -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | This project is dual-licensed under the Unlicense and MIT licenses. 2 | 3 | You may use this code under the terms of either license. -------------------------------------------------------------------------------- /src/resource/workflow_steps.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | impl<'a, TS: KeycloakTokenSupplier> KeycloakRealmAdmin<'a, TS> { 4 | //

Workflow Steps

5 | } 6 | -------------------------------------------------------------------------------- /src/rest/generated_rest/workflow_steps.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | impl KeycloakAdmin { 4 | //

Workflow Steps

5 | } 6 | // not all paths processed 7 | // left 247 8 | -------------------------------------------------------------------------------- /update.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | deno run --allow-env=KEYCLOAK_RUST_VERSION,KEYCLOAK_VERSION,KEYCLOAK_RUST_MAJOR_VERSION --allow-read=Cargo.toml --allow-write=Cargo.toml,api/openapi.json,src/types.rs,src/rest/generated_rest,src/resource --allow-net=keycloak.org,www.keycloak.org --allow-run=cargo,gh,git,handlebars-magic update.ts -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.6" 2 | services: 3 | keycloak: 4 | build: 5 | context: docker 6 | args: 7 | KEYCLOAK_VERSION: ${KEYCLOAK_VERSION} 8 | environment: 9 | KEYCLOAK_ADMIN: admin 10 | KEYCLOAK_ADMIN_PASSWORD: password 11 | KC_PROXY: edge 12 | ports: 13 | - "8080:8080" 14 | -------------------------------------------------------------------------------- /templates/src/lib.rs: -------------------------------------------------------------------------------- 1 | /*! 2 | {{ replace ( render ( read_to_str "templates/README.md" ) ) "```rust" "```rust, no_run" }} 3 | */ 4 | 5 | #[cfg(feature = "builder")] 6 | pub mod builder; 7 | #[cfg(feature = "resource")] 8 | pub mod resource; 9 | pub mod types; 10 | 11 | mod error; 12 | mod rest; 13 | 14 | pub use error::KeycloakError; 15 | pub use rest::{ 16 | DefaultResponse, KeycloakAdmin, KeycloakAdminToken, KeycloakRealmAdmin, 17 | KeycloakRealmAdminMethod, KeycloakServiceAccountAdminTokenRetriever, KeycloakTokenSupplier, 18 | }; 19 | -------------------------------------------------------------------------------- /src/resource/key.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | impl<'a, TS: KeycloakTokenSupplier> KeycloakRealmAdmin<'a, TS> { 4 | //

Key

5 | /// Parameters: 6 | /// 7 | /// - `realm`: realm name (not id!) 8 | /// 9 | /// Resource: `Key` 10 | /// 11 | /// `GET /admin/realms/{realm}/keys` 12 | /// 13 | /// Documentation: 14 | pub fn keys_get( 15 | &'a self, 16 | ) -> impl Future> + use<'a, TS> { 17 | self.admin.realm_keys_get(self.realm) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/rest/url_enc.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Display; 2 | 3 | pub fn encode_url_param(value: &str) -> impl Display + '_ { 4 | use percent_encoding::{utf8_percent_encode, AsciiSet, CONTROLS}; 5 | 6 | const FRAGMENT: &AsciiSet = &CONTROLS.add(b' ').add(b'"').add(b'<').add(b'>').add(b'`'); 7 | const PATH: &AsciiSet = &FRAGMENT.add(b'#').add(b'?').add(b'{').add(b'}'); 8 | const PATH_SEGMENT: &AsciiSet = &PATH.add(b'/').add(b'%'); 9 | 10 | utf8_percent_encode(value, PATH_SEGMENT) 11 | } 12 | 13 | #[cfg(test)] 14 | mod tests { 15 | #[test] 16 | fn non_alphanumerics() { 17 | assert_eq!( 18 | "group%20%2F%20element%20-+%3F*", 19 | super::encode_url_param("group / element -+?*").to_string() 20 | ) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/resource/client_registration_policy.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | impl<'a, TS: KeycloakTokenSupplier> KeycloakRealmAdmin<'a, TS> { 4 | //

Client Registration Policy

5 | /// Base path for retrieve providers with the configProperties properly filled 6 | /// 7 | /// Parameters: 8 | /// 9 | /// - `realm`: realm name (not id!) 10 | /// 11 | /// Resource: `Client Registration Policy` 12 | /// 13 | /// `GET /admin/realms/{realm}/client-registration-policy/providers` 14 | /// 15 | /// Documentation: 16 | pub fn client_registration_policy_providers_get( 17 | &'a self, 18 | ) -> impl Future, KeycloakError>> + use<'a, TS> 19 | { 20 | self.admin 21 | .realm_client_registration_policy_providers_get(self.realm) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/rest/generated_rest/key.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | impl KeycloakAdmin { 4 | //

Key

5 | 6 | /// Parameters: 7 | /// 8 | /// - `realm`: realm name (not id!) 9 | /// 10 | /// Resource: `Key` 11 | /// 12 | /// `GET /admin/realms/{realm}/keys` 13 | /// 14 | /// Documentation: 15 | pub async fn realm_keys_get( 16 | &self, 17 | realm: &str, 18 | ) -> Result { 19 | let realm = p(realm); 20 | let builder = self 21 | .client 22 | .get(format!("{}/admin/realms/{realm}/keys", self.url)) 23 | .bearer_auth(self.token_supplier.get(&self.url).await?); 24 | let response = builder.send().await?; 25 | Ok(error_check(response).await?.json().await?) 26 | } 27 | } 28 | // not all paths processed 29 | // left 246 30 | -------------------------------------------------------------------------------- /examples/openapi.patch.toml: -------------------------------------------------------------------------------- 1 | [path."/admin/realms:post:body"] 2 | from_type = "String" 3 | rust_type = "RealmRepresentation" 4 | [path."/admin/realms/{realm}/partialImport:post:body"] 5 | from_type = "String" 6 | rust_type = "RealmRepresentation" 7 | [path."/admin/realms/{realm}/authentication/register-required-action:post:body"] 8 | from_type = "TypeMap" 9 | rust_type = "RequiredActionProviderRepresentation" 10 | [path."/admin/realms/{realm}/authentication/unregistered-required-actions:get:"] 11 | from_type = "TypeVec>" 12 | rust_type = "TypeVec" 13 | [path."/admin/realms/{realm}/identity-provider/providers/{provider_id}:get:"] 14 | from_type = "Value" 15 | rust_type = "IdentityProviderRepresentation" 16 | [type."ClientPolicyExecutorRepresentation:configuration"] 17 | rust_type = "Option>" 18 | [type."ClientPolicyConditionRepresentation:configuration"] 19 | rust_type = "Option>" -------------------------------------------------------------------------------- /src/builder.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | future::{Future, IntoFuture}, 3 | pin::Pin, 4 | }; 5 | 6 | use crate::{KeycloakError, KeycloakRealmAdminMethod}; 7 | 8 | pub struct Builder<'m, M: 'm + KeycloakRealmAdminMethod> { 9 | method: M, 10 | pub(crate) args: M::Args, 11 | _marker: std::marker::PhantomData<&'m ()>, 12 | } 13 | 14 | impl From for Builder<'_, M> { 15 | fn from(method: M) -> Self { 16 | Builder { 17 | method, 18 | args: Default::default(), 19 | _marker: std::marker::PhantomData, 20 | } 21 | } 22 | } 23 | 24 | impl<'m, M: 'm> IntoFuture for Builder<'m, M> 25 | where 26 | M: KeycloakRealmAdminMethod + Send + Sync, 27 | { 28 | type Output = Result; 29 | type IntoFuture = Pin + Send>>; 30 | 31 | fn into_future(self) -> Self::IntoFuture { 32 | Box::pin(self.method.opts(self.args)) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/rest/default_response.rs: -------------------------------------------------------------------------------- 1 | use reqwest::Response; 2 | 3 | /// Default adapter around [Response]. 4 | pub struct DefaultResponse(Response); 5 | 6 | impl DefaultResponse { 7 | /// Id of resource created. 8 | /// 9 | /// Extracted as last element of header `Location` if present. 10 | pub fn to_id(&self) -> Option<&'_ str> { 11 | self.0 12 | .headers() 13 | .get(reqwest::header::LOCATION) 14 | .and_then(|v| v.to_str().ok()) 15 | .and_then(|v| v.split('/').next_back()) 16 | } 17 | 18 | pub fn into_response(self) -> Response { 19 | self.0 20 | } 21 | } 22 | 23 | impl From for DefaultResponse { 24 | fn from(value: Response) -> Self { 25 | Self(value) 26 | } 27 | } 28 | 29 | impl AsRef for DefaultResponse { 30 | fn as_ref(&self) -> &Response { 31 | &self.0 32 | } 33 | } 34 | 35 | impl AsMut for DefaultResponse { 36 | fn as_mut(&mut self) -> &mut Response { 37 | &mut self.0 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /examples/importconfig.rs: -------------------------------------------------------------------------------- 1 | #[tokio::main] 2 | async fn main() -> Result<(), Box> { 3 | #[cfg(feature = "multipart")] 4 | { 5 | use keycloak::{KeycloakAdmin, KeycloakAdminToken}; 6 | 7 | let url = std::env::var("KEYCLOAK_ADDR").unwrap_or_else(|_| "http://localhost:8080".into()); 8 | let user = std::env::var("KEYCLOAK_USER").unwrap_or_else(|_| "admin".into()); 9 | let password = std::env::var("KEYCLOAK_PASSWORD").unwrap_or_else(|_| "password".into()); 10 | 11 | let client = reqwest::Client::new(); 12 | let admin_token = KeycloakAdminToken::acquire(&url, &user, &password, &client).await?; 13 | 14 | eprintln!("{:?}", admin_token); 15 | 16 | let admin = KeycloakAdmin::new(&url, admin_token, client); 17 | 18 | let config = admin 19 | .realm_identity_provider_import_config_post_form( 20 | "master", 21 | "saml".to_string(), 22 | include_bytes!("metadata.xml").to_vec(), 23 | ) 24 | .await?; 25 | 26 | eprintln!("{:?}", config); 27 | } 28 | Ok(()) 29 | } 30 | -------------------------------------------------------------------------------- /MIT-LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2020 Alexander Korolev 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /UNLICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to -------------------------------------------------------------------------------- /src/rest/generated_rest/client_registration_policy.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | impl KeycloakAdmin { 4 | //

Client Registration Policy

5 | 6 | /// Base path for retrieve providers with the configProperties properly filled 7 | /// 8 | /// Parameters: 9 | /// 10 | /// - `realm`: realm name (not id!) 11 | /// 12 | /// Resource: `Client Registration Policy` 13 | /// 14 | /// `GET /admin/realms/{realm}/client-registration-policy/providers` 15 | /// 16 | /// Documentation: 17 | pub async fn realm_client_registration_policy_providers_get( 18 | &self, 19 | realm: &str, 20 | ) -> Result, KeycloakError> { 21 | let realm = p(realm); 22 | let builder = self 23 | .client 24 | .get(format!( 25 | "{}/admin/realms/{realm}/client-registration-policy/providers", 26 | self.url 27 | )) 28 | .bearer_auth(self.token_supplier.get(&self.url).await?); 29 | let response = builder.send().await?; 30 | Ok(error_check(response).await?.json().await?) 31 | } 32 | } 33 | // not all paths processed 34 | // left 246 35 | -------------------------------------------------------------------------------- /.github/workflows/integration.yml: -------------------------------------------------------------------------------- 1 | name: Integration Test 2 | 3 | on: 4 | push: 5 | branches: [ "master" ] 6 | pull_request: 7 | branches: [ "master" ] 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | integration: 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - uses: actions/checkout@v4 18 | - uses: dtolnay/rust-toolchain@1.87.0 19 | - run: mkdir .cargo && cp .cargo-config.toml .cargo/config.toml 20 | - name: Build with default features 21 | run: cargo build 22 | - name: Run unit tests with default features 23 | run: cargo test --lib 24 | - name: Build with all top level features 25 | run: cargo build --features=rc,schemars,multipart,resource-builder 26 | - name: Run unit tests with all top level features 27 | run: cargo test --features=rc,schemars,multipart,resource-builder 28 | - name: Run integration tests 29 | run: | 30 | export KEYCLOAK_VERSION=`cargo metadata --no-deps --format-version 1 | jq '.packages[0].version | split(".") | map(tonumber) | .[:-1] + [.[2] / 100] | map(floor) | join(".")' | tr -d '"'` 31 | docker run -p 8080:8080 --name keycloak -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=password -e KC_FEATURES=admin-api quay.io/keycloak/keycloak:${KEYCLOAK_VERSION} start-dev & 32 | sleep 40 33 | cargo run --example=adduser 34 | cargo run --example=resource_adduser --features=resource-builder 35 | cargo run --example=importconfig --features=multipart 36 | cargo run --example=adduser --features=rc,schemars,multipart,resource-builder 37 | cargo run --example=resource_adduser --features=rc,schemars,multipart,resource-builder 38 | -------------------------------------------------------------------------------- /src/rest/manual_rest.rs: -------------------------------------------------------------------------------- 1 | #[allow(unused_imports)] 2 | use super::{url_enc::encode_url_param as p, *}; 3 | 4 | impl KeycloakAdmin { 5 | /// Import identity provider from FORM MULTIPART body 6 | /// 7 | /// Parameters: 8 | /// 9 | /// - `realm`: realm name (not id!) 10 | /// - `provider_id`: identity provider type (for example `saml`) 11 | /// - `file`: metadata to parse (XML IDP Metadata for `saml`) 12 | /// 13 | /// Resource: `Identity Providers` 14 | /// 15 | /// `POST /admin/realms/{realm}/identity-provider/import-config` 16 | /// 17 | /// Documentation: 18 | #[cfg(all(feature = "tag-identity-providers", feature = "multipart"))] 19 | pub async fn realm_identity_provider_import_config_post_form( 20 | &self, 21 | realm: &str, 22 | provider_id: String, 23 | file: Vec, 24 | ) -> Result, KeycloakError> { 25 | use reqwest::multipart::{Form, Part}; 26 | 27 | let realm = p(realm); 28 | let file = Part::bytes(file).mime_str("application/octet-stream")?; 29 | let form = Form::new() 30 | .text("providerId", provider_id) 31 | .part("file", file); 32 | let builder = self 33 | .client 34 | .post(format!( 35 | "{}/admin/realms/{realm}/identity-provider/import-config", 36 | self.url 37 | )) 38 | .multipart(form) 39 | .bearer_auth(self.token_supplier.get(&self.url).await?); 40 | let response = builder.send().await?; 41 | Ok(error_check(response).await?.json().await?) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /examples/resource_adduser.rs: -------------------------------------------------------------------------------- 1 | #[cfg(not(all(feature = "builder", feature = "resource")))] 2 | fn main() {} 3 | #[cfg(all(feature = "builder", feature = "resource"))] 4 | #[tokio::main] 5 | async fn main() -> Result<(), Box> { 6 | use keycloak::{types::*, KeycloakAdmin, KeycloakAdminToken}; 7 | 8 | const REALM: &str = "resource"; 9 | 10 | let url = std::env::var("KEYCLOAK_ADDR").unwrap_or_else(|_| "http://localhost:8080".into()); 11 | let user = std::env::var("KEYCLOAK_USER").unwrap_or_else(|_| "admin".into()); 12 | let password = std::env::var("KEYCLOAK_PASSWORD").unwrap_or_else(|_| "password".into()); 13 | 14 | let client = reqwest::Client::new(); 15 | let admin_token = KeycloakAdminToken::acquire(&url, &user, &password, &client).await?; 16 | 17 | eprintln!("{admin_token:?}"); 18 | 19 | let admin = KeycloakAdmin::new(&url, admin_token, client); 20 | 21 | admin 22 | .post(RealmRepresentation { 23 | realm: Some(REALM.into()), 24 | ..Default::default() 25 | }) 26 | .await?; 27 | 28 | let realm = admin.realm(REALM); 29 | 30 | let response = realm 31 | .users_post(UserRepresentation { 32 | username: Some("user".into()), 33 | ..Default::default() 34 | }) 35 | .await?; 36 | 37 | eprintln!("{:?}", response.to_id()); 38 | 39 | let users = realm.users_get().username("user".to_string()).await?; 40 | 41 | eprintln!("{users:?}"); 42 | 43 | let id = users 44 | .iter() 45 | .find(|u| u.username == Some("user".into())) 46 | .unwrap() 47 | .id 48 | .as_ref() 49 | .unwrap() 50 | .to_string(); 51 | 52 | realm.users_with_user_id_delete(id.as_str()).await?; 53 | 54 | realm.delete().await?; 55 | Ok(()) 56 | } 57 | -------------------------------------------------------------------------------- /templates/README.md: -------------------------------------------------------------------------------- 1 | # Keycloak Admin REST API 2 | 3 | ## Legal 4 | 5 | Dual-licensed under `MIT` or the [UNLICENSE](http://unlicense.org/). 6 | 7 | ## Features 8 | 9 | Implements [Keycloak Admin REST API version {{ env_var "KEYCLOAK_VERSION" }}](https://www.keycloak.org/docs-api/{{ env_var "KEYCLOAK_VERSION" }}/rest-api/index.html). 10 | 11 | ### Feature flags 12 | 13 | Default flags: `tags-all`. 14 | 15 | - `rc`: use `Arc` for deserialization. 16 | - `schemars`: add [schemars](https://crates.io/crates/schemars) support. 17 | - `multipart`: add multipart support to reqwest, enabling extra methods in API. 18 | - `tags-all`: activate all tags (resource groups) in REST API, it is default behavior. Disable default features and use individual `tag-xxx` features to activate only required resource groups. For a full list reference the [Cargo.toml](Cargo.toml). 19 | - `resource-builder`: add resource builder support. 20 | 21 | ## Usage 22 | 23 | Requires Rust version >= `1.87.0`. 24 | 25 | Add dependency to Cargo.toml: 26 | 27 | ```toml 28 | [dependencies] 29 | keycloak = "~{{ env_var "KEYCLOAK_RUST_MAJOR_VERSION" }}" 30 | ``` 31 | 32 | {{ codeblock "rust" ( from "#[tokio::main]" ( read_to_str "examples/resource_adduser.rs" ) ) }} 33 | 34 | ## Version agreement 35 | 36 | If we have `x.y.z` version of `keycloak`, our package version would be `x.y.(z * 100 + v)` there v is a minor 37 | fix version to official `x.y.z` version. 38 | 39 | Example: official version `13.0.1` is `13.0.100` for crate version. `13.0.102` means keycloak version `13.0.1` and minor fix version `2`. 40 | 41 | ## Update 42 | 43 | To update current version use provided [update.ts](./update.ts) `deno` script: 44 | 45 | ```sh 46 | deno run --allow-env=KEYCLOAK_RUST_VERSION,KEYCLOAK_VERSION,KEYCLOAK_RUST_MAJOR_VERSION --allow-read=Cargo.toml --allow-write=Cargo.toml,api/openapi.json,src/types.rs,src/rest/generated_rest,src/resource --allow-net=keycloak.org,www.keycloak.org --allow-run=cargo,gh,git,handlebars-magic update.ts 47 | ``` 48 | -------------------------------------------------------------------------------- /src/error.rs: -------------------------------------------------------------------------------- 1 | use std::{borrow::Cow, error::Error, fmt::Display}; 2 | 3 | use serde::{Deserialize, Serialize}; 4 | 5 | #[derive(Debug)] 6 | pub enum KeycloakError { 7 | ReqwestFailure(reqwest::Error), 8 | HttpFailure { 9 | status: u16, 10 | body: Option, 11 | text: String, 12 | }, 13 | } 14 | 15 | impl From for KeycloakError { 16 | fn from(value: reqwest::Error) -> Self { 17 | KeycloakError::ReqwestFailure(value) 18 | } 19 | } 20 | 21 | impl Error for KeycloakError {} 22 | 23 | impl Display for KeycloakError { 24 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 25 | match self { 26 | KeycloakError::ReqwestFailure(e) => write!(f, "keycloak error (network): {e}"), 27 | KeycloakError::HttpFailure { status, body, text } => write!( 28 | f, 29 | "keycloak error (rest): {status} {}", 30 | body.as_ref() 31 | .and_then(|e| e.message()) 32 | .unwrap_or_else(|| Cow::from(text)) 33 | ), 34 | } 35 | } 36 | } 37 | 38 | #[derive(Debug, Clone, Deserialize, Serialize)] 39 | pub struct KeycloakHttpError { 40 | pub error: Option, 41 | pub error_description: Option, 42 | #[serde(rename = "errorMessage")] 43 | pub error_message: Option, 44 | } 45 | 46 | impl KeycloakHttpError { 47 | pub fn message(&self) -> Option> { 48 | self.error_message 49 | .as_deref() 50 | .map(Cow::from) 51 | .or_else(|| { 52 | self.error 53 | .as_deref() 54 | .map(|error| { 55 | format!( 56 | "{} [{error}]", 57 | self.error_description.as_deref().unwrap_or("null") 58 | ) 59 | }) 60 | .map(Cow::from) 61 | }) 62 | .or_else(|| self.error_description.as_deref().map(Cow::from)) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /examples/adduser.rs: -------------------------------------------------------------------------------- 1 | #[tokio::main] 2 | async fn main() -> Result<(), Box> { 3 | use keycloak::{ 4 | types::*, 5 | {KeycloakAdmin, KeycloakAdminToken}, 6 | }; 7 | 8 | const REALM: &str = "test"; 9 | 10 | let url = std::env::var("KEYCLOAK_ADDR").unwrap_or_else(|_| "http://localhost:8080".into()); 11 | let user = std::env::var("KEYCLOAK_USER").unwrap_or_else(|_| "admin".into()); 12 | let password = std::env::var("KEYCLOAK_PASSWORD").unwrap_or_else(|_| "password".into()); 13 | 14 | let client = reqwest::Client::new(); 15 | let admin_token = KeycloakAdminToken::acquire(&url, &user, &password, &client).await?; 16 | 17 | eprintln!("{admin_token:?}"); 18 | 19 | let admin = KeycloakAdmin::new(&url, admin_token, client); 20 | 21 | admin 22 | .post(RealmRepresentation { 23 | realm: Some(REALM.into()), 24 | ..Default::default() 25 | }) 26 | .await?; 27 | 28 | let response = admin 29 | .realm_users_post( 30 | REALM, 31 | UserRepresentation { 32 | username: Some("user".into()), 33 | ..Default::default() 34 | }, 35 | ) 36 | .await?; 37 | 38 | eprintln!("{:?}", response.to_id()); 39 | 40 | let users = admin 41 | .realm_users_get( 42 | REALM, 43 | None, 44 | None, 45 | None, 46 | None, 47 | None, 48 | None, 49 | None, 50 | None, 51 | None, 52 | None, 53 | None, 54 | None, 55 | None, 56 | Some("user".into()), 57 | ) 58 | .await?; 59 | 60 | eprintln!("{users:?}"); 61 | 62 | let id = users 63 | .iter() 64 | .find(|u| u.username == Some("user".into())) 65 | .unwrap() 66 | .id 67 | .as_ref() 68 | .unwrap() 69 | .to_string(); 70 | 71 | admin 72 | .realm_users_with_user_id_delete(REALM, id.as_str()) 73 | .await?; 74 | 75 | admin.realm_delete(REALM).await?; 76 | 77 | Ok(()) 78 | } 79 | -------------------------------------------------------------------------------- /src/rest/generated_rest/mod.rs: -------------------------------------------------------------------------------- 1 | use reqwest::header::CONTENT_LENGTH; 2 | use serde_json::Value; 3 | 4 | use super::{url_enc::encode_url_param as p, *}; 5 | 6 | /// Attack Detection 7 | #[cfg(feature = "tag-attack-detection")] 8 | pub mod attack_detection; 9 | /// Authentication Management 10 | #[cfg(feature = "tag-authentication-management")] 11 | pub mod authentication_management; 12 | /// Client Attribute Certificate 13 | #[cfg(feature = "tag-client-attribute-certificate")] 14 | pub mod client_attribute_certificate; 15 | /// Client Initial Access 16 | #[cfg(feature = "tag-client-initial-access")] 17 | pub mod client_initial_access; 18 | /// Client Registration Policy 19 | #[cfg(feature = "tag-client-registration-policy")] 20 | pub mod client_registration_policy; 21 | /// Client Role Mappings 22 | #[cfg(feature = "tag-client-role-mappings")] 23 | pub mod client_role_mappings; 24 | /// Client Scopes 25 | #[cfg(feature = "tag-client-scopes")] 26 | pub mod client_scopes; 27 | /// Clients 28 | #[cfg(feature = "tag-clients")] 29 | pub mod clients; 30 | /// Component 31 | #[cfg(feature = "tag-component")] 32 | pub mod component; 33 | /// Groups 34 | #[cfg(feature = "tag-groups")] 35 | pub mod groups; 36 | /// Identity Providers 37 | #[cfg(feature = "tag-identity-providers")] 38 | pub mod identity_providers; 39 | /// Key 40 | #[cfg(feature = "tag-key")] 41 | pub mod key; 42 | /// Organizations 43 | #[cfg(feature = "tag-organizations")] 44 | pub mod organizations; 45 | /// Other (non tagged) methods 46 | #[cfg(feature = "tag-none")] 47 | pub mod other_methods; 48 | /// Protocol Mappers 49 | #[cfg(feature = "tag-protocol-mappers")] 50 | pub mod protocol_mappers; 51 | /// Realms Admin 52 | #[cfg(feature = "tag-realms-admin")] 53 | pub mod realms_admin; 54 | /// Role Mapper 55 | #[cfg(feature = "tag-role-mapper")] 56 | pub mod role_mapper; 57 | /// Roles 58 | #[cfg(feature = "tag-roles")] 59 | pub mod roles; 60 | /// Roles (by ID) 61 | #[cfg(feature = "tag-roles-by-id")] 62 | pub mod roles_by_id; 63 | /// Scope Mappings 64 | #[cfg(feature = "tag-scope-mappings")] 65 | pub mod scope_mappings; 66 | /// Users 67 | #[cfg(feature = "tag-users")] 68 | pub mod users; 69 | /// Workflow Steps 70 | #[cfg(feature = "tag-workflow-steps")] 71 | pub mod workflow_steps; 72 | -------------------------------------------------------------------------------- /src/resource/client_initial_access.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | impl<'a, TS: KeycloakTokenSupplier> KeycloakRealmAdmin<'a, TS> { 4 | //

Client Initial Access

5 | /// Parameters: 6 | /// 7 | /// - `realm`: realm name (not id!) 8 | /// 9 | /// Resource: `Client Initial Access` 10 | /// 11 | /// `GET /admin/realms/{realm}/clients-initial-access` 12 | /// 13 | /// Documentation: 14 | pub fn clients_initial_access_get( 15 | &'a self, 16 | ) -> impl Future, KeycloakError>> 17 | + use<'a, TS> { 18 | self.admin.realm_clients_initial_access_get(self.realm) 19 | } 20 | 21 | /// Create a new initial access token. 22 | /// 23 | /// Parameters: 24 | /// 25 | /// - `realm`: realm name (not id!) 26 | /// - `body` 27 | /// 28 | /// Resource: `Client Initial Access` 29 | /// 30 | /// `POST /admin/realms/{realm}/clients-initial-access` 31 | /// 32 | /// Documentation: 33 | pub fn clients_initial_access_post( 34 | &'a self, 35 | body: ClientInitialAccessCreatePresentation, 36 | ) -> impl Future> + use<'a, TS> 37 | { 38 | self.admin 39 | .realm_clients_initial_access_post(self.realm, body) 40 | } 41 | 42 | /// Parameters: 43 | /// 44 | /// - `realm`: realm name (not id!) 45 | /// - `id` 46 | /// 47 | /// Returns response for future processing. 48 | /// 49 | /// Resource: `Client Initial Access` 50 | /// 51 | /// `DELETE /admin/realms/{realm}/clients-initial-access/{id}` 52 | /// 53 | /// Documentation: 54 | pub fn clients_initial_access_with_id_delete( 55 | &'a self, 56 | id: &'a str, 57 | ) -> impl Future> + use<'a, TS> { 58 | self.admin 59 | .realm_clients_initial_access_with_id_delete(self.realm, id) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/resource/mod.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | future::{Future, IntoFuture}, 3 | pin::Pin, 4 | }; 5 | 6 | use serde_json::Value; 7 | 8 | use crate::{ 9 | types::*, DefaultResponse, KeycloakError, KeycloakRealmAdmin, KeycloakRealmAdminMethod, 10 | KeycloakTokenSupplier, 11 | }; 12 | 13 | /// Attack Detection 14 | #[cfg(feature = "tag-attack-detection")] 15 | pub mod attack_detection; 16 | /// Authentication Management 17 | #[cfg(feature = "tag-authentication-management")] 18 | pub mod authentication_management; 19 | /// Client Attribute Certificate 20 | #[cfg(feature = "tag-client-attribute-certificate")] 21 | pub mod client_attribute_certificate; 22 | /// Client Initial Access 23 | #[cfg(feature = "tag-client-initial-access")] 24 | pub mod client_initial_access; 25 | /// Client Registration Policy 26 | #[cfg(feature = "tag-client-registration-policy")] 27 | pub mod client_registration_policy; 28 | /// Client Role Mappings 29 | #[cfg(feature = "tag-client-role-mappings")] 30 | pub mod client_role_mappings; 31 | /// Client Scopes 32 | #[cfg(feature = "tag-client-scopes")] 33 | pub mod client_scopes; 34 | /// Clients 35 | #[cfg(feature = "tag-clients")] 36 | pub mod clients; 37 | /// Component 38 | #[cfg(feature = "tag-component")] 39 | pub mod component; 40 | /// Groups 41 | #[cfg(feature = "tag-groups")] 42 | pub mod groups; 43 | /// Identity Providers 44 | #[cfg(feature = "tag-identity-providers")] 45 | pub mod identity_providers; 46 | /// Key 47 | #[cfg(feature = "tag-key")] 48 | pub mod key; 49 | /// Organizations 50 | #[cfg(feature = "tag-organizations")] 51 | pub mod organizations; 52 | /// Other (non tagged) methods 53 | #[cfg(feature = "tag-none")] 54 | pub mod other_methods; 55 | /// Protocol Mappers 56 | #[cfg(feature = "tag-protocol-mappers")] 57 | pub mod protocol_mappers; 58 | /// Realms Admin 59 | #[cfg(feature = "tag-realms-admin")] 60 | pub mod realms_admin; 61 | /// Role Mapper 62 | #[cfg(feature = "tag-role-mapper")] 63 | pub mod role_mapper; 64 | /// Roles 65 | #[cfg(feature = "tag-roles")] 66 | pub mod roles; 67 | /// Roles (by ID) 68 | #[cfg(feature = "tag-roles-by-id")] 69 | pub mod roles_by_id; 70 | /// Scope Mappings 71 | #[cfg(feature = "tag-scope-mappings")] 72 | pub mod scope_mappings; 73 | /// Users 74 | #[cfg(feature = "tag-users")] 75 | pub mod users; 76 | /// Workflow Steps 77 | #[cfg(feature = "tag-workflow-steps")] 78 | pub mod workflow_steps; 79 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "keycloak" 3 | version = "26.4.0" 4 | authors = ["Alexander Korolev "] 5 | edition = "2021" 6 | categories = ["api-bindings", "asynchronous"] 7 | description = """ 8 | Keycloak Admin REST API. 9 | """ 10 | homepage = "https://github.com/kilork/keycloak" 11 | keywords = ["api", "async", "keycloak", "rest"] 12 | license = "Unlicense OR MIT" 13 | repository = "https://github.com/kilork/keycloak" 14 | rust-version = "1.87" 15 | 16 | [features] 17 | default = ["tags-all", "resource-builder"] 18 | resource-builder = ["builder", "resource"] 19 | schemars = ["dep:schemars"] 20 | multipart = ["reqwest/multipart"] 21 | rc = ["rc-map", "rc-str", "rc-val", "rc-vec"] 22 | rc-map = ["serde/rc"] 23 | rc-str = ["serde/rc"] 24 | rc-val = ["serde/rc"] 25 | rc-vec = ["serde/rc"] 26 | tags-all = ["tag-attack-detection", "tag-authentication-management", "tag-client-attribute-certificate", "tag-client-initial-access", "tag-client-registration-policy", "tag-client-role-mappings", "tag-client-scopes", "tag-clients", "tag-component", "tag-groups", "tag-identity-providers", "tag-key", "tag-organizations", "tag-protocol-mappers", "tag-realms-admin", "tag-role-mapper", "tag-roles", "tag-roles-by-id", "tag-scope-mappings", "tag-users", "tag-workflow-steps", "tag-none"] 27 | tag-attack-detection = [] 28 | tag-authentication-management = [] 29 | tag-client-attribute-certificate = [] 30 | tag-client-initial-access = [] 31 | tag-client-registration-policy = [] 32 | tag-client-role-mappings = [] 33 | tag-client-scopes = [] 34 | tag-clients = [] 35 | tag-component = [] 36 | tag-groups = [] 37 | tag-identity-providers = [] 38 | tag-key = [] 39 | tag-organizations = [] 40 | tag-protocol-mappers = [] 41 | tag-realms-admin = [] 42 | tag-role-mapper = [] 43 | tag-roles = [] 44 | tag-roles-by-id = [] 45 | tag-scope-mappings = [] 46 | tag-users = [] 47 | tag-workflow-steps = [] 48 | tag-none = [] 49 | resource = [] 50 | builder = [] 51 | 52 | [dependencies] 53 | reqwest = { version = "0.12", default-features = false, features = ["json"] } 54 | serde_json = "1" 55 | serde = { version = "1", features = ["derive"] } 56 | serde_with = { version = "3", default-features = false, features = ["macros"] } 57 | async-trait = "0.1" 58 | schemars = { version = "0.8.11", default-features = false, features = [ 59 | "derive", 60 | ], optional = true } 61 | percent-encoding = "2.3.1" 62 | 63 | [dev-dependencies] 64 | tokio = { version = "1", features = ["full"] } 65 | heck = "0.5" 66 | clap = { version = "4", features = ["derive", "help", "std"], default-features = false } 67 | toml = "0.8" 68 | serde = { version = "1", features = ["derive", "rc"] } 69 | indexmap = { version = "2", features = ["serde"] } 70 | -------------------------------------------------------------------------------- /src/resource/attack_detection.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | impl<'a, TS: KeycloakTokenSupplier> KeycloakRealmAdmin<'a, TS> { 4 | //

Attack Detection

5 | /// Clear any user login failures for all users This can release temporary disabled users 6 | /// 7 | /// Parameters: 8 | /// 9 | /// - `realm`: realm name (not id!) 10 | /// 11 | /// Returns response for future processing. 12 | /// 13 | /// Resource: `Attack Detection` 14 | /// 15 | /// `DELETE /admin/realms/{realm}/attack-detection/brute-force/users` 16 | /// 17 | /// Documentation: 18 | pub fn attack_detection_brute_force_users_delete( 19 | &'a self, 20 | ) -> impl Future> + use<'a, TS> { 21 | self.admin 22 | .realm_attack_detection_brute_force_users_delete(self.realm) 23 | } 24 | 25 | /// Get status of a username in brute force detection 26 | /// 27 | /// Parameters: 28 | /// 29 | /// - `realm`: realm name (not id!) 30 | /// - `user_id` 31 | /// 32 | /// Resource: `Attack Detection` 33 | /// 34 | /// `GET /admin/realms/{realm}/attack-detection/brute-force/users/{user_id}` 35 | /// 36 | /// Documentation: 37 | /// 38 | /// REST method: `GET /admin/realms/{realm}/attack-detection/brute-force/users/{userId}` 39 | pub fn attack_detection_brute_force_users_with_user_id_get( 40 | &'a self, 41 | user_id: &'a str, 42 | ) -> impl Future, KeycloakError>> + use<'a, TS> { 43 | self.admin 44 | .realm_attack_detection_brute_force_users_with_user_id_get(self.realm, user_id) 45 | } 46 | 47 | /// Clear any user login failures for the user This can release temporary disabled user 48 | /// 49 | /// Parameters: 50 | /// 51 | /// - `realm`: realm name (not id!) 52 | /// - `user_id` 53 | /// 54 | /// Returns response for future processing. 55 | /// 56 | /// Resource: `Attack Detection` 57 | /// 58 | /// `DELETE /admin/realms/{realm}/attack-detection/brute-force/users/{user_id}` 59 | /// 60 | /// Documentation: 61 | /// 62 | /// REST method: `DELETE /admin/realms/{realm}/attack-detection/brute-force/users/{userId}` 63 | pub fn attack_detection_brute_force_users_with_user_id_delete( 64 | &'a self, 65 | user_id: &'a str, 66 | ) -> impl Future> + use<'a, TS> { 67 | self.admin 68 | .realm_attack_detection_brute_force_users_with_user_id_delete(self.realm, user_id) 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/rest/generated_rest/client_initial_access.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | impl KeycloakAdmin { 4 | //

Client Initial Access

5 | 6 | /// Parameters: 7 | /// 8 | /// - `realm`: realm name (not id!) 9 | /// 10 | /// Resource: `Client Initial Access` 11 | /// 12 | /// `GET /admin/realms/{realm}/clients-initial-access` 13 | /// 14 | /// Documentation: 15 | pub async fn realm_clients_initial_access_get( 16 | &self, 17 | realm: &str, 18 | ) -> Result, KeycloakError> { 19 | let realm = p(realm); 20 | let builder = self 21 | .client 22 | .get(format!( 23 | "{}/admin/realms/{realm}/clients-initial-access", 24 | self.url 25 | )) 26 | .bearer_auth(self.token_supplier.get(&self.url).await?); 27 | let response = builder.send().await?; 28 | Ok(error_check(response).await?.json().await?) 29 | } 30 | 31 | /// Create a new initial access token. 32 | /// 33 | /// Parameters: 34 | /// 35 | /// - `realm`: realm name (not id!) 36 | /// - `body` 37 | /// 38 | /// Resource: `Client Initial Access` 39 | /// 40 | /// `POST /admin/realms/{realm}/clients-initial-access` 41 | /// 42 | /// Documentation: 43 | pub async fn realm_clients_initial_access_post( 44 | &self, 45 | realm: &str, 46 | body: ClientInitialAccessCreatePresentation, 47 | ) -> Result { 48 | let realm = p(realm); 49 | let builder = self 50 | .client 51 | .post(format!( 52 | "{}/admin/realms/{realm}/clients-initial-access", 53 | self.url 54 | )) 55 | .json(&body) 56 | .bearer_auth(self.token_supplier.get(&self.url).await?); 57 | let response = builder.send().await?; 58 | Ok(error_check(response).await?.json().await?) 59 | } 60 | 61 | /// Parameters: 62 | /// 63 | /// - `realm`: realm name (not id!) 64 | /// - `id` 65 | /// 66 | /// Returns response for future processing. 67 | /// 68 | /// Resource: `Client Initial Access` 69 | /// 70 | /// `DELETE /admin/realms/{realm}/clients-initial-access/{id}` 71 | /// 72 | /// Documentation: 73 | pub async fn realm_clients_initial_access_with_id_delete( 74 | &self, 75 | realm: &str, 76 | id: &str, 77 | ) -> Result { 78 | let realm = p(realm); 79 | let id = p(id); 80 | let builder = self 81 | .client 82 | .delete(format!( 83 | "{}/admin/realms/{realm}/clients-initial-access/{id}", 84 | self.url 85 | )) 86 | .bearer_auth(self.token_supplier.get(&self.url).await?); 87 | let response = builder.send().await?; 88 | error_check(response).await.map(From::from) 89 | } 90 | } 91 | // not all paths processed 92 | // left 245 93 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Keycloak Admin REST API 2 | 3 | ## Legal 4 | 5 | Dual-licensed under `MIT` or the [UNLICENSE](http://unlicense.org/). 6 | 7 | ## Features 8 | 9 | Implements [Keycloak Admin REST API version 26.4.0](https://www.keycloak.org/docs-api/26.4.0/rest-api/index.html). 10 | 11 | ### Feature flags 12 | 13 | Default flags: `tags-all`. 14 | 15 | - `rc`: use `Arc` for deserialization. 16 | - `schemars`: add [schemars](https://crates.io/crates/schemars) support. 17 | - `multipart`: add multipart support to reqwest, enabling extra methods in API. 18 | - `tags-all`: activate all tags (resource groups) in REST API, it is default behavior. Disable default features and use individual `tag-xxx` features to activate only required resource groups. For a full list reference the [Cargo.toml](Cargo.toml). 19 | - `resource-builder`: add resource builder support. 20 | 21 | ## Usage 22 | 23 | Requires Rust version >= `1.87.0`. 24 | 25 | Add dependency to Cargo.toml: 26 | 27 | ```toml 28 | [dependencies] 29 | keycloak = "~26.4" 30 | ``` 31 | 32 | ```rust 33 | #[tokio::main] 34 | async fn main() -> Result<(), Box> { 35 | use keycloak::{types::*, KeycloakAdmin, KeycloakAdminToken}; 36 | 37 | const REALM: &str = "resource"; 38 | 39 | let url = std::env::var("KEYCLOAK_ADDR").unwrap_or_else(|_| "http://localhost:8080".into()); 40 | let user = std::env::var("KEYCLOAK_USER").unwrap_or_else(|_| "admin".into()); 41 | let password = std::env::var("KEYCLOAK_PASSWORD").unwrap_or_else(|_| "password".into()); 42 | 43 | let client = reqwest::Client::new(); 44 | let admin_token = KeycloakAdminToken::acquire(&url, &user, &password, &client).await?; 45 | 46 | eprintln!("{admin_token:?}"); 47 | 48 | let admin = KeycloakAdmin::new(&url, admin_token, client); 49 | 50 | admin 51 | .post(RealmRepresentation { 52 | realm: Some(REALM.into()), 53 | ..Default::default() 54 | }) 55 | .await?; 56 | 57 | let realm = admin.realm(REALM); 58 | 59 | let response = realm 60 | .users_post(UserRepresentation { 61 | username: Some("user".into()), 62 | ..Default::default() 63 | }) 64 | .await?; 65 | 66 | eprintln!("{:?}", response.to_id()); 67 | 68 | let users = realm.users_get().username("user".to_string()).await?; 69 | 70 | eprintln!("{users:?}"); 71 | 72 | let id = users 73 | .iter() 74 | .find(|u| u.username == Some("user".into())) 75 | .unwrap() 76 | .id 77 | .as_ref() 78 | .unwrap() 79 | .to_string(); 80 | 81 | realm.users_with_user_id_delete(id.as_str()).await?; 82 | 83 | realm.delete().await?; 84 | Ok(()) 85 | } 86 | ``` 87 | 88 | ## Version agreement 89 | 90 | If we have `x.y.z` version of `keycloak`, our package version would be `x.y.(z * 100 + v)` there v is a minor 91 | fix version to official `x.y.z` version. 92 | 93 | Example: official version `13.0.1` is `13.0.100` for crate version. `13.0.102` means keycloak version `13.0.1` and minor fix version `2`. 94 | 95 | ## Update 96 | 97 | To update current version use provided [update.ts](./update.ts) `deno` script: 98 | 99 | ```sh 100 | deno run --allow-env=KEYCLOAK_RUST_VERSION,KEYCLOAK_VERSION,KEYCLOAK_RUST_MAJOR_VERSION --allow-read=Cargo.toml --allow-write=Cargo.toml,api/openapi.json,src/types.rs,src/rest/generated_rest,src/resource --allow-net=keycloak.org,www.keycloak.org --allow-run=cargo,gh,git,handlebars-magic update.ts 101 | ``` 102 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | /*! 2 | # Keycloak Admin REST API 3 | 4 | ## Legal 5 | 6 | Dual-licensed under `MIT` or the [UNLICENSE](http://unlicense.org/). 7 | 8 | ## Features 9 | 10 | Implements [Keycloak Admin REST API version 26.4.0](https://www.keycloak.org/docs-api/26.4.0/rest-api/index.html). 11 | 12 | ### Feature flags 13 | 14 | Default flags: `tags-all`. 15 | 16 | - `rc`: use `Arc` for deserialization. 17 | - `schemars`: add [schemars](https://crates.io/crates/schemars) support. 18 | - `multipart`: add multipart support to reqwest, enabling extra methods in API. 19 | - `tags-all`: activate all tags (resource groups) in REST API, it is default behavior. Disable default features and use individual `tag-xxx` features to activate only required resource groups. For a full list reference the [Cargo.toml](Cargo.toml). 20 | - `resource-builder`: add resource builder support. 21 | 22 | ## Usage 23 | 24 | Requires Rust version >= `1.87.0`. 25 | 26 | Add dependency to Cargo.toml: 27 | 28 | ```toml 29 | [dependencies] 30 | keycloak = "~26.4" 31 | ``` 32 | 33 | ```rust, no_run 34 | #[tokio::main] 35 | async fn main() -> Result<(), Box> { 36 | use keycloak::{types::*, KeycloakAdmin, KeycloakAdminToken}; 37 | 38 | const REALM: &str = "resource"; 39 | 40 | let url = std::env::var("KEYCLOAK_ADDR").unwrap_or_else(|_| "http://localhost:8080".into()); 41 | let user = std::env::var("KEYCLOAK_USER").unwrap_or_else(|_| "admin".into()); 42 | let password = std::env::var("KEYCLOAK_PASSWORD").unwrap_or_else(|_| "password".into()); 43 | 44 | let client = reqwest::Client::new(); 45 | let admin_token = KeycloakAdminToken::acquire(&url, &user, &password, &client).await?; 46 | 47 | eprintln!("{admin_token:?}"); 48 | 49 | let admin = KeycloakAdmin::new(&url, admin_token, client); 50 | 51 | admin 52 | .post(RealmRepresentation { 53 | realm: Some(REALM.into()), 54 | ..Default::default() 55 | }) 56 | .await?; 57 | 58 | let realm = admin.realm(REALM); 59 | 60 | let response = realm 61 | .users_post(UserRepresentation { 62 | username: Some("user".into()), 63 | ..Default::default() 64 | }) 65 | .await?; 66 | 67 | eprintln!("{:?}", response.to_id()); 68 | 69 | let users = realm.users_get().username("user".to_string()).await?; 70 | 71 | eprintln!("{users:?}"); 72 | 73 | let id = users 74 | .iter() 75 | .find(|u| u.username == Some("user".into())) 76 | .unwrap() 77 | .id 78 | .as_ref() 79 | .unwrap() 80 | .to_string(); 81 | 82 | realm.users_with_user_id_delete(id.as_str()).await?; 83 | 84 | realm.delete().await?; 85 | Ok(()) 86 | } 87 | ``` 88 | 89 | ## Version agreement 90 | 91 | If we have `x.y.z` version of `keycloak`, our package version would be `x.y.(z * 100 + v)` there v is a minor 92 | fix version to official `x.y.z` version. 93 | 94 | Example: official version `13.0.1` is `13.0.100` for crate version. `13.0.102` means keycloak version `13.0.1` and minor fix version `2`. 95 | 96 | ## Update 97 | 98 | To update current version use provided [update.ts](./update.ts) `deno` script: 99 | 100 | ```sh 101 | deno run --allow-env=KEYCLOAK_RUST_VERSION,KEYCLOAK_VERSION,KEYCLOAK_RUST_MAJOR_VERSION --allow-read=Cargo.toml --allow-write=Cargo.toml,api/openapi.json,src/types.rs,src/rest/generated_rest,src/resource --allow-net=keycloak.org,www.keycloak.org --allow-run=cargo,gh,git,handlebars-magic update.ts 102 | ``` 103 | 104 | */ 105 | 106 | #[cfg(feature = "builder")] 107 | pub mod builder; 108 | #[cfg(feature = "resource")] 109 | pub mod resource; 110 | pub mod types; 111 | 112 | mod error; 113 | mod rest; 114 | 115 | pub use error::KeycloakError; 116 | pub use rest::{ 117 | DefaultResponse, KeycloakAdmin, KeycloakAdminToken, KeycloakRealmAdmin, 118 | KeycloakRealmAdminMethod, KeycloakServiceAccountAdminTokenRetriever, KeycloakTokenSupplier, 119 | }; 120 | -------------------------------------------------------------------------------- /src/rest/generated_rest/attack_detection.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | impl KeycloakAdmin { 4 | //

Attack Detection

5 | 6 | /// Clear any user login failures for all users This can release temporary disabled users 7 | /// 8 | /// Parameters: 9 | /// 10 | /// - `realm`: realm name (not id!) 11 | /// 12 | /// Returns response for future processing. 13 | /// 14 | /// Resource: `Attack Detection` 15 | /// 16 | /// `DELETE /admin/realms/{realm}/attack-detection/brute-force/users` 17 | /// 18 | /// Documentation: 19 | pub async fn realm_attack_detection_brute_force_users_delete( 20 | &self, 21 | realm: &str, 22 | ) -> Result { 23 | let realm = p(realm); 24 | let builder = self 25 | .client 26 | .delete(format!( 27 | "{}/admin/realms/{realm}/attack-detection/brute-force/users", 28 | self.url 29 | )) 30 | .bearer_auth(self.token_supplier.get(&self.url).await?); 31 | let response = builder.send().await?; 32 | error_check(response).await.map(From::from) 33 | } 34 | 35 | /// Get status of a username in brute force detection 36 | /// 37 | /// Parameters: 38 | /// 39 | /// - `realm`: realm name (not id!) 40 | /// - `user_id` 41 | /// 42 | /// Resource: `Attack Detection` 43 | /// 44 | /// `GET /admin/realms/{realm}/attack-detection/brute-force/users/{user_id}` 45 | /// 46 | /// Documentation: 47 | /// 48 | /// REST method: `GET /admin/realms/{realm}/attack-detection/brute-force/users/{userId}` 49 | pub async fn realm_attack_detection_brute_force_users_with_user_id_get( 50 | &self, 51 | realm: &str, 52 | user_id: &str, 53 | ) -> Result, KeycloakError> { 54 | let realm = p(realm); 55 | let user_id = p(user_id); 56 | let builder = self 57 | .client 58 | .get(format!( 59 | "{}/admin/realms/{realm}/attack-detection/brute-force/users/{user_id}", 60 | self.url 61 | )) 62 | .bearer_auth(self.token_supplier.get(&self.url).await?); 63 | let response = builder.send().await?; 64 | Ok(error_check(response).await?.json().await?) 65 | } 66 | 67 | /// Clear any user login failures for the user This can release temporary disabled user 68 | /// 69 | /// Parameters: 70 | /// 71 | /// - `realm`: realm name (not id!) 72 | /// - `user_id` 73 | /// 74 | /// Returns response for future processing. 75 | /// 76 | /// Resource: `Attack Detection` 77 | /// 78 | /// `DELETE /admin/realms/{realm}/attack-detection/brute-force/users/{user_id}` 79 | /// 80 | /// Documentation: 81 | /// 82 | /// REST method: `DELETE /admin/realms/{realm}/attack-detection/brute-force/users/{userId}` 83 | pub async fn realm_attack_detection_brute_force_users_with_user_id_delete( 84 | &self, 85 | realm: &str, 86 | user_id: &str, 87 | ) -> Result { 88 | let realm = p(realm); 89 | let user_id = p(user_id); 90 | let builder = self 91 | .client 92 | .delete(format!( 93 | "{}/admin/realms/{realm}/attack-detection/brute-force/users/{user_id}", 94 | self.url 95 | )) 96 | .bearer_auth(self.token_supplier.get(&self.url).await?); 97 | let response = builder.send().await?; 98 | error_check(response).await.map(From::from) 99 | } 100 | } 101 | // not all paths processed 102 | // left 245 103 | -------------------------------------------------------------------------------- /examples/metadata.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | MIID7TCCAtWgAwIBAgIJANn3qP9lF7M3MA0GCSqGSIb3DQEBCwUAMIGMMQswCQYDVQQGEwJVQTEXMBUGA1UE 8 | CAwOS2hhcmtpdiBSZWdpb24xEDAOBgNVBAcMB0toYXJrb3YxDzANBgNVBAoMBk9yYWNsZTEYMBYGA1UEAwwPc3RzeWJvdi12bTEudWEzMScw 9 | JQYJKoZIhvcNAQkBFhhzZXJnaWkudHN5Ym92QG9yYWNsZS5jb20wHhcNMTUxMjI1MTIyMjU5WhcNMjUxMjI0MTIyMjU5WjCBjDELMAkGA1UE 10 | BhMCVUExFzAVBgNVBAgMDktoYXJraXYgUmVnaW9uMRAwDgYDVQQHDAdLaGFya292MQ8wDQYDVQQKDAZPcmFjbGUxGDAWBgNVBAMMD3N0c3lib 11 | 3Ytdm0xLnVhMzEnMCUGCSqGSIb3DQEJARYYc2VyZ2lpLnRzeWJvdkBvcmFjbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCA 12 | QEAw4OFwuUNjn6xxb/OuAnmQA6mCWPY2hKMoOz0cAajUHjNZZMwGnuEeUyPtEcULfz2MYo1yKQLxVj3pY0HTIQAzpY8o+xCqJFQmdMiakb 13 | PFHlh4z/qqiS5jHng6JCeUpCIxeiTG9JXVwF1ErBEZbwZYjVxa6S+0grVkS3YxuH4uTyqxskuGnHK/AviTHLBrLfSrbFKYuQUrXyy6X22wpzo 14 | bQ3Z+4bhEE8SXQtVbQdy7K0MKWYopNhX05SMTv7yMfUGp8EkGNyJ5Km8AuQt6ZCbVao6cHL2hSujQiN6aMjKbdzHeA1QEicppnnoG/Zefyi/ 15 | okWdlLAaLjcpYrjUSWQJZQIDAQABo1AwTjAdBgNVHQ4EFgQUIKa0zeXmAJsCuNhJjhU0o7KiQgYwHwYDVR0jBBgwFoAUIKa0zeXmAJsCuNhJj 16 | hU0o7KiQgYwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAJawU5WRXqkW4emm+djpJAxZ0076qPgEsaaog6ng4MLAlU7RmfIY/ 17 | l0VhXQegvhIBfG4OfduuzGaqd9y4IsQZFJ0yuotl96iEVcqg7hJ1LEY6UT6u6dZyGj1a9I6IlwJm/9CXFZHuVqGJkMfQZ4gaunE4c5gjbQA5/ 18 | +PEJwPorKn48w8bojymV8hriqzrmaP8eQNuZUJsJdnKENOE5/asGyj+R2YfP6bmlOX3q0ozLcyJbXeZ6IvDFdRiDH5wO4JqW/ujvdvC553y 19 | CO3xxsorB4xCupuHu/c7vkzNpaKjYdmGRkqhEqBcCqYSxdwIFc1xhOwYPWKJzgn7pGQsT7yNJg== 20 | 21 | 22 | 23 | 24 | 25 | 26 | MIID7TCCAtWgAwIBAgIJANn3qP9lF7M3MA0GCSqGSIb3DQEBCwUAMIGMMQswCQYDVQQGEwJVQTEXMBUGA1 27 | UECAwOS2hhcmtpdiBSZWdpb24xEDAOBgNVBAcMB0toYXJrb3YxDzANBgNVBAoMBk9yYWNsZTEYMBYGA1UEAwwPc3RzeWJvdi12bTEud 28 | WEzMScwJQYJKoZIhvcNAQkBFhhzZXJnaWkudHN5Ym92QG9yYWNsZS5jb20wHhcNMTUxMjI1MTIyMjU5WhcNMjUxMjI0MTIyMjU5WjCB 29 | jDELMAkGA1UEBhMCVUExFzAVBgNVBAgMDktoYXJraXYgUmVnaW9uMRAwDgYDVQQHDAdLaGFya292MQ8wDQYDVQQKDAZPcmFjbGUxGDA 30 | WBgNVBAMMD3N0c3lib3Ytdm0xLnVhMzEnMCUGCSqGSIb3DQEJARYYc2VyZ2lpLnRzeWJvdkBvcmFjbGUuY29tMIIBIjANBgkqhkiG9w0B 31 | AQEFAAOCAQ8AMIIBCgKCAQEAw4OFwuUNjn6xxb/OuAnmQA6mCWPY2hKMoOz0cAajUHjNZZMwGnuEeUyPtEcULfz2MYo1yKQLxVj3pY0HT 32 | IQAzpY8o+xCqJFQmdMiakbPFHlh4z/qqiS5jHng6JCeUpCIxeiTG9JXVwF1ErBEZbwZYjVxa6S+0grVkS3YxuH4uTyqxskuGnHK/ 33 | AviTHLBrLfSrbFKYuQUrXyy6X22wpzobQ3Z+4bhEE8SXQtVbQdy7K0MKWYopNhX05SMTv7yMfUGp8EkGNyJ5Km8AuQt6ZCbVao6cHL2h 34 | SujQiN6aMjKbdzHeA1QEicppnnoG/Zefyi/okWdlLAaLjcpYrjUSWQJZQIDAQABo1AwTjAdBgNVHQ4EFgQUIKa0zeXmAJsCuNhJjhU0o 35 | 7KiQgYwHwYDVR0jBBgwFoAUIKa0zeXmAJsCuNhJjhU0o7KiQgYwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAJawU5WRXq 36 | kW4emm+djpJAxZ0076qPgEsaaog6ng4MLAlU7RmfIY/l0VhXQegvhIBfG4OfduuzGaqd9y4IsQZFJ0yuotl96iEVcqg7hJ1LEY6UT6u6d 37 | ZyGj1a9I6IlwJm/9CXFZHuVqGJkMfQZ4gaunE4c5gjbQA5/+PEJwPorKn48w8bojymV8hriqzrmaP8eQNuZUJsJdnKENOE5/ 38 | asGyj+R2YfP6bmlOX3q0ozLcyJbXeZ6IvDFdRiDH5wO4JqW/ujvdvC553yCO3xxsorB4xCupuHu/c7vkzNpaKjYdmGRkqhEqBcCqYSxd 39 | wIFc1xhOwYPWKJzgn7pGQsT7yNJg== 40 | 41 | 42 | 43 | 44 | urn:oasis:names:tc:SAML:2.0:nameid-format:transient 45 | 46 | 47 | 48 | Administrator 49 | name@emailprovider.com 50 | 51 | 52 | -------------------------------------------------------------------------------- /src/rest/generated_rest/component.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | impl KeycloakAdmin { 4 | //

Component

5 | 6 | /// Parameters: 7 | /// 8 | /// - `realm`: realm name (not id!) 9 | /// - `name` 10 | /// - `parent` 11 | /// - `type_` 12 | /// 13 | /// Resource: `Component` 14 | /// 15 | /// `GET /admin/realms/{realm}/components` 16 | /// 17 | /// Documentation: 18 | pub async fn realm_components_get( 19 | &self, 20 | realm: &str, 21 | name: Option, 22 | parent: Option, 23 | type_: Option, 24 | ) -> Result, KeycloakError> { 25 | let realm = p(realm); 26 | let mut builder = self 27 | .client 28 | .get(format!("{}/admin/realms/{realm}/components", self.url)) 29 | .bearer_auth(self.token_supplier.get(&self.url).await?); 30 | if let Some(v) = name { 31 | builder = builder.query(&[("name", v)]); 32 | } 33 | if let Some(v) = parent { 34 | builder = builder.query(&[("parent", v)]); 35 | } 36 | if let Some(v) = type_ { 37 | builder = builder.query(&[("type", v)]); 38 | } 39 | let response = builder.send().await?; 40 | Ok(error_check(response).await?.json().await?) 41 | } 42 | 43 | /// Parameters: 44 | /// 45 | /// - `realm`: realm name (not id!) 46 | /// - `body` 47 | /// 48 | /// Returns response for future processing. 49 | /// 50 | /// Resource: `Component` 51 | /// 52 | /// `POST /admin/realms/{realm}/components` 53 | /// 54 | /// Documentation: 55 | pub async fn realm_components_post( 56 | &self, 57 | realm: &str, 58 | body: ComponentRepresentation, 59 | ) -> Result { 60 | let realm = p(realm); 61 | let builder = self 62 | .client 63 | .post(format!("{}/admin/realms/{realm}/components", self.url)) 64 | .json(&body) 65 | .bearer_auth(self.token_supplier.get(&self.url).await?); 66 | let response = builder.send().await?; 67 | error_check(response).await.map(From::from) 68 | } 69 | 70 | /// Parameters: 71 | /// 72 | /// - `realm`: realm name (not id!) 73 | /// - `id` 74 | /// 75 | /// Resource: `Component` 76 | /// 77 | /// `GET /admin/realms/{realm}/components/{id}` 78 | /// 79 | /// Documentation: 80 | pub async fn realm_components_with_id_get( 81 | &self, 82 | realm: &str, 83 | id: &str, 84 | ) -> Result { 85 | let realm = p(realm); 86 | let id = p(id); 87 | let builder = self 88 | .client 89 | .get(format!("{}/admin/realms/{realm}/components/{id}", self.url)) 90 | .bearer_auth(self.token_supplier.get(&self.url).await?); 91 | let response = builder.send().await?; 92 | Ok(error_check(response).await?.json().await?) 93 | } 94 | 95 | /// Parameters: 96 | /// 97 | /// - `realm`: realm name (not id!) 98 | /// - `id` 99 | /// - `body` 100 | /// 101 | /// Returns response for future processing. 102 | /// 103 | /// Resource: `Component` 104 | /// 105 | /// `PUT /admin/realms/{realm}/components/{id}` 106 | /// 107 | /// Documentation: 108 | pub async fn realm_components_with_id_put( 109 | &self, 110 | realm: &str, 111 | id: &str, 112 | body: ComponentRepresentation, 113 | ) -> Result { 114 | let realm = p(realm); 115 | let id = p(id); 116 | let builder = self 117 | .client 118 | .put(format!("{}/admin/realms/{realm}/components/{id}", self.url)) 119 | .json(&body) 120 | .bearer_auth(self.token_supplier.get(&self.url).await?); 121 | let response = builder.send().await?; 122 | error_check(response).await.map(From::from) 123 | } 124 | 125 | /// Parameters: 126 | /// 127 | /// - `realm`: realm name (not id!) 128 | /// - `id` 129 | /// 130 | /// Returns response for future processing. 131 | /// 132 | /// Resource: `Component` 133 | /// 134 | /// `DELETE /admin/realms/{realm}/components/{id}` 135 | /// 136 | /// Documentation: 137 | pub async fn realm_components_with_id_delete( 138 | &self, 139 | realm: &str, 140 | id: &str, 141 | ) -> Result { 142 | let realm = p(realm); 143 | let id = p(id); 144 | let builder = self 145 | .client 146 | .delete(format!("{}/admin/realms/{realm}/components/{id}", self.url)) 147 | .bearer_auth(self.token_supplier.get(&self.url).await?); 148 | let response = builder.send().await?; 149 | error_check(response).await.map(From::from) 150 | } 151 | 152 | /// List of subcomponent types that are available to configure for a particular parent component. 153 | /// 154 | /// Parameters: 155 | /// 156 | /// - `realm`: realm name (not id!) 157 | /// - `id` 158 | /// - `type_` 159 | /// 160 | /// Resource: `Component` 161 | /// 162 | /// `GET /admin/realms/{realm}/components/{id}/sub-component-types` 163 | /// 164 | /// Documentation: 165 | pub async fn realm_components_with_id_sub_component_types_get( 166 | &self, 167 | realm: &str, 168 | id: &str, 169 | type_: Option, 170 | ) -> Result, KeycloakError> { 171 | let realm = p(realm); 172 | let id = p(id); 173 | let mut builder = self 174 | .client 175 | .get(format!( 176 | "{}/admin/realms/{realm}/components/{id}/sub-component-types", 177 | self.url 178 | )) 179 | .bearer_auth(self.token_supplier.get(&self.url).await?); 180 | if let Some(v) = type_ { 181 | builder = builder.query(&[("type", v)]); 182 | } 183 | let response = builder.send().await?; 184 | Ok(error_check(response).await?.json().await?) 185 | } 186 | } 187 | // not all paths processed 188 | // left 244 189 | -------------------------------------------------------------------------------- /src/rest/mod.rs: -------------------------------------------------------------------------------- 1 | use std::future::Future; 2 | 3 | use async_trait::async_trait; 4 | use serde::{Deserialize, Serialize}; 5 | 6 | use crate::{types::*, KeycloakError}; 7 | 8 | mod default_response; 9 | mod generated_rest; 10 | mod manual_rest; 11 | mod url_enc; 12 | 13 | pub use default_response::DefaultResponse; 14 | 15 | pub struct KeycloakAdmin { 16 | url: String, 17 | client: reqwest::Client, 18 | token_supplier: TS, 19 | } 20 | 21 | #[async_trait] 22 | pub trait KeycloakTokenSupplier { 23 | async fn get(&self, url: &str) -> Result; 24 | } 25 | 26 | #[derive(Clone)] 27 | pub struct KeycloakServiceAccountAdminTokenRetriever { 28 | client_id: String, 29 | client_secret: String, 30 | realm: String, 31 | reqwest_client: reqwest::Client, 32 | } 33 | 34 | #[async_trait] 35 | impl KeycloakTokenSupplier for KeycloakServiceAccountAdminTokenRetriever { 36 | async fn get(&self, url: &str) -> Result { 37 | let admin_token = self.acquire(url).await?; 38 | Ok(admin_token.access_token) 39 | } 40 | } 41 | 42 | impl KeycloakServiceAccountAdminTokenRetriever { 43 | /// Creates a token retriever for a [service account](https://www.keycloak.org/docs/latest/server_development/#authenticating-with-a-service-account) 44 | /// * `client_id` - The client id of a client with the following characteristics: 45 | /// 1. Exists in the **master** realm 46 | /// 2. `confidential` access type 47 | /// 3. `Service Accounts` option is enabled 48 | /// * `client_secret` - The secret credential assigned to the given `client_id` 49 | /// * `client` - A reqwest Client to perform the token retrieval call 50 | pub fn create(client_id: &str, client_secret: &str, client: reqwest::Client) -> Self { 51 | Self { 52 | client_id: client_id.into(), 53 | client_secret: client_secret.into(), 54 | realm: "master".into(), 55 | reqwest_client: client, 56 | } 57 | } 58 | 59 | pub fn create_with_custom_realm( 60 | client_id: &str, 61 | client_secret: &str, 62 | realm: &str, 63 | client: reqwest::Client, 64 | ) -> Self { 65 | Self { 66 | client_id: client_id.into(), 67 | client_secret: client_secret.into(), 68 | realm: realm.into(), 69 | reqwest_client: client, 70 | } 71 | } 72 | 73 | pub async fn acquire(&self, url: &str) -> Result { 74 | let realm = &self.realm; 75 | let response = self 76 | .reqwest_client 77 | .post(format!( 78 | "{url}/realms/{realm}/protocol/openid-connect/token", 79 | )) 80 | .form(&[ 81 | ("client_id", self.client_id.as_str()), 82 | ("client_secret", self.client_secret.as_str()), 83 | ("grant_type", "client_credentials"), 84 | ]) 85 | .send() 86 | .await?; 87 | Ok(error_check(response).await?.json().await?) 88 | } 89 | } 90 | 91 | #[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)] 92 | pub struct KeycloakAdminToken { 93 | access_token: String, 94 | expires_in: usize, 95 | #[serde(rename = "not-before-policy")] 96 | not_before_policy: Option, 97 | refresh_expires_in: Option, 98 | refresh_token: Option, 99 | scope: String, 100 | session_state: Option, 101 | token_type: String, 102 | } 103 | 104 | #[async_trait] 105 | impl KeycloakTokenSupplier for KeycloakAdminToken { 106 | async fn get(&self, _url: &str) -> Result { 107 | Ok(self.access_token.clone()) 108 | } 109 | } 110 | 111 | impl KeycloakAdminToken { 112 | pub async fn acquire( 113 | url: &str, 114 | username: &str, 115 | password: &str, 116 | client: &reqwest::Client, 117 | ) -> Result { 118 | Self::acquire_custom_realm( 119 | url, 120 | username, 121 | password, 122 | "master", 123 | "admin-cli", 124 | "password", 125 | client, 126 | ) 127 | .await 128 | } 129 | 130 | pub async fn acquire_custom_realm( 131 | url: &str, 132 | username: &str, 133 | password: &str, 134 | realm: &str, 135 | client_id: &str, 136 | grant_type: &str, 137 | client: &reqwest::Client, 138 | ) -> Result { 139 | let response = client 140 | .post(format!( 141 | "{url}/realms/{realm}/protocol/openid-connect/token", 142 | )) 143 | .form(&[ 144 | ("username", username), 145 | ("password", password), 146 | ("client_id", client_id), 147 | ("grant_type", grant_type), 148 | ]) 149 | .send() 150 | .await?; 151 | Ok(error_check(response).await?.json().await?) 152 | } 153 | } 154 | 155 | async fn error_check(response: reqwest::Response) -> Result { 156 | if !response.status().is_success() { 157 | let status = response.status().into(); 158 | let text = response.text().await?; 159 | return Err(KeycloakError::HttpFailure { 160 | status, 161 | body: serde_json::from_str(&text).ok(), 162 | text, 163 | }); 164 | } 165 | 166 | Ok(response) 167 | } 168 | 169 | impl KeycloakAdmin { 170 | pub fn new(url: &str, token_supplier: TS, client: reqwest::Client) -> Self { 171 | Self { 172 | url: url.into(), 173 | client, 174 | token_supplier, 175 | } 176 | } 177 | 178 | pub fn realm<'a>(&'a self, realm: &'a str) -> KeycloakRealmAdmin<'a, TS> { 179 | KeycloakRealmAdmin { realm, admin: self } 180 | } 181 | } 182 | 183 | pub struct KeycloakRealmAdmin<'a, TS: KeycloakTokenSupplier> { 184 | pub realm: &'a str, 185 | pub(crate) admin: &'a KeycloakAdmin, 186 | } 187 | 188 | pub trait KeycloakRealmAdminMethod { 189 | type Output; 190 | type Args: Default; 191 | 192 | fn opts( 193 | self, 194 | args: Self::Args, 195 | ) -> impl Future> + Send; 196 | 197 | fn with_default( 198 | self, 199 | f: F, 200 | ) -> impl Future> + Send 201 | where 202 | Self: Sized, 203 | Self::Args: Default, 204 | F: FnOnce(Self::Args) -> Self::Args, 205 | { 206 | self.opts(f(Default::default())) 207 | } 208 | 209 | #[cfg(feature = "builder")] 210 | fn builder<'m>(self) -> crate::builder::Builder<'m, Self> 211 | where 212 | Self: 'm + Sized, 213 | { 214 | From::from(self) 215 | } 216 | } 217 | -------------------------------------------------------------------------------- /src/resource/client_attribute_certificate.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | impl<'a, TS: KeycloakTokenSupplier> KeycloakRealmAdmin<'a, TS> { 4 | //

Client Attribute Certificate

5 | /// Get key info 6 | /// 7 | /// Parameters: 8 | /// 9 | /// - `realm`: realm name (not id!) 10 | /// - `client_uuid`: id of client (not client-id!) 11 | /// - `attr` 12 | /// 13 | /// Resource: `Client Attribute Certificate` 14 | /// 15 | /// `GET /admin/realms/{realm}/clients/{client_uuid}/certificates/{attr}` 16 | /// 17 | /// Documentation: 18 | /// 19 | /// REST method: `GET /admin/realms/{realm}/clients/{client-uuid}/certificates/{attr}` 20 | pub fn clients_with_client_uuid_certificates_with_attr_get( 21 | &'a self, 22 | client_uuid: &'a str, 23 | attr: &'a str, 24 | ) -> impl Future> + use<'a, TS> { 25 | self.admin 26 | .realm_clients_with_client_uuid_certificates_with_attr_get( 27 | self.realm, 28 | client_uuid, 29 | attr, 30 | ) 31 | } 32 | 33 | /// Get a keystore file for the client, containing private key and public certificate 34 | /// 35 | /// Parameters: 36 | /// 37 | /// - `realm`: realm name (not id!) 38 | /// - `client_uuid`: id of client (not client-id!) 39 | /// - `attr` 40 | /// - `body` 41 | /// 42 | /// Resource: `Client Attribute Certificate` 43 | /// 44 | /// `POST /admin/realms/{realm}/clients/{client_uuid}/certificates/{attr}/download` 45 | /// 46 | /// Documentation: 47 | /// 48 | /// REST method: `POST /admin/realms/{realm}/clients/{client-uuid}/certificates/{attr}/download` 49 | pub fn clients_with_client_uuid_certificates_with_attr_download_post( 50 | &'a self, 51 | client_uuid: &'a str, 52 | attr: &'a str, 53 | body: KeyStoreConfig, 54 | ) -> impl Future> + use<'a, TS> { 55 | self.admin 56 | .realm_clients_with_client_uuid_certificates_with_attr_download_post( 57 | self.realm, 58 | client_uuid, 59 | attr, 60 | body, 61 | ) 62 | } 63 | 64 | /// Generate a new certificate with new key pair 65 | /// 66 | /// Parameters: 67 | /// 68 | /// - `realm`: realm name (not id!) 69 | /// - `client_uuid`: id of client (not client-id!) 70 | /// - `attr` 71 | /// 72 | /// Resource: `Client Attribute Certificate` 73 | /// 74 | /// `POST /admin/realms/{realm}/clients/{client_uuid}/certificates/{attr}/generate` 75 | /// 76 | /// Documentation: 77 | /// 78 | /// REST method: `POST /admin/realms/{realm}/clients/{client-uuid}/certificates/{attr}/generate` 79 | pub fn clients_with_client_uuid_certificates_with_attr_generate_post( 80 | &'a self, 81 | client_uuid: &'a str, 82 | attr: &'a str, 83 | ) -> impl Future> + use<'a, TS> { 84 | self.admin 85 | .realm_clients_with_client_uuid_certificates_with_attr_generate_post( 86 | self.realm, 87 | client_uuid, 88 | attr, 89 | ) 90 | } 91 | 92 | /// Generate a new keypair and certificate, and get the private key file 93 | /// 94 | /// Generates a keypair and certificate and serves the private key in a specified keystore format. 95 | /// Only generated public certificate is saved in Keycloak DB - the private key is not. 96 | /// 97 | /// Parameters: 98 | /// 99 | /// - `realm`: realm name (not id!) 100 | /// - `client_uuid`: id of client (not client-id!) 101 | /// - `attr` 102 | /// - `body` 103 | /// 104 | /// Resource: `Client Attribute Certificate` 105 | /// 106 | /// `POST /admin/realms/{realm}/clients/{client_uuid}/certificates/{attr}/generate-and-download` 107 | /// 108 | /// Documentation: 109 | /// 110 | /// REST method: `POST /admin/realms/{realm}/clients/{client-uuid}/certificates/{attr}/generate-and-download` 111 | pub fn clients_with_client_uuid_certificates_with_attr_generate_and_download_post( 112 | &'a self, 113 | client_uuid: &'a str, 114 | attr: &'a str, 115 | body: KeyStoreConfig, 116 | ) -> impl Future> + use<'a, TS> { 117 | self.admin 118 | .realm_clients_with_client_uuid_certificates_with_attr_generate_and_download_post( 119 | self.realm, 120 | client_uuid, 121 | attr, 122 | body, 123 | ) 124 | } 125 | 126 | /// Upload certificate and eventually private key 127 | /// 128 | /// Parameters: 129 | /// 130 | /// - `realm`: realm name (not id!) 131 | /// - `client_uuid`: id of client (not client-id!) 132 | /// - `attr` 133 | /// 134 | /// Resource: `Client Attribute Certificate` 135 | /// 136 | /// `POST /admin/realms/{realm}/clients/{client_uuid}/certificates/{attr}/upload` 137 | /// 138 | /// Documentation: 139 | /// 140 | /// REST method: `POST /admin/realms/{realm}/clients/{client-uuid}/certificates/{attr}/upload` 141 | pub fn clients_with_client_uuid_certificates_with_attr_upload_post( 142 | &'a self, 143 | client_uuid: &'a str, 144 | attr: &'a str, 145 | ) -> impl Future> + use<'a, TS> { 146 | self.admin 147 | .realm_clients_with_client_uuid_certificates_with_attr_upload_post( 148 | self.realm, 149 | client_uuid, 150 | attr, 151 | ) 152 | } 153 | 154 | /// Upload only certificate, not private key 155 | /// 156 | /// Parameters: 157 | /// 158 | /// - `realm`: realm name (not id!) 159 | /// - `client_uuid`: id of client (not client-id!) 160 | /// - `attr` 161 | /// 162 | /// Resource: `Client Attribute Certificate` 163 | /// 164 | /// `POST /admin/realms/{realm}/clients/{client_uuid}/certificates/{attr}/upload-certificate` 165 | /// 166 | /// Documentation: 167 | /// 168 | /// REST method: `POST /admin/realms/{realm}/clients/{client-uuid}/certificates/{attr}/upload-certificate` 169 | pub fn clients_with_client_uuid_certificates_with_attr_upload_certificate_post( 170 | &'a self, 171 | client_uuid: &'a str, 172 | attr: &'a str, 173 | ) -> impl Future> + use<'a, TS> { 174 | self.admin 175 | .realm_clients_with_client_uuid_certificates_with_attr_upload_certificate_post( 176 | self.realm, 177 | client_uuid, 178 | attr, 179 | ) 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /src/resource/client_scopes.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | impl<'a, TS: KeycloakTokenSupplier> KeycloakRealmAdmin<'a, TS> { 4 | //

Client Scopes

5 | /// Get client scopes belonging to the realm Returns a list of client scopes belonging to the realm 6 | /// 7 | /// Parameters: 8 | /// 9 | /// - `realm`: realm name (not id!) 10 | /// 11 | /// Resource: `Client Scopes` 12 | /// 13 | /// `GET /admin/realms/{realm}/client-scopes` 14 | /// 15 | /// Documentation: 16 | pub fn client_scopes_get( 17 | &'a self, 18 | ) -> impl Future, KeycloakError>> + use<'a, TS> 19 | { 20 | self.admin.realm_client_scopes_get(self.realm) 21 | } 22 | 23 | /// Create a new client scope Client Scope’s name must be unique! 24 | /// 25 | /// Parameters: 26 | /// 27 | /// - `realm`: realm name (not id!) 28 | /// - `body` 29 | /// 30 | /// Returns response for future processing. 31 | /// 32 | /// Resource: `Client Scopes` 33 | /// 34 | /// `POST /admin/realms/{realm}/client-scopes` 35 | /// 36 | /// Documentation: 37 | pub fn client_scopes_post( 38 | &'a self, 39 | body: ClientScopeRepresentation, 40 | ) -> impl Future> + use<'a, TS> { 41 | self.admin.realm_client_scopes_post(self.realm, body) 42 | } 43 | 44 | /// Get representation of the client scope 45 | /// 46 | /// Parameters: 47 | /// 48 | /// - `realm`: realm name (not id!) 49 | /// - `client_scope_id` 50 | /// 51 | /// Resource: `Client Scopes` 52 | /// 53 | /// `GET /admin/realms/{realm}/client-scopes/{client_scope_id}` 54 | /// 55 | /// Documentation: 56 | /// 57 | /// REST method: `GET /admin/realms/{realm}/client-scopes/{client-scope-id}` 58 | pub fn client_scopes_with_client_scope_id_get( 59 | &'a self, 60 | client_scope_id: &'a str, 61 | ) -> impl Future> + use<'a, TS> { 62 | self.admin 63 | .realm_client_scopes_with_client_scope_id_get(self.realm, client_scope_id) 64 | } 65 | 66 | /// Update the client scope 67 | /// 68 | /// Parameters: 69 | /// 70 | /// - `realm`: realm name (not id!) 71 | /// - `client_scope_id` 72 | /// - `body` 73 | /// 74 | /// Returns response for future processing. 75 | /// 76 | /// Resource: `Client Scopes` 77 | /// 78 | /// `PUT /admin/realms/{realm}/client-scopes/{client_scope_id}` 79 | /// 80 | /// Documentation: 81 | /// 82 | /// REST method: `PUT /admin/realms/{realm}/client-scopes/{client-scope-id}` 83 | pub fn client_scopes_with_client_scope_id_put( 84 | &'a self, 85 | client_scope_id: &'a str, 86 | body: ClientScopeRepresentation, 87 | ) -> impl Future> + use<'a, TS> { 88 | self.admin 89 | .realm_client_scopes_with_client_scope_id_put(self.realm, client_scope_id, body) 90 | } 91 | 92 | /// Delete the client scope 93 | /// 94 | /// Parameters: 95 | /// 96 | /// - `realm`: realm name (not id!) 97 | /// - `client_scope_id` 98 | /// 99 | /// Returns response for future processing. 100 | /// 101 | /// Resource: `Client Scopes` 102 | /// 103 | /// `DELETE /admin/realms/{realm}/client-scopes/{client_scope_id}` 104 | /// 105 | /// Documentation: 106 | /// 107 | /// REST method: `DELETE /admin/realms/{realm}/client-scopes/{client-scope-id}` 108 | pub fn client_scopes_with_client_scope_id_delete( 109 | &'a self, 110 | client_scope_id: &'a str, 111 | ) -> impl Future> + use<'a, TS> { 112 | self.admin 113 | .realm_client_scopes_with_client_scope_id_delete(self.realm, client_scope_id) 114 | } 115 | 116 | /// Get client scopes belonging to the realm Returns a list of client scopes belonging to the realm 117 | /// 118 | /// Parameters: 119 | /// 120 | /// - `realm`: realm name (not id!) 121 | /// 122 | /// Resource: `Client Scopes` 123 | /// 124 | /// `GET /admin/realms/{realm}/client-templates` 125 | /// 126 | /// Documentation: 127 | pub fn client_templates_get( 128 | &'a self, 129 | ) -> impl Future, KeycloakError>> + use<'a, TS> 130 | { 131 | self.admin.realm_client_templates_get(self.realm) 132 | } 133 | 134 | /// Create a new client scope Client Scope’s name must be unique! 135 | /// 136 | /// Parameters: 137 | /// 138 | /// - `realm`: realm name (not id!) 139 | /// - `body` 140 | /// 141 | /// Returns response for future processing. 142 | /// 143 | /// Resource: `Client Scopes` 144 | /// 145 | /// `POST /admin/realms/{realm}/client-templates` 146 | /// 147 | /// Documentation: 148 | pub fn client_templates_post( 149 | &'a self, 150 | body: ClientScopeRepresentation, 151 | ) -> impl Future> + use<'a, TS> { 152 | self.admin.realm_client_templates_post(self.realm, body) 153 | } 154 | 155 | /// Get representation of the client scope 156 | /// 157 | /// Parameters: 158 | /// 159 | /// - `realm`: realm name (not id!) 160 | /// - `client_scope_id` 161 | /// 162 | /// Resource: `Client Scopes` 163 | /// 164 | /// `GET /admin/realms/{realm}/client-templates/{client_scope_id}` 165 | /// 166 | /// Documentation: 167 | /// 168 | /// REST method: `GET /admin/realms/{realm}/client-templates/{client-scope-id}` 169 | pub fn client_templates_with_client_scope_id_get( 170 | &'a self, 171 | client_scope_id: &'a str, 172 | ) -> impl Future> + use<'a, TS> { 173 | self.admin 174 | .realm_client_templates_with_client_scope_id_get(self.realm, client_scope_id) 175 | } 176 | 177 | /// Update the client scope 178 | /// 179 | /// Parameters: 180 | /// 181 | /// - `realm`: realm name (not id!) 182 | /// - `client_scope_id` 183 | /// - `body` 184 | /// 185 | /// Returns response for future processing. 186 | /// 187 | /// Resource: `Client Scopes` 188 | /// 189 | /// `PUT /admin/realms/{realm}/client-templates/{client_scope_id}` 190 | /// 191 | /// Documentation: 192 | /// 193 | /// REST method: `PUT /admin/realms/{realm}/client-templates/{client-scope-id}` 194 | pub fn client_templates_with_client_scope_id_put( 195 | &'a self, 196 | client_scope_id: &'a str, 197 | body: ClientScopeRepresentation, 198 | ) -> impl Future> + use<'a, TS> { 199 | self.admin.realm_client_templates_with_client_scope_id_put( 200 | self.realm, 201 | client_scope_id, 202 | body, 203 | ) 204 | } 205 | 206 | /// Delete the client scope 207 | /// 208 | /// Parameters: 209 | /// 210 | /// - `realm`: realm name (not id!) 211 | /// - `client_scope_id` 212 | /// 213 | /// Returns response for future processing. 214 | /// 215 | /// Resource: `Client Scopes` 216 | /// 217 | /// `DELETE /admin/realms/{realm}/client-templates/{client_scope_id}` 218 | /// 219 | /// Documentation: 220 | /// 221 | /// REST method: `DELETE /admin/realms/{realm}/client-templates/{client-scope-id}` 222 | pub fn client_templates_with_client_scope_id_delete( 223 | &'a self, 224 | client_scope_id: &'a str, 225 | ) -> impl Future> + use<'a, TS> { 226 | self.admin 227 | .realm_client_templates_with_client_scope_id_delete(self.realm, client_scope_id) 228 | } 229 | } 230 | -------------------------------------------------------------------------------- /src/resource/component.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | impl<'a, TS: KeycloakTokenSupplier> KeycloakRealmAdmin<'a, TS> { 4 | //

Component

5 | /// Parameters: 6 | /// 7 | /// - `realm`: realm name (not id!) 8 | /// - `name` 9 | /// - `parent` 10 | /// - `type_` 11 | /// 12 | /// Resource: `Component` 13 | /// 14 | /// `GET /admin/realms/{realm}/components` 15 | /// 16 | /// Documentation: 17 | pub fn components_get(&'a self) -> RealmComponentsGet<'a, TS> { 18 | RealmComponentsGet { realm_admin: self } 19 | } 20 | 21 | /// Parameters: 22 | /// 23 | /// - `realm`: realm name (not id!) 24 | /// - `body` 25 | /// 26 | /// Returns response for future processing. 27 | /// 28 | /// Resource: `Component` 29 | /// 30 | /// `POST /admin/realms/{realm}/components` 31 | /// 32 | /// Documentation: 33 | pub fn components_post( 34 | &'a self, 35 | body: ComponentRepresentation, 36 | ) -> impl Future> + use<'a, TS> { 37 | self.admin.realm_components_post(self.realm, body) 38 | } 39 | 40 | /// Parameters: 41 | /// 42 | /// - `realm`: realm name (not id!) 43 | /// - `id` 44 | /// 45 | /// Resource: `Component` 46 | /// 47 | /// `GET /admin/realms/{realm}/components/{id}` 48 | /// 49 | /// Documentation: 50 | pub fn components_with_id_get( 51 | &'a self, 52 | id: &'a str, 53 | ) -> impl Future> + use<'a, TS> { 54 | self.admin.realm_components_with_id_get(self.realm, id) 55 | } 56 | 57 | /// Parameters: 58 | /// 59 | /// - `realm`: realm name (not id!) 60 | /// - `id` 61 | /// - `body` 62 | /// 63 | /// Returns response for future processing. 64 | /// 65 | /// Resource: `Component` 66 | /// 67 | /// `PUT /admin/realms/{realm}/components/{id}` 68 | /// 69 | /// Documentation: 70 | pub fn components_with_id_put( 71 | &'a self, 72 | id: &'a str, 73 | body: ComponentRepresentation, 74 | ) -> impl Future> + use<'a, TS> { 75 | self.admin 76 | .realm_components_with_id_put(self.realm, id, body) 77 | } 78 | 79 | /// Parameters: 80 | /// 81 | /// - `realm`: realm name (not id!) 82 | /// - `id` 83 | /// 84 | /// Returns response for future processing. 85 | /// 86 | /// Resource: `Component` 87 | /// 88 | /// `DELETE /admin/realms/{realm}/components/{id}` 89 | /// 90 | /// Documentation: 91 | pub fn components_with_id_delete( 92 | &'a self, 93 | id: &'a str, 94 | ) -> impl Future> + use<'a, TS> { 95 | self.admin.realm_components_with_id_delete(self.realm, id) 96 | } 97 | 98 | /// List of subcomponent types that are available to configure for a particular parent component. 99 | /// 100 | /// Parameters: 101 | /// 102 | /// - `realm`: realm name (not id!) 103 | /// - `id` 104 | /// - `type_` 105 | /// 106 | /// Resource: `Component` 107 | /// 108 | /// `GET /admin/realms/{realm}/components/{id}/sub-component-types` 109 | /// 110 | /// Documentation: 111 | pub fn components_with_id_sub_component_types_get( 112 | &'a self, 113 | id: &'a str, 114 | ) -> RealmComponentsWithIdSubComponentTypesGet<'a, TS> { 115 | RealmComponentsWithIdSubComponentTypesGet { 116 | realm_admin: self, 117 | id, 118 | } 119 | } 120 | } 121 | 122 | //

Component

123 | pub struct RealmComponentsGet<'a, TS: KeycloakTokenSupplier> { 124 | /// Realm admin client 125 | pub realm_admin: &'a KeycloakRealmAdmin<'a, TS>, 126 | } 127 | 128 | #[derive(Default)] 129 | pub struct RealmComponentsGetArgs { 130 | pub name: Option, 131 | pub parent: Option, 132 | pub type_: Option, 133 | } 134 | 135 | impl<'a, TS: KeycloakTokenSupplier + Send + Sync> KeycloakRealmAdminMethod 136 | for RealmComponentsGet<'a, TS> 137 | { 138 | type Output = TypeVec; 139 | type Args = RealmComponentsGetArgs; 140 | 141 | fn opts( 142 | self, 143 | Self::Args { 144 | name, 145 | parent, 146 | type_, 147 | }: Self::Args, 148 | ) -> impl Future> + use<'a, TS> { 149 | self.realm_admin 150 | .admin 151 | .realm_components_get(self.realm_admin.realm, name, parent, type_) 152 | } 153 | } 154 | 155 | impl<'a, TS> IntoFuture for RealmComponentsGet<'a, TS> 156 | where 157 | TS: KeycloakTokenSupplier + Send + Sync, 158 | { 159 | type Output = Result, KeycloakError>; 160 | type IntoFuture = Pin + Send>>; 161 | fn into_future(self) -> Self::IntoFuture { 162 | Box::pin(self.opts(Default::default())) 163 | } 164 | } 165 | 166 | pub struct RealmComponentsWithIdSubComponentTypesGet<'a, TS: KeycloakTokenSupplier> { 167 | /// Realm admin client 168 | pub realm_admin: &'a KeycloakRealmAdmin<'a, TS>, 169 | pub id: &'a str, 170 | } 171 | 172 | #[derive(Default)] 173 | pub struct RealmComponentsWithIdSubComponentTypesGetArgs { 174 | pub type_: Option, 175 | } 176 | 177 | impl<'a, TS: KeycloakTokenSupplier + Send + Sync> KeycloakRealmAdminMethod 178 | for RealmComponentsWithIdSubComponentTypesGet<'a, TS> 179 | { 180 | type Output = TypeVec; 181 | type Args = RealmComponentsWithIdSubComponentTypesGetArgs; 182 | 183 | fn opts( 184 | self, 185 | Self::Args { type_ }: Self::Args, 186 | ) -> impl Future> + use<'a, TS> { 187 | self.realm_admin 188 | .admin 189 | .realm_components_with_id_sub_component_types_get( 190 | self.realm_admin.realm, 191 | self.id, 192 | type_, 193 | ) 194 | } 195 | } 196 | 197 | impl<'a, TS> IntoFuture for RealmComponentsWithIdSubComponentTypesGet<'a, TS> 198 | where 199 | TS: KeycloakTokenSupplier + Send + Sync, 200 | { 201 | type Output = Result, KeycloakError>; 202 | type IntoFuture = Pin + Send>>; 203 | fn into_future(self) -> Self::IntoFuture { 204 | Box::pin(self.opts(Default::default())) 205 | } 206 | } 207 | 208 | #[cfg(feature = "builder")] 209 | mod builder { 210 | use crate::builder::Builder; 211 | 212 | use super::*; 213 | 214 | //

Component

215 | impl<'a, TS> RealmComponentsGet<'a, TS> 216 | where 217 | TS: KeycloakTokenSupplier + Send + Sync, 218 | { 219 | pub fn name(self, value: impl Into>) -> Builder<'a, Self> { 220 | self.builder().name(value) 221 | } 222 | pub fn parent(self, value: impl Into>) -> Builder<'a, Self> { 223 | self.builder().parent(value) 224 | } 225 | pub fn type_(self, value: impl Into>) -> Builder<'a, Self> { 226 | self.builder().type_(value) 227 | } 228 | } 229 | 230 | impl Builder<'_, RealmComponentsGet<'_, TS>> 231 | where 232 | TS: KeycloakTokenSupplier + Send + Sync, 233 | { 234 | pub fn name(mut self, value: impl Into>) -> Self { 235 | self.args.name = value.into(); 236 | self 237 | } 238 | pub fn parent(mut self, value: impl Into>) -> Self { 239 | self.args.parent = value.into(); 240 | self 241 | } 242 | pub fn type_(mut self, value: impl Into>) -> Self { 243 | self.args.type_ = value.into(); 244 | self 245 | } 246 | } 247 | 248 | impl<'a, TS> RealmComponentsWithIdSubComponentTypesGet<'a, TS> 249 | where 250 | TS: KeycloakTokenSupplier + Send + Sync, 251 | { 252 | pub fn type_(self, value: impl Into>) -> Builder<'a, Self> { 253 | self.builder().type_(value) 254 | } 255 | } 256 | 257 | impl Builder<'_, RealmComponentsWithIdSubComponentTypesGet<'_, TS>> 258 | where 259 | TS: KeycloakTokenSupplier + Send + Sync, 260 | { 261 | pub fn type_(mut self, value: impl Into>) -> Self { 262 | self.args.type_ = value.into(); 263 | self 264 | } 265 | } 266 | } 267 | -------------------------------------------------------------------------------- /src/rest/generated_rest/client_attribute_certificate.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | impl KeycloakAdmin { 4 | //

Client Attribute Certificate

5 | 6 | /// Get key info 7 | /// 8 | /// Parameters: 9 | /// 10 | /// - `realm`: realm name (not id!) 11 | /// - `client_uuid`: id of client (not client-id!) 12 | /// - `attr` 13 | /// 14 | /// Resource: `Client Attribute Certificate` 15 | /// 16 | /// `GET /admin/realms/{realm}/clients/{client_uuid}/certificates/{attr}` 17 | /// 18 | /// Documentation: 19 | /// 20 | /// REST method: `GET /admin/realms/{realm}/clients/{client-uuid}/certificates/{attr}` 21 | pub async fn realm_clients_with_client_uuid_certificates_with_attr_get( 22 | &self, 23 | realm: &str, 24 | client_uuid: &str, 25 | attr: &str, 26 | ) -> Result { 27 | let realm = p(realm); 28 | let client_uuid = p(client_uuid); 29 | let attr = p(attr); 30 | let builder = self 31 | .client 32 | .get(format!( 33 | "{}/admin/realms/{realm}/clients/{client_uuid}/certificates/{attr}", 34 | self.url 35 | )) 36 | .bearer_auth(self.token_supplier.get(&self.url).await?); 37 | let response = builder.send().await?; 38 | Ok(error_check(response).await?.json().await?) 39 | } 40 | 41 | /// Get a keystore file for the client, containing private key and public certificate 42 | /// 43 | /// Parameters: 44 | /// 45 | /// - `realm`: realm name (not id!) 46 | /// - `client_uuid`: id of client (not client-id!) 47 | /// - `attr` 48 | /// - `body` 49 | /// 50 | /// Resource: `Client Attribute Certificate` 51 | /// 52 | /// `POST /admin/realms/{realm}/clients/{client_uuid}/certificates/{attr}/download` 53 | /// 54 | /// Documentation: 55 | /// 56 | /// REST method: `POST /admin/realms/{realm}/clients/{client-uuid}/certificates/{attr}/download` 57 | pub async fn realm_clients_with_client_uuid_certificates_with_attr_download_post( 58 | &self, 59 | realm: &str, 60 | client_uuid: &str, 61 | attr: &str, 62 | body: KeyStoreConfig, 63 | ) -> Result { 64 | let realm = p(realm); 65 | let client_uuid = p(client_uuid); 66 | let attr = p(attr); 67 | let builder = self 68 | .client 69 | .post(format!( 70 | "{}/admin/realms/{realm}/clients/{client_uuid}/certificates/{attr}/download", 71 | self.url 72 | )) 73 | .json(&body) 74 | .bearer_auth(self.token_supplier.get(&self.url).await?); 75 | let response = builder.send().await?; 76 | Ok(error_check(response).await?.text().await.map(From::from)?) 77 | } 78 | 79 | /// Generate a new certificate with new key pair 80 | /// 81 | /// Parameters: 82 | /// 83 | /// - `realm`: realm name (not id!) 84 | /// - `client_uuid`: id of client (not client-id!) 85 | /// - `attr` 86 | /// 87 | /// Resource: `Client Attribute Certificate` 88 | /// 89 | /// `POST /admin/realms/{realm}/clients/{client_uuid}/certificates/{attr}/generate` 90 | /// 91 | /// Documentation: 92 | /// 93 | /// REST method: `POST /admin/realms/{realm}/clients/{client-uuid}/certificates/{attr}/generate` 94 | pub async fn realm_clients_with_client_uuid_certificates_with_attr_generate_post( 95 | &self, 96 | realm: &str, 97 | client_uuid: &str, 98 | attr: &str, 99 | ) -> Result { 100 | let realm = p(realm); 101 | let client_uuid = p(client_uuid); 102 | let attr = p(attr); 103 | let builder = self 104 | .client 105 | .post(format!( 106 | "{}/admin/realms/{realm}/clients/{client_uuid}/certificates/{attr}/generate", 107 | self.url 108 | )) 109 | .bearer_auth(self.token_supplier.get(&self.url).await?); 110 | let response = builder.send().await?; 111 | Ok(error_check(response).await?.json().await?) 112 | } 113 | 114 | /// Generate a new keypair and certificate, and get the private key file 115 | /// 116 | /// Generates a keypair and certificate and serves the private key in a specified keystore format. 117 | /// Only generated public certificate is saved in Keycloak DB - the private key is not. 118 | /// 119 | /// Parameters: 120 | /// 121 | /// - `realm`: realm name (not id!) 122 | /// - `client_uuid`: id of client (not client-id!) 123 | /// - `attr` 124 | /// - `body` 125 | /// 126 | /// Resource: `Client Attribute Certificate` 127 | /// 128 | /// `POST /admin/realms/{realm}/clients/{client_uuid}/certificates/{attr}/generate-and-download` 129 | /// 130 | /// Documentation: 131 | /// 132 | /// REST method: `POST /admin/realms/{realm}/clients/{client-uuid}/certificates/{attr}/generate-and-download` 133 | pub async fn realm_clients_with_client_uuid_certificates_with_attr_generate_and_download_post( 134 | &self, 135 | realm: &str, 136 | client_uuid: &str, 137 | attr: &str, 138 | body: KeyStoreConfig, 139 | ) -> Result { 140 | let realm = p(realm); 141 | let client_uuid = p(client_uuid); 142 | let attr = p(attr); 143 | let builder = self 144 | .client 145 | .post(format!( 146 | "{}/admin/realms/{realm}/clients/{client_uuid}/certificates/{attr}/generate-and-download", 147 | self.url 148 | )) 149 | .json(&body) 150 | .bearer_auth(self.token_supplier.get(&self.url).await?); 151 | let response = builder.send().await?; 152 | Ok(error_check(response).await?.text().await.map(From::from)?) 153 | } 154 | 155 | /// Upload certificate and eventually private key 156 | /// 157 | /// Parameters: 158 | /// 159 | /// - `realm`: realm name (not id!) 160 | /// - `client_uuid`: id of client (not client-id!) 161 | /// - `attr` 162 | /// 163 | /// Resource: `Client Attribute Certificate` 164 | /// 165 | /// `POST /admin/realms/{realm}/clients/{client_uuid}/certificates/{attr}/upload` 166 | /// 167 | /// Documentation: 168 | /// 169 | /// REST method: `POST /admin/realms/{realm}/clients/{client-uuid}/certificates/{attr}/upload` 170 | pub async fn realm_clients_with_client_uuid_certificates_with_attr_upload_post( 171 | &self, 172 | realm: &str, 173 | client_uuid: &str, 174 | attr: &str, 175 | ) -> Result { 176 | let realm = p(realm); 177 | let client_uuid = p(client_uuid); 178 | let attr = p(attr); 179 | let builder = self 180 | .client 181 | .post(format!( 182 | "{}/admin/realms/{realm}/clients/{client_uuid}/certificates/{attr}/upload", 183 | self.url 184 | )) 185 | .bearer_auth(self.token_supplier.get(&self.url).await?); 186 | let response = builder.send().await?; 187 | Ok(error_check(response).await?.json().await?) 188 | } 189 | 190 | /// Upload only certificate, not private key 191 | /// 192 | /// Parameters: 193 | /// 194 | /// - `realm`: realm name (not id!) 195 | /// - `client_uuid`: id of client (not client-id!) 196 | /// - `attr` 197 | /// 198 | /// Resource: `Client Attribute Certificate` 199 | /// 200 | /// `POST /admin/realms/{realm}/clients/{client_uuid}/certificates/{attr}/upload-certificate` 201 | /// 202 | /// Documentation: 203 | /// 204 | /// REST method: `POST /admin/realms/{realm}/clients/{client-uuid}/certificates/{attr}/upload-certificate` 205 | pub async fn realm_clients_with_client_uuid_certificates_with_attr_upload_certificate_post( 206 | &self, 207 | realm: &str, 208 | client_uuid: &str, 209 | attr: &str, 210 | ) -> Result { 211 | let realm = p(realm); 212 | let client_uuid = p(client_uuid); 213 | let attr = p(attr); 214 | let builder = self 215 | .client 216 | .post(format!( 217 | "{}/admin/realms/{realm}/clients/{client_uuid}/certificates/{attr}/upload-certificate", 218 | self.url 219 | )) 220 | .bearer_auth(self.token_supplier.get(&self.url).await?); 221 | let response = builder.send().await?; 222 | Ok(error_check(response).await?.json().await?) 223 | } 224 | } 225 | // not all paths processed 226 | // left 241 227 | -------------------------------------------------------------------------------- /src/rest/generated_rest/client_scopes.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | impl KeycloakAdmin { 4 | //

Client Scopes

5 | 6 | /// Get client scopes belonging to the realm Returns a list of client scopes belonging to the realm 7 | /// 8 | /// Parameters: 9 | /// 10 | /// - `realm`: realm name (not id!) 11 | /// 12 | /// Resource: `Client Scopes` 13 | /// 14 | /// `GET /admin/realms/{realm}/client-scopes` 15 | /// 16 | /// Documentation: 17 | pub async fn realm_client_scopes_get( 18 | &self, 19 | realm: &str, 20 | ) -> Result, KeycloakError> { 21 | let realm = p(realm); 22 | let builder = self 23 | .client 24 | .get(format!("{}/admin/realms/{realm}/client-scopes", self.url)) 25 | .bearer_auth(self.token_supplier.get(&self.url).await?); 26 | let response = builder.send().await?; 27 | Ok(error_check(response).await?.json().await?) 28 | } 29 | 30 | /// Create a new client scope Client Scope’s name must be unique! 31 | /// 32 | /// Parameters: 33 | /// 34 | /// - `realm`: realm name (not id!) 35 | /// - `body` 36 | /// 37 | /// Returns response for future processing. 38 | /// 39 | /// Resource: `Client Scopes` 40 | /// 41 | /// `POST /admin/realms/{realm}/client-scopes` 42 | /// 43 | /// Documentation: 44 | pub async fn realm_client_scopes_post( 45 | &self, 46 | realm: &str, 47 | body: ClientScopeRepresentation, 48 | ) -> Result { 49 | let realm = p(realm); 50 | let builder = self 51 | .client 52 | .post(format!("{}/admin/realms/{realm}/client-scopes", self.url)) 53 | .json(&body) 54 | .bearer_auth(self.token_supplier.get(&self.url).await?); 55 | let response = builder.send().await?; 56 | error_check(response).await.map(From::from) 57 | } 58 | 59 | /// Get representation of the client scope 60 | /// 61 | /// Parameters: 62 | /// 63 | /// - `realm`: realm name (not id!) 64 | /// - `client_scope_id` 65 | /// 66 | /// Resource: `Client Scopes` 67 | /// 68 | /// `GET /admin/realms/{realm}/client-scopes/{client_scope_id}` 69 | /// 70 | /// Documentation: 71 | /// 72 | /// REST method: `GET /admin/realms/{realm}/client-scopes/{client-scope-id}` 73 | pub async fn realm_client_scopes_with_client_scope_id_get( 74 | &self, 75 | realm: &str, 76 | client_scope_id: &str, 77 | ) -> Result { 78 | let realm = p(realm); 79 | let client_scope_id = p(client_scope_id); 80 | let builder = self 81 | .client 82 | .get(format!( 83 | "{}/admin/realms/{realm}/client-scopes/{client_scope_id}", 84 | self.url 85 | )) 86 | .bearer_auth(self.token_supplier.get(&self.url).await?); 87 | let response = builder.send().await?; 88 | Ok(error_check(response).await?.json().await?) 89 | } 90 | 91 | /// Update the client scope 92 | /// 93 | /// Parameters: 94 | /// 95 | /// - `realm`: realm name (not id!) 96 | /// - `client_scope_id` 97 | /// - `body` 98 | /// 99 | /// Returns response for future processing. 100 | /// 101 | /// Resource: `Client Scopes` 102 | /// 103 | /// `PUT /admin/realms/{realm}/client-scopes/{client_scope_id}` 104 | /// 105 | /// Documentation: 106 | /// 107 | /// REST method: `PUT /admin/realms/{realm}/client-scopes/{client-scope-id}` 108 | pub async fn realm_client_scopes_with_client_scope_id_put( 109 | &self, 110 | realm: &str, 111 | client_scope_id: &str, 112 | body: ClientScopeRepresentation, 113 | ) -> Result { 114 | let realm = p(realm); 115 | let client_scope_id = p(client_scope_id); 116 | let builder = self 117 | .client 118 | .put(format!( 119 | "{}/admin/realms/{realm}/client-scopes/{client_scope_id}", 120 | self.url 121 | )) 122 | .json(&body) 123 | .bearer_auth(self.token_supplier.get(&self.url).await?); 124 | let response = builder.send().await?; 125 | error_check(response).await.map(From::from) 126 | } 127 | 128 | /// Delete the client scope 129 | /// 130 | /// Parameters: 131 | /// 132 | /// - `realm`: realm name (not id!) 133 | /// - `client_scope_id` 134 | /// 135 | /// Returns response for future processing. 136 | /// 137 | /// Resource: `Client Scopes` 138 | /// 139 | /// `DELETE /admin/realms/{realm}/client-scopes/{client_scope_id}` 140 | /// 141 | /// Documentation: 142 | /// 143 | /// REST method: `DELETE /admin/realms/{realm}/client-scopes/{client-scope-id}` 144 | pub async fn realm_client_scopes_with_client_scope_id_delete( 145 | &self, 146 | realm: &str, 147 | client_scope_id: &str, 148 | ) -> Result { 149 | let realm = p(realm); 150 | let client_scope_id = p(client_scope_id); 151 | let builder = self 152 | .client 153 | .delete(format!( 154 | "{}/admin/realms/{realm}/client-scopes/{client_scope_id}", 155 | self.url 156 | )) 157 | .bearer_auth(self.token_supplier.get(&self.url).await?); 158 | let response = builder.send().await?; 159 | error_check(response).await.map(From::from) 160 | } 161 | 162 | /// Get client scopes belonging to the realm Returns a list of client scopes belonging to the realm 163 | /// 164 | /// Parameters: 165 | /// 166 | /// - `realm`: realm name (not id!) 167 | /// 168 | /// Resource: `Client Scopes` 169 | /// 170 | /// `GET /admin/realms/{realm}/client-templates` 171 | /// 172 | /// Documentation: 173 | pub async fn realm_client_templates_get( 174 | &self, 175 | realm: &str, 176 | ) -> Result, KeycloakError> { 177 | let realm = p(realm); 178 | let builder = self 179 | .client 180 | .get(format!( 181 | "{}/admin/realms/{realm}/client-templates", 182 | self.url 183 | )) 184 | .bearer_auth(self.token_supplier.get(&self.url).await?); 185 | let response = builder.send().await?; 186 | Ok(error_check(response).await?.json().await?) 187 | } 188 | 189 | /// Create a new client scope Client Scope’s name must be unique! 190 | /// 191 | /// Parameters: 192 | /// 193 | /// - `realm`: realm name (not id!) 194 | /// - `body` 195 | /// 196 | /// Returns response for future processing. 197 | /// 198 | /// Resource: `Client Scopes` 199 | /// 200 | /// `POST /admin/realms/{realm}/client-templates` 201 | /// 202 | /// Documentation: 203 | pub async fn realm_client_templates_post( 204 | &self, 205 | realm: &str, 206 | body: ClientScopeRepresentation, 207 | ) -> Result { 208 | let realm = p(realm); 209 | let builder = self 210 | .client 211 | .post(format!( 212 | "{}/admin/realms/{realm}/client-templates", 213 | self.url 214 | )) 215 | .json(&body) 216 | .bearer_auth(self.token_supplier.get(&self.url).await?); 217 | let response = builder.send().await?; 218 | error_check(response).await.map(From::from) 219 | } 220 | 221 | /// Get representation of the client scope 222 | /// 223 | /// Parameters: 224 | /// 225 | /// - `realm`: realm name (not id!) 226 | /// - `client_scope_id` 227 | /// 228 | /// Resource: `Client Scopes` 229 | /// 230 | /// `GET /admin/realms/{realm}/client-templates/{client_scope_id}` 231 | /// 232 | /// Documentation: 233 | /// 234 | /// REST method: `GET /admin/realms/{realm}/client-templates/{client-scope-id}` 235 | pub async fn realm_client_templates_with_client_scope_id_get( 236 | &self, 237 | realm: &str, 238 | client_scope_id: &str, 239 | ) -> Result { 240 | let realm = p(realm); 241 | let client_scope_id = p(client_scope_id); 242 | let builder = self 243 | .client 244 | .get(format!( 245 | "{}/admin/realms/{realm}/client-templates/{client_scope_id}", 246 | self.url 247 | )) 248 | .bearer_auth(self.token_supplier.get(&self.url).await?); 249 | let response = builder.send().await?; 250 | Ok(error_check(response).await?.json().await?) 251 | } 252 | 253 | /// Update the client scope 254 | /// 255 | /// Parameters: 256 | /// 257 | /// - `realm`: realm name (not id!) 258 | /// - `client_scope_id` 259 | /// - `body` 260 | /// 261 | /// Returns response for future processing. 262 | /// 263 | /// Resource: `Client Scopes` 264 | /// 265 | /// `PUT /admin/realms/{realm}/client-templates/{client_scope_id}` 266 | /// 267 | /// Documentation: 268 | /// 269 | /// REST method: `PUT /admin/realms/{realm}/client-templates/{client-scope-id}` 270 | pub async fn realm_client_templates_with_client_scope_id_put( 271 | &self, 272 | realm: &str, 273 | client_scope_id: &str, 274 | body: ClientScopeRepresentation, 275 | ) -> Result { 276 | let realm = p(realm); 277 | let client_scope_id = p(client_scope_id); 278 | let builder = self 279 | .client 280 | .put(format!( 281 | "{}/admin/realms/{realm}/client-templates/{client_scope_id}", 282 | self.url 283 | )) 284 | .json(&body) 285 | .bearer_auth(self.token_supplier.get(&self.url).await?); 286 | let response = builder.send().await?; 287 | error_check(response).await.map(From::from) 288 | } 289 | 290 | /// Delete the client scope 291 | /// 292 | /// Parameters: 293 | /// 294 | /// - `realm`: realm name (not id!) 295 | /// - `client_scope_id` 296 | /// 297 | /// Returns response for future processing. 298 | /// 299 | /// Resource: `Client Scopes` 300 | /// 301 | /// `DELETE /admin/realms/{realm}/client-templates/{client_scope_id}` 302 | /// 303 | /// Documentation: 304 | /// 305 | /// REST method: `DELETE /admin/realms/{realm}/client-templates/{client-scope-id}` 306 | pub async fn realm_client_templates_with_client_scope_id_delete( 307 | &self, 308 | realm: &str, 309 | client_scope_id: &str, 310 | ) -> Result { 311 | let realm = p(realm); 312 | let client_scope_id = p(client_scope_id); 313 | let builder = self 314 | .client 315 | .delete(format!( 316 | "{}/admin/realms/{realm}/client-templates/{client_scope_id}", 317 | self.url 318 | )) 319 | .bearer_auth(self.token_supplier.get(&self.url).await?); 320 | let response = builder.send().await?; 321 | error_check(response).await.map(From::from) 322 | } 323 | } 324 | // not all paths processed 325 | // left 243 326 | -------------------------------------------------------------------------------- /src/resource/roles_by_id.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | impl<'a, TS: KeycloakTokenSupplier> KeycloakRealmAdmin<'a, TS> { 4 | //

Roles (by ID)

5 | /// Get a specific role's representation 6 | /// 7 | /// Parameters: 8 | /// 9 | /// - `realm`: realm name (not id!) 10 | /// - `role_id`: id of role 11 | /// 12 | /// Resource: `Roles (by ID)` 13 | /// 14 | /// `GET /admin/realms/{realm}/roles-by-id/{role_id}` 15 | /// 16 | /// Documentation: 17 | /// 18 | /// REST method: `GET /admin/realms/{realm}/roles-by-id/{role-id}` 19 | pub fn roles_by_id_with_role_id_get( 20 | &'a self, 21 | role_id: &'a str, 22 | ) -> impl Future> + use<'a, TS> { 23 | self.admin 24 | .realm_roles_by_id_with_role_id_get(self.realm, role_id) 25 | } 26 | 27 | /// Update the role 28 | /// 29 | /// Parameters: 30 | /// 31 | /// - `realm`: realm name (not id!) 32 | /// - `role_id`: id of role 33 | /// - `body` 34 | /// 35 | /// Returns response for future processing. 36 | /// 37 | /// Resource: `Roles (by ID)` 38 | /// 39 | /// `PUT /admin/realms/{realm}/roles-by-id/{role_id}` 40 | /// 41 | /// Documentation: 42 | /// 43 | /// REST method: `PUT /admin/realms/{realm}/roles-by-id/{role-id}` 44 | pub fn roles_by_id_with_role_id_put( 45 | &'a self, 46 | role_id: &'a str, 47 | body: RoleRepresentation, 48 | ) -> impl Future> + use<'a, TS> { 49 | self.admin 50 | .realm_roles_by_id_with_role_id_put(self.realm, role_id, body) 51 | } 52 | 53 | /// Delete the role 54 | /// 55 | /// Parameters: 56 | /// 57 | /// - `realm`: realm name (not id!) 58 | /// - `role_id`: id of role 59 | /// 60 | /// Returns response for future processing. 61 | /// 62 | /// Resource: `Roles (by ID)` 63 | /// 64 | /// `DELETE /admin/realms/{realm}/roles-by-id/{role_id}` 65 | /// 66 | /// Documentation: 67 | /// 68 | /// REST method: `DELETE /admin/realms/{realm}/roles-by-id/{role-id}` 69 | pub fn roles_by_id_with_role_id_delete( 70 | &'a self, 71 | role_id: &'a str, 72 | ) -> impl Future> + use<'a, TS> { 73 | self.admin 74 | .realm_roles_by_id_with_role_id_delete(self.realm, role_id) 75 | } 76 | 77 | /// Get role's children Returns a set of role's children provided the role is a composite. 78 | /// 79 | /// Parameters: 80 | /// 81 | /// - `realm`: realm name (not id!) 82 | /// - `role_id` 83 | /// - `first` 84 | /// - `max` 85 | /// - `search` 86 | /// 87 | /// Resource: `Roles (by ID)` 88 | /// 89 | /// `GET /admin/realms/{realm}/roles-by-id/{role_id}/composites` 90 | /// 91 | /// Documentation: 92 | /// 93 | /// REST method: `GET /admin/realms/{realm}/roles-by-id/{role-id}/composites` 94 | pub fn roles_by_id_with_role_id_composites_get( 95 | &'a self, 96 | role_id: &'a str, 97 | ) -> RealmRolesByIdWithRoleIdCompositesGet<'a, TS> { 98 | RealmRolesByIdWithRoleIdCompositesGet { 99 | realm_admin: self, 100 | role_id, 101 | } 102 | } 103 | 104 | /// Make the role a composite role by associating some child roles 105 | /// 106 | /// Parameters: 107 | /// 108 | /// - `realm`: realm name (not id!) 109 | /// - `role_id` 110 | /// - `body` 111 | /// 112 | /// Returns response for future processing. 113 | /// 114 | /// Resource: `Roles (by ID)` 115 | /// 116 | /// `POST /admin/realms/{realm}/roles-by-id/{role_id}/composites` 117 | /// 118 | /// Documentation: 119 | /// 120 | /// REST method: `POST /admin/realms/{realm}/roles-by-id/{role-id}/composites` 121 | pub fn roles_by_id_with_role_id_composites_post( 122 | &'a self, 123 | role_id: &'a str, 124 | body: Vec, 125 | ) -> impl Future> + use<'a, TS> { 126 | self.admin 127 | .realm_roles_by_id_with_role_id_composites_post(self.realm, role_id, body) 128 | } 129 | 130 | /// Remove a set of roles from the role's composite 131 | /// 132 | /// Parameters: 133 | /// 134 | /// - `realm`: realm name (not id!) 135 | /// - `role_id`: Role id 136 | /// - `body` 137 | /// 138 | /// Returns response for future processing. 139 | /// 140 | /// Resource: `Roles (by ID)` 141 | /// 142 | /// `DELETE /admin/realms/{realm}/roles-by-id/{role_id}/composites` 143 | /// 144 | /// Documentation: 145 | /// 146 | /// REST method: `DELETE /admin/realms/{realm}/roles-by-id/{role-id}/composites` 147 | pub fn roles_by_id_with_role_id_composites_delete( 148 | &'a self, 149 | role_id: &'a str, 150 | body: Vec, 151 | ) -> impl Future> + use<'a, TS> { 152 | self.admin 153 | .realm_roles_by_id_with_role_id_composites_delete(self.realm, role_id, body) 154 | } 155 | 156 | /// Get client-level roles for the client that are in the role's composite 157 | /// 158 | /// Parameters: 159 | /// 160 | /// - `realm`: realm name (not id!) 161 | /// - `client_uuid` 162 | /// - `role_id` 163 | /// 164 | /// Resource: `Roles (by ID)` 165 | /// 166 | /// `GET /admin/realms/{realm}/roles-by-id/{role_id}/composites/clients/{client_uuid}` 167 | /// 168 | /// Documentation: 169 | /// 170 | /// REST method: `GET /admin/realms/{realm}/roles-by-id/{role-id}/composites/clients/{clientUuid}` 171 | pub fn roles_by_id_with_role_id_composites_clients_with_client_uuid_get( 172 | &'a self, 173 | client_uuid: &'a str, 174 | role_id: &'a str, 175 | ) -> impl Future, KeycloakError>> + use<'a, TS> 176 | { 177 | self.admin 178 | .realm_roles_by_id_with_role_id_composites_clients_with_client_uuid_get( 179 | self.realm, 180 | client_uuid, 181 | role_id, 182 | ) 183 | } 184 | 185 | /// Get realm-level roles that are in the role's composite 186 | /// 187 | /// Parameters: 188 | /// 189 | /// - `realm`: realm name (not id!) 190 | /// - `role_id` 191 | /// 192 | /// Resource: `Roles (by ID)` 193 | /// 194 | /// `GET /admin/realms/{realm}/roles-by-id/{role_id}/composites/realm` 195 | /// 196 | /// Documentation: 197 | /// 198 | /// REST method: `GET /admin/realms/{realm}/roles-by-id/{role-id}/composites/realm` 199 | pub fn roles_by_id_with_role_id_composites_realm_get( 200 | &'a self, 201 | role_id: &'a str, 202 | ) -> impl Future, KeycloakError>> + use<'a, TS> 203 | { 204 | self.admin 205 | .realm_roles_by_id_with_role_id_composites_realm_get(self.realm, role_id) 206 | } 207 | 208 | /// Return object stating whether role Authorization permissions have been initialized or not and a reference 209 | /// 210 | /// Parameters: 211 | /// 212 | /// - `realm`: realm name (not id!) 213 | /// - `role_id` 214 | /// 215 | /// Resource: `Roles (by ID)` 216 | /// 217 | /// `GET /admin/realms/{realm}/roles-by-id/{role_id}/management/permissions` 218 | /// 219 | /// Documentation: 220 | /// 221 | /// REST method: `GET /admin/realms/{realm}/roles-by-id/{role-id}/management/permissions` 222 | pub fn roles_by_id_with_role_id_management_permissions_get( 223 | &'a self, 224 | role_id: &'a str, 225 | ) -> impl Future> + use<'a, TS> 226 | { 227 | self.admin 228 | .realm_roles_by_id_with_role_id_management_permissions_get(self.realm, role_id) 229 | } 230 | 231 | /// Return object stating whether role Authorization permissions have been initialized or not and a reference 232 | /// 233 | /// Parameters: 234 | /// 235 | /// - `realm`: realm name (not id!) 236 | /// - `role_id` 237 | /// - `body` 238 | /// 239 | /// Resource: `Roles (by ID)` 240 | /// 241 | /// `PUT /admin/realms/{realm}/roles-by-id/{role_id}/management/permissions` 242 | /// 243 | /// Documentation: 244 | /// 245 | /// REST method: `PUT /admin/realms/{realm}/roles-by-id/{role-id}/management/permissions` 246 | pub fn roles_by_id_with_role_id_management_permissions_put( 247 | &'a self, 248 | role_id: &'a str, 249 | body: ManagementPermissionReference, 250 | ) -> impl Future> + use<'a, TS> 251 | { 252 | self.admin 253 | .realm_roles_by_id_with_role_id_management_permissions_put(self.realm, role_id, body) 254 | } 255 | } 256 | 257 | //

Roles (by ID)

258 | pub struct RealmRolesByIdWithRoleIdCompositesGet<'a, TS: KeycloakTokenSupplier> { 259 | /// Realm admin client 260 | pub realm_admin: &'a KeycloakRealmAdmin<'a, TS>, 261 | pub role_id: &'a str, 262 | } 263 | 264 | #[derive(Default)] 265 | pub struct RealmRolesByIdWithRoleIdCompositesGetArgs { 266 | pub first: Option, 267 | pub max: Option, 268 | pub search: Option, 269 | } 270 | 271 | impl<'a, TS: KeycloakTokenSupplier + Send + Sync> KeycloakRealmAdminMethod 272 | for RealmRolesByIdWithRoleIdCompositesGet<'a, TS> 273 | { 274 | type Output = TypeVec; 275 | type Args = RealmRolesByIdWithRoleIdCompositesGetArgs; 276 | 277 | fn opts( 278 | self, 279 | Self::Args { first, max, search }: Self::Args, 280 | ) -> impl Future> + use<'a, TS> { 281 | self.realm_admin 282 | .admin 283 | .realm_roles_by_id_with_role_id_composites_get( 284 | self.realm_admin.realm, 285 | self.role_id, 286 | first, 287 | max, 288 | search, 289 | ) 290 | } 291 | } 292 | 293 | impl<'a, TS> IntoFuture for RealmRolesByIdWithRoleIdCompositesGet<'a, TS> 294 | where 295 | TS: KeycloakTokenSupplier + Send + Sync, 296 | { 297 | type Output = Result, KeycloakError>; 298 | type IntoFuture = Pin + Send>>; 299 | fn into_future(self) -> Self::IntoFuture { 300 | Box::pin(self.opts(Default::default())) 301 | } 302 | } 303 | 304 | #[cfg(feature = "builder")] 305 | mod builder { 306 | use crate::builder::Builder; 307 | 308 | use super::*; 309 | 310 | //

Roles (by ID)

311 | impl<'a, TS> RealmRolesByIdWithRoleIdCompositesGet<'a, TS> 312 | where 313 | TS: KeycloakTokenSupplier + Send + Sync, 314 | { 315 | pub fn first(self, value: impl Into>) -> Builder<'a, Self> { 316 | self.builder().first(value) 317 | } 318 | pub fn max(self, value: impl Into>) -> Builder<'a, Self> { 319 | self.builder().max(value) 320 | } 321 | pub fn search(self, value: impl Into>) -> Builder<'a, Self> { 322 | self.builder().search(value) 323 | } 324 | } 325 | 326 | impl Builder<'_, RealmRolesByIdWithRoleIdCompositesGet<'_, TS>> 327 | where 328 | TS: KeycloakTokenSupplier + Send + Sync, 329 | { 330 | pub fn first(mut self, value: impl Into>) -> Self { 331 | self.args.first = value.into(); 332 | self 333 | } 334 | pub fn max(mut self, value: impl Into>) -> Self { 335 | self.args.max = value.into(); 336 | self 337 | } 338 | pub fn search(mut self, value: impl Into>) -> Self { 339 | self.args.search = value.into(); 340 | self 341 | } 342 | } 343 | } 344 | -------------------------------------------------------------------------------- /src/rest/generated_rest/roles_by_id.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | impl KeycloakAdmin { 4 | //

Roles (by ID)

5 | 6 | /// Get a specific role's representation 7 | /// 8 | /// Parameters: 9 | /// 10 | /// - `realm`: realm name (not id!) 11 | /// - `role_id`: id of role 12 | /// 13 | /// Resource: `Roles (by ID)` 14 | /// 15 | /// `GET /admin/realms/{realm}/roles-by-id/{role_id}` 16 | /// 17 | /// Documentation: 18 | /// 19 | /// REST method: `GET /admin/realms/{realm}/roles-by-id/{role-id}` 20 | pub async fn realm_roles_by_id_with_role_id_get( 21 | &self, 22 | realm: &str, 23 | role_id: &str, 24 | ) -> Result { 25 | let realm = p(realm); 26 | let role_id = p(role_id); 27 | let builder = self 28 | .client 29 | .get(format!( 30 | "{}/admin/realms/{realm}/roles-by-id/{role_id}", 31 | self.url 32 | )) 33 | .bearer_auth(self.token_supplier.get(&self.url).await?); 34 | let response = builder.send().await?; 35 | Ok(error_check(response).await?.json().await?) 36 | } 37 | 38 | /// Update the role 39 | /// 40 | /// Parameters: 41 | /// 42 | /// - `realm`: realm name (not id!) 43 | /// - `role_id`: id of role 44 | /// - `body` 45 | /// 46 | /// Returns response for future processing. 47 | /// 48 | /// Resource: `Roles (by ID)` 49 | /// 50 | /// `PUT /admin/realms/{realm}/roles-by-id/{role_id}` 51 | /// 52 | /// Documentation: 53 | /// 54 | /// REST method: `PUT /admin/realms/{realm}/roles-by-id/{role-id}` 55 | pub async fn realm_roles_by_id_with_role_id_put( 56 | &self, 57 | realm: &str, 58 | role_id: &str, 59 | body: RoleRepresentation, 60 | ) -> Result { 61 | let realm = p(realm); 62 | let role_id = p(role_id); 63 | let builder = self 64 | .client 65 | .put(format!( 66 | "{}/admin/realms/{realm}/roles-by-id/{role_id}", 67 | self.url 68 | )) 69 | .json(&body) 70 | .bearer_auth(self.token_supplier.get(&self.url).await?); 71 | let response = builder.send().await?; 72 | error_check(response).await.map(From::from) 73 | } 74 | 75 | /// Delete the role 76 | /// 77 | /// Parameters: 78 | /// 79 | /// - `realm`: realm name (not id!) 80 | /// - `role_id`: id of role 81 | /// 82 | /// Returns response for future processing. 83 | /// 84 | /// Resource: `Roles (by ID)` 85 | /// 86 | /// `DELETE /admin/realms/{realm}/roles-by-id/{role_id}` 87 | /// 88 | /// Documentation: 89 | /// 90 | /// REST method: `DELETE /admin/realms/{realm}/roles-by-id/{role-id}` 91 | pub async fn realm_roles_by_id_with_role_id_delete( 92 | &self, 93 | realm: &str, 94 | role_id: &str, 95 | ) -> Result { 96 | let realm = p(realm); 97 | let role_id = p(role_id); 98 | let builder = self 99 | .client 100 | .delete(format!( 101 | "{}/admin/realms/{realm}/roles-by-id/{role_id}", 102 | self.url 103 | )) 104 | .bearer_auth(self.token_supplier.get(&self.url).await?); 105 | let response = builder.send().await?; 106 | error_check(response).await.map(From::from) 107 | } 108 | 109 | /// Get role's children Returns a set of role's children provided the role is a composite. 110 | /// 111 | /// Parameters: 112 | /// 113 | /// - `realm`: realm name (not id!) 114 | /// - `role_id` 115 | /// - `first` 116 | /// - `max` 117 | /// - `search` 118 | /// 119 | /// Resource: `Roles (by ID)` 120 | /// 121 | /// `GET /admin/realms/{realm}/roles-by-id/{role_id}/composites` 122 | /// 123 | /// Documentation: 124 | /// 125 | /// REST method: `GET /admin/realms/{realm}/roles-by-id/{role-id}/composites` 126 | pub async fn realm_roles_by_id_with_role_id_composites_get( 127 | &self, 128 | realm: &str, 129 | role_id: &str, 130 | first: Option, 131 | max: Option, 132 | search: Option, 133 | ) -> Result, KeycloakError> { 134 | let realm = p(realm); 135 | let role_id = p(role_id); 136 | let mut builder = self 137 | .client 138 | .get(format!( 139 | "{}/admin/realms/{realm}/roles-by-id/{role_id}/composites", 140 | self.url 141 | )) 142 | .bearer_auth(self.token_supplier.get(&self.url).await?); 143 | if let Some(v) = first { 144 | builder = builder.query(&[("first", v)]); 145 | } 146 | if let Some(v) = max { 147 | builder = builder.query(&[("max", v)]); 148 | } 149 | if let Some(v) = search { 150 | builder = builder.query(&[("search", v)]); 151 | } 152 | let response = builder.send().await?; 153 | Ok(error_check(response).await?.json().await?) 154 | } 155 | 156 | /// Make the role a composite role by associating some child roles 157 | /// 158 | /// Parameters: 159 | /// 160 | /// - `realm`: realm name (not id!) 161 | /// - `role_id` 162 | /// - `body` 163 | /// 164 | /// Returns response for future processing. 165 | /// 166 | /// Resource: `Roles (by ID)` 167 | /// 168 | /// `POST /admin/realms/{realm}/roles-by-id/{role_id}/composites` 169 | /// 170 | /// Documentation: 171 | /// 172 | /// REST method: `POST /admin/realms/{realm}/roles-by-id/{role-id}/composites` 173 | pub async fn realm_roles_by_id_with_role_id_composites_post( 174 | &self, 175 | realm: &str, 176 | role_id: &str, 177 | body: Vec, 178 | ) -> Result { 179 | let realm = p(realm); 180 | let role_id = p(role_id); 181 | let builder = self 182 | .client 183 | .post(format!( 184 | "{}/admin/realms/{realm}/roles-by-id/{role_id}/composites", 185 | self.url 186 | )) 187 | .json(&body) 188 | .bearer_auth(self.token_supplier.get(&self.url).await?); 189 | let response = builder.send().await?; 190 | error_check(response).await.map(From::from) 191 | } 192 | 193 | /// Remove a set of roles from the role's composite 194 | /// 195 | /// Parameters: 196 | /// 197 | /// - `realm`: realm name (not id!) 198 | /// - `role_id`: Role id 199 | /// - `body` 200 | /// 201 | /// Returns response for future processing. 202 | /// 203 | /// Resource: `Roles (by ID)` 204 | /// 205 | /// `DELETE /admin/realms/{realm}/roles-by-id/{role_id}/composites` 206 | /// 207 | /// Documentation: 208 | /// 209 | /// REST method: `DELETE /admin/realms/{realm}/roles-by-id/{role-id}/composites` 210 | pub async fn realm_roles_by_id_with_role_id_composites_delete( 211 | &self, 212 | realm: &str, 213 | role_id: &str, 214 | body: Vec, 215 | ) -> Result { 216 | let realm = p(realm); 217 | let role_id = p(role_id); 218 | let builder = self 219 | .client 220 | .delete(format!( 221 | "{}/admin/realms/{realm}/roles-by-id/{role_id}/composites", 222 | self.url 223 | )) 224 | .json(&body) 225 | .bearer_auth(self.token_supplier.get(&self.url).await?); 226 | let response = builder.send().await?; 227 | error_check(response).await.map(From::from) 228 | } 229 | 230 | /// Get client-level roles for the client that are in the role's composite 231 | /// 232 | /// Parameters: 233 | /// 234 | /// - `realm`: realm name (not id!) 235 | /// - `client_uuid` 236 | /// - `role_id` 237 | /// 238 | /// Resource: `Roles (by ID)` 239 | /// 240 | /// `GET /admin/realms/{realm}/roles-by-id/{role_id}/composites/clients/{client_uuid}` 241 | /// 242 | /// Documentation: 243 | /// 244 | /// REST method: `GET /admin/realms/{realm}/roles-by-id/{role-id}/composites/clients/{clientUuid}` 245 | pub async fn realm_roles_by_id_with_role_id_composites_clients_with_client_uuid_get( 246 | &self, 247 | realm: &str, 248 | client_uuid: &str, 249 | role_id: &str, 250 | ) -> Result, KeycloakError> { 251 | let realm = p(realm); 252 | let client_uuid = p(client_uuid); 253 | let role_id = p(role_id); 254 | let builder = self 255 | .client 256 | .get(format!( 257 | "{}/admin/realms/{realm}/roles-by-id/{role_id}/composites/clients/{client_uuid}", 258 | self.url 259 | )) 260 | .bearer_auth(self.token_supplier.get(&self.url).await?); 261 | let response = builder.send().await?; 262 | Ok(error_check(response).await?.json().await?) 263 | } 264 | 265 | /// Get realm-level roles that are in the role's composite 266 | /// 267 | /// Parameters: 268 | /// 269 | /// - `realm`: realm name (not id!) 270 | /// - `role_id` 271 | /// 272 | /// Resource: `Roles (by ID)` 273 | /// 274 | /// `GET /admin/realms/{realm}/roles-by-id/{role_id}/composites/realm` 275 | /// 276 | /// Documentation: 277 | /// 278 | /// REST method: `GET /admin/realms/{realm}/roles-by-id/{role-id}/composites/realm` 279 | pub async fn realm_roles_by_id_with_role_id_composites_realm_get( 280 | &self, 281 | realm: &str, 282 | role_id: &str, 283 | ) -> Result, KeycloakError> { 284 | let realm = p(realm); 285 | let role_id = p(role_id); 286 | let builder = self 287 | .client 288 | .get(format!( 289 | "{}/admin/realms/{realm}/roles-by-id/{role_id}/composites/realm", 290 | self.url 291 | )) 292 | .bearer_auth(self.token_supplier.get(&self.url).await?); 293 | let response = builder.send().await?; 294 | Ok(error_check(response).await?.json().await?) 295 | } 296 | 297 | /// Return object stating whether role Authorization permissions have been initialized or not and a reference 298 | /// 299 | /// Parameters: 300 | /// 301 | /// - `realm`: realm name (not id!) 302 | /// - `role_id` 303 | /// 304 | /// Resource: `Roles (by ID)` 305 | /// 306 | /// `GET /admin/realms/{realm}/roles-by-id/{role_id}/management/permissions` 307 | /// 308 | /// Documentation: 309 | /// 310 | /// REST method: `GET /admin/realms/{realm}/roles-by-id/{role-id}/management/permissions` 311 | pub async fn realm_roles_by_id_with_role_id_management_permissions_get( 312 | &self, 313 | realm: &str, 314 | role_id: &str, 315 | ) -> Result { 316 | let realm = p(realm); 317 | let role_id = p(role_id); 318 | let builder = self 319 | .client 320 | .get(format!( 321 | "{}/admin/realms/{realm}/roles-by-id/{role_id}/management/permissions", 322 | self.url 323 | )) 324 | .bearer_auth(self.token_supplier.get(&self.url).await?); 325 | let response = builder.send().await?; 326 | Ok(error_check(response).await?.json().await?) 327 | } 328 | 329 | /// Return object stating whether role Authorization permissions have been initialized or not and a reference 330 | /// 331 | /// Parameters: 332 | /// 333 | /// - `realm`: realm name (not id!) 334 | /// - `role_id` 335 | /// - `body` 336 | /// 337 | /// Resource: `Roles (by ID)` 338 | /// 339 | /// `PUT /admin/realms/{realm}/roles-by-id/{role_id}/management/permissions` 340 | /// 341 | /// Documentation: 342 | /// 343 | /// REST method: `PUT /admin/realms/{realm}/roles-by-id/{role-id}/management/permissions` 344 | pub async fn realm_roles_by_id_with_role_id_management_permissions_put( 345 | &self, 346 | realm: &str, 347 | role_id: &str, 348 | body: ManagementPermissionReference, 349 | ) -> Result { 350 | let realm = p(realm); 351 | let role_id = p(role_id); 352 | let builder = self 353 | .client 354 | .put(format!( 355 | "{}/admin/realms/{realm}/roles-by-id/{role_id}/management/permissions", 356 | self.url 357 | )) 358 | .json(&body) 359 | .bearer_auth(self.token_supplier.get(&self.url).await?); 360 | let response = builder.send().await?; 361 | Ok(error_check(response).await?.json().await?) 362 | } 363 | } 364 | // not all paths processed 365 | // left 242 366 | -------------------------------------------------------------------------------- /src/rest/generated_rest/client_role_mappings.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | impl KeycloakAdmin { 4 | //

Client Role Mappings

5 | 6 | /// Get client-level role mappings for the user or group, and the app 7 | /// 8 | /// Parameters: 9 | /// 10 | /// - `realm`: realm name (not id!) 11 | /// - `group_id` 12 | /// - `client_id`: client id (not clientId!) 13 | /// 14 | /// Resource: `Client Role Mappings` 15 | /// 16 | /// `GET /admin/realms/{realm}/groups/{group_id}/role-mappings/clients/{client_id}` 17 | /// 18 | /// Documentation: 19 | /// 20 | /// REST method: `GET /admin/realms/{realm}/groups/{group-id}/role-mappings/clients/{client-id}` 21 | pub async fn realm_groups_with_group_id_role_mappings_clients_with_client_id_get( 22 | &self, 23 | realm: &str, 24 | group_id: &str, 25 | client_id: &str, 26 | ) -> Result, KeycloakError> { 27 | let realm = p(realm); 28 | let group_id = p(group_id); 29 | let client_id = p(client_id); 30 | let builder = self 31 | .client 32 | .get(format!( 33 | "{}/admin/realms/{realm}/groups/{group_id}/role-mappings/clients/{client_id}", 34 | self.url 35 | )) 36 | .bearer_auth(self.token_supplier.get(&self.url).await?); 37 | let response = builder.send().await?; 38 | Ok(error_check(response).await?.json().await?) 39 | } 40 | 41 | /// Add client-level roles to the user or group role mapping 42 | /// 43 | /// Parameters: 44 | /// 45 | /// - `realm`: realm name (not id!) 46 | /// - `group_id` 47 | /// - `client_id`: client id (not clientId!) 48 | /// - `body` 49 | /// 50 | /// Returns response for future processing. 51 | /// 52 | /// Resource: `Client Role Mappings` 53 | /// 54 | /// `POST /admin/realms/{realm}/groups/{group_id}/role-mappings/clients/{client_id}` 55 | /// 56 | /// Documentation: 57 | /// 58 | /// REST method: `POST /admin/realms/{realm}/groups/{group-id}/role-mappings/clients/{client-id}` 59 | pub async fn realm_groups_with_group_id_role_mappings_clients_with_client_id_post( 60 | &self, 61 | realm: &str, 62 | group_id: &str, 63 | client_id: &str, 64 | body: Vec, 65 | ) -> Result { 66 | let realm = p(realm); 67 | let group_id = p(group_id); 68 | let client_id = p(client_id); 69 | let builder = self 70 | .client 71 | .post(format!( 72 | "{}/admin/realms/{realm}/groups/{group_id}/role-mappings/clients/{client_id}", 73 | self.url 74 | )) 75 | .json(&body) 76 | .bearer_auth(self.token_supplier.get(&self.url).await?); 77 | let response = builder.send().await?; 78 | error_check(response).await.map(From::from) 79 | } 80 | 81 | /// Delete client-level roles from user or group role mapping 82 | /// 83 | /// Parameters: 84 | /// 85 | /// - `realm`: realm name (not id!) 86 | /// - `group_id` 87 | /// - `client_id`: client id (not clientId!) 88 | /// - `body` 89 | /// 90 | /// Returns response for future processing. 91 | /// 92 | /// Resource: `Client Role Mappings` 93 | /// 94 | /// `DELETE /admin/realms/{realm}/groups/{group_id}/role-mappings/clients/{client_id}` 95 | /// 96 | /// Documentation: 97 | /// 98 | /// REST method: `DELETE /admin/realms/{realm}/groups/{group-id}/role-mappings/clients/{client-id}` 99 | pub async fn realm_groups_with_group_id_role_mappings_clients_with_client_id_delete( 100 | &self, 101 | realm: &str, 102 | group_id: &str, 103 | client_id: &str, 104 | body: Vec, 105 | ) -> Result { 106 | let realm = p(realm); 107 | let group_id = p(group_id); 108 | let client_id = p(client_id); 109 | let builder = self 110 | .client 111 | .delete(format!( 112 | "{}/admin/realms/{realm}/groups/{group_id}/role-mappings/clients/{client_id}", 113 | self.url 114 | )) 115 | .json(&body) 116 | .bearer_auth(self.token_supplier.get(&self.url).await?); 117 | let response = builder.send().await?; 118 | error_check(response).await.map(From::from) 119 | } 120 | 121 | /// Get available client-level roles that can be mapped to the user or group 122 | /// 123 | /// Parameters: 124 | /// 125 | /// - `realm`: realm name (not id!) 126 | /// - `group_id` 127 | /// - `client_id`: client id (not clientId!) 128 | /// 129 | /// Resource: `Client Role Mappings` 130 | /// 131 | /// `GET /admin/realms/{realm}/groups/{group_id}/role-mappings/clients/{client_id}/available` 132 | /// 133 | /// Documentation: 134 | /// 135 | /// REST method: `GET /admin/realms/{realm}/groups/{group-id}/role-mappings/clients/{client-id}/available` 136 | pub async fn realm_groups_with_group_id_role_mappings_clients_with_client_id_available_get( 137 | &self, 138 | realm: &str, 139 | group_id: &str, 140 | client_id: &str, 141 | ) -> Result, KeycloakError> { 142 | let realm = p(realm); 143 | let group_id = p(group_id); 144 | let client_id = p(client_id); 145 | let builder = self 146 | .client 147 | .get(format!( 148 | "{}/admin/realms/{realm}/groups/{group_id}/role-mappings/clients/{client_id}/available", 149 | self.url 150 | )) 151 | .bearer_auth(self.token_supplier.get(&self.url).await?); 152 | let response = builder.send().await?; 153 | Ok(error_check(response).await?.json().await?) 154 | } 155 | 156 | /// Get effective client-level role mappings This recurses any composite roles 157 | /// 158 | /// Parameters: 159 | /// 160 | /// - `realm`: realm name (not id!) 161 | /// - `group_id` 162 | /// - `client_id`: client id (not clientId!) 163 | /// - `brief_representation`: if false, return roles with their attributes 164 | /// 165 | /// Resource: `Client Role Mappings` 166 | /// 167 | /// `GET /admin/realms/{realm}/groups/{group_id}/role-mappings/clients/{client_id}/composite` 168 | /// 169 | /// Documentation: 170 | /// 171 | /// REST method: `GET /admin/realms/{realm}/groups/{group-id}/role-mappings/clients/{client-id}/composite` 172 | pub async fn realm_groups_with_group_id_role_mappings_clients_with_client_id_composite_get( 173 | &self, 174 | realm: &str, 175 | group_id: &str, 176 | client_id: &str, 177 | brief_representation: Option, 178 | ) -> Result, KeycloakError> { 179 | let realm = p(realm); 180 | let group_id = p(group_id); 181 | let client_id = p(client_id); 182 | let mut builder = self 183 | .client 184 | .get(format!( 185 | "{}/admin/realms/{realm}/groups/{group_id}/role-mappings/clients/{client_id}/composite", 186 | self.url 187 | )) 188 | .bearer_auth(self.token_supplier.get(&self.url).await?); 189 | if let Some(v) = brief_representation { 190 | builder = builder.query(&[("briefRepresentation", v)]); 191 | } 192 | let response = builder.send().await?; 193 | Ok(error_check(response).await?.json().await?) 194 | } 195 | 196 | /// Get client-level role mappings for the user or group, and the app 197 | /// 198 | /// Parameters: 199 | /// 200 | /// - `realm`: realm name (not id!) 201 | /// - `user_id` 202 | /// - `client_id`: client id (not clientId!) 203 | /// 204 | /// Resource: `Client Role Mappings` 205 | /// 206 | /// `GET /admin/realms/{realm}/users/{user_id}/role-mappings/clients/{client_id}` 207 | /// 208 | /// Documentation: 209 | /// 210 | /// REST method: `GET /admin/realms/{realm}/users/{user-id}/role-mappings/clients/{client-id}` 211 | pub async fn realm_users_with_user_id_role_mappings_clients_with_client_id_get( 212 | &self, 213 | realm: &str, 214 | user_id: &str, 215 | client_id: &str, 216 | ) -> Result, KeycloakError> { 217 | let realm = p(realm); 218 | let user_id = p(user_id); 219 | let client_id = p(client_id); 220 | let builder = self 221 | .client 222 | .get(format!( 223 | "{}/admin/realms/{realm}/users/{user_id}/role-mappings/clients/{client_id}", 224 | self.url 225 | )) 226 | .bearer_auth(self.token_supplier.get(&self.url).await?); 227 | let response = builder.send().await?; 228 | Ok(error_check(response).await?.json().await?) 229 | } 230 | 231 | /// Add client-level roles to the user or group role mapping 232 | /// 233 | /// Parameters: 234 | /// 235 | /// - `realm`: realm name (not id!) 236 | /// - `user_id` 237 | /// - `client_id`: client id (not clientId!) 238 | /// - `body` 239 | /// 240 | /// Returns response for future processing. 241 | /// 242 | /// Resource: `Client Role Mappings` 243 | /// 244 | /// `POST /admin/realms/{realm}/users/{user_id}/role-mappings/clients/{client_id}` 245 | /// 246 | /// Documentation: 247 | /// 248 | /// REST method: `POST /admin/realms/{realm}/users/{user-id}/role-mappings/clients/{client-id}` 249 | pub async fn realm_users_with_user_id_role_mappings_clients_with_client_id_post( 250 | &self, 251 | realm: &str, 252 | user_id: &str, 253 | client_id: &str, 254 | body: Vec, 255 | ) -> Result { 256 | let realm = p(realm); 257 | let user_id = p(user_id); 258 | let client_id = p(client_id); 259 | let builder = self 260 | .client 261 | .post(format!( 262 | "{}/admin/realms/{realm}/users/{user_id}/role-mappings/clients/{client_id}", 263 | self.url 264 | )) 265 | .json(&body) 266 | .bearer_auth(self.token_supplier.get(&self.url).await?); 267 | let response = builder.send().await?; 268 | error_check(response).await.map(From::from) 269 | } 270 | 271 | /// Delete client-level roles from user or group role mapping 272 | /// 273 | /// Parameters: 274 | /// 275 | /// - `realm`: realm name (not id!) 276 | /// - `user_id` 277 | /// - `client_id`: client id (not clientId!) 278 | /// - `body` 279 | /// 280 | /// Returns response for future processing. 281 | /// 282 | /// Resource: `Client Role Mappings` 283 | /// 284 | /// `DELETE /admin/realms/{realm}/users/{user_id}/role-mappings/clients/{client_id}` 285 | /// 286 | /// Documentation: 287 | /// 288 | /// REST method: `DELETE /admin/realms/{realm}/users/{user-id}/role-mappings/clients/{client-id}` 289 | pub async fn realm_users_with_user_id_role_mappings_clients_with_client_id_delete( 290 | &self, 291 | realm: &str, 292 | user_id: &str, 293 | client_id: &str, 294 | body: Vec, 295 | ) -> Result { 296 | let realm = p(realm); 297 | let user_id = p(user_id); 298 | let client_id = p(client_id); 299 | let builder = self 300 | .client 301 | .delete(format!( 302 | "{}/admin/realms/{realm}/users/{user_id}/role-mappings/clients/{client_id}", 303 | self.url 304 | )) 305 | .json(&body) 306 | .bearer_auth(self.token_supplier.get(&self.url).await?); 307 | let response = builder.send().await?; 308 | error_check(response).await.map(From::from) 309 | } 310 | 311 | /// Get available client-level roles that can be mapped to the user or group 312 | /// 313 | /// Parameters: 314 | /// 315 | /// - `realm`: realm name (not id!) 316 | /// - `user_id` 317 | /// - `client_id`: client id (not clientId!) 318 | /// 319 | /// Resource: `Client Role Mappings` 320 | /// 321 | /// `GET /admin/realms/{realm}/users/{user_id}/role-mappings/clients/{client_id}/available` 322 | /// 323 | /// Documentation: 324 | /// 325 | /// REST method: `GET /admin/realms/{realm}/users/{user-id}/role-mappings/clients/{client-id}/available` 326 | pub async fn realm_users_with_user_id_role_mappings_clients_with_client_id_available_get( 327 | &self, 328 | realm: &str, 329 | user_id: &str, 330 | client_id: &str, 331 | ) -> Result, KeycloakError> { 332 | let realm = p(realm); 333 | let user_id = p(user_id); 334 | let client_id = p(client_id); 335 | let builder = self 336 | .client 337 | .get(format!( 338 | "{}/admin/realms/{realm}/users/{user_id}/role-mappings/clients/{client_id}/available", 339 | self.url 340 | )) 341 | .bearer_auth(self.token_supplier.get(&self.url).await?); 342 | let response = builder.send().await?; 343 | Ok(error_check(response).await?.json().await?) 344 | } 345 | 346 | /// Get effective client-level role mappings This recurses any composite roles 347 | /// 348 | /// Parameters: 349 | /// 350 | /// - `realm`: realm name (not id!) 351 | /// - `user_id` 352 | /// - `client_id`: client id (not clientId!) 353 | /// - `brief_representation`: if false, return roles with their attributes 354 | /// 355 | /// Resource: `Client Role Mappings` 356 | /// 357 | /// `GET /admin/realms/{realm}/users/{user_id}/role-mappings/clients/{client_id}/composite` 358 | /// 359 | /// Documentation: 360 | /// 361 | /// REST method: `GET /admin/realms/{realm}/users/{user-id}/role-mappings/clients/{client-id}/composite` 362 | pub async fn realm_users_with_user_id_role_mappings_clients_with_client_id_composite_get( 363 | &self, 364 | realm: &str, 365 | user_id: &str, 366 | client_id: &str, 367 | brief_representation: Option, 368 | ) -> Result, KeycloakError> { 369 | let realm = p(realm); 370 | let user_id = p(user_id); 371 | let client_id = p(client_id); 372 | let mut builder = self 373 | .client 374 | .get(format!( 375 | "{}/admin/realms/{realm}/users/{user_id}/role-mappings/clients/{client_id}/composite", 376 | self.url 377 | )) 378 | .bearer_auth(self.token_supplier.get(&self.url).await?); 379 | if let Some(v) = brief_representation { 380 | builder = builder.query(&[("briefRepresentation", v)]); 381 | } 382 | let response = builder.send().await?; 383 | Ok(error_check(response).await?.json().await?) 384 | } 385 | } 386 | // not all paths processed 387 | // left 241 388 | -------------------------------------------------------------------------------- /src/rest/generated_rest/role_mapper.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | impl KeycloakAdmin { 4 | //

Role Mapper

5 | 6 | /// Get role mappings 7 | /// 8 | /// Parameters: 9 | /// 10 | /// - `realm`: realm name (not id!) 11 | /// - `group_id` 12 | /// 13 | /// Resource: `Role Mapper` 14 | /// 15 | /// `GET /admin/realms/{realm}/groups/{group_id}/role-mappings` 16 | /// 17 | /// Documentation: 18 | /// 19 | /// REST method: `GET /admin/realms/{realm}/groups/{group-id}/role-mappings` 20 | pub async fn realm_groups_with_group_id_role_mappings_get( 21 | &self, 22 | realm: &str, 23 | group_id: &str, 24 | ) -> Result { 25 | let realm = p(realm); 26 | let group_id = p(group_id); 27 | let builder = self 28 | .client 29 | .get(format!( 30 | "{}/admin/realms/{realm}/groups/{group_id}/role-mappings", 31 | self.url 32 | )) 33 | .bearer_auth(self.token_supplier.get(&self.url).await?); 34 | let response = builder.send().await?; 35 | Ok(error_check(response).await?.json().await?) 36 | } 37 | 38 | /// Get realm-level role mappings 39 | /// 40 | /// Parameters: 41 | /// 42 | /// - `realm`: realm name (not id!) 43 | /// - `group_id` 44 | /// 45 | /// Resource: `Role Mapper` 46 | /// 47 | /// `GET /admin/realms/{realm}/groups/{group_id}/role-mappings/realm` 48 | /// 49 | /// Documentation: 50 | /// 51 | /// REST method: `GET /admin/realms/{realm}/groups/{group-id}/role-mappings/realm` 52 | pub async fn realm_groups_with_group_id_role_mappings_realm_get( 53 | &self, 54 | realm: &str, 55 | group_id: &str, 56 | ) -> Result, KeycloakError> { 57 | let realm = p(realm); 58 | let group_id = p(group_id); 59 | let builder = self 60 | .client 61 | .get(format!( 62 | "{}/admin/realms/{realm}/groups/{group_id}/role-mappings/realm", 63 | self.url 64 | )) 65 | .bearer_auth(self.token_supplier.get(&self.url).await?); 66 | let response = builder.send().await?; 67 | Ok(error_check(response).await?.json().await?) 68 | } 69 | 70 | /// Add realm-level role mappings to the user 71 | /// 72 | /// Parameters: 73 | /// 74 | /// - `realm`: realm name (not id!) 75 | /// - `group_id` 76 | /// - `body` 77 | /// 78 | /// Returns response for future processing. 79 | /// 80 | /// Resource: `Role Mapper` 81 | /// 82 | /// `POST /admin/realms/{realm}/groups/{group_id}/role-mappings/realm` 83 | /// 84 | /// Documentation: 85 | /// 86 | /// REST method: `POST /admin/realms/{realm}/groups/{group-id}/role-mappings/realm` 87 | pub async fn realm_groups_with_group_id_role_mappings_realm_post( 88 | &self, 89 | realm: &str, 90 | group_id: &str, 91 | body: Vec, 92 | ) -> Result { 93 | let realm = p(realm); 94 | let group_id = p(group_id); 95 | let builder = self 96 | .client 97 | .post(format!( 98 | "{}/admin/realms/{realm}/groups/{group_id}/role-mappings/realm", 99 | self.url 100 | )) 101 | .json(&body) 102 | .bearer_auth(self.token_supplier.get(&self.url).await?); 103 | let response = builder.send().await?; 104 | error_check(response).await.map(From::from) 105 | } 106 | 107 | /// Delete realm-level role mappings 108 | /// 109 | /// Parameters: 110 | /// 111 | /// - `realm`: realm name (not id!) 112 | /// - `group_id` 113 | /// - `body` 114 | /// 115 | /// Returns response for future processing. 116 | /// 117 | /// Resource: `Role Mapper` 118 | /// 119 | /// `DELETE /admin/realms/{realm}/groups/{group_id}/role-mappings/realm` 120 | /// 121 | /// Documentation: 122 | /// 123 | /// REST method: `DELETE /admin/realms/{realm}/groups/{group-id}/role-mappings/realm` 124 | pub async fn realm_groups_with_group_id_role_mappings_realm_delete( 125 | &self, 126 | realm: &str, 127 | group_id: &str, 128 | body: Vec, 129 | ) -> Result { 130 | let realm = p(realm); 131 | let group_id = p(group_id); 132 | let builder = self 133 | .client 134 | .delete(format!( 135 | "{}/admin/realms/{realm}/groups/{group_id}/role-mappings/realm", 136 | self.url 137 | )) 138 | .json(&body) 139 | .bearer_auth(self.token_supplier.get(&self.url).await?); 140 | let response = builder.send().await?; 141 | error_check(response).await.map(From::from) 142 | } 143 | 144 | /// Get realm-level roles that can be mapped 145 | /// 146 | /// Parameters: 147 | /// 148 | /// - `realm`: realm name (not id!) 149 | /// - `group_id` 150 | /// 151 | /// Resource: `Role Mapper` 152 | /// 153 | /// `GET /admin/realms/{realm}/groups/{group_id}/role-mappings/realm/available` 154 | /// 155 | /// Documentation: 156 | /// 157 | /// REST method: `GET /admin/realms/{realm}/groups/{group-id}/role-mappings/realm/available` 158 | pub async fn realm_groups_with_group_id_role_mappings_realm_available_get( 159 | &self, 160 | realm: &str, 161 | group_id: &str, 162 | ) -> Result, KeycloakError> { 163 | let realm = p(realm); 164 | let group_id = p(group_id); 165 | let builder = self 166 | .client 167 | .get(format!( 168 | "{}/admin/realms/{realm}/groups/{group_id}/role-mappings/realm/available", 169 | self.url 170 | )) 171 | .bearer_auth(self.token_supplier.get(&self.url).await?); 172 | let response = builder.send().await?; 173 | Ok(error_check(response).await?.json().await?) 174 | } 175 | 176 | /// Get effective realm-level role mappings This will recurse all composite roles to get the result. 177 | /// 178 | /// Parameters: 179 | /// 180 | /// - `realm`: realm name (not id!) 181 | /// - `group_id` 182 | /// - `brief_representation`: if false, return roles with their attributes 183 | /// 184 | /// Resource: `Role Mapper` 185 | /// 186 | /// `GET /admin/realms/{realm}/groups/{group_id}/role-mappings/realm/composite` 187 | /// 188 | /// Documentation: 189 | /// 190 | /// REST method: `GET /admin/realms/{realm}/groups/{group-id}/role-mappings/realm/composite` 191 | pub async fn realm_groups_with_group_id_role_mappings_realm_composite_get( 192 | &self, 193 | realm: &str, 194 | group_id: &str, 195 | brief_representation: Option, 196 | ) -> Result, KeycloakError> { 197 | let realm = p(realm); 198 | let group_id = p(group_id); 199 | let mut builder = self 200 | .client 201 | .get(format!( 202 | "{}/admin/realms/{realm}/groups/{group_id}/role-mappings/realm/composite", 203 | self.url 204 | )) 205 | .bearer_auth(self.token_supplier.get(&self.url).await?); 206 | if let Some(v) = brief_representation { 207 | builder = builder.query(&[("briefRepresentation", v)]); 208 | } 209 | let response = builder.send().await?; 210 | Ok(error_check(response).await?.json().await?) 211 | } 212 | 213 | /// Get role mappings 214 | /// 215 | /// Parameters: 216 | /// 217 | /// - `realm`: realm name (not id!) 218 | /// - `user_id` 219 | /// 220 | /// Resource: `Role Mapper` 221 | /// 222 | /// `GET /admin/realms/{realm}/users/{user_id}/role-mappings` 223 | /// 224 | /// Documentation: 225 | /// 226 | /// REST method: `GET /admin/realms/{realm}/users/{user-id}/role-mappings` 227 | pub async fn realm_users_with_user_id_role_mappings_get( 228 | &self, 229 | realm: &str, 230 | user_id: &str, 231 | ) -> Result { 232 | let realm = p(realm); 233 | let user_id = p(user_id); 234 | let builder = self 235 | .client 236 | .get(format!( 237 | "{}/admin/realms/{realm}/users/{user_id}/role-mappings", 238 | self.url 239 | )) 240 | .bearer_auth(self.token_supplier.get(&self.url).await?); 241 | let response = builder.send().await?; 242 | Ok(error_check(response).await?.json().await?) 243 | } 244 | 245 | /// Get realm-level role mappings 246 | /// 247 | /// Parameters: 248 | /// 249 | /// - `realm`: realm name (not id!) 250 | /// - `user_id` 251 | /// 252 | /// Resource: `Role Mapper` 253 | /// 254 | /// `GET /admin/realms/{realm}/users/{user_id}/role-mappings/realm` 255 | /// 256 | /// Documentation: 257 | /// 258 | /// REST method: `GET /admin/realms/{realm}/users/{user-id}/role-mappings/realm` 259 | pub async fn realm_users_with_user_id_role_mappings_realm_get( 260 | &self, 261 | realm: &str, 262 | user_id: &str, 263 | ) -> Result, KeycloakError> { 264 | let realm = p(realm); 265 | let user_id = p(user_id); 266 | let builder = self 267 | .client 268 | .get(format!( 269 | "{}/admin/realms/{realm}/users/{user_id}/role-mappings/realm", 270 | self.url 271 | )) 272 | .bearer_auth(self.token_supplier.get(&self.url).await?); 273 | let response = builder.send().await?; 274 | Ok(error_check(response).await?.json().await?) 275 | } 276 | 277 | /// Add realm-level role mappings to the user 278 | /// 279 | /// Parameters: 280 | /// 281 | /// - `realm`: realm name (not id!) 282 | /// - `user_id` 283 | /// - `body` 284 | /// 285 | /// Returns response for future processing. 286 | /// 287 | /// Resource: `Role Mapper` 288 | /// 289 | /// `POST /admin/realms/{realm}/users/{user_id}/role-mappings/realm` 290 | /// 291 | /// Documentation: 292 | /// 293 | /// REST method: `POST /admin/realms/{realm}/users/{user-id}/role-mappings/realm` 294 | pub async fn realm_users_with_user_id_role_mappings_realm_post( 295 | &self, 296 | realm: &str, 297 | user_id: &str, 298 | body: Vec, 299 | ) -> Result { 300 | let realm = p(realm); 301 | let user_id = p(user_id); 302 | let builder = self 303 | .client 304 | .post(format!( 305 | "{}/admin/realms/{realm}/users/{user_id}/role-mappings/realm", 306 | self.url 307 | )) 308 | .json(&body) 309 | .bearer_auth(self.token_supplier.get(&self.url).await?); 310 | let response = builder.send().await?; 311 | error_check(response).await.map(From::from) 312 | } 313 | 314 | /// Delete realm-level role mappings 315 | /// 316 | /// Parameters: 317 | /// 318 | /// - `realm`: realm name (not id!) 319 | /// - `user_id` 320 | /// - `body` 321 | /// 322 | /// Returns response for future processing. 323 | /// 324 | /// Resource: `Role Mapper` 325 | /// 326 | /// `DELETE /admin/realms/{realm}/users/{user_id}/role-mappings/realm` 327 | /// 328 | /// Documentation: 329 | /// 330 | /// REST method: `DELETE /admin/realms/{realm}/users/{user-id}/role-mappings/realm` 331 | pub async fn realm_users_with_user_id_role_mappings_realm_delete( 332 | &self, 333 | realm: &str, 334 | user_id: &str, 335 | body: Vec, 336 | ) -> Result { 337 | let realm = p(realm); 338 | let user_id = p(user_id); 339 | let builder = self 340 | .client 341 | .delete(format!( 342 | "{}/admin/realms/{realm}/users/{user_id}/role-mappings/realm", 343 | self.url 344 | )) 345 | .json(&body) 346 | .bearer_auth(self.token_supplier.get(&self.url).await?); 347 | let response = builder.send().await?; 348 | error_check(response).await.map(From::from) 349 | } 350 | 351 | /// Get realm-level roles that can be mapped 352 | /// 353 | /// Parameters: 354 | /// 355 | /// - `realm`: realm name (not id!) 356 | /// - `user_id` 357 | /// 358 | /// Resource: `Role Mapper` 359 | /// 360 | /// `GET /admin/realms/{realm}/users/{user_id}/role-mappings/realm/available` 361 | /// 362 | /// Documentation: 363 | /// 364 | /// REST method: `GET /admin/realms/{realm}/users/{user-id}/role-mappings/realm/available` 365 | pub async fn realm_users_with_user_id_role_mappings_realm_available_get( 366 | &self, 367 | realm: &str, 368 | user_id: &str, 369 | ) -> Result, KeycloakError> { 370 | let realm = p(realm); 371 | let user_id = p(user_id); 372 | let builder = self 373 | .client 374 | .get(format!( 375 | "{}/admin/realms/{realm}/users/{user_id}/role-mappings/realm/available", 376 | self.url 377 | )) 378 | .bearer_auth(self.token_supplier.get(&self.url).await?); 379 | let response = builder.send().await?; 380 | Ok(error_check(response).await?.json().await?) 381 | } 382 | 383 | /// Get effective realm-level role mappings This will recurse all composite roles to get the result. 384 | /// 385 | /// Parameters: 386 | /// 387 | /// - `realm`: realm name (not id!) 388 | /// - `user_id` 389 | /// - `brief_representation`: if false, return roles with their attributes 390 | /// 391 | /// Resource: `Role Mapper` 392 | /// 393 | /// `GET /admin/realms/{realm}/users/{user_id}/role-mappings/realm/composite` 394 | /// 395 | /// Documentation: 396 | /// 397 | /// REST method: `GET /admin/realms/{realm}/users/{user-id}/role-mappings/realm/composite` 398 | pub async fn realm_users_with_user_id_role_mappings_realm_composite_get( 399 | &self, 400 | realm: &str, 401 | user_id: &str, 402 | brief_representation: Option, 403 | ) -> Result, KeycloakError> { 404 | let realm = p(realm); 405 | let user_id = p(user_id); 406 | let mut builder = self 407 | .client 408 | .get(format!( 409 | "{}/admin/realms/{realm}/users/{user_id}/role-mappings/realm/composite", 410 | self.url 411 | )) 412 | .bearer_auth(self.token_supplier.get(&self.url).await?); 413 | if let Some(v) = brief_representation { 414 | builder = builder.query(&[("briefRepresentation", v)]); 415 | } 416 | let response = builder.send().await?; 417 | Ok(error_check(response).await?.json().await?) 418 | } 419 | } 420 | // not all paths processed 421 | // left 239 422 | -------------------------------------------------------------------------------- /src/resource/role_mapper.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | impl<'a, TS: KeycloakTokenSupplier> KeycloakRealmAdmin<'a, TS> { 4 | //

Role Mapper

5 | /// Get role mappings 6 | /// 7 | /// Parameters: 8 | /// 9 | /// - `realm`: realm name (not id!) 10 | /// - `group_id` 11 | /// 12 | /// Resource: `Role Mapper` 13 | /// 14 | /// `GET /admin/realms/{realm}/groups/{group_id}/role-mappings` 15 | /// 16 | /// Documentation: 17 | /// 18 | /// REST method: `GET /admin/realms/{realm}/groups/{group-id}/role-mappings` 19 | pub fn groups_with_group_id_role_mappings_get( 20 | &'a self, 21 | group_id: &'a str, 22 | ) -> impl Future> + use<'a, TS> { 23 | self.admin 24 | .realm_groups_with_group_id_role_mappings_get(self.realm, group_id) 25 | } 26 | 27 | /// Get realm-level role mappings 28 | /// 29 | /// Parameters: 30 | /// 31 | /// - `realm`: realm name (not id!) 32 | /// - `group_id` 33 | /// 34 | /// Resource: `Role Mapper` 35 | /// 36 | /// `GET /admin/realms/{realm}/groups/{group_id}/role-mappings/realm` 37 | /// 38 | /// Documentation: 39 | /// 40 | /// REST method: `GET /admin/realms/{realm}/groups/{group-id}/role-mappings/realm` 41 | pub fn groups_with_group_id_role_mappings_realm_get( 42 | &'a self, 43 | group_id: &'a str, 44 | ) -> impl Future, KeycloakError>> + use<'a, TS> 45 | { 46 | self.admin 47 | .realm_groups_with_group_id_role_mappings_realm_get(self.realm, group_id) 48 | } 49 | 50 | /// Add realm-level role mappings to the user 51 | /// 52 | /// Parameters: 53 | /// 54 | /// - `realm`: realm name (not id!) 55 | /// - `group_id` 56 | /// - `body` 57 | /// 58 | /// Returns response for future processing. 59 | /// 60 | /// Resource: `Role Mapper` 61 | /// 62 | /// `POST /admin/realms/{realm}/groups/{group_id}/role-mappings/realm` 63 | /// 64 | /// Documentation: 65 | /// 66 | /// REST method: `POST /admin/realms/{realm}/groups/{group-id}/role-mappings/realm` 67 | pub fn groups_with_group_id_role_mappings_realm_post( 68 | &'a self, 69 | group_id: &'a str, 70 | body: Vec, 71 | ) -> impl Future> + use<'a, TS> { 72 | self.admin 73 | .realm_groups_with_group_id_role_mappings_realm_post(self.realm, group_id, body) 74 | } 75 | 76 | /// Delete realm-level role mappings 77 | /// 78 | /// Parameters: 79 | /// 80 | /// - `realm`: realm name (not id!) 81 | /// - `group_id` 82 | /// - `body` 83 | /// 84 | /// Returns response for future processing. 85 | /// 86 | /// Resource: `Role Mapper` 87 | /// 88 | /// `DELETE /admin/realms/{realm}/groups/{group_id}/role-mappings/realm` 89 | /// 90 | /// Documentation: 91 | /// 92 | /// REST method: `DELETE /admin/realms/{realm}/groups/{group-id}/role-mappings/realm` 93 | pub fn groups_with_group_id_role_mappings_realm_delete( 94 | &'a self, 95 | group_id: &'a str, 96 | body: Vec, 97 | ) -> impl Future> + use<'a, TS> { 98 | self.admin 99 | .realm_groups_with_group_id_role_mappings_realm_delete(self.realm, group_id, body) 100 | } 101 | 102 | /// Get realm-level roles that can be mapped 103 | /// 104 | /// Parameters: 105 | /// 106 | /// - `realm`: realm name (not id!) 107 | /// - `group_id` 108 | /// 109 | /// Resource: `Role Mapper` 110 | /// 111 | /// `GET /admin/realms/{realm}/groups/{group_id}/role-mappings/realm/available` 112 | /// 113 | /// Documentation: 114 | /// 115 | /// REST method: `GET /admin/realms/{realm}/groups/{group-id}/role-mappings/realm/available` 116 | pub fn groups_with_group_id_role_mappings_realm_available_get( 117 | &'a self, 118 | group_id: &'a str, 119 | ) -> impl Future, KeycloakError>> + use<'a, TS> 120 | { 121 | self.admin 122 | .realm_groups_with_group_id_role_mappings_realm_available_get(self.realm, group_id) 123 | } 124 | 125 | /// Get effective realm-level role mappings This will recurse all composite roles to get the result. 126 | /// 127 | /// Parameters: 128 | /// 129 | /// - `realm`: realm name (not id!) 130 | /// - `group_id` 131 | /// - `brief_representation`: if false, return roles with their attributes 132 | /// 133 | /// Resource: `Role Mapper` 134 | /// 135 | /// `GET /admin/realms/{realm}/groups/{group_id}/role-mappings/realm/composite` 136 | /// 137 | /// Documentation: 138 | /// 139 | /// REST method: `GET /admin/realms/{realm}/groups/{group-id}/role-mappings/realm/composite` 140 | pub fn groups_with_group_id_role_mappings_realm_composite_get( 141 | &'a self, 142 | group_id: &'a str, 143 | ) -> RealmGroupsWithGroupIdRoleMappingsRealmCompositeGet<'a, TS> { 144 | RealmGroupsWithGroupIdRoleMappingsRealmCompositeGet { 145 | realm_admin: self, 146 | group_id, 147 | } 148 | } 149 | 150 | /// Get role mappings 151 | /// 152 | /// Parameters: 153 | /// 154 | /// - `realm`: realm name (not id!) 155 | /// - `user_id` 156 | /// 157 | /// Resource: `Role Mapper` 158 | /// 159 | /// `GET /admin/realms/{realm}/users/{user_id}/role-mappings` 160 | /// 161 | /// Documentation: 162 | /// 163 | /// REST method: `GET /admin/realms/{realm}/users/{user-id}/role-mappings` 164 | pub fn users_with_user_id_role_mappings_get( 165 | &'a self, 166 | user_id: &'a str, 167 | ) -> impl Future> + use<'a, TS> { 168 | self.admin 169 | .realm_users_with_user_id_role_mappings_get(self.realm, user_id) 170 | } 171 | 172 | /// Get realm-level role mappings 173 | /// 174 | /// Parameters: 175 | /// 176 | /// - `realm`: realm name (not id!) 177 | /// - `user_id` 178 | /// 179 | /// Resource: `Role Mapper` 180 | /// 181 | /// `GET /admin/realms/{realm}/users/{user_id}/role-mappings/realm` 182 | /// 183 | /// Documentation: 184 | /// 185 | /// REST method: `GET /admin/realms/{realm}/users/{user-id}/role-mappings/realm` 186 | pub fn users_with_user_id_role_mappings_realm_get( 187 | &'a self, 188 | user_id: &'a str, 189 | ) -> impl Future, KeycloakError>> + use<'a, TS> 190 | { 191 | self.admin 192 | .realm_users_with_user_id_role_mappings_realm_get(self.realm, user_id) 193 | } 194 | 195 | /// Add realm-level role mappings to the user 196 | /// 197 | /// Parameters: 198 | /// 199 | /// - `realm`: realm name (not id!) 200 | /// - `user_id` 201 | /// - `body` 202 | /// 203 | /// Returns response for future processing. 204 | /// 205 | /// Resource: `Role Mapper` 206 | /// 207 | /// `POST /admin/realms/{realm}/users/{user_id}/role-mappings/realm` 208 | /// 209 | /// Documentation: 210 | /// 211 | /// REST method: `POST /admin/realms/{realm}/users/{user-id}/role-mappings/realm` 212 | pub fn users_with_user_id_role_mappings_realm_post( 213 | &'a self, 214 | user_id: &'a str, 215 | body: Vec, 216 | ) -> impl Future> + use<'a, TS> { 217 | self.admin 218 | .realm_users_with_user_id_role_mappings_realm_post(self.realm, user_id, body) 219 | } 220 | 221 | /// Delete realm-level role mappings 222 | /// 223 | /// Parameters: 224 | /// 225 | /// - `realm`: realm name (not id!) 226 | /// - `user_id` 227 | /// - `body` 228 | /// 229 | /// Returns response for future processing. 230 | /// 231 | /// Resource: `Role Mapper` 232 | /// 233 | /// `DELETE /admin/realms/{realm}/users/{user_id}/role-mappings/realm` 234 | /// 235 | /// Documentation: 236 | /// 237 | /// REST method: `DELETE /admin/realms/{realm}/users/{user-id}/role-mappings/realm` 238 | pub fn users_with_user_id_role_mappings_realm_delete( 239 | &'a self, 240 | user_id: &'a str, 241 | body: Vec, 242 | ) -> impl Future> + use<'a, TS> { 243 | self.admin 244 | .realm_users_with_user_id_role_mappings_realm_delete(self.realm, user_id, body) 245 | } 246 | 247 | /// Get realm-level roles that can be mapped 248 | /// 249 | /// Parameters: 250 | /// 251 | /// - `realm`: realm name (not id!) 252 | /// - `user_id` 253 | /// 254 | /// Resource: `Role Mapper` 255 | /// 256 | /// `GET /admin/realms/{realm}/users/{user_id}/role-mappings/realm/available` 257 | /// 258 | /// Documentation: 259 | /// 260 | /// REST method: `GET /admin/realms/{realm}/users/{user-id}/role-mappings/realm/available` 261 | pub fn users_with_user_id_role_mappings_realm_available_get( 262 | &'a self, 263 | user_id: &'a str, 264 | ) -> impl Future, KeycloakError>> + use<'a, TS> 265 | { 266 | self.admin 267 | .realm_users_with_user_id_role_mappings_realm_available_get(self.realm, user_id) 268 | } 269 | 270 | /// Get effective realm-level role mappings This will recurse all composite roles to get the result. 271 | /// 272 | /// Parameters: 273 | /// 274 | /// - `realm`: realm name (not id!) 275 | /// - `user_id` 276 | /// - `brief_representation`: if false, return roles with their attributes 277 | /// 278 | /// Resource: `Role Mapper` 279 | /// 280 | /// `GET /admin/realms/{realm}/users/{user_id}/role-mappings/realm/composite` 281 | /// 282 | /// Documentation: 283 | /// 284 | /// REST method: `GET /admin/realms/{realm}/users/{user-id}/role-mappings/realm/composite` 285 | pub fn users_with_user_id_role_mappings_realm_composite_get( 286 | &'a self, 287 | user_id: &'a str, 288 | ) -> RealmUsersWithUserIdRoleMappingsRealmCompositeGet<'a, TS> { 289 | RealmUsersWithUserIdRoleMappingsRealmCompositeGet { 290 | realm_admin: self, 291 | user_id, 292 | } 293 | } 294 | } 295 | 296 | //

Role Mapper

297 | pub struct RealmGroupsWithGroupIdRoleMappingsRealmCompositeGet<'a, TS: KeycloakTokenSupplier> { 298 | /// Realm admin client 299 | pub realm_admin: &'a KeycloakRealmAdmin<'a, TS>, 300 | pub group_id: &'a str, 301 | } 302 | 303 | #[derive(Default)] 304 | pub struct RealmGroupsWithGroupIdRoleMappingsRealmCompositeGetArgs { 305 | /// if false, return roles with their attributes 306 | pub brief_representation: Option, 307 | } 308 | 309 | impl<'a, TS: KeycloakTokenSupplier + Send + Sync> KeycloakRealmAdminMethod 310 | for RealmGroupsWithGroupIdRoleMappingsRealmCompositeGet<'a, TS> 311 | { 312 | type Output = TypeVec; 313 | type Args = RealmGroupsWithGroupIdRoleMappingsRealmCompositeGetArgs; 314 | 315 | fn opts( 316 | self, 317 | Self::Args { 318 | brief_representation, 319 | }: Self::Args, 320 | ) -> impl Future> + use<'a, TS> { 321 | self.realm_admin 322 | .admin 323 | .realm_groups_with_group_id_role_mappings_realm_composite_get( 324 | self.realm_admin.realm, 325 | self.group_id, 326 | brief_representation, 327 | ) 328 | } 329 | } 330 | 331 | impl<'a, TS> IntoFuture for RealmGroupsWithGroupIdRoleMappingsRealmCompositeGet<'a, TS> 332 | where 333 | TS: KeycloakTokenSupplier + Send + Sync, 334 | { 335 | type Output = Result, KeycloakError>; 336 | type IntoFuture = Pin + Send>>; 337 | fn into_future(self) -> Self::IntoFuture { 338 | Box::pin(self.opts(Default::default())) 339 | } 340 | } 341 | 342 | pub struct RealmUsersWithUserIdRoleMappingsRealmCompositeGet<'a, TS: KeycloakTokenSupplier> { 343 | /// Realm admin client 344 | pub realm_admin: &'a KeycloakRealmAdmin<'a, TS>, 345 | pub user_id: &'a str, 346 | } 347 | 348 | #[derive(Default)] 349 | pub struct RealmUsersWithUserIdRoleMappingsRealmCompositeGetArgs { 350 | /// if false, return roles with their attributes 351 | pub brief_representation: Option, 352 | } 353 | 354 | impl<'a, TS: KeycloakTokenSupplier + Send + Sync> KeycloakRealmAdminMethod 355 | for RealmUsersWithUserIdRoleMappingsRealmCompositeGet<'a, TS> 356 | { 357 | type Output = TypeVec; 358 | type Args = RealmUsersWithUserIdRoleMappingsRealmCompositeGetArgs; 359 | 360 | fn opts( 361 | self, 362 | Self::Args { 363 | brief_representation, 364 | }: Self::Args, 365 | ) -> impl Future> + use<'a, TS> { 366 | self.realm_admin 367 | .admin 368 | .realm_users_with_user_id_role_mappings_realm_composite_get( 369 | self.realm_admin.realm, 370 | self.user_id, 371 | brief_representation, 372 | ) 373 | } 374 | } 375 | 376 | impl<'a, TS> IntoFuture for RealmUsersWithUserIdRoleMappingsRealmCompositeGet<'a, TS> 377 | where 378 | TS: KeycloakTokenSupplier + Send + Sync, 379 | { 380 | type Output = Result, KeycloakError>; 381 | type IntoFuture = Pin + Send>>; 382 | fn into_future(self) -> Self::IntoFuture { 383 | Box::pin(self.opts(Default::default())) 384 | } 385 | } 386 | 387 | #[cfg(feature = "builder")] 388 | mod builder { 389 | use crate::builder::Builder; 390 | 391 | use super::*; 392 | 393 | //

Role Mapper

394 | impl<'a, TS> RealmGroupsWithGroupIdRoleMappingsRealmCompositeGet<'a, TS> 395 | where 396 | TS: KeycloakTokenSupplier + Send + Sync, 397 | { 398 | /// if false, return roles with their attributes 399 | pub fn brief_representation(self, value: impl Into>) -> Builder<'a, Self> { 400 | self.builder().brief_representation(value) 401 | } 402 | } 403 | 404 | impl Builder<'_, RealmGroupsWithGroupIdRoleMappingsRealmCompositeGet<'_, TS>> 405 | where 406 | TS: KeycloakTokenSupplier + Send + Sync, 407 | { 408 | /// if false, return roles with their attributes 409 | pub fn brief_representation(mut self, value: impl Into>) -> Self { 410 | self.args.brief_representation = value.into(); 411 | self 412 | } 413 | } 414 | 415 | impl<'a, TS> RealmUsersWithUserIdRoleMappingsRealmCompositeGet<'a, TS> 416 | where 417 | TS: KeycloakTokenSupplier + Send + Sync, 418 | { 419 | /// if false, return roles with their attributes 420 | pub fn brief_representation(self, value: impl Into>) -> Builder<'a, Self> { 421 | self.builder().brief_representation(value) 422 | } 423 | } 424 | 425 | impl Builder<'_, RealmUsersWithUserIdRoleMappingsRealmCompositeGet<'_, TS>> 426 | where 427 | TS: KeycloakTokenSupplier + Send + Sync, 428 | { 429 | /// if false, return roles with their attributes 430 | pub fn brief_representation(mut self, value: impl Into>) -> Self { 431 | self.args.brief_representation = value.into(); 432 | self 433 | } 434 | } 435 | } 436 | -------------------------------------------------------------------------------- /src/rest/generated_rest/groups.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | impl KeycloakAdmin { 4 | //

Groups

5 | 6 | /// Get group hierarchy. Only `name` and `id` are returned. `subGroups` are only returned when using the `search` or `q` parameter. If none of these parameters is provided, the top-level groups are returned without `subGroups` being filled. 7 | /// 8 | /// Parameters: 9 | /// 10 | /// - `realm`: realm name (not id!) 11 | /// - `brief_representation` 12 | /// - `exact` 13 | /// - `first` 14 | /// - `max` 15 | /// - `populate_hierarchy` 16 | /// - `q` 17 | /// - `search` 18 | /// - `sub_groups_count`: Boolean which defines whether to return the count of subgroups for each group (default: true 19 | /// 20 | /// Resource: `Groups` 21 | /// 22 | /// `GET /admin/realms/{realm}/groups` 23 | /// 24 | /// Documentation: 25 | #[allow(clippy::too_many_arguments)] 26 | pub async fn realm_groups_get( 27 | &self, 28 | realm: &str, 29 | brief_representation: Option, 30 | exact: Option, 31 | first: Option, 32 | max: Option, 33 | populate_hierarchy: Option, 34 | q: Option, 35 | search: Option, 36 | sub_groups_count: Option, 37 | ) -> Result, KeycloakError> { 38 | let realm = p(realm); 39 | let mut builder = self 40 | .client 41 | .get(format!("{}/admin/realms/{realm}/groups", self.url)) 42 | .bearer_auth(self.token_supplier.get(&self.url).await?); 43 | if let Some(v) = brief_representation { 44 | builder = builder.query(&[("briefRepresentation", v)]); 45 | } 46 | if let Some(v) = exact { 47 | builder = builder.query(&[("exact", v)]); 48 | } 49 | if let Some(v) = first { 50 | builder = builder.query(&[("first", v)]); 51 | } 52 | if let Some(v) = max { 53 | builder = builder.query(&[("max", v)]); 54 | } 55 | if let Some(v) = populate_hierarchy { 56 | builder = builder.query(&[("populateHierarchy", v)]); 57 | } 58 | if let Some(v) = q { 59 | builder = builder.query(&[("q", v)]); 60 | } 61 | if let Some(v) = search { 62 | builder = builder.query(&[("search", v)]); 63 | } 64 | if let Some(v) = sub_groups_count { 65 | builder = builder.query(&[("subGroupsCount", v)]); 66 | } 67 | let response = builder.send().await?; 68 | Ok(error_check(response).await?.json().await?) 69 | } 70 | 71 | /// create or add a top level realm groupSet or create child. 72 | /// 73 | /// Parameters: 74 | /// 75 | /// - `realm`: realm name (not id!) 76 | /// - `body` 77 | /// 78 | /// Returns response for future processing. 79 | /// 80 | /// Resource: `Groups` 81 | /// 82 | /// `POST /admin/realms/{realm}/groups` 83 | /// 84 | /// Documentation: 85 | pub async fn realm_groups_post( 86 | &self, 87 | realm: &str, 88 | body: GroupRepresentation, 89 | ) -> Result { 90 | let realm = p(realm); 91 | let builder = self 92 | .client 93 | .post(format!("{}/admin/realms/{realm}/groups", self.url)) 94 | .json(&body) 95 | .bearer_auth(self.token_supplier.get(&self.url).await?); 96 | let response = builder.send().await?; 97 | error_check(response).await.map(From::from) 98 | } 99 | 100 | /// Returns the groups counts. 101 | /// 102 | /// Parameters: 103 | /// 104 | /// - `realm`: realm name (not id!) 105 | /// - `search` 106 | /// - `top` 107 | /// 108 | /// Resource: `Groups` 109 | /// 110 | /// `GET /admin/realms/{realm}/groups/count` 111 | /// 112 | /// Documentation: 113 | pub async fn realm_groups_count_get( 114 | &self, 115 | realm: &str, 116 | search: Option, 117 | top: Option, 118 | ) -> Result, KeycloakError> { 119 | let realm = p(realm); 120 | let mut builder = self 121 | .client 122 | .get(format!("{}/admin/realms/{realm}/groups/count", self.url)) 123 | .bearer_auth(self.token_supplier.get(&self.url).await?); 124 | if let Some(v) = search { 125 | builder = builder.query(&[("search", v)]); 126 | } 127 | if let Some(v) = top { 128 | builder = builder.query(&[("top", v)]); 129 | } 130 | let response = builder.send().await?; 131 | Ok(error_check(response).await?.json().await?) 132 | } 133 | 134 | /// Parameters: 135 | /// 136 | /// - `realm`: realm name (not id!) 137 | /// - `group_id` 138 | /// 139 | /// Resource: `Groups` 140 | /// 141 | /// `GET /admin/realms/{realm}/groups/{group_id}` 142 | /// 143 | /// Documentation: 144 | /// 145 | /// REST method: `GET /admin/realms/{realm}/groups/{group-id}` 146 | pub async fn realm_groups_with_group_id_get( 147 | &self, 148 | realm: &str, 149 | group_id: &str, 150 | ) -> Result { 151 | let realm = p(realm); 152 | let group_id = p(group_id); 153 | let builder = self 154 | .client 155 | .get(format!( 156 | "{}/admin/realms/{realm}/groups/{group_id}", 157 | self.url 158 | )) 159 | .bearer_auth(self.token_supplier.get(&self.url).await?); 160 | let response = builder.send().await?; 161 | Ok(error_check(response).await?.json().await?) 162 | } 163 | 164 | /// Update group, ignores subgroups. 165 | /// 166 | /// Parameters: 167 | /// 168 | /// - `realm`: realm name (not id!) 169 | /// - `group_id` 170 | /// - `body` 171 | /// 172 | /// Returns response for future processing. 173 | /// 174 | /// Resource: `Groups` 175 | /// 176 | /// `PUT /admin/realms/{realm}/groups/{group_id}` 177 | /// 178 | /// Documentation: 179 | /// 180 | /// REST method: `PUT /admin/realms/{realm}/groups/{group-id}` 181 | pub async fn realm_groups_with_group_id_put( 182 | &self, 183 | realm: &str, 184 | group_id: &str, 185 | body: GroupRepresentation, 186 | ) -> Result { 187 | let realm = p(realm); 188 | let group_id = p(group_id); 189 | let builder = self 190 | .client 191 | .put(format!( 192 | "{}/admin/realms/{realm}/groups/{group_id}", 193 | self.url 194 | )) 195 | .json(&body) 196 | .bearer_auth(self.token_supplier.get(&self.url).await?); 197 | let response = builder.send().await?; 198 | error_check(response).await.map(From::from) 199 | } 200 | 201 | /// Parameters: 202 | /// 203 | /// - `realm`: realm name (not id!) 204 | /// - `group_id` 205 | /// 206 | /// Returns response for future processing. 207 | /// 208 | /// Resource: `Groups` 209 | /// 210 | /// `DELETE /admin/realms/{realm}/groups/{group_id}` 211 | /// 212 | /// Documentation: 213 | /// 214 | /// REST method: `DELETE /admin/realms/{realm}/groups/{group-id}` 215 | pub async fn realm_groups_with_group_id_delete( 216 | &self, 217 | realm: &str, 218 | group_id: &str, 219 | ) -> Result { 220 | let realm = p(realm); 221 | let group_id = p(group_id); 222 | let builder = self 223 | .client 224 | .delete(format!( 225 | "{}/admin/realms/{realm}/groups/{group_id}", 226 | self.url 227 | )) 228 | .bearer_auth(self.token_supplier.get(&self.url).await?); 229 | let response = builder.send().await?; 230 | error_check(response).await.map(From::from) 231 | } 232 | 233 | /// Return a paginated list of subgroups that have a parent group corresponding to the group on the URL 234 | /// 235 | /// Parameters: 236 | /// 237 | /// - `realm`: realm name (not id!) 238 | /// - `group_id` 239 | /// - `brief_representation`: Boolean which defines whether brief groups representations are returned or not (default: false) 240 | /// - `exact`: Boolean which defines whether the params "search" must match exactly or not 241 | /// - `first`: The position of the first result to be returned (pagination offset). 242 | /// - `max`: The maximum number of results that are to be returned. Defaults to 10 243 | /// - `search`: A String representing either an exact group name or a partial name 244 | /// - `sub_groups_count`: Boolean which defines whether to return the count of subgroups for each subgroup of this group (default: true 245 | /// 246 | /// Resource: `Groups` 247 | /// 248 | /// `GET /admin/realms/{realm}/groups/{group_id}/children` 249 | /// 250 | /// Documentation: 251 | /// 252 | /// REST method: `GET /admin/realms/{realm}/groups/{group-id}/children` 253 | #[allow(clippy::too_many_arguments)] 254 | pub async fn realm_groups_with_group_id_children_get( 255 | &self, 256 | realm: &str, 257 | group_id: &str, 258 | brief_representation: Option, 259 | exact: Option, 260 | first: Option, 261 | max: Option, 262 | search: Option, 263 | sub_groups_count: Option, 264 | ) -> Result, KeycloakError> { 265 | let realm = p(realm); 266 | let group_id = p(group_id); 267 | let mut builder = self 268 | .client 269 | .get(format!( 270 | "{}/admin/realms/{realm}/groups/{group_id}/children", 271 | self.url 272 | )) 273 | .bearer_auth(self.token_supplier.get(&self.url).await?); 274 | if let Some(v) = brief_representation { 275 | builder = builder.query(&[("briefRepresentation", v)]); 276 | } 277 | if let Some(v) = exact { 278 | builder = builder.query(&[("exact", v)]); 279 | } 280 | if let Some(v) = first { 281 | builder = builder.query(&[("first", v)]); 282 | } 283 | if let Some(v) = max { 284 | builder = builder.query(&[("max", v)]); 285 | } 286 | if let Some(v) = search { 287 | builder = builder.query(&[("search", v)]); 288 | } 289 | if let Some(v) = sub_groups_count { 290 | builder = builder.query(&[("subGroupsCount", v)]); 291 | } 292 | let response = builder.send().await?; 293 | Ok(error_check(response).await?.json().await?) 294 | } 295 | 296 | /// Set or create child. 297 | /// 298 | /// Parameters: 299 | /// 300 | /// - `realm`: realm name (not id!) 301 | /// - `group_id` 302 | /// - `body` 303 | /// 304 | /// Returns response for future processing. 305 | /// 306 | /// Resource: `Groups` 307 | /// 308 | /// `POST /admin/realms/{realm}/groups/{group_id}/children` 309 | /// 310 | /// Documentation: 311 | /// 312 | /// REST method: `POST /admin/realms/{realm}/groups/{group-id}/children` 313 | pub async fn realm_groups_with_group_id_children_post( 314 | &self, 315 | realm: &str, 316 | group_id: &str, 317 | body: GroupRepresentation, 318 | ) -> Result { 319 | let realm = p(realm); 320 | let group_id = p(group_id); 321 | let builder = self 322 | .client 323 | .post(format!( 324 | "{}/admin/realms/{realm}/groups/{group_id}/children", 325 | self.url 326 | )) 327 | .json(&body) 328 | .bearer_auth(self.token_supplier.get(&self.url).await?); 329 | let response = builder.send().await?; 330 | error_check(response).await.map(From::from) 331 | } 332 | 333 | /// Return object stating whether client Authorization permissions have been initialized or not and a reference 334 | /// 335 | /// Parameters: 336 | /// 337 | /// - `realm`: realm name (not id!) 338 | /// - `group_id` 339 | /// 340 | /// Resource: `Groups` 341 | /// 342 | /// `GET /admin/realms/{realm}/groups/{group_id}/management/permissions` 343 | /// 344 | /// Documentation: 345 | /// 346 | /// REST method: `GET /admin/realms/{realm}/groups/{group-id}/management/permissions` 347 | pub async fn realm_groups_with_group_id_management_permissions_get( 348 | &self, 349 | realm: &str, 350 | group_id: &str, 351 | ) -> Result { 352 | let realm = p(realm); 353 | let group_id = p(group_id); 354 | let builder = self 355 | .client 356 | .get(format!( 357 | "{}/admin/realms/{realm}/groups/{group_id}/management/permissions", 358 | self.url 359 | )) 360 | .bearer_auth(self.token_supplier.get(&self.url).await?); 361 | let response = builder.send().await?; 362 | Ok(error_check(response).await?.json().await?) 363 | } 364 | 365 | /// Return object stating whether client Authorization permissions have been initialized or not and a reference 366 | /// 367 | /// Parameters: 368 | /// 369 | /// - `realm`: realm name (not id!) 370 | /// - `group_id` 371 | /// - `body` 372 | /// 373 | /// Resource: `Groups` 374 | /// 375 | /// `PUT /admin/realms/{realm}/groups/{group_id}/management/permissions` 376 | /// 377 | /// Documentation: 378 | /// 379 | /// REST method: `PUT /admin/realms/{realm}/groups/{group-id}/management/permissions` 380 | pub async fn realm_groups_with_group_id_management_permissions_put( 381 | &self, 382 | realm: &str, 383 | group_id: &str, 384 | body: ManagementPermissionReference, 385 | ) -> Result { 386 | let realm = p(realm); 387 | let group_id = p(group_id); 388 | let builder = self 389 | .client 390 | .put(format!( 391 | "{}/admin/realms/{realm}/groups/{group_id}/management/permissions", 392 | self.url 393 | )) 394 | .json(&body) 395 | .bearer_auth(self.token_supplier.get(&self.url).await?); 396 | let response = builder.send().await?; 397 | Ok(error_check(response).await?.json().await?) 398 | } 399 | 400 | /// Get users Returns a stream of users, filtered according to query parameters 401 | /// 402 | /// Parameters: 403 | /// 404 | /// - `realm`: realm name (not id!) 405 | /// - `group_id` 406 | /// - `brief_representation`: Only return basic information (only guaranteed to return id, username, created, first and last name, email, enabled state, email verification state, federation link, and access. Note that it means that namely user attributes, required actions, and not before are not returned.) 407 | /// - `first`: Pagination offset 408 | /// - `max`: Maximum results size (defaults to 100) 409 | /// 410 | /// Resource: `Groups` 411 | /// 412 | /// `GET /admin/realms/{realm}/groups/{group_id}/members` 413 | /// 414 | /// Documentation: 415 | /// 416 | /// REST method: `GET /admin/realms/{realm}/groups/{group-id}/members` 417 | pub async fn realm_groups_with_group_id_members_get( 418 | &self, 419 | realm: &str, 420 | group_id: &str, 421 | brief_representation: Option, 422 | first: Option, 423 | max: Option, 424 | ) -> Result, KeycloakError> { 425 | let realm = p(realm); 426 | let group_id = p(group_id); 427 | let mut builder = self 428 | .client 429 | .get(format!( 430 | "{}/admin/realms/{realm}/groups/{group_id}/members", 431 | self.url 432 | )) 433 | .bearer_auth(self.token_supplier.get(&self.url).await?); 434 | if let Some(v) = brief_representation { 435 | builder = builder.query(&[("briefRepresentation", v)]); 436 | } 437 | if let Some(v) = first { 438 | builder = builder.query(&[("first", v)]); 439 | } 440 | if let Some(v) = max { 441 | builder = builder.query(&[("max", v)]); 442 | } 443 | let response = builder.send().await?; 444 | Ok(error_check(response).await?.json().await?) 445 | } 446 | } 447 | // not all paths processed 448 | // left 241 449 | --------------------------------------------------------------------------------