mirror of https://github.com/halo-dev/halo
feat: implement persistent token based remember me mechanism (#6131)
#### What type of PR is this? /kind feature /area core /milestone 2.17.x #### What this PR does / why we need it: 新增基于持久化 Token 的 RememberMe 机制 本次更新引入了一种新的 RememberMe 机制,该机制基于持久化 Token,以增强安全性和管理灵活性。在此之前,RememberMe 功能通过以下方式生成 Token,并将其作为 cookie 发送回客户端: ``` username + ":" + expiryTime + ":" + algorithmName + ":" + algorithmHex(username + ":" + expiryTime + ":" + password + ":" + key) ``` 此方法的优点在于无需存储 Token 就可以进行验证,并且用户密码的更改会自动使 Token 失效。然而,它的主要缺点是缺乏管理能力,例如无法手动撤销 Token。 鉴于最新的设备管理需求(见 PR #6100),我们需要一种支持设备撤销(revoke)的机制。因此,我们采用了持久化 Token 的方式,并通过随机生成的方法来提高安全性,而不将用户名和密码直接签名在 Token 中。新的 Token 格式如下: ``` base64(tokenValue:series) ``` 此更改将为系统带来更高的安全保障和更灵活的管理选项,特别是在需要高度控制和监管设备访问时。 #### Does this PR introduce a user-facing change? ```release-note 引入基于持久化 Token 的新 RememberMe 机制以增强安全性和管理灵活性,升级后需要重新登录 ```pull/6142/head
parent
3f94cfc9a8
commit
ae6724a2b6
|
@ -12403,6 +12403,243 @@
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/apis/security.halo.run/v1alpha1/remembermetokens": {
|
||||||
|
"get": {
|
||||||
|
"description": "List RememberMeToken",
|
||||||
|
"operationId": "listRememberMeToken",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "Page number. Default is 0.",
|
||||||
|
"in": "query",
|
||||||
|
"name": "page",
|
||||||
|
"schema": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Size number. Default is 0.",
|
||||||
|
"in": "query",
|
||||||
|
"name": "size",
|
||||||
|
"schema": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Label selector. e.g.: hidden!\u003dtrue",
|
||||||
|
"in": "query",
|
||||||
|
"name": "labelSelector",
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Field selector. e.g.: metadata.name\u003d\u003dhalo",
|
||||||
|
"in": "query",
|
||||||
|
"name": "fieldSelector",
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported.",
|
||||||
|
"in": "query",
|
||||||
|
"name": "sort",
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"content": {
|
||||||
|
"*/*": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/RememberMeTokenList"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "Response remembermetokens"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tags": [
|
||||||
|
"RememberMeTokenV1alpha1"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"post": {
|
||||||
|
"description": "Create RememberMeToken",
|
||||||
|
"operationId": "createRememberMeToken",
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"*/*": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/RememberMeToken"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "Fresh remembermetoken"
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"content": {
|
||||||
|
"*/*": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/RememberMeToken"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "Response remembermetokens created just now"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tags": [
|
||||||
|
"RememberMeTokenV1alpha1"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/apis/security.halo.run/v1alpha1/remembermetokens/{name}": {
|
||||||
|
"delete": {
|
||||||
|
"description": "Delete RememberMeToken",
|
||||||
|
"operationId": "deleteRememberMeToken",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "Name of remembermetoken",
|
||||||
|
"in": "path",
|
||||||
|
"name": "name",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Response remembermetoken deleted just now"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tags": [
|
||||||
|
"RememberMeTokenV1alpha1"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"get": {
|
||||||
|
"description": "Get RememberMeToken",
|
||||||
|
"operationId": "getRememberMeToken",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "Name of remembermetoken",
|
||||||
|
"in": "path",
|
||||||
|
"name": "name",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"content": {
|
||||||
|
"*/*": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/RememberMeToken"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "Response single remembermetoken"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tags": [
|
||||||
|
"RememberMeTokenV1alpha1"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"patch": {
|
||||||
|
"description": "Patch RememberMeToken",
|
||||||
|
"operationId": "patchRememberMeToken",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "Name of remembermetoken",
|
||||||
|
"in": "path",
|
||||||
|
"name": "name",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"application/json-patch+json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/JsonPatch"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"content": {
|
||||||
|
"*/*": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/RememberMeToken"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "Response remembermetoken patched just now"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tags": [
|
||||||
|
"RememberMeTokenV1alpha1"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"put": {
|
||||||
|
"description": "Update RememberMeToken",
|
||||||
|
"operationId": "updateRememberMeToken",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "Name of remembermetoken",
|
||||||
|
"in": "path",
|
||||||
|
"name": "name",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"*/*": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/RememberMeToken"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "Updated remembermetoken"
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"content": {
|
||||||
|
"*/*": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/RememberMeToken"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "Response remembermetokens updated just now"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tags": [
|
||||||
|
"RememberMeTokenV1alpha1"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
"/apis/storage.halo.run/v1alpha1/attachments": {
|
"/apis/storage.halo.run/v1alpha1/attachments": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "List Attachment",
|
"description": "List Attachment",
|
||||||
|
@ -19022,12 +19259,12 @@
|
||||||
},
|
},
|
||||||
"visible": {
|
"visible": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
"default": "PUBLIC",
|
||||||
"enum": [
|
"enum": [
|
||||||
"PUBLIC",
|
"PUBLIC",
|
||||||
"INTERNAL",
|
"INTERNAL",
|
||||||
"PRIVATE"
|
"PRIVATE"
|
||||||
],
|
]
|
||||||
"default": "PUBLIC"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -19524,6 +19761,114 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"RememberMeToken": {
|
||||||
|
"required": [
|
||||||
|
"apiVersion",
|
||||||
|
"kind",
|
||||||
|
"metadata",
|
||||||
|
"spec"
|
||||||
|
],
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"apiVersion": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"kind": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"$ref": "#/components/schemas/Metadata"
|
||||||
|
},
|
||||||
|
"spec": {
|
||||||
|
"$ref": "#/components/schemas/RememberMeTokenSpec"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"RememberMeTokenList": {
|
||||||
|
"required": [
|
||||||
|
"first",
|
||||||
|
"hasNext",
|
||||||
|
"hasPrevious",
|
||||||
|
"items",
|
||||||
|
"last",
|
||||||
|
"page",
|
||||||
|
"size",
|
||||||
|
"total",
|
||||||
|
"totalPages"
|
||||||
|
],
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"first": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Indicates whether current page is the first page."
|
||||||
|
},
|
||||||
|
"hasNext": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Indicates whether current page has previous page."
|
||||||
|
},
|
||||||
|
"hasPrevious": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Indicates whether current page has previous page."
|
||||||
|
},
|
||||||
|
"items": {
|
||||||
|
"type": "array",
|
||||||
|
"description": "A chunk of items.",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/components/schemas/RememberMeToken"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"last": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Indicates whether current page is the last page."
|
||||||
|
},
|
||||||
|
"page": {
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Page number, starts from 1. If not set or equal to 0, it means no pagination.",
|
||||||
|
"format": "int32"
|
||||||
|
},
|
||||||
|
"size": {
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Size of each page. If not set or equal to 0, it means no pagination.",
|
||||||
|
"format": "int32"
|
||||||
|
},
|
||||||
|
"total": {
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Total elements.",
|
||||||
|
"format": "int64"
|
||||||
|
},
|
||||||
|
"totalPages": {
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Indicates total pages.",
|
||||||
|
"format": "int64"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"RememberMeTokenSpec": {
|
||||||
|
"required": [
|
||||||
|
"series",
|
||||||
|
"tokenValue",
|
||||||
|
"username"
|
||||||
|
],
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"lastUsed": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "date-time"
|
||||||
|
},
|
||||||
|
"series": {
|
||||||
|
"minLength": 1,
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"tokenValue": {
|
||||||
|
"minLength": 1,
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"username": {
|
||||||
|
"minLength": 1,
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"RemoveOperation": {
|
"RemoveOperation": {
|
||||||
"required": [
|
"required": [
|
||||||
"op",
|
"op",
|
||||||
|
@ -20723,12 +21068,12 @@
|
||||||
},
|
},
|
||||||
"visible": {
|
"visible": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
"default": "PUBLIC",
|
||||||
"enum": [
|
"enum": [
|
||||||
"PUBLIC",
|
"PUBLIC",
|
||||||
"INTERNAL",
|
"INTERNAL",
|
||||||
"PRIVATE"
|
"PRIVATE"
|
||||||
],
|
]
|
||||||
"default": "PUBLIC"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -5152,12 +5152,12 @@
|
||||||
},
|
},
|
||||||
"visible": {
|
"visible": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
"default": "PUBLIC",
|
||||||
"enum": [
|
"enum": [
|
||||||
"PUBLIC",
|
"PUBLIC",
|
||||||
"INTERNAL",
|
"INTERNAL",
|
||||||
"PRIVATE"
|
"PRIVATE"
|
||||||
],
|
]
|
||||||
"default": "PUBLIC"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -5660,12 +5660,12 @@
|
||||||
},
|
},
|
||||||
"visible": {
|
"visible": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
"default": "PUBLIC",
|
||||||
"enum": [
|
"enum": [
|
||||||
"PUBLIC",
|
"PUBLIC",
|
||||||
"INTERNAL",
|
"INTERNAL",
|
||||||
"PRIVATE"
|
"PRIVATE"
|
||||||
],
|
]
|
||||||
"default": "PUBLIC"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -6179,6 +6179,243 @@
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/apis/security.halo.run/v1alpha1/remembermetokens": {
|
||||||
|
"get": {
|
||||||
|
"description": "List RememberMeToken",
|
||||||
|
"operationId": "listRememberMeToken",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "Page number. Default is 0.",
|
||||||
|
"in": "query",
|
||||||
|
"name": "page",
|
||||||
|
"schema": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Size number. Default is 0.",
|
||||||
|
"in": "query",
|
||||||
|
"name": "size",
|
||||||
|
"schema": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Label selector. e.g.: hidden!\u003dtrue",
|
||||||
|
"in": "query",
|
||||||
|
"name": "labelSelector",
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Field selector. e.g.: metadata.name\u003d\u003dhalo",
|
||||||
|
"in": "query",
|
||||||
|
"name": "fieldSelector",
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported.",
|
||||||
|
"in": "query",
|
||||||
|
"name": "sort",
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"content": {
|
||||||
|
"*/*": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/RememberMeTokenList"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "Response remembermetokens"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tags": [
|
||||||
|
"RememberMeTokenV1alpha1"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"post": {
|
||||||
|
"description": "Create RememberMeToken",
|
||||||
|
"operationId": "createRememberMeToken",
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"*/*": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/RememberMeToken"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "Fresh remembermetoken"
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"content": {
|
||||||
|
"*/*": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/RememberMeToken"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "Response remembermetokens created just now"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tags": [
|
||||||
|
"RememberMeTokenV1alpha1"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/apis/security.halo.run/v1alpha1/remembermetokens/{name}": {
|
||||||
|
"delete": {
|
||||||
|
"description": "Delete RememberMeToken",
|
||||||
|
"operationId": "deleteRememberMeToken",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "Name of remembermetoken",
|
||||||
|
"in": "path",
|
||||||
|
"name": "name",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Response remembermetoken deleted just now"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tags": [
|
||||||
|
"RememberMeTokenV1alpha1"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"get": {
|
||||||
|
"description": "Get RememberMeToken",
|
||||||
|
"operationId": "getRememberMeToken",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "Name of remembermetoken",
|
||||||
|
"in": "path",
|
||||||
|
"name": "name",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"content": {
|
||||||
|
"*/*": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/RememberMeToken"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "Response single remembermetoken"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tags": [
|
||||||
|
"RememberMeTokenV1alpha1"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"patch": {
|
||||||
|
"description": "Patch RememberMeToken",
|
||||||
|
"operationId": "patchRememberMeToken",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "Name of remembermetoken",
|
||||||
|
"in": "path",
|
||||||
|
"name": "name",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"application/json-patch+json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/JsonPatch"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"content": {
|
||||||
|
"*/*": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/RememberMeToken"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "Response remembermetoken patched just now"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tags": [
|
||||||
|
"RememberMeTokenV1alpha1"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"put": {
|
||||||
|
"description": "Update RememberMeToken",
|
||||||
|
"operationId": "updateRememberMeToken",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "Name of remembermetoken",
|
||||||
|
"in": "path",
|
||||||
|
"name": "name",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"*/*": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/RememberMeToken"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "Updated remembermetoken"
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"content": {
|
||||||
|
"*/*": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/RememberMeToken"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "Response remembermetokens updated just now"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tags": [
|
||||||
|
"RememberMeTokenV1alpha1"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
"/apis/storage.halo.run/v1alpha1/attachments": {
|
"/apis/storage.halo.run/v1alpha1/attachments": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "List Attachment",
|
"description": "List Attachment",
|
||||||
|
@ -10057,12 +10294,12 @@
|
||||||
},
|
},
|
||||||
"visible": {
|
"visible": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
"default": "PUBLIC",
|
||||||
"enum": [
|
"enum": [
|
||||||
"PUBLIC",
|
"PUBLIC",
|
||||||
"INTERNAL",
|
"INTERNAL",
|
||||||
"PRIVATE"
|
"PRIVATE"
|
||||||
],
|
]
|
||||||
"default": "PUBLIC"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -10140,6 +10377,114 @@
|
||||||
},
|
},
|
||||||
"description": "Extension reference object. The name is mandatory"
|
"description": "Extension reference object. The name is mandatory"
|
||||||
},
|
},
|
||||||
|
"RememberMeToken": {
|
||||||
|
"required": [
|
||||||
|
"apiVersion",
|
||||||
|
"kind",
|
||||||
|
"metadata",
|
||||||
|
"spec"
|
||||||
|
],
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"apiVersion": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"kind": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"$ref": "#/components/schemas/Metadata"
|
||||||
|
},
|
||||||
|
"spec": {
|
||||||
|
"$ref": "#/components/schemas/RememberMeTokenSpec"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"RememberMeTokenList": {
|
||||||
|
"required": [
|
||||||
|
"first",
|
||||||
|
"hasNext",
|
||||||
|
"hasPrevious",
|
||||||
|
"items",
|
||||||
|
"last",
|
||||||
|
"page",
|
||||||
|
"size",
|
||||||
|
"total",
|
||||||
|
"totalPages"
|
||||||
|
],
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"first": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Indicates whether current page is the first page."
|
||||||
|
},
|
||||||
|
"hasNext": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Indicates whether current page has previous page."
|
||||||
|
},
|
||||||
|
"hasPrevious": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Indicates whether current page has previous page."
|
||||||
|
},
|
||||||
|
"items": {
|
||||||
|
"type": "array",
|
||||||
|
"description": "A chunk of items.",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/components/schemas/RememberMeToken"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"last": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Indicates whether current page is the last page."
|
||||||
|
},
|
||||||
|
"page": {
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Page number, starts from 1. If not set or equal to 0, it means no pagination.",
|
||||||
|
"format": "int32"
|
||||||
|
},
|
||||||
|
"size": {
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Size of each page. If not set or equal to 0, it means no pagination.",
|
||||||
|
"format": "int32"
|
||||||
|
},
|
||||||
|
"total": {
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Total elements.",
|
||||||
|
"format": "int64"
|
||||||
|
},
|
||||||
|
"totalPages": {
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Indicates total pages.",
|
||||||
|
"format": "int64"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"RememberMeTokenSpec": {
|
||||||
|
"required": [
|
||||||
|
"series",
|
||||||
|
"tokenValue",
|
||||||
|
"username"
|
||||||
|
],
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"lastUsed": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "date-time"
|
||||||
|
},
|
||||||
|
"series": {
|
||||||
|
"minLength": 1,
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"tokenValue": {
|
||||||
|
"minLength": 1,
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"username": {
|
||||||
|
"minLength": 1,
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"RemoveOperation": {
|
"RemoveOperation": {
|
||||||
"required": [
|
"required": [
|
||||||
"op",
|
"op",
|
||||||
|
@ -11136,12 +11481,12 @@
|
||||||
},
|
},
|
||||||
"visible": {
|
"visible": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
"default": "PUBLIC",
|
||||||
"enum": [
|
"enum": [
|
||||||
"PUBLIC",
|
"PUBLIC",
|
||||||
"INTERNAL",
|
"INTERNAL",
|
||||||
"PRIVATE"
|
"PRIVATE"
|
||||||
],
|
]
|
||||||
"default": "PUBLIC"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -1455,12 +1455,12 @@
|
||||||
},
|
},
|
||||||
"visible": {
|
"visible": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
"default": "PUBLIC",
|
||||||
"enum": [
|
"enum": [
|
||||||
"PUBLIC",
|
"PUBLIC",
|
||||||
"INTERNAL",
|
"INTERNAL",
|
||||||
"PRIVATE"
|
"PRIVATE"
|
||||||
],
|
]
|
||||||
"default": "PUBLIC"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
package run.halo.app.core.extension;
|
||||||
|
|
||||||
|
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import java.time.Instant;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
import run.halo.app.extension.AbstractExtension;
|
||||||
|
import run.halo.app.extension.GVK;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@GVK(group = "security.halo.run", version = "v1alpha1", kind = "RememberMeToken", plural =
|
||||||
|
"remembermetokens", singular = "remembermetoken")
|
||||||
|
public class RememberMeToken extends AbstractExtension {
|
||||||
|
|
||||||
|
@Schema(requiredMode = REQUIRED)
|
||||||
|
private Spec spec;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Accessors(chain = true)
|
||||||
|
@Schema(name = "RememberMeTokenSpec")
|
||||||
|
public static class Spec {
|
||||||
|
@Schema(requiredMode = REQUIRED, minLength = 1)
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
@Schema(requiredMode = REQUIRED, minLength = 1)
|
||||||
|
private String series;
|
||||||
|
|
||||||
|
@Schema(requiredMode = REQUIRED, minLength = 1)
|
||||||
|
private String tokenValue;
|
||||||
|
|
||||||
|
private Instant lastUsed;
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,6 +22,7 @@ import run.halo.app.core.extension.Counter;
|
||||||
import run.halo.app.core.extension.Menu;
|
import run.halo.app.core.extension.Menu;
|
||||||
import run.halo.app.core.extension.MenuItem;
|
import run.halo.app.core.extension.MenuItem;
|
||||||
import run.halo.app.core.extension.Plugin;
|
import run.halo.app.core.extension.Plugin;
|
||||||
|
import run.halo.app.core.extension.RememberMeToken;
|
||||||
import run.halo.app.core.extension.ReverseProxy;
|
import run.halo.app.core.extension.ReverseProxy;
|
||||||
import run.halo.app.core.extension.Role;
|
import run.halo.app.core.extension.Role;
|
||||||
import run.halo.app.core.extension.RoleBinding;
|
import run.halo.app.core.extension.RoleBinding;
|
||||||
|
@ -432,6 +433,21 @@ public class SchemeInitializer implements ApplicationListener<ApplicationContext
|
||||||
|
|
||||||
// security.halo.run
|
// security.halo.run
|
||||||
schemeManager.register(PersonalAccessToken.class);
|
schemeManager.register(PersonalAccessToken.class);
|
||||||
|
schemeManager.register(RememberMeToken.class, indexSpecs -> {
|
||||||
|
indexSpecs.add(new IndexSpec()
|
||||||
|
.setName("spec.series")
|
||||||
|
.setUnique(true)
|
||||||
|
.setIndexFunc(simpleAttribute(RememberMeToken.class,
|
||||||
|
token -> token.getSpec().getSeries())
|
||||||
|
)
|
||||||
|
);
|
||||||
|
indexSpecs.add(new IndexSpec()
|
||||||
|
.setName("spec.username")
|
||||||
|
.setIndexFunc(simpleAttribute(RememberMeToken.class,
|
||||||
|
token -> token.getSpec().getUsername())
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
// migration.halo.run
|
// migration.halo.run
|
||||||
schemeManager.register(Backup.class);
|
schemeManager.register(Backup.class);
|
||||||
|
|
|
@ -5,12 +5,15 @@ import static run.halo.app.security.authentication.WebExchangeMatchers.ignoringM
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.security.config.web.server.ServerHttpSecurity;
|
import org.springframework.security.config.web.server.ServerHttpSecurity;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.web.server.WebFilterExchange;
|
import org.springframework.security.web.server.WebFilterExchange;
|
||||||
|
import org.springframework.security.web.server.authentication.logout.DelegatingServerLogoutHandler;
|
||||||
import org.springframework.security.web.server.authentication.logout.RedirectServerLogoutSuccessHandler;
|
import org.springframework.security.web.server.authentication.logout.RedirectServerLogoutSuccessHandler;
|
||||||
|
import org.springframework.security.web.server.authentication.logout.ServerLogoutHandler;
|
||||||
import org.springframework.security.web.server.authentication.logout.ServerLogoutSuccessHandler;
|
import org.springframework.security.web.server.authentication.logout.ServerLogoutSuccessHandler;
|
||||||
import org.springframework.security.web.server.ui.LogoutPageGeneratingWebFilter;
|
import org.springframework.security.web.server.ui.LogoutPageGeneratingWebFilter;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
@ -22,27 +25,37 @@ import run.halo.app.security.authentication.rememberme.RememberMeServices;
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class LogoutSecurityConfigurer implements SecurityConfigurer {
|
public class LogoutSecurityConfigurer implements SecurityConfigurer {
|
||||||
private final RememberMeServices rememberMeServices;
|
private final RememberMeServices rememberMeServices;
|
||||||
|
private final ApplicationContext applicationContext;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void configure(ServerHttpSecurity http) {
|
public void configure(ServerHttpSecurity http) {
|
||||||
http.logout(logout -> logout.logoutSuccessHandler(new LogoutSuccessHandler()));
|
var serverLogoutHandlers = getLogoutHandlers();
|
||||||
|
http.logout(
|
||||||
|
logout -> logout.logoutSuccessHandler(new LogoutSuccessHandler(serverLogoutHandlers)));
|
||||||
http.addFilterAt(new LogoutPageGeneratingWebFilter(), LOGOUT_PAGE_GENERATING);
|
http.addFilterAt(new LogoutPageGeneratingWebFilter(), LOGOUT_PAGE_GENERATING);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class LogoutSuccessHandler implements ServerLogoutSuccessHandler {
|
private class LogoutSuccessHandler implements ServerLogoutSuccessHandler {
|
||||||
|
|
||||||
private final ServerLogoutSuccessHandler defaultHandler;
|
private final ServerLogoutSuccessHandler defaultHandler;
|
||||||
|
private final ServerLogoutHandler logoutHandler;
|
||||||
|
|
||||||
public LogoutSuccessHandler() {
|
public LogoutSuccessHandler(ServerLogoutHandler... logoutHandler) {
|
||||||
var defaultHandler = new RedirectServerLogoutSuccessHandler();
|
var defaultHandler = new RedirectServerLogoutSuccessHandler();
|
||||||
defaultHandler.setLogoutSuccessUrl(URI.create("/console/?logout"));
|
defaultHandler.setLogoutSuccessUrl(URI.create("/console/?logout"));
|
||||||
this.defaultHandler = defaultHandler;
|
this.defaultHandler = defaultHandler;
|
||||||
|
if (logoutHandler.length == 1) {
|
||||||
|
this.logoutHandler = logoutHandler[0];
|
||||||
|
} else {
|
||||||
|
this.logoutHandler = new DelegatingServerLogoutHandler(logoutHandler);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<Void> onLogoutSuccess(WebFilterExchange exchange,
|
public Mono<Void> onLogoutSuccess(WebFilterExchange exchange,
|
||||||
Authentication authentication) {
|
Authentication authentication) {
|
||||||
return rememberMeServices.loginFail(exchange.getExchange())
|
return logoutHandler.logout(exchange, authentication)
|
||||||
|
.then(rememberMeServices.loginFail(exchange.getExchange()))
|
||||||
.then(ignoringMediaTypeAll(MediaType.APPLICATION_JSON)
|
.then(ignoringMediaTypeAll(MediaType.APPLICATION_JSON)
|
||||||
.matches(exchange.getExchange())
|
.matches(exchange.getExchange())
|
||||||
.flatMap(matchResult -> {
|
.flatMap(matchResult -> {
|
||||||
|
@ -56,4 +69,9 @@ public class LogoutSecurityConfigurer implements SecurityConfigurer {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ServerLogoutHandler[] getLogoutHandlers() {
|
||||||
|
return applicationContext.getBeansOfType(ServerLogoutHandler.class).values()
|
||||||
|
.toArray(new ServerLogoutHandler[0]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
package run.halo.app.security.authentication.rememberme;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import org.springframework.security.web.authentication.rememberme.PersistentRememberMeToken;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
public interface PersistentRememberMeTokenRepository {
|
||||||
|
Mono<Void> createNewToken(PersistentRememberMeToken token);
|
||||||
|
|
||||||
|
Mono<Void> updateToken(String series, String tokenValue, Instant lastUsed);
|
||||||
|
|
||||||
|
Mono<PersistentRememberMeToken> getTokenForSeries(String seriesId);
|
||||||
|
|
||||||
|
Mono<Void> removeUserTokens(String username);
|
||||||
|
}
|
|
@ -0,0 +1,90 @@
|
||||||
|
package run.halo.app.security.authentication.rememberme;
|
||||||
|
|
||||||
|
import static run.halo.app.extension.index.query.QueryFactory.equal;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.Date;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.dao.OptimisticLockingFailureException;
|
||||||
|
import org.springframework.security.web.authentication.rememberme.PersistentRememberMeToken;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
import reactor.util.retry.Retry;
|
||||||
|
import run.halo.app.core.extension.RememberMeToken;
|
||||||
|
import run.halo.app.extension.ListOptions;
|
||||||
|
import run.halo.app.extension.ListResult;
|
||||||
|
import run.halo.app.extension.Metadata;
|
||||||
|
import run.halo.app.extension.PageRequestImpl;
|
||||||
|
import run.halo.app.extension.ReactiveExtensionClient;
|
||||||
|
import run.halo.app.extension.router.selector.FieldSelector;
|
||||||
|
import run.halo.app.infra.ReactiveExtensionPaginatedOperatorImpl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extension based persistent remember me token repository implementation.
|
||||||
|
*
|
||||||
|
* @see RememberMeToken
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class PersistentRememberMeTokenRepositoryImpl
|
||||||
|
implements PersistentRememberMeTokenRepository {
|
||||||
|
private final ReactiveExtensionClient client;
|
||||||
|
private final ReactiveExtensionPaginatedOperatorImpl paginatedOperator;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Mono<Void> createNewToken(PersistentRememberMeToken token) {
|
||||||
|
var rememberMeToken = new RememberMeToken();
|
||||||
|
var metadata = new Metadata();
|
||||||
|
rememberMeToken.setMetadata(metadata);
|
||||||
|
metadata.setGenerateName("token-");
|
||||||
|
var creationTime = Instant.ofEpochMilli(token.getDate().getTime());
|
||||||
|
metadata.setCreationTimestamp(creationTime);
|
||||||
|
|
||||||
|
rememberMeToken.setSpec(new RememberMeToken.Spec());
|
||||||
|
rememberMeToken.getSpec()
|
||||||
|
.setUsername(token.getUsername())
|
||||||
|
.setSeries(token.getSeries())
|
||||||
|
.setTokenValue(token.getTokenValue());
|
||||||
|
return client.create(rememberMeToken).then();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Mono<Void> updateToken(String series, String tokenValue, Instant lastUsed) {
|
||||||
|
return Mono.defer(() -> getTokenExtensionForSeries(series)
|
||||||
|
.flatMap(token -> {
|
||||||
|
token.getSpec().setTokenValue(tokenValue)
|
||||||
|
.setLastUsed(lastUsed);
|
||||||
|
return client.update(token);
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.retryWhen(Retry.backoff(8, Duration.ofMillis(100))
|
||||||
|
.filter(OptimisticLockingFailureException.class::isInstance))
|
||||||
|
.then();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Mono<PersistentRememberMeToken> getTokenForSeries(String seriesId) {
|
||||||
|
return getTokenExtensionForSeries(seriesId)
|
||||||
|
.map(token -> new PersistentRememberMeToken(
|
||||||
|
token.getSpec().getUsername(),
|
||||||
|
token.getSpec().getSeries(),
|
||||||
|
token.getSpec().getTokenValue(),
|
||||||
|
new Date(token.getMetadata().getCreationTimestamp().toEpochMilli())
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Mono<Void> removeUserTokens(String username) {
|
||||||
|
var listOptions = new ListOptions();
|
||||||
|
listOptions.setFieldSelector(FieldSelector.of(equal("spec.username", username)));
|
||||||
|
return paginatedOperator.deleteInitialBatch(RememberMeToken.class, listOptions).then();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Mono<RememberMeToken> getTokenExtensionForSeries(String seriesId) {
|
||||||
|
var listOptions = new ListOptions();
|
||||||
|
listOptions.setFieldSelector(FieldSelector.of(equal("spec.series", seriesId)));
|
||||||
|
return client.listBy(RememberMeToken.class, listOptions, PageRequestImpl.ofSize(1))
|
||||||
|
.flatMap(result -> Mono.justOrEmpty(ListResult.first(result)));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,187 @@
|
||||||
|
package run.halo.app.security.authentication.rememberme;
|
||||||
|
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Base64;
|
||||||
|
import java.util.Date;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.userdetails.ReactiveUserDetailsService;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
import org.springframework.security.web.authentication.rememberme.CookieTheftException;
|
||||||
|
import org.springframework.security.web.authentication.rememberme.InvalidCookieException;
|
||||||
|
import org.springframework.security.web.authentication.rememberme.PersistentRememberMeToken;
|
||||||
|
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
|
||||||
|
import org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationException;
|
||||||
|
import org.springframework.security.web.server.WebFilterExchange;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.server.ServerWebExchange;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>{@link RememberMeServices} implementation based on Barry Jaspan's <a href=
|
||||||
|
* "https://web.archive.org/web/20180819014446/http://jaspan
|
||||||
|
* .com/improved_persistent_login_cookie_best_practice">Improved
|
||||||
|
* Persistent Login Cookie Best Practice</a>.</p>
|
||||||
|
* <p>There is a slight modification to the described approach, in that the username is not
|
||||||
|
* stored as part of the cookie but obtained from the persistent store via an
|
||||||
|
* implementation of {@link PersistentTokenRepository}. The latter should place a unique
|
||||||
|
* constraint on the series identifier, so that it is impossible for the same identifier
|
||||||
|
* to be allocated to two different users.</p>
|
||||||
|
* <p>User management such as changing passwords, removing users and setting user status
|
||||||
|
* should be combined with maintenance of the user's persistent tokens.</p>
|
||||||
|
* <p>
|
||||||
|
* Note that while this class will use the date a token was created to check whether a
|
||||||
|
* presented cookie is older than the configured <tt>tokenValiditySeconds</tt> property
|
||||||
|
* and deny authentication in this case, it will not delete these tokens from storage. A
|
||||||
|
* suitable batch process should be run periodically to remove expired tokens from the
|
||||||
|
* database.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author guqing
|
||||||
|
* @see
|
||||||
|
* <a href="https://github.com/spring-projects/spring-security/blob/902aff451f2f4d3f2ce44659bbef3645bf320ece/web/src/main/java/org/springframework/security/web/authentication/rememberme/PersistentTokenBasedRememberMeServices.java#L61">PersistentTokenBasedRememberMeServices</a>
|
||||||
|
* @since 2.17.0
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Setter
|
||||||
|
@Component
|
||||||
|
public class PersistentTokenBasedRememberMeServices extends TokenBasedRememberMeServices
|
||||||
|
implements RememberMeServices {
|
||||||
|
|
||||||
|
public static final int DEFAULT_SERIES_LENGTH = 16;
|
||||||
|
|
||||||
|
public static final int DEFAULT_TOKEN_LENGTH = 16;
|
||||||
|
|
||||||
|
private final SecureRandom random;
|
||||||
|
|
||||||
|
private final int seriesLength = DEFAULT_SERIES_LENGTH;
|
||||||
|
|
||||||
|
private final int tokenLength = DEFAULT_TOKEN_LENGTH;
|
||||||
|
|
||||||
|
private final PersistentRememberMeTokenRepository tokenRepository;
|
||||||
|
|
||||||
|
public PersistentTokenBasedRememberMeServices(
|
||||||
|
CookieSignatureKeyResolver cookieSignatureKeyResolver,
|
||||||
|
ReactiveUserDetailsService userDetailsService,
|
||||||
|
RememberMeCookieResolver rememberMeCookieResolver,
|
||||||
|
PersistentRememberMeTokenRepository tokenRepository) {
|
||||||
|
super(cookieSignatureKeyResolver, userDetailsService, rememberMeCookieResolver);
|
||||||
|
this.random = new SecureRandom();
|
||||||
|
this.tokenRepository = tokenRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Mono<UserDetails> processAutoLoginCookie(String[] cookieTokens,
|
||||||
|
ServerWebExchange exchange) {
|
||||||
|
if (cookieTokens.length != 2) {
|
||||||
|
throw new InvalidCookieException(
|
||||||
|
"Cookie token did not contain " + 2 + " tokens, but contained '"
|
||||||
|
+ Arrays.asList(cookieTokens) + "'");
|
||||||
|
}
|
||||||
|
String presentedSeries = cookieTokens[0];
|
||||||
|
String presentedToken = cookieTokens[1];
|
||||||
|
return this.tokenRepository.getTokenForSeries(presentedSeries)
|
||||||
|
// No series match, so we can't authenticate using this cookie
|
||||||
|
.switchIfEmpty(Mono.error(new RememberMeAuthenticationException(
|
||||||
|
"No persistent token found for series id: " + presentedSeries))
|
||||||
|
)
|
||||||
|
.flatMap(token -> {
|
||||||
|
// We have a match for this user/series combination
|
||||||
|
if (!presentedToken.equals(token.getTokenValue())) {
|
||||||
|
// Token doesn't match series value. Delete all logins for this user and throw
|
||||||
|
// an exception to warn them.
|
||||||
|
return this.tokenRepository.removeUserTokens(token.getUsername())
|
||||||
|
.then(Mono.error(new CookieTheftException(
|
||||||
|
"Invalid remember-me token (Series/token) mismatch. Implies previous "
|
||||||
|
+ "cookie theft"
|
||||||
|
+ " attack.")));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isTokenExpired(token)) {
|
||||||
|
return Mono.error(
|
||||||
|
new RememberMeAuthenticationException("Remember-me login has expired"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Token also matches, so login is valid. Update the token value, keeping the
|
||||||
|
// *same* series number.
|
||||||
|
log.debug("Refreshing persistent login token for user '{}', series '{}'",
|
||||||
|
token.getUsername(), token.getSeries());
|
||||||
|
var newToken = new PersistentRememberMeToken(token.getUsername(), token.getSeries(),
|
||||||
|
generateTokenData(), new Date());
|
||||||
|
return Mono.just(newToken);
|
||||||
|
})
|
||||||
|
.flatMap(newToken -> updateToken(newToken)
|
||||||
|
.doOnSuccess(unused -> addCookie(newToken, exchange))
|
||||||
|
.onErrorMap(ex -> {
|
||||||
|
log.error("Failed to update token: ", ex);
|
||||||
|
return new RememberMeAuthenticationException(
|
||||||
|
"Autologin failed due to data access problem");
|
||||||
|
})
|
||||||
|
.then(getUserDetailsService().findByUsername(newToken.getUsername()))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isTokenExpired(PersistentRememberMeToken token) {
|
||||||
|
return isTokenExpired(token.getDate().getTime() + getTokenValidityMillis());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Mono<Void> updateToken(PersistentRememberMeToken newToken) {
|
||||||
|
return this.tokenRepository.updateToken(newToken.getSeries(),
|
||||||
|
newToken.getTokenValue(), dateToInstant(newToken.getDate()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Instant dateToInstant(Date date) {
|
||||||
|
return Instant.ofEpochMilli(date.getTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new persistent login token with a new series number, stores the data in
|
||||||
|
* the persistent token repository and adds the corresponding cookie to the response.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected Mono<Void> onLoginSuccess(ServerWebExchange exchange,
|
||||||
|
Authentication successfulAuthentication) {
|
||||||
|
String username = successfulAuthentication.getName();
|
||||||
|
log.debug("Creating new persistent login for user {}", username);
|
||||||
|
PersistentRememberMeToken persistentToken =
|
||||||
|
new PersistentRememberMeToken(username, generateSeriesData(),
|
||||||
|
generateTokenData(), new Date());
|
||||||
|
return this.tokenRepository.createNewToken(persistentToken)
|
||||||
|
.doOnSuccess(unused -> addCookie(persistentToken, exchange))
|
||||||
|
.onErrorResume(Throwable.class, ex -> {
|
||||||
|
log.error("Failed to save persistent token ", ex);
|
||||||
|
return Mono.empty();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Mono<Void> onLogout(WebFilterExchange exchange, Authentication authentication) {
|
||||||
|
if (authentication != null) {
|
||||||
|
return this.tokenRepository.removeUserTokens(authentication.getName());
|
||||||
|
}
|
||||||
|
return Mono.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addCookie(PersistentRememberMeToken token, ServerWebExchange exchange) {
|
||||||
|
setCookie(new String[] {token.getSeries(), token.getTokenValue()}, exchange);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String generateSeriesData() {
|
||||||
|
byte[] newSeries = new byte[this.seriesLength];
|
||||||
|
this.random.nextBytes(newSeries);
|
||||||
|
return new String(Base64.getEncoder().encode(newSeries));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String generateTokenData() {
|
||||||
|
byte[] newToken = new byte[this.tokenLength];
|
||||||
|
this.random.nextBytes(newToken);
|
||||||
|
return new String(Base64.getEncoder().encode(newToken));
|
||||||
|
}
|
||||||
|
|
||||||
|
private long getTokenValidityMillis() {
|
||||||
|
return rememberMeCookieResolver.getCookieMaxAge().toMillis();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
package run.halo.app.security.authentication.rememberme;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.context.event.EventListener;
|
||||||
|
import org.springframework.scheduling.annotation.Async;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import run.halo.app.event.user.PasswordChangedEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remember me token revoker.
|
||||||
|
* <p>
|
||||||
|
* Listen to password changed event and revoke remember me token.
|
||||||
|
* </p>
|
||||||
|
* Maybe you should consider revoke remember me token when user logout or username changed.
|
||||||
|
*
|
||||||
|
* @author guqing
|
||||||
|
* @since 2.17.0
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class RememberMeTokenRevoker {
|
||||||
|
private final PersistentRememberMeTokenRepository tokenRepository;
|
||||||
|
|
||||||
|
@Async
|
||||||
|
@EventListener(PasswordChangedEvent.class)
|
||||||
|
public void onPasswordChanged(PasswordChangedEvent event) {
|
||||||
|
tokenRepository.removeUserTokens(event.getUsername())
|
||||||
|
.block();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
package run.halo.app.security.authentication.rememberme;
|
||||||
|
|
||||||
|
import static run.halo.app.extension.index.query.QueryFactory.and;
|
||||||
|
import static run.halo.app.extension.index.query.QueryFactory.isNull;
|
||||||
|
import static run.halo.app.extension.index.query.QueryFactory.lessThan;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.time.Instant;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import run.halo.app.core.extension.RememberMeToken;
|
||||||
|
import run.halo.app.extension.ListOptions;
|
||||||
|
import run.halo.app.extension.router.selector.FieldSelector;
|
||||||
|
import run.halo.app.infra.ReactiveExtensionPaginatedOperator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A cleaner for remember me tokens that cleans up expired tokens periodically.
|
||||||
|
*
|
||||||
|
* @author guqing
|
||||||
|
* @since 2.17.0
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class RememberTokenCleaner {
|
||||||
|
private final ReactiveExtensionPaginatedOperator paginatedOperator;
|
||||||
|
private final RememberMeCookieResolver rememberMeCookieResolver;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clean up expired tokens every day at 3:00 AM.
|
||||||
|
*/
|
||||||
|
@Scheduled(cron = "0 0 3 * * ?")
|
||||||
|
public void cleanUpExpiredTokens() {
|
||||||
|
paginatedOperator.deleteInitialBatch(RememberMeToken.class, getExpiredTokensListOptions())
|
||||||
|
.then().block();
|
||||||
|
log.info("Expired remember me tokens have been cleaned up.");
|
||||||
|
}
|
||||||
|
|
||||||
|
ListOptions getExpiredTokensListOptions() {
|
||||||
|
var listOptions = new ListOptions();
|
||||||
|
listOptions.setFieldSelector(FieldSelector.of(
|
||||||
|
and(isNull("metadata.deletionTimestamp"),
|
||||||
|
lessThan("metadata.creationTimestamp", getExpirationThreshold().toString())
|
||||||
|
)
|
||||||
|
));
|
||||||
|
return listOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Instant getExpirationThreshold() {
|
||||||
|
return Instant.now().minus(getTokenValidity());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Duration getTokenValidity() {
|
||||||
|
return rememberMeCookieResolver.getCookieMaxAge();
|
||||||
|
}
|
||||||
|
}
|
|
@ -31,7 +31,8 @@ import org.springframework.security.crypto.codec.Utf8;
|
||||||
import org.springframework.security.web.authentication.rememberme.CookieTheftException;
|
import org.springframework.security.web.authentication.rememberme.CookieTheftException;
|
||||||
import org.springframework.security.web.authentication.rememberme.InvalidCookieException;
|
import org.springframework.security.web.authentication.rememberme.InvalidCookieException;
|
||||||
import org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationException;
|
import org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationException;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.security.web.server.WebFilterExchange;
|
||||||
|
import org.springframework.security.web.server.authentication.logout.ServerLogoutHandler;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
import org.springframework.web.server.ServerWebExchange;
|
import org.springframework.web.server.ServerWebExchange;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
@ -54,9 +55,8 @@ import reactor.core.publisher.Mono;
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Setter
|
@Setter
|
||||||
@Getter
|
@Getter
|
||||||
@Component
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class TokenBasedRememberMeServices implements RememberMeServices {
|
public class TokenBasedRememberMeServices implements ServerLogoutHandler, RememberMeServices {
|
||||||
|
|
||||||
public static final int TWO_WEEKS_S = 1209600;
|
public static final int TWO_WEEKS_S = 1209600;
|
||||||
|
|
||||||
|
@ -66,11 +66,11 @@ public class TokenBasedRememberMeServices implements RememberMeServices {
|
||||||
|
|
||||||
private static final String DELIMITER = ":";
|
private static final String DELIMITER = ":";
|
||||||
|
|
||||||
private final CookieSignatureKeyResolver cookieSignatureKeyResolver;
|
protected final CookieSignatureKeyResolver cookieSignatureKeyResolver;
|
||||||
|
|
||||||
private final ReactiveUserDetailsService userDetailsService;
|
protected final ReactiveUserDetailsService userDetailsService;
|
||||||
|
|
||||||
private final RememberMeCookieResolver rememberMeCookieResolver;
|
protected final RememberMeCookieResolver rememberMeCookieResolver;
|
||||||
|
|
||||||
private UserDetailsChecker userDetailsChecker = new AccountStatusUserDetailsChecker();
|
private UserDetailsChecker userDetailsChecker = new AccountStatusUserDetailsChecker();
|
||||||
|
|
||||||
|
@ -218,6 +218,11 @@ public class TokenBasedRememberMeServices implements RememberMeServices {
|
||||||
log.debug("Remember-me login not requested.");
|
log.debug("Remember-me login not requested.");
|
||||||
return Mono.empty();
|
return Mono.empty();
|
||||||
}
|
}
|
||||||
|
return onLoginSuccess(exchange, successfulAuthentication);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Mono<Void> onLoginSuccess(ServerWebExchange exchange,
|
||||||
|
Authentication successfulAuthentication) {
|
||||||
return Mono.defer(() -> retrieveUsernamePassword(successfulAuthentication))
|
return Mono.defer(() -> retrieveUsernamePassword(successfulAuthentication))
|
||||||
.flatMap(pair -> {
|
.flatMap(pair -> {
|
||||||
var username = pair.username();
|
var username = pair.username();
|
||||||
|
@ -372,6 +377,19 @@ public class TokenBasedRememberMeServices implements RememberMeServices {
|
||||||
return cookieSignatureKeyResolver.resolveSigningKey();
|
return cookieSignatureKeyResolver.resolveSigningKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Mono<Void> logout(WebFilterExchange exchange, Authentication authentication) {
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("Logout of user {}", (authentication != null) ? authentication.getName()
|
||||||
|
: "Unknown");
|
||||||
|
}
|
||||||
|
return onLogout(exchange, authentication);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Mono<Void> onLogout(WebFilterExchange exchange, Authentication authentication) {
|
||||||
|
return Mono.empty();
|
||||||
|
}
|
||||||
|
|
||||||
record UsernamePassword(String username, String password) {
|
record UsernamePassword(String username, String password) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,163 @@
|
||||||
|
package run.halo.app.security.authentication.rememberme;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
import org.junit.jupiter.api.Nested;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.mockito.InjectMocks;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
|
||||||
|
import org.springframework.mock.web.server.MockServerWebExchange;
|
||||||
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
|
import org.springframework.security.core.userdetails.ReactiveUserDetailsService;
|
||||||
|
import org.springframework.security.web.authentication.rememberme.CookieTheftException;
|
||||||
|
import org.springframework.security.web.authentication.rememberme.InvalidCookieException;
|
||||||
|
import org.springframework.security.web.authentication.rememberme.PersistentRememberMeToken;
|
||||||
|
import org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationException;
|
||||||
|
import org.springframework.security.web.server.WebFilterExchange;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for {@link PersistentTokenBasedRememberMeServices}.
|
||||||
|
*
|
||||||
|
* @author guqing
|
||||||
|
* @since 2.17.0
|
||||||
|
*/
|
||||||
|
@ExtendWith(MockitoExtension.class)
|
||||||
|
class PersistentTokenBasedRememberMeServicesTest {
|
||||||
|
@Mock
|
||||||
|
private CookieSignatureKeyResolver cookieSignatureKeyResolver;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private ReactiveUserDetailsService userDetailsService;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private RememberMeCookieResolver rememberMeCookieResolver;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private PersistentRememberMeTokenRepository tokenRepository;
|
||||||
|
|
||||||
|
@InjectMocks
|
||||||
|
private PersistentTokenBasedRememberMeServices persistentTokenBasedRememberMeServices;
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
class ProcessAutoLoginCookieTest {
|
||||||
|
@Test
|
||||||
|
void invalidCookieTest() {
|
||||||
|
var exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/"));
|
||||||
|
assertThatThrownBy(() -> persistentTokenBasedRememberMeServices.processAutoLoginCookie(
|
||||||
|
new String[] {"test"},
|
||||||
|
exchange).block())
|
||||||
|
.isInstanceOf(InvalidCookieException.class)
|
||||||
|
.hasMessage("Cookie token did not contain 2 tokens, but contained '[test]'");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void noPersistentTokenFoundTest() {
|
||||||
|
var exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/"));
|
||||||
|
when(tokenRepository.getTokenForSeries(eq("test-series")))
|
||||||
|
.thenReturn(Mono.empty());
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> persistentTokenBasedRememberMeServices.processAutoLoginCookie(
|
||||||
|
new String[] {"test-series", "test"},
|
||||||
|
exchange).block()
|
||||||
|
).isInstanceOf(RememberMeAuthenticationException.class)
|
||||||
|
.hasMessage("No persistent token found for series id: test-series");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void tokenMismatchTest() {
|
||||||
|
var exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/"));
|
||||||
|
when(tokenRepository.getTokenForSeries(eq("fake-series")))
|
||||||
|
.thenReturn(Mono.just(
|
||||||
|
new PersistentRememberMeToken("test", "fake-series", "other-token-value",
|
||||||
|
new Date()))
|
||||||
|
);
|
||||||
|
when(tokenRepository.removeUserTokens(eq("test"))).thenReturn(Mono.empty());
|
||||||
|
assertThatThrownBy(() -> persistentTokenBasedRememberMeServices.processAutoLoginCookie(
|
||||||
|
new String[] {"fake-series", "token-value"},
|
||||||
|
exchange).block())
|
||||||
|
.isInstanceOf(CookieTheftException.class)
|
||||||
|
.hasMessage(
|
||||||
|
"Invalid remember-me token (Series/token) mismatch. Implies previous cookie "
|
||||||
|
+ "theft attack.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void rememberMeLoginExpiredTest() {
|
||||||
|
var exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/"));
|
||||||
|
when(tokenRepository.getTokenForSeries(eq("fake-series")))
|
||||||
|
.thenReturn(Mono.just(
|
||||||
|
new PersistentRememberMeToken("test", "fake-series", "token-value",
|
||||||
|
new Date(Instant.now().minusSeconds(10).toEpochMilli())))
|
||||||
|
);
|
||||||
|
when(rememberMeCookieResolver.getCookieMaxAge()).thenReturn(Duration.ofSeconds(5));
|
||||||
|
assertThatThrownBy(() -> persistentTokenBasedRememberMeServices.processAutoLoginCookie(
|
||||||
|
new String[] {"fake-series", "token-value"},
|
||||||
|
exchange).block())
|
||||||
|
.isInstanceOf(RememberMeAuthenticationException.class)
|
||||||
|
.hasMessage("Remember-me login has expired");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void successfulTest() {
|
||||||
|
var exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/"));
|
||||||
|
when(tokenRepository.getTokenForSeries(eq("fake-series")))
|
||||||
|
.thenReturn(Mono.just(
|
||||||
|
new PersistentRememberMeToken("test", "fake-series", "token-value",
|
||||||
|
new Date()))
|
||||||
|
);
|
||||||
|
when(rememberMeCookieResolver.getCookieMaxAge()).thenReturn(Duration.ofSeconds(5));
|
||||||
|
|
||||||
|
var generatedTokenValue = new AtomicReference<String>();
|
||||||
|
when(tokenRepository.updateToken(eq("fake-series"), any(), any()))
|
||||||
|
.thenAnswer(invocation -> {
|
||||||
|
var tokenValue = (String) invocation.getArgument(1);
|
||||||
|
generatedTokenValue.compareAndSet(null, tokenValue);
|
||||||
|
return Mono.empty();
|
||||||
|
});
|
||||||
|
|
||||||
|
when(userDetailsService.findByUsername(eq("test"))).thenReturn(Mono.empty());
|
||||||
|
|
||||||
|
persistentTokenBasedRememberMeServices.processAutoLoginCookie(
|
||||||
|
new String[] {"fake-series", "token-value"}, exchange)
|
||||||
|
.block();
|
||||||
|
|
||||||
|
verify(rememberMeCookieResolver).setRememberMeCookie(eq(exchange),
|
||||||
|
eq(persistentTokenBasedRememberMeServices.encodeCookie(
|
||||||
|
new String[] {"fake-series", generatedTokenValue.get()})));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void onLoginSuccessTest() {
|
||||||
|
var exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/"));
|
||||||
|
var authentication = new UsernamePasswordAuthenticationToken("test", "test");
|
||||||
|
|
||||||
|
when(tokenRepository.createNewToken(any())).thenReturn(Mono.empty());
|
||||||
|
persistentTokenBasedRememberMeServices.onLoginSuccess(exchange, authentication).block();
|
||||||
|
|
||||||
|
verify(rememberMeCookieResolver).setRememberMeCookie(eq(exchange), any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void onLogoutTest() {
|
||||||
|
var authentication = new UsernamePasswordAuthenticationToken("test", "test");
|
||||||
|
|
||||||
|
when(tokenRepository.removeUserTokens(eq("test"))).thenReturn(Mono.empty());
|
||||||
|
|
||||||
|
var filterExchange = mock(WebFilterExchange.class);
|
||||||
|
persistentTokenBasedRememberMeServices.onLogout(filterExchange, authentication).block();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
package run.halo.app.security.authentication.rememberme;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.time.Instant;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.mockito.InjectMocks;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test for {@link RememberTokenCleaner}.
|
||||||
|
*
|
||||||
|
* @author guqing
|
||||||
|
* @since 2.17.0
|
||||||
|
*/
|
||||||
|
@ExtendWith(MockitoExtension.class)
|
||||||
|
class RememberTokenCleanerTest {
|
||||||
|
@InjectMocks
|
||||||
|
private RememberTokenCleaner rememberTokenCleaner;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void test() {
|
||||||
|
var spyRememberTokenCleaner = spy(rememberTokenCleaner);
|
||||||
|
Mockito.doReturn(Duration.ofSeconds(30)).when(spyRememberTokenCleaner).getTokenValidity();
|
||||||
|
var expiredTime = spyRememberTokenCleaner.getExpirationThreshold();
|
||||||
|
|
||||||
|
var creationTime = Instant.now().minus(Duration.ofSeconds(31));
|
||||||
|
// creationTime < expirationThreshold means it has expired
|
||||||
|
assertThat(creationTime).isBefore(expiredTime);
|
||||||
|
|
||||||
|
// not expired
|
||||||
|
creationTime = Instant.now().minus(Duration.ofSeconds(29));
|
||||||
|
assertThat(creationTime).isAfter(expiredTime);
|
||||||
|
}
|
||||||
|
}
|
|
@ -46,6 +46,7 @@ api/post-v1alpha1-public-api.ts
|
||||||
api/post-v1alpha1-uc-api.ts
|
api/post-v1alpha1-uc-api.ts
|
||||||
api/reason-type-v1alpha1-api.ts
|
api/reason-type-v1alpha1-api.ts
|
||||||
api/reason-v1alpha1-api.ts
|
api/reason-v1alpha1-api.ts
|
||||||
|
api/remember-me-token-v1alpha1-api.ts
|
||||||
api/reply-v1alpha1-api.ts
|
api/reply-v1alpha1-api.ts
|
||||||
api/reply-v1alpha1-console-api.ts
|
api/reply-v1alpha1-console-api.ts
|
||||||
api/reverse-proxy-v1alpha1-api.ts
|
api/reverse-proxy-v1alpha1-api.ts
|
||||||
|
@ -241,6 +242,9 @@ models/reason-type.ts
|
||||||
models/reason.ts
|
models/reason.ts
|
||||||
models/ref.ts
|
models/ref.ts
|
||||||
models/register-verify-email-request.ts
|
models/register-verify-email-request.ts
|
||||||
|
models/remember-me-token-list.ts
|
||||||
|
models/remember-me-token-spec.ts
|
||||||
|
models/remember-me-token.ts
|
||||||
models/remove-operation.ts
|
models/remove-operation.ts
|
||||||
models/replace-operation.ts
|
models/replace-operation.ts
|
||||||
models/reply-list.ts
|
models/reply-list.ts
|
||||||
|
|
|
@ -59,6 +59,7 @@ export * from './api/post-v1alpha1-public-api';
|
||||||
export * from './api/post-v1alpha1-uc-api';
|
export * from './api/post-v1alpha1-uc-api';
|
||||||
export * from './api/reason-type-v1alpha1-api';
|
export * from './api/reason-type-v1alpha1-api';
|
||||||
export * from './api/reason-v1alpha1-api';
|
export * from './api/reason-v1alpha1-api';
|
||||||
|
export * from './api/remember-me-token-v1alpha1-api';
|
||||||
export * from './api/reply-v1alpha1-api';
|
export * from './api/reply-v1alpha1-api';
|
||||||
export * from './api/reply-v1alpha1-console-api';
|
export * from './api/reply-v1alpha1-console-api';
|
||||||
export * from './api/reverse-proxy-v1alpha1-api';
|
export * from './api/reverse-proxy-v1alpha1-api';
|
||||||
|
|
|
@ -0,0 +1,665 @@
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
/**
|
||||||
|
* Halo
|
||||||
|
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||||
|
*
|
||||||
|
* The version of the OpenAPI document: 2.17.0-SNAPSHOT
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||||
|
* https://openapi-generator.tech
|
||||||
|
* Do not edit the class manually.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
import type { Configuration } from '../configuration';
|
||||||
|
import type { AxiosPromise, AxiosInstance, RawAxiosRequestConfig } from 'axios';
|
||||||
|
import globalAxios from 'axios';
|
||||||
|
// Some imports not used depending on template conditions
|
||||||
|
// @ts-ignore
|
||||||
|
import { DUMMY_BASE_URL, assertParamExists, setApiKeyToObject, setBasicAuthToObject, setBearerAuthToObject, setOAuthToObject, setSearchParams, serializeDataIfNeeded, toPathString, createRequestFunction } from '../common';
|
||||||
|
// @ts-ignore
|
||||||
|
import { BASE_PATH, COLLECTION_FORMATS, RequestArgs, BaseAPI, RequiredError, operationServerMap } from '../base';
|
||||||
|
// @ts-ignore
|
||||||
|
import { JsonPatchInner } from '../models';
|
||||||
|
// @ts-ignore
|
||||||
|
import { RememberMeToken } from '../models';
|
||||||
|
// @ts-ignore
|
||||||
|
import { RememberMeTokenList } from '../models';
|
||||||
|
/**
|
||||||
|
* RememberMeTokenV1alpha1Api - axios parameter creator
|
||||||
|
* @export
|
||||||
|
*/
|
||||||
|
export const RememberMeTokenV1alpha1ApiAxiosParamCreator = function (configuration?: Configuration) {
|
||||||
|
return {
|
||||||
|
/**
|
||||||
|
* Create RememberMeToken
|
||||||
|
* @param {RememberMeToken} [rememberMeToken] Fresh remembermetoken
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
createRememberMeToken: async (rememberMeToken?: RememberMeToken, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||||
|
const localVarPath = `/apis/security.halo.run/v1alpha1/remembermetokens`;
|
||||||
|
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||||
|
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
||||||
|
let baseOptions;
|
||||||
|
if (configuration) {
|
||||||
|
baseOptions = configuration.baseOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options};
|
||||||
|
const localVarHeaderParameter = {} as any;
|
||||||
|
const localVarQueryParameter = {} as any;
|
||||||
|
|
||||||
|
// authentication basicAuth required
|
||||||
|
// http basic authentication required
|
||||||
|
setBasicAuthToObject(localVarRequestOptions, configuration)
|
||||||
|
|
||||||
|
// authentication bearerAuth required
|
||||||
|
// http bearer authentication required
|
||||||
|
await setBearerAuthToObject(localVarHeaderParameter, configuration)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
localVarHeaderParameter['Content-Type'] = 'application/json';
|
||||||
|
|
||||||
|
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||||
|
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||||
|
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||||
|
localVarRequestOptions.data = serializeDataIfNeeded(rememberMeToken, localVarRequestOptions, configuration)
|
||||||
|
|
||||||
|
return {
|
||||||
|
url: toPathString(localVarUrlObj),
|
||||||
|
options: localVarRequestOptions,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Delete RememberMeToken
|
||||||
|
* @param {string} name Name of remembermetoken
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
deleteRememberMeToken: async (name: string, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||||
|
// verify required parameter 'name' is not null or undefined
|
||||||
|
assertParamExists('deleteRememberMeToken', 'name', name)
|
||||||
|
const localVarPath = `/apis/security.halo.run/v1alpha1/remembermetokens/{name}`
|
||||||
|
.replace(`{${"name"}}`, encodeURIComponent(String(name)));
|
||||||
|
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||||
|
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
||||||
|
let baseOptions;
|
||||||
|
if (configuration) {
|
||||||
|
baseOptions = configuration.baseOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
const localVarRequestOptions = { method: 'DELETE', ...baseOptions, ...options};
|
||||||
|
const localVarHeaderParameter = {} as any;
|
||||||
|
const localVarQueryParameter = {} as any;
|
||||||
|
|
||||||
|
// authentication basicAuth required
|
||||||
|
// http basic authentication required
|
||||||
|
setBasicAuthToObject(localVarRequestOptions, configuration)
|
||||||
|
|
||||||
|
// authentication bearerAuth required
|
||||||
|
// http bearer authentication required
|
||||||
|
await setBearerAuthToObject(localVarHeaderParameter, configuration)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||||
|
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||||
|
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||||
|
|
||||||
|
return {
|
||||||
|
url: toPathString(localVarUrlObj),
|
||||||
|
options: localVarRequestOptions,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Get RememberMeToken
|
||||||
|
* @param {string} name Name of remembermetoken
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
getRememberMeToken: async (name: string, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||||
|
// verify required parameter 'name' is not null or undefined
|
||||||
|
assertParamExists('getRememberMeToken', 'name', name)
|
||||||
|
const localVarPath = `/apis/security.halo.run/v1alpha1/remembermetokens/{name}`
|
||||||
|
.replace(`{${"name"}}`, encodeURIComponent(String(name)));
|
||||||
|
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||||
|
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
||||||
|
let baseOptions;
|
||||||
|
if (configuration) {
|
||||||
|
baseOptions = configuration.baseOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options};
|
||||||
|
const localVarHeaderParameter = {} as any;
|
||||||
|
const localVarQueryParameter = {} as any;
|
||||||
|
|
||||||
|
// authentication basicAuth required
|
||||||
|
// http basic authentication required
|
||||||
|
setBasicAuthToObject(localVarRequestOptions, configuration)
|
||||||
|
|
||||||
|
// authentication bearerAuth required
|
||||||
|
// http bearer authentication required
|
||||||
|
await setBearerAuthToObject(localVarHeaderParameter, configuration)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||||
|
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||||
|
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||||
|
|
||||||
|
return {
|
||||||
|
url: toPathString(localVarUrlObj),
|
||||||
|
options: localVarRequestOptions,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* List RememberMeToken
|
||||||
|
* @param {number} [page] Page number. Default is 0.
|
||||||
|
* @param {number} [size] Size number. Default is 0.
|
||||||
|
* @param {Array<string>} [labelSelector] Label selector. e.g.: hidden!=true
|
||||||
|
* @param {Array<string>} [fieldSelector] Field selector. e.g.: metadata.name==halo
|
||||||
|
* @param {Array<string>} [sort] Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported.
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
listRememberMeToken: async (page?: number, size?: number, labelSelector?: Array<string>, fieldSelector?: Array<string>, sort?: Array<string>, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||||
|
const localVarPath = `/apis/security.halo.run/v1alpha1/remembermetokens`;
|
||||||
|
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||||
|
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
||||||
|
let baseOptions;
|
||||||
|
if (configuration) {
|
||||||
|
baseOptions = configuration.baseOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options};
|
||||||
|
const localVarHeaderParameter = {} as any;
|
||||||
|
const localVarQueryParameter = {} as any;
|
||||||
|
|
||||||
|
// authentication basicAuth required
|
||||||
|
// http basic authentication required
|
||||||
|
setBasicAuthToObject(localVarRequestOptions, configuration)
|
||||||
|
|
||||||
|
// authentication bearerAuth required
|
||||||
|
// http bearer authentication required
|
||||||
|
await setBearerAuthToObject(localVarHeaderParameter, configuration)
|
||||||
|
|
||||||
|
if (page !== undefined) {
|
||||||
|
localVarQueryParameter['page'] = page;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size !== undefined) {
|
||||||
|
localVarQueryParameter['size'] = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (labelSelector) {
|
||||||
|
localVarQueryParameter['labelSelector'] = labelSelector;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fieldSelector) {
|
||||||
|
localVarQueryParameter['fieldSelector'] = fieldSelector;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sort) {
|
||||||
|
localVarQueryParameter['sort'] = sort;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||||
|
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||||
|
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||||
|
|
||||||
|
return {
|
||||||
|
url: toPathString(localVarUrlObj),
|
||||||
|
options: localVarRequestOptions,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Patch RememberMeToken
|
||||||
|
* @param {string} name Name of remembermetoken
|
||||||
|
* @param {Array<JsonPatchInner>} [jsonPatchInner]
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
patchRememberMeToken: async (name: string, jsonPatchInner?: Array<JsonPatchInner>, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||||
|
// verify required parameter 'name' is not null or undefined
|
||||||
|
assertParamExists('patchRememberMeToken', 'name', name)
|
||||||
|
const localVarPath = `/apis/security.halo.run/v1alpha1/remembermetokens/{name}`
|
||||||
|
.replace(`{${"name"}}`, encodeURIComponent(String(name)));
|
||||||
|
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||||
|
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
||||||
|
let baseOptions;
|
||||||
|
if (configuration) {
|
||||||
|
baseOptions = configuration.baseOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
const localVarRequestOptions = { method: 'PATCH', ...baseOptions, ...options};
|
||||||
|
const localVarHeaderParameter = {} as any;
|
||||||
|
const localVarQueryParameter = {} as any;
|
||||||
|
|
||||||
|
// authentication basicAuth required
|
||||||
|
// http basic authentication required
|
||||||
|
setBasicAuthToObject(localVarRequestOptions, configuration)
|
||||||
|
|
||||||
|
// authentication bearerAuth required
|
||||||
|
// http bearer authentication required
|
||||||
|
await setBearerAuthToObject(localVarHeaderParameter, configuration)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
localVarHeaderParameter['Content-Type'] = 'application/json-patch+json';
|
||||||
|
|
||||||
|
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||||
|
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||||
|
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||||
|
localVarRequestOptions.data = serializeDataIfNeeded(jsonPatchInner, localVarRequestOptions, configuration)
|
||||||
|
|
||||||
|
return {
|
||||||
|
url: toPathString(localVarUrlObj),
|
||||||
|
options: localVarRequestOptions,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Update RememberMeToken
|
||||||
|
* @param {string} name Name of remembermetoken
|
||||||
|
* @param {RememberMeToken} [rememberMeToken] Updated remembermetoken
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
updateRememberMeToken: async (name: string, rememberMeToken?: RememberMeToken, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||||
|
// verify required parameter 'name' is not null or undefined
|
||||||
|
assertParamExists('updateRememberMeToken', 'name', name)
|
||||||
|
const localVarPath = `/apis/security.halo.run/v1alpha1/remembermetokens/{name}`
|
||||||
|
.replace(`{${"name"}}`, encodeURIComponent(String(name)));
|
||||||
|
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||||
|
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
||||||
|
let baseOptions;
|
||||||
|
if (configuration) {
|
||||||
|
baseOptions = configuration.baseOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
const localVarRequestOptions = { method: 'PUT', ...baseOptions, ...options};
|
||||||
|
const localVarHeaderParameter = {} as any;
|
||||||
|
const localVarQueryParameter = {} as any;
|
||||||
|
|
||||||
|
// authentication basicAuth required
|
||||||
|
// http basic authentication required
|
||||||
|
setBasicAuthToObject(localVarRequestOptions, configuration)
|
||||||
|
|
||||||
|
// authentication bearerAuth required
|
||||||
|
// http bearer authentication required
|
||||||
|
await setBearerAuthToObject(localVarHeaderParameter, configuration)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
localVarHeaderParameter['Content-Type'] = 'application/json';
|
||||||
|
|
||||||
|
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||||
|
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||||
|
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||||
|
localVarRequestOptions.data = serializeDataIfNeeded(rememberMeToken, localVarRequestOptions, configuration)
|
||||||
|
|
||||||
|
return {
|
||||||
|
url: toPathString(localVarUrlObj),
|
||||||
|
options: localVarRequestOptions,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RememberMeTokenV1alpha1Api - functional programming interface
|
||||||
|
* @export
|
||||||
|
*/
|
||||||
|
export const RememberMeTokenV1alpha1ApiFp = function(configuration?: Configuration) {
|
||||||
|
const localVarAxiosParamCreator = RememberMeTokenV1alpha1ApiAxiosParamCreator(configuration)
|
||||||
|
return {
|
||||||
|
/**
|
||||||
|
* Create RememberMeToken
|
||||||
|
* @param {RememberMeToken} [rememberMeToken] Fresh remembermetoken
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
async createRememberMeToken(rememberMeToken?: RememberMeToken, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<RememberMeToken>> {
|
||||||
|
const localVarAxiosArgs = await localVarAxiosParamCreator.createRememberMeToken(rememberMeToken, options);
|
||||||
|
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
|
||||||
|
const localVarOperationServerBasePath = operationServerMap['RememberMeTokenV1alpha1Api.createRememberMeToken']?.[localVarOperationServerIndex]?.url;
|
||||||
|
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Delete RememberMeToken
|
||||||
|
* @param {string} name Name of remembermetoken
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
async deleteRememberMeToken(name: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<void>> {
|
||||||
|
const localVarAxiosArgs = await localVarAxiosParamCreator.deleteRememberMeToken(name, options);
|
||||||
|
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
|
||||||
|
const localVarOperationServerBasePath = operationServerMap['RememberMeTokenV1alpha1Api.deleteRememberMeToken']?.[localVarOperationServerIndex]?.url;
|
||||||
|
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Get RememberMeToken
|
||||||
|
* @param {string} name Name of remembermetoken
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
async getRememberMeToken(name: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<RememberMeToken>> {
|
||||||
|
const localVarAxiosArgs = await localVarAxiosParamCreator.getRememberMeToken(name, options);
|
||||||
|
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
|
||||||
|
const localVarOperationServerBasePath = operationServerMap['RememberMeTokenV1alpha1Api.getRememberMeToken']?.[localVarOperationServerIndex]?.url;
|
||||||
|
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* List RememberMeToken
|
||||||
|
* @param {number} [page] Page number. Default is 0.
|
||||||
|
* @param {number} [size] Size number. Default is 0.
|
||||||
|
* @param {Array<string>} [labelSelector] Label selector. e.g.: hidden!=true
|
||||||
|
* @param {Array<string>} [fieldSelector] Field selector. e.g.: metadata.name==halo
|
||||||
|
* @param {Array<string>} [sort] Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported.
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
async listRememberMeToken(page?: number, size?: number, labelSelector?: Array<string>, fieldSelector?: Array<string>, sort?: Array<string>, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<RememberMeTokenList>> {
|
||||||
|
const localVarAxiosArgs = await localVarAxiosParamCreator.listRememberMeToken(page, size, labelSelector, fieldSelector, sort, options);
|
||||||
|
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
|
||||||
|
const localVarOperationServerBasePath = operationServerMap['RememberMeTokenV1alpha1Api.listRememberMeToken']?.[localVarOperationServerIndex]?.url;
|
||||||
|
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Patch RememberMeToken
|
||||||
|
* @param {string} name Name of remembermetoken
|
||||||
|
* @param {Array<JsonPatchInner>} [jsonPatchInner]
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
async patchRememberMeToken(name: string, jsonPatchInner?: Array<JsonPatchInner>, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<RememberMeToken>> {
|
||||||
|
const localVarAxiosArgs = await localVarAxiosParamCreator.patchRememberMeToken(name, jsonPatchInner, options);
|
||||||
|
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
|
||||||
|
const localVarOperationServerBasePath = operationServerMap['RememberMeTokenV1alpha1Api.patchRememberMeToken']?.[localVarOperationServerIndex]?.url;
|
||||||
|
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Update RememberMeToken
|
||||||
|
* @param {string} name Name of remembermetoken
|
||||||
|
* @param {RememberMeToken} [rememberMeToken] Updated remembermetoken
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
async updateRememberMeToken(name: string, rememberMeToken?: RememberMeToken, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<RememberMeToken>> {
|
||||||
|
const localVarAxiosArgs = await localVarAxiosParamCreator.updateRememberMeToken(name, rememberMeToken, options);
|
||||||
|
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
|
||||||
|
const localVarOperationServerBasePath = operationServerMap['RememberMeTokenV1alpha1Api.updateRememberMeToken']?.[localVarOperationServerIndex]?.url;
|
||||||
|
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RememberMeTokenV1alpha1Api - factory interface
|
||||||
|
* @export
|
||||||
|
*/
|
||||||
|
export const RememberMeTokenV1alpha1ApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) {
|
||||||
|
const localVarFp = RememberMeTokenV1alpha1ApiFp(configuration)
|
||||||
|
return {
|
||||||
|
/**
|
||||||
|
* Create RememberMeToken
|
||||||
|
* @param {RememberMeTokenV1alpha1ApiCreateRememberMeTokenRequest} requestParameters Request parameters.
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
createRememberMeToken(requestParameters: RememberMeTokenV1alpha1ApiCreateRememberMeTokenRequest = {}, options?: RawAxiosRequestConfig): AxiosPromise<RememberMeToken> {
|
||||||
|
return localVarFp.createRememberMeToken(requestParameters.rememberMeToken, options).then((request) => request(axios, basePath));
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Delete RememberMeToken
|
||||||
|
* @param {RememberMeTokenV1alpha1ApiDeleteRememberMeTokenRequest} requestParameters Request parameters.
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
deleteRememberMeToken(requestParameters: RememberMeTokenV1alpha1ApiDeleteRememberMeTokenRequest, options?: RawAxiosRequestConfig): AxiosPromise<void> {
|
||||||
|
return localVarFp.deleteRememberMeToken(requestParameters.name, options).then((request) => request(axios, basePath));
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Get RememberMeToken
|
||||||
|
* @param {RememberMeTokenV1alpha1ApiGetRememberMeTokenRequest} requestParameters Request parameters.
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
getRememberMeToken(requestParameters: RememberMeTokenV1alpha1ApiGetRememberMeTokenRequest, options?: RawAxiosRequestConfig): AxiosPromise<RememberMeToken> {
|
||||||
|
return localVarFp.getRememberMeToken(requestParameters.name, options).then((request) => request(axios, basePath));
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* List RememberMeToken
|
||||||
|
* @param {RememberMeTokenV1alpha1ApiListRememberMeTokenRequest} requestParameters Request parameters.
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
listRememberMeToken(requestParameters: RememberMeTokenV1alpha1ApiListRememberMeTokenRequest = {}, options?: RawAxiosRequestConfig): AxiosPromise<RememberMeTokenList> {
|
||||||
|
return localVarFp.listRememberMeToken(requestParameters.page, requestParameters.size, requestParameters.labelSelector, requestParameters.fieldSelector, requestParameters.sort, options).then((request) => request(axios, basePath));
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Patch RememberMeToken
|
||||||
|
* @param {RememberMeTokenV1alpha1ApiPatchRememberMeTokenRequest} requestParameters Request parameters.
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
patchRememberMeToken(requestParameters: RememberMeTokenV1alpha1ApiPatchRememberMeTokenRequest, options?: RawAxiosRequestConfig): AxiosPromise<RememberMeToken> {
|
||||||
|
return localVarFp.patchRememberMeToken(requestParameters.name, requestParameters.jsonPatchInner, options).then((request) => request(axios, basePath));
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Update RememberMeToken
|
||||||
|
* @param {RememberMeTokenV1alpha1ApiUpdateRememberMeTokenRequest} requestParameters Request parameters.
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
updateRememberMeToken(requestParameters: RememberMeTokenV1alpha1ApiUpdateRememberMeTokenRequest, options?: RawAxiosRequestConfig): AxiosPromise<RememberMeToken> {
|
||||||
|
return localVarFp.updateRememberMeToken(requestParameters.name, requestParameters.rememberMeToken, options).then((request) => request(axios, basePath));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request parameters for createRememberMeToken operation in RememberMeTokenV1alpha1Api.
|
||||||
|
* @export
|
||||||
|
* @interface RememberMeTokenV1alpha1ApiCreateRememberMeTokenRequest
|
||||||
|
*/
|
||||||
|
export interface RememberMeTokenV1alpha1ApiCreateRememberMeTokenRequest {
|
||||||
|
/**
|
||||||
|
* Fresh remembermetoken
|
||||||
|
* @type {RememberMeToken}
|
||||||
|
* @memberof RememberMeTokenV1alpha1ApiCreateRememberMeToken
|
||||||
|
*/
|
||||||
|
readonly rememberMeToken?: RememberMeToken
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request parameters for deleteRememberMeToken operation in RememberMeTokenV1alpha1Api.
|
||||||
|
* @export
|
||||||
|
* @interface RememberMeTokenV1alpha1ApiDeleteRememberMeTokenRequest
|
||||||
|
*/
|
||||||
|
export interface RememberMeTokenV1alpha1ApiDeleteRememberMeTokenRequest {
|
||||||
|
/**
|
||||||
|
* Name of remembermetoken
|
||||||
|
* @type {string}
|
||||||
|
* @memberof RememberMeTokenV1alpha1ApiDeleteRememberMeToken
|
||||||
|
*/
|
||||||
|
readonly name: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request parameters for getRememberMeToken operation in RememberMeTokenV1alpha1Api.
|
||||||
|
* @export
|
||||||
|
* @interface RememberMeTokenV1alpha1ApiGetRememberMeTokenRequest
|
||||||
|
*/
|
||||||
|
export interface RememberMeTokenV1alpha1ApiGetRememberMeTokenRequest {
|
||||||
|
/**
|
||||||
|
* Name of remembermetoken
|
||||||
|
* @type {string}
|
||||||
|
* @memberof RememberMeTokenV1alpha1ApiGetRememberMeToken
|
||||||
|
*/
|
||||||
|
readonly name: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request parameters for listRememberMeToken operation in RememberMeTokenV1alpha1Api.
|
||||||
|
* @export
|
||||||
|
* @interface RememberMeTokenV1alpha1ApiListRememberMeTokenRequest
|
||||||
|
*/
|
||||||
|
export interface RememberMeTokenV1alpha1ApiListRememberMeTokenRequest {
|
||||||
|
/**
|
||||||
|
* Page number. Default is 0.
|
||||||
|
* @type {number}
|
||||||
|
* @memberof RememberMeTokenV1alpha1ApiListRememberMeToken
|
||||||
|
*/
|
||||||
|
readonly page?: number
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Size number. Default is 0.
|
||||||
|
* @type {number}
|
||||||
|
* @memberof RememberMeTokenV1alpha1ApiListRememberMeToken
|
||||||
|
*/
|
||||||
|
readonly size?: number
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Label selector. e.g.: hidden!=true
|
||||||
|
* @type {Array<string>}
|
||||||
|
* @memberof RememberMeTokenV1alpha1ApiListRememberMeToken
|
||||||
|
*/
|
||||||
|
readonly labelSelector?: Array<string>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Field selector. e.g.: metadata.name==halo
|
||||||
|
* @type {Array<string>}
|
||||||
|
* @memberof RememberMeTokenV1alpha1ApiListRememberMeToken
|
||||||
|
*/
|
||||||
|
readonly fieldSelector?: Array<string>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported.
|
||||||
|
* @type {Array<string>}
|
||||||
|
* @memberof RememberMeTokenV1alpha1ApiListRememberMeToken
|
||||||
|
*/
|
||||||
|
readonly sort?: Array<string>
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request parameters for patchRememberMeToken operation in RememberMeTokenV1alpha1Api.
|
||||||
|
* @export
|
||||||
|
* @interface RememberMeTokenV1alpha1ApiPatchRememberMeTokenRequest
|
||||||
|
*/
|
||||||
|
export interface RememberMeTokenV1alpha1ApiPatchRememberMeTokenRequest {
|
||||||
|
/**
|
||||||
|
* Name of remembermetoken
|
||||||
|
* @type {string}
|
||||||
|
* @memberof RememberMeTokenV1alpha1ApiPatchRememberMeToken
|
||||||
|
*/
|
||||||
|
readonly name: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {Array<JsonPatchInner>}
|
||||||
|
* @memberof RememberMeTokenV1alpha1ApiPatchRememberMeToken
|
||||||
|
*/
|
||||||
|
readonly jsonPatchInner?: Array<JsonPatchInner>
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request parameters for updateRememberMeToken operation in RememberMeTokenV1alpha1Api.
|
||||||
|
* @export
|
||||||
|
* @interface RememberMeTokenV1alpha1ApiUpdateRememberMeTokenRequest
|
||||||
|
*/
|
||||||
|
export interface RememberMeTokenV1alpha1ApiUpdateRememberMeTokenRequest {
|
||||||
|
/**
|
||||||
|
* Name of remembermetoken
|
||||||
|
* @type {string}
|
||||||
|
* @memberof RememberMeTokenV1alpha1ApiUpdateRememberMeToken
|
||||||
|
*/
|
||||||
|
readonly name: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updated remembermetoken
|
||||||
|
* @type {RememberMeToken}
|
||||||
|
* @memberof RememberMeTokenV1alpha1ApiUpdateRememberMeToken
|
||||||
|
*/
|
||||||
|
readonly rememberMeToken?: RememberMeToken
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RememberMeTokenV1alpha1Api - object-oriented interface
|
||||||
|
* @export
|
||||||
|
* @class RememberMeTokenV1alpha1Api
|
||||||
|
* @extends {BaseAPI}
|
||||||
|
*/
|
||||||
|
export class RememberMeTokenV1alpha1Api extends BaseAPI {
|
||||||
|
/**
|
||||||
|
* Create RememberMeToken
|
||||||
|
* @param {RememberMeTokenV1alpha1ApiCreateRememberMeTokenRequest} requestParameters Request parameters.
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
* @memberof RememberMeTokenV1alpha1Api
|
||||||
|
*/
|
||||||
|
public createRememberMeToken(requestParameters: RememberMeTokenV1alpha1ApiCreateRememberMeTokenRequest = {}, options?: RawAxiosRequestConfig) {
|
||||||
|
return RememberMeTokenV1alpha1ApiFp(this.configuration).createRememberMeToken(requestParameters.rememberMeToken, options).then((request) => request(this.axios, this.basePath));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete RememberMeToken
|
||||||
|
* @param {RememberMeTokenV1alpha1ApiDeleteRememberMeTokenRequest} requestParameters Request parameters.
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
* @memberof RememberMeTokenV1alpha1Api
|
||||||
|
*/
|
||||||
|
public deleteRememberMeToken(requestParameters: RememberMeTokenV1alpha1ApiDeleteRememberMeTokenRequest, options?: RawAxiosRequestConfig) {
|
||||||
|
return RememberMeTokenV1alpha1ApiFp(this.configuration).deleteRememberMeToken(requestParameters.name, options).then((request) => request(this.axios, this.basePath));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get RememberMeToken
|
||||||
|
* @param {RememberMeTokenV1alpha1ApiGetRememberMeTokenRequest} requestParameters Request parameters.
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
* @memberof RememberMeTokenV1alpha1Api
|
||||||
|
*/
|
||||||
|
public getRememberMeToken(requestParameters: RememberMeTokenV1alpha1ApiGetRememberMeTokenRequest, options?: RawAxiosRequestConfig) {
|
||||||
|
return RememberMeTokenV1alpha1ApiFp(this.configuration).getRememberMeToken(requestParameters.name, options).then((request) => request(this.axios, this.basePath));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List RememberMeToken
|
||||||
|
* @param {RememberMeTokenV1alpha1ApiListRememberMeTokenRequest} requestParameters Request parameters.
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
* @memberof RememberMeTokenV1alpha1Api
|
||||||
|
*/
|
||||||
|
public listRememberMeToken(requestParameters: RememberMeTokenV1alpha1ApiListRememberMeTokenRequest = {}, options?: RawAxiosRequestConfig) {
|
||||||
|
return RememberMeTokenV1alpha1ApiFp(this.configuration).listRememberMeToken(requestParameters.page, requestParameters.size, requestParameters.labelSelector, requestParameters.fieldSelector, requestParameters.sort, options).then((request) => request(this.axios, this.basePath));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Patch RememberMeToken
|
||||||
|
* @param {RememberMeTokenV1alpha1ApiPatchRememberMeTokenRequest} requestParameters Request parameters.
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
* @memberof RememberMeTokenV1alpha1Api
|
||||||
|
*/
|
||||||
|
public patchRememberMeToken(requestParameters: RememberMeTokenV1alpha1ApiPatchRememberMeTokenRequest, options?: RawAxiosRequestConfig) {
|
||||||
|
return RememberMeTokenV1alpha1ApiFp(this.configuration).patchRememberMeToken(requestParameters.name, requestParameters.jsonPatchInner, options).then((request) => request(this.axios, this.basePath));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update RememberMeToken
|
||||||
|
* @param {RememberMeTokenV1alpha1ApiUpdateRememberMeTokenRequest} requestParameters Request parameters.
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
* @memberof RememberMeTokenV1alpha1Api
|
||||||
|
*/
|
||||||
|
public updateRememberMeToken(requestParameters: RememberMeTokenV1alpha1ApiUpdateRememberMeTokenRequest, options?: RawAxiosRequestConfig) {
|
||||||
|
return RememberMeTokenV1alpha1ApiFp(this.configuration).updateRememberMeToken(requestParameters.name, requestParameters.rememberMeToken, options).then((request) => request(this.axios, this.basePath));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -161,6 +161,9 @@ export * from './reason-type-notifier-request';
|
||||||
export * from './reason-type-spec';
|
export * from './reason-type-spec';
|
||||||
export * from './ref';
|
export * from './ref';
|
||||||
export * from './register-verify-email-request';
|
export * from './register-verify-email-request';
|
||||||
|
export * from './remember-me-token';
|
||||||
|
export * from './remember-me-token-list';
|
||||||
|
export * from './remember-me-token-spec';
|
||||||
export * from './remove-operation';
|
export * from './remove-operation';
|
||||||
export * from './replace-operation';
|
export * from './replace-operation';
|
||||||
export * from './reply';
|
export * from './reply';
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
/**
|
||||||
|
* Halo
|
||||||
|
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||||
|
*
|
||||||
|
* The version of the OpenAPI document: 2.17.0-SNAPSHOT
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||||
|
* https://openapi-generator.tech
|
||||||
|
* Do not edit the class manually.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
// May contain unused imports in some cases
|
||||||
|
// @ts-ignore
|
||||||
|
import { RememberMeToken } from './remember-me-token';
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @interface RememberMeTokenList
|
||||||
|
*/
|
||||||
|
export interface RememberMeTokenList {
|
||||||
|
/**
|
||||||
|
* Indicates whether current page is the first page.
|
||||||
|
* @type {boolean}
|
||||||
|
* @memberof RememberMeTokenList
|
||||||
|
*/
|
||||||
|
'first': boolean;
|
||||||
|
/**
|
||||||
|
* Indicates whether current page has previous page.
|
||||||
|
* @type {boolean}
|
||||||
|
* @memberof RememberMeTokenList
|
||||||
|
*/
|
||||||
|
'hasNext': boolean;
|
||||||
|
/**
|
||||||
|
* Indicates whether current page has previous page.
|
||||||
|
* @type {boolean}
|
||||||
|
* @memberof RememberMeTokenList
|
||||||
|
*/
|
||||||
|
'hasPrevious': boolean;
|
||||||
|
/**
|
||||||
|
* A chunk of items.
|
||||||
|
* @type {Array<RememberMeToken>}
|
||||||
|
* @memberof RememberMeTokenList
|
||||||
|
*/
|
||||||
|
'items': Array<RememberMeToken>;
|
||||||
|
/**
|
||||||
|
* Indicates whether current page is the last page.
|
||||||
|
* @type {boolean}
|
||||||
|
* @memberof RememberMeTokenList
|
||||||
|
*/
|
||||||
|
'last': boolean;
|
||||||
|
/**
|
||||||
|
* Page number, starts from 1. If not set or equal to 0, it means no pagination.
|
||||||
|
* @type {number}
|
||||||
|
* @memberof RememberMeTokenList
|
||||||
|
*/
|
||||||
|
'page': number;
|
||||||
|
/**
|
||||||
|
* Size of each page. If not set or equal to 0, it means no pagination.
|
||||||
|
* @type {number}
|
||||||
|
* @memberof RememberMeTokenList
|
||||||
|
*/
|
||||||
|
'size': number;
|
||||||
|
/**
|
||||||
|
* Total elements.
|
||||||
|
* @type {number}
|
||||||
|
* @memberof RememberMeTokenList
|
||||||
|
*/
|
||||||
|
'total': number;
|
||||||
|
/**
|
||||||
|
* Indicates total pages.
|
||||||
|
* @type {number}
|
||||||
|
* @memberof RememberMeTokenList
|
||||||
|
*/
|
||||||
|
'totalPages': number;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
/**
|
||||||
|
* Halo
|
||||||
|
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||||
|
*
|
||||||
|
* The version of the OpenAPI document: 2.17.0-SNAPSHOT
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||||
|
* https://openapi-generator.tech
|
||||||
|
* Do not edit the class manually.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @interface RememberMeTokenSpec
|
||||||
|
*/
|
||||||
|
export interface RememberMeTokenSpec {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof RememberMeTokenSpec
|
||||||
|
*/
|
||||||
|
'lastUsed'?: string;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof RememberMeTokenSpec
|
||||||
|
*/
|
||||||
|
'series': string;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof RememberMeTokenSpec
|
||||||
|
*/
|
||||||
|
'tokenValue': string;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof RememberMeTokenSpec
|
||||||
|
*/
|
||||||
|
'username': string;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
/**
|
||||||
|
* Halo
|
||||||
|
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||||
|
*
|
||||||
|
* The version of the OpenAPI document: 2.17.0-SNAPSHOT
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||||
|
* https://openapi-generator.tech
|
||||||
|
* Do not edit the class manually.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
// May contain unused imports in some cases
|
||||||
|
// @ts-ignore
|
||||||
|
import { Metadata } from './metadata';
|
||||||
|
// May contain unused imports in some cases
|
||||||
|
// @ts-ignore
|
||||||
|
import { RememberMeTokenSpec } from './remember-me-token-spec';
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @interface RememberMeToken
|
||||||
|
*/
|
||||||
|
export interface RememberMeToken {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof RememberMeToken
|
||||||
|
*/
|
||||||
|
'apiVersion': string;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof RememberMeToken
|
||||||
|
*/
|
||||||
|
'kind': string;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {Metadata}
|
||||||
|
* @memberof RememberMeToken
|
||||||
|
*/
|
||||||
|
'metadata': Metadata;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {RememberMeTokenSpec}
|
||||||
|
* @memberof RememberMeToken
|
||||||
|
*/
|
||||||
|
'spec': RememberMeTokenSpec;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue