|
| 1 | +# HAWK - Auth Server - Keycloak Extension |
| 2 | + |
| 3 | +This keycloak extension is a companion for the [HAWK Auth client](https://github.com/HAWK-Digital-Environments/hawk-auth-client), |
| 4 | +which aims to create a simple way of working with keycloak as an authentication and authorization backend for microservices. |
| 5 | +While keycloak is a really powerful tool, the REST api and the fine grained access control on it's own resources |
| 6 | +can be a bit cumbersome to work with. This extension provides multiple new endpoints to make it easier |
| 7 | +and more efficient. It also provides a (currently rather simple) logic to invalidate client caches when |
| 8 | +data of the realm changes. |
| 9 | + |
| 10 | +## Installation |
| 11 | + |
| 12 | +To install the extension you may copy the `target/cache-buster-extension.jar` and place it in the `standalone/deployments` folder of your keycloak server. |
| 13 | + |
| 14 | +### Configure access |
| 15 | + |
| 16 | +After the installation of the extension you need to restart the keycloak server. |
| 17 | +With the restart the extension will create a bunch of new roles you need to assign to your clients. |
| 18 | +To make your life easier, we have created a new role `hawk-client` that combines all the roles needed to access the new endpoints. |
| 19 | + |
| 20 | +Create a new client, or use an existing one, and assign the `hawk-client` role to the "Service account roles" of the client. |
| 21 | +This will give your client read-only access to the new endpoints. |
| 22 | + |
| 23 | +If you want to do management operations (like updating the profile structure or managing resource permissions), |
| 24 | +you need to assign the corresponding roles to your client: `hawk-manage-profile-structure`, `hawk-manage-profile-data`, `hawk-manage-resource-permissions`. |
| 25 | + |
| 26 | +## What's in the box? |
| 27 | + |
| 28 | +### New routes |
| 29 | +#### GET Users |
| 30 | +`/realms/{realm}/hawk/users` |
| 31 | + |
| 32 | +This route is more or less a drop-in replacement for the built-in keycloak user search endpoint (`/admin/realms/{realm}/users`), |
| 33 | +however it has some notable differences: |
| 34 | + |
| 35 | +* The response data mirrors the data structure of the `/realms/{realm}/protocol/openid-connect/token/introspect` endpoint (without the token related fields "exp", "iat", etc). |
| 36 | +* You can request multiple users at once by providing a list of user ids in the query parameter `ids`. The response will be a list of users in the same order as the ids. |
| 37 | +* You can request ONLY the user ids by providing the query parameter `idsOnly=true`. The response will be a list of user ids. |
| 38 | +* You can request ONLY users that are considered "online" by providing the query parameter `onlineOnly=true`. The response will be a list of users that have a session with activity in the last 10 minutes. |
| 39 | + |
| 40 | +Supported query parameters: |
| 41 | +* **search** - A String contained in username, first or last name, or email. Default search behavior is prefix-based (e.g., foo or foo*). Use *foo* for infix search and "foo" for exact search. |
| 42 | +* **attributes** - A query to search for custom attributes, in the format `key1:value2 key2:value2` |
| 43 | +* **ids** - A list of user ids to search for, in the format `id1,id2`. If provided, the search and attributes parameters CAN NOT be used. |
| 44 | +* **onlineOnly** - If true, only users with an active session (in any client of the realm) will be returned |
| 45 | +* **idsOnly** - If true, only the user ids will be returned |
| 46 | +* **first** - The first result to return (0-based) |
| 47 | +* **max** - The maximum number of results to return (default 100) |
| 48 | + |
| 49 | +Required roles: `query-users` and `view-users` (the latter is required if "idsOnly" is not set to true) |
| 50 | + |
| 51 | +#### GET User Count |
| 52 | +`/realms/{realm}/hawk/users/count` |
| 53 | + |
| 54 | +This route is a simple count of the users in the realm. Works similar to `/admin/realms/{realm}/users/count`, but allows specific filtering for online users. |
| 55 | + |
| 56 | +Supported query parameters: |
| 57 | +* **onlineOnly** - If true, only users with an active session (in any client of the realm) will be counted |
| 58 | +* **search** - A String contained in username, first or last name, or email. Default search behavior is prefix-based (e.g., foo or foo*). Use *foo* for infix search and "foo" for exact search. |
| 59 | +* **attributes** - A query to search for custom attributes, in the format `key1:value2 key2:value2` |
| 60 | + |
| 61 | +Required roles: `query-users` |
| 62 | + |
| 63 | +#### GET Client Resources |
| 64 | +`/realms/{realm}/hawk/resources` |
| 65 | + |
| 66 | +Returns a list of authorization resource definitions for the client requesting the endpoint. This is a custom implementation of: `/realms/{realm}/authz/protection/resource_set` |
| 67 | +that can be used to filter resources based on their ids. |
| 68 | + |
| 69 | +Supported query parameters: |
| 70 | +* **ids** - A list of resource ids to search for, in the format `id1,id2`. If provided, the search and attributes parameters CAN NOT be used. |
| 71 | +* **first** - The first result to return (0-based) |
| 72 | +* **max** - The maximum number of results to return (default 100) |
| 73 | + |
| 74 | +Required roles: `hawk-view-resource-permissions` or `hawk-manage-resource-permissions` or both. |
| 75 | + |
| 76 | +#### GET Client Resource Users |
| 77 | +`/realms/{realm}/hawk/resources/{resourceId}/users` |
| 78 | + |
| 79 | +Returns a list of users that have been granted permissions (does not include the owner) for the specified resource. |
| 80 | +The response contains both the user id and the allowed scopes. |
| 81 | + |
| 82 | +Required roles: `hawk-view-resource-permissions` or `hawk-manage-resource-permissions` or both. |
| 83 | + |
| 84 | +#### PUT Allow Resource to User |
| 85 | +`/realms/{realm}/hawk/resources/{resourceId}/users/{userId}` |
| 86 | + |
| 87 | +Grants the user the provided scopes for the specified resource. |
| 88 | +If the list of scopes is empty, the user will be granted all scopes for the resource (if the user does not have any scope yet), |
| 89 | +or remove all scopes from the user (if the user has any scope). This basically an endpoint that allows the "share" |
| 90 | +functionality provided by the "account" frontend but with custom roles. |
| 91 | + |
| 92 | +Required roles: `hawk-manage-resource-permissions` |
| 93 | + |
| 94 | +Expected body: |
| 95 | +```json |
| 96 | +{ |
| 97 | + "scopes": ["scope1", "scope2"] |
| 98 | +} |
| 99 | +``` |
| 100 | + |
| 101 | +#### GET Resources shared with User |
| 102 | +`/realms/{realm}/hawk/resources/shared-with/{userId}` |
| 103 | + |
| 104 | +Returns a list of resource ids that have been shared with the specified user. (Shared means, the resources |
| 105 | +have been specifically allowed to the user by a UMA ticket or using the "Allow Resource to User" endpoint). |
| 106 | + |
| 107 | +Supported query parameters: |
| 108 | +* **first** - The first result to return (0-based) |
| 109 | +* **max** - The maximum number of results to return (default 100) |
| 110 | + |
| 111 | +Required roles: `hawk-view-resource-permissions` or `hawk-manage-resource-permissions` or both. |
| 112 | + |
| 113 | +#### GET Resources shared by User |
| 114 | +`/realms/{realm}/hawk/resources/shared-by/{userId}` |
| 115 | + |
| 116 | +Returns a list of resource ids that have been shared by the specified user. (Shared means, the resources |
| 117 | +have been specifically allowed to the user by a UMA ticket or using the "Allow Resource to User" endpoint). |
| 118 | + |
| 119 | +Supported query parameters: |
| 120 | +* **first** - The first result to return (0-based) |
| 121 | +* **max** - The maximum number of results to return (default 100) |
| 122 | + |
| 123 | +Required roles: `hawk-view-resource-permissions` or `hawk-manage-resource-permissions` or both. |
| 124 | + |
| 125 | +#### GET Roles |
| 126 | +`/realms/{realm}/hawk/roles` |
| 127 | + |
| 128 | +This endpoint has the same output as the `/admin/realms/{realm}/roles` endpoint, but has some differences: |
| 129 | + |
| 130 | +* Built-In roles (e.g., `offline_access`, `uma_authorization`) are not included in the response. |
| 131 | +* The response contains `Realm roles` and `Client roles` in the same list. |
| 132 | + |
| 133 | +Supported query parameters: |
| 134 | +* **first** - The first result to return (0-based) |
| 135 | +* **max** - The maximum number of results to return (default 100) |
| 136 | + |
| 137 | +Required roles: `hawk-view-roles` |
| 138 | + |
| 139 | +#### GET Role Members |
| 140 | +`/realms/{realm}/hawk/roles/{roleName}/members` |
| 141 | + |
| 142 | +Returns a list of user ids that have the specified role. |
| 143 | +The response is a list of user ids. |
| 144 | + |
| 145 | +Supported query parameters: |
| 146 | +* **first** - The first result to return (0-based) |
| 147 | +* **max** - The maximum number of results to return (default 100) |
| 148 | + |
| 149 | +Required roles: `hawk-view-roles` AND `view-users` |
| 150 | + |
| 151 | +#### GET Profile structure |
| 152 | +`/realms/{realm}/hawk/profile/structure` |
| 153 | + |
| 154 | +Returns the structure of the user profile in the realm. This is a custom endpoint that |
| 155 | +allows clients to get the profile structure without having read access to the whole realm. |
| 156 | + |
| 157 | +The response is a [UPConfig](https://www.keycloak.org/docs-api/latest/rest-api/index.html#UPConfig) representation. |
| 158 | + |
| 159 | +Required roles: `hawk-view-profile-structure` |
| 160 | + |
| 161 | +#### PUT Profile structure |
| 162 | +`/realms/{realm}/hawk/profile/structure` |
| 163 | + |
| 164 | +Allows your client to update the profile structure of the realm. This is a custom endpoint that |
| 165 | +allows clients to update the profile structure without having write access to the whole realm. |
| 166 | + |
| 167 | +The body of the request should be a [UPConfig](https://www.keycloak.org/docs-api/latest/rest-api/index.html#UPConfig) representation. |
| 168 | + |
| 169 | +Required roles: `hawk-manage-profile-structure` |
| 170 | + |
| 171 | +#### POST User Profile Data |
| 172 | +`/realms/{realm}/hawk/profile/{userId}` |
| 173 | + |
| 174 | +Allows your client to update the profile data of a user. This is a custom endpoint that |
| 175 | +allows clients to update the profile without having global write access to the user or |
| 176 | +using impersonation to update the user. |
| 177 | + |
| 178 | +The body of the request should be a [UserRepresentation](https://www.keycloak.org/docs-api/latest/rest-api/index.html#UserRepresentation) |
| 179 | + |
| 180 | +Required roles: `hawk-manage-profile-data` |
| 181 | + |
| 182 | +#### GET Cache Buster |
| 183 | +`/realms/{realm}/hawk/cache-buster` |
| 184 | + |
| 185 | +This endpoint returns a single timestamp value. The timestamp is updated whenever a write operation |
| 186 | +is performed on the realm. This can be used by clients to invalidate their cache of realm data. |
| 187 | + |
| 188 | +**Beware of dragons:** The current approach is not the most efficient one, as it invalidates the cache of the whole realm |
| 189 | +on each write event. This is a simple approach that works for small realms, but it may not be the best |
| 190 | +solution for large realms. We are open to suggestions and PRs to improve this extension. |
| 191 | + |
| 192 | +Required roles: `hawk-view-cache-buster` |
| 193 | + |
| 194 | +#### GET Connection Info |
| 195 | +`/realms/{realm}/hawk/connection-info` |
| 196 | + |
| 197 | +This endpoint returns information about the connection to the keycloak server required |
| 198 | +for a smooth client experience. |
| 199 | + |
| 200 | +The response contains the following fields: |
| 201 | +* keycloakVersion - The version of the keycloak server (Used for compatibility checks on the client side) |
| 202 | +* extensionVersion - The version of the hawk keycloak extension |
| 203 | +* clientId - The client id of the client that requested the endpoint |
| 204 | +* clientUuid - The uuid of the client that requested the endpoint |
| 205 | + |
| 206 | +Required roles `hawk-client` |
| 207 | + |
| 208 | +### New roles |
| 209 | + |
| 210 | +The extension introduces new roles that can be used to control access to the new endpoints. |
| 211 | +All roles are created on the `realm-management` client of all realms (except the master realm). |
| 212 | +The roles are automatically installed on startup of the extension. |
| 213 | + |
| 214 | +- `hawk-view-cache-buster` - Allows the client to request the cache buster timestamp |
| 215 | +- `hawk-view-roles` - Allows the client to request the roles of the realm and clients |
| 216 | +- `hawk-manage-profile-structure` - Allows the client to update the profile structure of the realm |
| 217 | +- `hawk-view-profile-structure` - Allows the client to request the profile structure of the realm |
| 218 | +- `hawk-manage-profile-data` - Allows the client to update the profile data of a user |
| 219 | +- `hawk-view-resource-permissions` - Allows the client to request the resources of itself and the permissions of the resources |
| 220 | +- `hawk-manage-resource-permissions` - Allows the client to manage the permissions of the resources |
| 221 | + |
| 222 | +There is also a new convience role `hawk-client` that combines the following |
| 223 | +roles to create a read-only client: |
| 224 | + |
| 225 | +- `hawk-client` |
| 226 | + - (account) `view-groups` |
| 227 | + - (account) `view-profile` |
| 228 | + - (realm-management) `view-users` |
| 229 | + - (realm-management) `query-users` |
| 230 | + - (realm-management) `view-authorization` |
| 231 | + - (realm-management) `query-groups` |
| 232 | + - (realm-management) `hawk-view-roles` |
| 233 | + - (realm-management) `hawk-view-cache-buster` |
| 234 | + - (realm-management) `hawk-view-profile-structure` |
| 235 | + |
| 236 | +## Building |
| 237 | + |
| 238 | +To build the extension you may run the following command: |
| 239 | +```bash |
| 240 | +./build.sh |
| 241 | +``` |
| 242 | + |
| 243 | +It will generate the `target/cache-buster-extension.jar` file. |
| 244 | + |
| 245 | +## Postcardware |
| 246 | +You're free to use this package, but if it makes it to your production environment we highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using. |
| 247 | + |
| 248 | +HAWK Fakultät Gestaltung |
| 249 | +Interaction Design Lab |
| 250 | +Renatastraße 11 |
| 251 | +31134 Hildesheim |
| 252 | + |
| 253 | +Thank you :D |
0 commit comments