Add the Node.js Admin Client to the project (#3728)
This commit is contained in:
parent
5587314a70
commit
394dd48a94
123 changed files with 11689 additions and 38 deletions
3
.github/workflows/cypress.yml
vendored
3
.github/workflows/cypress.yml
vendored
|
@ -102,6 +102,9 @@ jobs:
|
|||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Compile Admin Client
|
||||
run: npm run build --workspace=@keycloak/keycloak-admin-client
|
||||
|
||||
- name: Restore Keycloak server
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
|
|
5
.github/workflows/main.yml
vendored
5
.github/workflows/main.yml
vendored
|
@ -49,6 +49,11 @@ jobs:
|
|||
command: lint
|
||||
- workspace: account-ui
|
||||
command: build
|
||||
# Keycloak Admin Client
|
||||
- workspace: "@keycloak/keycloak-admin-client"
|
||||
command: lint
|
||||
- workspace: "@keycloak/keycloak-admin-client"
|
||||
command: build
|
||||
# Keycloak Masthead
|
||||
- workspace: keycloak-masthead
|
||||
command: lint
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
"test": "wireit",
|
||||
"cy:open": "cypress open --e2e --browser chrome",
|
||||
"cy:run": "cypress run --browser chrome",
|
||||
"cy:check-types": "tsc --project cypress/tsconfig.json",
|
||||
"cy:check-types": "wireit",
|
||||
"cy:ldap-server": "ldap-server-mock --conf=./cypress/fixtures/ldap/server.json --database=./cypress/fixtures/ldap/users.json",
|
||||
"server:start": "./scripts/start-server.mjs",
|
||||
"server:import-client": "./scripts/import-client.mjs"
|
||||
|
@ -17,36 +17,47 @@
|
|||
"dev": {
|
||||
"command": "vite --host",
|
||||
"dependencies": [
|
||||
"../../libs/keycloak-js:build"
|
||||
"../../libs/keycloak-js:build",
|
||||
"../../libs/keycloak-admin-client:build"
|
||||
]
|
||||
},
|
||||
"preview": {
|
||||
"command": "vite preview",
|
||||
"dependencies": [
|
||||
"../../libs/keycloak-js:build"
|
||||
"../../libs/keycloak-js:build",
|
||||
"../../libs/keycloak-admin-client:build"
|
||||
]
|
||||
},
|
||||
"build": {
|
||||
"command": "vite build",
|
||||
"dependencies": [
|
||||
"../../libs/keycloak-js:build"
|
||||
"../../libs/keycloak-js:build",
|
||||
"../../libs/keycloak-admin-client:build"
|
||||
]
|
||||
},
|
||||
"lint": {
|
||||
"command": "eslint . --ext js,jsx,mjs,ts,tsx",
|
||||
"dependencies": [
|
||||
"../../libs/keycloak-js:build"
|
||||
"../../libs/keycloak-js:build",
|
||||
"../../libs/keycloak-admin-client:build"
|
||||
]
|
||||
},
|
||||
"test": {
|
||||
"command": "vitest",
|
||||
"dependencies": [
|
||||
"../../libs/keycloak-js:build"
|
||||
"../../libs/keycloak-js:build",
|
||||
"../../libs/keycloak-admin-client:build"
|
||||
]
|
||||
},
|
||||
"cy:check-types": {
|
||||
"command": "tsc --project cypress/tsconfig.json",
|
||||
"dependencies": [
|
||||
"../../libs/keycloak-admin-client:build"
|
||||
]
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@keycloak/keycloak-admin-client": "^21.0.0-dev.3",
|
||||
"@keycloak/keycloak-admin-client": "999.0.0-dev",
|
||||
"@patternfly/patternfly": "^4.219.2",
|
||||
"@patternfly/react-code-editor": "^4.82.55",
|
||||
"@patternfly/react-core": "^4.258.3",
|
||||
|
|
1
libs/keycloak-admin-client/.gitignore
vendored
Normal file
1
libs/keycloak-admin-client/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
lib/
|
5
libs/keycloak-admin-client/.mocharc.json
Normal file
5
libs/keycloak-admin-client/.mocharc.json
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"node-option": [
|
||||
"loader=ts-node/esm"
|
||||
]
|
||||
}
|
201
libs/keycloak-admin-client/LICENSE
Normal file
201
libs/keycloak-admin-client/LICENSE
Normal file
|
@ -0,0 +1,201 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
455
libs/keycloak-admin-client/README.md
Normal file
455
libs/keycloak-admin-client/README.md
Normal file
|
@ -0,0 +1,455 @@
|
|||
## Keycloak Admin Client
|
||||
|
||||
## Features
|
||||
|
||||
- TypeScript supported
|
||||
- Latest Keycloak version supported
|
||||
- [Complete resource definitions](https://github.com/keycloak/keycloak-ui/tree/main/libs/keycloak-admin-client/src/defs)
|
||||
- [Well-tested for supported APIs](https://github.com/keycloak/keycloak-ui/tree/main/libs/keycloak-admin-client/test)
|
||||
|
||||
## Install
|
||||
|
||||
```sh
|
||||
npm install @keycloak/keycloak-admin-client
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
import KcAdminClient from '@keycloak/keycloak-admin-client';
|
||||
|
||||
// To configure the client, pass an object to override any of these options:
|
||||
// {
|
||||
// baseUrl: 'http://127.0.0.1:8080',
|
||||
// realmName: 'master',
|
||||
// requestConfig: {
|
||||
// /* Axios request config options https://github.com/axios/axios#request-config */
|
||||
// },
|
||||
// }
|
||||
const kcAdminClient = new KcAdminClient();
|
||||
|
||||
// Authorize with username / password
|
||||
await kcAdminClient.auth({
|
||||
username: 'admin',
|
||||
password: 'admin',
|
||||
grantType: 'password',
|
||||
clientId: 'admin-cli',
|
||||
totp: '123456', // optional Time-based One-time Password if OTP is required in authentication flow
|
||||
});
|
||||
|
||||
// List all users
|
||||
const users = await kcAdminClient.users.find();
|
||||
|
||||
// Override client configuration for all further requests:
|
||||
kcAdminClient.setConfig({
|
||||
realmName: 'another-realm',
|
||||
});
|
||||
|
||||
// This operation will now be performed in 'another-realm' if the user has access.
|
||||
const groups = await kcAdminClient.groups.find();
|
||||
|
||||
// Set a `realm` property to override the realm for only a single operation.
|
||||
// For example, creating a user in another realm:
|
||||
await this.kcAdminClient.users.create({
|
||||
realm: 'a-third-realm',
|
||||
username: 'username',
|
||||
email: 'user@example.com',
|
||||
});
|
||||
```
|
||||
|
||||
To refresh the access token provided by Keycloak, an OpenID client like [panva/node-openid-client](https://github.com/panva/node-openid-client) can be used like this:
|
||||
|
||||
```js
|
||||
import {Issuer} from 'openid-client';
|
||||
|
||||
const keycloakIssuer = await Issuer.discover(
|
||||
'http://localhost:8080/realms/master',
|
||||
);
|
||||
|
||||
const client = new keycloakIssuer.Client({
|
||||
client_id: 'admin-cli', // Same as `clientId` passed to client.auth()
|
||||
token_endpoint_auth_method: 'none', // to send only client_id in the header
|
||||
});
|
||||
|
||||
// Use the grant type 'password'
|
||||
let tokenSet = await client.grant({
|
||||
grant_type: 'password',
|
||||
username: 'admin',
|
||||
password: 'admin',
|
||||
});
|
||||
|
||||
// Periodically using refresh_token grant flow to get new access token here
|
||||
setInterval(async () => {
|
||||
const refreshToken = tokenSet.refresh_token;
|
||||
tokenSet = await client.refresh(refreshToken);
|
||||
kcAdminClient.setAccessToken(tokenSet.access_token);
|
||||
}, 58 * 1000); // 58 seconds
|
||||
```
|
||||
|
||||
In cases where you don't have a refresh token, eg. in a client credentials flow, you can simply call `kcAdminClient.auth` to get a new access token, like this:
|
||||
|
||||
```js
|
||||
const credentials = {
|
||||
grantType: 'client_credentials',
|
||||
clientId: 'clientId',
|
||||
clientSecret: 'some-client-secret-uuid',
|
||||
};
|
||||
await kcAdminClient.auth(credentials);
|
||||
|
||||
setInterval(() => kcAdminClient.auth(credentials), 58 * 1000); // 58 seconds
|
||||
```
|
||||
|
||||
## Building and running the tests
|
||||
|
||||
To build the source do a build:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
Start the Keycloak server:
|
||||
|
||||
```bash
|
||||
npm run server:start
|
||||
```
|
||||
|
||||
If you started your container manually make sure there is an admin user named 'admin' with password 'admin'.
|
||||
Then start the tests with:
|
||||
|
||||
```bash
|
||||
npm test
|
||||
```
|
||||
|
||||
## Supported APIs
|
||||
|
||||
### [Realm admin](https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_realms_admin_resource)
|
||||
|
||||
Demo code: https://github.com/keycloak/keycloak-nodejs-admin-client/blob/main/libs/keycloak-admin-client/test/realms.spec.ts
|
||||
|
||||
- Import a realm from a full representation of that realm (`POST /`)
|
||||
- Get the top-level representation of the realm (`GET /{realm}`)
|
||||
- Update the top-level information of the realm (`PUT /{realm}`)
|
||||
- Delete the realm (`DELETE /{realm}`)
|
||||
- Partial export of existing realm into a JSON file (`POST /{realm}/partial-export`)
|
||||
- Get users management permissions (`GET /{realm}/users-management-permissions`)
|
||||
- Enable users management permissions (`PUT /{realm}/users-management-permissions`)
|
||||
- Get events (`GET /{realm}/events`)
|
||||
- Get admin events (`GET /{realm}/admin-events`)
|
||||
- Remove all user sessions (`POST /{realm}/logout-all`)
|
||||
- Remove a specific user session (`DELETE /{realm}/sessions/{session}`)
|
||||
- Get client policies policies (`GET /{realm}/client-policies/policies`)
|
||||
- Update client policies policies (`PUT /{realm}/client-policies/policies`)
|
||||
- Get client policies profiles (`GET /{realm}/client-policies/profiles`)
|
||||
- Update client policies profiles (`PUT /{realm}/client-policies/profiles`)
|
||||
- Get a group by path (`GET /{realm}/group-by-path/{path}`)
|
||||
### [Role](https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_roles_resource)
|
||||
|
||||
Demo code: https://github.com/keycloak/keycloak-nodejs-admin-client/blob/main/libs/keycloak-admin-client/test/roles.spec.ts
|
||||
|
||||
- Create a new role for the realm (`POST /{realm}/roles`)
|
||||
- Get all roles for the realm (`GET /{realm}/roles`)
|
||||
- Get a role by name (`GET /{realm}/roles/{role-name}`)
|
||||
- Update a role by name (`PUT /{realm}/roles/{role-name}`)
|
||||
- Delete a role by name (`DELETE /{realm}/roles/{role-name}`)
|
||||
- Get all users in a role by name for the realm (`GET /{realm}/roles/{role-name}/users`)
|
||||
|
||||
### [Roles (by ID)](https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_roles_by_id_resource)
|
||||
|
||||
- Get a specific role (`GET /{realm}/roles-by-id/{role-id}`)
|
||||
- Update the role (`PUT /{realm}/roles-by-id/{role-id}`)
|
||||
- Delete the role (`DELETE /{realm}/roles-by-id/{role-id}`)
|
||||
- Make the role a composite role by associating some child roles(`POST /{realm}/roles-by-id/{role-id}/composites`)
|
||||
- Get role’s children Returns a set of role’s children provided the role is a composite. (`GET /{realm}/roles-by-id/{role-id}/composites`)
|
||||
- Remove a set of roles from the role’s composite (`DELETE /{realm}/roles-by-id/{role-id}/composites`)
|
||||
- Get client-level roles for the client that are in the role’s composite (`GET /{realm}/roles-by-id/{role-id}/composites/clients/{client}`)
|
||||
- Get realm-level roles that are in the role’s composite (`GET /{realm}/roles-by-id/{role-id}/composites/realm`)
|
||||
|
||||
### [User](https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_users_resource)
|
||||
|
||||
Demo code: https://github.com/keycloak/keycloak-nodejs-admin-client/blob/main/libs/keycloak-admin-client/test/users.spec.ts
|
||||
|
||||
- Create a new user (`POST /{realm}/users`)
|
||||
- Get users Returns a list of users, filtered according to query parameters (`GET /{realm}/users`)
|
||||
- Get representation of the user (`GET /{realm}/users/{id}`)
|
||||
- Update the user (`PUT /{realm}/users/{id}`)
|
||||
- Delete the user (`DELETE /{realm}/users/{id}`)
|
||||
- Count users (`GET /{realm}/users/count`)
|
||||
- Send a update account email to the user An email contains a link the user can click to perform a set of required actions. (`PUT /{realm}/users/{id}/execute-actions-email`)
|
||||
- Get user groups (`GET /{realm}/users/{id}/groups`)
|
||||
- Add user to group (`PUT /{realm}/users/{id}/groups/{groupId}`)
|
||||
- Delete user from group (`DELETE /{realm}/users/{id}/groups/{groupId}`)
|
||||
- Remove TOTP from the user (`PUT /{realm}/users/{id}/remove-totp`)
|
||||
- Set up a temporary password for the user User will have to reset the temporary password next time they log in. (`PUT /{realm}/users/{id}/reset-password`)
|
||||
- Send an email-verification email to the user An email contains a link the user can click to verify their email address. (`PUT /{realm}/users/{id}/send-verify-email`)
|
||||
- Update a credential label for a user (`PUT /{realm}/users/{id}/credentials/{credentialId}/userLabel`)
|
||||
- Move a credential to a position behind another credential (`POST /{realm}/users/{id}/credentials/{credentialId}/moveAfter/{newPreviousCredentialId}`)
|
||||
- Move a credential to a first position in the credentials list of the user (`PUT /{realm}/users/{id}/credentials/{credentialId}/moveToFirst`)
|
||||
|
||||
### User group-mapping
|
||||
|
||||
Demo code: https://github.com/keycloak/keycloak-nodejs-admin-client/blob/main/libs/keycloak-admin-client/test/users.spec.ts#L178
|
||||
|
||||
- Add user to group (`PUT /{id}/groups/{groupId}`)
|
||||
- List all user groups (`GET /{id}/groups`)
|
||||
- Count user groups (`GET /{id}/groups/count`)
|
||||
- Remove user from group (`DELETE /{id}/groups/{groupId}`)
|
||||
|
||||
### User role-mapping
|
||||
|
||||
Demo code: https://github.com/keycloak/keycloak-nodejs-admin-client/blob/main/libs/keycloak-admin-client/test/users.spec.ts#L143
|
||||
|
||||
- Get user role-mappings (`GET /{realm}/users/{id}/role-mappings`)
|
||||
- Add realm-level role mappings to the user (`POST /{realm}/users/{id}/role-mappings/realm`)
|
||||
- Get realm-level role mappings (`GET /{realm}/users/{id}/role-mappings/realm`)
|
||||
- Delete realm-level role mappings (`DELETE /{realm}/users/{id}/role-mappings/realm`)
|
||||
- Get realm-level roles that can be mapped (`GET /{realm}/users/{id}/role-mappings/realm/available`)
|
||||
- Get effective realm-level role mappings This will recurse all composite roles to get the result. (`GET /{realm}/users/{id}/role-mappings/realm/composite`)
|
||||
|
||||
### [Group](https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_groups_resource)
|
||||
|
||||
Demo code: https://github.com/keycloak/keycloak-nodejs-admin-client/blob/main/libs/keycloak-admin-client/test/groups.spec.ts
|
||||
|
||||
- Create (`POST /{realm}/groups`)
|
||||
- List (`GET /{realm}/groups`)
|
||||
- Get one (`GET /{realm}/groups/{id}`)
|
||||
- Update (`PUT /{realm}/groups/{id}`)
|
||||
- Delete (`DELETE /{realm}/groups/{id}`)
|
||||
- Count (`GET /{realm}/groups/count`)
|
||||
- List members (`GET /{realm}/groups/{id}/members`)
|
||||
- Set or create child (`POST /{realm}/groups/{id}/children`)
|
||||
|
||||
### Group role-mapping
|
||||
|
||||
Demo code: https://github.com/keycloak/keycloak-nodejs-admin-client/blob/main/libs/keycloak-admin-client/test/groups.spec.ts#L76
|
||||
|
||||
- Get group role-mappings (`GET /{realm}/groups/{id}/role-mappings`)
|
||||
- Add realm-level role mappings to the group (`POST /{realm}/groups/{id}/role-mappings/realm`)
|
||||
- Get realm-level role mappings (`GET /{realm}/groups/{id}/role-mappings/realm`)
|
||||
- Delete realm-level role mappings (`DELETE /{realm}/groups/{id}/role-mappings/realm`)
|
||||
- Get realm-level roles that can be mapped (`GET /{realm}/groups/{id}/role-mappings/realm/available`)
|
||||
- Get effective realm-level role mappings This will recurse all composite roles to get the result. (`GET /{realm}/groups/{id}/role-mappings/realm/composite`)
|
||||
|
||||
### [Client](https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_clients_resource)
|
||||
|
||||
Demo code: https://github.com/keycloak/keycloak-nodejs-admin-client/blob/main/libs/keycloak-admin-client/test/clients.spec.ts
|
||||
|
||||
- Create a new client (`POST /{realm}/clients`)
|
||||
- Get clients belonging to the realm (`GET /{realm}/clients`)
|
||||
- Get representation of the client (`GET /{realm}/clients/{id}`)
|
||||
- Update the client (`PUT /{realm}/clients/{id}`)
|
||||
- Delete the client (`DELETE /{realm}/clients/{id}`)
|
||||
|
||||
### [Client roles](https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_roles_resource)
|
||||
|
||||
Demo code: https://github.com/keycloak/keycloak-nodejs-admin-client/blob/main/libs/keycloak-admin-client/test/clients.spec.ts
|
||||
|
||||
- Create a new role for the client (`POST /{realm}/clients/{id}/roles`)
|
||||
- Get all roles for the client (`GET /{realm}/clients/{id}/roles`)
|
||||
- Get a role by name (`GET /{realm}/clients/{id}/roles/{role-name}`)
|
||||
- Update a role by name (`PUT /{realm}/clients/{id}/roles/{role-name}`)
|
||||
- Delete a role by name (`DELETE /{realm}/clients/{id}/roles/{role-name}`)
|
||||
|
||||
### [Client role-mapping for group](https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_client_role_mappings_resource)
|
||||
|
||||
Demo code: https://github.com/keycloak/keycloak-nodejs-admin-client/blob/main/libs/keycloak-admin-client/test/groups.spec.ts#L150
|
||||
|
||||
- Add client-level roles to the group role mapping (`POST /{realm}/groups/{id}/role-mappings/clients/{client}`)
|
||||
- Get client-level role mappings for the group (`GET /{realm}/groups/{id}/role-mappings/clients/{client}`)
|
||||
- Delete client-level roles from group role mapping (`DELETE /{realm}/groups/{id}/role-mappings/clients/{client}`)
|
||||
- Get available client-level roles that can be mapped to the group (`GET /{realm}/groups/{id}/role-mappings/clients/{client}/available`)
|
||||
- Get effective client-level role mappings This will recurse all composite roles to get the result. (`GET /{realm}/groups/{id}/role-mappings/clients/{client}/composite`)
|
||||
|
||||
### [Client role-mapping for user](https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_client_role_mappings_resource)
|
||||
|
||||
Demo code: https://github.com/keycloak/keycloak-nodejs-admin-client/blob/main/libs/keycloak-admin-client/test/users.spec.ts#L217
|
||||
|
||||
- Add client-level roles to the user role mapping (`POST /{realm}/users/{id}/role-mappings/clients/{client}`)
|
||||
- Get client-level role mappings for the user (`GET /{realm}/users/{id}/role-mappings/clients/{client}`)
|
||||
- Delete client-level roles from user role mapping (`DELETE /{realm}/users/{id}/role-mappings/clients/{client}`)
|
||||
- Get available client-level roles that can be mapped to the user (`GET /{realm}/users/{id}/role-mappings/clients/{client}/available`)
|
||||
- Get effective client-level role mappings This will recurse all composite roles to get the result. (`GET /{realm}/users/{id}/role-mappings/clients/{client}/composite`)
|
||||
|
||||
### [Client Attribute Certificate](https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_client_attribute_certificate_resource)
|
||||
|
||||
- Get key info (`GET /{realm}/clients/{id}/certificates/{attr}`)
|
||||
- Get a keystore file for the client, containing private key and public certificate (`POST /{realm}/clients/{id}/certificates/{attr}/download`)
|
||||
- Generate a new certificate with new key pair (`POST /{realm}/clients/{id}/certificates/{attr}/generate`)
|
||||
- Generate a new keypair and certificate, and get the private key file Generates a keypair and certificate and serves the private key in a specified keystore format. (`POST /{realm}/clients/{id}/certificates/{attr}/generate-and-download`)
|
||||
- Upload certificate and eventually private key (`POST /{realm}/clients/{id}/certificates/{attr}/upload`)
|
||||
- Upload only certificate, not private key (`POST /{realm}/clients/{id}/certificates/{attr}/upload-certificate`)
|
||||
|
||||
### [Identity Providers](https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_identity_providers_resource)
|
||||
|
||||
Demo code: https://github.com/keycloak/keycloak-nodejs-admin-client/blob/main/libs/keycloak-admin-client/test/idp.spec.ts
|
||||
|
||||
- Create a new identity provider (`POST /{realm}/identity-provider/instances`)
|
||||
- Get identity providers (`GET /{realm}/identity-provider/instances`)
|
||||
- Get the identity provider (`GET /{realm}/identity-provider/instances/{alias}`)
|
||||
- Update the identity provider (`PUT /{realm}/identity-provider/instances/{alias}`)
|
||||
- Delete the identity provider (`DELETE /{realm}/identity-provider/instances/{alias}`)
|
||||
- Find identity provider factory (`GET /{realm}/identity-provider/providers/{providerId}`)
|
||||
- Create a new identity provider mapper (`POST /{realm}/identity-provider/instances/{alias}/mappers`)
|
||||
- Get identity provider mappers (`GET /{realm}/identity-provider/instances/{alias}/mappers`)
|
||||
- Get the identity provider mapper (`GET /{realm}/identity-provider/instances/{alias}/mappers/{id}`)
|
||||
- Update the identity provider mapper (`PUT /{realm}/identity-provider/instances/{alias}/mappers/{id}`)
|
||||
- Delete the identity provider mapper (`DELETE /{realm}/identity-provider/instances/{alias}/mappers/{id}`)
|
||||
- Find the identity provider mapper types (`GET /{realm}/identity-provider/instances/{alias}/mapper-types`)
|
||||
|
||||
### [Client Scopes](https://www.keycloak.org/docs-api/6.0/rest-api/index.html#_client_scopes_resource)
|
||||
|
||||
Demo code: https://github.com/keycloak/keycloak-nodejs-admin-client/blob/main/libs/keycloak-admin-client/test/clientScopes.spec.ts
|
||||
|
||||
- Create a new client scope (`POST /{realm}/client-scopes`)
|
||||
- Get client scopes belonging to the realm (`GET /{realm}/client-scopes`)
|
||||
- Get representation of the client scope (`GET /{realm}/client-scopes/{id}`)
|
||||
- Update the client scope (`PUT /{realm}/client-scopes/{id}`)
|
||||
- Delete the client scope (`DELETE /{realm}/client-scopes/{id}`)
|
||||
|
||||
### [Client Scopes for realm](https://www.keycloak.org/docs-api/6.0/rest-api/index.html#_client_scopes_resource)
|
||||
|
||||
Demo code: https://github.com/keycloak/keycloak-nodejs-admin-client/blob/main/libs/keycloak-admin-client/test/clientScopes.spec.ts
|
||||
|
||||
- Get realm default client scopes (`GET /{realm}/default-default-client-scopes`)
|
||||
- Add realm default client scope (`PUT /{realm}/default-default-client-scopes/{id}`)
|
||||
- Delete realm default client scope (`DELETE /{realm}/default-default-client-scopes/{id}`)
|
||||
- Get realm optional client scopes (`GET /{realm}/default-optional-client-scopes`)
|
||||
- Add realm optional client scope (`PUT /{realm}/default-optional-client-scopes/{id}`)
|
||||
- Delete realm optional client scope (`DELETE /{realm}/default-optional-client-scopes/{id}`)
|
||||
|
||||
### [Client Scopes for client](https://www.keycloak.org/docs-api/6.0/rest-api/index.html#_client_scopes_resource)
|
||||
|
||||
Demo code: https://github.com/keycloak/keycloak-nodejs-admin-client/blob/main/libs/keycloak-admin-client/test/clientScopes.spec.ts
|
||||
|
||||
- Get default client scopes (`GET /{realm}/clients/{id}/default-client-scopes`)
|
||||
- Add default client scope (`PUT /{realm}/clients/{id}/default-client-scopes/{clientScopeId}`)
|
||||
- Delete default client scope (`DELETE /{realm}/clients/{id}/default-client-scopes/{clientScopeId}`)
|
||||
- Get optional client scopes (`GET /{realm}/clients/{id}/optional-client-scopes`)
|
||||
- Add optional client scope (`PUT /{realm}/clients/{id}/optional-client-scopes/{clientScopeId}`)
|
||||
- Delete optional client scope (`DELETE /{realm}/clients/{id}/optional-client-scopes/{clientScopeId}`)
|
||||
|
||||
### [Scope Mappings for client scopes](https://www.keycloak.org/docs-api/6.0/rest-api/index.html#_scope_mappings_resource)
|
||||
|
||||
Demo code: https://github.com/keycloak/keycloak-nodejs-admin-client/blob/main/libs/keycloak-admin-client/test/clientScopes.spec.ts
|
||||
|
||||
- Get all scope mappings for the client (`GET /{realm}/client-scopes/{id}/scope-mappings`)
|
||||
- Add client-level roles to the client’s scope (`POST /{realm}/client-scopes/{id}/scope-mappings/clients/{client}`)
|
||||
- Get the roles associated with a client’s scope (`GET /{realm}/client-scopes/{id}/scope-mappings/clients/{client}`)
|
||||
- The available client-level roles (`GET /{realm}/client-scopes/{id}/scope-mappings/clients/{client}/available`)
|
||||
- Get effective client roles (`GET /{realm}/client-scopes/{id}/scope-mappings/clients/{client}/composite`)
|
||||
- Remove client-level roles from the client’s scope. (`DELETE /{realm}/client-scopes/{id}/scope-mappings/clients/{client}`)
|
||||
- Add a set of realm-level roles to the client’s scope (`POST /{realm}/client-scopes/{id}/scope-mappings/realm`)
|
||||
- Get realm-level roles associated with the client’s scope (`GET /{realm}/client-scopes/{id}/scope-mappings/realm`)
|
||||
- Remove a set of realm-level roles from the client’s scope (`DELETE /{realm}/client-scopes/{id}/scope-mappings/realm`)
|
||||
- Get realm-level roles that are available to attach to this client’s scope (`GET /{realm}/client-scopes/{id}/scope-mappings/realm/available`)
|
||||
- Get effective realm-level roles associated with the client’s scope (`GET /{realm}/client-scopes/{id}/scope-mappings/realm/composite`)
|
||||
|
||||
### [Scope Mappings for clients](https://www.keycloak.org/docs-api/6.0/rest-api/index.html#_scope_mappings_resource)
|
||||
|
||||
Demo code: https://github.com/keycloak/keycloak-nodejs-admin-client/blob/main/libs/keycloak-admin-client/test/clientScopes.spec.ts
|
||||
|
||||
- Get all scope mappings for the client (`GET /{realm}/clients/{id}/scope-mappings`)
|
||||
- Add client-level roles to the client’s scope (`POST /{realm}/clients/{id}/scope-mappings/clients/{client}`)
|
||||
- Get the roles associated with a client’s scope (`GET /{realm}/clients/{id}/scope-mappings/clients/{client}`)
|
||||
- Remove client-level roles from the client’s scope. (`DELETE /{realm}/clients/{id}/scope-mappings/clients/{client}`)
|
||||
- The available client-level roles (`GET /{realm}/clients/{id}/scope-mappings/clients/{client}/available`)
|
||||
- Get effective client roles (`GET /{realm}/clients/{id}/scope-mappings/clients/{client}/composite`)
|
||||
- Add a set of realm-level roles to the client’s scope (`POST /{realm}/clients/{id}/scope-mappings/realm`)
|
||||
- Get realm-level roles associated with the client’s scope (`GET /{realm}/clients/{id}/scope-mappings/realm`)
|
||||
- Remove a set of realm-level roles from the client’s scope (`DELETE /{realm}/clients/{id}/scope-mappings/realm`)
|
||||
- Get realm-level roles that are available to attach to this client’s scope (`GET /{realm}/clients/{id}/scope-mappings/realm/available`)
|
||||
- Get effective realm-level roles associated with the client’s scope (`GET /{realm}/clients/{id}/scope-mappings/realm/composite`)
|
||||
|
||||
### [Protocol Mappers for client scopes](https://www.keycloak.org/docs-api/6.0/rest-api/index.html#_protocol_mappers_resource)
|
||||
|
||||
Demo code: https://github.com/keycloak/keycloak-nodejs-admin-client/blob/main/libs/keycloak-admin-client/test/clientScopes.spec.ts
|
||||
|
||||
- Create multiple mappers (`POST /{realm}/client-scopes/{id}/protocol-mappers/add-models`)
|
||||
- Create a mapper (`POST /{realm}/client-scopes/{id}/protocol-mappers/models`)
|
||||
- Get mappers (`GET /{realm}/client-scopes/{id}/protocol-mappers/models`)
|
||||
- Get mapper by id (`GET /{realm}/client-scopes/{id}/protocol-mappers/models/{mapperId}`)
|
||||
- Update the mapper (`PUT /{realm}/client-scopes/{id}/protocol-mappers/models/{mapperId}`)
|
||||
- Delete the mapper (`DELETE /{realm}/client-scopes/{id}/protocol-mappers/models/{mapperId}`)
|
||||
- Get mappers by name for a specific protocol (`GET /{realm}/client-scopes/{id}/protocol-mappers/protocol/{protocol}`)
|
||||
|
||||
### [Protocol Mappers for clients](https://www.keycloak.org/docs-api/6.0/rest-api/index.html#_protocol_mappers_resource)
|
||||
|
||||
Demo code: https://github.com/keycloak/keycloak-nodejs-admin-client/blob/main/libs/keycloak-admin-client/test/clients.spec.ts
|
||||
|
||||
- Create multiple mappers (`POST /{realm}/clients/{id}/protocol-mappers/add-models`)
|
||||
- Create a mapper (`POST /{realm}/clients/{id}/protocol-mappers/models`)
|
||||
- Get mappers (`GET /{realm}/clients/{id}/protocol-mappers/models`)
|
||||
- Get mapper by id (`GET /{realm}/clients/{id}/protocol-mappers/models/{mapperId}`)
|
||||
- Update the mapper (`PUT /{realm}/clients/{id}/protocol-mappers/models/{mapperId}`)
|
||||
- Delete the mapper (`DELETE /{realm}/clients/{id}/protocol-mappers/models/{mapperId}`)
|
||||
- Get mappers by name for a specific protocol (`GET /{realm}/clients/{id}/protocol-mappers/protocol/{protocol}`)
|
||||
|
||||
### [Component]()
|
||||
|
||||
Supported for [user federation](https://www.keycloak.org/docs/latest/server_admin/index.html#_user-storage-federation). Demo code: https://github.com/keycloak/keycloak-nodejs-admin-client/blob/main/libs/keycloak-admin-client/test/components.spec.ts
|
||||
|
||||
- Create (`POST /{realm}/components`)
|
||||
- List (`GET /{realm}/components`)
|
||||
- Get (`GET /{realm}/components/{id}`)
|
||||
- Update (`PUT /{realm}/components/{id}`)
|
||||
- Delete (`DELETE /{realm}/components/{id}`)
|
||||
|
||||
### [Sessions for clients]()
|
||||
|
||||
Demo code: https://github.com/keycloak/keycloak-nodejs-admin-client/blob/main/libs/keycloak-admin-client/test/clients.spec.ts
|
||||
|
||||
- List user sessions for a specific client (`GET /{realm}/clients/{id}/user-sessions`)
|
||||
- List offline sessions for a specific client (`GET /{realm}/clients/{id}/offline-sessions`)
|
||||
- Get user session count for a specific client (`GET /{realm}/clients/{id}/session-count`)
|
||||
- List offline session count for a specific client (`GET /{realm}/clients/{id}/offline-session-count`)
|
||||
|
||||
### [Authentication Management: Required actions](https://www.keycloak.org/docs-api/8.0/rest-api/index.html#_authentication_management_resource)
|
||||
|
||||
Demo code: https://github.com/keycloak/keycloak-nodejs-admin-client/blob/main/libs/keycloak-admin-client/test/authenticationManagement.spec.ts
|
||||
|
||||
- Register a new required action (`POST /{realm}/authentication/register-required-action`)
|
||||
- Get required actions. Returns a list of required actions. (`GET /{realm}/authentication/required-actions`)
|
||||
- Get required action for alias (`GET /{realm}/authentication/required-actions/{alias}`)
|
||||
- Update required action (`PUT /{realm}/authentication/required-actions/{alias}`)
|
||||
- Delete required action (`DELETE /{realm}/authentication/required-actions/{alias}`)
|
||||
- Lower required action’s priority (`POST /{realm}/authentication/required-actions/{alias}/lower-priority`)
|
||||
- Raise required action’s priority (`POST /{realm}/authentication/required-actions/{alias}/raise-priority`)
|
||||
- Get unregistered required actions Returns a list of unregistered required actions. (`GET /{realm}/authentication/unregistered-required-actions`)
|
||||
|
||||
### [Authorization: Permission](https://www.keycloak.org/docs/8.0/authorization_services/#_overview)
|
||||
|
||||
Demo code: https://github.com/keycloak/keycloak-nodejs-admin-client/blob/main/libs/keycloak-admin-client/test/clients.spec.ts
|
||||
|
||||
- Create permission (`POST /{realm}/clients/{id}/authz/resource-server/permission/{type}`)
|
||||
- Get permission (`GET /{realm}/clients/{id}/authz/resource-server/permission/{type}/{permissionId}`)
|
||||
- Update permission (`PUT /{realm}/clients/{id}/authz/resource-server/permission/{type}/{permissionId}`)
|
||||
- Delete permission (`DELETE /{realm}/clients/{id}/authz/resource-server/permission/{type}/{permissionId}`)
|
||||
|
||||
### [Authorization: Policy](https://www.keycloak.org/docs/8.0/authorization_services/#_overview)
|
||||
|
||||
Demo code: https://github.com/keycloak/keycloak-nodejs-admin-client/blob/main/libs/keycloak-admin-client/test/clients.spec.ts
|
||||
|
||||
- Create policy (`POST /{realm}/clients/{id}/authz/resource-server/policy/{type}`)
|
||||
- Get policy (`GET /{realm}/clients/{id}/authz/resource-server/policy/{type}/{policyId}`)
|
||||
- Get policy by name (`GET /{realm}/clients/{id}/authz/resource-server/policy/search`)
|
||||
- Update policy (`PUT /{realm}/clients/{id}/authz/resource-server/policy/{type}/{policyId}`)
|
||||
- Delete policy (`DELETE /{realm}/clients/{id}/authz/resource-server/policy/{policyId}`)
|
||||
|
||||
### [Attack Detection](https://www.keycloak.org/docs-api/5.0/rest-api/index.html#_attack_detection_resource)
|
||||
|
||||
Demo code: https://github.com/keycloak/keycloak-nodejs-admin-client/blob/main/libs/keycloak-admin-client/test/attackDetection.spec.ts
|
||||
|
||||
- Clear any user login failures for all users This can release temporary disabled users (`DELETE /{realm}/attack-detection/brute-force/users`)
|
||||
- Get status of a username in brute force detection (`GET /{realm}/attack-detection/brute-force/users/{userId}`)
|
||||
- Clear any user login failures for the user This can release temporary disabled user (`DELETE /{realm}/attack-detection/brute-force/users/{userId}`)
|
||||
|
||||
## Not yet supported
|
||||
|
||||
- [Authentication Management](https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_authentication_management_resource)
|
||||
- [Client Initial Access](https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_client_initial_access_resource)
|
||||
- [Client Registration Policy](https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_client_registration_policy_resource)
|
||||
- [Key](https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_key_resource)
|
||||
- [User Storage Provider](https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_user_storage_provider_resource)
|
||||
|
||||
## Maintainers
|
||||
|
||||
This repo is originally developed by [Canner](https://www.cannercms.com) and [InfuseAI](https://infuseai.io) before being transferred under keycloak organization.
|
63
libs/keycloak-admin-client/package.json
Normal file
63
libs/keycloak-admin-client/package.json
Normal file
|
@ -0,0 +1,63 @@
|
|||
{
|
||||
"name": "@keycloak/keycloak-admin-client",
|
||||
"version": "999.0.0-dev",
|
||||
"description": "keycloak admin client",
|
||||
"type": "module",
|
||||
"main": "lib/index.js",
|
||||
"files": [
|
||||
"lib"
|
||||
],
|
||||
"types": "lib/index.d.ts",
|
||||
"engines": {
|
||||
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "wireit",
|
||||
"lint": "wireit",
|
||||
"test": "wireit",
|
||||
"prepublishOnly": "npm run build"
|
||||
},
|
||||
"wireit": {
|
||||
"build": {
|
||||
"command": "tsc --pretty",
|
||||
"files": [
|
||||
"src/**",
|
||||
"package.json",
|
||||
"tsconfig.json"
|
||||
],
|
||||
"output": [
|
||||
"lib/**"
|
||||
]
|
||||
},
|
||||
"lint": {
|
||||
"command": "eslint . --ext js,jsx,mjs,ts,tsx"
|
||||
},
|
||||
"test": {
|
||||
"command": "TS_NODE_PROJECT=tsconfig.test.json mocha --recursive \"test/**/*.spec.ts\" --timeout 10000"
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^0.27.2",
|
||||
"camelize-ts": "^2.1.1",
|
||||
"lodash-es": "^4.17.21",
|
||||
"url-join": "^5.0.0",
|
||||
"url-template": "^3.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@faker-js/faker": "^7.1.0",
|
||||
"@types/chai": "^4.2.14",
|
||||
"@types/lodash-es": "^4.17.5",
|
||||
"@types/mocha": "^10.0.0",
|
||||
"@types/node": "^18.0.3",
|
||||
"chai": "^4.1.2",
|
||||
"mocha": "^10.0.0",
|
||||
"ts-node": "^10.2.1"
|
||||
},
|
||||
"author": "wwwy3y3",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/keycloak/keycloak-ui.git"
|
||||
},
|
||||
"homepage": "https://www.keycloak.org/"
|
||||
}
|
144
libs/keycloak-admin-client/src/client.ts
Normal file
144
libs/keycloak-admin-client/src/client.ts
Normal file
|
@ -0,0 +1,144 @@
|
|||
import type { AxiosRequestConfig } from "axios";
|
||||
import type { RequestArgs } from "./resources/agent.js";
|
||||
import { AttackDetection } from "./resources/attackDetection.js";
|
||||
import { AuthenticationManagement } from "./resources/authenticationManagement.js";
|
||||
import { Cache } from "./resources/cache.js";
|
||||
import { ClientPolicies } from "./resources/clientPolicies.js";
|
||||
import { Clients } from "./resources/clients.js";
|
||||
import { ClientScopes } from "./resources/clientScopes.js";
|
||||
import { Components } from "./resources/components.js";
|
||||
import { Groups } from "./resources/groups.js";
|
||||
import { IdentityProviders } from "./resources/identityProviders.js";
|
||||
import { Realms } from "./resources/realms.js";
|
||||
import { Roles } from "./resources/roles.js";
|
||||
import { ServerInfo } from "./resources/serverInfo.js";
|
||||
import { Sessions } from "./resources/sessions.js";
|
||||
import { Users } from "./resources/users.js";
|
||||
import { UserStorageProvider } from "./resources/userStorageProvider.js";
|
||||
import { WhoAmI } from "./resources/whoAmI.js";
|
||||
import { Credentials, getToken } from "./utils/auth.js";
|
||||
import { defaultBaseUrl, defaultRealm } from "./utils/constants.js";
|
||||
|
||||
export interface TokenProvider {
|
||||
getAccessToken: () => Promise<string | undefined>;
|
||||
}
|
||||
|
||||
export interface ConnectionConfig {
|
||||
baseUrl?: string;
|
||||
realmName?: string;
|
||||
requestConfig?: AxiosRequestConfig;
|
||||
requestArgOptions?: Pick<RequestArgs, "catchNotFound">;
|
||||
}
|
||||
|
||||
export class KeycloakAdminClient {
|
||||
// Resources
|
||||
public users: Users;
|
||||
public userStorageProvider: UserStorageProvider;
|
||||
public groups: Groups;
|
||||
public roles: Roles;
|
||||
public clients: Clients;
|
||||
public realms: Realms;
|
||||
public clientScopes: ClientScopes;
|
||||
public clientPolicies: ClientPolicies;
|
||||
public identityProviders: IdentityProviders;
|
||||
public components: Components;
|
||||
public serverInfo: ServerInfo;
|
||||
public whoAmI: WhoAmI;
|
||||
public attackDetection: AttackDetection;
|
||||
public sessions: Sessions;
|
||||
public authenticationManagement: AuthenticationManagement;
|
||||
public cache: Cache;
|
||||
|
||||
// Members
|
||||
public baseUrl: string;
|
||||
public realmName: string;
|
||||
public accessToken?: string;
|
||||
public refreshToken?: string;
|
||||
|
||||
private requestConfig?: AxiosRequestConfig;
|
||||
private globalRequestArgOptions?: Pick<RequestArgs, "catchNotFound">;
|
||||
private tokenProvider?: TokenProvider;
|
||||
|
||||
constructor(connectionConfig?: ConnectionConfig) {
|
||||
this.baseUrl = connectionConfig?.baseUrl || defaultBaseUrl;
|
||||
this.realmName = connectionConfig?.realmName || defaultRealm;
|
||||
this.requestConfig = connectionConfig?.requestConfig;
|
||||
this.globalRequestArgOptions = connectionConfig?.requestArgOptions;
|
||||
|
||||
// Initialize resources
|
||||
this.users = new Users(this);
|
||||
this.userStorageProvider = new UserStorageProvider(this);
|
||||
this.groups = new Groups(this);
|
||||
this.roles = new Roles(this);
|
||||
this.clients = new Clients(this);
|
||||
this.realms = new Realms(this);
|
||||
this.clientScopes = new ClientScopes(this);
|
||||
this.clientPolicies = new ClientPolicies(this);
|
||||
this.identityProviders = new IdentityProviders(this);
|
||||
this.components = new Components(this);
|
||||
this.authenticationManagement = new AuthenticationManagement(this);
|
||||
this.serverInfo = new ServerInfo(this);
|
||||
this.whoAmI = new WhoAmI(this);
|
||||
this.sessions = new Sessions(this);
|
||||
this.attackDetection = new AttackDetection(this);
|
||||
this.cache = new Cache(this);
|
||||
}
|
||||
|
||||
public async auth(credentials: Credentials) {
|
||||
const { accessToken, refreshToken } = await getToken({
|
||||
baseUrl: this.baseUrl,
|
||||
realmName: this.realmName,
|
||||
credentials,
|
||||
requestConfig: this.requestConfig,
|
||||
});
|
||||
this.accessToken = accessToken;
|
||||
this.refreshToken = refreshToken;
|
||||
}
|
||||
|
||||
public registerTokenProvider(provider: TokenProvider) {
|
||||
if (this.tokenProvider) {
|
||||
throw new Error("An existing token provider was already registered.");
|
||||
}
|
||||
|
||||
this.tokenProvider = provider;
|
||||
}
|
||||
|
||||
public setAccessToken(token: string) {
|
||||
this.accessToken = token;
|
||||
}
|
||||
|
||||
public async getAccessToken() {
|
||||
if (this.tokenProvider) {
|
||||
return this.tokenProvider.getAccessToken();
|
||||
}
|
||||
|
||||
return this.accessToken;
|
||||
}
|
||||
|
||||
public getRequestConfig() {
|
||||
return this.requestConfig;
|
||||
}
|
||||
|
||||
public getGlobalRequestArgOptions():
|
||||
| Pick<RequestArgs, "catchNotFound">
|
||||
| undefined {
|
||||
return this.globalRequestArgOptions;
|
||||
}
|
||||
|
||||
public setConfig(connectionConfig: ConnectionConfig) {
|
||||
if (
|
||||
typeof connectionConfig.baseUrl === "string" &&
|
||||
connectionConfig.baseUrl
|
||||
) {
|
||||
this.baseUrl = connectionConfig.baseUrl;
|
||||
}
|
||||
|
||||
if (
|
||||
typeof connectionConfig.realmName === "string" &&
|
||||
connectionConfig.realmName
|
||||
) {
|
||||
this.realmName = connectionConfig.realmName;
|
||||
}
|
||||
this.requestConfig = connectionConfig.requestConfig;
|
||||
}
|
||||
}
|
4
libs/keycloak-admin-client/src/defs/AccessTokenAccess.ts
Normal file
4
libs/keycloak-admin-client/src/defs/AccessTokenAccess.ts
Normal file
|
@ -0,0 +1,4 @@
|
|||
export default interface AccessTokenAccess {
|
||||
roles?: string[];
|
||||
verify_caller?: boolean;
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
export default interface PermissionRepresentation {
|
||||
claims?: { [index: string]: string };
|
||||
rsid?: string;
|
||||
rsname?: string;
|
||||
scopes?: string[];
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
export default interface AccessTokenCertConf {
|
||||
"x5t#S256"?: string;
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
import type AccessTokenAccess from "./AccessTokenAccess.js";
|
||||
import type AccessTokenCertConf from "./accessTokenCertConf.js";
|
||||
import type AddressClaimSet from "./addressClaimSet.js";
|
||||
import type { Category } from "./resourceServerRepresentation.js";
|
||||
|
||||
export default interface AccessTokenRepresentation {
|
||||
acr?: string;
|
||||
address?: AddressClaimSet;
|
||||
"allowed-origins"?: string[];
|
||||
at_hash?: string;
|
||||
auth_time?: number;
|
||||
authorization?: AccessTokenRepresentation;
|
||||
azp?: string;
|
||||
birthdate?: string;
|
||||
c_hash?: string;
|
||||
category?: Category;
|
||||
claims_locales?: string;
|
||||
cnf?: AccessTokenCertConf;
|
||||
email?: string;
|
||||
email_verified?: boolean;
|
||||
exp?: number;
|
||||
family_name?: string;
|
||||
gender: string;
|
||||
given_name?: string;
|
||||
iat?: number;
|
||||
iss?: string;
|
||||
jti?: string;
|
||||
locale?: string;
|
||||
middle_name?: string;
|
||||
name?: string;
|
||||
nbf?: number;
|
||||
nickname?: string;
|
||||
nonce?: string;
|
||||
otherClaims?: { [index: string]: string };
|
||||
phone_number?: string;
|
||||
phone_number_verified?: boolean;
|
||||
picture?: string;
|
||||
preferred_username?: string;
|
||||
profile?: string;
|
||||
realm_access?: AccessTokenAccess;
|
||||
s_hash?: string;
|
||||
scope?: string;
|
||||
session_state?: string;
|
||||
sub?: string;
|
||||
"trusted-certs"?: string[];
|
||||
typ?: string;
|
||||
updated_at?: number;
|
||||
website?: string;
|
||||
zoneinfo?: string;
|
||||
}
|
8
libs/keycloak-admin-client/src/defs/addressClaimSet.ts
Normal file
8
libs/keycloak-admin-client/src/defs/addressClaimSet.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
export default interface AddressClaimSet {
|
||||
country?: string;
|
||||
formatted?: string;
|
||||
locality?: string;
|
||||
postal_code?: string;
|
||||
region?: string;
|
||||
street_address?: string;
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
import type AuthDetailsRepresentation from "./authDetailsRepresentation.js";
|
||||
|
||||
export default interface AdminEventRepresentation {
|
||||
authDetails?: AuthDetailsRepresentation;
|
||||
error?: string;
|
||||
operationType?: string;
|
||||
realmId?: string;
|
||||
representation?: string;
|
||||
resourcePath?: string;
|
||||
resourceType?: string;
|
||||
time?: number;
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
export default interface AuthDetailsRepresentation {
|
||||
clientId?: string;
|
||||
ipAddress?: string;
|
||||
realmId?: string;
|
||||
userId?: string;
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
/**
|
||||
* https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_authenticationexecutionexportrepresentation
|
||||
*/
|
||||
export default interface AuthenticationExecutionExportRepresentation {
|
||||
flowAlias?: string;
|
||||
userSetupAllowed?: boolean;
|
||||
authenticatorConfig?: string;
|
||||
authenticator?: string;
|
||||
requirement?: string;
|
||||
priority?: number;
|
||||
autheticatorFlow?: boolean;
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
/**
|
||||
* https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_authenticationexecutioninforepresentation
|
||||
*/
|
||||
export default interface AuthenticationExecutionInfoRepresentation {
|
||||
id?: string;
|
||||
requirement?: string;
|
||||
displayName?: string;
|
||||
alias?: string;
|
||||
description?: string;
|
||||
requirementChoices?: string[];
|
||||
configurable?: boolean;
|
||||
authenticationFlow?: boolean;
|
||||
providerId?: string;
|
||||
authenticationConfig?: string;
|
||||
flowId?: string;
|
||||
level?: number;
|
||||
index?: number;
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
import type AuthenticationExecutionExportRepresentation from "./authenticationExecutionExportRepresentation.js";
|
||||
|
||||
/**
|
||||
* https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_authenticationflowrepresentation
|
||||
*/
|
||||
export default interface AuthenticationFlowRepresentation {
|
||||
id?: string;
|
||||
alias?: string;
|
||||
description?: string;
|
||||
providerId?: string;
|
||||
topLevel?: boolean;
|
||||
builtIn?: boolean;
|
||||
authenticationExecutions?: AuthenticationExecutionExportRepresentation[];
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
/**
|
||||
* https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_authenticatorconfiginforepresentation
|
||||
*/
|
||||
export default interface AuthenticatorConfigInfoRepresentation {
|
||||
name?: string;
|
||||
providerId?: string;
|
||||
helpText?: string;
|
||||
properties?: ConfigPropertyRepresentation[];
|
||||
}
|
||||
|
||||
export interface ConfigPropertyRepresentation {
|
||||
name?: string;
|
||||
label?: string;
|
||||
helpText?: string;
|
||||
type?: string;
|
||||
defaultValue?: any;
|
||||
options?: string[];
|
||||
secret?: boolean;
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
/**
|
||||
* https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_authenticatorconfigrepresentation
|
||||
*/
|
||||
export default interface AuthenticatorConfigRepresentation {
|
||||
id?: string;
|
||||
alias?: string;
|
||||
config?: { [index: string]: string };
|
||||
}
|
||||
|
||||
// we defined this type ourself as the original is just `{[index: string]: any}[]`
|
||||
// but the admin console does assume these properties are there.
|
||||
export interface AuthenticationProviderRepresentation {
|
||||
id?: string;
|
||||
displayName?: string;
|
||||
description?: string;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
/**
|
||||
* https://www.keycloak.org/docs-api/11.0/rest-api/#_certificaterepresentation
|
||||
*/
|
||||
export default interface CertificateRepresentation {
|
||||
privateKey?: string;
|
||||
publicKey?: string;
|
||||
certificate?: string;
|
||||
kid?: string;
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
/**
|
||||
* https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_clientinitialaccesspresentation
|
||||
*/
|
||||
export default interface ClientInitialAccessPresentation {
|
||||
id?: string;
|
||||
token?: string;
|
||||
timestamp?: number;
|
||||
expiration?: number;
|
||||
count?: number;
|
||||
remainingCount?: number;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
import type ClientPolicyRepresentation from "./clientPolicyRepresentation.js";
|
||||
|
||||
/**
|
||||
* https://www.keycloak.org/docs-api/15.0/rest-api/#_clientpoliciesrepresentation
|
||||
*/
|
||||
export default interface ClientPoliciesRepresentation {
|
||||
policies?: ClientPolicyRepresentation[];
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
/**
|
||||
* https://www.keycloak.org/docs-api/15.0/rest-api/#_clientpolicyconditionrepresentation
|
||||
*/
|
||||
export default interface ClientPolicyConditionRepresentation {
|
||||
condition?: string;
|
||||
configuration?: object;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
/**
|
||||
* https://www.keycloak.org/docs-api/15.0/rest-api/#_clientpolicyexecutorrepresentation
|
||||
*/
|
||||
export default interface ClientPolicyExecutorRepresentation {
|
||||
configuration?: object;
|
||||
executor?: string;
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
import type ClientPolicyConditionRepresentation from "./clientPolicyConditionRepresentation.js";
|
||||
|
||||
/**
|
||||
* https://www.keycloak.org/docs-api/15.0/rest-api/#_clientpolicyrepresentation
|
||||
*/
|
||||
export default interface ClientPolicyRepresentation {
|
||||
conditions?: ClientPolicyConditionRepresentation[];
|
||||
description?: string;
|
||||
enabled?: boolean;
|
||||
name?: string;
|
||||
profiles?: string[];
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
import type ClientPolicyExecutorRepresentation from "./clientPolicyExecutorRepresentation.js";
|
||||
|
||||
/**
|
||||
* https://www.keycloak.org/docs-api/15.0/rest-api/#_clientprofilerepresentation
|
||||
*/
|
||||
export default interface ClientProfileRepresentation {
|
||||
description?: string;
|
||||
executors?: ClientPolicyExecutorRepresentation[];
|
||||
name?: string;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
import type ClientProfileRepresentation from "./clientProfileRepresentation.js";
|
||||
|
||||
/**
|
||||
* https://www.keycloak.org/docs-api/15.0/rest-api/#_clientprofilesrepresentation
|
||||
*/
|
||||
export default interface ClientProfilesRepresentation {
|
||||
globalProfiles?: ClientProfileRepresentation[];
|
||||
profiles?: ClientProfileRepresentation[];
|
||||
}
|
46
libs/keycloak-admin-client/src/defs/clientRepresentation.ts
Normal file
46
libs/keycloak-admin-client/src/defs/clientRepresentation.ts
Normal file
|
@ -0,0 +1,46 @@
|
|||
/**
|
||||
* https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_clientrepresentation
|
||||
*/
|
||||
import type ResourceServerRepresentation from "./resourceServerRepresentation.js";
|
||||
import type ProtocolMapperRepresentation from "./protocolMapperRepresentation.js";
|
||||
|
||||
export default interface ClientRepresentation {
|
||||
access?: Record<string, boolean>;
|
||||
adminUrl?: string;
|
||||
attributes?: Record<string, any>;
|
||||
authenticationFlowBindingOverrides?: Record<string, any>;
|
||||
authorizationServicesEnabled?: boolean;
|
||||
authorizationSettings?: ResourceServerRepresentation;
|
||||
baseUrl?: string;
|
||||
bearerOnly?: boolean;
|
||||
clientAuthenticatorType?: string;
|
||||
clientId?: string;
|
||||
consentRequired?: boolean;
|
||||
defaultClientScopes?: string[];
|
||||
defaultRoles?: string[];
|
||||
description?: string;
|
||||
directAccessGrantsEnabled?: boolean;
|
||||
enabled?: boolean;
|
||||
alwaysDisplayInConsole?: boolean;
|
||||
frontchannelLogout?: boolean;
|
||||
fullScopeAllowed?: boolean;
|
||||
id?: string;
|
||||
implicitFlowEnabled?: boolean;
|
||||
name?: string;
|
||||
nodeReRegistrationTimeout?: number;
|
||||
notBefore?: number;
|
||||
optionalClientScopes?: string[];
|
||||
origin?: string;
|
||||
protocol?: string;
|
||||
protocolMappers?: ProtocolMapperRepresentation[];
|
||||
publicClient?: boolean;
|
||||
redirectUris?: string[];
|
||||
registeredNodes?: Record<string, any>;
|
||||
registrationAccessToken?: string;
|
||||
rootUrl?: string;
|
||||
secret?: string;
|
||||
serviceAccountsEnabled?: boolean;
|
||||
standardFlowEnabled?: boolean;
|
||||
surrogateAuthRequired?: boolean;
|
||||
webOrigins?: string[];
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
/**
|
||||
* https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_clientscoperepresentation
|
||||
*/
|
||||
import type ProtocolMapperRepresentation from "./protocolMapperRepresentation.js";
|
||||
|
||||
export default interface ClientScopeRepresentation {
|
||||
attributes?: Record<string, any>;
|
||||
description?: string;
|
||||
id?: string;
|
||||
name?: string;
|
||||
protocol?: string;
|
||||
protocolMappers?: ProtocolMapperRepresentation[];
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
/**
|
||||
* https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_componentexportrepresentation
|
||||
*/
|
||||
|
||||
export default interface ComponentExportRepresentation {
|
||||
id?: string;
|
||||
name?: string;
|
||||
providerId?: string;
|
||||
subType?: string;
|
||||
subComponents?: { [index: string]: ComponentExportRepresentation };
|
||||
config?: { [index: string]: string };
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
/**
|
||||
* https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_componentrepresentation
|
||||
*/
|
||||
|
||||
export default interface ComponentRepresentation {
|
||||
id?: string;
|
||||
name?: string;
|
||||
providerId?: string;
|
||||
providerType?: string;
|
||||
parentId?: string;
|
||||
subType?: string;
|
||||
config?: { [index: string]: string | string[] };
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
import type { ConfigPropertyRepresentation } from "./configPropertyRepresentation.js";
|
||||
|
||||
/**
|
||||
* https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_componenttyperepresentation
|
||||
*/
|
||||
export default interface ComponentTypeRepresentation {
|
||||
id: string;
|
||||
helpText: string;
|
||||
properties: ConfigPropertyRepresentation[];
|
||||
metadata: { [index: string]: any };
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
/**
|
||||
* https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_configpropertyrepresentation
|
||||
*/
|
||||
export interface ConfigPropertyRepresentation {
|
||||
name?: string;
|
||||
label?: string;
|
||||
helpText?: string;
|
||||
type?: string;
|
||||
defaultValue?: object;
|
||||
options?: string[];
|
||||
secret?: boolean;
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
/**
|
||||
* https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_credentialrepresentation
|
||||
*/
|
||||
|
||||
export default interface CredentialRepresentation {
|
||||
createdDate?: number;
|
||||
credentialData?: string;
|
||||
id?: string;
|
||||
priority?: number;
|
||||
secretData?: string;
|
||||
temporary?: boolean;
|
||||
type?: string;
|
||||
userLabel?: string;
|
||||
value?: string;
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
import type { DecisionEffect } from "./policyRepresentation.js";
|
||||
import type PolicyResultRepresentation from "./policyResultRepresentation.js";
|
||||
import type ResourceRepresentation from "./resourceRepresentation.js";
|
||||
import type ScopeRepresentation from "./scopeRepresentation.js";
|
||||
|
||||
export default interface EvaluationResultRepresentation {
|
||||
resource?: ResourceRepresentation;
|
||||
scopes?: ScopeRepresentation[];
|
||||
policies?: PolicyResultRepresentation[];
|
||||
status?: DecisionEffect;
|
||||
allowedScopes?: ScopeRepresentation[];
|
||||
}
|
16
libs/keycloak-admin-client/src/defs/eventRepresentation.ts
Normal file
16
libs/keycloak-admin-client/src/defs/eventRepresentation.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
/**
|
||||
* https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_eventrepresentation
|
||||
*/
|
||||
import type EventType from "./eventTypes.js";
|
||||
|
||||
export default interface EventRepresentation {
|
||||
clientId?: string;
|
||||
details?: Record<string, any>;
|
||||
error?: string;
|
||||
ipAddress?: string;
|
||||
realmId?: string;
|
||||
sessionId?: string;
|
||||
time?: number;
|
||||
type?: EventType;
|
||||
userId?: string;
|
||||
}
|
89
libs/keycloak-admin-client/src/defs/eventTypes.ts
Normal file
89
libs/keycloak-admin-client/src/defs/eventTypes.ts
Normal file
|
@ -0,0 +1,89 @@
|
|||
type EventType =
|
||||
| "LOGIN"
|
||||
| "LOGIN_ERROR"
|
||||
| "REGISTER"
|
||||
| "REGISTER_ERROR"
|
||||
| "LOGOUT"
|
||||
| "LOGOUT_ERROR"
|
||||
| "CODE_TO_TOKEN"
|
||||
| "CODE_TO_TOKEN_ERROR"
|
||||
| "CLIENT_LOGIN"
|
||||
| "CLIENT_LOGIN_ERROR"
|
||||
| "REFRESH_TOKEN"
|
||||
| "REFRESH_TOKEN_ERROR"
|
||||
| "VALIDATE_ACCESS_TOKEN"
|
||||
| "VALIDATE_ACCESS_TOKEN_ERROR"
|
||||
| "INTROSPECT_TOKEN"
|
||||
| "INTROSPECT_TOKEN_ERROR"
|
||||
| "FEDERATED_IDENTITY_LINK"
|
||||
| "FEDERATED_IDENTITY_LINK_ERROR"
|
||||
| "REMOVE_FEDERATED_IDENTITY"
|
||||
| "REMOVE_FEDERATED_IDENTITY_ERROR"
|
||||
| "UPDATE_EMAIL"
|
||||
| "UPDATE_EMAIL_ERROR"
|
||||
| "UPDATE_PROFILE"
|
||||
| "UPDATE_PROFILE_ERROR"
|
||||
| "UPDATE_PASSWORD"
|
||||
| "UPDATE_PASSWORD_ERROR"
|
||||
| "UPDATE_TOTP"
|
||||
| "UPDATE_TOTP_ERROR"
|
||||
| "VERIFY_EMAIL"
|
||||
| "VERIFY_EMAIL_ERROR"
|
||||
| "REMOVE_TOTP"
|
||||
| "REMOVE_TOTP_ERROR"
|
||||
| "REVOKE_GRANT"
|
||||
| "REVOKE_GRANT_ERROR"
|
||||
| "SEND_VERIFY_EMAIL"
|
||||
| "SEND_VERIFY_EMAIL_ERROR"
|
||||
| "SEND_RESET_PASSWORD"
|
||||
| "SEND_RESET_PASSWORD_ERROR"
|
||||
| "SEND_IDENTITY_PROVIDER_LINK"
|
||||
| "SEND_IDENTITY_PROVIDER_LINK_ERROR"
|
||||
| "RESET_PASSWORD"
|
||||
| "RESET_PASSWORD_ERROR"
|
||||
| "RESTART_AUTHENTICATION"
|
||||
| "RESTART_AUTHENTICATION_ERROR"
|
||||
| "INVALID_SIGNATURE"
|
||||
| "INVALID_SIGNATURE_ERROR"
|
||||
| "REGISTER_NODE"
|
||||
| "REGISTER_NODE_ERROR"
|
||||
| "UNREGISTER_NODE"
|
||||
| "UNREGISTER_NODE_ERROR"
|
||||
| "USER_INFO_REQUEST"
|
||||
| "USER_INFO_REQUEST_ERROR"
|
||||
| "IDENTITY_PROVIDER_LINK_ACCOUNT"
|
||||
| "IDENTITY_PROVIDER_LINK_ACCOUNT_ERROR"
|
||||
| "IDENTITY_PROVIDER_LOGIN"
|
||||
| "IDENTITY_PROVIDER_LOGIN_ERROR"
|
||||
| "IDENTITY_PROVIDER_FIRST_LOGIN"
|
||||
| "IDENTITY_PROVIDER_FIRST_LOGIN_ERROR"
|
||||
| "IDENTITY_PROVIDER_POST_LOGIN"
|
||||
| "IDENTITY_PROVIDER_POST_LOGIN_ERROR"
|
||||
| "IDENTITY_PROVIDER_RESPONSE"
|
||||
| "IDENTITY_PROVIDER_RESPONSE_ERROR"
|
||||
| "IDENTITY_PROVIDER_RETRIEVE_TOKEN"
|
||||
| "IDENTITY_PROVIDER_RETRIEVE_TOKEN_ERROR"
|
||||
| "IMPERSONATE"
|
||||
| "IMPERSONATE_ERROR"
|
||||
| "CUSTOM_REQUIRED_ACTION"
|
||||
| "CUSTOM_REQUIRED_ACTION_ERROR"
|
||||
| "EXECUTE_ACTIONS"
|
||||
| "EXECUTE_ACTIONS_ERROR"
|
||||
| "EXECUTE_ACTION_TOKEN"
|
||||
| "EXECUTE_ACTION_TOKEN_ERROR"
|
||||
| "CLIENT_INFO"
|
||||
| "CLIENT_INFO_ERROR"
|
||||
| "CLIENT_REGISTER"
|
||||
| "CLIENT_REGISTER_ERROR"
|
||||
| "CLIENT_UPDATE"
|
||||
| "CLIENT_UPDATE_ERROR"
|
||||
| "CLIENT_DELETE"
|
||||
| "CLIENT_DELETE_ERROR"
|
||||
| "CLIENT_INITIATED_ACCOUNT_LINKING"
|
||||
| "CLIENT_INITIATED_ACCOUNT_LINKING_ERROR"
|
||||
| "TOKEN_EXCHANGE"
|
||||
| "TOKEN_EXCHANGE_ERROR"
|
||||
| "PERMISSION_TOKEN"
|
||||
| "PERMISSION_TOKEN_ERROR";
|
||||
|
||||
export default EventType;
|
|
@ -0,0 +1,9 @@
|
|||
/**
|
||||
* https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_federatedidentityrepresentation
|
||||
*/
|
||||
|
||||
export default interface FederatedIdentityRepresentation {
|
||||
identityProvider?: string;
|
||||
userId?: string;
|
||||
userName?: string;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
/**
|
||||
* https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_globalrequestresult
|
||||
*/
|
||||
export default interface GlobalRequestResult {
|
||||
successRequests?: string[];
|
||||
failedRequests?: string[];
|
||||
}
|
16
libs/keycloak-admin-client/src/defs/groupRepresentation.ts
Normal file
16
libs/keycloak-admin-client/src/defs/groupRepresentation.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
/**
|
||||
* https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_grouprepresentation
|
||||
*/
|
||||
|
||||
export default interface GroupRepresentation {
|
||||
id?: string;
|
||||
name?: string;
|
||||
path?: string;
|
||||
subGroups?: GroupRepresentation[];
|
||||
|
||||
// optional in response
|
||||
access?: Record<string, boolean>;
|
||||
attributes?: Record<string, any>;
|
||||
clientRoles?: Record<string, any>;
|
||||
realmRoles?: string[];
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
/**
|
||||
* https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_identityprovidermapperrepresentation
|
||||
*/
|
||||
|
||||
export default interface IdentityProviderMapperRepresentation {
|
||||
config?: any;
|
||||
id?: string;
|
||||
identityProviderAlias?: string;
|
||||
identityProviderMapper?: string;
|
||||
name?: string;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
import type { ConfigPropertyRepresentation } from "./configPropertyRepresentation.js";
|
||||
|
||||
export interface IdentityProviderMapperTypeRepresentation {
|
||||
id?: string;
|
||||
name?: string;
|
||||
category?: string;
|
||||
helpText?: string;
|
||||
properties?: ConfigPropertyRepresentation[];
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
/**
|
||||
* https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_identityproviderrepresentation
|
||||
*/
|
||||
|
||||
export default interface IdentityProviderRepresentation {
|
||||
addReadTokenRoleOnCreate?: boolean;
|
||||
alias?: string;
|
||||
config?: Record<string, any>;
|
||||
displayName?: string;
|
||||
enabled?: boolean;
|
||||
firstBrokerLoginFlowAlias?: string;
|
||||
internalId?: string;
|
||||
linkOnly?: boolean;
|
||||
postBrokerLoginFlowAlias?: string;
|
||||
providerId?: string;
|
||||
storeToken?: boolean;
|
||||
trustEmail?: boolean;
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
/**
|
||||
* https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_keysmetadatarepresentation-keymetadatarepresentation
|
||||
*/
|
||||
export default interface KeysMetadataRepresentation {
|
||||
active?: { [index: string]: string };
|
||||
keys?: KeyMetadataRepresentation[];
|
||||
}
|
||||
|
||||
export interface KeyMetadataRepresentation {
|
||||
providerId?: string;
|
||||
providerPriority?: number;
|
||||
kid?: string;
|
||||
status?: string;
|
||||
type?: string;
|
||||
algorithm?: string;
|
||||
publicKey?: string;
|
||||
certificate?: string;
|
||||
}
|
11
libs/keycloak-admin-client/src/defs/keystoreConfig.ts
Normal file
11
libs/keycloak-admin-client/src/defs/keystoreConfig.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
/**
|
||||
* https://www.keycloak.org/docs-api/11.0/rest-api/#_keystoreconfig
|
||||
*/
|
||||
export default interface KeyStoreConfig {
|
||||
realmCertificate?: boolean;
|
||||
storePassword?: string;
|
||||
keyPassword?: string;
|
||||
keyAlias?: string;
|
||||
realmAlias?: string;
|
||||
format?: string;
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
export interface ManagementPermissionReference {
|
||||
enabled?: boolean;
|
||||
resource?: string;
|
||||
scopePermissions?: Record<string, string>;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
/**
|
||||
* https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_mappingsrepresentation
|
||||
*/
|
||||
import type RoleRepresentation from "./roleRepresentation.js";
|
||||
|
||||
export default interface MappingsRepresentation {
|
||||
clientMappings?: Record<string, any>;
|
||||
realmMappings?: RoleRepresentation[];
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
/**
|
||||
* https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_passwordpolicytyperepresentation
|
||||
*/
|
||||
export default interface PasswordPolicyTypeRepresentation {
|
||||
id?: string;
|
||||
displayName?: string;
|
||||
configType?: string;
|
||||
defaultValue?: string;
|
||||
multipleSupported?: boolean;
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
import type AccessTokenRepresentation from "./accessTokenRepresentation.js";
|
||||
import type EvaluationResultRepresentation from "./evaluationResultRepresentation.js";
|
||||
import type { DecisionEffect } from "./policyRepresentation.js";
|
||||
|
||||
export default interface PolicyEvaluationResponse {
|
||||
results?: EvaluationResultRepresentation[];
|
||||
entitlements?: boolean;
|
||||
status?: DecisionEffect;
|
||||
rpt?: AccessTokenRepresentation;
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
export default interface PolicyProviderRepresentation {
|
||||
type?: string;
|
||||
name?: string;
|
||||
group?: string;
|
||||
}
|
40
libs/keycloak-admin-client/src/defs/policyRepresentation.ts
Normal file
40
libs/keycloak-admin-client/src/defs/policyRepresentation.ts
Normal file
|
@ -0,0 +1,40 @@
|
|||
/**
|
||||
* https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_policyrepresentation
|
||||
*/
|
||||
|
||||
export enum DecisionStrategy {
|
||||
AFFIRMATIVE = "AFFIRMATIVE",
|
||||
UNANIMOUS = "UNANIMOUS",
|
||||
CONSENSUS = "CONSENSUS",
|
||||
}
|
||||
|
||||
export enum DecisionEffect {
|
||||
Permit = "PERMIT",
|
||||
Deny = "DENY",
|
||||
}
|
||||
|
||||
export enum Logic {
|
||||
POSITIVE = "POSITIVE",
|
||||
NEGATIVE = "NEGATIVE",
|
||||
}
|
||||
|
||||
export interface PolicyRoleRepresentation {
|
||||
id: string;
|
||||
required?: boolean;
|
||||
}
|
||||
|
||||
export default interface PolicyRepresentation {
|
||||
config?: Record<string, any>;
|
||||
decisionStrategy?: DecisionStrategy;
|
||||
description?: string;
|
||||
id?: string;
|
||||
logic?: Logic;
|
||||
name?: string;
|
||||
owner?: string;
|
||||
policies?: string[];
|
||||
resources?: string[];
|
||||
scopes?: string[];
|
||||
type?: string;
|
||||
users?: string[];
|
||||
roles?: PolicyRoleRepresentation[];
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
import type PolicyRepresentation from "./policyRepresentation.js";
|
||||
import type { DecisionEffect } from "./policyRepresentation.js";
|
||||
|
||||
export default interface PolicyResultRepresentation {
|
||||
policy?: PolicyRepresentation;
|
||||
status?: DecisionEffect;
|
||||
associatedPolicies?: PolicyResultRepresentation[];
|
||||
scopes?: string[];
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
/**
|
||||
* https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_profileinforepresentation
|
||||
*/
|
||||
export default interface ProfileInfoRepresentation {
|
||||
name?: string;
|
||||
disabledFeatures?: string[];
|
||||
previewFeatures?: string[];
|
||||
experimentalFeatures?: string[];
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
/**
|
||||
* https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_protocolmapperrepresentation
|
||||
*/
|
||||
|
||||
export default interface ProtocolMapperRepresentation {
|
||||
config?: Record<string, any>;
|
||||
id?: string;
|
||||
name?: string;
|
||||
protocol?: string;
|
||||
protocolMapper?: string;
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
/**
|
||||
* https://www.keycloak.org/docs-api/11.0/rest-api/#_realmeventsconfigrepresentation
|
||||
*/
|
||||
|
||||
export interface RealmEventsConfigRepresentation {
|
||||
eventsEnabled?: boolean;
|
||||
eventsExpiration?: number;
|
||||
eventsListeners?: string[];
|
||||
enabledEventTypes?: string[];
|
||||
adminEventsEnabled?: boolean;
|
||||
adminEventsDetailsEnabled?: boolean;
|
||||
}
|
141
libs/keycloak-admin-client/src/defs/realmRepresentation.ts
Normal file
141
libs/keycloak-admin-client/src/defs/realmRepresentation.ts
Normal file
|
@ -0,0 +1,141 @@
|
|||
import type ClientRepresentation from "./clientRepresentation.js";
|
||||
import type ComponentExportRepresentation from "./componentExportRepresentation.js";
|
||||
import type UserRepresentation from "./userRepresentation.js";
|
||||
import type GroupRepresentation from "./groupRepresentation.js";
|
||||
import type IdentityProviderRepresentation from "./identityProviderRepresentation.js";
|
||||
import type RequiredActionProviderRepresentation from "./requiredActionProviderRepresentation.js";
|
||||
import type RolesRepresentation from "./rolesRepresentation.js";
|
||||
import type ClientProfilesRepresentation from "./clientProfilesRepresentation.js";
|
||||
import type ClientPoliciesRepresentation from "./clientPoliciesRepresentation.js";
|
||||
import type RoleRepresentation from "./roleRepresentation.js";
|
||||
|
||||
/**
|
||||
* https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_realmrepresentation
|
||||
*/
|
||||
|
||||
export default interface RealmRepresentation {
|
||||
accessCodeLifespan?: number;
|
||||
accessCodeLifespanLogin?: number;
|
||||
accessCodeLifespanUserAction?: number;
|
||||
accessTokenLifespan?: number;
|
||||
accessTokenLifespanForImplicitFlow?: number;
|
||||
accountTheme?: string;
|
||||
actionTokenGeneratedByAdminLifespan?: number;
|
||||
actionTokenGeneratedByUserLifespan?: number;
|
||||
adminEventsDetailsEnabled?: boolean;
|
||||
adminEventsEnabled?: boolean;
|
||||
adminTheme?: string;
|
||||
attributes?: Record<string, any>;
|
||||
// AuthenticationFlowRepresentation
|
||||
authenticationFlows?: any[];
|
||||
// AuthenticatorConfigRepresentation
|
||||
authenticatorConfig?: any[];
|
||||
browserFlow?: string;
|
||||
browserSecurityHeaders?: Record<string, any>;
|
||||
bruteForceProtected?: boolean;
|
||||
clientAuthenticationFlow?: string;
|
||||
clientScopeMappings?: Record<string, any>;
|
||||
// ClientScopeRepresentation
|
||||
clientScopes?: any[];
|
||||
clients?: ClientRepresentation[];
|
||||
clientPolicies?: ClientPoliciesRepresentation;
|
||||
clientProfiles?: ClientProfilesRepresentation;
|
||||
components?: { [index: string]: ComponentExportRepresentation };
|
||||
defaultDefaultClientScopes?: string[];
|
||||
defaultGroups?: string[];
|
||||
defaultLocale?: string;
|
||||
defaultOptionalClientScopes?: string[];
|
||||
defaultRoles?: string[];
|
||||
defaultRole?: RoleRepresentation;
|
||||
defaultSignatureAlgorithm?: string;
|
||||
directGrantFlow?: string;
|
||||
displayName?: string;
|
||||
displayNameHtml?: string;
|
||||
dockerAuthenticationFlow?: string;
|
||||
duplicateEmailsAllowed?: boolean;
|
||||
editUsernameAllowed?: boolean;
|
||||
emailTheme?: string;
|
||||
enabled?: boolean;
|
||||
enabledEventTypes?: string[];
|
||||
eventsEnabled?: boolean;
|
||||
eventsExpiration?: number;
|
||||
eventsListeners?: string[];
|
||||
failureFactor?: number;
|
||||
federatedUsers?: UserRepresentation[];
|
||||
groups?: GroupRepresentation[];
|
||||
id?: string;
|
||||
// IdentityProviderMapperRepresentation
|
||||
identityProviderMappers?: any[];
|
||||
identityProviders?: IdentityProviderRepresentation[];
|
||||
internationalizationEnabled?: boolean;
|
||||
keycloakVersion?: string;
|
||||
loginTheme?: string;
|
||||
loginWithEmailAllowed?: boolean;
|
||||
maxDeltaTimeSeconds?: number;
|
||||
maxFailureWaitSeconds?: number;
|
||||
minimumQuickLoginWaitSeconds?: number;
|
||||
notBefore?: number;
|
||||
offlineSessionIdleTimeout?: number;
|
||||
offlineSessionMaxLifespan?: number;
|
||||
offlineSessionMaxLifespanEnabled?: boolean;
|
||||
otpPolicyAlgorithm?: string;
|
||||
otpPolicyDigits?: number;
|
||||
otpPolicyInitialCounter?: number;
|
||||
otpPolicyLookAheadWindow?: number;
|
||||
otpPolicyPeriod?: number;
|
||||
otpPolicyType?: string;
|
||||
otpSupportedApplications?: string[];
|
||||
passwordPolicy?: string;
|
||||
permanentLockout?: boolean;
|
||||
// ProtocolMapperRepresentation
|
||||
protocolMappers?: any[];
|
||||
quickLoginCheckMilliSeconds?: number;
|
||||
realm?: string;
|
||||
refreshTokenMaxReuse?: number;
|
||||
registrationAllowed?: boolean;
|
||||
registrationEmailAsUsername?: boolean;
|
||||
registrationFlow?: string;
|
||||
rememberMe?: boolean;
|
||||
requiredActions?: RequiredActionProviderRepresentation[];
|
||||
resetCredentialsFlow?: string;
|
||||
resetPasswordAllowed?: boolean;
|
||||
revokeRefreshToken?: boolean;
|
||||
roles?: RolesRepresentation;
|
||||
// ScopeMappingRepresentation
|
||||
scopeMappings?: any[];
|
||||
smtpServer?: Record<string, any>;
|
||||
sslRequired?: string;
|
||||
ssoSessionIdleTimeout?: number;
|
||||
ssoSessionIdleTimeoutRememberMe?: number;
|
||||
ssoSessionMaxLifespan?: number;
|
||||
ssoSessionMaxLifespanRememberMe?: number;
|
||||
clientSessionIdleTimeout?: number;
|
||||
clientSessionMaxLifespan?: number;
|
||||
supportedLocales?: string[];
|
||||
// UserFederationMapperRepresentation
|
||||
userFederationMappers?: any[];
|
||||
// UserFederationProviderRepresentation
|
||||
userFederationProviders?: any[];
|
||||
userManagedAccessAllowed?: boolean;
|
||||
users?: UserRepresentation[];
|
||||
verifyEmail?: boolean;
|
||||
waitIncrementSeconds?: number;
|
||||
}
|
||||
|
||||
export type PartialImportRealmRepresentation = RealmRepresentation & {
|
||||
ifResourceExists: "FAIL" | "SKIP" | "OVERWRITE";
|
||||
};
|
||||
|
||||
export type PartialImportResponse = {
|
||||
overwritten: number;
|
||||
added: number;
|
||||
skipped: number;
|
||||
results: PartialImportResult[];
|
||||
};
|
||||
|
||||
export type PartialImportResult = {
|
||||
action: string;
|
||||
resourceType: string;
|
||||
resourceName: string;
|
||||
id: string;
|
||||
};
|
|
@ -0,0 +1,21 @@
|
|||
/**
|
||||
* https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_requiredactionproviderrepresentation
|
||||
*/
|
||||
|
||||
export enum RequiredActionAlias {
|
||||
VERIFY_EMAIL = "VERIFY_EMAIL",
|
||||
UPDATE_PROFILE = "UPDATE_PROFILE",
|
||||
CONFIGURE_TOTP = "CONFIGURE_TOTP",
|
||||
UPDATE_PASSWORD = "UPDATE_PASSWORD",
|
||||
terms_and_conditions = "terms_and_conditions",
|
||||
}
|
||||
|
||||
export default interface RequiredActionProviderRepresentation {
|
||||
alias?: string;
|
||||
config?: Record<string, any>;
|
||||
defaultAction?: boolean;
|
||||
enabled?: boolean;
|
||||
name?: string;
|
||||
providerId?: string;
|
||||
priority?: number;
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
export default interface RequiredActionProviderSimpleRepresentation {
|
||||
id?: string;
|
||||
name?: string;
|
||||
providerId?: string;
|
||||
}
|
14
libs/keycloak-admin-client/src/defs/resourceEvaluation.ts
Normal file
14
libs/keycloak-admin-client/src/defs/resourceEvaluation.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
import type ResourceRepresentation from "./resourceRepresentation.js";
|
||||
|
||||
export default interface ResourceEvaluation {
|
||||
roleIds?: string[];
|
||||
clientId: string;
|
||||
userId: string;
|
||||
resources?: ResourceRepresentation[];
|
||||
entitlements: boolean;
|
||||
context: {
|
||||
attributes: {
|
||||
[key: string]: string;
|
||||
};
|
||||
};
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
/**
|
||||
* https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_resourcerepresentation
|
||||
*/
|
||||
import type { ResourceOwnerRepresentation } from "./resourceServerRepresentation.js";
|
||||
import type ScopeRepresentation from "./scopeRepresentation.js";
|
||||
|
||||
export default interface ResourceRepresentation {
|
||||
name?: string;
|
||||
type?: string;
|
||||
owner?: ResourceOwnerRepresentation;
|
||||
ownerManagedAccess?: boolean;
|
||||
displayName?: string;
|
||||
attributes?: { [index: string]: string[] };
|
||||
_id?: string;
|
||||
uris?: string[];
|
||||
scopes?: ScopeRepresentation[];
|
||||
icon_uri?: string;
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
* https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_policyrepresentation
|
||||
*/
|
||||
import type PolicyRepresentation from "./policyRepresentation.js";
|
||||
import type ResourceRepresentation from "./resourceRepresentation.js";
|
||||
import type ScopeRepresentation from "./scopeRepresentation.js";
|
||||
|
||||
export default interface ResourceServerRepresentation {
|
||||
id?: string;
|
||||
clientId?: string;
|
||||
name?: string;
|
||||
allowRemoteResourceManagement?: boolean;
|
||||
policyEnforcementMode?: PolicyEnforcementMode;
|
||||
resources?: ResourceRepresentation[];
|
||||
policies?: PolicyRepresentation[];
|
||||
scopes?: ScopeRepresentation[];
|
||||
decisionStrategy?: DecisionStrategy;
|
||||
}
|
||||
export interface ResourceOwnerRepresentation {
|
||||
id?: string;
|
||||
name?: string;
|
||||
}
|
||||
export interface AbstractPolicyRepresentation {
|
||||
id?: string;
|
||||
name?: string;
|
||||
description?: string;
|
||||
type?: string;
|
||||
policies?: string[];
|
||||
resources?: string[];
|
||||
scopes?: string[];
|
||||
logic?: Logic;
|
||||
decisionStrategy?: DecisionStrategy;
|
||||
owner?: string;
|
||||
resourcesData?: ResourceRepresentation[];
|
||||
scopesData?: ScopeRepresentation[];
|
||||
}
|
||||
|
||||
export type PolicyEnforcementMode = "ENFORCING" | "PERMISSIVE" | "DISABLED";
|
||||
|
||||
export type DecisionStrategy = "AFFIRMATIVE" | "UNANIMOUS" | "CONSENSUS";
|
||||
|
||||
export type Logic = "POSITIVE" | "NEGATIVE";
|
||||
|
||||
export type Category = "INTERNAL" | "ACCESS" | "ID" | "ADMIN" | "USERINFO";
|
27
libs/keycloak-admin-client/src/defs/roleRepresentation.ts
Normal file
27
libs/keycloak-admin-client/src/defs/roleRepresentation.ts
Normal file
|
@ -0,0 +1,27 @@
|
|||
/**
|
||||
* https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_rolerepresentation
|
||||
*/
|
||||
|
||||
export default interface RoleRepresentation {
|
||||
id?: string;
|
||||
name?: string;
|
||||
description?: string;
|
||||
scopeParamRequired?: boolean;
|
||||
composite?: boolean;
|
||||
composites?: Composites;
|
||||
clientRole?: boolean;
|
||||
containerId?: string;
|
||||
attributes?: { [index: string]: string[] };
|
||||
}
|
||||
|
||||
export interface Composites {
|
||||
realm?: string[];
|
||||
client?: { [index: string]: string[] };
|
||||
application?: { [index: string]: string[] };
|
||||
}
|
||||
|
||||
// when requesting to role-mapping api (create, delete), id and name are required
|
||||
export interface RoleMappingPayload extends RoleRepresentation {
|
||||
id: string;
|
||||
name: string;
|
||||
}
|
11
libs/keycloak-admin-client/src/defs/rolesRepresentation.ts
Normal file
11
libs/keycloak-admin-client/src/defs/rolesRepresentation.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
/**
|
||||
* https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_rolesrepresentation
|
||||
*/
|
||||
|
||||
import type RoleRepresentation from "./roleRepresentation.js";
|
||||
|
||||
export default interface RolesRepresentation {
|
||||
realm?: RoleRepresentation[];
|
||||
client?: { [index: string]: RoleRepresentation[] };
|
||||
application?: { [index: string]: RoleRepresentation[] };
|
||||
}
|
14
libs/keycloak-admin-client/src/defs/scopeRepresentation.ts
Normal file
14
libs/keycloak-admin-client/src/defs/scopeRepresentation.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
/**
|
||||
* https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_scoperepresentation
|
||||
*/
|
||||
import type PolicyRepresentation from "./policyRepresentation.js";
|
||||
import type ResourceRepresentation from "./resourceRepresentation.js";
|
||||
|
||||
export default interface ScopeRepresentation {
|
||||
displayName?: string;
|
||||
iconUri?: string;
|
||||
id?: string;
|
||||
name?: string;
|
||||
policies?: PolicyRepresentation[];
|
||||
resources?: ResourceRepresentation[];
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
import type ComponentTypeRepresentation from "./componentTypeRepresentation.js";
|
||||
import type { ConfigPropertyRepresentation } from "./configPropertyRepresentation.js";
|
||||
import type PasswordPolicyTypeRepresentation from "./passwordPolicyTypeRepresentation.js";
|
||||
import type ProfileInfoRepresentation from "./profileInfoRepresentation.js";
|
||||
import type ProtocolMapperRepresentation from "./protocolMapperRepresentation.js";
|
||||
import type SystemInfoRepresentation from "./systemInfoRepersantation.js";
|
||||
|
||||
/**
|
||||
* https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_serverinforepresentation
|
||||
*/
|
||||
export interface ServerInfoRepresentation {
|
||||
systemInfo?: SystemInfoRepresentation;
|
||||
memoryInfo?: MemoryInfoRepresentation;
|
||||
profileInfo?: ProfileInfoRepresentation;
|
||||
themes?: { [index: string]: ThemeInfoRepresentation[] };
|
||||
socialProviders?: { [index: string]: string }[];
|
||||
identityProviders?: { [index: string]: string }[];
|
||||
clientImporters?: { [index: string]: string }[];
|
||||
providers?: { [index: string]: SpiInfoRepresentation };
|
||||
protocolMapperTypes?: { [index: string]: ProtocolMapperTypeRepresentation[] };
|
||||
builtinProtocolMappers?: { [index: string]: ProtocolMapperRepresentation[] };
|
||||
clientInstallations?: { [index: string]: ClientInstallationRepresentation[] };
|
||||
componentTypes?: { [index: string]: ComponentTypeRepresentation[] };
|
||||
passwordPolicies?: PasswordPolicyTypeRepresentation[];
|
||||
enums?: { [index: string]: string[] };
|
||||
}
|
||||
|
||||
export interface ThemeInfoRepresentation {
|
||||
name: string;
|
||||
locales?: string[];
|
||||
}
|
||||
|
||||
export interface SpiInfoRepresentation {
|
||||
internal: boolean;
|
||||
providers: { [index: string]: ProviderRepresentation };
|
||||
}
|
||||
|
||||
export interface ProviderRepresentation {
|
||||
order: number;
|
||||
operationalInfo?: Record<string, string>;
|
||||
}
|
||||
|
||||
export interface ClientInstallationRepresentation {
|
||||
id: string;
|
||||
protocol: string;
|
||||
downloadOnly: boolean;
|
||||
displayType: string;
|
||||
helpText: string;
|
||||
filename: string;
|
||||
mediaType: string;
|
||||
}
|
||||
|
||||
export interface MemoryInfoRepresentation {
|
||||
total: number;
|
||||
totalFormated: string;
|
||||
used: number;
|
||||
usedFormated: string;
|
||||
free: number;
|
||||
freePercentage: number;
|
||||
freeFormated: string;
|
||||
}
|
||||
|
||||
export interface ProtocolMapperTypeRepresentation {
|
||||
id: string;
|
||||
name: string;
|
||||
category: string;
|
||||
helpText: string;
|
||||
priority: number;
|
||||
properties: ConfigPropertyRepresentation[];
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
/**
|
||||
* https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_synchronizationresult
|
||||
*/
|
||||
|
||||
export default interface SynchronizationResultRepresentation {
|
||||
ignored?: boolean;
|
||||
added?: number;
|
||||
updated?: number;
|
||||
removed?: number;
|
||||
failed?: number;
|
||||
status?: string;
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
/**
|
||||
* https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_systeminforepresentation
|
||||
*/
|
||||
|
||||
export default interface SystemInfoRepresentation {
|
||||
version?: string;
|
||||
serverTime?: string;
|
||||
uptime?: string;
|
||||
uptimeMillis?: number;
|
||||
javaVersion?: string;
|
||||
javaVendor?: string;
|
||||
javaVm?: string;
|
||||
javaVmVersion?: string;
|
||||
javaRuntime?: string;
|
||||
javaHome?: string;
|
||||
osName?: string;
|
||||
osArchitecture?: string;
|
||||
osVersion?: string;
|
||||
fileEncoding?: string;
|
||||
userName?: string;
|
||||
userDir?: string;
|
||||
userTimezone?: string;
|
||||
userLocale?: string;
|
||||
}
|
15
libs/keycloak-admin-client/src/defs/testLdapConnection.ts
Normal file
15
libs/keycloak-admin-client/src/defs/testLdapConnection.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
/**
|
||||
* https://www.keycloak.org/docs-api/11.0/rest-api/#_testldapconnectionrepresentation
|
||||
*/
|
||||
|
||||
export default interface TestLdapConnectionRepresentation {
|
||||
action?: string;
|
||||
connectionUrl?: string;
|
||||
bindDn?: string;
|
||||
bindCredential?: string;
|
||||
useTruststoreSpi?: string;
|
||||
connectionTimeout?: string;
|
||||
componentId?: string;
|
||||
startTls?: string;
|
||||
authType?: string;
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
/**
|
||||
* https://www.keycloak.org/docs-api/11.0/rest-api/#_userconsentrepresentation
|
||||
*/
|
||||
|
||||
export default interface UserConsentRepresentation {
|
||||
clientId?: string;
|
||||
createDate?: string;
|
||||
grantedClientScopes?: string[];
|
||||
lastUpdatedDate?: number;
|
||||
}
|
42
libs/keycloak-admin-client/src/defs/userProfileConfig.ts
Normal file
42
libs/keycloak-admin-client/src/defs/userProfileConfig.ts
Normal file
|
@ -0,0 +1,42 @@
|
|||
// See: https://github.com/keycloak/keycloak/blob/main/services/src/main/java/org/keycloak/userprofile/config/UPConfig.java
|
||||
export default interface UserProfileConfig {
|
||||
attributes?: UserProfileAttribute[];
|
||||
groups?: UserProfileGroup[];
|
||||
}
|
||||
|
||||
// See: https://github.com/keycloak/keycloak/blob/main/services/src/main/java/org/keycloak/userprofile/config/UPAttribute.java
|
||||
export interface UserProfileAttribute {
|
||||
name?: string;
|
||||
validations?: Record<string, Record<string, unknown>>;
|
||||
annotations?: Record<string, unknown>[];
|
||||
required?: UserProfileAttributeRequired;
|
||||
permissions?: UserProfileAttributePermissions;
|
||||
selector?: UserProfileAttributeSelector;
|
||||
displayName?: string;
|
||||
group?: string;
|
||||
}
|
||||
|
||||
// See: https://github.com/keycloak/keycloak/blob/main/services/src/main/java/org/keycloak/userprofile/config/UPAttributeRequired.java
|
||||
export interface UserProfileAttributeRequired {
|
||||
roles?: string[];
|
||||
scopes?: string[];
|
||||
}
|
||||
|
||||
// See: https://github.com/keycloak/keycloak/blob/main/services/src/main/java/org/keycloak/userprofile/config/UPAttributePermissions.java
|
||||
export interface UserProfileAttributePermissions {
|
||||
view?: string[];
|
||||
edit?: string[];
|
||||
}
|
||||
|
||||
// See: https://github.com/keycloak/keycloak/blob/main/services/src/main/java/org/keycloak/userprofile/config/UPAttributeSelector.java
|
||||
export interface UserProfileAttributeSelector {
|
||||
scopes?: string[];
|
||||
}
|
||||
|
||||
// See: https://github.com/keycloak/keycloak/blob/main/services/src/main/java/org/keycloak/userprofile/config/UPGroup.java
|
||||
export interface UserProfileGroup {
|
||||
name?: string;
|
||||
displayHeader?: string;
|
||||
displayDescription?: string;
|
||||
annotations?: Record<string, unknown>;
|
||||
}
|
33
libs/keycloak-admin-client/src/defs/userRepresentation.ts
Normal file
33
libs/keycloak-admin-client/src/defs/userRepresentation.ts
Normal file
|
@ -0,0 +1,33 @@
|
|||
import type UserConsentRepresentation from "./userConsentRepresentation.js";
|
||||
import type CredentialRepresentation from "./credentialRepresentation.js";
|
||||
import type FederatedIdentityRepresentation from "./federatedIdentityRepresentation.js";
|
||||
import type { RequiredActionAlias } from "./requiredActionProviderRepresentation.js";
|
||||
|
||||
export default interface UserRepresentation {
|
||||
id?: string;
|
||||
createdTimestamp?: number;
|
||||
username?: string;
|
||||
enabled?: boolean;
|
||||
totp?: boolean;
|
||||
emailVerified?: boolean;
|
||||
disableableCredentialTypes?: string[];
|
||||
requiredActions?: (RequiredActionAlias | string)[];
|
||||
notBefore?: number;
|
||||
access?: Record<string, boolean>;
|
||||
|
||||
// optional from response
|
||||
attributes?: Record<string, any>;
|
||||
clientConsents?: UserConsentRepresentation[];
|
||||
clientRoles?: Record<string, any>;
|
||||
credentials?: CredentialRepresentation[];
|
||||
email?: string;
|
||||
federatedIdentities?: FederatedIdentityRepresentation[];
|
||||
federationLink?: string;
|
||||
firstName?: string;
|
||||
groups?: string[];
|
||||
lastName?: string;
|
||||
origin?: string;
|
||||
realmRoles?: string[];
|
||||
self?: string;
|
||||
serviceAccountClientId?: string;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
export default interface UserSessionRepresentation {
|
||||
id?: string;
|
||||
clients?: Record<string, string>;
|
||||
ipAddress?: string;
|
||||
lastAccess?: number;
|
||||
start?: number;
|
||||
userId?: string;
|
||||
username?: string;
|
||||
}
|
29
libs/keycloak-admin-client/src/defs/whoAmIRepresentation.ts
Normal file
29
libs/keycloak-admin-client/src/defs/whoAmIRepresentation.ts
Normal file
|
@ -0,0 +1,29 @@
|
|||
export type AccessType =
|
||||
| "view-realm"
|
||||
| "view-identity-providers"
|
||||
| "manage-identity-providers"
|
||||
| "impersonation"
|
||||
| "create-client"
|
||||
| "manage-users"
|
||||
| "query-realms"
|
||||
| "view-authorization"
|
||||
| "query-clients"
|
||||
| "query-users"
|
||||
| "manage-events"
|
||||
| "manage-realm"
|
||||
| "view-events"
|
||||
| "view-users"
|
||||
| "view-clients"
|
||||
| "manage-authorization"
|
||||
| "manage-clients"
|
||||
| "query-groups"
|
||||
| "anyone";
|
||||
|
||||
export default interface WhoAmIRepresentation {
|
||||
userId: string;
|
||||
realm: string;
|
||||
displayName: string;
|
||||
locale: string;
|
||||
createRealm: boolean;
|
||||
realm_access: { [key: string]: AccessType[] };
|
||||
}
|
5
libs/keycloak-admin-client/src/index.ts
Normal file
5
libs/keycloak-admin-client/src/index.ts
Normal file
|
@ -0,0 +1,5 @@
|
|||
import { RequiredActionAlias } from "./defs/requiredActionProviderRepresentation.js";
|
||||
import { KeycloakAdminClient } from "./client.js";
|
||||
|
||||
export const requiredAction = RequiredActionAlias;
|
||||
export default KeycloakAdminClient;
|
275
libs/keycloak-admin-client/src/resources/agent.ts
Normal file
275
libs/keycloak-admin-client/src/resources/agent.ts
Normal file
|
@ -0,0 +1,275 @@
|
|||
import axios, { AxiosRequestConfig, AxiosRequestHeaders, Method } from "axios";
|
||||
import { isUndefined, last, omit, pick } from "lodash-es";
|
||||
import urlJoin from "url-join";
|
||||
import { parseTemplate } from "url-template";
|
||||
import type { KeycloakAdminClient } from "../client.js";
|
||||
import { stringifyQueryParams } from "../utils/stringifyQueryParams.js";
|
||||
|
||||
// constants
|
||||
const SLASH = "/";
|
||||
|
||||
// interface
|
||||
export interface RequestArgs {
|
||||
method: Method;
|
||||
path?: string;
|
||||
// Keys of url params to be applied
|
||||
urlParamKeys?: string[];
|
||||
// Keys of query parameters to be applied
|
||||
queryParamKeys?: string[];
|
||||
// Mapping of key transformations to be performed on the payload
|
||||
keyTransform?: Record<string, string>;
|
||||
// If responding with 404, catch it and return null instead
|
||||
catchNotFound?: boolean;
|
||||
// The key of the value to use from the payload of request. Only works for POST & PUT.
|
||||
payloadKey?: string;
|
||||
// Whether the response header have a location field with newly created resource id
|
||||
// if this value is set, we return the field with format: {[field]: resourceId}
|
||||
// to represent the newly created resource
|
||||
// detail: keycloak/keycloak-nodejs-admin-client issue #11
|
||||
returnResourceIdInLocationHeader?: { field: string };
|
||||
/**
|
||||
* Keys to be ignored, meaning that they will not be filtered out of the request payload even if they are a part of `urlParamKeys` or `queryParamKeys`,
|
||||
*/
|
||||
ignoredKeys?: string[];
|
||||
headers?: AxiosRequestHeaders;
|
||||
}
|
||||
|
||||
export class Agent {
|
||||
private client: KeycloakAdminClient;
|
||||
private basePath: string;
|
||||
private getBaseParams?: () => Record<string, any>;
|
||||
private getBaseUrl?: () => string;
|
||||
|
||||
constructor({
|
||||
client,
|
||||
path = "/",
|
||||
getUrlParams = () => ({}),
|
||||
getBaseUrl = () => client.baseUrl,
|
||||
}: {
|
||||
client: KeycloakAdminClient;
|
||||
path?: string;
|
||||
getUrlParams?: () => Record<string, any>;
|
||||
getBaseUrl?: () => string;
|
||||
}) {
|
||||
this.client = client;
|
||||
this.getBaseParams = getUrlParams;
|
||||
this.getBaseUrl = getBaseUrl;
|
||||
this.basePath = path;
|
||||
}
|
||||
|
||||
public request({
|
||||
method,
|
||||
path = "",
|
||||
urlParamKeys = [],
|
||||
queryParamKeys = [],
|
||||
catchNotFound = false,
|
||||
keyTransform,
|
||||
payloadKey,
|
||||
returnResourceIdInLocationHeader,
|
||||
ignoredKeys,
|
||||
headers,
|
||||
}: RequestArgs) {
|
||||
return async (
|
||||
payload: any = {},
|
||||
options?: Pick<RequestArgs, "catchNotFound">
|
||||
) => {
|
||||
const baseParams = this.getBaseParams?.() ?? {};
|
||||
|
||||
// Filter query parameters by queryParamKeys
|
||||
const queryParams = queryParamKeys ? pick(payload, queryParamKeys) : null;
|
||||
|
||||
// Add filtered payload parameters to base parameters
|
||||
const allUrlParamKeys = [...Object.keys(baseParams), ...urlParamKeys];
|
||||
const urlParams = { ...baseParams, ...pick(payload, allUrlParamKeys) };
|
||||
|
||||
// Omit url parameters and query parameters from payload
|
||||
const omittedKeys = ignoredKeys
|
||||
? [...allUrlParamKeys, ...queryParamKeys].filter(
|
||||
(key) => !ignoredKeys.includes(key)
|
||||
)
|
||||
: [...allUrlParamKeys, ...queryParamKeys];
|
||||
|
||||
payload = omit(payload, omittedKeys);
|
||||
|
||||
// Transform keys of both payload and queryParams
|
||||
if (keyTransform) {
|
||||
this.transformKey(payload, keyTransform);
|
||||
this.transformKey(queryParams, keyTransform);
|
||||
}
|
||||
|
||||
return this.requestWithParams({
|
||||
method,
|
||||
path,
|
||||
payload,
|
||||
urlParams,
|
||||
queryParams,
|
||||
// catchNotFound precedence: global > local > default
|
||||
catchNotFound,
|
||||
...(this.client.getGlobalRequestArgOptions() ?? options ?? {}),
|
||||
payloadKey,
|
||||
returnResourceIdInLocationHeader,
|
||||
headers,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
public updateRequest({
|
||||
method,
|
||||
path = "",
|
||||
urlParamKeys = [],
|
||||
queryParamKeys = [],
|
||||
catchNotFound = false,
|
||||
keyTransform,
|
||||
payloadKey,
|
||||
returnResourceIdInLocationHeader,
|
||||
headers,
|
||||
}: RequestArgs) {
|
||||
return async (query: any = {}, payload: any = {}) => {
|
||||
const baseParams = this.getBaseParams?.() ?? {};
|
||||
|
||||
// Filter query parameters by queryParamKeys
|
||||
const queryParams = queryParamKeys ? pick(query, queryParamKeys) : null;
|
||||
|
||||
// Add filtered query parameters to base parameters
|
||||
const allUrlParamKeys = [...Object.keys(baseParams), ...urlParamKeys];
|
||||
const urlParams = {
|
||||
...baseParams,
|
||||
...pick(query, allUrlParamKeys),
|
||||
};
|
||||
|
||||
// Transform keys of queryParams
|
||||
if (keyTransform) {
|
||||
this.transformKey(queryParams, keyTransform);
|
||||
}
|
||||
|
||||
return this.requestWithParams({
|
||||
method,
|
||||
path,
|
||||
payload,
|
||||
urlParams,
|
||||
queryParams,
|
||||
catchNotFound,
|
||||
payloadKey,
|
||||
returnResourceIdInLocationHeader,
|
||||
headers,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
private async requestWithParams({
|
||||
method,
|
||||
path,
|
||||
payload,
|
||||
urlParams,
|
||||
queryParams,
|
||||
catchNotFound,
|
||||
payloadKey,
|
||||
returnResourceIdInLocationHeader,
|
||||
headers,
|
||||
}: {
|
||||
method: Method;
|
||||
path: string;
|
||||
payload: any;
|
||||
urlParams: any;
|
||||
queryParams?: Record<string, any> | null;
|
||||
catchNotFound: boolean;
|
||||
payloadKey?: string;
|
||||
returnResourceIdInLocationHeader?: { field: string };
|
||||
headers?: AxiosRequestHeaders;
|
||||
}) {
|
||||
const newPath = urlJoin(this.basePath, path);
|
||||
|
||||
// Parse template and replace with values from urlParams
|
||||
const pathTemplate = parseTemplate(newPath);
|
||||
const parsedPath = pathTemplate.expand(urlParams);
|
||||
const url = `${this.getBaseUrl?.() ?? ""}${parsedPath}`;
|
||||
|
||||
// Prepare request config
|
||||
const requestConfig: AxiosRequestConfig = {
|
||||
paramsSerializer: (params) => stringifyQueryParams(params),
|
||||
...(this.client.getRequestConfig() || {}),
|
||||
method,
|
||||
url,
|
||||
};
|
||||
|
||||
// Headers
|
||||
requestConfig.headers = {
|
||||
...requestConfig.headers,
|
||||
Authorization: `bearer ${await this.client.getAccessToken()}`,
|
||||
...headers,
|
||||
};
|
||||
|
||||
// Put payload into querystring if method is GET
|
||||
if (method === "GET") {
|
||||
requestConfig.params = payload;
|
||||
} else {
|
||||
// Set the request data to the payload, or the value corresponding to the payloadKey, if it's defined
|
||||
requestConfig.data = payloadKey ? payload[payloadKey] : payload;
|
||||
}
|
||||
|
||||
// Concat to existing queryParams
|
||||
if (queryParams) {
|
||||
requestConfig.params = requestConfig.params
|
||||
? {
|
||||
...requestConfig.params,
|
||||
...queryParams,
|
||||
}
|
||||
: queryParams;
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await axios.default(requestConfig);
|
||||
// now we get the response of the http request
|
||||
// if `resourceIdInLocationHeader` is true, we'll get the resourceId from the location header field
|
||||
// todo: find a better way to find the id in path, maybe some kind of pattern matching
|
||||
// for now, we simply split the last sub-path of the path returned in location header field
|
||||
if (returnResourceIdInLocationHeader) {
|
||||
const locationHeader = res.headers.location;
|
||||
|
||||
if (typeof locationHeader !== "string") {
|
||||
throw new Error(
|
||||
`location header is not found in request: ${res.config.url}`
|
||||
);
|
||||
}
|
||||
|
||||
const resourceId = last(locationHeader.split(SLASH));
|
||||
if (!resourceId) {
|
||||
// throw an error to let users know the response is not expected
|
||||
throw new Error(
|
||||
`resourceId is not found in Location header from request: ${res.config.url}`
|
||||
);
|
||||
}
|
||||
|
||||
// return with format {[field]: string}
|
||||
const { field } = returnResourceIdInLocationHeader;
|
||||
return { [field]: resourceId };
|
||||
}
|
||||
return res.data;
|
||||
} catch (err) {
|
||||
if (
|
||||
axios.default.isAxiosError(err) &&
|
||||
err.response?.status === 404 &&
|
||||
catchNotFound
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
private transformKey(payload: any, keyMapping: Record<string, string>) {
|
||||
if (!payload) {
|
||||
return;
|
||||
}
|
||||
|
||||
Object.keys(keyMapping).some((key) => {
|
||||
if (isUndefined(payload[key])) {
|
||||
// Skip if undefined
|
||||
return false;
|
||||
}
|
||||
const newKey = keyMapping[key];
|
||||
payload[newKey] = payload[key];
|
||||
delete payload[key];
|
||||
});
|
||||
}
|
||||
}
|
35
libs/keycloak-admin-client/src/resources/attackDetection.ts
Normal file
35
libs/keycloak-admin-client/src/resources/attackDetection.ts
Normal file
|
@ -0,0 +1,35 @@
|
|||
import Resource from "./resource.js";
|
||||
import type KeycloakAdminClient from "../index.js";
|
||||
|
||||
export class AttackDetection extends Resource<{ realm?: string }> {
|
||||
public findOne = this.makeRequest<
|
||||
{ id: string },
|
||||
Record<string, any> | undefined
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/users/{id}",
|
||||
urlParamKeys: ["id"],
|
||||
catchNotFound: true,
|
||||
});
|
||||
|
||||
public del = this.makeRequest<{ id: string }, void>({
|
||||
method: "DELETE",
|
||||
path: "/users/{id}",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
public delAll = this.makeRequest<{}, void>({
|
||||
method: "DELETE",
|
||||
path: "/users",
|
||||
});
|
||||
|
||||
constructor(client: KeycloakAdminClient) {
|
||||
super(client, {
|
||||
path: "/admin/realms/{realm}/attack-detection/brute-force",
|
||||
getUrlParams: () => ({
|
||||
realm: client.realmName,
|
||||
}),
|
||||
getBaseUrl: () => client.baseUrl,
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,286 @@
|
|||
import Resource from "./resource.js";
|
||||
import type RequiredActionProviderRepresentation from "../defs/requiredActionProviderRepresentation.js";
|
||||
import type { KeycloakAdminClient } from "../client.js";
|
||||
import type AuthenticationExecutionInfoRepresentation from "../defs/authenticationExecutionInfoRepresentation.js";
|
||||
import type AuthenticationFlowRepresentation from "../defs/authenticationFlowRepresentation.js";
|
||||
import type AuthenticatorConfigRepresentation from "../defs/authenticatorConfigRepresentation.js";
|
||||
import type { AuthenticationProviderRepresentation } from "../defs/authenticatorConfigRepresentation.js";
|
||||
import type AuthenticatorConfigInfoRepresentation from "../defs/authenticatorConfigInfoRepresentation.js";
|
||||
import type RequiredActionProviderSimpleRepresentation from "../defs/requiredActionProviderSimpleRepresentation.js";
|
||||
|
||||
export class AuthenticationManagement extends Resource {
|
||||
/**
|
||||
* Authentication Management
|
||||
* https://www.keycloak.org/docs-api/8.0/rest-api/index.html#_authentication_management_resource
|
||||
*/
|
||||
|
||||
// Register a new required action
|
||||
public registerRequiredAction = this.makeRequest<Record<string, any>>({
|
||||
method: "POST",
|
||||
path: "/register-required-action",
|
||||
});
|
||||
|
||||
// Get required actions. Returns a list of required actions.
|
||||
public getRequiredActions = this.makeRequest<
|
||||
void,
|
||||
RequiredActionProviderRepresentation[]
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/required-actions",
|
||||
});
|
||||
|
||||
// Get required action for alias
|
||||
public getRequiredActionForAlias = this.makeRequest<{
|
||||
alias: string;
|
||||
}>({
|
||||
method: "GET",
|
||||
path: "/required-actions/{alias}",
|
||||
urlParamKeys: ["alias"],
|
||||
catchNotFound: true,
|
||||
});
|
||||
|
||||
public getClientAuthenticatorProviders = this.makeRequest<
|
||||
void,
|
||||
AuthenticationProviderRepresentation[]
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/client-authenticator-providers",
|
||||
});
|
||||
|
||||
public getAuthenticatorProviders = this.makeRequest<
|
||||
void,
|
||||
AuthenticationProviderRepresentation[]
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/authenticator-providers",
|
||||
});
|
||||
|
||||
public getFormActionProviders = this.makeRequest<
|
||||
void,
|
||||
AuthenticationProviderRepresentation[]
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/form-action-providers",
|
||||
});
|
||||
|
||||
// Update required action
|
||||
public updateRequiredAction = this.makeUpdateRequest<
|
||||
{ alias: string },
|
||||
RequiredActionProviderRepresentation,
|
||||
void
|
||||
>({
|
||||
method: "PUT",
|
||||
path: "/required-actions/{alias}",
|
||||
urlParamKeys: ["alias"],
|
||||
});
|
||||
|
||||
// Delete required action
|
||||
public deleteRequiredAction = this.makeRequest<{ alias: string }, void>({
|
||||
method: "DELETE",
|
||||
path: "/required-actions/{alias}",
|
||||
urlParamKeys: ["alias"],
|
||||
});
|
||||
|
||||
// Lower required action’s priority
|
||||
public lowerRequiredActionPriority = this.makeRequest<{
|
||||
alias: string;
|
||||
}>({
|
||||
method: "POST",
|
||||
path: "/required-actions/{alias}/lower-priority",
|
||||
urlParamKeys: ["alias"],
|
||||
});
|
||||
|
||||
// Raise required action’s priority
|
||||
public raiseRequiredActionPriority = this.makeRequest<{
|
||||
alias: string;
|
||||
}>({
|
||||
method: "POST",
|
||||
path: "/required-actions/{alias}/raise-priority",
|
||||
urlParamKeys: ["alias"],
|
||||
});
|
||||
|
||||
// Get unregistered required actions Returns a list of unregistered required actions.
|
||||
public getUnregisteredRequiredActions = this.makeRequest<
|
||||
void,
|
||||
RequiredActionProviderSimpleRepresentation[]
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/unregistered-required-actions",
|
||||
});
|
||||
|
||||
public getFlows = this.makeRequest<{}, AuthenticationFlowRepresentation[]>({
|
||||
method: "GET",
|
||||
path: "/flows",
|
||||
});
|
||||
|
||||
public getFlow = this.makeRequest<
|
||||
{ flowId: string },
|
||||
AuthenticationFlowRepresentation
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/flows/{flowId}",
|
||||
urlParamKeys: ["flowId"],
|
||||
});
|
||||
|
||||
public getFormProviders = this.makeRequest<
|
||||
void,
|
||||
AuthenticationProviderRepresentation[]
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/form-providers",
|
||||
});
|
||||
|
||||
public createFlow = this.makeRequest<
|
||||
AuthenticationFlowRepresentation,
|
||||
AuthenticationFlowRepresentation
|
||||
>({
|
||||
method: "POST",
|
||||
path: "/flows",
|
||||
returnResourceIdInLocationHeader: { field: "id" },
|
||||
});
|
||||
|
||||
public copyFlow = this.makeRequest<{ flow: string; newName: string }>({
|
||||
method: "POST",
|
||||
path: "/flows/{flow}/copy",
|
||||
urlParamKeys: ["flow"],
|
||||
});
|
||||
|
||||
public deleteFlow = this.makeRequest<{ flowId: string }>({
|
||||
method: "DELETE",
|
||||
path: "/flows/{flowId}",
|
||||
urlParamKeys: ["flowId"],
|
||||
});
|
||||
|
||||
public updateFlow = this.makeUpdateRequest<
|
||||
{ flowId: string },
|
||||
AuthenticationFlowRepresentation
|
||||
>({
|
||||
method: "PUT",
|
||||
path: "/flows/{flowId}",
|
||||
urlParamKeys: ["flowId"],
|
||||
});
|
||||
|
||||
public getExecutions = this.makeRequest<
|
||||
{ flow: string },
|
||||
AuthenticationExecutionInfoRepresentation[]
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/flows/{flow}/executions",
|
||||
urlParamKeys: ["flow"],
|
||||
});
|
||||
|
||||
public addExecution = this.makeUpdateRequest<
|
||||
{ flow: string },
|
||||
AuthenticationExecutionInfoRepresentation
|
||||
>({
|
||||
method: "POST",
|
||||
path: "/flows/{flow}/executions",
|
||||
urlParamKeys: ["flow"],
|
||||
});
|
||||
|
||||
public addExecutionToFlow = this.makeRequest<
|
||||
{ flow: string; provider: string },
|
||||
AuthenticationExecutionInfoRepresentation
|
||||
>({
|
||||
method: "POST",
|
||||
path: "/flows/{flow}/executions/execution",
|
||||
urlParamKeys: ["flow"],
|
||||
returnResourceIdInLocationHeader: { field: "id" },
|
||||
});
|
||||
|
||||
public addFlowToFlow = this.makeRequest<
|
||||
{
|
||||
flow: string;
|
||||
alias: string;
|
||||
type: string;
|
||||
provider: string;
|
||||
description: string;
|
||||
},
|
||||
AuthenticationFlowRepresentation
|
||||
>({
|
||||
method: "POST",
|
||||
path: "/flows/{flow}/executions/flow",
|
||||
urlParamKeys: ["flow"],
|
||||
returnResourceIdInLocationHeader: { field: "id" },
|
||||
});
|
||||
|
||||
public updateExecution = this.makeUpdateRequest<
|
||||
{ flow: string },
|
||||
AuthenticationExecutionInfoRepresentation
|
||||
>({
|
||||
method: "PUT",
|
||||
path: "/flows/{flow}/executions",
|
||||
urlParamKeys: ["flow"],
|
||||
});
|
||||
|
||||
public delExecution = this.makeRequest<{ id: string }>({
|
||||
method: "DELETE",
|
||||
path: "/executions/{id}",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
public lowerPriorityExecution = this.makeRequest<{ id: string }>({
|
||||
method: "POST",
|
||||
path: "/executions/{id}/lower-priority",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
public raisePriorityExecution = this.makeRequest<{ id: string }>({
|
||||
method: "POST",
|
||||
path: "/executions/{id}/raise-priority",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
public getConfigDescription = this.makeRequest<
|
||||
{ providerId: string },
|
||||
AuthenticatorConfigInfoRepresentation
|
||||
>({
|
||||
method: "GET",
|
||||
path: "config-description/{providerId}",
|
||||
urlParamKeys: ["providerId"],
|
||||
});
|
||||
|
||||
public createConfig = this.makeRequest<
|
||||
AuthenticatorConfigRepresentation,
|
||||
AuthenticatorConfigRepresentation
|
||||
>({
|
||||
method: "POST",
|
||||
path: "/executions/{id}/config",
|
||||
urlParamKeys: ["id"],
|
||||
returnResourceIdInLocationHeader: { field: "id" },
|
||||
});
|
||||
|
||||
public updateConfig = this.makeRequest<
|
||||
AuthenticatorConfigRepresentation,
|
||||
void
|
||||
>({
|
||||
method: "PUT",
|
||||
path: "/config/{id}",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
public getConfig = this.makeRequest<
|
||||
{ id: string },
|
||||
AuthenticatorConfigRepresentation
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/config/{id}",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
public delConfig = this.makeRequest<{ id: string }>({
|
||||
method: "DELETE",
|
||||
path: "/config/{id}",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
constructor(client: KeycloakAdminClient) {
|
||||
super(client, {
|
||||
path: "/admin/realms/{realm}/authentication",
|
||||
getUrlParams: () => ({
|
||||
realm: client.realmName,
|
||||
}),
|
||||
getBaseUrl: () => client.baseUrl,
|
||||
});
|
||||
}
|
||||
}
|
19
libs/keycloak-admin-client/src/resources/cache.ts
Normal file
19
libs/keycloak-admin-client/src/resources/cache.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
import Resource from "./resource.js";
|
||||
import type { KeycloakAdminClient } from "../client.js";
|
||||
|
||||
export class Cache extends Resource<{ realm?: string }> {
|
||||
public clearUserCache = this.makeRequest<{}, void>({
|
||||
method: "POST",
|
||||
path: "/clear-user-cache",
|
||||
});
|
||||
|
||||
constructor(client: KeycloakAdminClient) {
|
||||
super(client, {
|
||||
path: "/admin/realms/{realm}",
|
||||
getUrlParams: () => ({
|
||||
realm: client.realmName,
|
||||
}),
|
||||
getBaseUrl: () => client.baseUrl,
|
||||
});
|
||||
}
|
||||
}
|
50
libs/keycloak-admin-client/src/resources/clientPolicies.ts
Normal file
50
libs/keycloak-admin-client/src/resources/clientPolicies.ts
Normal file
|
@ -0,0 +1,50 @@
|
|||
import Resource from "./resource.js";
|
||||
import type { KeycloakAdminClient } from "../client.js";
|
||||
import type ClientProfilesRepresentation from "../defs/clientProfilesRepresentation.js";
|
||||
import type ClientPoliciesRepresentation from "../defs/clientPoliciesRepresentation.js";
|
||||
|
||||
/**
|
||||
* https://www.keycloak.org/docs-api/15.0/rest-api/#_client_registration_policy_resource
|
||||
*/
|
||||
export class ClientPolicies extends Resource<{ realm?: string }> {
|
||||
constructor(client: KeycloakAdminClient) {
|
||||
super(client, {
|
||||
path: "/admin/realms/{realm}/client-policies",
|
||||
getUrlParams: () => ({
|
||||
realm: client.realmName,
|
||||
}),
|
||||
getBaseUrl: () => client.baseUrl,
|
||||
});
|
||||
}
|
||||
|
||||
/* Client Profiles */
|
||||
|
||||
public listProfiles = this.makeRequest<
|
||||
{ includeGlobalProfiles?: boolean },
|
||||
ClientProfilesRepresentation
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/profiles",
|
||||
queryParamKeys: ["include-global-profiles"],
|
||||
keyTransform: {
|
||||
includeGlobalProfiles: "include-global-profiles",
|
||||
},
|
||||
});
|
||||
|
||||
public createProfiles = this.makeRequest<ClientProfilesRepresentation, void>({
|
||||
method: "PUT",
|
||||
path: "/profiles",
|
||||
});
|
||||
|
||||
/* Client Policies */
|
||||
|
||||
public listPolicies = this.makeRequest<{}, ClientPoliciesRepresentation>({
|
||||
method: "GET",
|
||||
path: "/policies",
|
||||
});
|
||||
|
||||
public updatePolicy = this.makeRequest<ClientPoliciesRepresentation, void>({
|
||||
method: "PUT",
|
||||
path: "/policies",
|
||||
});
|
||||
}
|
336
libs/keycloak-admin-client/src/resources/clientScopes.ts
Normal file
336
libs/keycloak-admin-client/src/resources/clientScopes.ts
Normal file
|
@ -0,0 +1,336 @@
|
|||
import type ClientScopeRepresentation from "../defs/clientScopeRepresentation.js";
|
||||
import Resource from "./resource.js";
|
||||
import type { KeycloakAdminClient } from "../client.js";
|
||||
import type ProtocolMapperRepresentation from "../defs/protocolMapperRepresentation.js";
|
||||
import type MappingsRepresentation from "../defs/mappingsRepresentation.js";
|
||||
import type RoleRepresentation from "../defs/roleRepresentation.js";
|
||||
|
||||
export class ClientScopes extends Resource<{ realm?: string }> {
|
||||
public find = this.makeRequest<{}, ClientScopeRepresentation[]>({
|
||||
method: "GET",
|
||||
path: "/client-scopes",
|
||||
});
|
||||
|
||||
public create = this.makeRequest<ClientScopeRepresentation, { id: string }>({
|
||||
method: "POST",
|
||||
path: "/client-scopes",
|
||||
returnResourceIdInLocationHeader: { field: "id" },
|
||||
});
|
||||
|
||||
/**
|
||||
* Client-Scopes by id
|
||||
*/
|
||||
|
||||
public findOne = this.makeRequest<
|
||||
{ id: string },
|
||||
ClientScopeRepresentation | undefined
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/client-scopes/{id}",
|
||||
urlParamKeys: ["id"],
|
||||
catchNotFound: true,
|
||||
});
|
||||
|
||||
public update = this.makeUpdateRequest<
|
||||
{ id: string },
|
||||
ClientScopeRepresentation,
|
||||
void
|
||||
>({
|
||||
method: "PUT",
|
||||
path: "/client-scopes/{id}",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
public del = this.makeRequest<{ id: string }, void>({
|
||||
method: "DELETE",
|
||||
path: "/client-scopes/{id}",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
/**
|
||||
* Default Client-Scopes
|
||||
*/
|
||||
|
||||
public listDefaultClientScopes = this.makeRequest<
|
||||
void,
|
||||
ClientScopeRepresentation[]
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/default-default-client-scopes",
|
||||
});
|
||||
|
||||
public addDefaultClientScope = this.makeRequest<{ id: string }, void>({
|
||||
method: "PUT",
|
||||
path: "/default-default-client-scopes/{id}",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
public delDefaultClientScope = this.makeRequest<{ id: string }, void>({
|
||||
method: "DELETE",
|
||||
path: "/default-default-client-scopes/{id}",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
/**
|
||||
* Default Optional Client-Scopes
|
||||
*/
|
||||
|
||||
public listDefaultOptionalClientScopes = this.makeRequest<
|
||||
void,
|
||||
ClientScopeRepresentation[]
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/default-optional-client-scopes",
|
||||
});
|
||||
|
||||
public addDefaultOptionalClientScope = this.makeRequest<{ id: string }, void>(
|
||||
{
|
||||
method: "PUT",
|
||||
path: "/default-optional-client-scopes/{id}",
|
||||
urlParamKeys: ["id"],
|
||||
}
|
||||
);
|
||||
|
||||
public delDefaultOptionalClientScope = this.makeRequest<{ id: string }, void>(
|
||||
{
|
||||
method: "DELETE",
|
||||
path: "/default-optional-client-scopes/{id}",
|
||||
urlParamKeys: ["id"],
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Protocol Mappers
|
||||
*/
|
||||
|
||||
public addMultipleProtocolMappers = this.makeUpdateRequest<
|
||||
{ id: string },
|
||||
ProtocolMapperRepresentation[],
|
||||
void
|
||||
>({
|
||||
method: "POST",
|
||||
path: "/client-scopes/{id}/protocol-mappers/add-models",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
public addProtocolMapper = this.makeUpdateRequest<
|
||||
{ id: string },
|
||||
ProtocolMapperRepresentation,
|
||||
void
|
||||
>({
|
||||
method: "POST",
|
||||
path: "/client-scopes/{id}/protocol-mappers/models",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
public listProtocolMappers = this.makeRequest<
|
||||
{ id: string },
|
||||
ProtocolMapperRepresentation[]
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/client-scopes/{id}/protocol-mappers/models",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
public findProtocolMapper = this.makeRequest<
|
||||
{ id: string; mapperId: string },
|
||||
ProtocolMapperRepresentation | undefined
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/client-scopes/{id}/protocol-mappers/models/{mapperId}",
|
||||
urlParamKeys: ["id", "mapperId"],
|
||||
catchNotFound: true,
|
||||
});
|
||||
|
||||
public findProtocolMappersByProtocol = this.makeRequest<
|
||||
{ id: string; protocol: string },
|
||||
ProtocolMapperRepresentation[]
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/client-scopes/{id}/protocol-mappers/protocol/{protocol}",
|
||||
urlParamKeys: ["id", "protocol"],
|
||||
catchNotFound: true,
|
||||
});
|
||||
|
||||
public updateProtocolMapper = this.makeUpdateRequest<
|
||||
{ id: string; mapperId: string },
|
||||
ProtocolMapperRepresentation,
|
||||
void
|
||||
>({
|
||||
method: "PUT",
|
||||
path: "/client-scopes/{id}/protocol-mappers/models/{mapperId}",
|
||||
urlParamKeys: ["id", "mapperId"],
|
||||
});
|
||||
|
||||
public delProtocolMapper = this.makeRequest<
|
||||
{ id: string; mapperId: string },
|
||||
void
|
||||
>({
|
||||
method: "DELETE",
|
||||
path: "/client-scopes/{id}/protocol-mappers/models/{mapperId}",
|
||||
urlParamKeys: ["id", "mapperId"],
|
||||
});
|
||||
|
||||
/**
|
||||
* Scope Mappings
|
||||
*/
|
||||
public listScopeMappings = this.makeRequest<
|
||||
{ id: string },
|
||||
MappingsRepresentation
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/client-scopes/{id}/scope-mappings",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
public addClientScopeMappings = this.makeUpdateRequest<
|
||||
{ id: string; client: string },
|
||||
RoleRepresentation[],
|
||||
void
|
||||
>({
|
||||
method: "POST",
|
||||
path: "/client-scopes/{id}/scope-mappings/clients/{client}",
|
||||
urlParamKeys: ["id", "client"],
|
||||
});
|
||||
|
||||
public listClientScopeMappings = this.makeRequest<
|
||||
{ id: string; client: string },
|
||||
RoleRepresentation[]
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/client-scopes/{id}/scope-mappings/clients/{client}",
|
||||
urlParamKeys: ["id", "client"],
|
||||
});
|
||||
|
||||
public listAvailableClientScopeMappings = this.makeRequest<
|
||||
{ id: string; client: string },
|
||||
RoleRepresentation[]
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/client-scopes/{id}/scope-mappings/clients/{client}/available",
|
||||
urlParamKeys: ["id", "client"],
|
||||
});
|
||||
|
||||
public listCompositeClientScopeMappings = this.makeRequest<
|
||||
{ id: string; client: string },
|
||||
RoleRepresentation[]
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/client-scopes/{id}/scope-mappings/clients/{client}/composite",
|
||||
urlParamKeys: ["id", "client"],
|
||||
});
|
||||
|
||||
public delClientScopeMappings = this.makeUpdateRequest<
|
||||
{ id: string; client: string },
|
||||
RoleRepresentation[],
|
||||
void
|
||||
>({
|
||||
method: "DELETE",
|
||||
path: "/client-scopes/{id}/scope-mappings/clients/{client}",
|
||||
urlParamKeys: ["id", "client"],
|
||||
});
|
||||
|
||||
public addRealmScopeMappings = this.makeUpdateRequest<
|
||||
{ id: string },
|
||||
RoleRepresentation[],
|
||||
void
|
||||
>({
|
||||
method: "POST",
|
||||
path: "/client-scopes/{id}/scope-mappings/realm",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
public listRealmScopeMappings = this.makeRequest<
|
||||
{ id: string },
|
||||
RoleRepresentation[]
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/client-scopes/{id}/scope-mappings/realm",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
public listAvailableRealmScopeMappings = this.makeRequest<
|
||||
{ id: string },
|
||||
RoleRepresentation[]
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/client-scopes/{id}/scope-mappings/realm/available",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
public listCompositeRealmScopeMappings = this.makeRequest<
|
||||
{ id: string },
|
||||
RoleRepresentation[]
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/client-scopes/{id}/scope-mappings/realm/composite",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
public delRealmScopeMappings = this.makeUpdateRequest<
|
||||
{ id: string },
|
||||
RoleRepresentation[],
|
||||
void
|
||||
>({
|
||||
method: "DELETE",
|
||||
path: "/client-scopes/{id}/scope-mappings/realm",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
constructor(client: KeycloakAdminClient) {
|
||||
super(client, {
|
||||
path: "/admin/realms/{realm}",
|
||||
getUrlParams: () => ({
|
||||
realm: client.realmName,
|
||||
}),
|
||||
getBaseUrl: () => client.baseUrl,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Find client scope by name.
|
||||
*/
|
||||
public async findOneByName(payload: {
|
||||
realm?: string;
|
||||
name: string;
|
||||
}): Promise<ClientScopeRepresentation | undefined> {
|
||||
const allScopes = await this.find({
|
||||
...(payload.realm ? { realm: payload.realm } : {}),
|
||||
});
|
||||
return allScopes.find((item) => item.name === payload.name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete client scope by name.
|
||||
*/
|
||||
public async delByName(payload: {
|
||||
realm?: string;
|
||||
name: string;
|
||||
}): Promise<void> {
|
||||
const scope = await this.findOneByName(payload);
|
||||
|
||||
if (!scope) {
|
||||
throw new Error("Scope not found.");
|
||||
}
|
||||
|
||||
await this.del({
|
||||
...(payload.realm ? { realm: payload.realm } : {}),
|
||||
id: scope.id!,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Find single protocol mapper by name.
|
||||
*/
|
||||
public async findProtocolMapperByName(payload: {
|
||||
realm?: string;
|
||||
id: string;
|
||||
name: string;
|
||||
}): Promise<ProtocolMapperRepresentation | undefined> {
|
||||
const allProtocolMappers = await this.listProtocolMappers({
|
||||
id: payload.id,
|
||||
...(payload.realm ? { realm: payload.realm } : {}),
|
||||
});
|
||||
return allProtocolMappers.find((mapper) => mapper.name === payload.name);
|
||||
}
|
||||
}
|
1034
libs/keycloak-admin-client/src/resources/clients.ts
Normal file
1034
libs/keycloak-admin-client/src/resources/clients.ts
Normal file
File diff suppressed because it is too large
Load diff
72
libs/keycloak-admin-client/src/resources/components.ts
Normal file
72
libs/keycloak-admin-client/src/resources/components.ts
Normal file
|
@ -0,0 +1,72 @@
|
|||
import Resource from "./resource.js";
|
||||
import type ComponentRepresentation from "../defs/componentRepresentation.js";
|
||||
import type ComponentTypeRepresentation from "../defs/componentTypeRepresentation.js";
|
||||
import type { KeycloakAdminClient } from "../client.js";
|
||||
|
||||
export interface ComponentQuery {
|
||||
name?: string;
|
||||
parent?: string;
|
||||
type?: string;
|
||||
}
|
||||
|
||||
export class Components extends Resource<{ realm?: string }> {
|
||||
/**
|
||||
* components
|
||||
* https://www.keycloak.org/docs-api/11.0/rest-api/#_component_resource
|
||||
*/
|
||||
|
||||
public find = this.makeRequest<ComponentQuery, ComponentRepresentation[]>({
|
||||
method: "GET",
|
||||
});
|
||||
|
||||
public create = this.makeRequest<ComponentRepresentation, { id: string }>({
|
||||
method: "POST",
|
||||
returnResourceIdInLocationHeader: { field: "id" },
|
||||
});
|
||||
|
||||
public findOne = this.makeRequest<
|
||||
{ id: string },
|
||||
ComponentRepresentation | undefined
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/{id}",
|
||||
urlParamKeys: ["id"],
|
||||
catchNotFound: true,
|
||||
});
|
||||
|
||||
public update = this.makeUpdateRequest<
|
||||
{ id: string },
|
||||
ComponentRepresentation,
|
||||
void
|
||||
>({
|
||||
method: "PUT",
|
||||
path: "/{id}",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
public del = this.makeRequest<{ id: string }, void>({
|
||||
method: "DELETE",
|
||||
path: "/{id}",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
public listSubComponents = this.makeRequest<
|
||||
{ id: string; type: string },
|
||||
ComponentTypeRepresentation[]
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/{id}/sub-component-types",
|
||||
urlParamKeys: ["id"],
|
||||
queryParamKeys: ["type"],
|
||||
});
|
||||
|
||||
constructor(client: KeycloakAdminClient) {
|
||||
super(client, {
|
||||
path: "/admin/realms/{realm}/components",
|
||||
getUrlParams: () => ({
|
||||
realm: client.realmName,
|
||||
}),
|
||||
getBaseUrl: () => client.baseUrl,
|
||||
});
|
||||
}
|
||||
}
|
242
libs/keycloak-admin-client/src/resources/groups.ts
Normal file
242
libs/keycloak-admin-client/src/resources/groups.ts
Normal file
|
@ -0,0 +1,242 @@
|
|||
import type { KeycloakAdminClient } from "../client.js";
|
||||
import type GroupRepresentation from "../defs/groupRepresentation.js";
|
||||
import type { ManagementPermissionReference } from "../defs/managementPermissionReference.js";
|
||||
import type MappingsRepresentation from "../defs/mappingsRepresentation.js";
|
||||
import type RoleRepresentation from "../defs/roleRepresentation.js";
|
||||
import type { RoleMappingPayload } from "../defs/roleRepresentation.js";
|
||||
import type UserRepresentation from "../defs/userRepresentation.js";
|
||||
import Resource from "./resource.js";
|
||||
|
||||
export interface GroupQuery {
|
||||
first?: number;
|
||||
max?: number;
|
||||
search?: string;
|
||||
briefRepresentation?: boolean;
|
||||
}
|
||||
|
||||
export interface GroupCountQuery {
|
||||
search?: string;
|
||||
top?: boolean;
|
||||
}
|
||||
|
||||
export class Groups extends Resource<{ realm?: string }> {
|
||||
public find = this.makeRequest<GroupQuery, GroupRepresentation[]>({
|
||||
method: "GET",
|
||||
});
|
||||
|
||||
public create = this.makeRequest<GroupRepresentation, { id: string }>({
|
||||
method: "POST",
|
||||
returnResourceIdInLocationHeader: { field: "id" },
|
||||
});
|
||||
|
||||
/**
|
||||
* Single user
|
||||
*/
|
||||
|
||||
public findOne = this.makeRequest<
|
||||
{ id: string },
|
||||
GroupRepresentation | undefined
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/{id}",
|
||||
urlParamKeys: ["id"],
|
||||
catchNotFound: true,
|
||||
});
|
||||
|
||||
public update = this.makeUpdateRequest<
|
||||
{ id: string },
|
||||
GroupRepresentation,
|
||||
void
|
||||
>({
|
||||
method: "PUT",
|
||||
path: "/{id}",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
public del = this.makeRequest<{ id: string }, void>({
|
||||
method: "DELETE",
|
||||
path: "/{id}",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
public count = this.makeRequest<GroupCountQuery, { count: number }>({
|
||||
method: "GET",
|
||||
path: "/count",
|
||||
});
|
||||
|
||||
/**
|
||||
* Set or create child.
|
||||
* This will just set the parent if it exists. Create it and set the parent if the group doesn’t exist.
|
||||
*/
|
||||
|
||||
public setOrCreateChild = this.makeUpdateRequest<
|
||||
{ id: string },
|
||||
GroupRepresentation,
|
||||
{ id: string }
|
||||
>({
|
||||
method: "POST",
|
||||
path: "/{id}/children",
|
||||
urlParamKeys: ["id"],
|
||||
returnResourceIdInLocationHeader: { field: "id" },
|
||||
});
|
||||
|
||||
/**
|
||||
* Members
|
||||
*/
|
||||
|
||||
public listMembers = this.makeRequest<
|
||||
{ id: string; first?: number; max?: number },
|
||||
UserRepresentation[]
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/{id}/members",
|
||||
urlParamKeys: ["id"],
|
||||
catchNotFound: true,
|
||||
});
|
||||
|
||||
/**
|
||||
* Role mappings
|
||||
* https://www.keycloak.org/docs-api/11.0/rest-api/#_role_mapper_resource
|
||||
*/
|
||||
|
||||
public listRoleMappings = this.makeRequest<
|
||||
{ id: string },
|
||||
MappingsRepresentation
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/{id}/role-mappings",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
public addRealmRoleMappings = this.makeRequest<
|
||||
{ id: string; roles: RoleMappingPayload[] },
|
||||
void
|
||||
>({
|
||||
method: "POST",
|
||||
path: "/{id}/role-mappings/realm",
|
||||
urlParamKeys: ["id"],
|
||||
payloadKey: "roles",
|
||||
});
|
||||
|
||||
public listRealmRoleMappings = this.makeRequest<
|
||||
{ id: string },
|
||||
RoleRepresentation[]
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/{id}/role-mappings/realm",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
public delRealmRoleMappings = this.makeRequest<
|
||||
{ id: string; roles: RoleMappingPayload[] },
|
||||
void
|
||||
>({
|
||||
method: "DELETE",
|
||||
path: "/{id}/role-mappings/realm",
|
||||
urlParamKeys: ["id"],
|
||||
payloadKey: "roles",
|
||||
});
|
||||
|
||||
public listAvailableRealmRoleMappings = this.makeRequest<
|
||||
{ id: string },
|
||||
RoleRepresentation[]
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/{id}/role-mappings/realm/available",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
// Get effective realm-level role mappings This will recurse all composite roles to get the result.
|
||||
public listCompositeRealmRoleMappings = this.makeRequest<
|
||||
{ id: string },
|
||||
RoleRepresentation[]
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/{id}/role-mappings/realm/composite",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
/**
|
||||
* Client role mappings
|
||||
* https://www.keycloak.org/docs-api/11.0/rest-api/#_client_role_mappings_resource
|
||||
*/
|
||||
|
||||
public listClientRoleMappings = this.makeRequest<
|
||||
{ id: string; clientUniqueId: string },
|
||||
RoleRepresentation[]
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/{id}/role-mappings/clients/{clientUniqueId}",
|
||||
urlParamKeys: ["id", "clientUniqueId"],
|
||||
});
|
||||
|
||||
public addClientRoleMappings = this.makeRequest<
|
||||
{ id: string; clientUniqueId: string; roles: RoleMappingPayload[] },
|
||||
void
|
||||
>({
|
||||
method: "POST",
|
||||
path: "/{id}/role-mappings/clients/{clientUniqueId}",
|
||||
urlParamKeys: ["id", "clientUniqueId"],
|
||||
payloadKey: "roles",
|
||||
});
|
||||
|
||||
public delClientRoleMappings = this.makeRequest<
|
||||
{ id: string; clientUniqueId: string; roles: RoleMappingPayload[] },
|
||||
void
|
||||
>({
|
||||
method: "DELETE",
|
||||
path: "/{id}/role-mappings/clients/{clientUniqueId}",
|
||||
urlParamKeys: ["id", "clientUniqueId"],
|
||||
payloadKey: "roles",
|
||||
});
|
||||
|
||||
public listAvailableClientRoleMappings = this.makeRequest<
|
||||
{ id: string; clientUniqueId: string },
|
||||
RoleRepresentation[]
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/{id}/role-mappings/clients/{clientUniqueId}/available",
|
||||
urlParamKeys: ["id", "clientUniqueId"],
|
||||
});
|
||||
|
||||
public listCompositeClientRoleMappings = this.makeRequest<
|
||||
{ id: string; clientUniqueId: string },
|
||||
RoleRepresentation[]
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/{id}/role-mappings/clients/{clientUniqueId}/composite",
|
||||
urlParamKeys: ["id", "clientUniqueId"],
|
||||
});
|
||||
|
||||
/**
|
||||
* Authorization permissions
|
||||
*/
|
||||
public updatePermission = this.makeUpdateRequest<
|
||||
{ id: string },
|
||||
ManagementPermissionReference,
|
||||
ManagementPermissionReference
|
||||
>({
|
||||
method: "PUT",
|
||||
path: "/{id}/management/permissions",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
public listPermissions = this.makeRequest<
|
||||
{ id: string },
|
||||
ManagementPermissionReference
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/{id}/management/permissions",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
constructor(client: KeycloakAdminClient) {
|
||||
super(client, {
|
||||
path: "/admin/realms/{realm}/groups",
|
||||
getUrlParams: () => ({
|
||||
realm: client.realmName,
|
||||
}),
|
||||
getBaseUrl: () => client.baseUrl,
|
||||
});
|
||||
}
|
||||
}
|
157
libs/keycloak-admin-client/src/resources/identityProviders.ts
Normal file
157
libs/keycloak-admin-client/src/resources/identityProviders.ts
Normal file
|
@ -0,0 +1,157 @@
|
|||
import type { KeycloakAdminClient } from "../client.js";
|
||||
import type IdentityProviderMapperRepresentation from "../defs/identityProviderMapperRepresentation.js";
|
||||
import type { IdentityProviderMapperTypeRepresentation } from "../defs/identityProviderMapperTypeRepresentation.js";
|
||||
import type IdentityProviderRepresentation from "../defs/identityProviderRepresentation.js";
|
||||
import type { ManagementPermissionReference } from "../defs/managementPermissionReference.js";
|
||||
import Resource from "./resource.js";
|
||||
|
||||
export class IdentityProviders extends Resource<{ realm?: string }> {
|
||||
/**
|
||||
* Identity provider
|
||||
* https://www.keycloak.org/docs-api/11.0/rest-api/#_identity_providers_resource
|
||||
*/
|
||||
|
||||
public find = this.makeRequest<{}, IdentityProviderRepresentation[]>({
|
||||
method: "GET",
|
||||
path: "/instances",
|
||||
});
|
||||
|
||||
public create = this.makeRequest<
|
||||
IdentityProviderRepresentation,
|
||||
{ id: string }
|
||||
>({
|
||||
method: "POST",
|
||||
path: "/instances",
|
||||
returnResourceIdInLocationHeader: { field: "id" },
|
||||
});
|
||||
|
||||
public findOne = this.makeRequest<
|
||||
{ alias: string },
|
||||
IdentityProviderRepresentation | undefined
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/instances/{alias}",
|
||||
urlParamKeys: ["alias"],
|
||||
catchNotFound: true,
|
||||
});
|
||||
|
||||
public update = this.makeUpdateRequest<
|
||||
{ alias: string },
|
||||
IdentityProviderRepresentation,
|
||||
void
|
||||
>({
|
||||
method: "PUT",
|
||||
path: "/instances/{alias}",
|
||||
urlParamKeys: ["alias"],
|
||||
});
|
||||
|
||||
public del = this.makeRequest<{ alias: string }, void>({
|
||||
method: "DELETE",
|
||||
path: "/instances/{alias}",
|
||||
urlParamKeys: ["alias"],
|
||||
});
|
||||
|
||||
public findFactory = this.makeRequest<{ providerId: string }, any>({
|
||||
method: "GET",
|
||||
path: "/providers/{providerId}",
|
||||
urlParamKeys: ["providerId"],
|
||||
});
|
||||
|
||||
public findMappers = this.makeRequest<
|
||||
{ alias: string },
|
||||
IdentityProviderMapperRepresentation[]
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/instances/{alias}/mappers",
|
||||
urlParamKeys: ["alias"],
|
||||
});
|
||||
|
||||
public findOneMapper = this.makeRequest<
|
||||
{ alias: string; id: string },
|
||||
IdentityProviderMapperRepresentation | undefined
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/instances/{alias}/mappers/{id}",
|
||||
urlParamKeys: ["alias", "id"],
|
||||
catchNotFound: true,
|
||||
});
|
||||
|
||||
public createMapper = this.makeRequest<
|
||||
{
|
||||
alias: string;
|
||||
identityProviderMapper: IdentityProviderMapperRepresentation;
|
||||
},
|
||||
{ id: string }
|
||||
>({
|
||||
method: "POST",
|
||||
path: "/instances/{alias}/mappers",
|
||||
urlParamKeys: ["alias"],
|
||||
payloadKey: "identityProviderMapper",
|
||||
returnResourceIdInLocationHeader: { field: "id" },
|
||||
});
|
||||
|
||||
public updateMapper = this.makeUpdateRequest<
|
||||
{ alias: string; id: string },
|
||||
IdentityProviderMapperRepresentation,
|
||||
void
|
||||
>({
|
||||
method: "PUT",
|
||||
path: "/instances/{alias}/mappers/{id}",
|
||||
urlParamKeys: ["alias", "id"],
|
||||
});
|
||||
|
||||
public delMapper = this.makeRequest<{ alias: string; id: string }, void>({
|
||||
method: "DELETE",
|
||||
path: "/instances/{alias}/mappers/{id}",
|
||||
urlParamKeys: ["alias", "id"],
|
||||
});
|
||||
|
||||
public findMapperTypes = this.makeRequest<
|
||||
{ alias: string },
|
||||
Record<string, IdentityProviderMapperTypeRepresentation>
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/instances/{alias}/mapper-types",
|
||||
urlParamKeys: ["alias"],
|
||||
});
|
||||
|
||||
public importFromUrl = this.makeRequest<
|
||||
{
|
||||
fromUrl: string;
|
||||
providerId: string;
|
||||
},
|
||||
Record<string, string>
|
||||
>({
|
||||
method: "POST",
|
||||
path: "/import-config",
|
||||
});
|
||||
|
||||
public updatePermission = this.makeUpdateRequest<
|
||||
{ alias: string },
|
||||
ManagementPermissionReference,
|
||||
ManagementPermissionReference
|
||||
>({
|
||||
method: "PUT",
|
||||
path: "/instances/{alias}/management/permissions",
|
||||
urlParamKeys: ["alias"],
|
||||
});
|
||||
|
||||
public listPermissions = this.makeRequest<
|
||||
{ alias: string },
|
||||
ManagementPermissionReference
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/instances/{alias}/management/permissions",
|
||||
urlParamKeys: ["alias"],
|
||||
});
|
||||
|
||||
constructor(client: KeycloakAdminClient) {
|
||||
super(client, {
|
||||
path: "/admin/realms/{realm}/identity-provider",
|
||||
getUrlParams: () => ({
|
||||
realm: client.realmName,
|
||||
}),
|
||||
getBaseUrl: () => client.baseUrl,
|
||||
});
|
||||
}
|
||||
}
|
402
libs/keycloak-admin-client/src/resources/realms.ts
Normal file
402
libs/keycloak-admin-client/src/resources/realms.ts
Normal file
|
@ -0,0 +1,402 @@
|
|||
import Resource from "./resource.js";
|
||||
import type AdminEventRepresentation from "../defs/adminEventRepresentation.js";
|
||||
import type RealmRepresentation from "../defs/realmRepresentation.js";
|
||||
import type {
|
||||
PartialImportRealmRepresentation,
|
||||
PartialImportResponse,
|
||||
} from "../defs/realmRepresentation.js";
|
||||
import type EventRepresentation from "../defs/eventRepresentation.js";
|
||||
import type EventType from "../defs/eventTypes.js";
|
||||
import type KeysMetadataRepresentation from "../defs/keyMetadataRepresentation.js";
|
||||
import type ClientInitialAccessPresentation from "../defs/clientInitialAccessPresentation.js";
|
||||
import type TestLdapConnectionRepresentation from "../defs/testLdapConnection.js";
|
||||
|
||||
import type { KeycloakAdminClient } from "../client.js";
|
||||
import type { RealmEventsConfigRepresentation } from "../defs/realmEventsConfigRepresentation.js";
|
||||
import type GlobalRequestResult from "../defs/globalRequestResult.js";
|
||||
import type GroupRepresentation from "../defs/groupRepresentation.js";
|
||||
import type { ManagementPermissionReference } from "../defs/managementPermissionReference.js";
|
||||
import type ComponentTypeRepresentation from "../defs/componentTypeRepresentation.js";
|
||||
|
||||
export class Realms extends Resource {
|
||||
/**
|
||||
* Realm
|
||||
* https://www.keycloak.org/docs-api/11.0/rest-api/#_realms_admin_resource
|
||||
*/
|
||||
|
||||
public find = this.makeRequest<
|
||||
{ briefRepresentation?: boolean },
|
||||
RealmRepresentation[]
|
||||
>({
|
||||
method: "GET",
|
||||
});
|
||||
|
||||
public create = this.makeRequest<RealmRepresentation, { realmName: string }>({
|
||||
method: "POST",
|
||||
returnResourceIdInLocationHeader: { field: "realmName" },
|
||||
});
|
||||
|
||||
public findOne = this.makeRequest<
|
||||
{ realm: string },
|
||||
RealmRepresentation | undefined
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/{realm}",
|
||||
urlParamKeys: ["realm"],
|
||||
catchNotFound: true,
|
||||
});
|
||||
|
||||
public update = this.makeUpdateRequest<
|
||||
{ realm: string },
|
||||
RealmRepresentation,
|
||||
void
|
||||
>({
|
||||
method: "PUT",
|
||||
path: "/{realm}",
|
||||
urlParamKeys: ["realm"],
|
||||
});
|
||||
|
||||
public del = this.makeRequest<{ realm: string }, void>({
|
||||
method: "DELETE",
|
||||
path: "/{realm}",
|
||||
urlParamKeys: ["realm"],
|
||||
});
|
||||
|
||||
public partialImport = this.makeRequest<
|
||||
{
|
||||
realm: string;
|
||||
rep: PartialImportRealmRepresentation;
|
||||
},
|
||||
PartialImportResponse
|
||||
>({
|
||||
method: "POST",
|
||||
path: "/{realm}/partialImport",
|
||||
urlParamKeys: ["realm"],
|
||||
payloadKey: "rep",
|
||||
});
|
||||
|
||||
public export = this.makeRequest<
|
||||
{
|
||||
realm: string;
|
||||
exportClients?: boolean;
|
||||
exportGroupsAndRoles?: boolean;
|
||||
},
|
||||
RealmRepresentation
|
||||
>({
|
||||
method: "POST",
|
||||
path: "/{realm}/partial-export",
|
||||
urlParamKeys: ["realm"],
|
||||
queryParamKeys: ["exportClients", "exportGroupsAndRoles"],
|
||||
});
|
||||
|
||||
public getDefaultGroups = this.makeRequest<
|
||||
{ realm: string },
|
||||
GroupRepresentation[]
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/{realm}/default-groups",
|
||||
urlParamKeys: ["realm"],
|
||||
});
|
||||
|
||||
public addDefaultGroup = this.makeRequest<{ realm: string; id: string }>({
|
||||
method: "PUT",
|
||||
path: "/{realm}/default-groups/{id}",
|
||||
urlParamKeys: ["realm", "id"],
|
||||
});
|
||||
|
||||
public removeDefaultGroup = this.makeRequest<{ realm: string; id: string }>({
|
||||
method: "DELETE",
|
||||
path: "/{realm}/default-groups/{id}",
|
||||
urlParamKeys: ["realm", "id"],
|
||||
});
|
||||
|
||||
public getGroupByPath = this.makeRequest<
|
||||
{ path: string; realm: string },
|
||||
GroupRepresentation
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/{realm}/group-by-path/{path}",
|
||||
urlParamKeys: ["realm", "path"],
|
||||
});
|
||||
|
||||
/**
|
||||
* Get events Returns all events, or filters them based on URL query parameters listed here
|
||||
*/
|
||||
public findEvents = this.makeRequest<
|
||||
{
|
||||
realm: string;
|
||||
client?: string;
|
||||
dateFrom?: Date;
|
||||
dateTo?: Date;
|
||||
first?: number;
|
||||
ipAddress?: string;
|
||||
max?: number;
|
||||
type?: EventType | EventType[];
|
||||
user?: string;
|
||||
},
|
||||
EventRepresentation[]
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/{realm}/events",
|
||||
urlParamKeys: ["realm"],
|
||||
queryParamKeys: [
|
||||
"client",
|
||||
"dateFrom",
|
||||
"dateTo",
|
||||
"first",
|
||||
"ipAddress",
|
||||
"max",
|
||||
"type",
|
||||
"user",
|
||||
],
|
||||
});
|
||||
|
||||
public getConfigEvents = this.makeRequest<
|
||||
{ realm: string },
|
||||
RealmEventsConfigRepresentation
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/{realm}/events/config",
|
||||
urlParamKeys: ["realm"],
|
||||
});
|
||||
|
||||
public updateConfigEvents = this.makeUpdateRequest<
|
||||
{ realm: string },
|
||||
RealmEventsConfigRepresentation,
|
||||
void
|
||||
>({
|
||||
method: "PUT",
|
||||
path: "/{realm}/events/config",
|
||||
urlParamKeys: ["realm"],
|
||||
});
|
||||
|
||||
public clearEvents = this.makeRequest<{ realm: string }, void>({
|
||||
method: "DELETE",
|
||||
path: "/{realm}/events",
|
||||
urlParamKeys: ["realm"],
|
||||
});
|
||||
|
||||
public clearAdminEvents = this.makeRequest<{ realm: string }, void>({
|
||||
method: "DELETE",
|
||||
path: "/{realm}/admin-events",
|
||||
urlParamKeys: ["realm"],
|
||||
});
|
||||
|
||||
public getClientRegistrationPolicyProviders = this.makeRequest<
|
||||
{ realm: string },
|
||||
ComponentTypeRepresentation[]
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/{realm}/client-registration-policy/providers",
|
||||
urlParamKeys: ["realm"],
|
||||
});
|
||||
|
||||
public getClientsInitialAccess = this.makeRequest<
|
||||
{ realm: string },
|
||||
ClientInitialAccessPresentation[]
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/{realm}/clients-initial-access",
|
||||
urlParamKeys: ["realm"],
|
||||
});
|
||||
|
||||
public createClientsInitialAccess = this.makeUpdateRequest<
|
||||
{ realm: string },
|
||||
{ count?: number; expiration?: number },
|
||||
ClientInitialAccessPresentation
|
||||
>({
|
||||
method: "POST",
|
||||
path: "/{realm}/clients-initial-access",
|
||||
urlParamKeys: ["realm"],
|
||||
});
|
||||
|
||||
public delClientsInitialAccess = this.makeRequest<
|
||||
{ realm: string; id: string },
|
||||
void
|
||||
>({
|
||||
method: "DELETE",
|
||||
path: "/{realm}/clients-initial-access/{id}",
|
||||
urlParamKeys: ["realm", "id"],
|
||||
});
|
||||
|
||||
/**
|
||||
* Remove a specific user session.
|
||||
*/
|
||||
public removeSession = this.makeRequest<
|
||||
{ realm: string; sessionId: string },
|
||||
void
|
||||
>({
|
||||
method: "DELETE",
|
||||
path: "/{realm}/sessions/{session}",
|
||||
urlParamKeys: ["realm", "session"],
|
||||
catchNotFound: true,
|
||||
});
|
||||
|
||||
/**
|
||||
* Get admin events Returns all admin events, or filters events based on URL query parameters listed here
|
||||
*/
|
||||
public findAdminEvents = this.makeRequest<
|
||||
{
|
||||
realm: string;
|
||||
authClient?: string;
|
||||
authIpAddress?: string;
|
||||
authRealm?: string;
|
||||
authUser?: string;
|
||||
dateFrom?: Date;
|
||||
dateTo?: Date;
|
||||
first?: number;
|
||||
max?: number;
|
||||
operationTypes?: string;
|
||||
resourcePath?: string;
|
||||
resourceTypes?: string;
|
||||
},
|
||||
AdminEventRepresentation[]
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/{realm}/admin-events",
|
||||
urlParamKeys: ["realm"],
|
||||
queryParamKeys: [
|
||||
"authClient",
|
||||
"authIpAddress",
|
||||
"authRealm",
|
||||
"authUser",
|
||||
"dateFrom",
|
||||
"dateTo",
|
||||
"max",
|
||||
"first",
|
||||
"operationTypes",
|
||||
"resourcePath",
|
||||
"resourceTypes",
|
||||
],
|
||||
});
|
||||
|
||||
/**
|
||||
* Users management permissions
|
||||
*/
|
||||
public getUsersManagementPermissions = this.makeRequest<
|
||||
{ realm: string },
|
||||
ManagementPermissionReference
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/{realm}/users-management-permissions",
|
||||
urlParamKeys: ["realm"],
|
||||
});
|
||||
|
||||
public updateUsersManagementPermissions = this.makeRequest<
|
||||
{ realm: string; enabled: boolean },
|
||||
ManagementPermissionReference
|
||||
>({
|
||||
method: "PUT",
|
||||
path: "/{realm}/users-management-permissions",
|
||||
urlParamKeys: ["realm"],
|
||||
});
|
||||
|
||||
/**
|
||||
* Sessions
|
||||
*/
|
||||
public logoutAll = this.makeRequest<{ realm: string }, void>({
|
||||
method: "POST",
|
||||
path: "/{realm}/logout-all",
|
||||
urlParamKeys: ["realm"],
|
||||
});
|
||||
|
||||
public deleteSession = this.makeRequest<
|
||||
{ realm: string; session: string },
|
||||
void
|
||||
>({
|
||||
method: "DELETE",
|
||||
path: "/{realm}/sessions/{session}",
|
||||
urlParamKeys: ["realm", "session"],
|
||||
});
|
||||
|
||||
public pushRevocation = this.makeRequest<
|
||||
{ realm: string },
|
||||
GlobalRequestResult
|
||||
>({
|
||||
method: "POST",
|
||||
path: "/{realm}/push-revocation",
|
||||
urlParamKeys: ["realm"],
|
||||
ignoredKeys: ["realm"],
|
||||
});
|
||||
|
||||
public getKeys = this.makeRequest<
|
||||
{ realm: string },
|
||||
KeysMetadataRepresentation
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/{realm}/keys",
|
||||
urlParamKeys: ["realm"],
|
||||
});
|
||||
|
||||
public testLDAPConnection = this.makeUpdateRequest<
|
||||
{ realm: string },
|
||||
TestLdapConnectionRepresentation
|
||||
>({
|
||||
method: "POST",
|
||||
path: "/{realm}/testLDAPConnection",
|
||||
urlParamKeys: ["realm"],
|
||||
});
|
||||
|
||||
public testSMTPConnection = this.makeUpdateRequest<
|
||||
{ realm: string },
|
||||
Record<string, string | number>
|
||||
>({
|
||||
method: "POST",
|
||||
path: "/{realm}/testSMTPConnection",
|
||||
urlParamKeys: ["realm"],
|
||||
});
|
||||
|
||||
public ldapServerCapabilities = this.makeUpdateRequest<
|
||||
{ realm: string },
|
||||
TestLdapConnectionRepresentation
|
||||
>({
|
||||
method: "POST",
|
||||
path: "/{realm}/ldap-server-capabilities",
|
||||
urlParamKeys: ["realm"],
|
||||
});
|
||||
|
||||
public getRealmSpecificLocales = this.makeRequest<
|
||||
{ realm: string },
|
||||
string[]
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/{realm}/localization",
|
||||
urlParamKeys: ["realm"],
|
||||
});
|
||||
|
||||
public getRealmLocalizationTexts = this.makeRequest<
|
||||
{ realm: string; selectedLocale: string; first?: number; max?: number },
|
||||
Record<string, string>
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/{realm}/localization/{selectedLocale}",
|
||||
urlParamKeys: ["realm", "selectedLocale"],
|
||||
});
|
||||
|
||||
public addLocalization = this.makeUpdateRequest<
|
||||
{ realm: string; selectedLocale: string; key: string },
|
||||
string,
|
||||
void
|
||||
>({
|
||||
method: "PUT",
|
||||
path: "/{realm}/localization/{selectedLocale}/{key}",
|
||||
urlParamKeys: ["realm", "selectedLocale", "key"],
|
||||
headers: { "content-type": "text/plain" },
|
||||
});
|
||||
|
||||
public deleteRealmLocalizationTexts = this.makeRequest<
|
||||
{ realm: string; selectedLocale: string; key?: string },
|
||||
void
|
||||
>({
|
||||
method: "DELETE",
|
||||
path: "/{realm}/localization/{selectedLocale}/{key}",
|
||||
urlParamKeys: ["realm", "selectedLocale", "key"],
|
||||
});
|
||||
|
||||
constructor(client: KeycloakAdminClient) {
|
||||
super(client, {
|
||||
path: "/admin/realms",
|
||||
getBaseUrl: () => client.baseUrl,
|
||||
});
|
||||
}
|
||||
}
|
42
libs/keycloak-admin-client/src/resources/resource.ts
Normal file
42
libs/keycloak-admin-client/src/resources/resource.ts
Normal file
|
@ -0,0 +1,42 @@
|
|||
import type { KeycloakAdminClient } from "../client.js";
|
||||
import { Agent, RequestArgs } from "./agent.js";
|
||||
|
||||
export default class Resource<ParamType = {}> {
|
||||
private agent: Agent;
|
||||
constructor(
|
||||
client: KeycloakAdminClient,
|
||||
settings: {
|
||||
path?: string;
|
||||
getUrlParams?: () => Record<string, any>;
|
||||
getBaseUrl?: () => string;
|
||||
} = {}
|
||||
) {
|
||||
this.agent = new Agent({
|
||||
client,
|
||||
...settings,
|
||||
});
|
||||
}
|
||||
|
||||
public makeRequest = <PayloadType = any, ResponseType = any>(
|
||||
args: RequestArgs
|
||||
): ((
|
||||
payload?: PayloadType & ParamType,
|
||||
options?: Pick<RequestArgs, "catchNotFound">
|
||||
) => Promise<ResponseType>) => {
|
||||
return this.agent.request(args);
|
||||
};
|
||||
|
||||
// update request will take three types: query, payload and response
|
||||
public makeUpdateRequest = <
|
||||
QueryType = any,
|
||||
PayloadType = any,
|
||||
ResponseType = any
|
||||
>(
|
||||
args: RequestArgs
|
||||
): ((
|
||||
query: QueryType & ParamType,
|
||||
payload: PayloadType
|
||||
) => Promise<ResponseType>) => {
|
||||
return this.agent.updateRequest(args);
|
||||
};
|
||||
}
|
178
libs/keycloak-admin-client/src/resources/roles.ts
Normal file
178
libs/keycloak-admin-client/src/resources/roles.ts
Normal file
|
@ -0,0 +1,178 @@
|
|||
import Resource from "./resource.js";
|
||||
import type RoleRepresentation from "../defs/roleRepresentation.js";
|
||||
import type UserRepresentation from "../defs/userRepresentation.js";
|
||||
import type { KeycloakAdminClient } from "../client.js";
|
||||
import type { ManagementPermissionReference } from "../defs/managementPermissionReference.js";
|
||||
|
||||
export interface RoleQuery {
|
||||
first?: number;
|
||||
max?: number;
|
||||
search?: string;
|
||||
briefRepresentation?: boolean;
|
||||
}
|
||||
|
||||
export class Roles extends Resource<{ realm?: string }> {
|
||||
/**
|
||||
* Realm roles
|
||||
*/
|
||||
|
||||
public find = this.makeRequest<RoleQuery, RoleRepresentation[]>({
|
||||
method: "GET",
|
||||
path: "/roles",
|
||||
});
|
||||
|
||||
public create = this.makeRequest<RoleRepresentation, { roleName: string }>({
|
||||
method: "POST",
|
||||
path: "/roles",
|
||||
returnResourceIdInLocationHeader: { field: "roleName" },
|
||||
});
|
||||
|
||||
/**
|
||||
* Roles by name
|
||||
*/
|
||||
|
||||
public findOneByName = this.makeRequest<
|
||||
{ name: string },
|
||||
RoleRepresentation | undefined
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/roles/{name}",
|
||||
urlParamKeys: ["name"],
|
||||
catchNotFound: true,
|
||||
});
|
||||
|
||||
public updateByName = this.makeUpdateRequest<
|
||||
{ name: string },
|
||||
RoleRepresentation,
|
||||
void
|
||||
>({
|
||||
method: "PUT",
|
||||
path: "/roles/{name}",
|
||||
urlParamKeys: ["name"],
|
||||
});
|
||||
|
||||
public delByName = this.makeRequest<{ name: string }, void>({
|
||||
method: "DELETE",
|
||||
path: "/roles/{name}",
|
||||
urlParamKeys: ["name"],
|
||||
});
|
||||
|
||||
public findUsersWithRole = this.makeRequest<
|
||||
{ name: string; first?: number; max?: number },
|
||||
UserRepresentation[]
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/roles/{name}/users",
|
||||
urlParamKeys: ["name"],
|
||||
catchNotFound: true,
|
||||
});
|
||||
|
||||
/**
|
||||
* Roles by id
|
||||
*/
|
||||
|
||||
public findOneById = this.makeRequest<
|
||||
{ id: string },
|
||||
RoleRepresentation | undefined
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/roles-by-id/{id}",
|
||||
urlParamKeys: ["id"],
|
||||
catchNotFound: true,
|
||||
});
|
||||
|
||||
public createComposite = this.makeUpdateRequest<
|
||||
{ roleId: string },
|
||||
RoleRepresentation[],
|
||||
void
|
||||
>({
|
||||
method: "POST",
|
||||
path: "/roles-by-id/{roleId}/composites",
|
||||
urlParamKeys: ["roleId"],
|
||||
});
|
||||
|
||||
public getCompositeRoles = this.makeRequest<
|
||||
{ id: string; search?: string; first?: number; max?: number },
|
||||
RoleRepresentation[]
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/roles-by-id/{id}/composites",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
public getCompositeRolesForRealm = this.makeRequest<
|
||||
{ id: string },
|
||||
RoleRepresentation[]
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/roles-by-id/{id}/composites/realm",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
public getCompositeRolesForClient = this.makeRequest<
|
||||
{ id: string; clientId: string },
|
||||
RoleRepresentation[]
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/roles-by-id/{id}/composites/clients/{clientId}",
|
||||
urlParamKeys: ["id", "clientId"],
|
||||
});
|
||||
|
||||
public delCompositeRoles = this.makeUpdateRequest<
|
||||
{ id: string },
|
||||
RoleRepresentation[],
|
||||
void
|
||||
>({
|
||||
method: "DELETE",
|
||||
path: "/roles-by-id/{id}/composites",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
public updateById = this.makeUpdateRequest<
|
||||
{ id: string },
|
||||
RoleRepresentation,
|
||||
void
|
||||
>({
|
||||
method: "PUT",
|
||||
path: "/roles-by-id/{id}",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
public delById = this.makeRequest<{ id: string }, void>({
|
||||
method: "DELETE",
|
||||
path: "/roles-by-id/{id}",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
/**
|
||||
* Authorization permissions
|
||||
*/
|
||||
public updatePermission = this.makeUpdateRequest<
|
||||
{ id: string },
|
||||
ManagementPermissionReference,
|
||||
ManagementPermissionReference
|
||||
>({
|
||||
method: "PUT",
|
||||
path: "/roles-by-id/{id}/management/permissions",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
public listPermissions = this.makeRequest<
|
||||
{ id: string },
|
||||
ManagementPermissionReference
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/roles-by-id/{id}/management/permissions",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
constructor(client: KeycloakAdminClient) {
|
||||
super(client, {
|
||||
path: "/admin/realms/{realm}",
|
||||
getUrlParams: () => ({
|
||||
realm: client.realmName,
|
||||
}),
|
||||
getBaseUrl: () => client.baseUrl,
|
||||
});
|
||||
}
|
||||
}
|
17
libs/keycloak-admin-client/src/resources/serverInfo.ts
Normal file
17
libs/keycloak-admin-client/src/resources/serverInfo.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
import Resource from "./resource.js";
|
||||
import type { ServerInfoRepresentation } from "../defs/serverInfoRepesentation.js";
|
||||
import type KeycloakAdminClient from "../index.js";
|
||||
|
||||
export class ServerInfo extends Resource {
|
||||
constructor(client: KeycloakAdminClient) {
|
||||
super(client, {
|
||||
path: "/admin/serverinfo",
|
||||
getBaseUrl: () => client.baseUrl,
|
||||
});
|
||||
}
|
||||
|
||||
public find = this.makeRequest<{}, ServerInfoRepresentation>({
|
||||
method: "GET",
|
||||
path: "/",
|
||||
});
|
||||
}
|
18
libs/keycloak-admin-client/src/resources/sessions.ts
Normal file
18
libs/keycloak-admin-client/src/resources/sessions.ts
Normal file
|
@ -0,0 +1,18 @@
|
|||
import Resource from "./resource.js";
|
||||
import type KeycloakAdminClient from "../index.js";
|
||||
|
||||
export class Sessions extends Resource<{ realm?: string }> {
|
||||
public find = this.makeRequest<{}, Record<string, any>[]>({
|
||||
method: "GET",
|
||||
});
|
||||
|
||||
constructor(client: KeycloakAdminClient) {
|
||||
super(client, {
|
||||
path: "/admin/realms/{realm}/client-session-stats",
|
||||
getUrlParams: () => ({
|
||||
realm: client.realmName,
|
||||
}),
|
||||
getBaseUrl: () => client.baseUrl,
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
import type { KeycloakAdminClient } from "../client.js";
|
||||
import type SynchronizationResultRepresentation from "../defs/synchronizationResultRepresentation.js";
|
||||
import Resource from "./resource.js";
|
||||
|
||||
type ActionType = "triggerFullSync" | "triggerChangedUsersSync";
|
||||
type DirectionType = "fedToKeycloak" | "keycloakToFed";
|
||||
type NameResponse = {
|
||||
id: string;
|
||||
name: string;
|
||||
};
|
||||
|
||||
export class UserStorageProvider extends Resource<{ realm?: string }> {
|
||||
public name = this.makeRequest<{ id: string }, NameResponse>({
|
||||
method: "GET",
|
||||
path: "/{id}/name",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
public removeImportedUsers = this.makeRequest<{ id: string }, void>({
|
||||
method: "POST",
|
||||
path: "/{id}/remove-imported-users",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
public sync = this.makeRequest<
|
||||
{ id: string; action?: ActionType },
|
||||
SynchronizationResultRepresentation
|
||||
>({
|
||||
method: "POST",
|
||||
path: "/{id}/sync",
|
||||
urlParamKeys: ["id"],
|
||||
queryParamKeys: ["action"],
|
||||
});
|
||||
|
||||
public unlinkUsers = this.makeRequest<{ id: string }, void>({
|
||||
method: "POST",
|
||||
path: "/{id}/unlink-users",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
public mappersSync = this.makeRequest<
|
||||
{ id: string; parentId: string; direction?: DirectionType },
|
||||
SynchronizationResultRepresentation
|
||||
>({
|
||||
method: "POST",
|
||||
path: "/{parentId}/mappers/{id}/sync",
|
||||
urlParamKeys: ["id", "parentId"],
|
||||
queryParamKeys: ["direction"],
|
||||
});
|
||||
|
||||
constructor(client: KeycloakAdminClient) {
|
||||
super(client, {
|
||||
path: "/admin/realms/{realm}/user-storage",
|
||||
getUrlParams: () => ({
|
||||
realm: client.realmName,
|
||||
}),
|
||||
getBaseUrl: () => client.baseUrl,
|
||||
});
|
||||
}
|
||||
}
|
488
libs/keycloak-admin-client/src/resources/users.ts
Normal file
488
libs/keycloak-admin-client/src/resources/users.ts
Normal file
|
@ -0,0 +1,488 @@
|
|||
import Resource from "./resource.js";
|
||||
import type UserRepresentation from "../defs/userRepresentation.js";
|
||||
import type UserConsentRepresentation from "../defs/userConsentRepresentation.js";
|
||||
import type UserSessionRepresentation from "../defs/userSessionRepresentation.js";
|
||||
import type { KeycloakAdminClient } from "../client.js";
|
||||
import type MappingsRepresentation from "../defs/mappingsRepresentation.js";
|
||||
import type RoleRepresentation from "../defs/roleRepresentation.js";
|
||||
import type { RoleMappingPayload } from "../defs/roleRepresentation.js";
|
||||
import type { RequiredActionAlias } from "../defs/requiredActionProviderRepresentation.js";
|
||||
import type FederatedIdentityRepresentation from "../defs/federatedIdentityRepresentation.js";
|
||||
import type GroupRepresentation from "../defs/groupRepresentation.js";
|
||||
import type CredentialRepresentation from "../defs/credentialRepresentation.js";
|
||||
import type UserProfileConfig from "../defs/userProfileConfig.js";
|
||||
|
||||
export interface UserQuery {
|
||||
email?: string;
|
||||
first?: number;
|
||||
firstName?: string;
|
||||
lastName?: string;
|
||||
max?: number;
|
||||
search?: string;
|
||||
username?: string;
|
||||
exact?: boolean;
|
||||
[key: string]: string | number | undefined | boolean;
|
||||
}
|
||||
|
||||
export class Users extends Resource<{ realm?: string }> {
|
||||
public find = this.makeRequest<UserQuery, UserRepresentation[]>({
|
||||
method: "GET",
|
||||
});
|
||||
|
||||
public create = this.makeRequest<UserRepresentation, { id: string }>({
|
||||
method: "POST",
|
||||
returnResourceIdInLocationHeader: { field: "id" },
|
||||
});
|
||||
|
||||
/**
|
||||
* Single user
|
||||
*/
|
||||
|
||||
public findOne = this.makeRequest<
|
||||
{ id: string },
|
||||
UserRepresentation | undefined
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/{id}",
|
||||
urlParamKeys: ["id"],
|
||||
catchNotFound: true,
|
||||
});
|
||||
|
||||
public update = this.makeUpdateRequest<
|
||||
{ id: string },
|
||||
UserRepresentation,
|
||||
void
|
||||
>({
|
||||
method: "PUT",
|
||||
path: "/{id}",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
public del = this.makeRequest<{ id: string }, void>({
|
||||
method: "DELETE",
|
||||
path: "/{id}",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
public count = this.makeRequest<UserQuery, number>({
|
||||
method: "GET",
|
||||
path: "/count",
|
||||
});
|
||||
|
||||
public getProfile = this.makeRequest<{}, UserProfileConfig>({
|
||||
method: "GET",
|
||||
path: "/profile",
|
||||
});
|
||||
|
||||
public updateProfile = this.makeRequest<UserProfileConfig, UserProfileConfig>(
|
||||
{
|
||||
method: "PUT",
|
||||
path: "/profile",
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* role mappings
|
||||
*/
|
||||
|
||||
public listRoleMappings = this.makeRequest<
|
||||
{ id: string },
|
||||
MappingsRepresentation
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/{id}/role-mappings",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
public addRealmRoleMappings = this.makeRequest<
|
||||
{ id: string; roles: RoleMappingPayload[] },
|
||||
void
|
||||
>({
|
||||
method: "POST",
|
||||
path: "/{id}/role-mappings/realm",
|
||||
urlParamKeys: ["id"],
|
||||
payloadKey: "roles",
|
||||
});
|
||||
|
||||
public listRealmRoleMappings = this.makeRequest<
|
||||
{ id: string },
|
||||
RoleRepresentation[]
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/{id}/role-mappings/realm",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
public delRealmRoleMappings = this.makeRequest<
|
||||
{ id: string; roles: RoleMappingPayload[] },
|
||||
void
|
||||
>({
|
||||
method: "DELETE",
|
||||
path: "/{id}/role-mappings/realm",
|
||||
urlParamKeys: ["id"],
|
||||
payloadKey: "roles",
|
||||
});
|
||||
|
||||
public listAvailableRealmRoleMappings = this.makeRequest<
|
||||
{ id: string },
|
||||
RoleRepresentation[]
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/{id}/role-mappings/realm/available",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
// Get effective realm-level role mappings This will recurse all composite roles to get the result.
|
||||
public listCompositeRealmRoleMappings = this.makeRequest<
|
||||
{ id: string },
|
||||
RoleRepresentation[]
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/{id}/role-mappings/realm/composite",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
/**
|
||||
* Client role mappings
|
||||
* https://www.keycloak.org/docs-api/11.0/rest-api/#_client_role_mappings_resource
|
||||
*/
|
||||
|
||||
public listClientRoleMappings = this.makeRequest<
|
||||
{ id: string; clientUniqueId: string },
|
||||
RoleRepresentation[]
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/{id}/role-mappings/clients/{clientUniqueId}",
|
||||
urlParamKeys: ["id", "clientUniqueId"],
|
||||
});
|
||||
|
||||
public addClientRoleMappings = this.makeRequest<
|
||||
{ id: string; clientUniqueId: string; roles: RoleMappingPayload[] },
|
||||
void
|
||||
>({
|
||||
method: "POST",
|
||||
path: "/{id}/role-mappings/clients/{clientUniqueId}",
|
||||
urlParamKeys: ["id", "clientUniqueId"],
|
||||
payloadKey: "roles",
|
||||
});
|
||||
|
||||
public delClientRoleMappings = this.makeRequest<
|
||||
{ id: string; clientUniqueId: string; roles: RoleMappingPayload[] },
|
||||
void
|
||||
>({
|
||||
method: "DELETE",
|
||||
path: "/{id}/role-mappings/clients/{clientUniqueId}",
|
||||
urlParamKeys: ["id", "clientUniqueId"],
|
||||
payloadKey: "roles",
|
||||
});
|
||||
|
||||
public listAvailableClientRoleMappings = this.makeRequest<
|
||||
{ id: string; clientUniqueId: string },
|
||||
RoleRepresentation[]
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/{id}/role-mappings/clients/{clientUniqueId}/available",
|
||||
urlParamKeys: ["id", "clientUniqueId"],
|
||||
});
|
||||
|
||||
public listCompositeClientRoleMappings = this.makeRequest<
|
||||
{ id: string; clientUniqueId: string },
|
||||
RoleRepresentation[]
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/{id}/role-mappings/clients/{clientUniqueId}/composite",
|
||||
urlParamKeys: ["id", "clientUniqueId"],
|
||||
});
|
||||
|
||||
/**
|
||||
* Send a update account email to the user
|
||||
* an email contains a link the user can click to perform a set of required actions.
|
||||
*/
|
||||
|
||||
public executeActionsEmail = this.makeRequest<
|
||||
{
|
||||
id: string;
|
||||
clientId?: string;
|
||||
lifespan?: number;
|
||||
redirectUri?: string;
|
||||
actions?: (RequiredActionAlias | string)[];
|
||||
},
|
||||
void
|
||||
>({
|
||||
method: "PUT",
|
||||
path: "/{id}/execute-actions-email",
|
||||
urlParamKeys: ["id"],
|
||||
payloadKey: "actions",
|
||||
queryParamKeys: ["lifespan", "redirectUri", "clientId"],
|
||||
headers: { "content-type": "application/json" },
|
||||
keyTransform: {
|
||||
clientId: "client_id",
|
||||
redirectUri: "redirect_uri",
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Group
|
||||
*/
|
||||
|
||||
public listGroups = this.makeRequest<
|
||||
{ id: string; briefRepresentation?: boolean },
|
||||
GroupRepresentation[]
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/{id}/groups",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
public addToGroup = this.makeRequest<{ id: string; groupId: string }, string>(
|
||||
{
|
||||
method: "PUT",
|
||||
path: "/{id}/groups/{groupId}",
|
||||
urlParamKeys: ["id", "groupId"],
|
||||
}
|
||||
);
|
||||
|
||||
public delFromGroup = this.makeRequest<
|
||||
{ id: string; groupId: string },
|
||||
string
|
||||
>({
|
||||
method: "DELETE",
|
||||
path: "/{id}/groups/{groupId}",
|
||||
urlParamKeys: ["id", "groupId"],
|
||||
});
|
||||
|
||||
public countGroups = this.makeRequest<
|
||||
{ id: string; search?: string },
|
||||
{ count: number }
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/{id}/groups/count",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
/**
|
||||
* Federated Identity
|
||||
*/
|
||||
|
||||
public listFederatedIdentities = this.makeRequest<
|
||||
{ id: string },
|
||||
FederatedIdentityRepresentation[]
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/{id}/federated-identity",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
public addToFederatedIdentity = this.makeRequest<
|
||||
{
|
||||
id: string;
|
||||
federatedIdentityId: string;
|
||||
federatedIdentity: FederatedIdentityRepresentation;
|
||||
},
|
||||
void
|
||||
>({
|
||||
method: "POST",
|
||||
path: "/{id}/federated-identity/{federatedIdentityId}",
|
||||
urlParamKeys: ["id", "federatedIdentityId"],
|
||||
payloadKey: "federatedIdentity",
|
||||
});
|
||||
|
||||
public delFromFederatedIdentity = this.makeRequest<
|
||||
{ id: string; federatedIdentityId: string },
|
||||
void
|
||||
>({
|
||||
method: "DELETE",
|
||||
path: "/{id}/federated-identity/{federatedIdentityId}",
|
||||
urlParamKeys: ["id", "federatedIdentityId"],
|
||||
});
|
||||
|
||||
/**
|
||||
* remove totp
|
||||
*/
|
||||
public removeTotp = this.makeRequest<{ id: string }, void>({
|
||||
method: "PUT",
|
||||
path: "/{id}/remove-totp",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
/**
|
||||
* reset password
|
||||
*/
|
||||
public resetPassword = this.makeRequest<
|
||||
{ id: string; credential: CredentialRepresentation },
|
||||
void
|
||||
>({
|
||||
method: "PUT",
|
||||
path: "/{id}/reset-password",
|
||||
urlParamKeys: ["id"],
|
||||
payloadKey: "credential",
|
||||
});
|
||||
|
||||
public getUserStorageCredentialTypes = this.makeRequest<
|
||||
{ id: string },
|
||||
string[]
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/{id}/configured-user-storage-credential-types",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
/**
|
||||
* get user credentials
|
||||
*/
|
||||
public getCredentials = this.makeRequest<
|
||||
{ id: string },
|
||||
CredentialRepresentation[]
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/{id}/credentials",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
/**
|
||||
* delete user credentials
|
||||
*/
|
||||
public deleteCredential = this.makeRequest<
|
||||
{ id: string; credentialId: string },
|
||||
void
|
||||
>({
|
||||
method: "DELETE",
|
||||
path: "/{id}/credentials/{credentialId}",
|
||||
urlParamKeys: ["id", "credentialId"],
|
||||
});
|
||||
|
||||
/**
|
||||
* update a credential label for a user
|
||||
*/
|
||||
public updateCredentialLabel = this.makeUpdateRequest<
|
||||
{ id: string; credentialId: string },
|
||||
string,
|
||||
void
|
||||
>({
|
||||
method: "PUT",
|
||||
path: "/{id}/credentials/{credentialId}/userLabel",
|
||||
urlParamKeys: ["id", "credentialId"],
|
||||
headers: { "content-type": "text/plain" },
|
||||
});
|
||||
|
||||
// Move a credential to a position behind another credential
|
||||
public moveCredentialPositionDown = this.makeRequest<
|
||||
{
|
||||
id: string;
|
||||
credentialId: string;
|
||||
newPreviousCredentialId: string;
|
||||
},
|
||||
void
|
||||
>({
|
||||
method: "POST",
|
||||
path: "/{id}/credentials/{credentialId}/moveAfter/{newPreviousCredentialId}",
|
||||
urlParamKeys: ["id", "credentialId", "newPreviousCredentialId"],
|
||||
});
|
||||
|
||||
// Move a credential to a first position in the credentials list of the user
|
||||
public moveCredentialPositionUp = this.makeRequest<
|
||||
{
|
||||
id: string;
|
||||
credentialId: string;
|
||||
},
|
||||
void
|
||||
>({
|
||||
method: "POST",
|
||||
path: "/{id}/credentials/{credentialId}/moveToFirst",
|
||||
urlParamKeys: ["id", "credentialId"],
|
||||
});
|
||||
|
||||
/**
|
||||
* send verify email
|
||||
*/
|
||||
public sendVerifyEmail = this.makeRequest<
|
||||
{ id: string; clientId?: string; redirectUri?: string },
|
||||
void
|
||||
>({
|
||||
method: "PUT",
|
||||
path: "/{id}/send-verify-email",
|
||||
urlParamKeys: ["id"],
|
||||
queryParamKeys: ["clientId", "redirectUri"],
|
||||
keyTransform: {
|
||||
clientId: "client_id",
|
||||
redirectUri: "redirect_uri",
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* list user sessions
|
||||
*/
|
||||
public listSessions = this.makeRequest<
|
||||
{ id: string },
|
||||
UserSessionRepresentation[]
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/{id}/sessions",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
/**
|
||||
* list offline sessions associated with the user and client
|
||||
*/
|
||||
public listOfflineSessions = this.makeRequest<
|
||||
{ id: string; clientId: string },
|
||||
UserSessionRepresentation[]
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/{id}/offline-sessions/{clientId}",
|
||||
urlParamKeys: ["id", "clientId"],
|
||||
});
|
||||
|
||||
/**
|
||||
* logout user from all sessions
|
||||
*/
|
||||
public logout = this.makeRequest<{ id: string }, void>({
|
||||
method: "POST",
|
||||
path: "/{id}/logout",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
/**
|
||||
* list consents granted by the user
|
||||
*/
|
||||
public listConsents = this.makeRequest<
|
||||
{ id: string },
|
||||
UserConsentRepresentation[]
|
||||
>({
|
||||
method: "GET",
|
||||
path: "/{id}/consents",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
public impersonation = this.makeUpdateRequest<
|
||||
{ id: string },
|
||||
{ user: string; realm: string },
|
||||
Record<string, any>
|
||||
>({
|
||||
method: "POST",
|
||||
path: "/{id}/impersonation",
|
||||
urlParamKeys: ["id"],
|
||||
});
|
||||
|
||||
/**
|
||||
* revoke consent and offline tokens for particular client from user
|
||||
*/
|
||||
public revokeConsent = this.makeRequest<
|
||||
{ id: string; clientId: string },
|
||||
void
|
||||
>({
|
||||
method: "DELETE",
|
||||
path: "/{id}/consents/{clientId}",
|
||||
urlParamKeys: ["id", "clientId"],
|
||||
});
|
||||
|
||||
constructor(client: KeycloakAdminClient) {
|
||||
super(client, {
|
||||
path: "/admin/realms/{realm}/users",
|
||||
getUrlParams: () => ({
|
||||
realm: client.realmName,
|
||||
}),
|
||||
getBaseUrl: () => client.baseUrl,
|
||||
});
|
||||
}
|
||||
}
|
20
libs/keycloak-admin-client/src/resources/whoAmI.ts
Normal file
20
libs/keycloak-admin-client/src/resources/whoAmI.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
import type WhoAmIRepresentation from "../defs/whoAmIRepresentation.js";
|
||||
import type KeycloakAdminClient from "../index.js";
|
||||
import Resource from "./resource.js";
|
||||
|
||||
export class WhoAmI extends Resource<{ realm?: string }> {
|
||||
constructor(client: KeycloakAdminClient) {
|
||||
super(client, {
|
||||
path: "/admin/{realm}/console",
|
||||
getUrlParams: () => ({
|
||||
realm: client.realmName,
|
||||
}),
|
||||
getBaseUrl: () => client.baseUrl,
|
||||
});
|
||||
}
|
||||
|
||||
public find = this.makeRequest<{}, WhoAmIRepresentation>({
|
||||
method: "GET",
|
||||
path: "/whoami",
|
||||
});
|
||||
}
|
88
libs/keycloak-admin-client/src/utils/auth.ts
Normal file
88
libs/keycloak-admin-client/src/utils/auth.ts
Normal file
|
@ -0,0 +1,88 @@
|
|||
import axios, { AxiosRequestConfig, AxiosResponse } from "axios";
|
||||
import camelize from "camelize-ts";
|
||||
import { defaultBaseUrl, defaultRealm } from "./constants.js";
|
||||
import { stringifyQueryParams } from "./stringifyQueryParams.js";
|
||||
|
||||
export type GrantTypes = "client_credentials" | "password" | "refresh_token";
|
||||
|
||||
export interface Credentials {
|
||||
username?: string;
|
||||
password?: string;
|
||||
grantType: GrantTypes;
|
||||
clientId: string;
|
||||
clientSecret?: string;
|
||||
totp?: string;
|
||||
offlineToken?: boolean;
|
||||
refreshToken?: string;
|
||||
}
|
||||
|
||||
export interface Settings {
|
||||
realmName?: string;
|
||||
baseUrl?: string;
|
||||
credentials: Credentials;
|
||||
requestConfig?: AxiosRequestConfig;
|
||||
}
|
||||
|
||||
export interface TokenResponseRaw {
|
||||
access_token: string;
|
||||
expires_in: string;
|
||||
refresh_expires_in: number;
|
||||
refresh_token: string;
|
||||
token_type: string;
|
||||
not_before_policy: number;
|
||||
session_state: string;
|
||||
scope: string;
|
||||
}
|
||||
|
||||
export interface TokenResponse {
|
||||
accessToken: string;
|
||||
expiresIn: string;
|
||||
refreshExpiresIn: number;
|
||||
refreshToken: string;
|
||||
tokenType: string;
|
||||
notBeforePolicy: number;
|
||||
sessionState: string;
|
||||
scope: string;
|
||||
}
|
||||
|
||||
export const getToken = async (settings: Settings): Promise<TokenResponse> => {
|
||||
// Construct URL
|
||||
const baseUrl = settings.baseUrl || defaultBaseUrl;
|
||||
const realmName = settings.realmName || defaultRealm;
|
||||
const url = `${baseUrl}/realms/${realmName}/protocol/openid-connect/token`;
|
||||
|
||||
// Prepare credentials for openid-connect token request
|
||||
// ref: http://openid.net/specs/openid-connect-core-1_0.html#TokenEndpoint
|
||||
const credentials = settings.credentials || ({} as any);
|
||||
const payload = stringifyQueryParams({
|
||||
username: credentials.username,
|
||||
password: credentials.password,
|
||||
grant_type: credentials.grantType,
|
||||
client_id: credentials.clientId,
|
||||
totp: credentials.totp,
|
||||
...(credentials.offlineToken ? { scope: "offline_access" } : {}),
|
||||
...(credentials.refreshToken
|
||||
? {
|
||||
refresh_token: credentials.refreshToken,
|
||||
client_secret: credentials.clientSecret,
|
||||
}
|
||||
: {}),
|
||||
});
|
||||
|
||||
const config: AxiosRequestConfig = {
|
||||
...settings.requestConfig,
|
||||
};
|
||||
|
||||
if (credentials.clientSecret) {
|
||||
config.auth = {
|
||||
username: credentials.clientId,
|
||||
password: credentials.clientSecret,
|
||||
};
|
||||
}
|
||||
|
||||
const { data } = await axios.default.post<
|
||||
any,
|
||||
AxiosResponse<TokenResponseRaw>
|
||||
>(url, payload, config);
|
||||
return camelize(data);
|
||||
};
|
3
libs/keycloak-admin-client/src/utils/constants.ts
Normal file
3
libs/keycloak-admin-client/src/utils/constants.ts
Normal file
|
@ -0,0 +1,3 @@
|
|||
export const defaultBaseUrl = "http://127.0.0.1:8180";
|
||||
|
||||
export const defaultRealm = "master";
|
21
libs/keycloak-admin-client/src/utils/stringifyQueryParams.ts
Normal file
21
libs/keycloak-admin-client/src/utils/stringifyQueryParams.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
export function stringifyQueryParams(params: Record<string, unknown>) {
|
||||
return new URLSearchParams(
|
||||
Object.entries(params).filter((param): param is [string, string] => {
|
||||
const [, value] = param;
|
||||
|
||||
if (typeof value === "undefined" || value === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof value === "string" && value.length === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Array.isArray(value) && value.length === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
})
|
||||
).toString();
|
||||
}
|
47
libs/keycloak-admin-client/test/attackDetection.spec.ts
Normal file
47
libs/keycloak-admin-client/test/attackDetection.spec.ts
Normal file
|
@ -0,0 +1,47 @@
|
|||
// tslint:disable:no-unused-expression
|
||||
import { faker } from "@faker-js/faker";
|
||||
import * as chai from "chai";
|
||||
import { KeycloakAdminClient } from "../src/client.js";
|
||||
import type UserRepresentation from "../src/defs/userRepresentation.js";
|
||||
import { credentials } from "./constants.js";
|
||||
|
||||
const expect = chai.expect;
|
||||
|
||||
describe("Attack Detection", () => {
|
||||
let kcAdminClient: KeycloakAdminClient;
|
||||
let currentUser: UserRepresentation;
|
||||
|
||||
before(async () => {
|
||||
kcAdminClient = new KeycloakAdminClient();
|
||||
await kcAdminClient.auth(credentials);
|
||||
|
||||
const username = faker.internet.userName();
|
||||
currentUser = await kcAdminClient.users.create({
|
||||
username,
|
||||
});
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await kcAdminClient.users.del({ id: currentUser.id! });
|
||||
});
|
||||
|
||||
it("list attack detection for user", async () => {
|
||||
const attackDetection = await kcAdminClient.attackDetection.findOne({
|
||||
id: currentUser.id!,
|
||||
});
|
||||
expect(attackDetection).to.deep.equal({
|
||||
numFailures: 0,
|
||||
disabled: false,
|
||||
lastIPFailure: "n/a",
|
||||
lastFailure: 0,
|
||||
});
|
||||
});
|
||||
|
||||
it("clear any user login failures for all users", async () => {
|
||||
await kcAdminClient.attackDetection.delAll();
|
||||
});
|
||||
|
||||
it("clear any user login failures for a user", async () => {
|
||||
await kcAdminClient.attackDetection.del({ id: currentUser.id! });
|
||||
});
|
||||
});
|
24
libs/keycloak-admin-client/test/auth.spec.ts
Normal file
24
libs/keycloak-admin-client/test/auth.spec.ts
Normal file
|
@ -0,0 +1,24 @@
|
|||
import * as chai from "chai";
|
||||
import { getToken } from "../src/utils/auth.js";
|
||||
import { credentials } from "./constants.js";
|
||||
|
||||
const expect = chai.expect;
|
||||
|
||||
describe("Authorization", () => {
|
||||
it("should get token from local keycloak", async () => {
|
||||
const data = await getToken({
|
||||
credentials,
|
||||
});
|
||||
|
||||
expect(data).to.have.all.keys(
|
||||
"accessToken",
|
||||
"expiresIn",
|
||||
"refreshExpiresIn",
|
||||
"refreshToken",
|
||||
"tokenType",
|
||||
"notBeforePolicy",
|
||||
"sessionState",
|
||||
"scope"
|
||||
);
|
||||
});
|
||||
});
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue