The Knox Token Service enables the ability for clients to acquire the same JWT token that is used for KnoxSSO with WebSSO flows for UIs to be used for accessing REST APIs. By acquiring the token and setting it as a Bearer token on a request, a client is able to access REST APIs that are protected with the JWTProvider federation provider.
This section describes the overall setup requirements and options for KnoxToken service.
The Knox Token Service configuration can be configured in any descriptor/topology, tailored to issue tokens to authenticated users, and constrain the usage of the tokens in a number of ways.
"services": [ { "name": "KNOXTOKEN", "params": { "knox.token.ttl": "36000000", "knox.token.audiences": "tokenbased", "knox.token.target.url": "https://localhost:8443/gateway/tokenbased", "knox.token.exp.server-managed": "false", "knox.token.renewer.whitelist": "admin", "knox.token.exp.renew-interval": "86400000", "knox.token.exp.max-lifetime": "604800000", "knox.token.type": "JWT" } } ]
Parameter | Description | Default |
---|---|---|
knox.token.ttl | This indicates the lifespan (milliseconds) of the token. Once it expires a new token must be acquired from KnoxToken service. The 36000000 in the topology above gives you 10 hrs. | 30000 (30 seconds) |
knox.token.audiences | This is a comma-separated list of audiences to add to the JWT token. This is used to ensure that a token received by a participating application knows that the token was intended for use with that application. It is optional. In the event that an endpoint has expected audiences and they are not present the token must be rejected. In the event where the token has audiences and the endpoint has none expected then the token is accepted. | empty |
knox.token.target.url | This is an optional configuration parameter to indicate the intended endpoint for which the token may be used. The KnoxShell token credential collector can pull this URL from a knoxtokencache file to be used in scripts. This eliminates the need to prompt for or hardcode endpoints in your scripts. | n/a |
knox.token.exp.server-managed | This is an optional configuration parameter to enable/disable server-managed token state, to support the associated token renewal and revocation APIs. | false |
knox.token.renewer.whitelist | This is an optional configuration parameter to authorize the comma-separated list of users to invoke the associated token renewal and revocation APIs. | |
knox.token.exp.renew-interval | This is an optional configuration parameter to specify the amount of time (milliseconds) to be added to a token's TTL when a renewal request is approved. | 86400000 (24 hours) |
knox.token.exp.max-lifetime | This is an optional configuration parameter to specify the maximum allowed lifetime (milliseconds) of a token, after which renewal will not be permitted. | 604800000 (7 days) |
knox.token.type | If this is configured the generated JWT's header will have this value as the typ property | |
knox.token.issuer | This is an optional configuration parameter to specify the issuer of a token. | KNOXSSO |
Note that server-managed token state can be configured for all KnoxToken service deployments in gateway-site (see gateway.knox.token.exp.server-managed). If it is configured at the gateway level, then the associated service parameter, if configured, will override the gateway configuration.
Adding the KnoxToken configuration shown above to a topology that is protected with the ShrioProvider is a very simple and effective way to expose an endpoint from which a Knox token can be requested. Once it is acquired it may be used to access resources at intended endpoints until it expires.
The following curl command can be used to acquire a token from the Knox Token service as configured in the sandbox topology:
curl -ivku guest:guest-password https://localhost:8443/gateway/sandbox/knoxtoken/api/v1/token
Resulting in a JSON response that contains the token, the expiration and the optional target endpoint:
`{"access_token":"eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJndWVzdCIsImF1ZCI6InRva2VuYmFzZWQiLCJpc3MiOiJLTk9YU1NPIiwiZXhwIjoxNDg5OTQyMTg4fQ.bcqSK7zMnABEM_HVsm3oWNDrQ_ei7PcMI4AtZEERY9LaPo9dzugOg3PA5JH2BRF-lXM3tuEYuZPaZVf8PenzjtBbuQsCg9VVImuu2r1YNVJlcTQ7OV-eW50L6OTI0uZfyrFwX6C7jVhf7d7YR1NNxs4eVbXpS1TZ5fDIRSfU3MU","target_url":"https://localhost:8443/gateway/tokenbased","token_type":"Bearer ","expires_in":1489942188233}`
The following curl example shows how to add a bearer token to an Authorization header:
curl -ivk -H "Authorization: Bearer eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJndWVzdCIsImF1ZCI6InRva2VuYmFzZWQiLCJpc3MiOiJLTk9YU1NPIiwiZXhwIjoxNDg5OTQyMTg4fQ.bcqSK7zMnABEM_HVsm3oWNDrQ_ei7PcMI4AtZEERY9LaPo9dzugOg3PA5JH2BRF-lXM3tuEYuZPaZVf8PenzjtBbuQsCg9VVImuu2r1YNVJlcTQ7OV-eW50L6OTI0uZfyrFwX6C7jVhf7d7YR1NNxs4eVbXpS1TZ5fDIRSfU3MU" https://localhost:8443/gateway/tokenbased/webhdfs/v1/tmp?op=LISTSTATUS
If you want tokens to include group membership informations, add a knox.token.include.groups
query parameter to the URL.
curl -u admin:admin-password -k "https://localhost:8443/gateway/homepage/knoxtoken/api/v1/token?knox.token.include.groups=true"
The response contains the token with the group information:
{ "sub": "admin", "jku": "https://localhost:8443/gateway/homepage/knoxtoken/api/v1/jwks.json", "kid": "oigA7mZCwA2d7oimQyUaB0oDAfhI-1Bjq9y1n-Mw_OU", "iss": "KNOXSSO", "exp": 1649777837, "knox.groups": [ "admin-group2", "admin-group1" ], "managed.token": "true", "knox.id": "dfeb8979-7f00-4938-bbff-1bc7574bb53d" }
This feature is enabled by default. If you want to disable it, add the following configuration to the KNOXTOKEN service.
<param> <name>knox.token.include.groups.allowed</name> <!-- default = true --> <value>false</value> </param>
The KnoxToken service supports the renewal and explicit revocation of tokens it has issued. Support for both requires server-managed token state to be enabled with at least one renewer white-listed.
curl -ivku admin:admin-password -X PUT -d $TOKEN 'https://localhost:8443/gateway/sandbox/knoxtoken/api/v1/token/renew'
The JSON responses include a flag indicating success or failure.
A successful result includes the updated expiration time.
{ "renewed": "true", "expires": "1584278311658" }
Error results include a message describing the reason for failure.
Invalid token
{ "renewed": "false", "error": "Unknown token: 9caf743e-1e0d-4708-a9ac-a684a576067c" }
Unauthorized caller
{ "renewed": "false", "error": "Caller (guest) not authorized to renew tokens." }
curl -ivku admin:admin-password -X DELETE -d $TOKEN 'https://localhost:8443/gateway/sandbox/knoxtoken/api/v1/token/revoke'
The JSON responses include a flag indicating success or failure.
{ "revoked": "true" }
Error results include a message describing the reason for the failure.
Invalid token
{ "revoked": "false", "error": "Unknown token: 9caf743e-1e0d-4708-a9ac-a684a576067c" }
Unauthorized caller
{ "revoked": "false", "error": "Caller (guest) not authorized to revoke tokens." }
KnoxSSO Cookies must not be revoked
$ curl -iku admin:admin-password -H "Content-Type: application/json" -d 'c236d20c-4a05-4cfa-b35e-2ba6dc451de0' -X DELETE https://localhost:8443/gateway/sandbox/knoxtoken/api/v1/token/revoke HTTP/1.1 403 Forbidden Date: Fri, 09 Oct 2023 08:55:25 GMT Set-Cookie: KNOXSESSIONID=node03e9y0cy8giy31rh00xc1mrcfx0.node0; Path=/gateway/sandbox; Secure; HttpOnly Expires: Thu, 01 Jan 1970 00:00:00 GMT Set-Cookie: rememberMe=deleteMe; Path=/gateway/sandbox; Max-Age=0; Expires=Thu, 05-Oct-2023 08:55:25 GMT; SameSite=lax Content-Type: application/json Content-Length: 113 { "revoked": "false", "error": "SSO cookie (c236d20c...2ba6dc451de0) cannot not be revoked.", "code": 20 }
Revoke multiple tokens in one batch:
$ curl -iku admin:admin-password -H "Content-Type: application/json" -d '["3c043de7-f9e9-4c1a-b32f-abfbc3dcbcb2","5735f5ae-bddd-4ed1-9383-47a839b9ae2b"]' -X DELETE https://localhost:8443/gateway/sandbox/knoxtoken/api/v1/token/revokeTokens HTTP/1.1 200 OK Date: Tue, 10 Oct 2023 07:20:39 GMT ... { "revoked": "true" }
When revoking multiple tokens, current token state check is executed one by one. This means, if there was at least failed token revocation, the HTTP response will indicate that despite the fact that the rest of the token revocation actions succeeded.
This endpoint added in the scope of KNOX-2602.
$ curl -ku admin:admin-password -d "1e2f286e-9df1-4123-8d41-e6af523d6923" -X PUT https://localhost:8443/gateway/sandbox/knoxtoken/api/v1/token/enable { "setEnabledFlag": "true", "isEnabled": "true" }
The JSON responses include a flag (setEnabledFlag
) indicating success or failure along with the token state after the action is executed (isEnabled
).
Trying to enable an already enabled token:
$ curl -ku admin:admin-password -d "1e2f286e-9df1-4123-8d41-e6af523d6923" -X PUT https://localhost:8443/gateway/sandbox/knoxtoken/api/v1/token/enable { "setEnabledFlag": "false", "error": "Token is already enabled" }
Disabled KnoxSSO Cookies must not be (re-)enabled:
$ curl -iku admin:admin-password -H "Content-Type: application/json" -d '107824ab-c54d-4db3-b3b5-5c964892ad05' -X PUT https://localhost:8443/gateway/sandbox/knoxtoken/api/v1/token/enable HTTP/1.1 400 Bad Request Date: Fri, 06 Oct 2023 08:57:58 GMT Set-Cookie: KNOXSESSIONID=node011ejmvgcjnlpl13mchqmqjtdjc1.node0; Path=/gateway/sandbox; Secure; HttpOnly Expires: Thu, 01 Jan 1970 00:00:00 GMT Set-Cookie: rememberMe=deleteMe; Path=/gateway/sandbox; Max-Age=0; Expires=Thu, 05-Oct-2023 08:57:58 GMT; SameSite=lax Content-Type: application/json Content-Length: 107 { "setEnabledFlag": "false", "error": "Disabled KnoxSSO Cookies cannot not be enabled", "code": 80 }
Enable multiple tokens in one batch:
$ curl -iku admin:admin-password -H "Content-Type: application/json" -d '["3c043de7-f9e9-4c1a-b32f-abfbc3dcbcb2","5735f5ae-bddd-4ed1-9383-47a839b9ae2b"]' -X PUT https://localhost:8443/gateway/sandbox/knoxtoken/api/v1/token/enableTokens HTTP/1.1 200 OK Date: Tue, 10 Oct 2023 07:19:23 GMT ... { "setEnabledFlag": "true", "isEnabled": "true" }
When enabling multiple tokens, current token state check is not executed. This means, if you are enabling tokens that were already enabled before the batch operation, they remain enabled.
This endpoint added in the scope of KNOX-2602.
$ curl -ku admin:admin-password -d "1e2f286e-9df1-4123-8d41-e6af523d6923" -X PUT https://localhost:8443/gateway/sandbox/knoxtoken/api/v1/token/disable { "setEnabledFlag": "true", "isEnabled": "false" }
The JSON responses include a flag (setEnabledFlag
) indicating success or failure along with the token state after the action is executed (isEnabled
).
Trying to enable an already enabled token:
$ curl -ku admin:admin-password -d "1e2f286e-9df1-4123-8d41-e6af523d6923" -X PUT https://localhost:8443/gateway/sandbox/knoxtoken/api/v1/token/disable { "setEnabledFlag": "false", "error": "Token is already disabled" }
Disable multiple tokens in one batch:
$ curl -iku admin:admin-password -H "Content-Type: application/json" -d '["3c043de7-f9e9-4c1a-b32f-abfbc3dcbcb2","5735f5ae-bddd-4ed1-9383-47a839b9ae2b"]' -X PUT https://localhost:8443/gateway/sandbox/knoxtoken/api/v1/token/disableTokens HTTP/1.1 200 OK Date: Tue, 10 Oct 2023 07:16:14 GMT ... { "setEnabledFlag": "true", "isEnabled": "false" }
When disabling multiple tokens, current token state check is not executed. This means, if you are disabling tokens that were already disabled before the batch operation, they remain disabled.
Fetching tokens by userName
:
$ curl -iku admin:admin-password -X GET https://localhost:8443/gateway/sandbox/knoxtoken/api/v1/token/getUserTokens?userName=admin HTTP/1.1 200 OK Date: Tue, 10 Oct 2023 07:02:32 GMT Set-Cookie: KNOXSESSIONID=node01vfrmf5kpjt0ku6mt9765wwx64.node0; Path=/gateway/sandbox; Secure; HttpOnly Expires: Thu, 01 Jan 1970 00:00:00 GMT Set-Cookie: rememberMe=deleteMe; Path=/gateway/sandbox; Max-Age=0; Expires=Mon, 09-Oct-2023 07:02:32 GMT; SameSite=lax Content-Type: application/json Content-Length: 822 {"tokens":[{"tokenId":"5244358f-19a3-4834-b16f-aa7ddb2e7fe1","issueTime":"2023-10-10T09:02:03.904+0200","expiration":"2023-10-11T09:02:03.000+0200","maxLifetime":"2023-10-17T09:02:03.904+0200","metadata":{"customMetadataMap":{},"knoxSsoCookie":true,"createdBy":null,"userName":"admin","enabled":true,"comment":null},"issueTimeLong":1696921323904,"expirationLong":1697007723000,"maxLifetimeLong":1697526123904},{"tokenId":"9b37e838-4aa2-43fd-b2f1-b35660b33778","issueTime":"2023-10-10T09:02:14.271+0200","expiration":"2023-10-10T10:02:14.242+0200","maxLifetime":"2023-10-17T09:02:14.271+0200","metadata":{"customMetadataMap":{},"knoxSsoCookie":false,"createdBy":null,"userName":"admin","enabled":true,"comment":"admin token 1"},"issueTimeLong":1696921334271,"expirationLong":1696924934242,"maxLifetimeLong":1697526134271}]}
Fetching tokens by createdBy
:
$ curl -iku admin:admin-password -X GET https://localhost:8443/gateway/sandbox/knoxtoken/api/v1/token/getUserTokens?createdBy=admin HTTP/1.1 200 OK Date: Tue, 10 Oct 2023 07:05:45 GMT Set-Cookie: KNOXSESSIONID=node047nn0zjkauc41qzexnjmlhj2j6.node0; Path=/gateway/sandbox; Secure; HttpOnly Expires: Thu, 01 Jan 1970 00:00:00 GMT Set-Cookie: rememberMe=deleteMe; Path=/gateway/sandbox; Max-Age=0; Expires=Mon, 09-Oct-2023 07:05:46 GMT; SameSite=lax Content-Type: application/json Content-Length: 436 {"tokens":[{"tokenId":"3c043de7-f9e9-4c1a-b32f-abfbc3dcbcb2","issueTime":"2023-10-10T09:02:29.146+0200","expiration":"2023-10-10T10:02:29.127+0200","maxLifetime":"2023-10-17T09:02:29.146+0200","metadata":{"customMetadataMap":{},"knoxSsoCookie":false,"createdBy":"admin","userName":"guest","enabled":true,"comment":"admin token 1 for guest"},"issueTimeLong":1696921349146,"expirationLong":1696924949127,"maxLifetimeLong":1697526149146}]}
Fetching tokens by userNameOrCreatedBy
:
$ curl -iku admin:admin-password -X GET https://localhost:8443/gateway/sandbox/knoxtoken/api/v1/token/getUserTokens?userNameOrCreatedBy=admin HTTP/1.1 200 OK Date: Tue, 10 Oct 2023 07:07:02 GMT Set-Cookie: KNOXSESSIONID=node0rt50pq4getaj1s1owcj3pvgfm7.node0; Path=/gateway/sandbox; Secure; HttpOnly Expires: Thu, 01 Jan 1970 00:00:00 GMT Set-Cookie: rememberMe=deleteMe; Path=/gateway/sandbox; Max-Age=0; Expires=Mon, 09-Oct-2023 07:07:02 GMT; SameSite=lax Content-Type: application/json Content-Length: 1246 {"tokens":[{"tokenId":"5244358f-19a3-4834-b16f-aa7ddb2e7fe1","issueTime":"2023-10-10T09:02:03.904+0200","expiration":"2023-10-11T09:02:03.000+0200","maxLifetime":"2023-10-17T09:02:03.904+0200","metadata":{"customMetadataMap":{},"knoxSsoCookie":true,"createdBy":null,"userName":"admin","enabled":true,"comment":null},"issueTimeLong":1696921323904,"expirationLong":1697007723000,"maxLifetimeLong":1697526123904},{"tokenId":"9b37e838-4aa2-43fd-b2f1-b35660b33778","issueTime":"2023-10-10T09:02:14.271+0200","expiration":"2023-10-10T10:02:14.242+0200","maxLifetime":"2023-10-17T09:02:14.271+0200","metadata":{"customMetadataMap":{},"knoxSsoCookie":false,"createdBy":null,"userName":"admin","enabled":true,"comment":"admin token 1"},"issueTimeLong":1696921334271,"expirationLong":1696924934242,"maxLifetimeLong":1697526134271},{"tokenId":"3c043de7-f9e9-4c1a-b32f-abfbc3dcbcb2","issueTime":"2023-10-10T09:02:29.146+0200","expiration":"2023-10-10T10:02:29.127+0200","maxLifetime":"2023-10-17T09:02:29.146+0200","metadata":{"customMetadataMap":{},"knoxSsoCookie":false,"createdBy":"admin","userName":"guest","enabled":true,"comment":"admin token 1 for guest"},"issueTimeLong":1696921349146,"expirationLong":1696924949127,"maxLifetimeLong":1697526149146}]}
Fetching all
tokens:
$ curl -iku admin:admin-password -X GET https://localhost:8443/gateway/sandbox/knoxtoken/api/v1/token/getUserTokens?allTokens=true HTTP/1.1 200 OK Date: Tue, 10 Oct 2023 07:08:08 GMT Set-Cookie: KNOXSESSIONID=node0fctcnhp9fm3w1gq1mc2z993109.node0; Path=/gateway/sandbox; Secure; HttpOnly Expires: Thu, 01 Jan 1970 00:00:00 GMT Set-Cookie: rememberMe=deleteMe; Path=/gateway/sandbox; Max-Age=0; Expires=Mon, 09-Oct-2023 07:08:08 GMT; SameSite=lax Content-Type: application/json Content-Length: 2048 {"tokens":[{"tokenId":"5244358f-19a3-4834-b16f-aa7ddb2e7fe1","issueTime":"2023-10-10T09:02:03.904+0200","expiration":"2023-10-11T09:02:03.000+0200","maxLifetime":"2023-10-17T09:02:03.904+0200","metadata":{"customMetadataMap":{},"knoxSsoCookie":true,"createdBy":null,"userName":"admin","enabled":true,"comment":null},"issueTimeLong":1696921323904,"expirationLong":1697007723000,"maxLifetimeLong":1697526123904},{"tokenId":"9b37e838-4aa2-43fd-b2f1-b35660b33778","issueTime":"2023-10-10T09:02:14.271+0200","expiration":"2023-10-10T10:02:14.242+0200","maxLifetime":"2023-10-17T09:02:14.271+0200","metadata":{"customMetadataMap":{},"knoxSsoCookie":false,"createdBy":null,"userName":"admin","enabled":true,"comment":"admin token 1"},"issueTimeLong":1696921334271,"expirationLong":1696924934242,"maxLifetimeLong":1697526134271},{"tokenId":"3c043de7-f9e9-4c1a-b32f-abfbc3dcbcb2","issueTime":"2023-10-10T09:02:29.146+0200","expiration":"2023-10-10T10:02:29.127+0200","maxLifetime":"2023-10-17T09:02:29.146+0200","metadata":{"customMetadataMap":{},"knoxSsoCookie":false,"createdBy":"admin","userName":"guest","enabled":true,"comment":"admin token 1 for guest"},"issueTimeLong":1696921349146,"expirationLong":1696924949127,"maxLifetimeLong":1697526149146},{"tokenId":"75f1b921-680d-433d-976f-270a100a1cf9","issueTime":"2023-10-10T09:07:50.871+0200","expiration":"2023-10-11T09:07:50.000+0200","maxLifetime":"2023-10-17T09:07:50.871+0200","metadata":{"customMetadataMap":{},"knoxSsoCookie":true,"createdBy":null,"userName":"sam","enabled":true,"comment":null},"issueTimeLong":1696921670871,"expirationLong":1697008070000,"maxLifetimeLong":1697526470871},{"tokenId":"5735f5ae-bddd-4ed1-9383-47a839b9ae2b","issueTime":"2023-10-10T09:07:55.293+0200","expiration":"2023-10-10T10:07:55.276+0200","maxLifetime":"2023-10-17T09:07:55.293+0200","metadata":{"customMetadataMap":{},"knoxSsoCookie":false,"createdBy":null,"userName":"sam","enabled":true,"comment":"sam token"},"issueTimeLong":1696921675293,"expirationLong":1696925275276,"maxLifetimeLong":1697526475293}]}
In Apache Knox v2.0.0 the team added two new UIs that are directly accessible from the Knox Home page:
By default, the homepage
topology comes with the KNOXTOKEN
service enabled with the following attributes:
In this topology, homepage, two new applications were added in order to display the above-listed UIs:
tokengen
: this is an old-style JSP UI, with a relatively simple JS code included. The source is located in the gateway-applications Maven sub-module.token-management
: this is an Angular UI. The source is located in its own knox-token-management-ui Maven sub-module.On the Knox Home page, you will see a new town in the General Proxy Information table like this:
However, the Integration Token links are disabled by default, because token integration requires a gateway-level alias - called knox.token.hash.key
- being created and without that alias, it does not make sense to show those links.
As explained, if you would like to use Knox's token generation features, you will have to create a gateway-level alias with a 256, 384, or 512-bit length JWK. You can do it in - at least - two different ways:
generate-jwk --saveAlias knox.token.hash.key
The second option involves a newly created Knox CLI command called generate-jwk
:
There was an important step the Knox team made to provide more flexibility for our end-users: there are some internal service implementations in Knox that were hard-coded in the Java source code. One of those services is the Token State
service implementation which you can change in gateway-site.xml going forward by setting the gateway.service.tokenstate.impl
property to any of:
org.apache.knox.gateway.services.token.impl.DefaultTokenStateService
- keeps all token information in memory, therefore all of this information is lost when Knox is shut downorg.apache.knox.gateway.services.token.impl.AliasBasedTokenStateService
- token information is stored in the gateway credential store. This is a durable option, but not suitable for HA deploymentsorg.apache.knox.gateway.services.token.impl.JournalBasedTokenStateService
- token information is stored in plain files within $KNOX_DATA_DIR/security/token-state
folder. This option also provides a durable persistence layer for tokens and it might be good for HA scenarios too (in case of KNOX_DATA_DIR is on a shared drive), but the token data is written out in plain text (i.e. not encrypted) so it's less secure.org.apache.knox.gateway.services.token.impl.ZookeeperTokenStateService
- this is an extension of the keystore-based approach. In this case, token information is stored in Zookeeper using Knox aliases. The token's alias name equals to its generated token ID.org.apache.knox.gateway.services.token.impl.JDBCTokenStateService
- stores token information in relational databases. It‘s not only durable, but it’s perfectly fine with HA deployments. Currently, PostgreSQL and MySQL databases are supported.By default, the AliasBasedTokenStateService
implementation is used.
If you want to use the newly implemented database token management, you’ve to set gateway.service.tokenstate.impl
in gateway-site.xml to org.apache.knox.gateway.services.token.impl.JDBCTokenStateService
.
Now, that you have configured your token state backend, you need to configure a valid database in gateway-site.xml. There are two ways to do that:
gateway.database.type
- should be set to postgresql
or mysql
gateway.database.host
- the host where your DB server is runninggateway.database.port
- the port that your DB server is listening ongateway.database.name
- the name of the database you are connecting togateway.database.connection.url
. The following value will show you how to connect to an SSL enabled PostgreSQL server:If your database requires user/password authentication, the following aliases must be saved into the Knox Gateway’s credential store (__gateway-credentials.jceks):
gateway_database_user
- the usernamegateway_database_password
- the passwordAs you can see, there are only 2 tables:
KNOXTOKENS
contains basic information about the generated tokenKNOX_TOKEN_METADATA
contains an arbitrary number of metadata information for the generated token. At the time of this document being written the following metadata exist:passcode
- this is the BASE-64 encoded value of the generated passcode token MAC. That is, the BASE-64 decoded value is a generated MAC.userName
- the logged-in user who generated the tokenenabled
- this is a boolean flag indicating that the given token is enabled or not (a disabled token cannot be used for authentication purposes)comment
- this is optional metadata, saved only if the user enters something in the Comment input field on the Token Generation page (see below)createdBy
- if the token is an impersonated token, this metadata holds the name if the user who generated the token (see Token impersonation below)Once you configured the knox.token.hash.key
alias and optionally customized your token state service, you are all set to generate Knox tokens using the new Token Generation UI:
The following sections are displayed on the page:
Configured maximum lifetime
informs the clients about the knox.token.ttl
property set in the homepage
topology (defaults to 120 days). If that property is not set (e.g. someone removes it from he homepage topology), Knox uses a hard-coded value of 30 seconds (aka. default Knox token TTL)Out of the box, Knox will display the custom lifetime spinners on the Token Generation page. However, they can be hidden by setting the knox.token.lifespan.input.enabled
property to false
in the homepage
topology. Given that possibility and the configured maximum lifetime the generated token can have the following TTL value:
On the resulting page there is two sensitive information that you can use in Knox to authenticate your request:
JWT token - this is the serialized JWT and is fully compatible with the old-style Bearer authorization method. Clicking the JWT Token
label on the page will copy the value into the clipboard. You might want to use it as the ‘Token’ user:
$ curl -ku Token:eyJqa3UiOiJodHRwczpcL1wvbG9jYWxob3N0Ojg0NDNcL2dhdGV3YXlcL2hvbWVwYWdlXC9rbm94dG9rZW5cL2FwaVwvdjFcL2p3a3MuanNvbiIsImtpZCI6IkdsOTZfYTM2MTJCZWFsS2tURFRaOTZfVkVsLVhNRVRFRmZuNTRMQ1A2UDQiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsImprdSI6Imh0dHBzOlwvXC9sb2NhbGhvc3Q6ODQ0M1wvZ2F0ZXdheVwvaG9tZXBhZ2VcL2tub3h0b2tlblwvYXBpXC92MVwvandrcy5qc29uIiwia2lkIjoiR2w5Nl9hMzYxMkJlYWxLa1REVFo5Nl9WRWwtWE1FVEVGZm41NExDUDZQNCIsImlzcyI6IktOT1hTU08iLCJleHAiOjE2MzY2MjU3MTAsIm1hbmFnZWQudG9rZW4iOiJ0cnVlIiwia25veC5pZCI6ImQxNjFjYWMxLWY5M2UtNDIyOS1hMGRkLTNhNzdhYjkxNDg3MSJ9.e_BNPf_G1iBrU0m3hul5VmmSbpw0w1pUAXl3czOcuxFOQ0Tki-Gq76fCBFUNdKt4QwLpNXxM321cH1TeMG4IhL-92QORSIZgRxY4OUtUgERzcU7-27VNYOzJbaRCjrx-Vb4bSriRJJDwbbXyAoEw_bjiP8EzFFJTPmGcctEzrOLWFk57cLO-2QLd2nbrNd4qmrRR6sEfP81Jg8UL-Ptp66vH_xalJJWuoyoNgGRmH8IMdLVwBgeLeVHiI7NmokuhO-vbctoEwV3Rt4pMpA0VSWGFN0MI4WtU0crjXXHg8U9xSZyOeyT3fMZBXctvBomhGlWaAvuT5AxQGyMMP3VLGw https:/localhost:8443/gateway/sandbox/webhdfs/v1?op=LISTSTATUS
{"FileStatuses":{"FileStatus":[{"accessTime":0,"blockSize":0,"childrenNum":1,"fileId":16386,"group":"supergroup","length":0,"modificationTime":1621238405734,"owner":"hdfs","pathSuffix":"tmp","permission":"1777","replication":0,"storagePolicy":0,"type":"DIRECTORY"},{"accessTime":0,"blockSize":0,"childrenNum":1,"fileId":16387,"group":"supergroup","length":0,"modificationTime":1621238326078,"owner":"hdfs","pathSuffix":"user","permission":"755","replication":0,"storagePolicy":0,"type":"DIRECTORY"}]}}
Passcode token - this is the serialized passcode token, which you can use as the ‘Passcode’ user (Clicking the Passcode Token
label on the page will copy the value into the clipboard):
$ curl -ku Passcode:WkRFMk1XTmhZekV0WmprelpTMDBNakk1TFdFd1pHUXRNMkUzTjJGaU9URTBPRGN4OjpPVEV5Tm1KbFltUXROVEUyWkMwME9HSTBMVGd4TTJZdE1HRmxaalJrWlRVNFpXRTA= https://localhost:8443/gateway/sandbox/webhdfs/v1?op=LISTSTATUS
{"FileStatuses":{"FileStatus":[{"accessTime":0,"blockSize":0,"childrenNum":1,"fileId":16386,"group":"supergroup","length":0,"modificationTime":1621238405734,"owner":"hdfs","pathSuffix":"tmp","permission":"1777","replication":0,"storagePolicy":0,"type":"DIRECTORY"},{"accessTime":0,"blockSize":0,"childrenNum":1,"fileId":16387,"group":"supergroup","length":0,"modificationTime":1621238326078,"owner":"hdfs","pathSuffix":"user","permission":"755","replication":0,"storagePolicy":0,"type":"DIRECTORY"}]}}
The reason, we needed to support the shorter Passcode token
, is that there are 3rd party tools where the long JWT exceeds input fields limitations so we need to address this issue with shorter token values.
The rest of the fields are complementary information such as the expiration date/time of the generated token or the user who created it.
If there was an error during token generation, you will see a failure right under the input field boxes (above the Generate Token button):
The above error message indicates a failure that the admin user already generated more tokens than they are allowed to. This limitation is configurable in the gateway-site.xml
:
gateway.knox.token.limit.per.user
- indicates the maximum number of tokens a user can manage at the same time. -1
means that users are allowed to create/manage as many tokens as they want. This configuration only applies when the server-managed token state is enabled either in gateway-site
or at the topology
level. Defaults to 10.This behavior can be changed by setting the following KNOXTOKEN
service-level parameter called knox.token.user.limit.exceeded.action
. This property may have the following values:
REMOVE_OLDEST
- if that’s configured, the oldest token of the user, who the token is being generated for, will be removedRETURN_ERROR
- if that’s configured, Knox will return an error response with 403 error code (as it did in previous versions)The default value is RETURN_ERROR
.
In addition to the token generation UI, Knox comes with the Token Management UI where logged-in users can see all the active tokens that were generated before. That is, if a token got expired and was removed from the underlying token store, it won't be displayed here. Based on a configuration you can find below, users can see only their tokens or all of them.
On this page, you will a table with the following information:
KNOXSSO
service if the feature was enabledIn order to refresh the table, you can use the Refresh icon
above the table (if you generated tokens on another tab for instance).
Batch operations
When at least one token is selected, the following buttons are shown under the table:
Disable Selected Tokens
: when executed, all the selected tokens become disabled (if they were disabled originally, they will remain disabled)Enable Selected Tokens
: when executed, all the selected tokens become enabled (if they were enabled originally, they will remain enabled)Revoke Selected Tokens
: when executed, all the selected tokens will be revoked. Please note this option is shown only, if there is no KnoxSSO cookie (token) selected (i.e. batch revocation only works with regular tokens).Toggles
Show Disabled KnoxSSO Cookies
: this is true by default. Since disabled KnoxSSO cookies remain in the underlying token state service until they expire, it may bother users to see them in the tokens table. Flipping this toggle button helps to hide them.Show My Tokens Only
: this toggle button is only visible to users, who can see all tokens. By default, this is false. Enabling it will filter the tokens table in a way such that it will contain tokens only that were generated for the logged in user (impersonated or not).Configuration
By default, logged in users can see token that were generated by them or for them (in caase of token impersonation). However, you may want to edit the gateway.knox.token.management.users.can.see.all.tokens
parameter in gateway-site.xml
to allow other users than admin
to become such a “superuser”, who can see all tokens on the Token Management UI.
<property> <name>gateway.knox.token.management.users.can.see.all.tokens</name> <value>admin</value> <description>A comma-separated list of user names who can see all tokens on the Token Management page</description> </property>
On the token generation page end-users can generate tokens on behalf of other users by specifying the desired user name in the token impersonation
field. The following screenshot sows a successful token generation for user tom
(the logged in user is admin
).
For this to work, the topology has to be configured with the HadoopAuth authentication provider, or an identity assertion provider where impersonation is enabled In both cases, doAs
support will only work with a valid Hadoop proxyuser configuration (see Hadoop Proxyuser impersonation above)
As indicated above, the KNOXTOKEN
service maintains some hard-coded token metadata out-of-the-box:
In v2.0.0, the Knox team implemented a change in this service that allows end-users to add accept query parameters starting with the md_
prefix and treat them as Knox Token Metadata.
For instance:
curl -iku admin:admin-password -X GET 'https://localhost:8443/gateway/sandbox/knoxtoken/api/v1/token?md_notebookName=accountantKnoxToken&md_souldBeRemovedBy=31March2022&md_otherMeaningfuMetadata=KnoxIsCool'
When such a token is created by Knox, we should save the following metadata too:
It‘s not only Knox can save these metadata, but the Knox’s existing getUserTokens API
endpoint is able to fetch basic token information using the supplied metadata name besides the user name information.
It's important to note the following: the getUserTokens
API returns tokens if any of the supplied metadata exists for the given token. Metadata values may or may not be matched: you can either use the *
wildcard to match all metadata values with a given name or you can further filter the stored metadata information by specifying the desired value.
For instance:
curl -iku admin:admin-password -X GET 'https://localhost:8443/gateway/sandbox/knoxtoken/api/v1/token/getUserTokens?userName=admin&md_notebookName=accountantKnoxToken&md_name=*'
will return all Knox tokens where metadata with notebookName
exists and equals accountantKnoxToken
OR metadata with name
exists.
Another sample:
md_Name=reina&md_Score=50
md_Name=mary&md_Score=100
md_Name=mary&md_Score=20&md_Grade=A
The following table shows the returned token(s) in case metadata filtering is added in the getUserTokens
API:
Metadata | Token returned |
---|---|
md_Name=reina | token1 |
md_Name=mary | token2 and token3 |
md_Score=100 | token2 |
md_Name=mary&md_Score=20 | token2 and token3 |
md_Name=mary&md_Name=reina | token1, token2 and token3 |
md_Name=* | token1, token2 and token3 |
md_Uknown=* | Empty list |
You may want to check out GitHub Pull Request #542 for sample curl
commands.